STM32 是一个性价比很高的处理器,学习一段时间,终于开始做项目,但是串口的问题对于第一次接触它的人来说,真让人头痛。我的项目需要从PC获得大的数据流,而且数量不确定,检测到特定结束字符时终止。几天来,用中断接收,没有一次是成功的,总是会丢失数据!通过几天的时间摸索,发现STM32的串口不同于AVR。只有一个缓冲器位于总线和移位寄存器这间,在传输大文件流的时候,靠中断接收很容易丢失数据。硬件RTS控制也有问题!
上传的手册图中可以看到,RTS在接收到停止位并RXNE置位后被拉高,通知PC端暂停发送。但是PC接到这个信号以及处理这个信号都需要时间,在响应这个信号这前,PC串口的移位寄存器一直在工作的,所以上图中的“空闲”时间,实际上是没有的,后面直接就是下个数据的起始位,从而RTS又被拉低,被允许接收数据了。这样一来,RTS就没有用了,形同虚设。我实际测试中,用硬件流控去接收数据流,稍有延迟就会丢失数据。我觉得,应该设计成这样:当检测到有效起始位的时候就将RTS拉高,而当数据被读走的时候(RXNE清空),RTS再拉低,允许接收数据,就比较合理了。因为在接收的过程中,RTS信号有足够的时间传到PC并被响应。也许我的测试程序有问题,大家自己可以试试大的文件流,用中断方式接收,在中断里USART_ReceiveData后稍稍延时(模拟用于处理数据的时间),再将数据由这个或别的串口发送到PC端,再比较两者的数据就可以发现数据丢失了,延时越久丢的数据越多。
解决的办法,想出来一个,但是还没有测试。我想把原RTS脚设置成普通的IO口,用于模拟RTS功能。USART中断不用,改为DMA中断处理数据。设立接收缓冲区大小为100字节,用于存放DMA接收的到数据。DMA传输的数据的大小设为160个字节。打开DMA接收一半时的中断响应,不用DMA全部接收的中断响应。为什么这样呢,因为当DMA接收完成后会自动关闭DMA通道,这样还是回到以前的老问题,关闭通道后,数据依然在传输!如果来不及接收,就会丢失。所以在DMA传输一半的时候响应中断,进入中断后先拉高RTS信号,通知PC不要传了,然后循环检查RXNE,不断接收数据,直到RXNE为零后退出中断(这里应该加个数限制,一般几个左右,排除RTS传输线路故障,造成的不断接收数据不退出的情况),一组数据接收完成了!设定接收160个数据,在接收到80个的位置中断了,并暂停传输,加上我们处理的时间,所以预留了20个空间,应该够用了,如果不够就设160个得了。不知道是否成功,明天测试。。。 |