毕业设计之短信控制步进电机

前几天受老师之托,帮一个大四的学长搞毕业设计,于是这几天就在忙活这玩意儿,幸不辱命,终于在今天给搞出来了,从前也没搞过串口通信,这是我的错,学单片机这么久了,连这个都没接触过,不过现在算是补上了。

刚开始的几天真的是无从下手,看了些资料,最后和老师一起把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++);

}

(未完待续)