使用串口接收连续的一帧数据是我们平时比较常用到的一种方式(通过485或者232总线),而且往往这一帧数据的长度不确定,实现这种功能如果我们使用传统的接收中断方式的话会带来非常频繁的中断,查询方式的话则会造成系统大的延时,总之,这两种传统的方式都会对系统的实时性有较大的影响(频繁的中断或者大延时都会引起一些任务得不到实时响应)。
飞思卡尔Kinetis系列的UART模块自带IDLE Line即总线空闲检测功能,如下图。这个IDLE Line detection和DMA巧妙结合起来可以很好的解决上述的问题,即当连续的一帧数据发送过来时(长度不确定),可以通过DMA将数据存放到RAM区的Buffer中(事先给Buffer预留一定的空间),当一帧数据发送完成时IDLE Detection功能会从最后一个数据的STOP位开始检测,当检测到连续10或者13个高电平时,即表示没有start位过来了,即判断上一帧数据已经传输完毕,此时UART可以产生IDLE Line中断(即在整个传送过程中只有这一次中断),在此中断中可以置一个数据帧接收完成标志,然后在主程序可以对接收到的数据进行解包处理。
<img id="aimg_wcqse" class="zoom" height="541" file="http://files.chinaaet.com/images/blog/2015/06/15/4077086449550.png" border="0" alt="" />
不过需要注意的是,DMA目标空间的buffer长度在实际使用中必须要大于外部总线有可能发送过来的最大长度(即先评估好外部总线最大可能发送的数据长度,最后留一定余量,前提是确保RAM空间足够大),否则buffer存满了之后会被剩下的数据覆盖掉。当然如果RAM不够大的话实际上也是可以解决的(即小RAM的芯片),则可以将RAM分成两个大小相等的小数据空间,然后在第一个小块存满之后产生DMA中断,切换到另一个数据块继续存,第一个存满的小块则可以拿去先处理了,然后在一帧数据接收完成之后触发IDLE Line中断读取剩下的数据(如果需要接收的数据大于两小数据块的大小,则可以在这两个数据块之间来回切换了,具体看我们自己的想象空间了)。
下图为我写的一个测试工程运行的效果图,跑在Kinetis KL26上面(FRDM-KL26板上),程序中我预留了1024字节的Buffer,每次上位机发送完一帧数据即会触发一次IDLE Line功能,在UART的IDLE Line中断里有一点需要注意,即每次IDLE Line都要记得把DMA的目标偏移地址重新复位到Buffer的首地址,否则的话下一帧的数据会继续往下存直至最后溢出,虽然我在程序中也做了DMA溢出中断对此做了处理,但是还是不要惹麻烦的好是吧,呵呵。
<img id="aimg_TFooX" class="zoom" height="586" file="http://files.chinaaet.com/images/blog/2015/06/15/4077092999987.jpg" border="0" alt="" />
好了,本篇**就到这里了,秉承继续开源的思想,我把完整的测试代码已上传至博客最后附件中供广大博友借鉴参考。赠人玫瑰,手有余香,从个人做起继续把开源精神发扬起来,敝帚自珍有悖于科学精神,而且有谁问心无愧的说没有借鉴过别人的呢,为什么到你那就止步了呢,没有借鉴就没有创新,这的确是真的。好了,有点牢骚了(自己就是从最开始新手一步步的步履维艰的过来的,对敝帚自珍的人深恶痛绝,当然只是个人抒发情感了,呵呵)。啰嗦到这了,再聊,未完待续~
附件为完整测试代码: |