概述
USART(通用同步异步收发器)的正确通信要求发送和接收的波特率必须相对接近地匹配,否则可能会发生通信错误。
在建立两个设备之间的通信链路时,自动波特率检测非常有用,其中从设备能够检测主控制器的波特率并据此进行自我调整。这需要一种自动机制来确定波特率。
一些ARM内核MCU设备中嵌入的USART外设提供了许多功能,包括自动波特率检测的硬件支持。
本应用说明的目的是介绍MCU微控制器的自动波特率检测功能,并为那些没有在硬件中实现此功能的MCU提供一种替代的软件方法。
1 适用范围
本应用说明适用于基于Arm®的32位微控制器。
注意:Arm是美国或其他地区Arm Limited(或其子公司)的注册商标。
2 硬件自动波特率检测
2.1 功能概述
自动波特率检测(ABR)使接收设备能够接受来自各种以不同速率工作的发送设备的数据,而无需事先建立数据速率。在一些MCU微控制器中,USART能够使用专用硬件自动确定波特率。
首先,需要明确的是,在MCU中,并非所有系列都支持硬件自动波特率检测。早期MCU并不支持这一功能,近期推出的新产品大多数都支持这一功能。此外,对于内置ABR的MCU而言,并非所有实例化USART接口均支持自动波特率检测。
其次,关于自动波特率检测(ABR)的工作原理,它是指接收设备通过检查第一个字符(通常是预先选择的标志字符)来确定传入数据速率的过程。MCU微控制器上的自动波特率检测功能内置了多种模式,这些模式基于不同的字符模式,包括:
- 模式0:以“1”位为开头的任意字符。
- 模式1:以10xx模式开头的任何字符。
- 模式2:0x7F。
- 模式3:0x55。
在所有ABR模式下,都会在同步数据接收期间多次检测波特率,并将每一次的检测值与上一次的检测值进行比较。但需要注意的是,在7位数据长度模式下,不支持0x7F和0x55帧检测ABR模式。
最后,MCU的官方为自动波特率检测功能提供了基于标准外设库和HAL库的参考例程,开发者进行需要详细了解以进行相关的代码配置。
总的来说,MCU的USART自动波特率检测功能为开发者提供了一种方便、灵活的方式来处理不同速率的数据传输,特别是在事先不知道系统通信速度或系统正在使用精确度相对较低的时钟源的情况下。
2.2 自动波特率检测模式
ABR(自动波特率检测)是指接收设备通过检查第一个字符(通常是预先选择的标志字符)来确定传入数据速率的过程。
MCU上的自动波特率检测功能基于不同的字符模式嵌入了各种模式:
- 模式0:以“1”位为开头的任意字符。
- 模式1:以10xx模式开头的任何字符。
- 模式2:0x7F(十六进制中的127,二进制中的01111111)。
- 模式3:0x55(十六进制中的85,二进制中的01010101)。
在使用这些模式时,通常需要在发送和接收设备之间约定一个特定的起始字符或字符模式,以便接收设备能够正确地检测并设置波特率。在配置USART的自动波特率检测功能时,需要选择适当的模式,并根据所选模式调整相关参数。
模式 | 描述 | 波形 |
0 | 在自动波特率检测(ABR)的过程中,当接收到的字符以“1”位开始时,USART会测量起始位的持续时间(即从下降边缘到上升边缘的时间)。 | |
1 | 以10xx模式开头的任意字符 在这种情况下,USART会测量起始位和第一个数据位的持续时间。这个持续时间是从下降边缘到下一个下降边缘测量的,以确保在信号斜率较慢的情况下具有更高的准确度。通过测量这两个位的持续时间,USART可以估算出数据的波特率。 | |
2 | 0x7F字符帧 在这种情况下,波特率首先在起始位结束时更新,然后在第6位结束时再次更新。这是通过检测特定字符(即0x7F,它在二进制中表示为01111111)的起始位和第六位来实现的,从而更准确地估算和设置波特率。 | |
3 | 0x55字符帧 在这种情况下,波特率首先在起始位结束时更新,然后在每一位结束时更新,最后在第6位结束时再次更新。与此同时,对于RX线的每一个中间转换,还会进行另一个检查。这种检查是为了进一步提高波特率估算的准确性,确保接收设备能够更可靠地与发送设备同步。 |
在激活自动波特率检测(ABR)之前,必须通过USARTx_CR2寄存器中的ABRMOD[1:0]字段选择一种ABR模式。在所有ABR模式下,在同步数据接收期间会多次测量波特率,并且每次都会与之前的测量结果进行比较。
注意:在7位数据长度模式下,不支持基于0x7F和0x55帧检测的ABR模式。
2.3 ABR的误差计算
USART的时钟源(fCK)决定了通信速度范围(特别是最大通信速度)。接收器通过区分有效的传入数据和噪声来实现不同的用户可配置过采样技术以进行数据恢复。这允许在最大通信速度和抗噪声/时钟不准确性之间取得平衡。
过采样方法通过编程USARTx_CR1寄存器中的OVER8位来选择,可以是波特率时钟的16倍或8倍。
USART时钟源频率必须与预期的通信速度兼容:
- 当过采样倍数为16时,波特率应在fCK/65535和fCK/16之间
- 当过采样倍数为8时,波特率应在fCK/65535和fCK/8之间。
波特率误差取决于USART时钟源、过采样方法和ABR模式。
其中:期望的波特率是由发送设备固定的。
实际的波特率是由USART接收器使用自动波特率检测操作确定的。
3 软件自动波特率检测
当硬件自动波特率检测不支持时,可以采用本节中描述的软件方法。
软件方法的基本思想是通过USARTx_RX引脚发送一个0x7F数据帧。这个引脚连接到EXTI线,它被配置为在每个上升边沿生成中断。
使用SysTick定时器测量两个上升边沿之间的时间间隔。这个时间间隔对应于8位的持续时间,因此:
- 位时间 = 计算出的持续时间 / 8
- 波特率 = 1 / 位时间
然后,基于计算出的波特率值来配置USARTx_BRR寄存器。
通过这种方式,软件可以估算出与发送设备匹配的波特率,并相应地配置USART接收器。这种方法虽然可能不如硬件自动波特率检测精确或快速,但在某些情况下可以作为替代方案来确保数据通信的可靠性。
图 1. 软件自动波特率检测概述
4 软件和硬件方法的设置
本设置示例使用了嵌入硬件自动波特率功能的MCU。
使用PC应用程序来向MCU发送和接收数据帧。
因此,测试了从600比特/秒到115200比特/秒范围内的标准波特率。使用另一个MCU设备作为发射器来测试可以达到的最高波特率值(9 Mbits/s)。
4.1 USART1配置示例
在两个示例中,MCU的配置如下:
/*##-1- Configure the UART peripheral
######################################*/
/* Put the USART peripheral in the Asynchronous mode (UART Mode) */
/* UART configured as follows:
- Word Length = 8 Bits
- Stop Bit = One Stop bit
- Parity = NONE parity
- BaudRate = 115200 baud It can be any other value as the USARTx_BRR register will be reprogrammed
- Hardware flow control disabled (RTS and CTS signals)
- The oversampling mode is 8 or 16 (Both are tested) */
UartHandle.Instance = USARTx;
UartHandle.Init.BaudRate = 115200;
UartHandle.Init.WordLength = UART_WORDLENGTH_8B;
UartHandle.Init.StopBits = UART_STOPBITS_1;
UartHandle.Init.Parity = UART_PARITY_NONE;
UartHandle.Init.HwFlowCtl = UART_HWCONTROL_NONE;
UartHandle.Init.Mode = UART_MODE_TX_RX;
UartHandle.Init.OverSampling = UART_OVERSAMPLING_16;
注意:USART1的时钟源是使用HSE PLL时钟源的72 MHz系统时钟。有些测试使用HSI时钟作为USART1的时钟源,这是为了检查HSI的不准确性对结果的影响。
4.2 硬件自动波特率检测
USART1被配置为自动检测波特率。用户需要在USART1初始化函数中选择ABR模式,如下所示:
/*##-2- Configure the AutoBaudRate method */
UartHandle.AdvancedInit.AdvFeatureInit =UART_ADVFEATURE_AUTOBAUDRATE_INIT;
UartHandle.AdvancedInit.AutoBaudRateEnable =
UART_ADVFEATURE_AUTOBAUDRATE_ENABLE;
/*Uncomment your appropriate mode */
//UartHandle.AdvancedInit.AutoBaudRateMode =
UART_ADVFEATURE_AUTOBAUDRATE_ONSTARTBIT;
//UartHandle.AdvancedInit.AutoBaudRateMode =
UART_ADVFEATURE_AUTOBAUDRATE_ONFALLINGEDGE;
//UartHandle.AdvancedInit.AutoBaudRateMode =
UART_ADVFEATURE_AUTOBAUDRATE_ON0X7FFRAME;
//UartHandle.AdvancedInit.AutoBaudRateMode =
UART_ADVFEATURE_AUTOBAUDRATE_ON0X55FRAME;
if (HAL_UART_Init(&UartHandle) != HAL_OK)
{
/* Initialization Error */
Error_Handler();
}
/* Wait until Receive enable acknowledge flag is set */
while(__HAL_UART_GET_FLAG(&UartHandle,UART_FLAG_REACK) == RESET)
{}
/* Wait until Transmit enable acknowledge flag is set */
while(__HAL_UART_GET_FLAG(&UartHandle,UART_FLAG_TEACK) == RESET)
{}
/* Loop until the end of Autobaudrate phase */
while(__HAL_UART_GET_FLAG(&UartHandle,UART_FLAG_ABRF) == RESET)
{}
一旦整个初始化完成,USART会等待从PC接收到数据后才开始自动波特率检测阶段。这个阶段的结束是通过ABRF标志来监测的。
- 如果自动波特率操作不成功,ABRE标志会被设置
- 如果自动波特率操作成功完成,会向PC发送一个确认数据。
/* If AutoBaudBate error occurred */
if (__HAL_UART_GET_FLAG(&UartHandle, UART_FLAG_ABRE)!= RESET)
{
Error_Handler();
}
else
{
/* Wait until RXNE flag is set */
while(__HAL_UART_GET_FLAG(&UartHandle,UART_FLAG_RXNE) == RESET)
{}
/* Send acknowledgement message*/
if (HAL_UART_Transmit_DMA(&UartHandle, (uint8_t *)aTxBuffer, TXBUFFERSIZE)
!= HAL_OK)
{
/* Transfer error in transmission process */
Error_Handler();
}
while (HAL_UART_GetState(&UartHandle) != HAL_UART_STATE_READY)
{
}
}
4.3 软件自动波特率检测
4.3.1 抽象硬件库HAL库初始化
暂停Tick增量以防止被SysTick中断唤醒。
HAL_Init();
HAL_SuspendTick();
4.3.2 配置系统时钟
配置系统时钟为72 MHz。
最终可以在主程序中执行SystemCoreClockUpdate函数来验证CPU的工作频率。
System Clock source = PLL (HSE)
PLLMUL = RCC_PLL_MUL9 (9)
Flash Latency(WS) = 2
4.3.3 中断设置
配置USARTx RX引脚以在每个上升边沿产生中断
static void EXTILine1_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* Enable GPIOE clock */
__GPIOE_CLK_ENABLE();
/* Configure PE1 pin as input floating */
GPIO_InitStructure.Mode = GPIO_MODE_IT_RISING;
GPIO_InitStructure.Pull = GPIO_NOPULL;
GPIO_InitStructure.Pin = GPIO_PIN_1;
HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);
/* Enable and set EXTI Line0 Interrupt to the lowest priority */
HAL_NVIC_SetPriority(EXTI1_IRQn, 2, 2);
HAL_NVIC_EnableIRQ(EXTI1_IRQn);
}
4.3.4 等待中断
当在RX引脚接收到0x7F时,等待中断结束。
/*Wait until the end of interrupt */
while (end_interrupt_flag != 1) {
BSP_LED_On(LED2);
}
/* Autobaudrate sequence : Update BRR register */
Autobaudrate();
/* Send acknowledgement */
if (HAL_UART_Transmit_DMA(&UartHandle, (uint8_t*)aTxBuffer, TXBUFFERSIZE) != HAL_OK)
{
/* Transfer error in transmission process */
Error_Handler();
}
while (HAL_UART_GetState(&UartHandle) !=HAL_UART_STATE_READY)
{}
/* Infinite loop */
while (1)
{}
4.3.5 自动波特率功能
static void Autobaudrate(void)
{
float tmp=0, elapsed;
uint32_t USART1_clk=0;
uint32_t start_time_val=0;
uint32_t BRR=0;
tmp += 0xFFFFFF - stop_time_val;
tmp -= start_time_val;
elapsed =(tmp/(SystemCoreClock/1000000))/8;
USART1_clk=SystemCoreClock;
if( (USART1->CR1 & 0x8000)== 0x8000)
{
/*In case of oversampling by 8*/
BRR =(elapsed*((2*USART1_clk)/1000000))+1;
USART1->BRR= BRR;
}
else
{
/*In case of oversampling by 16*/
BRR =(elapsed* ((USART1_clk)/1000000))+1;
USART1->BRR=BRR;
}
}
4.3.6 外部线路中断1请求处理
外部线路1中断请求:
第一次上升沿:temp=0,启动SysTick定时器
第二次上升沿:
• 停止SysTick计数器
• 获取编码时间
• 清除SysTick计数器
void EXTI1_IRQHandler()
{
HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_1);
if(temp==0)
{
HAL_SYSTICK_Config(0xFFFFFF);
temp++;
}
else
{
SysTick->CTRL &= SysTick_Counter_Disable;
/* Stop the Timer and get the encoding time */
GETMYTIME(&stop_time_val);
/* Clear the SysTick Counter */
SysTick->VAL = SysTick_Counter_Clear;
/* Clear the temp flag*/
temp=0;
/*end of interrupt*/
interrupt_flag=1;
}
4.3.7 所需的项目定义
#define SysTick_Counter_Disable ((uint32_t)0xFFFFFFFE)
#define SysTick_Counter_Enable ((uint32_t)0x00000001)
#define SysTick_Counter_Clear ((uint32_t)0x00000000)
#define GETMYTIME(_t) (*_t=SysTick->VAL)
5 结论
本文讨论了某些MCU中嵌入的硬件自动波特率检测功能。同时,它还提供了一种在软件中实现此功能的技术,作为未在硬件中实现此功能的MCU的解决方案。
尽管自动波特率检测在示例的初始阶段被应用,但它可以被扩展并在发射器和接收器设备检测到通信错误时随时使用。这使得应用程序更加健壮,允许主机在通信之间更改其波特率。