锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

51单片机多机通信协议

时间:2024-05-15 08:37:10

做自己以前没做过的东西,总会有各种踌躇,害怕做不出来,其实要是真的开始去做了,问题就解决大半了。 在家没网,就开始写了, 熬了两夜,加一个半天,总算是完成了通信协议,经调试,可以正常工作。 如果有孩子也要做这个,可以参考一下哈! 别的不多说,贴代码。

//------------------------------------------------- //主机程序,主机座控制,用中断法 //-----------------------------------------------
#include "basic.h"

//--------------------------------------------------- //宏定义
#define EN_ADDSEND TB8=1;//发送寻址,搜寻从机 #define EN_DATASEND TB8=0;//发送数据
#define M_S 0Xf0//握手后的命令字,主机到从机 #define S_M 0Xf1//握手后的命令字,从机到主机 #define M_SOK 0Xf2//主到从准备完成,从机发送的反馈信息 #define S_MOK 0xf3//从到主准备完成,主机发送的反馈信息 #define OP 0xf4//主机到从机发送结束
#define ERROR 0xf5//错误 #define Response 0xf6//应答信号 #define CO INUE 0xf7//接受数据之后给对方发送的反馈,请求继续 #define OK 0xf8
//-------------------------------------------------- //数据定义 uchar DATA[20]={0};//从机返回的状态值
uchar CMD[20]= {0x44,0x44,0x44,0x55,0x55,0x55,0x47,0x45,0x65,0x35,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,};// 主机给从机发送的命令 uchar state=0;//状态值,进行中断判断 uchar Address;//呼叫从机地址 uchar temp=0;//SBUF缓存 uchar *Position=0;//数据指针,指定数据更新的位置
//--------------------------------------------- //串口1初始化,用于和从机通讯 void Uart1_Init(void) //9600bps@11.0592MHz { PC &= 0x7F; //波特率不倍速 SCON = 0xD0; //9位数据,可变波特率 AUXR |= 0x40; //定时器1时钟为Fosc,即1T AUXR &= 0xFE; //串口1选择定时器1为波特率发生器 TMOD &= 0x0F; //清除定时器1模式位 TMOD |= 0x20; //设定定时器1为8位自动重装方式 = 0x ; //设定定时初值 TH1 = 0xDC; //设定定时器重装值 ET1 = 0; //禁止定时器1中断 TR1 = 1; //启动定时器1 EA=1; //总中断启动 SM2=0; ES=1; }
//------------------------------------------ //查询法发送一个数据,TB8=0; void SendByte (uchar date) {
//EN_DATASEND;//TB8=0; TB8=1; SBUF=date; while(! ); TI=0; }
//----------------------------------- //寻址从机 void Search(uchar ADD) { //EN_ADDSEND; TB8=1; SBUF=ADD; while(!TI); TI=0; }

//主机向从机发送命令 //因为主机为控制端,为便于控制从机,所以选择用查询法而不选用中断 void M_S_Protocol(uchar add,uchar *m)//三个参量分别为从机地址,命令的字节数,命令的位置 { state=1; ES=1; Position=m; Search(add); } //主机接收从机状态,同样也为查询法不用中断 void S_M_Protocol(uchar add,uchar *m)//三个参量分别为从机地址,命令的字节数,命令的位置 { state=4; ES=1; Position=m; Search(add); } void M_S_Send(uchar add,uchar *m)//主机到从机整个过程 { M_S_Protocol(add,m); while(state); ES=0; } void S_M_Send(uchar add,uchar *m)//从机到主机的整个过程 { S_M_Protocol(add,m); while(state); ES=0; } //----------------------------- //主函数,主机主函数主要用于与GPRS和从机之间做桥接 void main() { Uart1_Init(); while(1) { S_M_Send(0x01,CMD); } } void UART1() interrupt 4 { RI=0;//清除中断标志 temp=SBUF; if(state)//处于传输状态 { switch(state) { //----------------------------------------------------------------- //---------------------M_S部分-------------------------------- case 1: { if(temp==Response)//寻址成功 { SendByte(M_S); //发送M_S命令 state=2; //转换状态 break; } /*else//寻址不成功,通信结束,转换为非通信状态 { state=0; SendByte(STOP);//发送通信停止命令 break; }*/ break; } case 2: { if(temp==M_SOK)//M_S得到回应 { state=3; SendByte(*Position);//发送第一字节 break; } break; } case 3: { if(temp==CONTINUE) //从机继续要求数据 { if(Position-CMD<19)//数组长度判断 { Position++; SendByte(*Position);//发送数据 break;
} else//数组溢出,停止通信 { state=0; SendByte(STOP); break; } } break; } //----------------------------------------------------------------------- //----------------接收部分--------------------------------------------- case 4: { if(temp==Response)//呼叫从机得到回应 { state=5;//转换状态 SendByte(S_M);//发送从机到主机命令 break; } /*else//无回应,停止此次传输 { state=0; SendByte(STOP); break; } */ else break; } case 5: { if(temp==OK)//发送S_M得到回应 { state=6;//转换状态 SendByte(S_MOK);//准备完成 break; } /*else //无回应,停止通信 { state=0; SendByte(STOP); //发送停止命令 break; }*/ else break; } case 6: { if(Position-CMD<20) //数组溢出判断 { *Position=temp;//接收数据 Position++; SendByte(CONTINUE); //要求从机继续发送数据 break; } else//超出数组,停止通信 { state=0; SendByte(STOP); break; } } default: break; } } }

//----------------------------------------------- //从机程序,从机接收信息,所以用中断法会更便于反馈和执行命令 //------------------------------- #include "basic.h"
//--------------------------------------------------- //宏定义
#define EN_ADDSEND TB8=1;//发送寻址,搜寻从机 #define EN_DATASEND TB8=0;//发送数据
#define M_S 0Xf0//握手后的命令字,主机到从机 #define S_M 0Xf1//握手后的命令字,从机到主机 #define M_SOK 0Xf2//主到从准备完成,从机发送的反馈信息 #define S_MOK 0xf3//从到主准备完成,主机发送的反馈信息 #define STOP 0xf4//主机到从机发送结束
#define ERROR 0xf5//错误 #define Response 0xf6//应答信号 #define CONTINUE 0xf7//接受数据之后给对方发送的反馈,请求继续 #define OK 0xf8
sbit key=P3^7; //-------------------------------------------------- //数据定义 uchar DATA[20]={0x12,0x11,0x22,0x33,0x44,0x55,0x66,0x77,0x88,0x99,0x00,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,0x55,};//从机返回的状态值 uchar CMD[20]={0};//主机给从机发送的命令 uchar state=0;//状态值,进行中断判断 uchar A;//呼叫从机地址 uchar temp=0;//SBUF缓存 uchar *Position=0;//数据指针,指定数据更新的位置
//------------------------------------------ //STC12具有7字节全球唯一ID,将7位的ID加和作为从机地址.(有可能从机地址会重复) uchar Set_Add() { uchar *p; uchar i; uchar addr=0; p=0xf1;//上电后唯一ID起始地址 for(i=0;i<7;i++) { addr+=*p; } return (addr); }
//--------------------------------------------- //串口1初始化,用于和从机通讯 void Uart1_Init(void) //9600bps@11.0592MHz { PCON &= 0x7F; //波特率不倍速 SCON = 0xD0; //9位数据,可变波特率 AUXR |= 0x40; //定时器1时钟为Fosc,即1T AUXR &= 0xFE; //串口1选择定时器1为波特率发生器 TMOD &= 0x0F; //清除定时器1模式位 TMOD |= 0x20; //设定定时器1为8位自动重装方式 TL1 = 0xDC; //设定定时初值 TH1 = 0xDC; //设定定时器重装值 ET1 = 0; //禁止定时器1中断 TR1 = 1; //启动定时器1 } void All_Init() { Uart1_Init(); ADDR=Set_Add(); EA=1;//打开总中断 ES=1;//打开串口中断 } //------------------------------------------ //查询法发送一个字 void SendByte (uchar date) { ES=0;//关断串口中断 EN_DATASEND; SBUF=date; while(!TI); TI=0; ES=1; //打开串口中断 }
//主函数,可以用大循环只执行全局数组命令,而中断接收并修改全局命令命令 void main() { All_Init(); Position=DATA; //SendCmd(DATA); while(1); { } }
//串口1中断服务程序,用state进行状态判断处理 void UART1() interrupt 4 { RI=0; temp=SBUF;//读取数据 if (state) { switch (state) { case 1: if(temp==M_S)//主机发送到从机,从机准备好接收数据 { SendByte(M_SOK);//发送应答 state=2;//更换状态 break; } else if(temp==S_M)//主机要求从机发数据 { SendByte(OK);//回应主机 state=3;//转换状态 Position=DATA; break; } else if(temp==STOP) { SM2=1; state=0; break; } break; case 2: { if(temp==STOP)//停止符判定,回到待机状态 { state=0; SM2=1; break; } DATA[1]=temp;//接收数据 SendByte(CONTINUE);//接收数据后回应 //SendByte(DATA[1]);//串口测试用的 break; } case 3: { switch(temp) { case S_MOK://主机准备完成 { SendByte(*Position);//发送数据 break; } case CONTIN
锐单商城拥有海量元器件数据手册IC替代型号,打造电子元器件IC百科大全!

相关文章