HC32F460 串口 DMA 发送 接收

前言

利用DMA 进行串口读写,主要内容包括:
DMA 通道 *2
串口发送空中断,发送完成中断
串口接收中断,接收超时中断
定时器 (串口接收超时定时器 )

发送/接收功能 比较

功能触发DMA传输次数DMA中断结束标志
TXTI中断适应接收字节个数DMA传输完成中断发送完成标志中断
RXRI中断无数次DMA块完成中断接收超时中断

接收超时定时器通道选择

默认关系,无法任意选择通道,根据实际使用的串口确认定时器通道

TIMEOUT 计数器采用Timer0 模块的计数器,具体对应关系如下:
USART1:Timer0 Unit1 A 通道
USART2:Timer0 Unit1 B 通道
USART3:Timer0 Unit2 A 通道
USART4:Timer0 Unit2 B 通道

串口初始化

/**
 *******************************************************************************
 ** \brief  Usart_init function of project
 **
 ** \param  None
 **
 ** \retval void
 **
 ******************************************************************************/
void Usart_init(void)
{
    en_result_t enRet = Ok;
    stc_irq_regi_conf_t stcIrqRegiCfg;
	  stc_port_init_t stc_485_RE_PortInit,stc_485_TX_PortInit;
    uint32_t u32Fcg1Periph = PWC_FCG1_PERIPH_USART1 | PWC_FCG1_PERIPH_USART2 | \
                             PWC_FCG1_PERIPH_USART3 | PWC_FCG1_PERIPH_USART4;
    const stc_usart_uart_init_t stcInitCfg = {
        UsartIntClkCkNoOutput,//时钟源可选:内部时钟源(内部波特率生成器生成的时钟)/外部时钟源( CKn管脚输入的时钟)
        UsartClkDiv_1,
        UsartDataBits8,//数据长度可编程:8位/9位
        UsartDataLsbFirst,
        UsartOneStopBit,//停止位可配置:1 位/2位
        UsartParityNone,//校验功能可配置:奇校验/偶校验/无校验
        UsartSampleBit8,
        UsartStartBitFallEdge,
        UsartRtsEnable,
    };

    /* Initialize Timer0 */
    Timer0Init();

	/* Initialize DMA */
    DmaInit();
	DmaInit_Tx();

    /* Enable peripheral clock */
    PWC_Fcg1PeriphClockCmd(u32Fcg1Periph, Enable);

    /* Initialize USART IO */

    PORT_SetFunc(USART_RX_PORT, USART_RX_PIN, USART_RX_FUNC, Disable);
	MEM_ZERO_STRUCT(stc_485_TX_PortInit);
	stc_485_TX_PortInit.enPullUp=Enable;
	PORT_Init(USART_TX_PORT,USART_TX_PIN,&stc_485_TX_PortInit);
    PORT_SetFunc(USART_TX_PORT, USART_TX_PIN, USART_TX_FUNC, Disable);

    /* configuration RS485_RE structure initialization */
    MEM_ZERO_STRUCT(stc_485_RE_PortInit);
    stc_485_RE_PortInit.enPinMode = Pin_Mode_Out;
    PORT_Init(USART_RE_PORT, USART_RE_PIN, &stc_485_RE_PortInit);		
	PORT_ResetBits(USART_RE_PORT, USART_RE_PIN);
		
    /* Initialize UART */
    enRet = USART_UART_Init(USART_CH, &stcInitCfg);
    if (enRet != Ok)
    {
        while (1)
        {
        }
    }

    /* Set baudrate */
    enRet = USART_SetBaudrate(USART_CH, USART_BAUDRATE);
    if (enRet != Ok)
    {
        while (1)
        {
        }
    }

    /* Set USART RX IRQ */
    stcIrqRegiCfg.enIRQn = USART_RI_IRQn;
    stcIrqRegiCfg.pfnCallback = &UsartRxIrqCallback;
    stcIrqRegiCfg.enIntSrc = USART_RI_NUM;
    enIrqRegistration(&stcIrqRegiCfg);
    NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
    NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
    NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);

    /* Set USART RX error IRQ */
    stcIrqRegiCfg.enIRQn = USART_EI_IRQn;
    stcIrqRegiCfg.pfnCallback = &UsartErrIrqCallback;
    stcIrqRegiCfg.enIntSrc = USART_EI_NUM;
    enIrqRegistration(&stcIrqRegiCfg);
    NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
    NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
    NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);

    /* Set USART RX timeout error IRQ */
    stcIrqRegiCfg.enIRQn = USART_RTO_IRQn;
    stcIrqRegiCfg.pfnCallback = &UsartTimeoutIrqCallback;
    stcIrqRegiCfg.enIntSrc = USART_RTO_NUM;
    enIrqRegistration(&stcIrqRegiCfg);
    NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
    NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
    NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);

    /* Set USART TX IRQ */
    stcIrqRegiCfg.enIRQn = USART_TI_IRQn;
    stcIrqRegiCfg.pfnCallback = &UsartTxIrqCallback;
    stcIrqRegiCfg.enIntSrc = USART_TI_NUM;
    enIrqRegistration(&stcIrqRegiCfg);
    NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
    NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
    NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);

    /* Set USART TX complete IRQ */
    stcIrqRegiCfg.enIRQn = USART_TCI_IRQn;
    stcIrqRegiCfg.pfnCallback = &UsartTxCmpltIrqCallback;
    stcIrqRegiCfg.enIntSrc = USART_TCI_NUM;
    enIrqRegistration(&stcIrqRegiCfg);
    NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
    NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
    NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);

    /*Enable RX && RX interupt && timeout interrupt function*/
		USART_FuncCmd(USART_CH, UsartNoiseFilter,Enable);

    USART_FuncCmd(USART_CH, UsartRx, Enable);
    USART_FuncCmd(USART_CH, UsartRxInt, Enable);
    USART_FuncCmd(USART_CH, UsartTimeOut, Enable);
    USART_FuncCmd(USART_CH, UsartTimeOutInt, Enable);
    /*Enable TX && RX && RX interrupt function*/

}

DMA初始化

static void DmaInit(void)
{
    stc_dma_config_t stcDmaInit;
    stc_irq_regi_conf_t stcIrqRegiCfg;

    /* Enable peripheral clock */
    PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_DMA1 | PWC_FCG0_PERIPH_DMA2,Enable);

    /* Enable DMA. */
    DMA_Cmd(DMA_UNIT,Enable);

    /* Initialize DMA. */
    MEM_ZERO_STRUCT(stcDmaInit);
    stcDmaInit.u16BlockSize = 1u; /* 1 block */
    stcDmaInit.u32SrcAddr = ((uint32_t)(&USART_CH->DR)+2ul); /* Set source address. */
    stcDmaInit.u32DesAddr = (uint32_t)(&m_stcRingBuf.au8Buf);     /* Set destination address. */
    stcDmaInit.stcDmaChCfg.enSrcInc = AddressFix;  /* Set source address mode. */
    stcDmaInit.stcDmaChCfg.enDesInc = AddressIncrease;  /* Set destination address mode. */
    stcDmaInit.stcDmaChCfg.enIntEn = Enable;       /* Enable interrupt. */
    stcDmaInit.stcDmaChCfg.enTrnWidth = Dma8Bit;   /* Set data width 8bit. */
	  stcDmaInit.u16DesRptSize=m_stcRingBuf.u16Capacity;
	
	   /* Disable linked list transfer. */
    stcDmaInit.stcDmaChCfg.enLlpEn = Disable;
		 /* Enable repeat function. */
    stcDmaInit.stcDmaChCfg.enDesRptEn = Enable;
		
    DMA_InitChannel(DMA_UNIT, DMA_CH, &stcDmaInit);

    /* Enable the specified DMA channel. */
    DMA_ChannelCmd(DMA_UNIT, DMA_CH, Enable);

    /* Clear DMA flag. */
    DMA_ClearIrqFlag(DMA_UNIT, DMA_CH, TrnCpltIrq);

    /* Enable peripheral circuit trigger function. */
    PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS,Enable);

    /* Set DMA trigger source. */
    DMA_SetTriggerSrc(DMA_UNIT, DMA_CH, DMA_TRG_SEL);

    /* Set DMA block transfer complete IRQ */
    stcIrqRegiCfg.enIRQn = DMA_BTC_INT_IRQn;
    stcIrqRegiCfg.pfnCallback = &DmaBtcIrqCallback;
    stcIrqRegiCfg.enIntSrc = DMA_BTC_INT_NUM;
    enIrqRegistration(&stcIrqRegiCfg);
    NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
    NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
    NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);
}
static void DmaInit_Tx(void)
{
    stc_dma_config_t stcDmaInit;
    stc_irq_regi_conf_t stcIrqRegiCfg;

    /* Enable peripheral clock */
    PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_DMA1 | PWC_FCG0_PERIPH_DMA2,Enable);

    /* Enable DMA. */
    DMA_Cmd(DMA_UNIT_TX,Enable);

    /* Initialize DMA. */
    MEM_ZERO_STRUCT(stcDmaInit);
    stcDmaInit.u16BlockSize = 1u; /* 1 block */
    stcDmaInit.u32SrcAddr =  (uint32_t)(&m_stcTingBuf.au8Buf); /* Set source address. */
    stcDmaInit.u32DesAddr = ((uint32_t)(&USART_CH->DR));     /* Set destination address. */ //TDR
    stcDmaInit.stcDmaChCfg.enSrcInc = AddressIncrease;  /* Set source address mode. */
    stcDmaInit.stcDmaChCfg.enDesInc = AddressFix;  /* Set destination address mode. */
    stcDmaInit.stcDmaChCfg.enIntEn = Enable;       /* Enable interrupt. */
    stcDmaInit.stcDmaChCfg.enTrnWidth = Dma8Bit;   /* Set data width 8bit. */
	  stcDmaInit.u16TransferCnt=11;//根据长度  
    DMA_InitChannel(DMA_UNIT_TX, DMA_CH_TX, &stcDmaInit);

    /* Enable the specified DMA channel. */
    DMA_ChannelCmd(DMA_UNIT_TX, DMA_CH_TX, Enable);

    /* Clear DMA flag. */
    DMA_ClearIrqFlag(DMA_UNIT_TX, DMA_CH_TX, TrnCpltIrq);

    /* Enable peripheral circuit trigger function. */
    PWC_Fcg0PeriphClockCmd(PWC_FCG0_PERIPH_AOS,Enable);

    /* Set DMA trigger source. */
    DMA_SetTriggerSrc(DMA_UNIT_TX, DMA_CH_TX, DMA_TRG_SEL_TX);

    /* Set DMA transfer complete IRQ */
    stcIrqRegiCfg.enIRQn = DMA_BTC_INT_IRQn_TX;
    stcIrqRegiCfg.pfnCallback = &DmaTcIrqCallback_TX;
    stcIrqRegiCfg.enIntSrc = DMA_BTC_INT_NUM_TX;
    enIrqRegistration(&stcIrqRegiCfg);
    NVIC_SetPriority(stcIrqRegiCfg.enIRQn, DDL_IRQ_PRIORITY_DEFAULT);
    NVIC_ClearPendingIRQ(stcIrqRegiCfg.enIRQn);
    NVIC_EnableIRQ(stcIrqRegiCfg.enIRQn);
}

定时器初始化

/**
 *******************************************************************************
 ** \brief Initliaze Timer0.
 **
 ** \param [in] None
 **
 ** \retval None
 **
 ******************************************************************************/
static void Timer0Init(void)
{
    stc_clk_freq_t stcClkTmp;
    stc_tim0_base_init_t stcTimerCfg;
    stc_tim0_trigger_init_t StcTimer0TrigInit;

    MEM_ZERO_STRUCT(stcClkTmp);
    MEM_ZERO_STRUCT(stcTimerCfg);
    MEM_ZERO_STRUCT(StcTimer0TrigInit);

    /* Timer0 peripheral enable */
    PWC_Fcg2PeriphClockCmd(TMR_FCG_PERIPH, Enable);
    CLK_LrcCmd(Enable);
	
    /* Clear CNTAR register for channel B */
//    TIMER0_WriteCntReg(TMR_UNIT, Tim0_ChannelA, 0u);
    TIMER0_WriteCntReg(TMR_UNIT, Tim0_ChannelB, 0u);

    /* Config register for channel B */
    stcTimerCfg.Tim0_CounterMode = Tim0_Async;
    stcTimerCfg.Tim0_AsyncClockSource = Tim0_LRC;
    stcTimerCfg.Tim0_ClockDivision = Tim0_ClkDiv8;//32/8   =4K   0.25ms
    stcTimerCfg.Tim0_CmpValue = 2;//0.25*2=0.5ms    3.5个字节
    TIMER0_BaseInit(TMR_UNIT, Tim0_ChannelB, &stcTimerCfg);

    /* Clear compare flag */
    TIMER0_ClearFlag(TMR_UNIT, Tim0_ChannelB);

    /* Config timer0 hardware trigger */
    StcTimer0TrigInit.Tim0_InTrigEnable = false;
    StcTimer0TrigInit.Tim0_InTrigClear = true;
    StcTimer0TrigInit.Tim0_InTrigStart = true;
    StcTimer0TrigInit.Tim0_InTrigStop = false;
    TIMER0_HardTriggerInit(TMR_UNIT, Tim0_ChannelB, &StcTimer0TrigInit);
}

串口DMA 发送

en_result_t UART_Transmit_DMA(M4_USART_TypeDef *huart, uint8_t *pData, uint16_t Size)
{
	if(DMA_TxComplete==0)
	{
		  if ((pData == NULL) || (Size == 0U))
    {
      return Error;
    }
      DMA_TxComplete=1;
			DMA_SetSrcAddress (DMA_UNIT_TX,DMA_CH_TX,(uint32_t)pData);
			DMA_SetTransferCnt(DMA_UNIT_TX,DMA_CH_TX, Size);
			PORT_SetBits(USART_RE_PORT, USART_RE_PIN);
			while( PORT_GetBit(USART_RE_PORT, USART_RE_PIN)!=1){}
			DMA_ChannelCmd(DMA_UNIT_TX, DMA_CH_TX, Enable);			
			USART_FuncCmd(huart, UsartTxAndTxEmptyInt, Enable);	
			return Ok;
	}
	  else
  {
    return ErrorNotReady;
  }
}

DMA_TX发送流程图

在这里插入图片描述

发送相关中断

/**
 *******************************************************************************
 ** \brief DMA block transfer complete irq callback function.
 **
 ** \param [in] None
 **
 ** \retval None
 **
 ******************************************************************************/
static void DmaTcIrqCallback_TX(void)
{

	DMA_ClearIrqFlag(DMA_UNIT_TX, DMA_CH_TX, TrnCpltIrq);
    DMA_ChannelCmd(DMA_UNIT_TX, DMA_CH_TX, Disable);
    USART_FuncCmd(USART_CH, UsartTxEmptyInt, Disable);
    USART_FuncCmd(USART_CH, UsartTxCmpltInt, Enable);

}
/**
 *******************************************************************************
 ** \brief USART TX complete irq callback function.
 **
 ** \param [in] None
 **
 ** \retval None
 **
 ******************************************************************************/
static void UsartTxCmpltIrqCallback(void)
{
    USART_FuncCmd(USART_CH, UsartTx, Disable);
    USART_FuncCmd(USART_CH, UsartTxCmpltInt, Disable);
	PORT_ResetBits(USART_RE_PORT, USART_RE_PIN); 
	while( PORT_GetBit(USART_RE_PORT, USART_RE_PIN)!=0){}	
	DMA_TxComplete=0;
}
static void UsartTxIrqCallback(void)
{
//    uint8_t u8Data = 0u;

//    if (Ok == RingBufRead(&m_stcRingBuf, &u8Data))
//    {
//				PORT_SetBits(USART_RE_PORT, USART_RE_PIN);
//        USART_SendData(USART_CH, (uint16_t)u8Data);
			 USART_SendData(USART_CH, 0x55);
//    }
//    if (IS_RING_BUFFER_EMPTY(&m_stcRingBuf))
//    {
//        USART_FuncCmd(USART_CH, UsartTxEmptyInt, Disable);
//        USART_FuncCmd(USART_CH, UsartTxCmpltInt, Enable);
//    }
}

串口DMA 接收

DMA_RX 流程图

在这里插入图片描述

接收相关中断

static void DmaBtcIrqCallback(void)
{
	  DMA_ClearIrqFlag(DMA_UNIT, DMA_CH, BlkTrnCpltIrq);
    RingBufWrite_DMA(&m_stcRingBuf);
}
static void UsartTimeoutIrqCallback(void)//
{
    TIMER0_Cmd(TMR_UNIT, Tim0_ChannelB,Disable);
    USART_ClearStatus(USART_CH, UsartRxTimeOut);
//	  DMA_SetDesAddress(DMA_UNIT, DMA_CH, (uint32_t)(&m_stcRingBuf.au8Buf));//  Reset DesAddress	
	  DMA_RxComplete=1;
}
  • 16
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: hc32f460是一款高性能的32位微控制器,它支持串口DMA功能。串口DMA是一种通过直接内存访问(DMA)方式来传输数据的技术,可以大大提高串口通信的效率。 hc32f460串口DMA功能通过将串口数据的传输交给DMA控制器来完成,减轻了CPU的负担。在使用串口DMA时,首先需要配置DMA控制器,包括设置DMA通道、传输数据的起始地址和长度等。然后,将数据写入串口发送缓冲区,并启动DMA传输。DMA控制器会自动根据配置的参数从内存中读取数据,并将数据直接发送串口,无需CPU的干预。 串口DMA可以极大地提高数据传输的速度,尤其适用于大量数据的传输和高速通信的场景。相比于传统的CPU中断方式,串口DMA能够实现数据的无缝传输,提高了系统的响应速度和实时性。 hc32f460串口DMA功能还具有灵活的配置选项,例如可以选择不同的DMA通道进行数据传输,还支持循环传输模式和多缓冲区传输,以满足不同的应用需求。 总之,hc32f460串口DMA功能是一项强大且高效的数据传输技术,能够提升系统的性能和可靠性。通过 DMA 控制器和串口的协同工作,能够实现高速、实时的数据传输,广泛应用于各种通信和控制系统中。 ### 回答2: HC32F460是一款基于ARM Cortex-M4内核的高性能微控制器。它具有丰富的外设功能,包括多个串口接口和DMA控制器。串口DMA是指通过DMA控制器来管理串口数据的传输。 在HC32F460中,串口DMA的工作原理如下:首先,我们需要配置串口控制器的相关参数,包括波特率、数据位、停止位和校验位等。然后,我们通过编程的方式配置DMA控制器,以使其能够将串口数据的发送接收与内存之间进行直接传输。 对于串口发送功能,当我们要发送一段数据时,首先将数据存储在内存中的发送缓冲区中,然后通过编程的方式触发DMA控制器开始传输。DMA控制器会自动从内存中读取数据,并通过串口控制器发送出去。在传输过程中,我们无需干预,可以继续进行其他的操作。 对于串口接收功能,当有数据到达时,串口控制器会将数据存储在接收缓冲区中。然后,我们再次通过编程的方式触发DMA控制器开始传输。DMA控制器会自动将数据从接收缓冲区读取到内存中,以供后续的处理使用。同样,在传输过程中我们无需干预。 通过使用串口DMA,我们可以实现高效的串口数据传输,提高系统的性能。它可以减少CPU的负载,降低数据传输的延迟。同时,由于采用了直接内存访问的方式,可以减少CPU与外设之间的数据拷贝,提高数据传输的速度。 总之,HC32F460串口DMA是一种高效的数据传输方式,通过使用DMA控制器来管理串口数据的传输,可以提高系统的性能和可靠性。 ### 回答3: HC32F460是一种高性能的32位MCU芯片,具有丰富的外设接口和强大的处理能力。其中,串口DMA是这款芯片上的一个功能模块,用于实现串口的数据传输。 串口DMA可以通过配置寄存器来进行初始化设置。首先需要配置串口的传输参数,例如波特率、数据位数、停止位等。然后设置DMA的初始化参数,包括数据的传输方向、传输大小、源地址和目的地址等。接下来,通过使能串口DMA功能,就可以开始进行数据传输。 串口DMA的工作原理是通过中断触发和DMA通道来实现数据的传输。当有数据到达串口时,串口DMA会产生一个中断请求,触发DMA通道进行数据的传输。DMA通道会自动从源地址读取数据,并将数据传输到目的地址。数据传输完成后,DMA通道会产生一个传输完成的中断,在此中断中可以进行相应的处理,例如发送一个完成信号给外部设备。 串口DMA的优点是能够大大提高数据传输的效率和可靠性。由于数据传输由DMA通道完成,可以减轻CPU的负担,提高系统的响应速度。同时,采用DMA传输数据,可以避免由于CPU繁忙而导致的数据丢失或错误。因此,串口DMA在需要高效、稳定传输大量数据的应用中非常有用。 总之,HC32F460串口DMA是一种可靠高效的数据传输方式,通过合理配置和使用,可以实现高速稳定的串口通信。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值