SIM900A,集成GSM和GPRS功能,可是鲜见玩GPRS 的,论坛里也没有多少用900a的朋友,早想远程控制家电,觉得论便携移动还有成本来说,900a比ENC28J60和W5100有优势,当然实时数据传输还得后者,所以小弟斗胆献丑,扒一扒SIM900a的事儿。
上个月我把家里路由器的9v电源插到SIM900A上让电流倒灌到uno中烧了板子和1602,后来用万用表测电压,着实被吓了一跳,明明是直流电但是电压高一下低一下,我勒个去,还是PWM的电压?!
后来买了mega2560,没有了uno程序到19kb就烧录不了(可能是变量太多?)的问题,这次写智能家居也差不多这么大,完全没问题,可是为什么uno上能播放的SD卡音乐mega却识别不了??
进入正题,先前装了网灵客户端,可以用手机或者电脑访问控制另一台电脑,晚上手机AP上网不用下床就能关了电脑,远程调文件什么的so easy,当然用GPRS流量访问的话一个电脑截屏300多kb,您自己斟酌着用。这么好的软件(俺还不是付费升级用户)唯一不能做的,就是开电脑了,咱不能为了以防万一需要电脑文件就24小时开着PC吧。睡眠休眠?不好意思,那样的话会自动断网,断网了的话当然控制不了电脑了。所以,我的智能家居第一步,控制电脑开机(关机什么的就用网灵)。
所用配件:
Arduino什么板都可以,本人2560,60元;
SIM900A 模块,142元;
USBtinyISP(这个因为我不小心下程序时没拔连900a的串口线,不知道烧了什么,后来bootloader也烧不上,万幸用编程器下载程序能用,就是每次下载完了拔掉线插mega麻烦),35元;
舵机,耳麦,红外遥控器和接收头,三色RGB灯,蜂鸣器;
木板,钉子,锯子等,反正您看着什么合适能成就用吧;
连线的话根据自己的板子在代码开头相应位置改,就不说了,上代码(I2C什么的被我烧了,有的可以连上,没有的不管也可):
int ledpin=13; //定义数字接口13
int val; //定义变量val
#include<LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,16,2);
#include<Wire.h>
#include <Servo.h>
Servo myservo;
#define MAXCHAR 81 //recive buff max char,81 orginally
#include<IRremote.h>
int RECV_PIN = 5;
IRrecv irrecv(RECV_PIN);
decode_results results;
int buzzer=53;
int redpin=A9;
int bluepin=A10;
int greenpin=A8;
//#include "Raw.h"
//#include "Message.h"
char aa[MAXCHAR]; //recive gsm model back signal,接收GSM的返回信号GSM》》Atmega
int j=0; //recive index
int g_timeout=0; //handing time
int k=0; //sms content identifier
int l=0; //sms send to number identifier
int m=0; //call identifier
//boolean flag2=0;
//unsigned long time;
boolean flag=0;
boolean flag1=0;
////////////////////////////////////////////////////
char ATE0[]="ATE0";
char CREG_CMD[]="AT+CREG?";////////////网络注册信息
char SMS_send[]="AT+CMGS=18";//////////发送短消息
char ATCN[]="AT+CNMI=2,1";///////////////新消息指示
char CMGF0[]="AT+CMGF=0";//////////////设置短消息的发送格式PDU
char CMGF1[]="AT+CMGF=1";//////////////纯文本
char CMGR[12]="AT+CMGR=1";////////////读取短消息
char CMGD[12]="AT+CMGD=1";////////////删除所有已读短消息
///////////////////////////////////////////////////
#define SEND_MESSA_TO_YOUR "at+cmgs=\"159********\"\r\n" //l=0
#define SEND_MESSA_TO_YOUR_1 "at+cmgs=\"182********\"\r\n" //l=1
#define SEND_MESSA_CONTENT "From SIM900A" //k=0
#define SEND_MESSA_CONTENT_1 "Master,servo moved done" //k=1
#define CALL_YOU_TELNUMBER "ATD159********;\r\n" //m=0
#define CALL_YOU_TELNUMBER_1 "ATD182********;\r\n" //m=1
///////////////////////////////////////////////////
/*
Read input serial
*/
int readSerial(char result[])///////////////////////////////////SIM900a to Arduino
{
int i = 0;
while (Serial.available() > 0) //返回串口缓冲区字符个数 已经传输到,并存储在串行接收缓冲区(能够存储64个字节)的字节数(字符)。
{
char inChar = Serial.read();
if (inChar == '\n')////////////////换行,一次只能读一行
{
result = '\0';///////////////string end
Serial.flush();/////////////////一次发送串口接收缓冲器中存储的数据(ATD159*******)
return 0;//////////////////////if中的跳出用法
}
if(inChar!='\r')
{
result = inChar;
i++;
}
}
}
/*
clean buff
*/
void clearBuff(void)
{
for(j=0;j<MAXCHAR;j++)
{
aa[j]=0x00;
}
j=0;
}
/*
clean buff
*/
int Hand(char *s)
{
delay(200);
clearBuff();
delay(300);
readSerial(aa);//////////////////////////aa[]=result[]
if(strstr(aa,s)!=NULL) //检测单片机和模块的连接,aa中若有s字符 串
{
g_timeout=0;
clearBuff();
return 1;
}
if(g_timeout>50)
{
g_timeout=0;
return -1;
}
g_timeout++;////////////////半秒加一
return 0;
}
/*
13 LED test
*/
void led(int i)
{
if(i)
{
digitalWrite(ledpin,HIGH);//点亮数字13 口LED。
delay(500);
}
else
{
digitalWrite(ledpin,LOW);//熄灭数字13 口LED
delay(500);
}
}
void AT(void)
{
clearBuff();
Serial.println(ATE0);////////////
delay(100);
readSerial(aa);
while(strstr(aa,"OK")==NULL)//////////OK在aa中第一次出现的位置,如果没有则返回NULL
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print("connect [..]");
clearBuff();
led(1);
Serial.println(ATE0);
delay(500);
readSerial(aa);
led(0);
}
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" connected");
clearBuff();
Serial.println(ATCN);
delay(500);
while(Hand("OK")==0);//////////////////aa中第二次出现OK字符串
clearBuff();
Serial.println("AT+CLCC");
delay(500);
while(Hand("OK")==0); //laidianxianshi phone number
clearBuff();
Serial.println("AT+CLIP=1\r\n");
delay(500);
while(Hand("OK")==0);//////////////////aa中第二次出现OK字符串
while(1)
{
clearBuff();
Serial.println(CREG_CMD); //AT+CREG?
delay(500);
readSerial(aa);
if((strstr(aa,"0,1")!=NULL)||(strstr(aa,"0,5")!=NULL))/////////出现0,1或0,5了的话……
{
clearBuff();
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" register [OK]");
Serial.println("OK");
break;//////////////////////跳出while(1)
}
else
{
lcd.clear();
lcd.setCursor(0,0);
lcd.print(" register [..]");
delay(500);
}
}
}
void send_english(int l,int k)
{
clearBuff();
Serial.println(CMGF1);/////////设置发送格式为文本
delay(200); //not necessary as hand() delay 0.5s
while(Hand("OK")==0);////////aa中没有OK字符串就先在此等待;
clearBuff();
switch(l){
case 0:
Serial.println(SEND_MESSA_TO_YOUR);
break;
case 1:
Serial.println(SEND_MESSA_TO_YOUR_1);
break;
}
delay(200);
while(Hand(">")==0);/*在接收电话号码与短信内容之间的必填字符,we can't use delay() here,cause??????????
function Hand() invoking readSerial(aa),and ">" will be transmitted immediately,once we missed ">",aa can not got it one more time*/
switch(k){
case 0:
clearBuff();
Serial.println(SEND_MESSA_CONTENT); //发短信内容
break;
case 1:
clearBuff();
Serial.println(SEND_MESSA_CONTENT_1); //发短信内容
break;
}
while(Hand(">")==0);
delay(100); //not necessary
Serial.print("\x1A"); //发送结束符号,\x means hex
delay(10);
delay(1000); //real sending sms time
while(Hand("OK")==0);
}
void send_call(int m)
{
clearBuff();
switch(m){
case 0:
Serial.println(CALL_YOU_TELNUMBER); //打电话
break;
case 1:
Serial.println(CALL_YOU_TELNUMBER_1); //打电话
break;
}
delay(2000);
while(Hand("OK")==0);
}
void color (unsigned char red, unsigned char green, unsigned char blue)
{
analogWrite(redpin, 255-red);
analogWrite(bluepin, 255-blue);
analogWrite(greenpin, 255-green);
}
void setup (void) {
pinMode(buzzer,OUTPUT);
pinMode(redpin, OUTPUT);
pinMode(greenpin, OUTPUT);
pinMode(bluepin, OUTPUT);
myservo.attach(9);
myservo.write(90);
lcd.init(); // initialize the lcd
lcd.backlight();
Serial.begin(9600);//设置波特率为9600
pinMode(ledpin,OUTPUT);//设置数字13 口为输出接
irrecv.enableIRIn(); //启动红外解码
Serial.println("serial port [ok]!");//显示字符串
}
void loop (void) {
int aa13,aa12,y; //index,index1;
char sms[5],cmgr[13];
boolean flag_read=0;
//String comdata="";
//char subaa[5];
//String aaa;
lcd.clear();
lcd.setCursor(0,0);
lcd.print("Welcome To");
lcd.setCursor(0,1); // 定义光标位置为第二行第二个位置
delay(10);
lcd.print("www.csgsm.com");
delay(100);
color(255,0,255); //待机中,绿色
digitalWrite(buzzer,LOW);
AT();
myservo.write(100);
clearBuff(); //删除则报错
while(1)
{
while(Serial.available()>0)
{
delay(50); //'L'型读写串行数据缓冲器
readSerial(aa);
if(strstr(aa,"RING")!=NULL) //call in
{
Serial.println(aa);
lcd.print("got a call from:");
Serial.println("RING,Answer?"); //set buzzer on,which modulated by pulse wave
flag=1; //zhi jie ting biao zhi
Serial.flush(); //
clearBuff();
color(0,255,255); //来电话,红色
while(!(irrecv.decode(&results)))
{
digitalWrite(buzzer,HIGH);
delay(300);
digitalWrite(buzzer,LOW);
delay(400);
}
}
if(strstr(aa,"+CMTI: \"SM\",")) //if we got a message
{
color(255,255,0); //blue
aa13=aa[13];
aa12=aa[12];
y=(aa12-48)*10+(aa13-48);
lcd.clear();
lcd.print(aa);
Serial.print("Read message ");
/*Serial.print(aa[0]); //+
Serial.print(aa[10]); //"
Serial.print(aa[11]); //,
Serial.print(aa[12]); //3
Serial.print(aa[13]); //4
Serial.print(aa[14]); //
Serial.print(aa[15]); */
Serial.print(y);
Serial.println("?");
Serial.println(aa);
flag1=1; //got a sms
flag_read=0; //haven't read yet
cmgr[0]='A';
cmgr[1]='T';
cmgr[2]='+';
cmgr[3]='C';
cmgr[4]='M';
cmgr[5]='G';
cmgr[6]='R';
cmgr[7]='=';
cmgr[8]=aa[12];
cmgr[9]=aa[13];
cmgr[10]='\r';
cmgr[11]='\n';
cmgr[12]='\0';
Serial.flush(); //if we don't clear now,this serial.available check would run all the time and occupy too much ir's check time
}
} //while(Serial.available) end
if (irrecv.decode(&results))
{
switch(results.value)
{
case 0xFF22DD:
color(0,0,0);
AT(); //initialization
color(255,0,255); //white light
break;
case 0xFF30CF: //"1",发短信
lcd.clear(); // 屏幕清空,光标位置归零
lcd.setCursor(0,0);
lcd.print(" send sms [..]");
k=0;
send_english(l,k); //k
break;
case 0xFF18E7: //"2",发短信
lcd.clear(); // 屏幕清空,光标位置归零
lcd.setCursor(0,0);
lcd.print(" send sms [..]");
k=1;
l=0;
send_english(l,k);
break;
case 0xFF42BD: //"7"call out
lcd.clear(); // 屏幕清空,光标位置归零
lcd.setCursor(1,1);// 定义光标位置为第二行第二个位置
lcd.print(CALL_YOU_TELNUMBER);
delay(10);
lcd.setCursor(1,0);
delay(10);
m=0;
color(0,255,255);
send_call(m);
delay(5000);
case 0xFF52AD: //"9"answer call in
if(flag)
{
color(255,255,0);
for(int w=0;w<50;w++)
{
digitalWrite(buzzer,HIGH);
delay(5);
digitalWrite(buzzer,LOW);
delay(5);
}
digitalWrite(buzzer,LOW);
Serial.println("ATA\r\n");
}
break;
case 0xFFA25D: //"ON/OFF" hang up
Serial.println("ATH\r\n");
color(255,0,255);
break;
case 0xFFB04F: //press U\SD button,read SMS again;at the first time we read automatically
clearBuff();
Serial.flush();
color(255,0,255);
Serial.print(cmgr);
delay(200);
readSerial(aa); //读出第一行,带走换行符,下一个a
while(strstr(aa,"+CMGR:")==NULL)
{
clearBuff();
delay(400);
readSerial(aa);
}
Serial.println(aa);
Serial.println("Receive SMS from:");
if(flag_read==0)
{
for(int i=24;i<35;i++)
{
Serial.print(aa);
}
}
else
{
for(int i=22;i<33;i++)
{
Serial.print(aa);
}
}
flag_read=1;
Serial.print("\r\n"); //0x0D其十进制ASCII码为13.第二次读短信read变unread,号码位置有所变动
Serial.println("Remaining room of serial buffer:");
Serial.println(Serial.available()); //aa接收完了串口缓冲器里的数据,读一个少一个,最后没了为0
for(int j=0;j<5;j++)
{
sms[j]=char (Serial.read());
}
Serial.print(sms);
switch(sms[0])
{
case 0x61:
myservo.write(110); //110 middle,90 up
delay(400);
break;
default:break;
}
clearBuff();
Serial.flush();
color(255,0,255);
break;
} //switch over
irrecv.resume();
} //if(IR.available) over
if(flag1==1)
{
clearBuff();
Serial.flush();
color(255,255,0);
Serial.println(cmgr);
delay(200);
readSerial(aa); //读出第一行,带走换行符,下一个b
while(strstr(aa,"+CMGR:")==NULL)
{
clearBuff();
delay(400);
readSerial(aa);
}
Serial.println("move servo");
Serial.println(aa);
clearBuff();
for(int j=0;j<5;j++)
{
sms[j]=char (Serial.read());
}
Serial.println(sms);
switch(sms[0])
{
case 0x62:
myservo.write(120);
delay(2500);
myservo.write(80);
//send_english(1,1);
delay(1000);
break;
}
color(255,0,255);
flag1=0;
flag_read=1;
}//if(flag1)end
}//while(1) never end
} //loop end
注意由于读取短信的AT指令长于64字节,要把串口缓冲区改到128字节,这个在吧里搜(先前一直怕引起其他麻烦没用,后来实验效果很好)。
目前功能,正常的拨打电话,接听电话,读取短信(产生控制舵机命令),发送某内容短信给某电话。读取短信时是首先Arduino自己读一遍,是某个命令(这里收到“b”就让舵机工作)就执行指定的操作,不是不执行,这是远程控制操作,而后遥控器按键可以再次读取这条短信,即使是已读的(可以改改液晶显示放在客厅当座机用)。
接下来扒一扒本屌自制的舵机驱动的开电脑开关,手头只有木头钉子,什么乐高积木、机械之类的东西一概没有。制成才发现木头确实是最适合的材料。图见““C”形舵机架”。
三块木板钉一起成“C”形,舵机用螺丝、钢针固定,用粗铁丝或钢丝折成“L"形,小拐弯处用于插入舵机头。铁丝另一端插入一根小木头(我用的筷子^_^...),木头下端穿过固定在木板上的瓶盖,最后将铁丝和舵机柄上的小孔捆绑起来。舵机转到100居中,转到120时木头向下顶住笔记本电源键。
最后说SIM900A的事儿,没有的童鞋绕道吧,都是些繁琐的细节问题。
一、串口调试方法(先用GSM串口调试工具玩熟练,把该记的指令记下)
1.短接跳线帽不要
2.插SIM卡,RS232线连好,电源接上等到由0.8s闪烁一次变为3s闪烁一次时打开串口调试助手
3.COM口不要大于5,越小越好
4.Arduino和电脑间有串行数据缓冲器,但是与SIM900a间没有?
5.打电话测试ATD13399059548;分号必须
6.接电话 AT+CLIP=1来电显示,ATA接听,ATH挂机
7.开机加电源后等几秒再开串口调试器
8.持续CREG不返回OK时试试重启或按reset
9.持续ATE0?串口调试工具没有关闭并安全退出,重新打开并关闭退出,或等模块灯3s闪两次后再开IDE串口
即-下程序,拔USB,开服务器,插USB,等3s灯,开串口
10.while();{}中的“;”编译器检测不出来,复制代码时注意
11.使用USBtinyISP下载程序时先连ISP到电脑,再连到mega,下载程序需要1分钟,红线靠Uart口.十根线不能拔
12.多次发送AT指令并检测返回信号提高接收率且最主要能接收几行readSerial(aa)遇换行跳出
一个小问题,执行程序时舵机不停地响动,貌似是检测位置,不知道如何解决,有经验的请留步。
SIM900A调试起来不像吧里其他GSM模块,没有库函数,只能发送接收AT指令,问题很多,欢迎交流。
|