单片机: 自定义串口通信协议的实现

使用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;
} 


  • 13
    点赞
  • 95
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值