You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

STM32中如何将UART接收的uint8_t缓冲区转换为Mesaj结构体?

STM32 UART DMA接收数据转Mesaj结构体实现方案

针对你的需求,在验证接收缓冲区长度为15字节后,可通过两种可靠方式完成uint8_t数组到Mesaj结构体的转换,同时需要注意内存对齐和字节序的问题:

前提准备:修正结构体内存布局

STM32默认的编译器对齐规则会给结构体成员添加填充字节,导致Mesaj结构体总大小超过15字节,因此必须给结构体添加打包属性,确保内存布局与接收字节流完全对应:

// GCC/Clang 使用 __attribute__((packed)),Keil 可替换为 __packed
typedef struct __attribute__((packed)) {
    uint8_t baslangic;
    uint16_t emirNo;
    uint8_t birimNo;
    uint32_t emirAdresi;
    uint8_t komut;
    uint8_t dataTipi;
    uint32_t data;
    uint8_t bitis;
} Mesaj;

方法一:手动逐成员赋值(推荐,兼容性强)

这种方式不依赖内存拷贝,可灵活处理字节序差异,适合对数据可靠性要求高的场景。假设串口发送端采用小端字节序(与STM32默认字节序一致),转换代码如下:

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
    if (huart->Instance == USART1)
    {
        HAL_UARTEx_ReceiveToIdle_DMA(&huart1, RxBuffer, RxBufferSize);
        __HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
            
        for (int i = Size; i < RxBufferSize; i++)
        {
            RxBuffer[i] = 0;
        }
                                
        if (Size == 15) 
        {
            Mesaj alinanMesaj;

            // 提取单字节成员
            alinanMesaj.baslangic = RxBuffer[0];
            alinanMesaj.birimNo = RxBuffer[3];
            alinanMesaj.komut = RxBuffer[8];
            alinanMesaj.dataTipi = RxBuffer[9];
            alinanMesaj.bitis = RxBuffer[14];

            // 提取16位成员(小端模式:低字节在前)
            alinanMesaj.emirNo = (uint16_t)RxBuffer[1] | ((uint16_t)RxBuffer[2] << 8);

            // 提取32位成员(小端模式:低字节在前)
            alinanMesaj.emirAdresi = (uint32_t)RxBuffer[4] | 
                                     ((uint32_t)RxBuffer[5] << 8) | 
                                     ((uint32_t)RxBuffer[6] << 16) | 
                                     ((uint32_t)RxBuffer[7] << 24);
            alinanMesaj.data = (uint32_t)RxBuffer[10] | 
                               ((uint32_t)RxBuffer[11] << 8) | 
                               ((uint32_t)RxBuffer[12] << 16) | 
                               ((uint32_t)RxBuffer[13] << 24);

            // 可选:验证帧头帧尾(根据协议要求)
            if (alinanMesaj.baslangic != 0xAA || alinanMesaj.bitis != 0x55) {
                // 处理帧格式错误
                return;
            }

            // 此处添加后续处理逻辑,比如使用alinanMesaj
        }
        else
        {
            // 处理长度不符情况,比如重置接收、记录错误等
        }
    }
}

若发送端采用大端字节序,只需反转多字节成员的字节顺序即可,以emirNo为例:

alinanMesaj.emirNo = (uint16_t)RxBuffer[2] | ((uint16_t)RxBuffer[1] << 8);

方法二:直接内存拷贝(简洁高效)

在结构体已添加打包属性的前提下,可直接通过memcpy完成转换,前提是发送端字节序与STM32一致:

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
    if (huart->Instance == USART1)
    {
        HAL_UARTEx_ReceiveToIdle_DMA(&huart1, RxBuffer, RxBufferSize);
        __HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
            
        for (int i = Size; i < RxBufferSize; i++)
        {
            RxBuffer[i] = 0;
        }
                                
        if (Size == 15) 
        {
            Mesaj alinanMesaj;
            // 直接拷贝15字节到结构体(sizeof(Mesaj)此时为15)
            memcpy(&alinanMesaj, RxBuffer, sizeof(Mesaj));

            // 可选:帧头帧尾验证
            if (alinanMesaj.baslangic != 0xAA || alinanMesaj.bitis != 0x55) {
                // 处理格式错误
                return;
            }

            // 后续处理逻辑
        }
        else
        {
            // 长度不符处理
        }
    }
}

注意事项

  1. 务必确认发送端与STM32的字节序一致,否则多字节成员会出现数据错误;
  2. 帧头帧尾的验证可有效过滤无效数据,建议根据通信协议添加;
  3. 若使用Keil编译器,结构体打包属性需替换为__packed。

内容的提问来源于stack exchange,提问作者Hasan Altay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.12 14:00:42