自定义通信协议,异步不归零码,单线通信,非常巧妙

背景介绍我们设计了一款用于增氧泵保护控制的控制器。
其特点是需要检测6路的三相电流以及零序电流信号,加上三相电压检测,一共需要26个A/D检测通道。
而且为了简化外围电路的设计,采用了真有效值检测方法。
对每一个通道的信号在1个周期20ms内采样128个数据,需要用到处理器的regular group转换和DMA的功能;
但是,STM32F103处理器regular group转换功能仅支持16通道。
因此,采用两片STM32F030处理器扩展A/D转换通道。
问题来了,两片从处理器如何将数据发送给主处理器。
采用UART?
主处理器的2个UART需要用于RS485以及4G模块的通信,
UART是宝贵的资源,剩余的1个UART口需要留作它用;
而且一路的UART需要占用两个IO口,这会让原来IO口就不够的主处理器雪上加霜;
另外,从处理器没有采用外部晶振,其内部振荡器精度比较差,会导致UART通信误码; 
采用SPI?
占用IO口太多,主处理器表示没有那么多IO口挥霍;
采用IIC?
好是好,就是主处理器需要用为主定时查询,从片从处理器不能按自己的时序即时上报数据,而且万一未来需要降成本,从处理器只能从具有IIC接口的单片机中选择,不能将成本做到极致;
协议介绍一番深思熟虑之后,我设计了一个采用异步不归零码的单线通信协议;
编码方式如图所示,采用特殊的比特编码格式,根据数据线上两次电平跳变的时间间隔定义比特0和比特1。
30976590eed14faa8f764557dbcebb12?from=pc.jpg
比特编码

例如,将两次跳变的时间间隔t1定义为比特0,将两次跳变的时间间隔t2定义为比特1。
接收方设定两个时间区间:
cb5cbf358bcd48c4aa09a7c036849449?from=pc.jpg
时间区间

若两次跳变的时间间隔t∈T1 ,则为比特0,两次跳变的时间间隔t∈T2 ,则为比特1。
通过设置合理的t1、t2的数值以及T1、T2的范围,可消除发送方以及接收方处理器的时钟误差对通信带来的影响。
假设上述t1小于t2 ,发送和接收方的处理器的时钟相对误差分别为±a1±a2
则接收方解析得到的比特0的最小时间间隔为t1*(1-a1)*(1-a2),最大时间间隔为t1*(1+a1)*(1+a2),而解析得到的比特1的最小时间间隔为t2*(1-a1)*(1-a2),最大时间间隔为t2*(1-a1)*(1-a2)。
为了保证比特0和比特1在最坏情况时钟精度下能被正确解析,必须满足:
100067c57cff4cfda5a09893c791bec1?from=pc.jpg
时间区间关系

此外,数据发送采用定时器中断,数据接收采用外部中断。
没有设置中断优先级,数据发收发过程中,如果正在处理其它中断,控制器不能即时处理数据收发中断,这将导致时间区间的变化; 
综合考虑如下因素:
1)从处理器的时钟精度在全温度范围内为±5%
2)最坏情况下,从处理器所有中断的总处理时间为20us; 
3)最坏情况下,主处理器所有中断的总处理时间为30us; 
在一番埋头苦算之后,我把时间范围定为0~256us以及512us~2ms。
在发送端,用256us的定时器中断进行数据发送; 
在接收端,采用一个定时器配合外部中断进行数据接收,以384us为判断阈值,
如果跳变时间间隔小于384us则解析为0,否则小于2ms解析为1,大于2ms由认为数据发送开始;
帧超时时间设置为100ms; 
数据发送程序如下:
22a6f17bba1244ee977e88df9de60842?from=pc.jpg
数据发送程序




来源:物联网全栈开发