遗忘海岸

江湖程序员 -Feiph(LM战士)

导航

C#+Arduino Uno 实现声控系统完全实施手册

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

另外可参考这里: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文件播放,注意不是所有的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===================
View Code

 

 单片机端注意的事项

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.

 

完整代码下载:点这里

                         点这里V2版

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

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

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

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

 

何须问

posted on 2020-11-03 14:17  遗忘海岸  阅读(1336)  评论(4编辑  收藏  举报