串口基本空闲中断和DMA实现不定长数据接收,在实现应用中用得很多,特别是Modbus协议。现在,有了cube,在初始化配置上,确实方便了很多,但从标准外设库转过来,还是需要适应一段时间。在工作中也用到了这一功能,借着二姨家的活动,把这点方法分享给大家,有不对之处,欢迎指正。
1.首先选择单片机,我是直接选择的Nucleo-144开发板。
2.可以看的出来,板上串口使用的是USART3,当然,我们还是要在左侧的功能树中将USART3使能,Asynchronous模式。
3.使能串口全局中断,实际只用到其中的空闲中断。
4.添加DMA,选择USART3_RX。其它保持默认,如图。
5.OK ,保存,生成工程文件。
6.代码。
/* USER CODE BEGIN 0 */
#define RX_BUFFER_SIZE 32 //用于接收到一帧数据的最大长度
uint8_t Rx_Buffer[RX_BUFFER_SIZE]; //保存接收到的一帧数据
uint32_t RxLength; //实际接收到的一帧数据的长度
uint8_t RxFlag; //接收到一帧数据标记
/*******************************************************************************
串口空闲中断回调函数,在stm32f4xx_it.c 中的 void USART3_IRQHandler(void) 中调用
*******************************************************************************/
void UsartIdle_Callback(void)
{
uint32_t tmp1 = 0U, tmp2 = 0U;
tmp1 = __HAL_UART_GET_FLAG(&huart3,UART_FLAG_IDLE);
if((tmp1 != RESET))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart3);
HAL_UART_DMAStop(&huart3);
tmp2 = hdma_usart3_rx.Instance->NDTR;
RxLength = RX_BUFFER_SIZE - tmp2;
RxFlag = 1;
}
}
/*******************************************************************************
解析接收到的一帧数据,根据实际应用修改
*******************************************************************************/
void Rx_Handle(void)
{
char *pString;
if(RxFlag)
{
RxFlag = 0;
pString = "unknown\r\n";
if(RxLength == 3)
{
if(strncmp(Rx_Buffer, "MCU", 3) == 0)
{
pString = "MCU:STM32F446ZET6\r\n";
}
}
else if(RxLength == 5)
{
if(strncmp(Rx_Buffer, "Board", 5) == 0)
{
pString = "Board:Nucleo-144\r\n";
}
else if(strncmp(Rx_Buffer, "Flash", 5) == 0)
{
pString = "Flash:512 KB Flash\r\n";
}
}
else if(RxLength == 4)
{
if(strncmp(Rx_Buffer, "SRAM", 4) == 0)
{
pString = "SRAM:128+4 KB SRAM\r\n";
}
}
HAL_UART_Transmit(&huart3, pString, strlen(pString), 1000);
HAL_UART_Receive_DMA(&huart3, Rx_Buffer, RX_BUFFER_SIZE); //重新启动串口接收
}
}
/* USER CODE END 0 */
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration----------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART3_UART_Init();
/* USER CODE BEGIN 2 */
__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE); //使能空闲中断
HAL_UART_Receive_DMA(&huart3, Rx_Buffer, RX_BUFFER_SIZE); //启动串口接收
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
Rx_Handle();
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
其他函数由Cube生成,我就不复制了,主要增加两个函数,一个是串口空闲中断的处理函数,一个是数据帧的解析函数。
void USART3_IRQHandler(void)
{
/* USER CODE BEGIN USART3_IRQn 0 */
UsartIdle_Callback();
/* USER CODE END USART3_IRQn 0 */
HAL_UART_IRQHandler(&huart3);
/* USER CODE BEGIN USART3_IRQn 1 */
/* USER CODE END USART3_IRQn 1 */
}
7.实际效果
8.上传工程文件
F446Test.zip
(2.5 MB)
|