在我的项目中,我试图在Cortex-M3上实现类似Cortex-M0的UART自动波特率检测功能,遗憾的是,它没有板载这种便利功能。
这个想法是主机在每个发送帧的开头使用两个同步位(1-0序列),允许从机通过测量两个下降沿之间的时间使自身与(未知)波特率同步(起始位和高位)。
基本上我使用定时器输入捕获功能来连接到UART RX引脚,但前提是我的初始波特率接近主机使用的实际波特率(+/- 15%) 。
但是,如果我使用的从属默认波特率远低于或高于实际使用的波特率,则会出现问题。我仍然可以测量前两个(同步)位的持续时间,调整我的波特率,但仍然无法与帧/停止位的末尾同步,因此我会丢失数据。
例如,如果我将我的奴隶的UART默认设置为9600 B / s而我的主人实际上发送的波特率要高得多,那就说230,400 B / s:
我已经使用STM32F0的自动波特率功能对此进行了测试,在那里我可以选择任何默认的波特率值而不会丢失任何数据。所以我想,因为M0-UART"知道"两个同步位已通过它只会在波特率测量后再采样6个数据位,以保持与停止位同步。但是如何手动实现此行为?
我希望你能明白我的观点,虽然对我来说有点难以解释,但我很感激你的想法!
答案 0 :(得分:1)
你发布的内容非常好。我有点不清楚你对帧的意思,因为它可能是一个UART字符(通常是10位),或者它是一个多字节数据包。
听起来你遇到的问题是你使用UART字符的前两位来设置波特率,所以如果UART配置的波特率和输入波特率之间的差异足够大,UART外设无法识别出有任何数据。
一般来说,我不认为在接收字符的过程中会改变波特率,我认为问题在于UART没有像你期望的那样进行调整。
我建议使用同步字符。 ASCII'U'是一个很好的选择,因为它在串行线上产生1和0的交替序列。根据您的应用需求,您可以发送一个同步字符来确定初始波特率,或者如果预计波特率会发生显着变化,您可以在每次数据传输之前发送一个同步字符。如果您只是在补偿速度波动,可以使用混合方法,根据单个同步字符设置波特率,然后在接收到的每个其他字符上调整波特率。
对于单个同步,您的过程看起来有点像这样:
对于重复同步,您将拥有与上述相同的过程,但是当接收器空闲时(这需要在发送器和接收器上预先确定),它将返回到步骤1.
对于单个同步和常量调整,您将执行与上面相同的步骤,但您将继续使用输入捕获。收到字符后,您将使用自上一个完整字符(整个字符时序,通常为10位)以来的第一个和最后一个输入捕获值来计算新的波特率并进行设置,然后清除存储的输入捕获值以进行调整为下一个角色。
或者,根据您的评论,听起来您不能使用同步字节,所以我认为您的解决方案,如果微控制器的UART外设无法自行处理该方法,用定时器模块完全实现接收器。以下是我将如何做到这一点,粗略地说:
如果你在Cortex-M3上运行,即使是在适度的32 MHz,你应该有足够的时间以200 kbps的速度运行。你可能需要循环一些边缓冲区,因为我不确定将边转换成字节需要多少时间,如果你要背靠背发送字节,你至少需要两个可以ping的缓冲区乒乓之间。
步骤1-6如何实现的细节将根据您使用的微控制器而有所不同,但几乎任何定时器外设都应该能够处理。如果不支持同时触发,则限制可能不得不改变触发的边沿,并且如果定时器没有报告哪个边缘引起中断,则读取引脚的状态以找出触发中断的边沿。您还必须仔细选择计时器的时间基准,这样您就可以有足够的分辨率来计算高速率的位数和计数器中足够的跑道来计算时间,而不需要在低速率下进行多次环绕。
答案 1 :(得分:0)
我在我的项目中使用了这样的算法:
存在两种模式 unsync 和 sync 。两个设备(主设备和从设备)都具有同步模式的计时器。每当发生不成功交换(或计时器到期)时,设备都会切换到 unsync 模式。在此模式下,主器件仅向从器件发送字节0x7F
,从器件等待同步字节与禁用的USART和使能的定时器输入捕获。当从设备成功同步时,它会向主设备发送ACK
字节,然后两个设备都在 sync 模式下工作。此外,如果已经同步,则发送NACK
。
字节0x7F
为0
起始位,然后从#7到#1 1
数据位,然后0
#0数据位然后1
停止位。该位序列允许通过定时器输入捕获来同步从器件。