<p>原帖地址:<a href="http://www.eeworld.com.cn/mcu/article_2018042238782.html">http://www.eeworld.com.cn/mcu/article_2018042238782.html</a></p>
<h1>引言</h1>
<p>在一般的项目开发过程中,往往需要两块或以上单片机进行通信完成<strong><a href="http://www.eeworld.com.cn/tags/%E6%95%B0%E6%8D%AE%E4%BC%A0%E8%BE%93">数据传输</a></strong>,例如四旋翼无人机在飞行过程中无线传输数据回到地面站,治疗仪器需要实时将患者和机器运转情况传回上位机平台,粮仓温控装置需将各种传感器通过RS485总线或者CAN总线的方式达到数据传输的目的等等,这些数据传输往往需要合适稳定的总线和灵活的<strong><a href="http://www.eeworld.com.cn/tags/%E9%80%9A%E4%BF%A1%E5%8D%8F%E8%AE%AE">通信协议</a></strong>,我发现无论什么数据传输,原理大同小异,这里简单以stm32的几种数据传输总结下平时项目中用的一些传输方法。</p>
<h1>通信协议</h1>
<h2>简单情况(如一对一)</h2>
<p>首先在数据传输前一定要想好通信协议,如果传输的数据和过程非常简单,那么就可以采用简单的传输协议,例如: </p>
<p>直接上代码:</p>
<p> </p>
<p>int temp; </p>
<p>u8 RS485_receive_str[128]; //接收缓冲,最大128个字节.</p>
<p>u8 uart_byte_count=0; //接收到的数据长度</p>
<p> ...</p>
<p>/****************************************************************************</p>
<p>* void RS485_Receive_Data(u8 *buf,u8 *len)</p>
<p>* RS485查询接收到的数据</p>
<p>* 入口参数:buf:接收缓存首地址</p>
<p> len:读到的数据长度 </p>
<p>****************************************************************************/</p>
<p>void RS485_Receive_Data(u8 *buf,u8 *len)</p>
<p>{<!-- --></p>
<p> u8 rxlen=uart_byte_count;</p>
<p> u8 i=0;</p>
<p> *len=0; //默认为0</p>
<p> delay_ms(10); //等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束</p>
<p> </p>
<p> if(rxlen==uart_byte_count&&rxlen) //接收到了数据,且接收完成了</p>
<p> {<!-- --></p>
<p> for(i=0;i</p>
<p> {<!-- --></p>
<p> buf[i]=RS485_receive_str[i]; </p>
<p> } </p>
<p> *len=uart_byte_count; //记录本次数据长度</p>
<p> uart_byte_count=0; //清零</p>
<p> }</p>
<p>}</p>
<p>//接收中断服务函数</p>
<p>int state=0;</p>
<p>void USART2_IRQHandler(void)</p>
<p>{<!-- --></p>
<p> u8 rec_data; </p>
<p> if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)//接收到数据</p>
<p> { </p>
<p> rec_data =(u8)USART_ReceiveData(USART2); //(USART2->DR) 读取接收到的数据</p>
<p> if(rec_data=='S'&&state==0) //如果是S,表示是命令信息的起始位</p>
<p> {<!-- --></p>
<p> state=1;</p>
<p> uart_byte_count=0x00; </p>
<p> }else if(rec_data=='E'&&state==2) //如果E,表示是命令信息传送的结束位并开始处理数据</p>
<p> {<!-- --></p>
<p> state=0;</p>
<p> if(RS485_receive_str[0]==0x00) //判断地址 地址正确</p>
<p> {<!-- --></p>
<p> if(RS485_receive_str[1]==0x02) //接受温度数据</p>
<p> {<!-- --></p>
<p> temp=RS485_receive_str[5]<<24"RS485_receive_str[2]|RS485_receive_str[3]<<8|RS485_receive_str[4]<<16;</p>
<p> </p>
<p> } else if(RS485_receive_str[1]==0x03) //led控制回馈</p>
<p> {<!-- --></p>
<p> led=RS485_receive_str[2];</p>
<p> </p>
<p> }</p>
<p> }</p>
<p> }else if(state==1) //一位位接收数据并装入缓存</p>
<p> {<!-- --></p>
<p> RS485_receive_str[uart_byte_count++]=rec_data;</p>
<p> if(uart_byte_count==6)</p>
<p> state=2;</p>
<p> }</p>
<p> } </p>
<p>} </p>
<p>这样的传输协议往往在两个一对一的传输中比较好用,主要在接受缓存部分使用了状态机机制,并且定义了简单的帧头和结束帧,显然这样的通信协议并不可靠,遇到复杂的情况就不好办了。</p>
<h2>复杂情况</h2>
<p>复杂情况的协议可以先制定协议表,再做细分,帧头+功能字+长度+数据+校验位,这样的协议既能满足多功能的场合也能避免数据过多出现错误,比较通用。 <br> 例如 GPS定位下位机协议: <br> </p>
<p>遥控上位机协议:</p>
<p> </p>
<ul><li> <p>SUM所有字节的和:等于从该数据帧第一字节开始,也就是帧头开始,至该 |
|