华大 HC32F460 ADC+DMA实验代码详解 您所在的位置:网站首页 单片机看门狗作用大不大 华大 HC32F460 ADC+DMA实验代码详解

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

2024-06-18 19:12| 来源: 网络整理| 查看: 265

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

一.基础知识

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 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实验代码到此结束了,有什么疑问可以私信我~



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有