打印
[应用方案]

APM32F407串口空闲中断在高速通信中的应用

[复制链接]
221|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主

背景

在工业控制、数据采集等应用场景中,串口(UART)经常被用于实时传输大数据量信息。然而,这些应用场景通常面临以下挑战:

  1. 数据帧长度不固定:协议复杂且数据帧长度动态变化,无法预先确定。
  2. 实时性要求高:高速通信下需要确保数据实时处理,避免丢包。
  3. 大数据量传输:频繁中断或轮询可能占用大量CPU资源,影响系统其他任务。

为解决这些问题,采用 DMA+UART空闲中断 的方式是一种高效的解决方案。DMA负责数据搬运,空闲中断检测帧结束,结合起来可以实现高性能的数据接收和分包处理。

设计方案

1. 方案概述

  • DMA负责搬运数据:将UART接收的数据直接存储到内存缓冲区,避免CPU参与每字节数据的搬运。
  • 空闲中断触发分包处理:检测到UART空闲状态后,触发中断,将缓冲区中的数据分解成完整数据帧。
  • 动态分包:通过检查帧结束标志(如换行符)动态切分数据帧,适应长度变化。

2. 系统架构图

image.png

详细实现步骤

1. USART和DMA初始化

USART配置

初始化UART的波特率、数据位、停止位、校验位等,配置为DMA接收模式:

#include "apm32f4xx_usart.h"

// 定义USART初始化函数
void USART_Init_Config(USART_T *usart)
{
    USART_Config_T usartConfig;

    USART_ConfigStructInit(&usartConfig);
    usartConfig.baudRate = 115200;                    // 波特率115200
    usartConfig.wordLength = USART_WORD_LEN_8B;      // 8位数据长度
    usartConfig.stopBits = USART_STOP_BIT_1;         // 1个停止位
    usartConfig.parity = USART_PARITY_NONE;          // 无校验
    usartConfig.mode = USART_MODE_TX_RX;             // 启用收发功能

    USART_Config(usart, &usartConfig);
    USART_Enable(usart);                             // 启用USART
}

DMA配置

配置DMA接收缓冲区,将UART数据直接传输到内存中:

#include "apm32f4xx_dma.h"

#define DMA_BUFFER_SIZE 1024
uint8_t dmaBuffer[DMA_BUFFER_SIZE];  // DMA缓冲区

void USART_DMA_Init(USART_T *usart)
{
    DMA_Config_T dmaConfig;
    dmaConfig.periphBaseAddr = (uint32_t)&usart->DATA_B.DATA;  // USART数据寄存器地址
    dmaConfig.memoryBaseAddr = (uint32_t)dmaBuffer;           // 缓冲区地址
    dmaConfig.direction = DMA_DIR_PERIPH_TO_MEMORY;
    dmaConfig.bufferSize = DMA_BUFFER_SIZE;
    dmaConfig.memoryInc = ENABLE;  // 递增缓冲区地址
    dmaConfig.periphInc = DISABLE; // 禁止外设地址递增

    DMA_Config(DMA1_Channel5, &dmaConfig);
    DMA_Enable(DMA1_Channel5);     // 启用DMA

    USART_EnableDMA(usart, USART_DMA_RX);  // 启用USART的DMA接收
}

2. 空闲中断配置

空闲中断用于检测接收数据帧结束:


#include "apm32f4xx_usart.h"
#include "apm32f4xx_int.h"

// 使能空闲中断
void USART_Enable_IDLE_Interrupt(USART_T *usart)
{
    USART_EnableInterrupt(usart, USART_INT_IDLE);  // 开启空闲中断
    NVIC_EnableIRQRequest(USART1_IRQn, 1, 0);      // 配置中断优先级
}

3. 中断处理与动态分包

中断处理函数

当UART检测到空闲状态时触发中断,计算接收数据长度并动态分包,通过帧结束符(如换行符)切分数据帧,并解析处理:

void ProcessUARTData(uint16_t length)
{
    static uint8_t frameBuffer[256]; // 临时帧缓冲区
    static uint16_t frameIndex = 0;

    for (uint16_t i = 0; i < length; i++)
    {
        frameBuffer[frameIndex++] = dmaBuffer[i];

        if (frameBuffer[frameIndex - 1] == '\n')  // 检测帧结束符
        {
            HandleCompleteFrame(frameBuffer, frameIndex);  // 处理完整帧
            frameIndex = 0;  // 重置帧缓冲区
        }
    }
}

// 数据帧处理函数
void HandleCompleteFrame(uint8_t *frame, uint16_t length)
{
    // 解析数据帧的内容
    // 示例:打印接收到的帧
    printf("Received Frame: %s", frame);
}
void USART1_IRQHandler(void)
{
    static uint16_t lastDMAIndex = 0;

    // 检测空闲中断
    if (USART_ReadIntFlag(USART1, USART_INT_IDLE))
    {
        USART_ClearIntFlag(USART1, USART_INT_IDLE);  // 清除中断标志

        uint16_t currentDMAIndex = DMA_GetCurrentDataCounter(DMA1_Channel5);
        uint16_t receivedLength = DMA_BUFFER_SIZE - currentDMAIndex;

        ProcessUARTData(receivedLength);  // 调用数据分包函数
        lastDMAIndex = currentDMAIndex;  // 更新最后处理位置
    }
}

方案特点

  1. 支持大数据量传输: 通过DMA接收数据,避免频繁中断或轮询,占用更少的CPU资源。
  2. 动态分包: 根据帧结束符(如换行符)动态切分帧,支持长度不固定的数据帧。
  3. 实时性强: 空闲中断快速响应帧结束状态,结合DMA实现高效通信。
  4. 低资源占用: 数据搬运完全交由硬件完成,CPU专注于数据帧解析。

应用场景

  1. 工业通信协议:如Modbus RTU、RS485总线通信等。
  2. 传感器数据采集:高频采样数据实时上传。
  3. 文件传输协议:如Xmodem/Ymodem高速传输协议。

总结

本文详细说明了如何基于APM32F407的串口功能,利用DMA和空闲中断实现高效的数据接收与分包处理。该方案特别适合高速通信、大数据量传输以及动态数据帧的应用场景,为嵌入式开发提供了高效可靠的参考实现。如果有更复杂的应用需求,可以在此基础上进一步优化。

使用特权

评论回复
沙发
问天少年| | 2024-12-10 18:38 | 只看该作者
还可以加环形缓冲

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

29

主题

32

帖子

0

粉丝