打印
[APM32F4]

【APM32F411V Tiny Board测评】+ADC采样测试

[复制链接]
210|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本次研究一下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");
最终串口打印数据:




使用特权

评论回复
沙发
星辰大海不退缩| | 2024-6-22 20:50 | 只看该作者
传感器产生的电压随着温度线性变化,可通过 ADC 获取转换的电压值换算成温度。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

119

主题

4485

帖子

26

粉丝