注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
曹世鹏的个人空间 https://home.eeworld.com.cn/space-uid-438848.html [收藏] [复制] [分享] [RSS]
日志

SIM900小制作。短信控制,飞信控制,电话控制。

热度 1已有 2705 次阅读2014-7-29 12:58 |个人分类:制作| SIM900, 电话, 短信, 远程控制

最近......应该说是搞了很长时间的东西了。

在搞一个自己很久很久就想做的东西。简要说一下功能吧。

这个东西有3个按键。暂且叫它们为Key1,Key2和Set吧。其中还有两个继电器S1和S2,一个单片机(STC12LE5A60S2),一个SIM900A模块。简单的就这些东西。我也不会写博文,描述的功能很乱,暂且就这么写吧。我也不知道大家看得懂吗。

 

功能呢。

如果按键Key1被按下,则继电器S1翻转状态。再次按Key1,则继电器S1的状态再次翻转。相同原理按键Key2同样原理控制继电器S2。这个都是比较容易实现的。

现在说一下电话控制功能。也就是说当我打电话给模块的时候,单片机会通过串口收到数据

RING
+CLIP: "18158113280",161,"",,"",0

然后单片机会通过读取串口数据来获得来电电话号码为:18158113280。再然后,单片机将这个电话号码和自己之前存在eepom中的主人电话号码相比对。如果电话号码相同,则控制继电器S1状态翻转。然后发送ATH挂掉电话。如果电话号码不一致则不做任何处理。

然后就是短信控制了。当我向模块发送短信内容:继电器S1打开。则继电器S1打开。当我向模块发送短信内容:继电器S1关闭。则继电器S1关闭。同样也可以这样控制继电器S2。只是将短信内容换成继电器S2打开和继电器S2关闭就可以了。

目前就着三个功能。在制作过程中,论坛里的好友辛昕给予了我无私的帮助。在这儿先感谢一下。可是现在我还是有很多疑惑。就是我在网上下载的一些例程百篇一律。几乎都是出自一处。例如下面这段。

 while(!Hand("OK"))//与GSM模块握手,判断是否收到GSM模块返回的OK
 {
  Uart2SendStr("AT\r");//握手,同步波特率。
  DelaySec(1);//延时 
 }

无一例外的都是这种模式。发送完一串AT命令字符。然后等待1秒。然后检测收到的字符串里面有没有OK这两个字。如果有,则说明握手成功,跳出while循环。如果没有,则继续发送AT。直到收到OK为止。这样就很容易出现问题。但是我也不知道该怎么解决这个问题。

其实SIM900A的数据手册上写的很清楚。就是SIM900的回复命令都是以0D 0A开头,中间是内容,然后以0D 0A结尾。例如下面:

0D 0A 4F 4B 0D 0A                   //这是SIM900回复的内容:OK

但是有的命令就不一样了。举个例子。当有电话打进来的时候。你会在串口截获下面这组字符串:

0D 0A 52 49 4E 47 0D 0A 0D 0A 2B 43 4C 49 50 3A 20 22 31 38 31 35 38 31 31 33 32 38 30 22 2C 31 36 31 2C 22 22 2C 2C 22 22 2C 30 0D 0A

其中绿色字体是单词RING。蓝色字体是我的手机号码:18158113280.反正大家看到了吗。这里面有四组0D 0A。是吧。很恼人。我就不知道串口数组该怎么处理了。

因为我不知道这组数据什么时候收完,什么时候该清掉。说了这么多我还是没有说到自己困扰的地方。我想问一下我怎么处理串口数组的收发数呢。我把我自己的代码贴出来让大家看一下吧。代码还没完善好。所以有些地方读起来可能比较费劲。

#include "stc12c5a.h"
#include <string.h>
#include <intrins.h>
#define uchar unsigned char
#define uint  unsigned int
#define UART1_PRIO 2  // 串口1中断优先级2
#define UART2_PRIO 3  // 串口2中断优先级3
#define MAXBUF 200
#define MAXRCV 200

/*定义单片机的IO口*/
sbit LED2=P2^7; //定义LED指示灯I/O口
sbit LED3=P2^6; //定义LED指示灯I/O口  黄色灯
sbit LED4=P2^5; //定义LED指示灯I/O口  蓝色灯
sbit KEY1=P2^2; //定义按键I/O口
sbit KEY2=P2^1; //定义按键I/O口
sbit KEY_Set=P2^0; //定义按键I/O口
sbit SIM_900A_STAR=P2^4;//定义SIM900开机
sbit Buzzer=P1^0;//定义蜂鸣器

//以下是开机后单片机所发送的一些指令。
uchar AT_DATA_1[] = {0x41,0x54,0x2B,0x43,0x4D,0x47,0x52,0x3D,0x31,0x0D,0x0A};//AT+CMGR=1   读1号短信位置。
uchar AT_DATA_2[] = {0x41,0x54,0x0D,0x0A};//AT  握手
uchar AT_DATA_3[] = {0x41,0x54,0x0D,0x0A};//ATH  挂电话

uchar  GsmRcv[MAXRCV] = {0};
uchar  DebugBuf_U2[MAXBUF] = {0};
uchar  DebugBuf_U1[MAXBUF] = {0};

uchar  Boss_Tel_NO[14]={0};//主人电话号码
uchar  New_Tel_NO[11]={0};//新来电/新短信电话号码
uchar  Boss_Feixin_NO[9]={0};//主人飞信号码
uchar  New_Feixin_NO[9]={0};//新飞信电话号码


uchar  SEND_SBUF[20] = {0};//串口发送字符串数组

uchar GsmRcvCnt = 0;

uchar SEND_NUM=0;//发送数组中字节数
uchar SEND=0;//字符发送个数


uint  timer0_cnt = 0; //秒定时器
uint  timer0_mcnt = 0;//毫秒定时器
uint  sec_cnt = 0;
uint  msec_cnt = 0;
uchar SBUF2_tmp = 0;//定义串口2缓存寄存器
uchar check=0;//校验符。F

uchar Address_Message=1;//新来的短信地址号码。
bit   CleanGsmRcv_Enable=0;//置保护位。不准清GsmRcv。1:不可以清buf。0:可以清buf。
uchar Number_0D_0A_Message=0;//读短信0D 0A组合个数寄存器。

uint  Key1_TimeCnt=0; //按键去抖动延时计数器
bit   Key1_Lock=0; //按键触发后自锁的变量标志
uint  Key2_TimeCnt=0; //按键去抖动延时计数器
bit   Key2_Lock=0; //按键触发后自锁的变量标志
uint  Key_Set_TimeCnt=0; //按键去抖动延时计数器
bit   Key_Set_Lock=0; //按键触发后自锁的变量标志

uint  Buzzer_Open_time=0;
uint  Buzzer_Closed_time=0;
uchar  Buzzer_Number=0;//蜂鸣器发声变量
uchar Buzzer_flag=0;//蜂鸣器鸣叫类型标志位
uchar SBUF_flag  =0;//串口回复类型标志位。
bit   Buzzer_condition=0;//蜂鸣器是在鸣叫还是静音
bit   Buzzer_Doing=0;//判断蜂鸣器是否正在工作,如果没工作,就给参数赋值。

bit   rev_start = 0; //标志位为1,开始接收
bit   GsmRcv_dispose_flag = 0; //告诉主函数可以解析数据了。0:不能解析。1:可以解析。
bit   GSM_RECEIVE_flag=0;//当单片机收到OK时,就将这个位置1.

void initialise();//系统初始化
void Timer0Init();//定时器初始化
char Uart1Init(char smod,char brtx12,uchar reload);//串口1初始化
char Uart2Init(char s2smod,char brtx12,uchar reload);//串口2初始化
void DelaySec(uint sec);//秒延时函数
void DelaymSec(uint msec);//豪秒延时函数
void CleanGsmRcv();//清除buf内容
void Buzzer_SCAN();//蜂鸣器
void KEY_SCAN();//按键扫描
void SBUF_flag_SCAN();//串口字符串处理函数


void main()//主函数函数在这里面运行

    initialise();//系统初始化  GsmRcv_dispose_flag = 0;//串口数据处理标志。当处理完毕,就会将其置零。
 DelaymSec(100); 
 DelaySec(1);

 Boss_Tel_NO[1]=0x31;//主人电话号码
 Boss_Tel_NO[2]=0x38;
 Boss_Tel_NO[3]=0x31;
 Boss_Tel_NO[4]=0x35;
 Boss_Tel_NO[5]=0x38;
 Boss_Tel_NO[6]=0x31;
 Boss_Tel_NO[7]=0x31;
 Boss_Tel_NO[8]=0x33;
 Boss_Tel_NO[9]=0x32;
 Boss_Tel_NO[10]=0x38;
 Boss_Tel_NO[11]=0x30;

 Boss_Feixin_NO[1]=0x32;//主人飞信号码
 Boss_Feixin_NO[2]=0x37;
 Boss_Feixin_NO[3]=0x33;
 Boss_Feixin_NO[4]=0x37;
 Boss_Feixin_NO[5]=0x38;
 Boss_Feixin_NO[6]=0x32;
 Boss_Feixin_NO[7]=0x34;
 Boss_Feixin_NO[8]=0x31;
 Boss_Feixin_NO[9]=0x39;

 while(GSM_RECEIVE_flag==0)
 {
  strcpy(SEND_SBUF,AT_DATA_2);//将字符串AT赋给字符串SEND_SBUF
  SEND_NUM = strlen(SEND_SBUF);//所发AT命令字节个数。
  S2BUF = SEND_SBUF[0];
  DelaySec(1);//延时1秒
 }
 GSM_RECEIVE_flag=0;

 while(GSM_RECEIVE_flag==0)
 {
  strcpy(SEND_SBUF,AT_DATA_2);//将字符串AT赋给字符串SEND_SBUF
  SEND_NUM = strlen(SEND_SBUF);//所发AT命令字节个数。
  S2BUF = SEND_SBUF[0];
  DelaySec(1);//延时1秒
 }
 GSM_RECEIVE_flag=0;

 while(GSM_RECEIVE_flag==0)
 {
  strcpy(SEND_SBUF,AT_DATA_2);//将字符串AT赋给字符串SEND_SBUF
  SEND_NUM = strlen(SEND_SBUF);//所发AT命令字节个数。
  S2BUF = SEND_SBUF[0];
  DelaySec(1);//延时1秒
 }
 GSM_RECEIVE_flag=0;

 while(1)
 {
  
 if(!SBUF_flag==0)
  { 
   GsmRcv_dispose_flag=0;//锁住,不再进入SBUF_flag_SCAN      
   switch(SBUF_flag)//判断SBUF_flag来判断应该如何再次通信
   {
    case 0://      
      SBUF_flag=0;             
     break; 
    case 1://
      SBUF_flag=0;//将串口回复类型标志位置零。
      SEND_SBUF[0]=0x41;//AT+CMGD=Address  删除所读短信
     SEND_SBUF[1]=0x54;
     SEND_SBUF[2]=0x2B;
     SEND_SBUF[3]=0x43;
     SEND_SBUF[4]=0x4D;
     SEND_SBUF[5]=0x47;
     SEND_SBUF[6]=0x44;
     SEND_SBUF[7]=0x3D;
     SEND_SBUF[8]=Address_Message;
     SEND_SBUF[9]=0x0D;
     SEND_SBUF[10]=0x0A;
     SEND_NUM=10;
     S2BUF = SEND_SBUF[0];//启动发送字符串命令                
     break;
    case 2:// 读新来的短信 0x41,0x54,0x2B,0x43,0x4D,0x47,0x52,0x3D,0x31,0x0D,0x0A
     SBUF_flag=0;//将串口回复类型标志位置零。
      SEND_SBUF[0]=0x41; //AT+CMGR=1
     SEND_SBUF[1]=0x54;
     SEND_SBUF[2]=0x2B;
     SEND_SBUF[3]=0x43;
     SEND_SBUF[4]=0x4D;
     SEND_SBUF[5]=0x47;
     SEND_SBUF[6]=0x52;
     SEND_SBUF[7]=0x3D;
     SEND_SBUF[8]=Address_Message;
//     SEND_SBUF[8]=0x31;
     SEND_SBUF[9]=0x0D;
     SEND_SBUF[10]=0x0A;
     SEND_NUM=10;
     S2BUF = SEND_SBUF[0];//启动发送字符串命令
//     strcpy(SEND_SBUF,AT_DATA_1);//将字符串AT赋给字符串SEND_SBUF
//     SEND_NUM = strlen(SEND_SBUF);//所发AT命令字节个数。
//     S2BUF = SEND_SBUF[0];        
     break;
    case 3://
     SBUF_flag=0;//将串口回复类型标志位置零。
      SEND_SBUF[0]=0x41; //AT+CMGR=1
     SEND_SBUF[1]=0x54;
     SEND_SBUF[2]=0x2B;
     SEND_SBUF[3]=0x43;
     SEND_SBUF[4]=0x4D;
     SEND_SBUF[5]=0x47;
     SEND_SBUF[6]=0x52;
     SEND_SBUF[7]=0x3D;
     SEND_SBUF[8]=0x31;
//     SEND_SBUF[8]=0x31;
     SEND_SBUF[9]=0x0D;
     SEND_SBUF[10]=0x0A;
     SEND_NUM=10;
     S2BUF = SEND_SBUF[0];//启动发送字符串命令
//     strcpy(SEND_SBUF,AT_DATA_1);//将字符串AT赋给字符串SEND_SBUF
//     SEND_NUM = strlen(SEND_SBUF);//所发AT命令字节个数。
//     S2BUF = SEND_SBUF[0];        
     break;
      SBUF_flag=0;             
     break;
    default:
      SBUF_flag=0;
      break;
   }
   
  }                      
    }   
}
void initialise()//系统初始化
{  
// P2M0=0xF0;//设置P2口输入输出
// P2M1=0x07;//         
 
// P1M0=0x01;//设置蜂鸣器为输出
// P1M1=0x00;//
  
 Timer0Init();//定时器0初始化
 Uart1Init(0,1,253);//初始化串口1,设置波特率115200
 Uart2Init(0,1,253);//初始化串口2,设置波特率115200
 IPH=0x10;
 IP=0x02;
 IP2H=0x01;
 IP2=0x01; 

 LED2=1; //打开LED
 LED3=1;//关闭LED
 LED4=1;//关闭LED
 KEY1=1; //关闭LED
 KEY2=1;
 KEY_Set=1;
 Buzzer=1;
 SIM_900A_STAR=1;
}
void Timer0Init()//初始化定时器0
{
 TMOD=0x01;         //设置定时器0为工作方式1。16位定时器/计数器,TL0,TH0全用。
 TH0=0xFC ;         //放入初值,11.0592M,1ms。计算方法:65535-(1ms/1.085μs)=64614=FC66H。
 TL0=0x66;     //上式中。1ms代表定时器周期。1.085μs=12/11.0592。其中11.0592代表的是晶振频率。
 // 设置定时器0中断优先级(优先级1)
// IPH &= (~PT0H); //定时器0中断优先级控制高位 注意:IPH不可以位寻址
// PT0 = 1;   //定时器0中断优先级控制低位   PT0H=0 PT0=1  定时器0中断为优先级1中断
 EA=1;         //开总中断
 ET0=1;        //开定时器0中断
    TR0=1;        //启动定时器0
}
char Uart1Init(char smod,char brtx12,uchar reload)//串口1初始化函数  0,1,253
{
 SCON =  0X50;//8位可变波特率,无奇偶位(SM0=0,SM1=1)方式1,使能串口接收模块(REN=1)
 BRT = reload;//设置独立波特率发生器波特率 

 if(smod == 1)//备注:串口设置位独立波特率提供波特率,和串口2使用同一个波特率,也可以使用定时器1来提供波特率
 {
  PCON |= SMOD;   //SMOD = 1;//波特率倍速位
 }
 else if(smod == 0)
 {
  PCON &= (~SMOD);   //SMOD = 0;//取消波特率倍速位
 }
 else
 {
  return -1;//输出参数: -1  smod位错误,没有写入0/1
 }
  
 if(brtx12 == 1)
 {
  AUXR |= BRTx12;//BRTx12 = 1;1T模式 
 }
 else if(brtx12 == 0)
 {
  AUXR &= (~BRTx12);//BRTx12 = 0;12T模式  
 }
 else
 {
  return -2;//输出参数: -2  brtx12位错误,没有写入0/1
 } 
   AUXR |= S1BRS;//串口设置为使用独立波特率发生器   S1BRS默认值为0。但是在系统头文件中是0x01。        
 AUXR |= BRTR;//开启波特率发生器        BRTR 默认值为0。但是在系统头文件中是0x10。
 //设置串口1中断优先级
// if (UART1_PRIO & 0x02)    //设置串口2的优先级为2   PSH=1   PS=0 
// {
//  IPH |= PSH;  //置1;
// }
// else
// {
//  IPH &= ~PSH; //置0;
// }
//  if (UART1_PRIO & 0x01)
// {
//  PS = 1;    //置1;
// }
// else
// {
//  PS = 0;    //置0
// }                    
 ES = 1;    //开串口中断
 EA = 1;    //开总中断
 return 0; 
}

char Uart2Init(char s2smod,char brtx12,uchar reload)//串口2初始化函数函数
{
 S2CON = 0X50;//8位可变波特率,无奇偶位
 BRT = reload;//设置独立波特率发生器波特率 reload寄存器数值   0-255
 //函数功能:初始化用于连接gprs的串口2 ,串口2只能设置为独立波特率提供波特率,并打开串口2中断和全局中断
 if(s2smod == 1)
 {
  AUXR |= S2SMOD;   //S2SMOD = 1;//波特率倍速位
 }
 else if(s2smod == 0)
 {
  AUXR &= (~S2SMOD);   //S2SMOD = 0;//取消波特率倍速位
 }
 else
 {
  return -1;//输出参数: -1  s2smod位错误,没有写入0/1
 }
  
 if(brtx12 == 1)
 {
  AUXR |= BRTx12;//BRTx12 = 1;1T模式 
 }
 else if(brtx12 == 0)
 {
  AUXR &= (~BRTx12);//BRTx12 = 0;12T模式  
 }
 else
 {
  return -2;//输出参数: -2  brtx12位错误,没有写入0/1
 }
   AUXR |= S1BRS;//串口设置为使用独立波特率发生器   S1BRS默认值为0。但是在系统头文件中是0x01。           
 AUXR |= BRTR;//开启波特率发生器
// if (UART2_PRIO & 0x02)// 设置串口2的中断级别最高。为优先级3.  只要与的结果不为0,就表示为1.
// {
//  IP2H |= PS2H; //置1;
// }
// else
// {
//  IP2H &= ~PS2H;  //置0;
// }
//  if (UART2_PRIO & 0x01)
// {
//  IP2 |= PS2;  //置1
// }
// else
// {
//  IP2 &= ~PS2; //置0;
// }                      
 IE2 |= ES2;// ES2 = 1;    //允许串口2中断
 EA = 1;    //开总中断
 return 0; 
}


void Uart1InterruptReceive() interrupt 4//串口1发送接收中断函数
{//备注:接收函数内部不可以放入其他的中断或者发送函数,否则影响接收数据
// ET0=0;        //开定时器0中断
 ES=0;//关串行口中断
 if(TI)  //如果是发送中断,则不做任何处理
 {     
  if(SEND>=SEND_NUM)//数据串发送完毕
  {
   SEND=0;
   SEND_NUM=0;
  }
  else
  {
   SEND++;
   SBUF = SEND_SBUF[SEND]; //发送一个字节
  }
  TI = 0;   //清除发送中断标志位          
 }
 if(RI)
 {  
  RI=0;//接收中断信号清零,表示将继续接收   SEND_NUM   
 }
 ES=1;//开串行口中断
// ET0=1;        //开定时器0中断
}
void Uart2InterruptReceive() interrupt 8//串口2发送接收中断函数
{
// ET0=0;        //关闭定时器0中断
 IE2 &= (~ES2);//关闭串口2中断//ES2 = 0;ES2的复位值是0. 
 if(S2CON & S2RI) //if(S2RI == 1),如果有中断产生。即S2RI为1.
 { 
  S2CON &= (~S2RI);//将S2RI置0。
  SBUF2_tmp = S2BUF;//将串口2缓存中的数据放到tmp中。&& (GsmRcvCnt==0)   && (GsmRcv_dispose_flag == 0)
  //开始接收到了完整的AT指令回复,完整的AT指令是以0x0a 0x0d开头的。故作此判断,在接收的过程中是否收到0x0a 0x0d
  //如果数据包头出现的数据不是0D 0A,则说明这组数据错误,扔掉。
  if ((SBUF2_tmp == 0x0D) &&(rev_start == 0) )  //如果收到字符0d而且串口寄存数组里还没有收到下一个0D数据。
  {             //表明有数据进来了。则可以接收这串数据。置标志位。
   rev_start = 1; //标志位为1,开始接收
   GsmRcvCnt = 0; //将串口接收数组指针指到0位置
   Number_0D_0A_Message=0;//将计数次数清零
  }  
  if (rev_start == 1)  //标志位为1,开始接收
  {
   GsmRcv[GsmRcvCnt] = SBUF2_tmp;  //字符存到数组中  //接收缓存
//   GsmRcvAt[GsmRcvCnt] = SBUF2_tmp;  //字符存到数组中  //接收缓存
   GsmRcvCnt++;   
   if ( (GsmRcvCnt>=3)&&(GsmRcv[GsmRcvCnt-2]==0x0D) && (GsmRcv[GsmRcvCnt-1] == 0x0A)  ) //如果上一个字节是0d,而且串口寄存数组字节个数大于3。
   {                      //则说明不是第一个0d 0a。是一串数接收完了。
    if((GsmRcv[2]==0x2B) && (GsmRcv[3]==0x43) && (GsmRcv[4]==0x4D) && (GsmRcv[5]==0x47) && (GsmRcv[6]==0x52))
    { //如果是+CMGR,说明正在读短信。需要将下面的数据全部接收后再清除GsmRcv。置保护位。
     Number_0D_0A_Message++;
     if(Number_0D_0A_Message==4) //说明收到了完整的短信息。
     {
      GsmRcv_dispose_flag = 1; //告诉主函数可以解析数据了
      CleanGsmRcv_Enable=0;//置保护位。收完一串数据了。可以清GsmRcv。
      Number_0D_0A_Message=0;//将计数次数清零     
     }
     else
     {
     CleanGsmRcv_Enable=1;//置保护位。不准清GsmRcv。
     GsmRcv_dispose_flag = 0; //告诉主函数不可以解析数据
     }
    }
    else if((GsmRcv[2]==0x52) && (GsmRcv[3]==0x49) && (GsmRcv[4]==0x4E) && (GsmRcv[5]==0x47))  
    { //如果是RING,说明是来电电话。需要将下面的数据全部接收后再清除GsmRcv。置保护位。
     Number_0D_0A_Message++;
     if(Number_0D_0A_Message==3) //说明收到了完整的来电电话号码信息。
     {
      GsmRcv_dispose_flag = 1; //告诉主函数可以解析数据了
      CleanGsmRcv_Enable=0;//置保护位。收完一串数据了。可以清GsmRcv。
      Number_0D_0A_Message=0;//将计数次数清零     
     }
     else
     {
     CleanGsmRcv_Enable=1;//置保护位。不准清GsmRcv。
     GsmRcv_dispose_flag = 0; //告诉主函数不可以解析数据
     }
    }
    else
    {
     Number_0D_0A_Message=0;//将计数次数清零
     CleanGsmRcv_Enable=0;//置保护位。收完一串数据了。可以清GsmRcv。
     GsmRcv_dispose_flag = 1; //告诉主函数可以解析数据了
    }                                                                   
   }   
  }//收到了完整的AT指令,完整的AT指令是以0x0a 0x0d结尾的。故作此判断,在接收的过程中是否收到0x0a 0x0d    
 }
 if(S2CON & S2TI) //if(S2TI == 1),如果有中断产生。即S2TI为1.
 { 
  S2CON &= ~S2TI;  //将S2TI置0。清除发送中断标志位。
  if(SEND>=SEND_NUM)//数据串发送完毕
  {
   SEND=0;
   SEND_NUM=0;
  }
  else
  {
   SEND++;
   S2BUF = SEND_SBUF[SEND]; //发送一个字节
  }      
 }
// ET0=1;        //打开定时器0中断 
 IE2 |= ES2;//ES2 = 1;
}
void timer0() interrupt 1//定时器0中断,每1ms执行一次中断,中断内部重新赋值
{  
 TH0=0xFC;//对定时器重装初值,1毫秒。
 TL0=0x66; 
 timer0_cnt++;
 if(timer0_cnt == 1000)//是否到了1秒钟
 {
  timer0_cnt = 0;
  sec_cnt++;
  LED2=~LED2;  
 }
 timer0_mcnt++;
 if(timer0_mcnt == 1)//是否到了10毫秒钟
 {
  timer0_mcnt = 0;
  msec_cnt++;
 }
 KEY_SCAN();//按键扫描 
 Buzzer_SCAN();//蜂鸣器扫描
 SBUF_flag_SCAN();//串口字符串处理函数    
}
void DelaySec(uint sec)//定时函数,单位是秒。
{
 sec_cnt = 0;
 while(sec_cnt < sec);    
}

void DelaymSec(uint msec)//定时函数,单位是毫秒。
{
 msec_cnt = 0;
 while(msec_cnt < msec);  
}
void CleanGsmRcv()//清除GPRS接收缓冲数据初始化函数
{
 uchar i = 0;
 for(i=0; i<=MAXRCV; i++)
 {
  GsmRcv[i] = 0; 
 }
 GsmRcvCnt = 0;//将GsmRcv[]数据清除,并且使缓冲指针移到第一位。 
}
void KEY_SCAN()//按键扫描
{
/****************************************************************************/
  if(KEY1==1)//IO是高电平,说明按键没有被按下,这时要及时清零一些标志位
  {
     Key1_Lock=0; //按键自锁标志清零
     Key1_TimeCnt=0;//按键去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。
  }
  else if(Key1_Lock==0&&KEY1==0)//有按键按下,且是第一次被按下
  {
     Key1_TimeCnt++;  //延时计数器
     if(Key1_TimeCnt>=20)
     {    
  Buzzer_flag=1;
        Key1_TimeCnt=0;//清计数器
        Key1_Lock=1;  //自锁按键置位,避免一直触发。当置1后,程序就再也不会在这个循环里跑了。
  LED3=~LED3;
     }
  }
/****************************************************************************/
  if(KEY2==1)//IO是高电平,说明按键没有被按下,这时要及时清零一些标志位
  {
     Key2_Lock=0; //按键自锁标志清零
     Key2_TimeCnt=0;//按键去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。
  }
  else if(Key2_Lock==0&&KEY2==0)//有按键按下,且是第一次被按下
  {
     Key2_TimeCnt++;  //延时计数器
     if(Key2_TimeCnt>=20)
     { 
   SBUF_flag=3;  
  Buzzer_flag=2;
        Key2_TimeCnt=0;//清计数器
        Key2_Lock=1;  //自锁按键置位,避免一直触发。当置1后,程序就再也不会在这个循环里跑了。
  LED4=~LED4;  
     }
  }
/****************************************************************************/
  if(KEY_Set==1)//IO是高电平,说明按键没有被按下,这时要及时清零一些标志位
  {
     Key_Set_Lock=0; //按键自锁标志清零
     Key_Set_TimeCnt=0;//按键去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。
  SIM_900A_STAR=1;
  }
  else if(Key_Set_Lock==0&&KEY_Set==0)//有按键按下,且是第一次被按下
  {
     Key_Set_TimeCnt++;  //延时计数器
     if(Key_Set_TimeCnt>=20)
     { 
      
  Buzzer_flag=3;
        Key_Set_TimeCnt=0;//清计数器
        Key_Set_Lock=1;  //自锁按键置位,避免一直触发。当置1后,程序就再也不会在这个循环里跑了。
  SIM_900A_STAR=0;//SIM900开机  
     }
  }
/****************************************************************************/
}
void Buzzer_SCAN()//蜂鸣器
{
  switch(Buzzer_flag)//判断Buzzer_flag来判断应该如何鸣叫
 {
  case 0://蜂鸣器静音         
   Buzzer=1;//静音
   Buzzer_condition=0;//蜂鸣器是在响还是没响
   Buzzer_Doing=0;//蜂鸣器不在工作状态
   Buzzer_flag=0;//选择叫声标志位清零
   Buzzer_Number=0;//响次数清零
   Buzzer_Open_time=0;//响时间清零
   Buzzer_Closed_time=0;//不响时间清0
   break; 
  case 1://蜂鸣器响5声
    if(Buzzer_Doing==0)//判断蜂鸣器是否正在工作,如果没工作,就给参数赋值。
   {
    Buzzer_Number=4;//响4声
    Buzzer_Open_time=30;//响50毫秒
    Buzzer_Closed_time=30;//不响50毫秒
    Buzzer_Doing=1;//重新赋值,不再进入此循环。
   }
   else
   {     
    if( (Buzzer_Number>0)&&(Buzzer_Doing==1) )//没有达到响声次数
    {
      if(Buzzer_condition)//如果正在响,就进入响延时状态1
      {
     
       Buzzer_Open_time--; 
       if(Buzzer_Open_time>0)
       {
        Buzzer=0;//鸣叫       
       }
       else
       {
        Buzzer_condition=!Buzzer_condition;//翻转状态为静音
        Buzzer_Open_time=30;//计数器重新赋值
        Buzzer_Number--;//叫声次数减1
//        SBUF = Buzzer_Number;
       }     
      }
      else//如果没在响,就进入不响延时状态0
      {
       Buzzer_Closed_time--; 
       if(Buzzer_Closed_time>0)
       {
        Buzzer=1;//静音       
       }
       else
       {
        Buzzer_condition=!Buzzer_condition;//翻转状态为鸣叫
        Buzzer_Closed_time=30;//计数器重新赋值
       }
      }
    }
    else //鸣叫完毕,除去标志位。
    { 
      Buzzer=1;//静音
      Buzzer_condition=0;//蜂鸣器是在响还是没响
      Buzzer_Doing=0;//蜂鸣器不在工作状态
      Buzzer_flag=0;//选择叫声标志位清零
      Buzzer_Number=0;//响次数清零
       Buzzer_Open_time=0;//响时间清零
       Buzzer_Closed_time=0;//不响时间清零
    }
   }              
   break;
       
  case 2://蜂鸣器响2声
    if(Buzzer_Doing==0)//判断蜂鸣器是否正在工作,如果没工作,就给参数赋值。
   {
    Buzzer_Number=4;//响4声
    Buzzer_Open_time=20;//响50毫秒
    Buzzer_Closed_time=20;//不响50毫秒
    Buzzer_Doing=1;//重新赋值,不再进入此循环。
   }
   else
   {     
    if( (Buzzer_Number>0)&&(Buzzer_Doing==1) )//没有达到响声次数
    {
      if(Buzzer_condition)//如果正在响,就进入响延时状态1
      {
     
       Buzzer_Open_time--; 
       if(Buzzer_Open_time>0)
       {
        Buzzer=0;//鸣叫       
       }
       else
       {
        Buzzer_condition=!Buzzer_condition;//翻转状态为静音
        Buzzer_Open_time=20;//计数器重新赋值
        Buzzer_Number--;//叫声次数减1
//        SBUF = Buzzer_Number;
       }     
      }
      else//如果没在响,就进入不响延时状态0
      {
       Buzzer_Closed_time--; 
       if(Buzzer_Closed_time>0)
       {
        Buzzer=1;//静音       
       }
       else
       {
        Buzzer_condition=!Buzzer_condition;//翻转状态为鸣叫
        Buzzer_Closed_time=20;//计数器重新赋值
       }
      }
    }
    else //鸣叫完毕,除去标志位。
    { 
      Buzzer=1;//静音
      Buzzer_condition=0;//蜂鸣器是在响还是没响
      Buzzer_Doing=0;//蜂鸣器不在工作状态
      Buzzer_flag=0;//选择叫声标志位清零
      Buzzer_Number=0;//响次数清零
       Buzzer_Open_time=0;//响时间清零
       Buzzer_Closed_time=0;//不响时间清零
    }
   }              
   break;
  case 3://蜂鸣器响2声
    if(Buzzer_Doing==0)//判断蜂鸣器是否正在工作,如果没工作,就给参数赋值。
   {
    Buzzer_Number=4;//响4声
    Buzzer_Open_time=10;//响50毫秒
    Buzzer_Closed_time=30;//不响50毫秒
    Buzzer_Doing=1;//重新赋值,不再进入此循环。
   }
   else
   {     
    if(Buzzer_Number>0)//没有达到响声次数
    {
      if(Buzzer_condition)//如果正在响,就进入响延时状态1
      {
       Buzzer_Open_time--; 
       if(Buzzer_Open_time>0)
       {
        Buzzer=0;//鸣叫       
       }
       else
       {
        Buzzer_condition=!Buzzer_condition;//翻转状态为静音
        Buzzer_Open_time=10;//计数器重新赋值
        Buzzer_Number--;//叫声次数减1
       }     
      }
      else//如果没在响,就进入不响延时状态0
      {
       Buzzer_Closed_time--; 
       if(Buzzer_Closed_time>0)
       {
        Buzzer=1;//静音       
       }
       else
       {
        Buzzer_condition=!Buzzer_condition;//翻转状态为鸣叫
        Buzzer_Closed_time=30;//计数器重新赋值
       }
      }
    }
    else//鸣叫完毕,除去标志位。
    {     
      Buzzer=1;//静音
      Buzzer_condition=0;//蜂鸣器是在响还是没响
      Buzzer_Doing=0;//蜂鸣器不在工作状态
      Buzzer_flag=0;//选择叫声标志位清零
      Buzzer_Number=0;//响次数清零
       Buzzer_Open_time=0;//响时间清零
       Buzzer_Closed_time=0;//不响时间清零
    }
   }              
   break;

  default:
    Buzzer=1;//静音
   Buzzer_flag=0;
    break;
 }
}
void SBUF_flag_SCAN()//串口字符串处理函数。用于触发各种消息。
{
 if(GsmRcv_dispose_flag)//判断是否可以解析串口字符串中的数据
 {
  if( (GsmRcv[2]==0x4F) && (GsmRcv[3]==0x4B) )//检测到:OK
  {
//   SBUF_flag=3;
   GSM_RECEIVE_flag=1;//收到OK就将这个位置1.
   Buzzer_flag=2;
  }
  else if( (GsmRcv[2]==0x2B) && (GsmRcv[3]==0x43) && (GsmRcv[4]==0x4D) && (GsmRcv[5]==0x54) && (GsmRcv[6]==0x49))//检测到:+CMTI
  {    //检测到有短信
   Address_Message=GsmRcv[14]; //读取短信地址。
   SBUF_flag=2;
//   Buzzer_flag=2;
  }
//  else if( (GsmRcv[2]==0x52) && (GsmRcv[3]==0x49) && (GsmRcv[4]==0x4E) && (GsmRcv[5]==0x47) )//检测到:RING
//  {    //检测到有电话
//   SBUF_flag=3;
//   Buzzer_flag=3;
//  }
  else if( (GsmRcv[2]==0x45) && (GsmRcv[3]==0x52) && (GsmRcv[4]==0x52) && (GsmRcv[5]==0x4F)&& (GsmRcv[6]==0x52) )//检测到:ERROR
  {
   SBUF_flag=4;
  }
  else if( (GsmRcv[2]==0x2B) && (GsmRcv[3]==0x43) && (GsmRcv[4]==0x4D) && (GsmRcv[5]==0x47) && (GsmRcv[6]==0x52) )        
  {//读短信,判断。特定位置收到+CMGR

    
    if( (GsmRcv[42]==0x36) && (GsmRcv[43]==0x38) )//如果是68开头的号码。则为短信。
  {//判断短信
   
   New_Tel_NO[1]=GsmRcv[45];//新来电电话号码
   New_Tel_NO[2]=GsmRcv[44];
   New_Tel_NO[3]=GsmRcv[47];
   New_Tel_NO[4]=GsmRcv[46];
   New_Tel_NO[5]=GsmRcv[49];
   New_Tel_NO[6]=GsmRcv[48];
   New_Tel_NO[7]=GsmRcv[51];
   New_Tel_NO[8]=GsmRcv[50];
   New_Tel_NO[9]=GsmRcv[53];
   New_Tel_NO[10]=GsmRcv[52];
   New_Tel_NO[11]=GsmRcv[55];
   if(!strcmp(New_Tel_NO,Boss_Tel_NO))//电话号码与主人电话号码符号。进入下面括号内继续判断。    
     { //此句代表New_Tel_NOBoss_Tel_NO只要和Boss_Tel_NO一样,则进入到下面大括号里去执行命令。
     LED4=!LED4;
    }
  }
    if( (GsmRcv[42]==0x32) && (GsmRcv[43]==0x31) )//如果是21开头的号码。则为飞信。
  {//判断飞信
   New_Feixin_NO[1]=GsmRcv[46];//新来电电话号码
   New_Feixin_NO[2]=GsmRcv[49];
   New_Feixin_NO[3]=GsmRcv[48];
   New_Feixin_NO[4]=GsmRcv[51];
   New_Feixin_NO[5]=GsmRcv[50];
   New_Feixin_NO[6]=GsmRcv[53];
   New_Feixin_NO[7]=GsmRcv[52];
   New_Feixin_NO[8]=GsmRcv[55];
   New_Feixin_NO[9]=GsmRcv[54];
   if(!strcmp(New_Feixin_NO,Boss_Feixin_NO))// 飞信号码与主人飞信号码符号。进入下面括号内继续判断。   
     { //此句代表New_Feixin_NO只要和Boss_Feixin_NO一样,则进入到下面大括号里去执行命令。
     LED3=!LED3;
    }
  }
    else//否则为广告。
     {

  }
  SBUF_flag=1;    
  }
  else if( (GsmRcv[11]==0x43) && (GsmRcv[12]==0x4C) && (GsmRcv[13]==0x49) )//检测到CLIP。说明有电话打进来。      
  {//读电话号码,判断。Boss_Tel_NO1
  New_Tel_NO[1]=GsmRcv[18];//新来电电话号码
  New_Tel_NO[2]=GsmRcv[19];
  New_Tel_NO[3]=GsmRcv[20];
  New_Tel_NO[4]=GsmRcv[21];
  New_Tel_NO[5]=GsmRcv[22];
  New_Tel_NO[6]=GsmRcv[23];
  New_Tel_NO[7]=GsmRcv[24];
  New_Tel_NO[8]=GsmRcv[25];
  New_Tel_NO[9]=GsmRcv[26];
  New_Tel_NO[10]=GsmRcv[27];
  New_Tel_NO[11]=GsmRcv[28];
  if(!strcmp(New_Tel_NO,Boss_Tel_NO))//当数组New_Tel_NOBoss_Tel_NO与Boss_Tel_NO数组相等,则返回0.此句代表New_Tel_NOBoss_Tel_NO只要和Boss_Tel_NO一样,则进入到下面大括号里去执行命令。    
  {
   Buzzer_flag=2;
   LED3=!LED3;
   LED4=!LED4;
  }     
  }
  else
  {

  }
  if(CleanGsmRcv_Enable==0)//如果可以清,就清除。
  {
   CleanGsmRcv(); //清除串口数组的数据
  }
 
  GsmRcv_dispose_flag=0;
  rev_start = 0; //可以接收下一组数据了
 } 
}

发表评论 评论 (5 个评论)
回复 曹世鹏 2014-7-29 14:45
感觉自己写的这个东西晦涩难懂。菜鸟刚开始搞单片机。惭愧惭愧。继续完善。争取写出可读性高的代码来。
回复 曹世鹏 2014-7-29 23:54
没人看,没人评论。很不开心。
回复 曹世鹏 2014-7-30 14:04
最新总结的发送AT指令方法。
for(Send_Once = 0; Send_Once < Send_Once_Max; Send_Once ++)//最多防止出错三次。
                                        {
                                                Uart2SendStr("ATH\r\n");
                                                DelaySec(1);//延时1秒
                                                if(GSM_RECEIVE_flag)
                                                {
                                                        GSM_RECEIVE_flag=0;//清除标志位。
                                                        Send_Once=0;//计数归零。
                                                        break;
                                                }       
                                        }
这样就可以避免在一个地方总是发送。避免死机的时候用的。最多发三次,则退出循环。
回复 曹世鹏 2014-8-1 09:51
发送短信大家不要用txt模式发送。要用PDU模式。因为txt模式发送的短信电信的手机识别不了。不知道为神马。移动和联通的没问题。
回复 shi123jia 2015-1-27 09:26
“其中绿色字体是单词RING。蓝色字体是我的手机号码:18158113280.反正大家看到了吗。这里面有四组0D 0A”不知道这问题你解决了没有 我现在也在做单片机和SIM900a通讯的一个新项目

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

热门文章