测试板卡: 正点原子MINISTM32(STM32F103RB)
实现思路: 位机向STM32发送连续数据,STM32串口中断一直接收,期间使用定时器控制接收时间,如果在3.5个时间字符时间内没有接收到任何数据,那么定时器就判定为一帧数据接收完毕,然后根据modbus协议处理接收到的数据就可以了。
MODBUS RTU 方式的收发都需要3.5个字符的等待时间,这个时间可以通过定时器控制,两个字符之间的间隔时间按照9600的波特率算,1s可以发9600/8=1200字节,1个字节发送的时间就是1/1200≈833微秒,3.5个字符时间就是1/1200*3.5≈2917微秒,这里我为了方便直接用了5ms,如果你测试不行的话,调小定时器的超时时间。
贴一下主要的代码片段:串口接收中断回调函数:
串口1为调试串口
串口3作为modbus的收发数据端口
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance == DEBUG_UART_HANDLER.Instance)
{
if ((DEBUG_UART_RX_STA & 0x8000) == 0) // 接收未完毕
{
if (DEBUG_UART_RX_STA & 0x4000) // 已经接收到了回车符
{
if (DEBUG_UART_RX_BYTE == '\n') DEBUG_UART_RX_STA |= 0x8000; // 本次接收到的是换行符,标记接收到了换行符
else DEBUG_UART_RX_STA = 0; // 本次接收到的不是换行符,视为接收错误,状态置为初始
}
else
{
if (DEBUG_UART_RX_BYTE == '\r') DEBUG_UART_RX_STA |= 0x4000; // 本次接收到的是回车符,标记接收到了回车符
else
{
DEBUG_UART_RX_BUF[DEBUG_UART_RX_STA & 0x3FFF] = DEBUG_UART_RX_BYTE; // 将本次接收到的数据保存到接收缓存中
if (DEBUG_UART_RX_STA++ >= DEBUG_UART_RX_LEN) DEBUG_UART_RX_STA = 0; // 连续接收到的数据长度高于最大接收长度,则视为接收错误
}
}
}
HAL_UART_Receive_IT(huart, &DEBUG_UART_RX_BYTE, 1); // 再次使能接收中断
}
else if (huart->Instance == huart3.Instance)
{
if (MODBUS_RX_STA < MODBUS_RX_LEN)
{
__HAL_TIM_SET_COUNTER(&htim4, 0); // 清除5ms定时器的计数值
if (MODBUS_RX_STA == 0) TIM4_Set(TIM4_ENABLE); // 如果接收为初始状态,则启动定时器
MODBUS_RX_BUF[MODBUS_RX_STA++] = MODBUS_RX_BYTE; // 接收数据
}
else
{
MODBUS_RX_STA |= 0x8000; // 超长,标记接收结束
}
HAL_UART_Receive_IT(huart, &MODBUS_RX_BYTE, 1); // 再次使能接收中断
}
}
|