MCU微课堂 | CKS32F107xx USART(二)

在上一讲中,我们对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表示通道号):

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

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

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

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

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

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

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

1.png

图1 利用DMA发送

利用DMA接收

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

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

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

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

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

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

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

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

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

2.png

图2 利用DMA接收

DMA通道

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

3.png

图3 USART1 DMA通道

USART初始化程序

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

  1. 开启GPIO、USART1、DMA1时钟;

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

  3. 初始化DMA1相关参数;

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

  5. 对中断参数进行配置;

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

* 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);

}

相关链接:MCU微课堂 | CKS32F107xx USART(一)

来源:中科芯MCU

免责声明:本文为转载文章,转载此文目的在于传递更多信息,版权归原作者所有。本文所用视频、图片、文字如涉及作品版权问题,请联系小编进行处理(联系邮箱:cathy@eetrend.com)。