短信控制的 智能插头(sim900a arduino uno)-Arduino中文社区 - Powered by Discuz! Archiver

Pentagram113 发表于 2016-2-28 00:34

短信控制的 智能插头(sim900a arduino uno)

本帖最后由 Pentagram113 于 2016-2-28 00:33 编辑

我是个初学者,心血来潮(也是为了完成SI作业),做了一个用短信控制的插头(名曰“智能插头”)。当然由于我之前对于串口通信一无所知,收发短信会有十几秒的延迟,还有每个组件都太大了,所以希望大家多提宝贵意见,谢谢。(还有我不知道为什么串口通信要加延迟,为什么要按下复位键才能正常使用,望大神告诉)
附图(有点简陋哈)

智能插头的功能:通过短信控制插头开关,查询插头的状态。

智能插头的优点:不需要改变现有插头,只要在用电器的插头和插座之间加上智能插头就能控制用电器的开关,能发短信的手机都能控制。


智能插头的适用人群:懒人不想走很远去关电源,关灯(比如我);出门前非要挨个电源检查的人;健忘但是坚持节能省电的人(机顶盒待机状态一月好几度呢),怕小孩摸电源的家长,想有点科技感的家的人。


------------------------------------------------------------------------------------------------------------------------------------------------------------------------
言归正传:

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.

4.代码
#include <SoftwareSerial.h>

//define Pins and Data
#define rxPin 8
#define txPin 7
#define relayPin 13
#define relayVCC 12
#define relayGND 11
#define relay_closeLOW
#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_MSG.length();p_begin++)
{
    if(p_MSG.substring(p_begin,p_begin+5)=="+CMTI")
      return true;
}
return false;
}

void sndSMS(const char *phone_num,const char *content,SoftwareSerial &p_serial)
{
p_serial.println("AT");
delay(500);
p_serial.println("AT+CSCS=\"GSM\"");
delay(500);
p_serial.println("AT+CMGF=1");
delay(500);
p_serial.print("AT+CMGS=\"");
p_serial.print(phone_num);
p_serial.println("\"");
for(;m_serial.read()!='>';) ;
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,还可以实现定时开关(定时发送短信)。

Pentagram113 发表于 2016-5-11 20:36

那个,抄代码的时候,能不能把电话号改一下,别总往我手机里发信息,顺便说一下,那位大哥,你成功了,把号码改一下好吗?都发20多条信息了

热爱生活 发表于 2016-12-4 12:26

zzzz345 发表于 2016-7-26 08:39
楼主,缓冲区改成128就够用了。推荐大家在改软串口缓存大小的时候,尽量不要改太大,因为多分了内存给串口 ...

谢谢分享,真的非常好啊!

PPeach 发表于 2016-2-28 11:43

可以可以,就是为啥不把220V的线弄得长一点........

Pentagram113 发表于 2016-2-28 14:31

PPeach 发表于 2016-2-28 11:43
可以可以,就是为啥不把220V的线弄得长一点........

线买短了:$

zzzz345 发表于 2016-5-12 17:13

楼主,我直接用了你的代码,但是用手机回复sim900a open后总显示default的结果,是为什么呀?不知道是接收信息哪里出了问题。谢谢

zzzz345 发表于 2016-7-26 08:39

楼主,缓冲区改成128就够用了。推荐大家在改软串口缓存大小的时候,尽量不要改太大,因为多分了内存给串口会使其他部分所能使用的内存下降很多,基本上在这个代码基础上再加功能就会使UNO运行不起来。

lilala1402 发表于 2016-12-29 19:13

楼主你那个sim900a哪里买的能不能发个链接

GGG1101 发表于 2017-6-6 13:36

楼主,你这个是用哪个版本的IDE编译的,为什么我把你代码放在IDE编译上传后,发送OPEN,CLOSE,
ASK,这个3个指令中任何一个都是回复default,继电器也不能工作

gaohuakai 发表于 2017-6-8 10:33

为啥米十几年的遥控开关,到这里就变智能的了?
页: [1] 2
查看完整版本: 短信控制的 智能插头(sim900a arduino uno)