话不多说先上视频,一看就懂

另外可参考这里:https://www.cnblogs.com/dehai/p/4285749.html ,这个近6年前的帖子

程序结构

程序分成上位机(PC端)与下位机(单片机):

PC端,使用的是WinForm ,声音识别采用微软的System.Speech.dll(这个也有很多坑后面会每坑说明)

程序由 :指令库,任务库,Http服务3部分组成

指令库:
系统会选择加载目录下XH.Cmd.xxxx.dll文件,并加载XHCmd开头的类型,类型需要做XHCmdAttribute标注,并且继承XHCommandBasic类

任务库:
系统会选择加载目录下XH.Task.xxxx.dll文件,并且加载XHTask开头的定义且继承XHTaskBasic的类,这可以用来提醒下班,自动关灯,关空调

定期检查机房服务器状态等等。。。。可以做很多扩展。

可以在在配置文件AppSetting节中ExcludeCmd与ExcludeTask,排除不需要加载的类型,另外下班提醒时间,开灯开空调提醒域值也在配置文件中

 下面是PC端需要注意的问题---各种坑点

1.操作系统用的是Win7 64位完整版,很多Ghost版不带语音模块,程序能编译但一运行就会出错

2.电脑的麦克风跟杨声器最好是2个设备并且分开一段距离防

3.无法把程序改成Windows服务的形式,必需是可视化的Windows Form形式, 远程桌面连接或计划任务启动的都无法使用语音识别功能

  如果要长期处于监听状态,只能将程序执行文件的快捷方式拖进Windows的 “启动”目录下,并且取消windows的登陆界面

4.为保证程序稳定运行,建议在计划任务里设置每天凌晨重启PC、

5.当然为了保证一定的安全,PC机专用,开启防火墙(但要开放TCP ,9495端口),另外可以在网关设备或核心交换机处禁止PC访问外网或被外网访问。

6.提供的代码里定义PC的IP是10.2.8.188,端口是9495, 使用时务必修改成实际的IP地址

7.app.Config中的DefaultClientIP用来区分多个单片机用的,目前只涉及一个单片机的情况下设置成服务器IP:Port形式,如果要支持多个单片机,需要自己调整程序,框架是支持的。

  具体原理是,单片机每个http请求会在QueryString携带传感器读数,并且带上自己的标识(也就是TagIP), 而PC会将下发的指令(指开灯,开空调等)通过这个请求的Response 返回给

 指定tagIp的单片机,下发指令存放在一个以tagIp作为key的字典中。收到http请求后,在生成Response时会查看对应Key的字典中有无要携带回去的指令,有的话就会在Response中体现。每个单片机每隔2-3秒左右发送一次请求,也就是系统延迟在2-3秒左右。

8.执行目录下的data下面可以放mp3,语音指令是”播放音乐“,程序会随机选择一个mp3文件播放。

单片机是arduino uno 配合网络板扩展,采用的是有线网络,硬件模块也是近6年前的老物件

单片上连了红外头用来控制空调,光敏电阻采集网照强度可以在昏暗时提醒开灯,用温湿传感器DHT11--这个也比较坑,用电流传感器--用来确定空调是否打开,还有控制灯的继电器

完整的单片机代码入下,注意接口

#define DHT11_PIN 0   ---dht11 连的是arduino的A0 口
#define CurrentIndexPin A3   --- 电流传感器连A3口
#define IlluminationPin A2     --热敏电阻连A2口
#define relayAPin 8             ---继电器连 8号口
#define RebootPin 5           --这个是5号口连的是三级管的基级,用来物理重启单片机用的,这样你的系统可以非常非常强壮

/*
Web client This sketch connects to a website (http://www.google.com)
using an Arduino Wiznet Ethernet shield. Circuit:
* Ethernet shield attached to pins 10, 11, 12, 13 created 18 Dec 2009
by David A. Mellis
modified 9 Apr 2012
by Tom Igoe, based on work by Adrian McEwen */
#include <avr/io.h>
#include <avr/pgmspace.h>
#include <SPI.h>
#include <Ethernet.h>
#include <IRremote.h>
//#include <avr/wdt.h> #define DHT11_PIN 0
#define CurrentIndexPin A3
#define IlluminationPin A2
#define relayAPin 8
#define RebootPin 5
// Enter a MAC address for your controller below.
// Newer Ethernet shields have a MAC address printed on a sticker on the shield
byte mac[] = { 0xDE, 0xAA, 0xBE, 0xEF, 0xFF, 0xE2 };
// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
//IPAddress server(74,125,232,128); // numeric IP for Google (no DNS)
char server[] = "10.2.8.188"; // name address for Google (using DNS) // Set the static IP address to use if the DHCP fails to assign
IPAddress ip(10,2,8,198);
IPAddress gateway(10,2,8,1);
IPAddress dns_server(60,191,134,196);
IPAddress subnet(255,255,255,0);
// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client; // Media Control RAW Code
IRsend irsend;
//open_cool_20_strong
const unsigned int PowerOn[] PROGMEM={
4610,4152,742,1395,740,354,737,1398,724,1438,718,350,714,380,709,1439,688,408,665,
405,641,1522,628,442,621,472,618,1518,612,1550,607,469,591,1567,586,1555,574,522,566,
1573,555,1608,554,1608,547,1589,543,1619,540,1595,546,547,544,1592,545,548,546,522,
541,553,548,519,544,550,542,525,544,550,545,522,544,1617,545,524,542,551,543,524,543,
524,543,551,548,1587,545,1617,543,524,570,1591,542,1619,547,1589,545,1616,546,1590,
543,5188,4375,4380,544,1590,548,545,546,1590,541,1621,545,522,544,550,545,1590,546,
547,546,521,542,1620,544,522,544,550,543,1592,543,1619,549,519,543,1618,541,1621,545,
521,546,1617,544,1592,546,1616,546,1589,543,1619,546,1615,545,524,541,1620,542,524,
543,551,545,523,543,524,542,551,545,523,543,549,548,520,539,1622,541,527,546,547,543,
523,542,551,544,524,540,1622,541,1594,546,548,543,1592,545,1616,543,1593,545,1616,
548,1614,540
}; //共有199条数据 //close
const unsigned int PowerOff[] PROGMEM={
4589,4171,734,1402,725,369,717,1419,715,1447,711,361,700,404,673,1466,653,443,634,
435,626,1535,624,445,620,474,614,1522,610,1552,601,468,597,1567,590,490,569,1590,567,
1574,553,1609,549,1612,549,519,541,1620,551,1586,542,1620,545,522,546,548,544,523,
546,548,546,1589,533,561,535,532,534,1628,535,1601,537,1624,541,527,545,547,543,526,
546,547,544,523,545,549,547,522,537,529,573,1589,543,1619,544,1592,555,1605,551,1584,
548,5184,4376,4377,542,1594,544,549,544,1592,544,1618,548,519,543,552,546,1589,544,
550,543,523,547,1616,546,521,544,549,546,1589,546,1616,544,523,545,1618,543,523,571,
1592,546,1615,549,1587,546,1616,549,518,546,1616,543,1593,545,1616,542,550,545,523,
545,522,544,549,546,1590,546,547,546,520,549,1615,544,1617,545,1590,546,548,545,521,
548,520,544,547,545,524,545,549,544,524,544,550,544,1592,542,1618,546,1590,543,1619,
546,1615,540
}; //共有199条数据 byte relayAStatus=0;
int il=0;
int ci=0;
int errCount=0; void setup() { pinMode(relayAPin,OUTPUT);
digitalWrite(relayAPin, relayAStatus);
pinMode(RebootPin,OUTPUT);
digitalWrite(RebootPin,LOW); //wdt_enable(WDTO_8S); DDRC|=_BV(DHT11_PIN);
PORTC|=_BV(DHT11_PIN);
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
} // start the Ethernet connection:
// give the Ethernet shield a second to initialize: if (Ethernet.begin(mac) == 0) {
Serial.println("Failed to configure Ethernet using DHCP");
Ethernet.begin(mac, ip,dns_server,gateway,subnet);
} delay(2000);
Serial.println("Ready");
} void loop()
{ double t=0;
double h=0;
bool isOK=false; isOK=readDHT11Data(t,h);
httpRequest(t,h);
if(relayAStatus==1){
digitalWrite(relayAPin, HIGH);
}else{
digitalWrite(relayAPin,LOW) ;
}
il=analogRead(IlluminationPin);
ci=getMaxValue();
Serial.println(il);
Serial.println(ci); delay(1000); }
//================DHT11 Code================== //================DT11 Code 1=======================
bool readDHT11Data(double &t,double &h){
t=-888;
h=-888; byte dht11_dat[5];
byte dht11_in;
byte i;
PORTC &= ~_BV(DHT11_PIN);
delay(18);
PORTC|=_BV(DHT11_PIN);
delayMicroseconds(40);
DDRC &= ~_BV(DHT11_PIN);
delayMicroseconds(40);
dht11_in = PINC & _BV(DHT11_PIN);
if(dht11_in)
{
Serial.println("dht11 start condition 1 not met");
return false;
} delayMicroseconds(80);
dht11_in=PINC & _BV(DHT11_PIN);
if(!dht11_in) {
Serial.println("dht11 start condition 2 not met");
return false;
} delayMicroseconds(80);
for(i=0;i<5;i++)
dht11_dat[i]=read_dht11_dat();
DDRC|=_BV(DHT11_PIN);
PORTC|=_BV(DHT11_PIN);
byte dht11_check_sum = dht11_dat[0]+dht11_dat[1]+dht11_dat[2]+dht11_dat[3];
if(dht11_dat[4]!=dht11_check_sum)
{
Serial.println("DHT11 checksum error");
return false;
} t= dht11_dat[2] + (double)dht11_dat[3]/100;
h=dht11_dat[0] + (double)dht11_dat[1] /100; Serial.print("temperature = ");
Serial.print(t,DEC);
Serial.print("C");
Serial.print("Current humdity= ");
Serial.print(String(h));
Serial.println("%"); return true;
}
byte read_dht11_dat()
{
byte i = 0;
byte result = 0;
for(i=0;i<8;i++)
{
while(!(PINC&_BV(DHT11_PIN)));
delayMicroseconds(30);
if(PINC&_BV(DHT11_PIN))
result|=(1<<(7-i));
while((PINC&_BV(DHT11_PIN)));
}
return result;
} //================End DHT11 Code================== //================Http Request Code========================
void httpRequest(double t,double h){
// if you get a connection, report back via serial: if(!client.connected()){
Serial.println("disconnecting.");
client.stop();
if (client.connect(server, 9495)) {
Serial.println("connected");
}else{
// kf you didn't get a connection to the server:
Serial.println("connection failed");
errCount++;
if(errCount>=3){
digitalWrite(RebootPin,HIGH);
delay(1000);
}
}
} else{ // Make a HTTP request:
client.println("GET /?m=c&mil=" + String(millis()) + "&t="+String(t)+"&h="+String(h)+ "&ra=" +String(relayAStatus)+"&i="+String(il) +"&ci=" +String(ci) +" HTTP/1.1");
client.println("Host:10.2.8.188");
//client.println("Connection: close"); client.println();
delay(10);
String reply="";
// if there are incoming bytes available
// from the server, read them and print them:
while (client.available()) {
char c = client.read();
reply+=c; }
//Serial.print(reply);
if(reply.indexOf("\"Model\":\"OPENA\"")>=0){
Serial.println("OPEN");
powerOnA();
}
if(reply.indexOf("\"Model\":\"CLOSEA\"")>=0){
Serial.println("CLOSE");
powerOffA();
}
if(reply.indexOf("\"Model\":\"OPENL\"")>=0){
Serial.println("OPENL");
powerOnL();
}
if(reply.indexOf("\"Model\":\"CLOSEL\"")>=0){
Serial.println("CLOSEL");
powerOffL();
}
errCount=0;
//wdt_reset();
} }
//================End Http Request Code=============== //================AirConditioner && Light Control===========
void powerOffA(){ unsigned int t[199];
for(int i=0;i<199;i++){
t[i] = pgm_read_word_near(PowerOff+i); }
irsend.sendRaw2(t,199,38);
delay(3000);
}
void powerOnA(){ unsigned int t[199];
for(int i=0;i<199;i++){
t[i] = pgm_read_word_near(PowerOn+i); } irsend.sendRaw2(t,199,38);
delay(3000);
}
void powerOffL(){
relayAStatus=0;
}
void powerOnL(){
relayAStatus=1; } //================CurrentIndex Read Max Value=================
int getMaxValue()
{
int sensorValue; //value read from the sensor
int sensorMax = 0;
uint32_t start_time = millis();
while((millis()-start_time) < 1000)//sample for 1000ms
{
sensorValue = analogRead(CurrentIndexPin);
if (sensorValue > sensorMax)
{
/*record the maximum sensor value*/
sensorMax = sensorValue;
}
}
return sensorMax;
} //================End CurrentIndex ReadMax Value============= //================End AirConditioner Control===================

 单片机端注意的事项

1.DHT11 正负极一定不能接反,数据线要检测下是否导通的,话说折腾了几个小时发现是陈年的数据线时通时不通导致的。。。

如果单片机用mega2560那么使用DHT11库比较方便.

2.红外发射头针对Uno 使用的是3号脚,而针对mega2560使用的是9号脚,另外红外头必需足够靠近空调。同时务必注意连线接触要
好。

3.继电器,刚开始用的机械的,然后是光藕隔离机械的,但是由于负载是LED(220AC,70W)结果经常一吸合上就跳不开了。

所以如果也是LED等带交流转直流的务必采用固态继电器,这里使用的是5V高电平触发,220V AC 2A 的固态继电器,可自己

上某宝或某东找去。

4.电流传感器,这个是检测空调是否启动的,某宝上能找到的是最大支持5A电流,用来检测空调有点问题(空调最大16A),所以要改动空调电源线的火线(L线)

,在主空调火线上旁路一条细线分流,

线径是主线的1/5,电流传感器(感应式的)就装旁线上,理论上可将电流降低1/6,就能符合传感器的规格了。

5.最后是三极管(S8050),基极过1K电阻连5号口,集电极过270欧电阻连Vcc,同时集电极连单片机RESET口,发射极连GND,单片机

代码里检测到连续3次错误后会给5号口高电平,这样就可以重启单片机,5号口默认是数字输出LOW.

完整代码下载:点这里

------------------------------------------------------------------------------------------------------------------

5年前接触的arduino,做为一个.net程序员15年了,儿子也11岁了

马上奔4了,15年前是程序员,现在仍旧是程序员,只是年纪大了,身体差了,毛病多了,亲人朋友也有离世。。。。

园子里的程序员门,你们还好吗,多珍重。。。。。

何须问

最新文章

  1. 代码质量管理工具——SonarQube
  2. 窥探Swift之字符串(String)
  3. JSP内置对象---request和 response
  4. [ACM_模拟][ACM_暴力] Lazier Salesgirl [暴力 懒销售睡觉]
  5. 在阿里云主机的Debian操作系统上安装Docker
  6. 自用java字符串工具类
  7. Oracle 给表添加主键和使ID自增、触发器、创建结构一样的表
  8. C# 打印多页tif
  9. 普通Java类获取spring 容器的bean的5种方法
  10. yii [error] [exception.CHttpException.404] exception &#39;CHttpException&#39; with message &#39;Unable to resolve the request &quot;favicon.ico&quot;.&#39;
  11. Android 动画系列
  12. [SDOI 2012]Longge的问题
  13. Docker仓库
  14. Numpy的学习
  15. 简单的ALV示例
  16. pycharm断点应用
  17. [转]Docker中的镜像
  18. VUE.js 简单引用
  19. xtrabackup备份mysql-2 增量备份
  20. genymotion 模拟器内安装软件 the app contains ARM native code and your devices cannot run ARM instructions

热门文章

  1. tornado-简介和原理
  2. mysql-3-orderby
  3. Arduino 多线程简单代码
  4. C/C++的二分查找
  5. CPU 执行程序的秘密,藏在了这 15 张图里
  6. Scala小记(一)
  7. ansible-playbook安装tomcat
  8. ng2 父子组件传值 - 状态管理
  9. unix中的线程池技术详解
  10. mysql update 子查询作为条件