【STM32L4】UART4串口DMA空闲中断接收

环境

  • STM32L476G-DISCO 开发板
  • STM32CubeIDE 1.1.0
  • STM32CubeMX 5.4.0
  • 说明:由于STM32L476G-DISCO 开发板将UART4串口的RX(PA1)和TX(PA0)两个引脚分别用于JoyStick的按键输入,和地相连,所以如果同样使用STM32L476G-DISCO开发板的UART4引脚做测试,需要根据原理图,将电路板的C43\C42\R59断开(硬件小白,不知道不断可不可以)。

STM32CubeMX配置

UART4配置

  • 打开UART4,选择Asynchronous异步通信模式。参数设置默认。
    【STM32L4】UART4串口DMA空闲中断接收_第1张图片

  • 中断(NVIC)设置,打开串口总中断。
    【STM32L4】UART4串口DMA空闲中断接收_第2张图片

  • DMA设置,打开接收Rx的DMA通道。
    【STM32L4】UART4串口DMA空闲中断接收_第3张图片

  • GPIO设置,选择Rx和Tx的GPIO引脚。默认打开即可。
    【STM32L4】UART4串口DMA空闲中断接收_第4张图片

  • 整体的引脚视图
    【STM32L4】UART4串口DMA空闲中断接收_第5张图片

  • 时钟配置,选择自动生成的配置即可。
    【STM32L4】UART4串口DMA空闲中断接收_第6张图片

之后生成工程文件即可。实际用的是STM32CubeIDE创建的工程,直接生成代码。

相关代码(只贴出修改的代码)

usart.c

    /* UART4 init function */
    void MX_UART4_Init(void) {

        huart4.Instance = UART4;
        huart4.Init.BaudRate = 115200;
        huart4.Init.WordLength = UART_WORDLENGTH_8B;
        huart4.Init.StopBits = UART_STOPBITS_1;
        huart4.Init.Parity = UART_PARITY_NONE;
        huart4.Init.Mode = UART_MODE_TX_RX;
        huart4.Init.HwFlowCtl = UART_HWCONTROL_NONE;
        huart4.Init.OverSampling = UART_OVERSAMPLING_16;
        huart4.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
        huart4.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
        if (HAL_UART_Init(&huart4) != HAL_OK) {
            Error_Handler();
        }
        //在这里添加__HAL_UART_ENABLE_IT(),打开huart4的空闲中断
        __HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE);
    }

stm32l4xx_it.c

    //从其他文件中找到定义的相关变量
    /* USER CODE BEGIN EV */
    extern uint8_t rxData[100];
    extern uint8_t tempData[100];
    extern uint8_t receiveFlag;
    /* USER CODE END EV */

    /**
     * @brief This function handles UART4 global interrupt.
     */
    void UART4_IRQHandler(void) {
    	/* USER CODE BEGIN UART4_IRQn 0 */
    	uint8_t temp;

    	if (__HAL_UART_GET_FLAG(&huart4, UART_FLAG_IDLE) != RESET) {
    		//空闲中断
    		//temp = huart4.Instance->ISR;

        //清除空闲中断标志位
    		__HAL_UART_CLEAR_IDLEFLAG(&huart4);

        //清除数据读寄存器
    		temp = huart4.Instance->RDR;
    		temp = temp;

        //关闭DMA传输通道,防止在处理数据过程中有新的数据被DMA导入
    		HAL_UART_DMAStop(&huart4);

        //对传输的数据进行转存处理,把rxData暂存区空闲出来,用来接收新的数据。
    		if (strlen(rxData) != 0) {
    			memcpy(tempData, rxData, strlen(rxData));
    			memset(rxData, 0x00, strlen(rxData));
    		}

        //再次清楚空闲中断标志位。打开空闲中断,重新启动串口DMA传输。
    		__HAL_UART_CLEAR_IDLEFLAG(&huart4);
    		__HAL_UART_ENABLE_IT(&huart4, UART_IT_IDLE);
    		HAL_UART_Receive_DMA(&huart4, rxData, 100);

        //接收标志位置位。通知在主函数中处理数据。
    		receiveFlag = SET;
    	}
    	/* USER CODE END UART4_IRQn 0 */
    	HAL_UART_IRQHandler(&huart4);
    	/* USER CODE BEGIN UART4_IRQn 1 */

    	/* USER CODE END UART4_IRQn 1 */
    }

main.c

    /* USER CODE BEGIN Includes */
    #include "string.h"
    /* USER CODE END Includes */

    //定义一些需要用到的全局变量。这些变量可能在其他文件中用到
    /* USER CODE BEGIN PV */
    uint8_t rxData[100] = { 0 };
    uint8_t tempData[100] = { 0 };
    uint8_t receiveFlag = RESET;
    /* USER CODE END PV */

    /* USER CODE BEGIN 4 */

    //定义UART错误回调函数,用来处理串口的各种错误。注意,如果是用多个串口同时工作,需要简单修改本函数中的判断逻辑,实现更好的兼容和代码的简洁。
    void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart) {
    	/* Prevent unused argument(s) compilation warning */
    	UNUSED(huart);

    	/* NOTE : This function should not be modified, when the callback is needed,
    	 the HAL_UART_ErrorCallback can be implemented in the user file.
    	 */
    	if (__HAL_UART_GET_FLAG(&huart4, UART_FLAG_ORE) != RESET) {
    		__HAL_UART_CLEAR_OREFLAG(&huart4);
    		HAL_UART_Receive_DMA(&huart4, rxData, 100);
    	}
    }

    //主函数
    /**
     * @brief  The application entry point.
     * @retval int
     */
    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();

    	/* USER CODE BEGIN Init */

    	/* USER CODE END Init */

    	/* Configure the system clock */
    	SystemClock_Config();

    	/* USER CODE BEGIN SysInit */

    	/* USER CODE END SysInit */

    	/* Initialize all configured peripherals */
    	MX_GPIO_Init();
    	MX_DMA_Init();
    	MX_UART4_Init();
    	/* USER CODE BEGIN 2 */
      //在最开始开启串口的DMA传输
      /*
      经过测试、如果这里的数据长度BUFFERSIZE设为10的话,在第一次接收到的数据超过10位数据时,只能收到前10位数据,
      之后就无法继续接收数据了。断点了一下,并没有进入ORE的错误处理回调函数。还需要进一步调试。如果有
      哪位大佬看出来问题,不吝赐教。
      */
    	HAL_UART_Receive_DMA(&huart4, rxData, BUFFERSIZE);
    	/* USER CODE END 2 */

    	/* Infinite loop */
    	/* USER CODE BEGIN WHILE */
    	while (1) {
    		/* USER CODE END WHILE */
        //当空闲中断一帧数据接收完成后,receiveFlag这个变量在中断函数中被置位。我们在主函数将接收到的数据再通过串口发送给上位机。
    		if (receiveFlag != RESET){
    			receiveFlag = RESET;
    			HAL_UART_Transmit(&huart4, tempData, strlen(tempData), 1000);
          memset(tempData, 0x00, strlen(tempData));
    		}
    		HAL_Delay(500);
    		/* USER CODE BEGIN 3 */
    	}
    	/* USER CODE END 3 */
    }
    /* USER CODE END 4 */

结果

将BUFFERSIZE设置为1024后,牺牲了一些空间,但是保证串口接收到的数据不会丢失是正确的。具体的结果图就不贴了。

你可能感兴趣的:(STM32)