前几天受老师之托,帮一个大四的学长搞毕业设计,于是这几天就在忙活这玩意儿,幸不辱命,终于在今天给搞出来了,从前也没搞过串口通信,这是我的错,学单片机这么久了,连这个都没接触过,不过现在算是补上了。
刚开始的几天真的是无从下手,看了些资料,最后和老师一起把GSM和单片机连接成功了,发了几条短信来控制灯的亮灭,倒是觉得还有点味道。然后就是用短信来对步进电机进行控制,开始的时候,进入了编程的误区,那就是心浮气躁,不能够冷静下来,而且没有换思路,这点很坑,要不然也不会折腾这么久了,很痛苦。
最开始电机用的是循环来控制的,后来发现不行,于是用了定时器中断来控制它,同样也是可以控制的,开始太傻了。最关键的问题就是,我用短信启动电机之后,它就无法再停下来,这个问题真的是纠结的我要吐,后来发现用定时器可以控制它停止,可是就是短信控制不了,后来发现一个很重要的点,那就是串口中断,例程是把状态判断放在主程序里面的,用个while(1)进行不断的判断,后来试着把判断放在串口中断程序里面,果然也是可行的,哦,对的,最重要的就是串口中断的优先级设置的不对,应该为高优先级的,这样的话才不会被电机执行的定时器中断所干扰,这样就可行了。于是懂得了真的是不能够太相信例程,那也只是人写出来的而已,写的人或许水平比较高,但是你得按实际情况来,绝对不能够照搬他的例程,不然有的你受的,一定要会转换思维。好吧,上张图:发了200条短信,才控制了这几个家伙。
附代码:
/************************************************************
程序说明:
首先要确定模块已经注册到网络
然后正确的硬件连接 P3.0-----STXD或者5VT P3.1-----SRXD或者5VR GND---GND(只要保证公地即可,没必要单独接一次)
然后确认你单片机上的晶振,根据晶振修改自己的程序。
推荐先将单片机与电脑相连,确定单片机发送的数据是正确的。如果发送的是乱码,请检查晶振与单片机的串口波特率。
*************************************************************/
/**
* 操作说明:
短信发送“LEDON”——打开所有LED灯
短信发送“LEDOFF”——关闭所有LED灯
短信发送“MADAON”——启动步进电机
短信发送“MADAOFF”——停止步进电机
*
**/
#include <REG51.H>
#include <string.H>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define speed 2
//Motor
sbit PH1 = P0^0; //定义管脚
sbit PH2 = P0^1;
sbit I01 = P0^2;
sbit I11 = P0^3;
sbit I02 = P0^4;
sbit I12 = P0^5;
//以下是板子上LED的配置,把Px_x改成自己对应的脚。
//以下是你的51单片机的晶振大小
//#define FOSC_110592M
#define FOSC_12M
sbit P10=P1^0;
sbit P11=P1^1;
sbit P12=P1^2;
sbit P13=P1^3;
sbit P14=P1^4;
sbit P15=P1^5;
void Go();
void delay(int);
void Uart1Sends(uchar *str);
void DelaySec(int sec);
uchar flag_rec_message;//接收到短信标志位
unsigned char flag_reced_mess=0;
unsigned char fenhao_num;//数据中分号的个数,用来区分短信数据中各个字段的内容
unsigned int rec_data_len_uart=0; //标记Buffer_Uart0接收数组
unsigned char flag_rec_message=0;//收到了一条短信提醒时的标志位,我没有SIM900A模块,为了能让单片机处理,所以直接让此标志位为1,你做的时候
//通过收到短信的提醒要置此标志位。
unsigned char flag_rec_message_data=0;//开始接收短信数据
unsigned char flag_start_rec_message;//开始处理短信数据标志位
unsigned char flag_read_or_un_message;//1 未读取过,0 读取过
unsigned char flag_send_result=0;
unsigned char message_data[20];//存储短信数据
unsigned char xdata temp_data_read[11],temp_data_tele_num[14],temp_data_date[21];
unsigned char idata Buffer_Uart0_Rec[25]={0}; //Uart0中断接收数组
unsigned char flag_return = 0;
unsigned char flag_time = 0;
unsigned int temp0 = (65535 - 10000) / 256;
unsigned int temp1 = (65535 - 10000) % 256;
//注意,无论接收到信号还是发送完信号,都会进中断服务程序的
/*初始化程序(必须使用,否则无法收发),此程序将会使用定时器1*/
void SerialInti()//初始化程序(必须使用,否则无法收发)
{
TMOD=0x21;//定时器1操作模式2:8位自动重载定时器
#ifdef FOSC_12M //在这里根据晶振大小设置不同的数值初始化串口
TH1=0xf3;//装入初值,波特率2400
TL1=0xf3;
#else
TH1=0xfd;//装入初值,波特率9600
TL1=0xfd;
#endif //end of SOC_12M
ET0 = 1;
TR0 = 0;
TH0 = temp0;
TL0 = temp1;
TR1=1;//打开定时器
SM0=0;//设置串行通讯工作模式,(10为一部发送,波特率可变,由定时器1的溢出率控制)
SM1=1;//(同上)在此模式下,定时器溢出一次就发送一个位的数据
REN=1;//串行接收允许位(要先设置sm0sm1再开串行允许)
PS = 1; //串口中断为高优先级,这一句可谓是神来之笔!!!
EA=1;//开总中断
ES=1;//开串行口中断
}
unsigned char hand(unsigned char *data_source,unsigned char *ptr)
{
if(strstr(data_source,ptr)!=NULL)
return 1;
else
return 0;
}
void clear_rec_data()
{
uchar i,temp_len;
temp_len=strlen(Buffer_Uart0_Rec);
if(temp_len>25)
{
temp_len=25;
}
for(i=0;i<temp_len;i++)
{
Buffer_Uart0_Rec[i]='\0';
}
rec_data_len_uart=0;
}
void clear_message_data()
{
unsigned char temp_len,i;
temp_len=strlen(message_data);
if(temp_len>20)
{
temp_len=20;
}
for(i=0;i<temp_len;i++)
{
message_data[i]='\0';
}
}
/*串行通讯中断,收发完成将进入该中断*/
void Serial_interrupt() interrupt 4
{
unsigned char temp_rec_data_uart0;
temp_rec_data_uart0 = SBUF;//读取接收数据
RI=0;//接收中断信号清零,表示将继续接收
if(flag_rec_message==1)//如果检测到收到一条短信,开始执行短信数据接收
{
if((temp_rec_data_uart0=='R')&&(rec_data_len_uart>5)) //如果接收到的数据‘R’,并且已经接了一些数据了,此时可能单片机开始接收短信数据
{
if((Buffer_Uart0_Rec[rec_data_len_uart-1]=='G')&&(Buffer_Uart0_Rec[rec_data_len_uart-2]=='M')&&(Buffer_Uart0_Rec[rec_data_len_uart-3]=='C')&&(Buffer_Uart0_Rec[rec_data_len_uart-4]=='+'))//说明收到了短信数据 +CMGR
{
flag_start_rec_message=1;//置开始接收短信数据标志位
fenhao_num=0;//重新开始根据逗号个数查找短信内容
rec_data_len_uart=0;//前接的数据无用了
flag_rec_message_data=0;
}
}
if(flag_start_rec_message==1)//收到短信数据才进行后续短信数据的提取
{
if(temp_rec_data_uart0=='"')//如果收到的数据是 ‘,’
{
fenhao_num++;
if(fenhao_num>11)//一次读取回来的短信数据中逗号的个数不可能超过11个,超过了还没处理完 说明数据有误
{
fenhao_num=0;
flag_rec_message=0;//不对短信数据进行处理
flag_start_rec_message=0;//无短信数据数据 ,好似不需要处理,待定
flag_rec_message_data=0;
}
switch (fenhao_num)
{
case 2: //后取短信是否读取
memcpy(temp_data_read,Buffer_Uart0_Rec+rec_data_len_uart-8,rec_data_len_uart-4);//多存一些
if(hand(temp_data_read,"UNREAD"))
{
flag_read_or_un_message=1;//没读取过
}
else
{
flag_read_or_un_message=0;//读取过
}
temp_data_read[rec_data_len_uart-3]='\0';
rec_data_len_uart=0x00;//前面数据处理完毕,重新接
break;
case 4: //temp_data_tele_num获取电话号码
memcpy(temp_data_tele_num,Buffer_Uart0_Rec+(rec_data_len_uart-13),13);//多存一些
rec_data_len_uart=0;//前面数据处理完毕,重新接
break;
case 6://空
rec_data_len_uart=0;//前面数据处理完毕,重新接
break;
case 7://时期开始
rec_data_len_uart=0;//前面数据处理完毕,重新接
break;
case 8: //temp_data_date,日期
memcpy(temp_data_date,Buffer_Uart0_Rec+1,20);//
flag_rec_message_data=1;//置开始接收短信数据标志位
fenhao_num=0;
rec_data_len_uart=0;
break;
default:
break;
}
}
if(flag_rec_message_data==1)//开始接收短信内容数据
{
if((temp_rec_data_uart0==0x0a)&&(Buffer_Uart0_Rec[rec_data_len_uart-1]==0x0d)&&(Buffer_Uart0_Rec[rec_data_len_uart-2]==0X4B)&&(Buffer_Uart0_Rec[rec_data_len_uart-3]==0x4F))//短信接收完毕
{
if((Buffer_Uart0_Rec[0]!=0x22)||(Buffer_Uart0_Rec[1]!=0x0d)||(Buffer_Uart0_Rec[2]!=0x0a))//数据有误
{ //数据舍弃
rec_data_len_uart=0;
fenhao_num=0;
flag_rec_message=0;//不对短信数据进行处理
flag_start_rec_message=0;//无短信数据数据 ,好似不需要处理,待定
}
else//短信数据正确,接收保存
{
memcpy(message_data,Buffer_Uart0_Rec+3,rec_data_len_uart-10);
rec_data_len_uart=0;
fenhao_num=0;
flag_rec_message=1;//清来短信标志位
flag_start_rec_message=0;//无短信数据数据 ,好似不需要处理,待定
flag_send_result=1;
message_data[rec_data_len_uart-9]='\0';
}
clear_rec_data();
}
//------------------测试完毕----------------------
}
}
}
Buffer_Uart0_Rec[rec_data_len_uart]=temp_rec_data_uart0;//接收数据
if((temp_rec_data_uart0=='I')&&(rec_data_len_uart>3))
{
if((Buffer_Uart0_Rec[rec_data_len_uart-1]=='T')&&(Buffer_Uart0_Rec[rec_data_len_uart-2]=='M')&&(Buffer_Uart0_Rec[rec_data_len_uart-3]=='C')&&(Buffer_Uart0_Rec[rec_data_len_uart-4]=='+'))
{
flag_rec_message=1;
flag_reced_mess=1;
}
}
rec_data_len_uart++;
if(rec_data_len_uart>24)
{
rec_data_len_uart=0; //从头开始接收数据
}
//////
if(flag_send_result==1)
{
flag_send_result=0;
flag_rec_message=0;
Uart1Sends("AT+CMGD=1,4\r\n"); //解析完毕,删除短信
if(hand(message_data,"LEDON"))
{
P1 = 0;
//flag_return = 1;
}
if(hand(message_data,"LEDOFF"))
{
P1 = 0xff;
}
if(hand(message_data,"MADAON"))
{
TR0 = 1;
}
if(hand(message_data,"MADAOFF"))
{
TR0 = 0;
P1 = 0x00;
}
clear_message_data();
}
if(flag_reced_mess==1)
{
_nop_();_nop_();
_nop_();_nop_();
_nop_();_nop_();
flag_reced_mess=0;
P15=~P15;//用来指示收到短信提示
DelaySec(1);//延时3秒
P15=0;
Uart1Sends("AT+CMGR=1\r\n");
//clear_rec_data();
}
}
void t0(void) interrupt 1
{
TH0 = temp0;
TL0 = temp1;
flag_time++;
Go();
if(flag_time == 10)
{
flag_time = 0;
P1 = ~P1;
}
}
void Uart1Send(uchar c)
{
SBUF=c;
while(!TI);//等待发送完成信号(TI=1)出现
TI=0;
}
//串行口连续发送char型数组,遇到终止号/0将停止
void Uart1Sends(uchar *str)
{
while(*str!='\0')
{
SBUF=*str;
while(!TI);//等待发送完成信号(TI=1)出现
TI=0;
str++;
}
}
//延时函数大概是1s钟,不过延时大的话不准...
void DelaySec(int sec)
{
uint i , j= 0;
for(i=0; i<sec; i++)
{
for(j=0; j<65535; j++)
{
}
}
}
void main()
{
uchar i = 0;
SerialInti();
P1=0;//所有LED 都亮
Uart1Sends("AT\r\n");
DelaySec(1);//延时3秒
Uart1Sends("AT\r\n");
DelaySec(1);//延时3秒
Uart1Sends("ATE0\r\n");
DelaySec(1);//延时3秒
//-----------配置接收短信方式----------------
Uart1Sends("AT+CMGF=1\r\n");
DelaySec(1);//延时3秒
Uart1Sends("AT+CSCS=\"GSM\"\r\n");
DelaySec(1);//延时3秒
Uart1Sends("AT+CMGD=1,4\r\n");
DelaySec(1);//延时3秒
P14=1; //提示初始化完成
while(1);
}
/***************************************
函数功能:产生单相四拍脉冲控制步进机
**************************************/
void Go()
{ //A
PH1 = 0; //PH1为0 则A线圈为反向电流
I01 = 0;
I11 = 0; //以最大电流输出
PH2 = 0; //PH2为0 则B线圈为反向电流
I02 = 1;
I12 = 1; //输出0
delay(speed);
//0
PH1 = 0; //PH1为0 则A线圈为反向电流
I01 = 1; //输出0
I11 = 1;
PH2 = 1; //PH2为1 则B线圈为正电流
I02 = 0; //以最大电流输出
I12 = 0;
delay(speed);
//B
PH1 = 1; //PH1为1 则A线圈为正向电流
I01 = 0; //以最大电流输出
I11 = 0;
PH2 = 1; //PH2为1 则B线圈为正向电流
I02 = 1; //输出0
I12 = 1;
delay(speed);
//0
PH1 = 1; //PH1为1 则A线圈为正向电流
I01 = 1;
I11 = 1;
PH2 = 0; //PH2为0 则B线圈为反向电流
I02 = 0;
I12 = 0;
delay(speed);
}
/*******************延时函数****************************/
void delay(int time)
{
int i,j;
for(j=0; j <= time; j++)
for(i =0 ; i <= 120; i++);
}
(未完待续)