我们来讨论一个单片机双机通讯程序,例子很简单就是两个单片机之间简单的通讯。在去年工作期间一位做硬件的同事问我什么通讯协议,我竟然不知道该怎么回答他。简单就是说应该两个单片机之间通讯报文的编码和解码的方式。我不知这样解释他明白没。
我们现在需要为一个温湿度监控的测量设备编写一个协议。项目要求主机能读取传感器的温度和湿度。因为协议只有一条所以非常简单。
主机发送 :68 00 xx xx xx xx 16 xx 是任意字符,所以不检查
传感器回复:68 00 TH TL HH HL 16 TH是温度高8位, TL是温度低8位 , HH 湿度高8位,HL湿度低8位 。因为我们可以给规定温度和湿度保留两位小数点。所以温度和湿度的真正的值可以通过下面公式计算。
温度 = (TH*256 TL)/100, 湿度=(HH*256 HL)/100。
我们来写一下主程序怎么写:
#define FOSC 11059200L
#define BAUD 9600
typedef struct UART_RT
{
unsigned char buf[7];
unsigned char count;
unsigned char flag;
} UART_RT;
UART_RT UART0={{0,0},0,0};
unsigned int RdatCount=0;
unsigned int tempu hadirty;
/***********************************/
// 串口初始化程序
/***********************************/
void uartInit( )
{
SCON = 0x50;
TMOD |= 0x20;
TH1=TL1 = -(FOSC/12/32/BAUD);
TR1 =1;
ES = 1;
EA =1;
}
/***********************************/
// 串口1发送一个字节到上位机
/***********************************/
void uartSendData(unsigned char dat)
{
SBUF=dat;
while(TI==0);
TI=0;
}
/***********************************/
// 串口发送一个数组到上位机
/***********************************/
void uartSendArray(unsigned char *dat, unsigned char len )
{
unsigned char i;
for(i=0; i<len;i++)< p="">
{
uartSendData(*dat);
dat++ ;
}
}
/**********************************
接收数据函数
***********************************/
void uartRecive(dat) //接收数据函数
{
switch(UART0.count)
{
case 0:
if(dat==0x68)
{
UART0.buf[0] = 0x68;
UART0.count = 1;
}
break;
case 1:
if(dat==0x00)
{
UART0.buf[0] = 0x00;
UART0.count = 2;
}
else
{
UART0.count = 0x00;
}
break;
case 2:
case 3:
case 4:
case 5:
UART0.buf[0] = dat;
UART0.count++;
break;
case 6:
if(dat==0x16)
{
UART0.buf[0] = 0x16;
UART0.flag = 1;
}
break;
default:
break;
}
}
//-----------------------------------
// 串口1中断程序
//------------------------------------
void uart_Isr( )interrupt 4
{
unsigned char dat =SBUF;
if(RI)
{
RI=0;
uartRecive(dat); //接收数据函数
}
if(TI)
{
/ / TI=0;
}
}
/*************************************/
//定时器初始化
//每20毫秒中断一次
/*************************************/
void Timer0_Init( );
{
TMOD = TMOD | 0x01;
TH0 = 0XFD;
TL0 = 0X9A;
EA =1;
ET0 =1;
TR0 =1;
}
/**********************************
定时器中断程序
***********************************/
void Timer0_isr( ) interrupt 1
{
if(RdatCount<=5)
{
RdatCount++;
}
}
void exeRecUart( )
{
tempu = (UART0.buf[2]<<8) +UART0.buf[3];
hadirty= (UART0.buf[4]<<8) +UART0.buf[5];
}
unsigned char code R_CMD[7] ={0x68,0x00,0x00,0x00,0x00,0x00,0x16}
void main( )
{
unsigned char m, n;
Timer0_Init( );
while(1)
{
if(RdatCount>=5)
{
uartSendArray(R_CMD, 7 );
RdatCount =0x00;
}
if(UART0.flag)
{
exeRecUart( );
UART0.flag = 0;
UART0.count = 0;
}
}
}
橙色代码是接收数据的代码,函数根据协议检查了接收的数据第一、二以及最后字节是否是 0x68、0x00、0x16。当接收万一帧数据后UART0.flag置1.主程序会通过exeRecUart( )处理接收到的数据,读取了
接收到数据的信息。
下面我们看看传感器单片机的程序。
我们只需改写主程序的代码即可。
void main( )
{
unsigned int tempu hadirty;
unsigned char xdata dat[7] ={0x68,0x00,0x00,0x00,0x00,0x00,0x16}
Timer0_Init( );
while(1)
{
if(RdatCount>=5)
{
read_Sensor( );
RdatCount =0x00;
}
if(UART0.flag)
{
dat[3] = tempu>>8;
dat[4] = tempu&0x00ff;
dat[5] =hadirty>>8;
dat[6] =hadirty&0x00ff;
uartSendArray(dat, 7 );
UART0.flag = 0;
UART0.count = 0;
}
}
read_Sensor( ); 是读取传感器的函数,负责更新tempu hadirty; 当接收到读取温湿度置的指令后。主函数负责打包发送tempu hadirty;数据。
以上是一个简单的双击通讯程序,通讯帧是定长的。