设计目标 以一个情景来说,当发生火灾时,本系统会检测到火灾,然后通过GSM通信模块,将定位和火警信息以短信形式发送给目标手机,并控制蜂鸣器实现报警。按下复位按键可以使系统重新工作在监测状态。(点此查看效果)
准备阶段 长文,有点啰嗦,但几乎涵盖所有可能会遇到的问题,望读者有所准备。不过内容简单,请放心阅读。
硬件
元件清单
简介
Arduino nano主控板,1块
作为系统主控制器
北斗定位模块,1个
本系统采用的是正点原子的ATK-1218-BD模块,带有源天线的版本,用来实现室内的定位
GSM通信模块,1个
本系统采用的是SIM900A模块,通过它发送报警短信,SIM800系列的好像也兼容
MQ-2烟雾传感器模块,1个
用来检测烟雾和可燃气体
火焰传感器模块,1个
通过红外线接收管来检测火焰
蜂鸣器模块,1个
用于报警
USB-TTL模块,1个
非必要,只是用于电脑调试GSM模块,最好是CP2102芯片那款
microUSB数据线,1根
用来供电以及给nano主控板烧录程序
面包板或洞洞板,1块
用于放置电路,面包板需若干杜邦线配合使用
如果跟我一样是用洞洞板搭电路的话,还需电烙铁、焊锡、电线等工具和材料。
软件
Arduino IDE,开发Arduino必备的集成开发环境,官网下载地址 (点此跳转) ,根据自己操作系统版本下载对应软件安装包即可
GNSS_Viewer,专门用来观察和设置北斗模块的软件,购买ATK-1218-BD模块时店家会提供资料,当然也可以到正点原子的资料下载中心获取,点此跳转
TinyGPS++库,是由Mikal Hart开发的Arduino第三方库,用来解析北斗模块发来的定位信息。这是作者主页 ,里面有下载地址还有对这个库的详细介绍。我用的1.0.2版本的库,百度网盘地址 ,提取码: q5bn,如果不知道库怎么用那就下我这个老版本吧。库的安装比较容易这里就不赘述了。
设计阶段 管脚接线 下表展示了Arduino nano与各模块的连接关系。
Arduino nano引脚
作用
接法
D2
普通数字输出口
接蜂鸣器I/O引脚
D8
软串口1的RX
接北斗模块TX引脚
D9
软串口1的TX
接北斗模块RX引脚
D10
软串口2的RX
接GSM模块TX引脚
D11
软串口2的TX
接GSM模块RX引脚
A0
普通模拟输入口
接火焰传感器AO引脚
A1
普通模拟输入口
接烟雾传感器AO引脚
原理图 用AD画的,点开图片可以看得清晰点,内容跟上面其实差不多,就是看起来生动一点。
报警解除电路可以忽略,实际上它是通过Arduino nano内部的复位电路实现的,只不过现在把它画到外面了。蜂鸣器电路偷懒用了之前画的,不过不影响。
程序流程图 最底下的报警解除按键实际上是通过硬件电路实现的,就是nano本身自带的复位电路。把它画在程序流程图里只是为了说明蜂鸣器报警程序虽然是死循环但是可以通过复位解除。
调试阶段 注意事项
GSM模块需要5V2A的电源供电,否则模块工作可能不正常;
单独调试GSM模块跟电脑串口通信时需要质量较好的USB转TTL模块,我用自己之前买的劣质CH340芯片的USB转TTL模块在调试时失败了,电脑串口能识别但是发AT指令给GSM模块没反应,换了CP21202芯片的USB转TTL模块就好了;
北斗定位模块的有源天线最好放到阳台外,这样才能搜到卫星;
虽然Arduino nano软串口支持的最高波特率是115200,但测试时发现,只有波特率工作在9600才正常,这也是为什么下面把北斗模块波特率也设成9600的原因;
北斗模块每次使用前需要用GNSS_Viewer软件对它的波特率修改为9600(这个可能是我的北斗模块有问题,没法把设置写进flash);
烟雾传感器使用前需要预热几分钟,具体多久看串口,打印的数值不咋跳了,就预热完了;
火焰传感器对光是敏感的,也就是说中午太阳光很亮的话,它也会触发,这也是为什么加烟雾传感器的原因。
火焰、烟雾传感器 这两模块均可通过以下代码测试好坏,检测到火焰或烟雾后,串口打印的数值会发生较大变化。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #define flameSensor A0 #define smogSensor A1 void setup () { pinMode (flameSensor,INPUT ); Serial .begin (9600 ); } void loop () { Serial .println (analogRead (flameSensor)); delay (1000 ); }
一个参考:我的火焰传感器在晚上测出来数值在1015-1017徘徊,拿手机闪光灯照射数值会降到850以下;烟雾传感器正常值应该在500以下,检测到烟雾数值会超过500,当时测得应该67百这样。 以上仅是参考,实际上每个传感器检测的返回值各不相同,只要检测到火焰或烟雾时,数值上有较大的变动即可说明模块工作正常。
SIM900A通信模块
插入手机卡后,与USB转TTL模块(按TXD-RXD、RXD-TXD、GND-GND连接)好后,供上5V2A的电,不出意外的话,模块已经正常工作了。
可以给模块上的手机号打电话,正常拨通振铃的话说明模块应该没问题。然后就可以把USB转TTL模块接到电脑上,打开串口助手,设置通信参数(波特率9600,数据位8,停止位1),然后打开对应的串口,发送指令‘AT’,如果收到模块的回复‘OK’,那就说明电脑与模块串口通信正常。
然后就可以通过以下程序烧录到单片机,测试单片机与GSM模块的串口通信是否正常。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <SoftwareSerial.h> SoftwareSerial SIM900A (10 ,11 ) ; String msg="Hello!" ; void sendMeg () { SIM900A.println ("AT" ); delay (1000 ); SIM900A.println (F"AT+CMG=1" ); delay (1000 ); SIM900A.println ("AT+CMGS=\"13xxxxxxxx2\"" ); delay (1000 ); SIM900A.print (msg); SIM900A.print ("\r\n" ); delay (1000 ); SIM900A.write (0x1A ); } void setup () { SIM900A.begin (9600 ); sendMeg (); } void loop () {}
如果程序中的手机号码收到了对应短信内容,说明模块工作正常,测试完成。
北斗模块 跟GSM一样与USB转TTL模块连接好后,可以通过GNSS_Viewer软件查看模块是否定位成功,我的北斗模块通信波特率默认是115200,所以定位成功后需设置波特率为9600。 然后就可以通过TinyGPS++自带的例程测试本模块,该例程在正常安装好TinyGPS++库后,应该能在Arduino IDE的菜单栏(File->Examples->TinyGPS++)里找到。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 #include <TinyGPS++.h> #include <SoftwareSerial.h> TinyGPSPlus gps; SoftwareSerial ss (8 ,9 ) ;float latitude;float longitude;void setup () { Serial .begin (9600 ); ss.begin (9600 ); } void loop () { ss.listen (); while (ss.available () > 0 ){ gps.encode (ss.read ()); if (gps.location.isUpdated ()){ latitude = gps.location.lat (); longitude = gps.location.lng (); Serial .print ("Latitude=" ); Serial .print (latitude, 6 ); Serial .print (" Longitude=" ); Serial .println (longitude, 6 ); delay (500 ); } } }
没问题的话,该例程会在串口打印输出经纬度信息,即说明北斗模块定位正常且该库正常解析出定位信息中的经纬度信息。
蜂鸣器模块 该模块可通过下面这个程序检测。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #define Buzz 2 void BuzzOnOff () { digitalWrite (Buzz,HIGH ); delay (100 ); digitalWrite (Buzz,LOW ); delay (100 ); } void setup () { pinMode (Buzz,OUTPUT ); } void loop () { BuzzOnOff (); }
它够吵就说明模块正常。
Arduino软串口 因为GSM模块与北斗模块都要用串口通信,而nano仅有一个物理串口,这就需要用软件实现串口,简称软串口。关于例程在Arduino IDE的菜单栏(File->Examples->SoftwareSerial->SoftwareSerialExample)里可以找到。 下面是我测试软串口的程序,它将nano的D8、D9、D10、D11这四个脚模拟成两个串口,一个串口发信息,另一个串口可以收到该信息。简而言之,让Arduino自言自语,哦,准确的说,好像是我在自言自语。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <SoftwareSerial.h> SoftwareSerial beidou (8 , 9 ) ; SoftwareSerial gsm (10 , 11 ) ;void setup () { beidou.begin (57600 ); gsm.begin (4800 ); beidou.println ("Hi!This is beidou." ); gsm.println ("Hello,It's gsm" ); } void loop () { if (beidou.available ()) { gsm.write (beidou.read ()); } if (gsm.available ()) { beidou.write (gsm.read ()); } }
测试需要两个USB转TTL模块分别(按TXD-D8、RXD-D9、GND-GND和TXD-D10、RXD-D11、GND-GND)连接,然后打开两个串口助手软件才能看到效果。没问题的话,你在一个串口助手发消息,可以在另一个串口助手收到消息。
最终实现 下面是最终测试的视频
过会儿手机就会受到火灾报警短信,如下所示。
总程序 就60几行代码?是的,就这么点。你完全可以读懂每一行代码在做什么。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 #include <SoftwareSerial.h> #include <TinyGPS++.h> #define Buzz 2 #define flameSensor A0 #define smogSensor A1 TinyGPSPlus gps; SoftwareSerial Beidou (8 ,9 ) ; float latitude;float longitude;SoftwareSerial SIM900A (10 ,11 ) ; String msg="EMERGENCY! FIRE ALARM!!!\r\nPositioin Here: " ;void sendMeg () { SIM900A.println ("AT" ); delay (1000 ); SIM900A.println ("AT+CMGF=1" ); delay (1000 ); SIM900A.println ("AT+CMGS=\"12345654321\"" ); delay (1000 ); SIM900A.print (msg); SIM900A.print ("Latitude=" ); SIM900A.print (latitude, 6 ); SIM900A.print (", Longitude=" ); SIM900A.print (longitude, 6 ); SIM900A.print ("\r\n" ); delay (1000 ); SIM900A.write (0x1A ); } void BuzzOnOff () { digitalWrite (Buzz,HIGH ); delay (100 ); digitalWrite (Buzz,LOW ); delay (100 ); } void setup () { pinMode (flameSensor,INPUT ); pinMode (smogSensor,INPUT ); pinMode (Buzz,OUTPUT ); SIM900A.begin (9600 ); Beidou.begin (9600 ); } void loop () { Beidou.listen (); while (Beidou.available () > 0 ){ gps.encode (Beidou.read ()); if (gps.location.isUpdated ()){ latitude = gps.location.lat (); longitude = gps.location.lng (); delay (500 ); } if (analogRead (smogSensor)>500 && analogRead (flameSensor)<650 ){ BuzzOnOff (); sendMeg (); while (1 ){BuzzOnOff ();} } } }