0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

如何使用DMA进行USART不定长度接收

中科芯MCU 来源:中科芯MCU 2025-02-18 17:01 次阅读

在上一讲中,我们对USART进行了简单介绍,并讲解了如何在不使用DMA的情况下进行不定长度数据接收,本讲将着重讲解如何使用DMA进行USART不定长度接收。

USART可以利用DMA连续通信。Rx缓冲器和Tx缓冲器的DMA请求是分别产生的。参考产品技术说明以确定是否可用DMA控制器。如果所用产品无DMA功能,发送器或接收器里所描述的方法使用USART。在USART2_SR寄存器里,可以清零TXE/RXNE标志来实现连续通信。

利用DMA发送

使用DMA进行发送,可以通过设置USART_CR3寄存器上的DMAT位激活。当TXE位被置为’1’时,DMA就从指定的SRAM区传送数据到USART_DR寄存器。为USART的发送分配一个DMA通道的步骤如下(x表示通道号):

在DMA控制寄存器上将USART_DR寄存器地址配置成DMA传输的目的地址。在每个TXE事件后,数据将被传送到这个地址;

在DMA控制寄存器上将存储器地址配置成DMA传输的源地址。在每个TXE事件后,将从此存储器区读出数据并传送到USART_DR寄存器;

在DMA控制寄存器中配置要传输的总的字节数;

在DMA寄存器上配置通道优先级;

根据应用程序的要求,配置在传输完成一半还是全部完成时产生DMA中断;

在DMA寄存器上激活该通道。

当传输完成DMA控制器指定的数据量时,DMA控制器在该DMA通道的中断向量上产生一中断。在发送模式下,当DMA传输完所有要发送的数据时,DMA控制器设置DMA_ISR寄存器的TCIF标志;监视USART_SR寄存器的TC标志可以确认USART通信是否结束,这样可以在关闭USART或进入停机模式之前避免破坏最后一次传输的数据;软件需要先等待TXE=1,再等待TC=1。

175ab9a8-edd4-11ef-9310-92fbcf53809c.png

图1 利用DMA发送

利用DMA接收

可以通过设置USART_CR3寄存器的DMAR位激活使用DMA进行接收,每次接收到一个字节,DMA控制器就就把数据从USART_DR寄存器传送到指定的SRAM区(参考DMA相关说明)。

为USART的接收分配一个DMA通道的步骤如下(x表示通道号):

通过DMA控制寄存器把USART_DR寄存器地址配置成传输的源地址。在每个RXNE事件后,将从此地址读出数据并传输到存储器;

通过DMA控制寄存器把存储器地址配置成传输的目的地址。在每个RXNE事件后,数据将从USART_DR传输到此存储器区;

在DMA控制寄存器中配置要传输的总的字节数;

在DMA寄存器上配置通道优先级;

根据应用程序的要求配置在传输完成一半还是全部完成时产生DMA中断;

在DMA控制寄存器上激活该通道。

当接收完成DMA控制器指定的传输量时,DMA控制器在该DMA通道的中断矢量上产生一中断。

17a2e6ba-edd4-11ef-9310-92fbcf53809c.png

图2 利用DMA接收

DMA通道

在CKS32F107xx DMA章节中,我们对DMA进行了基本介绍,根据各通道DMA请求表可以发现,USART1需要使用的DMA通道为DMA1的第4和第5通道。

17e1777c-edd4-11ef-9310-92fbcf53809c.png

图3 USART1 DMA通道

USART初始化程序

在该例程中,我们使用USART1,利用DMA接收并发送不定长度数据。

开启GPIO、USART1、DMA1时钟

对USART引脚进行配置,PA9映射TX,PA10映射RX;

初始化DMA1相关参数;

对USART参数进行配置,此例程使用USART的IDLE中断对不定长度数据接收完成进行判断;

对中断参数进行配置;

/*******************************************************************************

* Function Name : USART_Configuration

* Description : Configure USART1

* Input : None

* Output : None

* Return : None

* Attention : None

*******************************************************************************/

void CKS_USART_Init(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

USART_InitTypeDef USART_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

DMA_InitTypeDef DMA_InitStructure;

RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1,ENABLE);

RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

/*USART1_TX -> PA9 , USART1_RX -> PA10*/

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);

/* DMA configuration ----------------------------------------------*/

/* USART1_RX DMA Init */

DMA_DeInit(DMA1_Channel5);

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;

DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)CKS_Uart_Rx;

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;

DMA_InitStructure.DMA_BufferSize = CKS_UART_TX_RX_BUFF;

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

DMA_InitStructure.DMA_Priority = DMA_Priority_High;

DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

DMA_Init(DMA1_Channel5, &DMA_InitStructure);

DMA_Cmd(DMA1_Channel5, ENABLE);

/* USART1_TX DMA Init */

DMA_DeInit(DMA1_Channel4);

DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&USART1->DR;

DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)CKS_Uart_Tx;

DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;

DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;

DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;

DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;

DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;

DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;

DMA_InitStructure.DMA_Priority = DMA_Priority_High;

DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;

DMA_Init(DMA1_Channel4, &DMA_InitStructure);

DMA_Cmd(DMA1_Channel4, DISABLE);

USART_InitStructure.USART_BaudRate = 115200;

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(USART1, &USART_InitStructure);

USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);

/* USART1 interrupt configuration ----------------------------------------------*/

NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

USART_DMACmd(USART1, USART_DMAReq_Rx, ENABLE);

USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);

USART_Cmd(USART1, ENABLE);

}

USART_IRQHandler函数

我们利用USART的IDLE进行不定长度数据接收完成判断,当USART被IDLE中断触发后,即标志着本次数据流已完成传输。

/*******************************************************************************

* Function Name : USART1_IRQHandler

* Description : This function handles USART1 global interrupt request.

* Input : None

* Output : None

* Return : None

*******************************************************************************/

void USART1_IRQHandler(void)

{

if(USART_GetFlagStatus(USART1, USART_FLAG_IDLE) != RESET)

{

DMA_Cmd(DMA1_Channel5, DISABLE);

uint8_t i = USART1->SR;

i = USART1->DR;

CKS_Uart_Rx_Data_Lenth = CKS_UART_TX_RX_BUFF - DMA_GetCurrDataCounter(DMA1_Channel5);

DMA1_Channel5->CNDTR = CKS_UART_TX_RX_BUFF;

CKS_Uart_Tx_Data_Lenth = CKS_Uart_Rx_Data_Lenth;

memcpy(CKS_Uart_Tx, CKS_Uart_Rx, CKS_Uart_Rx_Data_Lenth);

memset(CKS_Uart_Rx, 0x00, sizeof(CKS_Uart_Rx));

DMA_Cmd(DMA1_Channel5, ENABLE);

CKS_Uart_Transmite_With_DMA(CKS_Uart_Tx_Data_Lenth);

}

USART_ClearFlag(USART1, USART_IT_RXNE);

}

USART发送程序

发送程序通过DMA发送长度为lenth的CKS_Uart_Tx数组。

/*******************************************************************************

* Function Name : CKS_Uart_Transmite_With_DMA

* Description : transmite data.

* Input : None

* Output : None

* Return : None

*******************************************************************************/

void CKS_Uart_Transmite_With_DMA(uint32_t lenth)

{

DMA1_Channel4->CNDTR = lenth;

DMA_Cmd(DMA1_Channel4, ENABLE);

while(!DMA_GetFlagStatus(DMA1_FLAG_TC4)){}

DMA_ClearFlag(DMA1_FLAG_TC4);

memset(CKS_Uart_Tx, 0x00, sizeof(CKS_Uart_Tx));

CKS_Uart_Tx_Data_Lenth = 0x00;

DMA_Cmd(DMA1_Channel4, DISABLE);

}

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 控制器
    +关注

    关注

    113

    文章

    16600

    浏览量

    180573
  • 寄存器
    +关注

    关注

    31

    文章

    5394

    浏览量

    122012
  • dma
    dma
    +关注

    关注

    3

    文章

    568

    浏览量

    101548
  • USART
    +关注

    关注

    1

    文章

    198

    浏览量

    31222

原文标题:MCU微课堂|CKS32F107xx USART(二)

文章出处:【微信号:中科芯MCU,微信公众号:中科芯MCU】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    FreeRTOS串口DMA收发不定长数据

    FreeRTOS例程,介绍串口DMA收发不定长数据
    的头像 发表于 09-26 09:08 4919次阅读
    FreeRTOS串口<b class='flag-5'>DMA</b>收发<b class='flag-5'>不定长</b>数据

    stm32串口怎么用DMA接收不定长数据?

    stm32串口怎么用DMA接收不定长数据,求大神点播1. 网上查到,空闲中断+DMA可以接收不定长
    发表于 08-21 09:21

    用串口DMA传输不定长度包的方式

    经常看到有人在问用DMA接收不定长包的问题,由于STM32DMA的特殊性,使其对接收不定长的数据
    发表于 12-26 08:48

    STM32之串口DMA接收不定长数据

      STM32之串口DMA接收不定长数据引言  在使用stm32或者其他单片机的时候,会经常使用到串口通讯,那么如何有效地接收数据呢?假如这段数据是
    发表于 09-05 16:52

    DMA如何接收不定长的数据?

    STM32串口DMA如何接收不定长的数据呢?
    发表于 12-21 07:39

    stm32串口是如何实现接收不定长度数据的呢

    1.不定长度数据为什么会存在串口接收不定长度数据呢?首先,在通信双方进行数据传输的时候,由于不同的设备在实现控制,数据采样时,发送的数据指令字节数量存在着差异,就产生了串口
    发表于 08-11 08:18

    STM32 HAL DMA串口接收不定长度的实现方法

    STM32 HAL DMA串口接收不定长度的实现方法
    发表于 12-08 07:59

    基于DMA接收利用空闲模式接收不定长数据

    STM32L051 HAL库非DMA模式使用空闲中断接收不定长数据因项目中的上位机与单片机之间的通信协议采用非标准协议,上位机发送的数据长度不定
    发表于 01-12 07:44

    STM32F072使用DMA+IDLE进行串口接收不定长数据有问题,改为DMA+RTO接收正常。

    把调试STM32F072串口过程中,出现了一小点问题,记录下来,F0的串口寄存器有些增加的功能以前没用到,F0增加了modbus协议之类的接收超时处理,完美实现了不定长数据包的帧接收。本次
    发表于 12-03 09:21 11次下载
    STM32F072使用<b class='flag-5'>DMA</b>+IDLE<b class='flag-5'>进行</b>串口<b class='flag-5'>接收</b><b class='flag-5'>不定长</b>数据有问题,改为<b class='flag-5'>DMA</b>+RTO<b class='flag-5'>接收</b>正常。

    stm32 串口接收不定长度数据及黏包处理 + 串口DMA接收

    1.不定长度数据 为什么会存在串口接收不定长度数据呢?首先,在通信双方进行数据传输的时候,由于不同的设备在实现控制,数据采样时,发送的数据指令字节数量存在着差异,就产生了串口
    发表于 12-23 19:09 27次下载
    stm32 串口<b class='flag-5'>接收</b><b class='flag-5'>不定长度</b>数据及黏包处理 + 串口<b class='flag-5'>DMA</b><b class='flag-5'>接收</b>

    STM32 DMA串口接收不定长数据

    STM32 DMA串口接收不定长数据
    发表于 12-24 18:50 40次下载
    STM32  <b class='flag-5'>DMA</b>串口<b class='flag-5'>接收</b><b class='flag-5'>不定长</b>数据

    STM32之串口DMA接收不定长数据

    目录STM32之串口DMA接收不定长数据引言DMA简介什么是DMA在STM32的DMA资源
    发表于 12-24 19:03 30次下载
    STM32之串口<b class='flag-5'>DMA</b><b class='flag-5'>接收</b><b class='flag-5'>不定长</b>数据

    STM32F429 标准库 串口完成中断+DMA 接收不定长数据

    之前写过STM32F103的串口+DMA不定长数据接收驱动,近期在设计STM32F429系列单片机标准库函数 串口+DAM 接收不定长数据驱
    发表于 12-24 19:03 21次下载
    STM32F429 标准库  串口完成中断+<b class='flag-5'>DMA</b>  <b class='flag-5'>接收</b><b class='flag-5'>不定长</b>数据

    STM32CUBEMX(8)--USART通过定时器中断方式接收不定长数据

    本文利用中断实现串口不定长接收(非DMA),使用HAL库,将接收的数据打印出去。
    的头像 发表于 11-14 16:31 1550次阅读
    STM32CUBEMX(8)--<b class='flag-5'>USART</b>通过定时器中断方式<b class='flag-5'>接收</b><b class='flag-5'>不定长</b>数据

    STM32CubeMX之串口接收不定长数据

    基本串口通信通常只能接收定长数据,无法稳定接收不定长数据,本章介绍利用STM32单片机的IDLE空闲中断,接收
    的头像 发表于 05-11 09:59 3739次阅读
    STM32CubeMX之串口<b class='flag-5'>接收</b><b class='flag-5'>不定长</b>数据