华大 HC32F460 ADC+DMA实验代码详解

声明:以下内容为个人学习心得。

一.基础知识

HC32F460系列MCU内部集成了ADC1和ADC2两个模块,挂载于AHB-APB(APB3)总线,可配置12位、10位和8位分辨率,支持最多16个外部模拟输入通道和1个内部基准电压/8bitDAC输出的检测通道。

HC32F460系列MCU操作起来很灵活,体现在:模拟输入通道可以任意组合一个序列(序列A和序列B),一个序列可以进行单次扫描(包括两个动作:采样和转换),或连续扫描。支持对任意指定通道进行连续多次扫描,并对转换结果进行平均。

特别地,ADC模块还搭载模拟看门狗(以下简称AWD)功能,可对任意指定通道的转换结果进行监视,检测是否超出设定的阈值。

二.实验代码详解

本例程以ADC1的序列A和DMA1的通道0为例,实现了通过DMA读取ADC数据。例程实现原理:PE7的下

降沿触发ADC的序列A扫描,序列A扫描结束后,产生事件“EVT_SRC_ADC1_EOCA”,该事件触发DMA1的通道0

从指定的ADC数据寄存器地址(源地址)读取指定长度的数据到指定的目标地址,如此重复。

说明:

本例程中,DMA的块大小(block size)必须覆盖从最小通道编号到最大通道编号的所有通道,因为

DMA每读取一个数据后,数据指针加1,指向下一个需要读取的数据地址。例程中选用的ADC通道为ADC_CH2、

ADC_CH3和ADC_CH10,那么DMA的块大小须设置为不小于9,同样地,用于保存ADC数据的数组的大小,

也应不小于9。

①ADC、DMA相关寄存器配置参数说明

/* ADC unit instance for this example. */
#define ADC_UNIT                        (CM_ADC1)//ADC1基地址
#define ADC_PERIPH_CLK                  (FCG3_PERIPH_ADC1)//ADC1使能时钟

/* Selects ADC channels that needed. */
#define ADC_CHX                         (ADC_CH2)//选择ADC_CH2通道
#define ADC_CHX_PORT                    (GPIO_PORT_A)//对应PA2口
#define ADC_CHX_PIN                     (GPIO_PIN_02)

#define ADC_CHY                         (ADC_CH3)//选择ADC_CH3通道
#define ADC_CHY_PORT                    (GPIO_PORT_A)//对应PA3口
#define ADC_CHY_PIN                     (GPIO_PIN_03)

#define ADC_CHZ                         (ADC_CH10)//选择ADC_CH10通道
#define ADC_CHZ_PORT                    (GPIO_PORT_C)对应PC0口
#define ADC_CHZ_PIN                     (GPIO_PIN_00)

#define ADC_CH_MIN                      (ADC_CHX)
#define ADC_CH_MAX                      (ADC_CHZ)
#define ADC_DR_START                    ((uint32_t)&ADC_UNIT->DR2)//DMA数据源地址
#define PTTM_VAL_IDX                    (8U)//DMA缓存区大小

/* ADC sequence to be used. */
#define ADC_SEQ                         (ADC_SEQ_A)//使用ADC1的序列A

/* Hard trigger of the specified sequence. */
#define ADC_SEQ_HARDTRIG                (ADC_HARDTRIG_ADTRG_PIN) //硬件触发标志位
#define ADC_SEQ_TRIG_PORT               (GPIO_PORT_E) //PE7下降沿触发
#define ADC_SEQ_TRIG_PIN                (GPIO_PIN_07)
#define ADC_SEQ_TRIG_PIN_FUNC           (GPIO_FUNC_1)//设置PE7功能引脚

/*
 * Definitions of DMA.
 * 'APP_DMA_BLOCK_SIZE': 1~1024, inclusive. 1~16 for ADC1 and ADC2; 1~20 for ADC3.
 * 'APP_DMA_TRANS_COUNT': 0~65535, inclusive. 0: always transmit.
 */
#define DMA_UNIT                        (CM_DMA1)//DMA1基地址
#define DMA_PERIPH_CLK                  (FCG0_PERIPH_DMA1)//DMA1使能时钟
#define DMA_CH                          (DMA_CH0)//通道0地址
#define DMA_AOS_TRIG_SEL                (AOS_DMA1_0)//外设电路之间的联动(AOS)

#define DMA_TRANS_CNT                   (0U)//设置DMA传输次数,0表示无限次数
#define DMA_BLOCK_SIZE                  (ADC_CH_MAX - ADC_CH_MIN + 1U)//设置DMA数据块大小
#define DMA_DATA_WIDTH                  (DMA_DATAWIDTH_16BIT)//设置数据宽度,也决定了源地址和目的地址增加或减少多少
#define DMA_SRC_ADDR                    ADC_DR_START//DMA数据源地址
#define DMA_DEST_ADDR                   ((uint32_t)(&m_au16AdcValue[0U]))//DMA数据目的地址

#define DMA_TRIG_EVT                    (EVT_SRC_ADC1_EOCA)//选择AOS触发源

#define DMA_INT_SRC                     (INT_SRC_DMA1_BTC0)//选择DMA中断类型为:数据块传输完成
#define DMA_INT_IRQn                    (INT038_IRQn)//DMA中断序号为038
#define DMA_INT_PRIO                    (DDL_IRQ_PRIO_03)//DMA中断优先级为03(根据自己需要设定)
#define DMA_INT_FLAG                    (DMA_FLAG_BTC_CH0)//DMA中断完成标志位

②ADC转换电压计算

/* ADC reference voltage. The voltage of pin VREFH. */
#define ADC_VREF                        (3.3F) //参考电压为3.3V

/* ADC accuracy(according to the resolution of ADC). */
#define ADC_ACCURACY                    (1UL << 12U)//设置ADC分辨率为12位,0x10000 ->4096,2^12次方。

/* Calculate the voltage(mV). */
#define ADC_CAL_VOL(adcVal)             (uint16_t)((((float32_t)(adcVal) * ADC_VREF) / ((float32_t)ADC_ACCURACY)) * 1000.F)

③函数定义和DMA接收数据缓存区定义

static void AdcConfig(void);
static void AdcInitConfig(void);
static void AdcSetPinAnalogMode(void);
static void AdcHardTriggerConfig(void);

static void DmaConfig(void);
static void DmaIrqConfig(void);
static void DMA_IrqCallback(void);

static uint16_t m_au16AdcValue[DMA_BLOCK_SIZE];
__IO static uint8_t m_u8AdcValUpdated = 0U; //软件实现下降沿

④ADC初始化配置

static void AdcInitConfig(void)
{
    stc_adc_init_t stcAdcInit;

    /* 1. Enable ADC peripheral clock. */
    FCG_Fcg3PeriphClockCmd(ADC_PERIPH_CLK, ENABLE);

    /* 2. Modify the default value depends on the application. */
    (void)ADC_StructInit(&stcAdcInit);

    /* 3. Initializes ADC. */
    (void)ADC_Init(ADC_UNIT, &stcAdcInit);

    /* 4. ADC channel configuration. */
    /* 4.1 Set the ADC pin to analog input mode. */
    AdcSetPinAnalogMode();
    /* 4.2 Enable ADC channels. */
    ADC_ChCmd(ADC_UNIT, ADC_SEQ, ADC_CHX, ENABLE);
    ADC_ChCmd(ADC_UNIT, ADC_SEQ, ADC_CHY, ENABLE);
    ADC_ChCmd(ADC_UNIT, ADC_SEQ, ADC_CHZ, ENABLE);
}

⑤设置ADC引脚为模拟输入

static void AdcSetPinAnalogMode(void)
{
    stc_gpio_init_t stcGpioInit;

    (void)GPIO_StructInit(&stcGpioInit);
    stcGpioInit.u16PinAttr = PIN_ATTR_ANALOG;
    (void)GPIO_Init(ADC_CHX_PORT, ADC_CHX_PIN, &stcGpioInit);
    (void)GPIO_Init(ADC_CHY_PORT, ADC_CHY_PIN, &stcGpioInit);
    (void)GPIO_Init(ADC_CHZ_PORT, ADC_CHZ_PIN, &stcGpioInit);
}

⑥设置ADC硬件触发

static void AdcHardTriggerConfig(void)
{
    /************** Hard trigger of sequence A ****************/
    GPIO_SetFunc(ADC_SEQ_TRIG_PORT, ADC_SEQ_TRIG_PIN, ADC_SEQ_TRIG_PIN_FUNC);
    ADC_TriggerConfig(ADC_UNIT, ADC_SEQ, ADC_SEQ_HARDTRIG);
    ADC_TriggerCmd(ADC_UNIT, ADC_SEQ, ENABLE);
}

GPIO_SetFunc(ADC_SEQ_TRIG_PORT, ADC_SEQ_TRIG_PIN, ADC_SEQ_TRIG_PIN_FUNC);此函数作用是将GPIO口设定指定引脚功能,这里需要查看数据手册,通过配置GPIO.PFSRxy(功能选择寄存器)b5~b0进行功能选择,参数1、2为GPIO口,参数3 为对应的功能。

ADC_TriggerConfig(ADC_UNIT, ADC_SEQ, ADC_SEQ_HARDTRIG); 设置了ADC1的序列A 对应的端口在下降沿有效,通过配置ADC_TRGSR(A/D转换开始触发寄存器)中b2~b0。

⑦DMA初始化配置

static void DmaConfig(void)
{
    stc_dma_init_t stcDmaInit;
    stc_dma_repeat_init_t stcDmaRptInit;

    (void)DMA_StructInit(&stcDmaInit);
    stcDmaInit.u32IntEn       = DMA_INT_ENABLE;
    stcDmaInit.u32SrcAddr     = DMA_SRC_ADDR;
    stcDmaInit.u32DestAddr    = DMA_DEST_ADDR;
    stcDmaInit.u32DataWidth   = DMA_DATA_WIDTH;
    stcDmaInit.u32BlockSize   = DMA_BLOCK_SIZE;
    stcDmaInit.u32TransCount  = DMA_TRANS_CNT;
    stcDmaInit.u32SrcAddrInc  = DMA_SRC_ADDR_INC;
    stcDmaInit.u32DestAddrInc = DMA_DEST_ADDR_INC;

    /* Enable DMA peripheral clock and AOS function. */
    FCG_Fcg0PeriphClockCmd(DMA_PERIPH_CLK, ENABLE);
    (void)DMA_Init(DMA_UNIT, DMA_CH, &stcDmaInit);

    stcDmaRptInit.u32Mode      = DMA_RPT_BOTH;
    stcDmaRptInit.u32SrcCount  = DMA_BLOCK_SIZE;
    stcDmaRptInit.u32DestCount = DMA_BLOCK_SIZE;
    (void)DMA_RepeatInit(DMA_UNIT, DMA_CH, &stcDmaRptInit);

    /* Enable AOS clock */
    FCG_Fcg0PeriphClockCmd(FCG0_PERIPH_AOS, ENABLE);
    /* Set DMA trigger source */
    AOS_SetTriggerEventSrc(DMA_AOS_TRIG_SEL, DMA_TRIG_EVT);

    /* DMA IRQ configuration. */
    DmaIrqConfig();

    DMA_Cmd(DMA_UNIT, ENABLE);
    DMA_ChCmd(DMA_UNIT, DMA_CH, ENABLE);
}

具体DMA结构体成员说明,在本人发表DMA实验中有详细解析。

AOS_SetTriggerEventSrc(DMA_AOS_TRIG_SEL, DMA_TRIG_EVT); 第一个参数是被触发的外设电路动作,第二个参数是外设电路产生的事件。比如这里:ADC转换完成->DMA传输数据。

⑧DMA中断配置

static void DmaIrqConfig(void)
{
    stc_irq_signin_config_t stcIrqSignConfig;

    stcIrqSignConfig.enIntSrc    = DMA_INT_SRC;
    stcIrqSignConfig.enIRQn      = DMA_INT_IRQn;
    stcIrqSignConfig.pfnCallback = &DMA_IrqCallback;

    (void)INTC_IrqSignIn(&stcIrqSignConfig);
    DMA_ClearTransCompleteStatus(DMA_UNIT, DMA_INT_FLAG);

    /* NVIC setting */
    NVIC_ClearPendingIRQ(DMA_INT_IRQn);
    NVIC_SetPriority(DMA_INT_IRQn, DMA_INT_PRIO);
    NVIC_EnableIRQ(DMA_INT_IRQn);
}

中断详解请看本人发的中断实验文章。

⑨DMA中断回调函数

static void DMA_IrqCallback(void)
{
    DMA_ClearTransCompleteStatus(DMA_UNIT, DMA_INT_FLAG);
    m_u8AdcValUpdated = 1U;
}

⑩主函数

int32_t main(void)
{
    /* System clock is MRC@8MHz */

    /* MCU Peripheral registers write unprotected. */
    LL_PERIPH_WE(LL_PERIPH_GPIO | LL_PERIPH_FCG | LL_PERIPH_PWC_CLK_RMU);
    /* Initializes UART for debug printing. Baudrate is 19200. */
    DDL_PrintfInit(BSP_PRINTF_DEVICE, 19200U, BSP_PRINTF_Preinit);
    /* Configures ADC. */
    AdcConfig();
    /* MCU Peripheral registers write protected. */
    LL_PERIPH_WP(LL_PERIPH_GPIO | LL_PERIPH_FCG | LL_PERIPH_PWC_CLK_RMU);

    /***************** Configuration end, application start **************/

    for (;;) {
        /* Make a falling edge on the specified pin ADTRG to start ADC. */
        if (m_u8AdcValUpdated != 0U) {
            m_u8AdcValUpdated = 0U;
            DDL_Printf("Sequence A DMA transmission completed.\r\n");
            /* User code: Use the ADC value of sequence A. */
            DDL_Printf("The ADC value of potentiometer is %u, voltage is %u mV\r\n", \
                       m_au16AdcValue[PTTM_VAL_IDX], ADC_CAL_VOL(m_au16AdcValue[PTTM_VAL_IDX]));
        }
    }
}

特别声明的是:该实验除了通过PE7触发下降沿,还通过一个if函数 去掉按键抖动。if (m_u8AdcValUpdated != 0U){....}。

ADC+DMA实验代码到此结束了,有什么疑问可以私信我~

  • 2
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答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是一种可靠高效的数据传输方式,通过合理配置和使用,可以实现高速稳定的串口通信。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值