实现:控制小灯亮灭 发送R1亮

一、搬运小助手DMA

cpu每次触发非空中断就要跑回来搬运数据,也会占用cpu的性能,所以可以调用DMA(直接内存访问)来代替cpu进行搬运

开启DMA方法:

1.串口端口中添加DMA TX和RX的通道,然后

2..使用发送HAL_UART_Transmit_DMA(&huart1, receiveDate, 2);  接收:HAL_UART_Receive_DMA(&huart1, receiveDate, 2);

这2个函数就是在串口中断收发IT上改成DMA,就变成了中断DMA收发,但是中断回调函数还是void HAL_UART_RxCpltCallback,这个就不是串口的中断了,DMA会调用自己的传输完成中断。

代码示例:

/* USER CODE BEGIN PV */
uint8\_t receiveDate\[2\];
\* USER CODE END PV *\

            / USER CODE BEGIN 0 /
            void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
            HAL_UART_Transmit_DMA(&huart1, receiveDate, 2);
          GPIO_PinState state = GPIO_PIN_SET;   //定义gpio_pinstate类型的state变量,默认成高电平
          if(receiveDate[1] == '0'){
          state = GPIO_PIN_RESET;
          }
          //判断receivedate的第0位数字是不是0,如果是0就设置成低电平,如果不是则保持高电平
          if(receiveDate[0] == 'R'){
          HAL_GPIO_WritePin(LED_RED_GPIO_Port, LED_RED_Pin, state);
          }else if(receiveDate[0] == 'G'){
          HAL_GPIO_WritePin(LED_RED_GPIO_Port, LED_RED_Pin, state);
          }else if(receiveDate[0] == 'B'){
          HAL_GPIO_WritePin(LED_RED_GPIO_Port, LED_RED_Pin, state);
          }
          //判断第二位是R,G,B,则输出相应端口高电
          HAL_UART_Receive_DMA(&huart1, receiveDate, 2);
          //继续接收
            }
            / USER CODE END 0 /

            /* USER CODE BEGIN 2 */
            HAL_UART_Receive_DMA(&huart1, receiveDate, 2);
            /* USER CODE END 2 */

二、接收不定长数据

1.原理

主要是靠 串口空闲中断(ldle) 来接收不定长数据,只有当串口从忙碌转为空闲时才会触发。空闲中断发生时,就判断数据接收完了,然后进行数据处理。

2.使用方法

2.1接收数据函数:HAL_UARTEx_ReceiveToIdle_DMA(&huart1, receiveDate, sizeof(receiveDate)); 后面长度是判断变量声明时的长度,HAL_UART_Transmit_DMA(huart, receiveDate, sizeof(receiveDate));//把接收的数据发送出去

2.2.这个触发的中断函数是:void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size) 与上面中断触发的函数唯一区别是传参多了size,

2.3DMA在数据传送过半时也会触发中断,就会导致数据传输不完整,要在每次触发时关闭一下传输过半中断,关闭过半中断代码:__HAL_DMA_DISABLE_IT(&hdma_usart1_rx,DMA_IT_HT);

2.4.

代码示例:

    /* USER CODE BEGIN PV */
    uint8_t receiveDate[50];  //全局变量长度50
    /* USER CODE END PV */

    /* USER CODE BEGIN 0 */
    void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){ //中断处理函数
    if(huart == &huart1){//确认是谁触发了回调函数
    HAL_UART_Transmit_DMA(huart, receiveDate, sizeof(receiveDate));//把接收的数据发送出去
    HAL_UARTEx_ReceiveToIdle_DMA(huart, receiveDate, sizeof(receiveDate));//再次启用接收函数
    __HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
    }
    }
    /* USER CODE END 0 */

    /* USER CODE BEGIN 2 */
    HAL_UARTEx_ReceiveToIdle_DMA(&huart1, receiveDate, sizeof(receiveDate));
    __HAL_DMA_DISABLE_IT(&hdma_usart1_rx,DMA_IT_HT);
    /* USER CODE END 2 */

错误提示:hdma_usart2_rx没找到

如果接收过半中断对你的逻辑判断是没有影响的话, 可以不禁用. 2. 按照视频里的讲解,是没有问题的, 但是如果你在CubeMX的Project Manager->Code Generator里勾选了Generate peripheral initialization as a pair of '.c/.h. files per peripheral, hdma_usart2_rx就会定义到usart.c, 并且usart.h中没有声明, 你只需要自己在usart.h中添加extern DMA_HandleTypeDef hdma_usart3_rx; 就好了,或者去MX里取消勾选

学习教程视频地址:

【工作STM32】第10集 STM32串口DMA模式与收发不定长数据 | keysking的stm32教程

最后修改:2024 年 09 月 12 日 12 : 09 PM
如果觉得我的文章对你有用,请随意赞赏