使用51单片机完成一个简单的串口通信协议。
要求:
一个协议帧为8个字节,其中头部两个字节,分别是0xFF,0xFE;
第3个字节代表第一个数据,第4个字节代表第二个数据(均为正数);
第5个字节如果是0,代表两个数据的和,1的话代表两个数据的差;
第6个字节为0,代表使用十进制显示,为1代表十六进制显示;
最后两个字节代表协议尾部,值分别为0xFD,0xFC。
将传输的两个数据和他们的计算结果分别显示在数码管上。
注意,如果差为负数,要将负号显示出来。
思路:使用串口中断,先接收8个字节至数组保存,最后再分析处理数据,具体
见代码,注释很详细。
/*-----------------------------------------------
名称:串口通信
内容:连接好串口或者usb转串口至电脑,下载该程序,打开电源
打开串口调试程序,将波特率设置为9600,无奇偶校验
晶振11.0592MHz,发送和接收使用的格式相同,如都使用
字符型格式,按复位重启程序,可以看到接收到 RST
然后在发送区发送任意信息,接收区返回同样信息,表明串口收发无误
------------------------------------------------*/
#include<reg52.h> //包含头文件,一般情况不需要改动,头文件包含特殊功能寄存器的定义
sbit WEI=P2^7;
sbit DUAN=P2^6;
unsigned char code dofly_DuanMa[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71,0x40};// 显示段码值0~9
unsigned char code dofly_WeiMa[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};//分别对应相应的数码管点亮,即位码
void delay(int t)
{
while(t--);
}
/*------------------------------------------------
函数声明
------------------------------------------------*/
void SendStr(unsigned char *s);
/*------------------------------------------------
串口初始化
------------------------------------------------*/
void InitUART (void)
{
SCON = 0x50; // SCON: 模式 1, 8-bit UART, 使能接收
TMOD |= 0x20; // TMOD: timer 1, mode 2, 8-bit 重装
TH1 = 0xFD; // TH1: 重装值 9600 波特率 晶振 11.0592MHz
TR1 = 1; // TR1: timer 1 打开
EA = 1; //打开总中断
ES = 1; //打开串口中断
}
//参数含义:i为第几号数码管,n为要显示的值
void Screen(int i,int n)
{
P0=0;
DUAN=1;
DUAN=0;
P0=dofly_WeiMa[i];
WEI=1;
WEI=0;
P0=dofly_DuanMa[n];
DUAN=1;
DUAN=0;
}
/*------------------------------------------------
主函数
------------------------------------------------*/
int flag=0;
int num1,num2;
int res;
int judge[8];
int cnt=0;
int is_fd;
int hex_mod;
void main (void)
{
num1=0;
num2=0;
//res=0;
InitUART();
ES= 1;//打开串口中断
is_fd=0;
while (1)
{
if(judge[0]==0xFF&&judge[1]==0xFE&&judge[6]==0xFD&&judge[7]==0xFC)
{
if(judge[5]==0x01)
{
hex_mod=16;
}
else
{
hex_mod=10;
}
if(judge[2]/hex_mod>0)
Screen(6,judge[2]/hex_mod);
Screen(7,judge[2]%hex_mod);
if(judge[3]/hex_mod>0)
Screen(4,judge[3]/hex_mod);
Screen(5,judge[3]%hex_mod);
if(judge[4]==0x00)
{
res=judge[2]+judge[3];
is_fd=0;
}
else
{
res=judge[2]-judge[3];
if(res<0)
{
is_fd=1;
res=-res;
}
else
is_fd=0;
}
if(res/hex_mod>0)
Screen(2,res/hex_mod);
Screen(3,res%hex_mod);
delay(10);
if(is_fd) //判断负号
{
Screen(1,16);
}
}
}
}
/*------------------------------------------------
发送一个字节
------------------------------------------------*/
void SendByte(unsigned char dat)
{
SBUF = dat;
while(!TI);
TI = 0;
}
/*------------------------------------------------
发送一个字符串
------------------------------------------------*/
void SendStr(unsigned char *s)
{
while(*s!='\0')// \0 表示字符串结束标志,通过检测是否字符串末尾
{
SendByte(*s);
s++;
}
}
/*------------------------------------------------
串口中断程序
------------------------------------------------*/
void UART_SER (void) interrupt 4 //串行中断服务程序
{
unsigned char Temp; //定义临时变量
if(RI) //判断是接收中断产生
{
RI=0; //标志位清零
Temp=SBUF; //读入缓冲区的值
judge[cnt++]=Temp;
//报头不满足或者一个协议帧发送完毕
if(cnt==8||judge[0]!=0xFF)
cnt=0;
SBUF=Temp; //把接收到的值再发回电脑端
}
if(TI) //如果是发送标志位,清零
TI=0;
}