STM32HAL库CubeMx FreeRTOS 消息队列 DMA串口空闲中断接收消息

        本文主要讲在FreeRTOS中使用消息队列传输串口接收到的不定长数据,主要传指针。串口方面使用DMA接收,然后串口空闲中断进行接收数据的管理。

        原理:创建一个消息队列、创建串口数据缓冲区结构体数组。数组长度多少,队列长度就有多长。该结构体至少包含数据缓冲区和数据大小,后面有代码演示的。创建完成后让DMA接收的数据放在结构体里的数据缓冲区里面,然后用指针指向这整个结构体,最后通过消息队列发送出去

        传指针的方法可以快速传输数据,哪怕有几千的字节,只要定义好保存数据的缓冲区,最后也不过是往消息队列里面发一个几字节大小的指针罢了。

一、CubeMX配置

1.1 配置串口
1.1.1 打开串口

 1.1.2 打开接收DMA传输,设置优先级最高

1.1.3 打开串口全局中断

1.2 配置FreeRTOS
1.2.1 打开FreeRTOS,下面配置默认就好了,新手一般不用改什么,了解FreeRTOS的就根据你自己需要去更改

1.2.2 注意:因为FreeRTOS用了系统滴答时钟,所以这里更换一下系统时钟源

1.2.3 新建一个线程,用作接收和处理串口接收到的数据

 1.2.4 创建一个消息队列

        队列单个数据大小,我们直接用指针(STM32一般是4字节大小,你也可以直接填4)。因为一会传输的是指针,而不是串口接收的实际数据。

配置已完成,开始写代码。

二、Keil部分

2.1勾选下use micro lib

三、代码部分

        分为图示和要添加的代码,不用你一个一个敲,都放在图示后面了。

3.1 在mian.h文件

        这里的缓冲区大小和缓冲区数量你们自己按照实际的项目情况来定义。例如在你的项目中是单次少量数据,但是短时间会有很多次,那么这里可以把UART_BUFFER_SIZE改小点,节省内存,然后UART_BUFFER_QUANTITY改大些,最后别忘了改一下队列的长度!要和这个UART_BUFFER_QUANTITY同样。

        以下为图示,后面可以直接复制。

只需添加以下代码:

/* 一、引用标准输入输出库 */
#include <stdio.h>

/* 二、定义串口数据缓冲区配置 */
#define UART_BUFFER_SIZE        (256)
#define UART_BUFFER_QUANTITY    (5)

/* 三、定义串口数据结构体,DMA传输的数据将保存在这里 */
typedef struct
{
    uint8_t buffer[UART_BUFFER_SIZE];   /* 存放数据的空间 */
    uint16_t size;                      /* 已存放数据的大小 */
}UART_RX_TypeDef;
3.2 在mian.c文件

添加变量。

添加处理函数:

要添加的代码:

/* 先定义好存放数据的空间,队列大小是5,这里就定义5个。 */
UART_RX_TypeDef uart_rx_data_t[UART_BUFFER_QUANTITY];
/* 定义一个变量用作分配上面定义的数据 */
uint8_t uart_buff_ctrl = 0;
/* 引用串口DMA handle  */
extern DMA_HandleTypeDef hdma_usart1_rx;
/* 队列 handle。去freertos.c文件里面找CubeMX给你创建好的。 */
extern osMessageQId uart_queueHandle;

/* Redirect printf function */
int fputc(int ch, FILE *f)
{
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000);
    return (ch);
}

void USART1_DMAHandler(void)
{
    if (RESET != __HAL_UART_GET_FLAG(&huart1, UART_FLAG_IDLE)) // 判断是否是空闲中断
    {
        UART_RX_TypeDef *pUartData; /* 定义指向创建串口数据的指针 */

        __HAL_UART_CLEAR_IDLEFLAG(&huart1); // 清除空闲中断标志
        HAL_UART_DMAStop(&huart1);          // 停止本次DMA传输

        /* 计算接收到的数据长度,放进串口数据结构体中 */
        uart_rx_data_t[uart_buff_ctrl].size = UART_BUFFER_SIZE - __HAL_DMA_GET_COUNTER(&hdma_usart1_rx);
        /* 将这个串口数据的结构体地址给指针 */
        pUartData = &uart_rx_data_t[uart_buff_ctrl];
        /* 把指向串口接收数据的指针放入消息队列。注意,这里传的是指针的地址,也就是指针串口数据结构体的指针的地址不能传pUartData本身 */
        xQueueSendFromISR(uart_queueHandle, &pUartData, NULL);
        /* 这里进行加一,使其下一次DMA传输时将接收的数据放到下一个串口缓冲区中 */
        uart_buff_ctrl++;
        /* 取余操作防止越界 */
        uart_buff_ctrl %= UART_BUFFER_QUANTITY;
        /* 重启开始DMA传输 */
        HAL_UART_Receive_DMA(&huart1, uart_rx_data_t[uart_buff_ctrl].buffer, UART_BUFFER_SIZE);
    }
}

在main函数中开启串口空闲中断和DMA传输。

这部分放main函数里面:

__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart1, uart_rx_data_t[uart_buff_ctrl].buffer, UART_BUFFER_SIZE);
3.3 在stm32f4xx_it.c文件

        如果你的是F1系列的,就去stm32f1xx_it.c里面去找,我这个就是f4。

引用外部函数声明

串口1中断调用处理函数

代码:

extern void USART1_DMAHandler(void);
void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
  USART1_DMAHandler();
  /* USER CODE END USART1_IRQn 0 */
  HAL_UART_IRQHandler(&huart1);
  /* USER CODE BEGIN USART1_IRQn 1 */

  /* USER CODE END USART1_IRQn 1 */
}
3.4 在freertos文件

找到我们的两个线程。主要是Uart_Thread线程函数

void Uart_Thread(void const *argument)
{
    /* USER CODE BEGIN Uart_Thread */
    UART_RX_TypeDef *pRecvUartData; /* 定义指向串口数据的指针 */

    printf("Uart Thread init. \r\n");
    /* Infinite loop */
    for (;;)
    {
        /* 一直等待直到有数据 */
        /* 参数1:队列handle */
        /* 参数2:放入接收消息的指针,也就是让它指向串口中断中已接收串口数据完成的结构体 */
        /* 参数3:等待时间,这里是等待永久,直到有数据 */
        if (xQueueReceive(uart_queueHandle, &pRecvUartData, portMAX_DELAY) == pdTRUE)
        {
            /* 打印或处理接收到的数据,这里为了演示做个串口回显 */
            HAL_UART_Transmit(&huart1, pRecvUartData->buffer, pRecvUartData->size, 1000);
        }
    }
    /* USER CODE END Uart_Thread */
}

添加完毕,现在可以Run了

四、演示

直接定时发送,有回显说明没问题了。

### 回答1: STM32是一款32位嵌入式微控制器系列,其中HAL(硬件抽象层)是一个软件库,用于与STM32微控制器的硬件进行高级的交互操作。FreeRTOS(实时操作系统)是一个开源的实时操作系统内核,用于实现多任务处理和任务调度。串口消息队列是HAL和FreeRTOS的结合应用,用于实现串口通信过程中的消息传递和任务调度。 在STM32中,通过HAL库中的串口接口可以实现与其他设备的串口通信。而使用FreeRTOS串口消息队列,可以将串口接收到的消息经过处理后,以队列形式存储,等待任务调度进行处理。该消息队列可以是有大小限制的,根据实际需求进行设置。 当串口收到消息时,HAL库会触发中断,将接收到的数据存储到缓冲区中。然后,通过FreeRTOS的任务和队列机制,将数据从缓冲区移动到消息队列中。任务可以从消息队列中获取消息,并进行处理,例如解析数据、执行相应的操作等。 在使用STM32 HAL与FreeRTOS串口消息队列时,需要注意以下几点: 1. 配置串口参数:使用HAL库的API函数配置串口的通信参数,如波特率、数据位、停止位等。 2. 创建任务:使用FreeRTOS的任务创建函数创建串口任务,指定任务优先级和任务堆栈大小。 3. 创建消息队列:使用FreeRTOS消息队列创建函数创建串口消息队列,指定消息队列的长度和消息大小。 4. 中断处理:在串口中断中,通过HAL库提供的函数将接收到的数据存储到缓冲区中。 5. 任务调度:使用FreeRTOS的任务调度机制,从缓冲区中将数据移动到消息队列中,并让任务从消息队列中获取消息进行处理。 6. 数据处理:任务从消息队列中获取消息后,根据消息进行相应的数据处理和操作。 通过STM32 HAL与FreeRTOS串口消息队列,可以实现高效的串口通信和任务调度。这样可以将不同的串口任务分配给不同的任务进行处理,提高系统的实时性和并行处理能力。同时,通过消息队列机制,可以避免数据的丢失和冲突,提高系统的稳定性和可靠性。 ### 回答2: stm32是一款基于ARM Cortex-M处理器的微控制器系列,具有强大的性能和丰富的外设功能。HAL (Hardware Abstraction Layer)是一种抽象硬件层,提供了简化外设驱动程序编写的API接口。FreeRTOS是一款开源的实时操作系统,能够提供任务调度和同步机制。 在使用stm32 hal freertos时,可以通过串口消息队列来实现任务间的通信。消息队列是一种先进先出的数据结构,用于在任务之间传递数据。 首先,需要初始化一个消息队列,通过调用FreeRTOS提供的API函数来创建。可以指定队列的大小和每个消息的大小。 然后,可以在发送任务中使用hal库提供的串口发送函数,将需要传递的消息发送给消息队列。发送任务可以使用FreeRTOS提供的队列发送函数来向消息队列发送消息接收任务可以使用hal库提供的串口接收函数,然后调用FreeRTOS提供的队列接收函数来从消息队列接收消息。 通过消息队列,发送任务可以将消息放入队列,接收任务可以从队列中获取消息。这样就实现了任务间的通信。 需要注意的是,由于消息队列是有限大小的,当队列已满时,发送任务可能会被阻塞。类似地,当队列为空时,接收任务可能会被阻塞。因此,在使用串口消息队列时,需要合理地设计队列的大小,以免造成问题。 总之,通过使用stm32 hal freertos串口消息队列,可以方便地实现任务间的通信,实现数据的传递和处理。这对于复杂的嵌入式系统开发是非常有用的。 ### 回答3: stm32是一种微控制器品牌,HAL(Hardware Abstraction Layer)是一种硬件抽象层,FreeRTOS是一款开源的实时操作系统。 在使用stm32微控制器时,我们可以使用HAL库来简化与硬件的交互。针对串口通信,HAL库提供了一系列的函数,使我们可以方便地通过串口与其他设备进行数据传输。 而FreeRTOS则可以帮助我们实现任务调度和管理。在使用串口进行数据传输时,我们可以利用FreeRTOS提供的消息队列特性来实现线程间的高效通信。 消息队列是一种用来在不同任务之间传递数据的机制。当一个任务需要发送数据时,它可以将数据封装成一个消息并将其发送到消息队列中。其他任务可以从消息队列接收消息,并根据接收到的消息做出相应的处理。 使用HAL库FreeRTOS时,我们可以通过以下步骤来实现串口消息队列: 1. 初始化串口:使用HAL库中的函数初始化串口,设置好串口的参数和通信速率。 2. 创建消息队列:使用FreeRTOS中的函数创建一个消息队列,设置好队列的长度和消息的大小。 3. 发送消息:在需要发送数据的任务中,使用FreeRTOS提供的函数将数据封装成消息,并将消息发送到消息队列中。 4. 接收消息:在需要接收数据的任务中,使用FreeRTOS提供的函数从消息队列接收消息,并根据接收到的消息进行处理。 通过以上步骤,我们可以实现多个任务之间的串口通信,并且保证数据的安全传输和高效处理。 总结起来,使用stm32HAL库FreeRTOS消息队列特性,可以方便地实现串口通信,并且保证多任务间的高效通信。
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Troubadour~

觉得不错,打赏支持一下!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值