嵌入式硬件通信接口协议-UART(四)设计起止式的应用层协议
解析思路是:
本文引用地址:https://www.eepw.com.cn/article/201903/398678.htm1.确保环形缓冲区有足够一个帧结构的数据量,否则返数据量不足的错误;
2.接着读出一个字节判断帧头标志是否为0x55,否则返帧头错误;
3.再次读一个字节作为帧长度数据,且长度至少3个字节(2个CRC校验值+至少1字节数据包),否则返帧长度错误;
4.读出帧长度数据,如果此时环形缓冲区的可读数量比长度数值小,出现这情况的原因可能是帧长度字段在发送期间出现异常,或是对端设备串口传输慢而未完整传输一帧,此时可做适当的延时等待,如果超时退出,且返帧长度错误;
5.继续读出2个字节作为CRC校验值,且需要注意先收到的是crc16L,先收到小端数值;
6.紧接着把数据包读出,此时读的长度应该是第4步中的帧长度数据少2个字节;
7.最后对数据包计算一个CRC校验值,对比接收到的校验值,校验值不一致则返错误校验码。
函数返回值符合以下枚举的错误码:

被解析数据源
看到这里也许仍有疑问,用于解析的数据源哪来?数据什么时候被写进环形缓冲区内?
参考上一篇《嵌入式硬件通信接口-使用RingBuffer处理数据(二)详细设计过程》介绍的关于向环形缓冲区写入一个字节,但dclib_ringbuffer这个模块属于应用库模块层,而如果直接把dclib_rb_writebyte这一个接口放在串口接收中断里执行,这就破坏了系统的架构层次,对工程代码的维护和移植是个麻烦事,因此采用回调函数的方式。
嵌入式开发工程师都知道,一般在使用官方的库时,经常会遇到需要自己实现一些回调函数,从而利用注册接口把回调函数传递给库或者驱动层,使库或者驱动层在执行时调用该回调函数。
根据这个思路,同样的这里也采用回调函数的形式,回调函数内完成了把串口接收到的数据写入环形缓冲区内。
回调函数的实现源码截图:

事实上仅仅调用了dclib_ringbuffer功能里的写一字节接口dclib_rb_writebyte,回调函数传进来的参数dat就是串口接收到的数据。
有了回调函数,还要把这个回调函数的地址传给底层驱动,这也就是常说的“注册”的过程,注册接口在固件板级接口层里串口模块dcbsp_uart实现,注册接口时dclib_uart_callback_reg函数:

又偏题了,关于回调函数在此不做深入论述。
简而言之,环形缓冲区写入一字节的执行过程,放在回调函数里,当串口接收中断触发后,中断里会根据注册的回调函数地址,进而执行回调函数,实现对环形缓冲区写入一个字节数据。如此操作的理由是不改变工程代码的分层架构,并且便于维护与移植!
为了缩减篇幅,最后贴上测试代码的部分:


最后也附上调试期间串口打印的解析结果:

起止式帧结构的讲解稍有匆忙,篇幅也略大,文中基础技术要点未能细致讲解,后续统筹规划再做单独介绍!
接下来在此帧结构基础上,讲述如何设计在数据包放置应用层的交互指令,敬请期待下回分!
评论