STM32CubeMX—串口空闲中断+DMA接收

STM32CubeMX—串口空闲中断+DMA接收_第1张图片

一.串口中断通信

串口中断方式的特点

  1. 发送数据时,将一字节数据放入数据寄存器DR;接收数据时,将DR的内容存放到用户存储区;
  2. 中断方式不必等待数据的传输过程,只需要在每字节数据收发完成后,由中断标志位触发中断,在中断服务程序中放入新的一字数据或者读取接收到 的一字节数据;
  3. 在传输数据量较大,且通信波特率较高(大于38400)时,如果采用中断方式,每收发一个字节的数据,CPU都会被打断,造成CPU无法处理其他事务。因此在批量数据传输,通信波特率较高时,建议采用DMA方式。

 中断代码如下

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
  if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_RXNE) != RESET)
  {
    if (rxReceiveCount1 < 20)
    {
      rxBuffer1[rxReceiveCount1]=(uint8_t)(huart1.Instance->DR);
      ++rxReceiveCount1;
    }
    else
    {
      rxReceiveCount1 = 0;
    }
    __HAL_UART_CLEAR_FLAG(&huart1, UART_FLAG_RXNE);
  }
  else if (__HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE) != RESET)
  {

    __HAL_UART_CLEAR_IDLEFLAG(&huart1);
    uint32_t tmp1;
    tmp1 = huart1.Instance->SR;
    tmp1 = huart1.Instance->DR;


    rxFrameFlag1 = 1;
  }

  /* USER CODE END USART1_IRQn 0 */

  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}

/**

HAL_UART_Receive_IT(&huart1, (uint8_t *)&rc_data, 1)的作用是:

  1. 启动UART1的中断接收模式:该代码将启动UART1的中断接收模式,使UART1开始等待接收数据。

  2. 指定接收缓冲区:将rc_data变量的地址作为接收数据的缓冲区地址。这意味着当UART1接收到数据时,数据将存储在rc_data变量中。

  3. 指定缓冲区大小:1表示接收数据的大小为1个字节。这意味着当UART1接收到1个字节的数据时,将触发一个接收中断,并将数据存储在rc_data变量中。

需要注意的是,在初始化UART1时,需要先调用一次该函数,来启动UART1的中断接收模式;再接受完一个数据后,也需要再调用该函数来重新启动UART1的中断接收模式,以等待接收下一个字节的数据。

二.串口空闲中断+DMA

1.空闲中断接收

        空闲中断接收,当一帧数据接收完成之后,串口会进入到空闲中断中去,然后在空闲中断中处理收到的数据。这种模式对处理不定长数据帧带来很大的便利,我们不必频繁的进入接收中断处理数据,但是弊端也是明显的,由于每次都要接收完一个完整的数据帧后才空闲中断,所以当一帧数据出错时,我们也不得不接收这帧错误的数据。在通讯可靠的场合,使用空闲中断接收模式接收串口数据,将会大大提高系统的性能。

2.DMA

1.简介

DMA(Direct Memory Access)—直接存储器存取,是单片机的一个外设,它的主要功能是用来搬数
据,但是不需要占用 CPU ,即在传输数据的时候, CPU 可以干其他的事情,好像是多线程一样。

2、使用场景

DMA用在只需要传输数据,不需要处理数据的地方,有三种传输方式:

  • 外设→存储器(例:从串口RDR寄存器写入某数据buf)
  • 存储器→外设(例:从某数据buf写入串口TDR寄存器)
  • 存储器→存储器(例:复制某特别大的数据buf)

3、指针递增

在传输数据时,可以配置指向传输双方数据的指针是否自动向后递增。通过单个寄存器访问外设源或目标数据时,禁止递增模式十分有用。
通常如下图配置:STM32CubeMX—串口空闲中断+DMA接收_第2张图片

Cubemx配置

 串口设置STM32CubeMX—串口空闲中断+DMA接收_第3张图片

 DMA设置STM32CubeMX—串口空闲中断+DMA接收_第4张图片

 开启全局中断STM32CubeMX—串口空闲中断+DMA接收_第5张图片

最后直接生成文件 

代码编写

1.在usart.c文件中添加

定义变量

/* USER CODE BEGIN 0 */
volatile uint8_t rx_len=0;  //接收到的数据长度
volatile uint8_t recv_end_flag=0;//接收完成标志
uint8_t rx_buffer[200];//缓存数组
/* USER CODE END 0 */

 开启空闲中断和dma接收

  /* USER CODE BEGIN USART1_Init 2 */
  __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE); //使能空闲中断
  HAL_UARTEx_ReceiveToIdle_DMA(&huart1,rx_buffer,200); //开启DMA接收

  /* USER CODE END USART1_Init 2 */

重定义fputc,是为了能使用printf函数 

/* USER CODE BEGIN 1 */
//重定向fputc函数
int fputc(int ch, FILE *f)
{
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF);
    return ch;
}
/* USER CODE END 1 */


2.在usart.h文件中添加

#include 

/* USER CODE BEGIN Includes */
extern  volatile uint8_t rx_len ;  //接收一帧数据的长度
extern volatile uint8_t recv_end_flag; //一帧数据接收完成标志
extern uint8_t rx_buffer[200];  //接收数据缓存数组

注意这里的#include ,不添加的话重定向fputc函数那里会报错

3.在中断函数中添加

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */    
  uint32_t tmp_flag = 0;
    uint32_t temp;
    tmp_flag =__HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE); //获取IDLE标志位
    if((tmp_flag != RESET))
    { 
        __HAL_UART_CLEAR_IDLEFLAG(&huart1);//
        temp = huart1.Instance->SR;  
        temp = huart1.Instance->DR; 
        HAL_UART_DMAStop(&huart1); 
        temp  = hdma_usart1_rx.Instance->CNDTR;//获取此时DMA中未传输的数据个数
        rx_len =  200 - temp; //总计数减去未传输的数据个数,得到此次接收到的数据个数
        recv_end_flag = 1;		
    }
    HAL_UART_IRQHandler(&huart1);	

  /* USER CODE END USART1_IRQn 0 */
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}

这里不使用回调函数

4.在main.c中添加

  while (1)
  {
    /* USER CODE END WHILE */
    if(recv_end_flag ==1)			
		{	
			printf("接收到的数据长度为%d\r\n",rx_len);
			HAL_UART_Transmit(&huart1,rx_buffer, rx_len,200);
			for(uint8_t i=0;i

这里只是测试代码,将接收到的数据再利用串口输出到串口助手

5.结果

STM32CubeMX—串口空闲中断+DMA接收_第6张图片

当数据接收间隔时间很短的情况下,这里是1ms,数据接收会出错;在10ms后就正常

注意事项

1.程序下载到板子上没反应,只有在一步一步调试时才有输出。最后勾选了Use MicoLIB后程序就正常运行了

 STM32CubeMX—串口空闲中断+DMA接收_第7张图片

2.输出中文时串口助手上显示乱码,代码格式要改为GB 2312,但直接在keil上修改没什么用,我这里是在vscode上修改格式后保存,在keil上运行就行了。

STM32CubeMX—串口空闲中断+DMA接收_第8张图片

你可能感兴趣的:(stm32,单片机,嵌入式硬件)