https://www.arduino.cn/thread-19432-1-2.html
1.所需工具:
(1)arduino UNO,(2)sim900a模块,(3)单路继电器,(4)220v ac转12v dc的降压模块【给arduino供电,12V是官方说明的供电极限】(我用的是高能立方),(5)插头,插孔,电线。
2.连线:
我是小白,不会设计电路,没法画图了,就直接说我自己的连线了。
火线接降压模块的L,零线接N,地线接E(插头遵守 左零右火上接地 原则);降压模块的正极接VIN,负极接GND;arduino 7脚接sim900a的5VR,8脚接sim900a的5VT;arduino的5V接sim900a的VCC,arduino的GND接sim900a的GND;arduino的11脚接继电器GND,12脚接继电器VCC,13脚接继电器的控制端;插孔的地线、零线接插头的地线、零线,插孔的火线一段接插头、一端接插孔、中间连入继电器。
3.注意事项:
(1)事先检查线有没有断(我就因为RX的线断了,折腾了好几天)
(2)保证sim卡安装好,sim卡的内容提前保存好程序会删除所有短信
(3)为了接收短信的全部内容可以增加串口缓冲区的大小,方法:找到Arduino\hardware\arduino\avr\libraries\SoftwareSerial\SoftwareSerial.h,里面有一行#define _SS_MAX_RX_BUFF 64 // RX buffer size。把64(或者其他数字)改大一点,我改成1024.
#include//define Pins and Data #define rxPin 8 #define txPin 7 #define relayPin 13 #define relayVCC 12 #define relayGND 11 #define relay_close LOW #define relay_open HIGH enum SMStype {UNRELATED,OPEN,CLOSE,ASK}; //globle variable SoftwareSerial m_serial(rxPin,txPin); String MSG(""); String SMS(""); char myRelay=1; char myPhone[]={"18843109531"}; char snd_tips[]={"Send open to open. Send close to close. Send ask to get the status. Case-Insensitive!"}; char snd_unrelated[]={"Sorry.I can't understand what you sent!"}; char snd_open[]={"The Plug has been Opened!"},snd_close[]={"The Plug has been Colsed!"},snd_ask_o[]={"The Plug is Opening..."},snd_ask_c[]={"The Plug is Closing..."}; //function declaration void init(SoftwareSerial &p_serial); //initialize the sim900a module void getMSG(String &p_MSG,SoftwareSerial &p_serial); //get the sim900a module's message bool chkMSG(String &p_MSG); //check the message's type void rcvSMS(String &p_SMS,SoftwareSerial &p_serial); //recieve the first SMS char chkSMS(String &p_SMS); //check the SMS's type void sndSMS(const char *phone_num,const char *content,SoftwareSerial &p_serial);//send Short Message void openRelay(char relay_VCC,char relay_GND); void ctrlRelay(char relayType); //contral the relay //main function void setup() { openRelay(relayVCC,relayGND); init(m_serial); ctrlRelay(relayPin,relay_open); sndSMS(myPhone,snd_tips,m_serial); } void loop() { delay(100); getMSG(MSG,m_serial); //delay(100); if(!chkMSG(MSG)) return; rcvSMS(SMS,m_serial); delay(100); switch(chkSMS(SMS)) { case OPEN: { myRelay=relay_open; sndSMS(myPhone,snd_open,m_serial); delay(100); break; } case CLOSE: { myRelay=relay_close; sndSMS(myPhone,snd_close,m_serial); delay(100); break; } case ASK: { if(myRelay) { sndSMS(myPhone,snd_ask_o,m_serial); delay(100); } else { sndSMS(myPhone,snd_ask_c,m_serial); delay(100); } break; } default: { sndSMS(myPhone,snd_unrelated,m_serial); delay(100); sndSMS(myPhone,snd_tips,m_serial); delay(100); } } ctrlRelay(relayPin,myRelay); } void init(SoftwareSerial &p_serial) { p_serial.begin(9600); p_serial.println("AT"); delay(500); p_serial.println("AT+CMGD=1, 4"); delay(500); p_serial.flush(); delay(100); } void getMSG(String &p_MSG,SoftwareSerial &p_serial) { p_MSG=""; while(!p_serial.available()) ; for(char in='\0',flag=0;p_serial.available();) { in=p_serial.read(); if(in=='+') flag=1; if(flag&&((in=='\r')||(in=='\n'))) break; if(flag) p_MSG+=in; } p_MSG.trim(); p_serial.flush(); } bool chkMSG(String &p_MSG) { for(int p_begin=0;(p_begin+5) ';) ; p_serial.print(content); delay(500); p_serial.write(0x1A); delay(500); p_serial.flush(); delay(100); } void rcvSMS(String &p_SMS,SoftwareSerial &p_serial) { p_SMS=""; m_serial.println("AT"); delay(500); m_serial.println("AT+CSCS=\"GSM\""); delay(500); m_serial.println("AT+CMGF=1"); delay(500); m_serial.flush(); m_serial.println("AT+CMGR=1"); delay(500); while(!p_serial.available()) ; for(char in='\0',flag=0;p_serial.available();) { in=p_serial.read(); if(in=='\"') flag++; if(flag==8) { p_serial.read(); p_serial.read(); while((in!='\r')&&(in!='\n')&&p_serial.available()) { in=p_serial.read(); p_SMS+=in; } break; } } p_serial.println("AT+CMGD=1, 4"); delay(500); p_serial.flush(); delay(100); } char chkSMS(String &p_SMS) { String temp_open="open\r",temp_close="close\r",temp_ask="ask\r"; if(p_SMS.equalsIgnoreCase(temp_open)) return OPEN; if(p_SMS.equalsIgnoreCase(temp_close)) return CLOSE; if(p_SMS.equalsIgnoreCase(temp_ask)) return ASK; return UNRELATED; } void openRelay(char relay_VCC,char relay_GND) { pinMode(relay_VCC,OUTPUT); digitalWrite(relay_VCC,HIGH); pinMode(relay_GND,OUTPUT); digitalWrite(relay_GND,LOW); } void ctrlRelay(char p_pin,char relayType) { pinMode(p_pin,OUTPUT); digitalWrite(p_pin,relayType); }
5.代码解释
(1)之所以用软串口,是因为硬串口用来查bug。
(2)sim900a模块发送短信流程:
首先要同步波特率,给sim900a发送“AT\r”,详见init()。//应该是一次就行
发送英文短信要设置GSM字符集设置文本模式发送“AT+CMGS=\"188xxxxxxxxx\"\r"(188xxxxxxxx是手机号)
等模块返回">"后,发送短信内容不要加\r或\n
最后发送16进制的0x1A(注意是16进制的,不要发送成字符)
然后就发送成功了,详见sndSMS()。
(3)sim900a模块接收短信流程
sim900a模块接收到短信后会给arduino发送含有”+CMTI"的字符串
要设置GSM字符集
设置文本模式
发送”AT+CMGF=1"查询第一条短信,=2就查询第二条以此类推
在sim900a返回的字符中查找短信的内容,第8个 “ 后就是短信内容
6.还需改进
(1)在chkSMS()中可以判断短信内容,为了安全考虑,可以在短信内加入密码(如sim卡的pin),如发送“pin码+open”表示打开。
(2)未来可以做一个有收发短信功能的手机app,还可以实现定时开关(定时发送短信)。
#includeSoftwareSerial softSerial1(4,5);//软串口RXD4、TXD5,与短信模块通信 #define yudi_d 2 //水传感器口 #define relay 3 //继电器口 unsigned long previousMillis=0;//存储时间,用于计时 const long interval=10000; //短信间隔10000ms int flag=0;//出水短信发送 int sendMeg(String phonenum,String text)//发送信息的函数,直接调用即可,无需修改 { char comdata=0;//判断接收到的最后一位是否对 String phone="";//电话号码存储 phone="AT+CMGS=\""+phonenum+'\"'; while (softSerial1.available() > 0){ comdata = softSerial1.read(); //每次读一个char字符,并相加 delay(2); } softSerial1.println("AT");//对GSM发送AT,看响应 delay(1000); while (softSerial1.available() > 2){ comdata = softSerial1.read(); //每次读一个char字符,并相加 Serial.print(comdata);//错误 delay(2); } if(comdata!='K')//判断没有收到OK { Serial.println("error1");//错误 // return 0; } comdata=0; softSerial1.println("AT+CMGF=1");//设置GSM文本模式 delay(500); while (softSerial1.available() > 2){ comdata = softSerial1.read(); //每次读一个char字符,并相加 delay(2); } if(comdata!='K')//没有收到OK { Serial.println("error2"); // return 0; } comdata=0; softSerial1.println(phone);//发送的目标号码 delay(1000); while (softSerial1.available() > 1){ comdata = softSerial1.read(); //每次读一个char字符,并相加 delay(2); } if(comdata!='>')//没有收到> { Serial.println("error3"); // return 0; } comdata=0; softSerial1.print(text);//发送所写内容 delay(500); softSerial1.write(0x1A); //结束输入文本,并发送 Serial.println("success"); //成功 } void setup(){ Serial.begin(9600);//串口 softSerial1.begin(9600); //监听软串口通信 softSerial1.listen(); pinMode(A7,INPUT);//水传感器模拟端口设置模式 pinMode(relay,OUTPUT);//继电器端口模式 pinMode(yudi_d,INPUT);//水传感器数字端口设置模式 } void loop(){ unsigned long currentMillis=millis();//当前时间,用于判断时间 int a0= analogRead(A7);//获取模拟端口值 //Serial.print(a0); //Serial.print("--");//串口输出,主要用于电脑监视和调试 int d2=digitalRead(yudi_d);//获取数字端口值 //Serial.println(d2);//串口输出,主要用于电脑监视和调试 if(d2==0)//判断是否浸入水中 digitalWrite(relay,LOW);//进入,打开继电器 else digitalWrite(relay,HIGH);//未进入,关闭 if(d2==0&¤tMillis-previousMillis>=interval)//浸入水中,并时间间隔大于10s { previousMillis=currentMillis;//获取当前时间,以便于为下次发短信计时 sendMeg("15147300333","Water logging alarm of No.2 well of 110kV gold lead cable tunnel, please handle it quickly");//给15147300333 发送信息 Serial.println("1"); //成功 flag=1; } if(d2==1&&flag==1)//出水 { delay(2000); sendMeg("15147300333","The water logging alarm of No.2 well of 110kV gold lead cable tunnel has been removed.the equipment is normal");//给15147300333 发送的信息 Serial.println("2"); //成功 flag=0; } delay(100); }