Chinaunix首页 | 论坛 | 博客
  • 博客访问: 165403
  • 博文数量: 73
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 235
  • 用 户 组: 普通用户
  • 注册时间: 2014-06-27 09:43
个人简介

为兴趣挑灯夜战

文章分类
文章存档

2018年(4)

2017年(7)

2016年(9)

2015年(4)

2014年(49)

分类: 嵌入式

2016-11-09 00:29:07


在使用串行接口传输指令时,做为接收方,要确保准确的接收对方传来的数据,那就到有一个稳定的接收机制,下面是针对一种简单协议的代码实现。
定义有这样一个指令协议: 指令头+地址+长度+命令+数据+校验值。每一项都只占一个字节,“指令头”固定为0x02, “长度”是“命令”+“数据”的长度。“校验”是除“指令头”和“校验值”外所有数据的异或结果。
为了接收数据,定义这样一个结构体和相应的宏:


点击(此处)折叠或打开

  1. #define FRAMLEN 128 //数据接收缓存长度

  2. // recevie status
  3. #define WAITRECEVIE 0x00 //wait receive
  4. #define ISRCVING 0x01 // receive busy
  5. #define RCVFINISH 0x02 // receive finsh

  6. typedef struct _USARTRCV
  7. {
  8.     u8 stataus;//有三种状态:空闲(WAITRECEVIE )、接收(ISRCVING )、接收完成(RCVFINISH)
  9.     u8 ReceivedLen;//已接收的长度
  10.     u8 length;//需要接收数据的长度
  11.     u8 RCdata[FRAMLEN];
  12.     
  13. }USARTRCV;





下面是接收代码

点击(此处)折叠或打开



  1. USARTRCV USARTCmdData;//the command from

  2. u8 RxTimeOutMs;//超时计数

  3. //start recevie
  4. void StartRcv(void)
  5. {
  6.     USARTCmdData.ReceivedLen=0;
  7.     USARTCmdData.length=0;
  8.     USARTCmdData.stataus=WAITRECEVIE;//idle staus
  9. }


  10. //在定时中断函数里执行,这个函数放在一个10ms的定时器中断里面运行
  11. void TimeOutManage(void)
  12. {
  13.     if(RxTimeOutMs>0)
  14.     {
  15.         RxTimeOutMs--;
  16.         if(0 == RxTimeOutMs)
  17.         {
  18.             StartRcv();//超时后重新启动接收
  19.         }
  20.     }else if(USARTCmdData.stataus !=RCVFINISH )
  21.     {
  22.          StartRcv();//接收错误时重新启动接收
  23.     }
  24. }
  25. // data receive
  26. void USART_Rcv(USARTRCV* AcData,u8 RcvData)
  27. {

  28.     switch(AcData->stataus)
  29.     {
  30.         case WAITRECEVIE://接收第一个数据
  31.             if(RcvData==0x02)
  32.             {
  33.                 AcData->RCdata[0]=RcvData;
  34.                 AcData->stataus=ISRCVING;
  35.                 AcData->ReceivedLen=1;
  36.             }
  37.             break;
  38.             
  39.         case ISRCVING:
  40.             
  41.             if(1==AcData->ReceivedLen)//接收第二个数据
  42.             {
  43.                 AcData->RCdata[1]=RcvData;
  44.                 AcData->ReceivedLen=2;
  45.                 
  46.             }else if(2==AcData->ReceivedLen)//接收第三个数据
  47.             {
  48.                 if(RcvData>sizeof(CMDFRAME))//判断长度字的合法性
  49.                 {
  50.                     RxTimeOutMs= 0;
  51.                     AcData->stataus= WAITRECEVIE;
  52.                 }
  53.                 AcData->length=RcvData;//保存指令中的长度字
  54.                 AcData->RCdata[2]=RcvData;
  55.                 AcData->ReceivedLen=3;
  56.             }else if((AcData->ReceivedLen < (AcData->length+4)) && (AcData->ReceivedLen > 2))//接收第AcData->ReceivedLen个数据
  57.             {
  58.                 AcData->RCdata[AcData->ReceivedLen]=RcvData;
  59.                 AcData->ReceivedLen++;
  60.                 
  61.                 if(AcData->ReceivedLen==(AcData->length+4))//加上指令头、设备地址、长度和校验4个字节长度
  62.                 {
  63.                     RxTimeOutMs= 0;
  64.                     AcData->stataus=RCVFINISH;//数据接收完成
  65.                 }
  66.             }
  67.             break;
  68.                 
  69.         default ://其他不合法的状态
  70.                 RxTimeOutMs= 0;
  71.                 AcData->stataus= WAITRECEVIE;
  72.             break;
  73.     }
  74.     
  75.     if(AcData->stataus == ISRCVING)
  76.     {
  77.         RxTimeOutMs= 20;//重置超时值
  78.     }else
  79.     {
  80.         RxTimeOutMs= 0;
  81.     }
  82. }

  83. //USART1 Interrupt
  84. void USART1_IRQHandler(void)
  85. {
  86.     if ( USART_GetFlagStatus(USART1, USART_FLAG_RXNE)!=RESET)
  87.     {
  88.         USART_ClearFlag(USART1, USART_IT_RXNE);
  89.         USART_Rcv(&USARTCmdData,USART_ReceiveData(USART1));
  90.     }
  91. }

上面代码逻辑清晰,能稳定接收数据,有超时机制,看看注释就能很快明白,在此不做更多解释,数据接收完后再由其他函数对指令进行校验和解析。




阅读(1569) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~