[AT32F421] AT32F421使用DMA+USART

[复制链接]
 楼主| 盗铃何须掩耳 发表于 2025-2-28 15:48 | 显示全部楼层 |阅读模式
USART引脚配置:将USART的TX(发送)和RX(接收)引脚设置为复用功能模式。
  1. gpio_init_type gpio_init_struct;
  2. // 使能GPIO时钟(例如USART1使用PA9/PA10)
  3. crm_periph_clock_enable(CRM_GPIOA_PERIPH_CLOCK, TRUE);
  4. // 配置TX引脚为复用推挽输出
  5. gpio_init_struct.gpio_pins = GPIO_PINS_9;
  6. gpio_init_struct.gpio_out_type = GPIO_OUTPUT_PUSH_PULL;
  7. gpio_init_struct.gpio_pull = GPIO_PULL_NONE;
  8. gpio_init_struct.gpio_mode = GPIO_MODE_MUX;
  9. gpio_init(GPIOA, &gpio_init_struct);
  10. // 配置RX引脚为浮空输入
  11. gpio_init_struct.gpio_pins = GPIO_PINS_10;
  12. gpio_init_struct.gpio_mode = GPIO_MODE_INPUT;
  13. gpio_init(GPIOA, &gpio_init_struct);
初始化USART
配置USART的基本参数(波特率、数据位、停止位等),并启用DMA发送/接收功能:
  1. usart_init_type usart_init_struct;
  2. // 使能USART时钟
  3. crm_periph_clock_enable(CRM_USART1_PERIPH_CLOCK, TRUE);
  4. // 配置USART参数
  5. usart_init_struct.baud_rate = 115200;
  6. usart_init_struct.word_length = USART_WORD_LENGTH_8B;
  7. usart_init_struct.stop_bits = USART_STOP_BITS_1;
  8. usart_init_struct.parity = USART_PARITY_NONE;
  9. usart_init_struct.mode = USART_MODE_TXRX;
  10. usart_init(USART1, &usart_init_struct);
  11. // 使能USART
  12. usart_enable(USART1, TRUE);
DMA发送配置(内存到USART)​
  1. dma_init_type dma_init_struct;
  2. // 使能DMA时钟
  3. crm_periph_clock_enable(CRM_DMA1_PERIPH_CLOCK, TRUE);
  4. // 配置DMA通道(根据数据手册选择对应USART的DMA通道,例如USART1_TX用DMA1_CH4)
  5. dma_reset(DMA1_CHANNEL4);
  6. dma_default_para_init(&dma_init_struct);
  7. dma_init_struct.direction = DMA_DIR_MEMORY_TO_PERIPHERAL;
  8. dma_init_struct.memory_data_width = DMA_MEMORY_DATA_WIDTH_BYTE;
  9. dma_init_struct.peripheral_data_width = DMA_PERIPHERAL_DATA_WIDTH_BYTE;
  10. dma_init_struct.priority = DMA_PRIORITY_MEDIUM;
  11. dma_init_struct.memory_inc_enable = TRUE;  // 内存地址自增
  12. dma_init_struct.peripheral_inc_enable = FALSE;
  13. dma_init_struct.loop_mode_enable = FALSE;  // 非循环模式
  14. dma_init_struct.peripheral_address = (uint32_t)&USART1->dt; // USART数据寄存器地址
  15. dma_init(DMA1_CHANNEL4, &dma_init_struct);
  16. // 使能USART的DMA发送请求
  17. usart_dma_transmitter_enable(USART1, TRUE);
DMA接收配置(USART到内存)​
  1. // 配置DMA通道(例如USART1_RX用DMA1_CH5)
  2. dma_reset(DMA1_CHANNEL5);
  3. dma_default_para_init(&dma_init_struct);
  4. dma_init_struct.direction = DMA_DIR_PERIPHERAL_TO_MEMORY;
  5. dma_init_struct.memory_inc_enable = TRUE;
  6. dma_init_struct.loop_mode_enable = TRUE;  // 循环模式(持续接收)
  7. dma_init_struct.peripheral_address = (uint32_t)&USART1->dt;
  8. dma_init(DMA1_CHANNEL5, &dma_init_struct);
  9. // 使能USART的DMA接收请求
  10. usart_dma_receiver_enable(USART1, TRUE);
启动DMA传输发送数据
  1. // 设置内存地址和传输数据量
  2. dma_memory_address_config(DMA1_CHANNEL4, (uint32_t)tx_buffer);
  3. dma_transfer_number_config(DMA1_CHANNEL4, tx_buffer_size);
  4. // 启动DMA传输
  5. dma_channel_enable(DMA1_CHANNEL4, TRUE);
接收数据

  1. // 设置接收缓冲区
  2. dma_memory_address_config(DMA1_CHANNEL5, (uint32_t)rx_buffer);
  3. dma_transfer_number_config(DMA1_CHANNEL5, rx_buffer_size);
  4. // 启动DMA接收(循环模式)
  5. dma_channel_enable(DMA1_CHANNEL5, TRUE);




Hdj123 发表于 2025-8-12 14:44 | 显示全部楼层
void usart_init(void)
{
    GPIO_InitType GPIO_InitStructure;
    USART_InitType USART_InitStructure;
    NVIC_InitType NVIC_InitStructure;
    DMA_InitType DMA_InitStructure;

    RCC_AHBPeriphClockCmd(RCC_AHBPERIPH_GPIOA, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1PERIPH_USART2, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPERIPH_DMA1, ENABLE);

    GPIO_PinAFConfig(GPIOA, GPIO_PinsSource2, GPIO_AF_1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinsSource3, GPIO_AF_1);

    GPIO_InitStructure.GPIO_Pins = GPIO_Pins_2 | GPIO_Pins_3; // USART2 TX/RX
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_MaxSpeed = GPIO_MaxSpeed_50MHz;
    GPIO_InitStructure.GPIO_OutType = GPIO_OutType_PP;
    GPIO_InitStructure.GPIO_Pull = GPIO_Pull_NOPULL;
    GPIO_Init(GPIOA, &GPIO_InitStructure); // USART2 GPIO config

    USART_InitStructure.USART_BaudRate = 921600;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART2, &USART_InitStructure); // USART2 config

    //USART_INTConfig(USART2, USART_INT_RDNE, ENABLE);
        USART_Cmd(USART2, ENABLE); // USART2 enable
    USART_INTConfig(USART2, USART_INT_IDLEF, ENABLE);
        USART_DMACmd(USART2, USART_DMAReq_Rx, ENABLE);
   

    DMA_Reset(DMA1_Channel5);
    DMA_DefaultInitParaConfig(&DMA_InitStructure);
    DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART2 ->DT;
    DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)dma_rx;
    DMA_InitStructure.DMA_Direction = DMA_DIR_PERIPHERALSRC;
    DMA_InitStructure.DMA_BufferSize = sizeof(dma_rx);
    DMA_InitStructure.DMA_PeripheralInc = DMA_PERIPHERALINC_DISABLE;
    DMA_InitStructure.DMA_MemoryInc = DMA_MEMORYINC_ENABLE;
    DMA_InitStructure.DMA_PeripheralDataWidth = DMA_PERIPHERALDATAWIDTH_BYTE;
    DMA_InitStructure.DMA_MemoryDataWidth = DMA_MEMORYDATAWIDTH_BYTE;
    DMA_InitStructure.DMA_Mode = DMA_MODE_CIRCULAR;//DMA_MODE_NORMAL;//
    DMA_InitStructure.DMA_Priority = DMA_PRIORITY_HIGH;
    DMA_InitStructure.DMA_MTOM = DMA_MEMTOMEM_DISABLE;
    DMA_Init(DMA1_Channel5, &DMA_InitStructure);
       
    NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

        DMA_ChannelEnable(DMA1_Channel5, ENABLE); // 启用DMA接收

}void USART2_IRQHandler(void)
{
#if 1
    if( USART_GetITStatus(USART2, USART_INT_IDLEF) != RESET)
    {
//                USART_ClearITPendingBit(USART2, USART_INT_IDLEF);
//                USART_ReceiveData(USART2);
                USART2->STS;
                USART2->DT;
               
        DMA_ChannelEnable(DMA1_Channel5, DISABLE);
                receiver.data_length = sizeof(dma_rx) - DMA_GetCurrDataCounter(DMA1_Channel5);
        DMA_SetCurrDataCounter(DMA1_Channel5, sizeof(dma_rx));
        DMA_ChannelEnable(DMA1_Channel5, ENABLE);
                receiver.frame_complete = 1;
                key_test ++;
    }
#endif
    //处理错误标志
    if(USART_GetFlagStatus(USART2, USART_FLAG_ORERR) != RESET)
    {
        USART_ClearFlag(USART2, USART_FLAG_ORERR);
        uint8_t data = USART_ReceiveData(USART2);
    }
}这个为什么有时候接收到的数据会不全
EchoInEons 发表于 2025-8-19 14:44 | 显示全部楼层
这个确实挺有用,直接用DMA搬运数据即可。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

50

主题

385

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部

50

主题

385

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部