本次研究一下APM32F411的ADC外设功能。 该MCU有 2 个 ADC,精度为 12 位,每个 ADC 最多有 16 个外部通道和 3 个内部通道, 各通道 A/D 转换模式有单次、连续、扫描或间断, ADC 转换结果可以左对齐或右对齐存储在 16 位数据寄存器中。支持模拟看门狗,支持 DMA功能。 内置 1 个温度传感器(TSensor),内部连接 ADC_IN18 通道,传感器产生的电压随着温度线性变化,可通过 ADC 获取转换的电压值换算成温度。
内置 1 个 VBAT 监控器,内部连接 ADC_IN18 通道。 当同时设置温度传感器和 VBAT转换时,仅执行 VBAT转换。
内置参考电压 VREFINT,内部连接 ADC_IN17 通道,可通过 ADC 获取该 VREFINT; VREFINT 为ADC、比较器提供稳定的电压输出。
下面开始测试ADC转换功能。使用了PA0,PA1,PA2,PA3这4个ADC通道引脚。
(框内有个书写错误)。
间断模式和扫描模式差别:
扫描模式是一次触发,组内通道全部转换,然后产生标志位。
间断模式是一次触发转换一个通道,等组内所有通道转换完,再产生标志位。
ADC规则序列转换测试:
先使用ADC的规则序列转换功能。初始化ADC如下,间断模式和单次转换模式。使用中断方式读取数据:
- void ADC_Init(void)
- {
- GPIO_Config_T gpioConfig;
- ADC_Config_T adcConfig;
- ADC_CommonConfig_T adcCommonConfig;
- /* Enable GPIOA clock */
- RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOA);
- /* ADC channel 0 configuration */
- GPIO_ConfigStructInit(&gpioConfig);
- gpioConfig.mode = GPIO_MODE_AN;
- gpioConfig.pupd = GPIO_PUPD_NOPULL;
- gpioConfig.pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3;
- GPIO_Config(GPIOA, &gpioConfig);
- /* Enable ADC clock */
- RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1);
- /* ADC configuration */
- ADC_Reset();
- adcConfig.resolution = ADC_RESOLUTION_12BIT;
- adcConfig.scanConvMode = DISABLE;
- adcConfig.continuousConvMode = DISABLE;
- adcConfig.extTrigEdge = ADC_EXT_TRIG_EDGE_NONE;
- adcConfig.extTrigConv = ADC_EXT_TRIG_CONV_TMR1_CC1;
- adcConfig.dataAlign = ADC_DATA_ALIGN_RIGHT;
- adcConfig.nbrOfChannel = 4;
- ADC_Config(ADC1, &adcConfig);
- ADC_CommonConfigStructInit(&adcCommonConfig);
- /*Set ADC Clock Prescaler. ADC_Clock = APB2_Clock/4, 84/4=21MHz*/
- adcCommonConfig.prescaler = ADC_PRESCALER_DIV4;
- ADC_CommonConfig(&adcCommonConfig);
-
-
- /* ADC channel 0-3 Convert configuration */
- ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_0, 1, ADC_SAMPLETIME_112CYCLES);
- ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_1, 2, ADC_SAMPLETIME_112CYCLES);
- ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_2, 3, ADC_SAMPLETIME_112CYCLES);
- ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_3, 4, ADC_SAMPLETIME_112CYCLES);
- /* Enable complete conversion interupt */
- ADC_EnableInterrupt(ADC1, ADC_INT_EOC);
-
-
- /* NVIC configuration */
- NVIC_EnableIRQRequest(ADC_IRQn, 1, 1);
- /* Enable ADC */
- ADC_Enable(ADC1);
-
- }
复制代码 中断函数:
- uint16_t adcData[4] = {0};
- uint16_t adcIndex = 0;
- void ADC_IRQHandler(void)
- {
- if (ADC_ReadStatusFlag(ADC1, ADC_FLAG_EOC))
- {
- ADC_ClearStatusFlag(ADC1, ADC_FLAG_EOC);
-
- adcData[adcIndex++] = ADC_ReadConversionValue(ADC1);
- if(adcIndex == 4)
- {
- // adcIndex = 0;
- }else{
- ADC_SoftwareStartConv(ADC1);
- }
- }
- }
复制代码
在使用规则通道采样时要注意:多路采样时如果不用DMA方式读取数据的话,不要使用连续扫描模式。因为规则采样在采集多路ADC时只有一个转换完成标志。而且数据寄存器也只有1个。
这里我使用的是触发一次采样一次。没有使用连续扫描模式。
测试代码:
- #include "nr_micro_shell.h"
- void adc_read(char argc, char *argv)
- {
- ADC_SoftwareStartConv(ADC1); //ADC_EnableSoftwareStartInjectedConv();
- printf("ADC:\r\n");
- while(adcIndex < 4);
- adcIndex = 0;
- printf("1=%X\r\n",adcData[0]);
- printf("2=%X\r\n",adcData[1]);
- printf("3=%X\r\n",adcData[2]);
- printf("4=%X\r\n",adcData[3]);
- }
- NR_SHELL_CMD_EXPORT(adc, adc_read, "adc data");
复制代码
通过串口查看ADC采样值:
ADC注入序列采样模式:
接下来试试注入序列采样模式。
初始化如下:
- void ADC_Init(void)
- {
- GPIO_Config_T gpioConfig;
- ADC_Config_T adcConfig;
- ADC_CommonConfig_T adcCommonConfig;
- /* Enable GPIOA clock */
- RCM_EnableAHB1PeriphClock(RCM_AHB1_PERIPH_GPIOA);
- /* ADC channel 0 configuration */
- GPIO_ConfigStructInit(&gpioConfig);
- gpioConfig.mode = GPIO_MODE_AN;
- gpioConfig.pupd = GPIO_PUPD_NOPULL;
- gpioConfig.pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3;
- GPIO_Config(GPIOA, &gpioConfig);
- /* Enable ADC clock */
- RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1);
- /* ADC configuration */
- ADC_Reset();
- adcConfig.resolution = ADC_RESOLUTION_12BIT;
- adcConfig.scanConvMode = ENABLE; //DISABLE;
- adcConfig.continuousConvMode = DISABLE;
- adcConfig.extTrigEdge = ADC_EXT_TRIG_EDGE_NONE;
- adcConfig.extTrigConv = ADC_EXT_TRIG_CONV_TMR1_CC1;
- adcConfig.dataAlign = ADC_DATA_ALIGN_RIGHT;
- adcConfig.nbrOfChannel = 4;
- ADC_Config(ADC1, &adcConfig);
- ADC_CommonConfigStructInit(&adcCommonConfig);
- /*Set ADC Clock Prescaler. ADC_Clock = APB2_Clock/4, 84/4=21MHz*/
- adcCommonConfig.prescaler = ADC_PRESCALER_DIV4;
- ADC_CommonConfig(&adcCommonConfig);
-
-
- // /* ADC channel 0-3 Convert configuration */
- // ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_0, 1, ADC_SAMPLETIME_112CYCLES);
- // ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_1, 2, ADC_SAMPLETIME_112CYCLES);
- // ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_2, 3, ADC_SAMPLETIME_112CYCLES);
- // ADC_ConfigRegularChannel(ADC1, ADC_CHANNEL_3, 4, ADC_SAMPLETIME_112CYCLES);
- // /* Enable complete conversion interupt */
- // ADC_EnableInterrupt(ADC1, ADC_INT_EOC);
-
-
- ADC_ConfigInjectedSequencerLength(ADC1, 4);
- ADC_ConfigInjectedChannel(ADC1, ADC_CHANNEL_0, 1, ADC_SAMPLETIME_112CYCLES);
- ADC_ConfigInjectedChannel(ADC1, ADC_CHANNEL_1, 2, ADC_SAMPLETIME_112CYCLES);
- ADC_ConfigInjectedChannel(ADC1, ADC_CHANNEL_2, 3, ADC_SAMPLETIME_112CYCLES);
- ADC_ConfigInjectedChannel(ADC1, ADC_CHANNEL_3, 4, ADC_SAMPLETIME_112CYCLES);
- ADC_EnableInterrupt(ADC1, ADC_INT_INJEOC);
-
-
- /* NVIC configuration */
- NVIC_EnableIRQRequest(ADC_IRQn, 1, 1);
- /* Enable ADC */
- ADC_Enable(ADC1);
-
- }
复制代码 中断读取数据:
- uint16_t adcData[4] = {0};
- uint16_t adcIndex = 0;
- void ADC_IRQHandler(void)
- {
- // if (ADC_ReadStatusFlag(ADC1, ADC_FLAG_EOC))
- // {
- // ADC_ClearStatusFlag(ADC1, ADC_FLAG_EOC);
- //
- // adcData[adcIndex++] = ADC_ReadConversionValue(ADC1);
- // if(adcIndex == 4)
- // {
- // }else{
- // ADC_SoftwareStartConv(ADC1);
- // }
- // }
-
- if (ADC_ReadStatusFlag(ADC1, ADC_FLAG_INJEOC))
- {
- ADC_ClearStatusFlag(ADC1, ADC_FLAG_INJEOC);
- adcData[0] = ADC_ReadInjectedConversionValue(ADC1,1);
- adcData[1] = ADC_ReadInjectedConversionValue(ADC1,2);
- adcData[2] = ADC_ReadInjectedConversionValue(ADC1,3);
- adcData[3] = ADC_ReadInjectedConversionValue(ADC1,4);
- adcIndex = 4;
- }
- }
复制代码 测试代码:
- void adcin_read(char argc, char *argv)
- {
- ADC_EnableSoftwareStartInjectedConv(ADC1);
- printf("ADC1 Inject:\r\n");
- while(adcIndex < 4);
- adcIndex = 0;
- printf("1=%X\r\n",adcData[0]);
- printf("2=%X\r\n",adcData[1]);
- printf("3=%X\r\n",adcData[2]);
- printf("4=%X\r\n",adcData[3]);
- }
- NR_SHELL_CMD_EXPORT(adc, adcin_read, "adc data");
复制代码 最终串口打印数据:
|
|