打印
[APM32E0]

APM32E030ADC

[复制链接]
352|3
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
LIZARD925|  楼主 | 2025-7-20 17:57 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 LIZARD925 于 2025-7-20 17:39 编辑

#技术资源#

APM32E030系列使用记录--ADC的使用

  • ADC单通道,实现ADC采样的与读取
目标:实现阻塞式读取ADC数值
程序中使用ADC1的通道2进行ADC的读取,初始化程序如下
void AD_Init(void)
{
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1);
    RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA);
        
        GPIO_Config_T GPIO_InitStructure;
        GPIO_InitStructure.mode = GPIO_MODE_AN;
        GPIO_InitStructure.pupd = GPIO_PUPD_NO;
        GPIO_InitStructure.pin = GPIO_PIN_2;
        GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
        GPIO_Config(GPIOA, &GPIO_InitStructure);
        
        ADC_Reset();
        
        ADC_Config_T ADC_InitStructure;
        ADC_InitStructure.resolution = ADC_RESOLUTION_12B;                         //ADC数据分辨率
        ADC_InitStructure.scanDir = ADC_SCAN_DIR_UPWARD;                        //ADC扫描序列方向
        ADC_InitStructure.convMode = ADC_CONVERSION_CONTINUOUS;                //连续扫描
        ADC_InitStructure.dataAlign = ADC_DATA_ALIGN_RIGHT;                        //右对齐
        ADC_InitStructure.extTrigEdge = ADC_EXT_TRIG_EDGE_NONE;                //禁用外部触发转换模式
        ADC_InitStructure.extTrigConv = ADC_EXT_TRIG_CONV_TRG0;                //ADC外部触发转换定时器1 TRG0
        ADC_Config(&ADC_InitStructure);
        
        ADC_ConfigChannel(ADC_CHANNEL_2, ADC_SAMPLE_TIME_239_5);
        
        ADC_ReadCalibrationFactor();        //ADC 读取校准系数
        
    ADC_Enable();
        
        ADC_StartConversion();                        //开始转换
}

uint16_t AD_getvalue(void)
{
        while(ADC_ReadStatusFlag(ADC_FLAG_CC)==RESET);                //转换结束标志
        return ADC_ReadConversionValue();
}
此方式的ADC数值读取使用阻塞的方式,可能会阻塞主循环的其它函数,使用滑动电阻求连接ADC引脚,通过串口将采集的数据打印出来,查看是否正确
uint16_t ADvalue;
float v;

int main (void)
{
        LED_init();
        AD_Init();
        Serial_Init(115200);

        printf("APM32E030\r\n");
        
        while(1)
        {
                ADvalue=AD_getvalue();
                v=(float)ADvalue/4095*3.3;
                printf("ADC:%f\n",v);
               
                LED1_turn();
                Delay_ms(1000);
               
                rx_test();        //串口接收
        }
}
  • ADC单通道+中断,实现ADC采样的与读取
目标:实现中断读取ADC数值
程序中使用ADC1的通道2进行ADC的读取,初始化程序如下
void AD_Init(void)
{
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1);
    RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA);
        RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_SYSCFG);
        
        GPIO_Config_T GPIO_InitStructure;
        GPIO_InitStructure.mode = GPIO_MODE_AN;
        GPIO_InitStructure.pupd = GPIO_PUPD_NO;
        GPIO_InitStructure.pin = GPIO_PIN_2;
        GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
        GPIO_Config(GPIOA, &GPIO_InitStructure);
        
        ADC_Reset();
        
        ADC_Config_T ADC_InitStructure;
        ADC_InitStructure.resolution = ADC_RESOLUTION_12B;                         //ADC数据分辨率
        ADC_InitStructure.scanDir = ADC_SCAN_DIR_UPWARD;                        //ADC扫描序列方向
        ADC_InitStructure.convMode = ADC_CONVERSION_CONTINUOUS;                //连续扫描
        ADC_InitStructure.dataAlign = ADC_DATA_ALIGN_RIGHT;                        //右对齐
        ADC_InitStructure.extTrigEdge = ADC_EXT_TRIG_EDGE_NONE;                //禁用外部触发转换模式
        ADC_InitStructure.extTrigConv = ADC_EXT_TRIG_CONV_TRG0;                //ADC外部触发转换定时器1 TRG0
        ADC_Config(&ADC_InitStructure);
        
        ADC_ConfigChannel(ADC_CHANNEL_2, ADC_SAMPLE_TIME_239_5);
        
        /* Enable Interrupt*/
    ADC_EnableInterrupt(ADC_INT_CS);
    NVIC_EnableIRQRequest(ADC1_IRQn, 2);
        
        ADC_ReadCalibrationFactor();        //ADC 读取校准系数
    ADC_Enable();
        /* Wait until ADC is ready */
    while (!ADC_ReadStatusFlag(ADC_FLAG_ADRDY));
        ADC_StartConversion();                        //开始转换

}
只有ADC采集结束才会进入中断,将数据进行保存,此方式不阻塞主循环的其它函数,主循环通过串口将采集的数据进行打印,查看是否正确采集
uint16_t ADvalue;
float v;

int main (void)
{
        LED_init();
        Serial_Init(115200);
        AD_Init();

        printf("APM32E030\r\n");

        while(1)
        {
                v=(float)ADvalue/4095*3.3;
                printf("ADC:%f\n",v);
               
                LED1_turn();
                Delay_ms(1000);
               
                rx_test();        //串口接收
        }
}

void ADC1_IRQHandler(void)
{
    if (ADC_ReadIntFlag(ADC_INT_FLAG_CS) == SET)
    {
        ADC_ClearIntFlag(ADC_INT_FLAG_CS);
        ADvalue = ADC_ReadConversionValue();
    }
}
  • ADC多通道+DMA,实现ADC采样的与读取
目标:实现DMA读取ADC数值
程序中使用ADC1的通道0、1、2、3进行ADC的读取,初始化程序如下
#define ADC_CH_SIZE         4
uint16_t adcData[ADC_CH_SIZE];

void DMA_Init(void)
{
    DMA_Config_T dmaConfig;

    RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_DMA1);

    dmaConfig.peripheralAddress = ((uint32_t)ADC_BASE + 0x40);
    dmaConfig.memoryAddress = (uint32_t)&adcData;
    dmaConfig.direction = DMA_DIR_PERIPHERAL;
    dmaConfig.bufferSize = ADC_CH_SIZE;
    dmaConfig.peripheralInc = DMA_PERIPHERAL_INC_DISABLE;
    dmaConfig.memoryInc = DMA_MEMORY_INC_ENABLE;
    dmaConfig.peripheralDataSize = DMA_PERIPHERAL_DATASIZE_HALFWORD;
    dmaConfig.memoryDataSize = DMA_MEMORY_DATASIZE_HALFWORD;
    dmaConfig.circular = DMA_CIRCULAR_ENABLE;
    dmaConfig.memoryTomemory = DMA_M2M_DISABLE;
    dmaConfig.priority = DMA_PRIORITY_LEVEL_HIGHT;

    DMA_Config(DMA1_CHANNEL_1, &dmaConfig);
    DMA_Enable(DMA1_CHANNEL_1);
}

void AD_Init(void)
{
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1);
    RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA);
        
        GPIO_Config_T GPIO_InitStructure;
        GPIO_InitStructure.mode = GPIO_MODE_AN;
        GPIO_InitStructure.pupd = GPIO_PUPD_NO;
        GPIO_InitStructure.pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3;
        GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
        GPIO_Config(GPIOA, &GPIO_InitStructure);
        
        ADC_Reset();
        
        ADC_Config_T ADC_InitStructure;
        ADC_InitStructure.resolution = ADC_RESOLUTION_12B;
        ADC_InitStructure.scanDir = ADC_SCAN_DIR_UPWARD;
        ADC_InitStructure.convMode = ADC_CONVERSION_CONTINUOUS;        //连续扫描
        ADC_InitStructure.dataAlign = ADC_DATA_ALIGN_RIGHT;        //右对齐
        ADC_InitStructure.extTrigEdge = ADC_EXT_TRIG_EDGE_NONE;
        ADC_InitStructure.extTrigConv = ADC_EXT_TRIG_CONV_TRG0;
        ADC_Config(&ADC_InitStructure);
        
        ADC_ConfigChannel(ADC_CHANNEL_0, ADC_SAMPLE_TIME_239_5);
    ADC_ConfigChannel(ADC_CHANNEL_1, ADC_SAMPLE_TIME_239_5);
    ADC_ConfigChannel(ADC_CHANNEL_2, ADC_SAMPLE_TIME_239_5);
        ADC_ConfigChannel(ADC_CHANNEL_3, ADC_SAMPLE_TIME_239_5);
        
        DMA_Init();
        ADC_ReadCalibrationFactor();
        
        ADC_EnableDMA();
    ADC_DMARequestMode(ADC_DMA_MODE_CIRCULAR);
        
    ADC_Enable();

        ADC_StartConversion();
}

uint16_t AD_getvalue(uint8_t index)
{
        return adcData[index];
}
配置DMA进行ADC数据的搬运,我们只需要在必要的时候读取buff中的数据即可得到ADC采集的数据,主循环中通过串口将采集的数据进行打印,查看数据是否正确
uint16_t ADvalue;
float v;

int main (void)
{
        LED_init();
        Serial_Init(115200);
        AD_Init();
        printf("APM32E030\r\n");
        
        while(1)
        {
                ADvalue=AD_getvalue(0);
                v=(float)ADvalue/4095*3.3;
                printf("PA0ADC:%f\n",v);
               
                ADvalue=AD_getvalue(1);
                v=(float)ADvalue/4095*3.3;
                printf("PA1ADC:%f\n",v);
               
                ADvalue=AD_getvalue(2);
                v=(float)ADvalue/4095*3.3;
                printf("PA2ADC:%f\n",v);
               
                ADvalue=AD_getvalue(3);
                v=(float)ADvalue/4095*3.3;
                printf("PA3ADC:%f\r\n",v);

                LED1_turn();
                Delay_ms(1000);
               
                rx_test();        //串口接收
        }
}
  • ADC单通道+参考电压/温度,实现ADC采样的与读取
目标:实现读取ADC数值
程序中使用ADC1的通道16/17进行ADC的读取参考电压,初始化程序如下
#include "ad.h"                  // Device header

void AD_Init(void)
{
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1);

        ADC_Reset();
//        ADC_EnableTempSensor();        //温度初始化
        ADC_EnableVrefint();        //参考电压初始化
        
        ADC_Config_T ADC_InitStructure;
        ADC_InitStructure.resolution = ADC_RESOLUTION_12B;                         //ADC数据分辨率
        ADC_InitStructure.scanDir = ADC_SCAN_DIR_UPWARD;                        //ADC扫描序列方向
        ADC_InitStructure.convMode = ADC_CONVERSION_CONTINUOUS;                //连续扫描
        ADC_InitStructure.dataAlign = ADC_DATA_ALIGN_RIGHT;                        //右对齐
        ADC_InitStructure.extTrigEdge = ADC_EXT_TRIG_EDGE_NONE;                //禁用外部触发转换模式
        ADC_InitStructure.extTrigConv = ADC_EXT_TRIG_CONV_TRG0;                //ADC外部触发转换定时器1 TRG0
        ADC_Config(&ADC_InitStructure);
        
//        ADC_ConfigChannel(ADC_CHANNEL_16, ADC_SAMPLE_TIME_239_5);
        ADC_ConfigChannel(ADC_CHANNEL_17, ADC_SAMPLE_TIME_239_5);
        
        ADC_ReadCalibrationFactor();        //ADC 读取校准系数
        
    ADC_Enable();
        
        ADC_StartConversion();                        //开始转换
}

void AD_getvalue(void)
{        
        uint32_t reference_adc_value = 0, tsen_adc_value = 0;
        ADC_DisableTempSensor();

//        ADC_ConfigChannel(ADC_CHANNEL_16, ADC_SAMPLE_TIME_239_5);
//        ADC_StartConversion();
//        while(ADC_ReadStatusFlag(ADC_FLAG_CC)==RESET);                //转换结束标志
//        tsen_adc_value = ADC_ReadConversionValue();
//        printf("tsen_adc_value: %d\n", tsen_adc_value);

        
        ADC_StopConversion();
        ADC_ConfigChannel(ADC_CHANNEL_17, ADC_SAMPLE_TIME_239_5);
        ADC_StartConversion();
        while(ADC_ReadStatusFlag(ADC_FLAG_CC)==RESET);                //转换结束标志
        reference_adc_value = ADC_ReadConversionValue();
        printf("reference_adc_value: %d\n", reference_adc_value);
}
但是读取的结果与手册写的1.2v有出入,我读到的是1.5V,不知道哪里出了问题,中断与DMA的流程和之前的一样,都可以进行读取
  • ADC多通道+参考电压/温度,实现ADC采样的与读取
目标:实现DMA读取ADC数值
程序中使用ADC1的通道进行ADC的读取,初始化程序如下
#include "ad.h"                  // Device header

#define ADC_CH_SIZE         6
uint16_t adcData[ADC_CH_SIZE];

void DMA_Init(void)
{
    DMA_Config_T dmaConfig;

    RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_DMA1);

    dmaConfig.peripheralAddress = ((uint32_t)ADC_BASE + 0x40);
    dmaConfig.memoryAddress = (uint32_t)&adcData;
    dmaConfig.direction = DMA_DIR_PERIPHERAL;
    dmaConfig.bufferSize = ADC_CH_SIZE;
    dmaConfig.peripheralInc = DMA_PERIPHERAL_INC_DISABLE;
    dmaConfig.memoryInc = DMA_MEMORY_INC_ENABLE;
    dmaConfig.peripheralDataSize = DMA_PERIPHERAL_DATASIZE_HALFWORD;
    dmaConfig.memoryDataSize = DMA_MEMORY_DATASIZE_HALFWORD;
    dmaConfig.circular = DMA_CIRCULAR_ENABLE;
    dmaConfig.memoryTomemory = DMA_M2M_DISABLE;
    dmaConfig.priority = DMA_PRIORITY_LEVEL_HIGHT;

    DMA_Config(DMA1_CHANNEL_1, &dmaConfig);
    DMA_Enable(DMA1_CHANNEL_1);
}

void AD_Init(void)
{
    RCM_EnableAPB2PeriphClock(RCM_APB2_PERIPH_ADC1);
    RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_GPIOA);
       
        GPIO_Config_T GPIO_InitStructure;
        GPIO_InitStructure.mode = GPIO_MODE_AN;
        GPIO_InitStructure.pupd = GPIO_PUPD_NO;
        GPIO_InitStructure.pin = GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_3;
        GPIO_InitStructure.speed = GPIO_SPEED_50MHz;
        GPIO_Config(GPIOA, &GPIO_InitStructure);
       
        ADC_Reset();
        ADC_EnableTempSensor();
        ADC_EnableVrefint();
       
        ADC_Config_T ADC_InitStructure;
        ADC_InitStructure.resolution = ADC_RESOLUTION_12B;
        ADC_InitStructure.scanDir = ADC_SCAN_DIR_UPWARD;
        ADC_InitStructure.convMode = ADC_CONVERSION_CONTINUOUS;        //连续扫描
        ADC_InitStructure.dataAlign = ADC_DATA_ALIGN_RIGHT;        //右对齐
        ADC_InitStructure.extTrigEdge = ADC_EXT_TRIG_EDGE_NONE;
        ADC_InitStructure.extTrigConv = ADC_EXT_TRIG_CONV_TRG0;
        ADC_Config(&ADC_InitStructure);
       
        ADC_ConfigChannel(ADC_CHANNEL_0, ADC_SAMPLE_TIME_239_5);
    ADC_ConfigChannel(ADC_CHANNEL_1, ADC_SAMPLE_TIME_239_5);
    ADC_ConfigChannel(ADC_CHANNEL_2, ADC_SAMPLE_TIME_239_5);
        ADC_ConfigChannel(ADC_CHANNEL_3, ADC_SAMPLE_TIME_239_5);
        ADC_ConfigChannel(ADC_CHANNEL_16, ADC_SAMPLE_TIME_239_5);
        ADC_ConfigChannel(ADC_CHANNEL_17, ADC_SAMPLE_TIME_239_5);
       

        DMA_Init();
        ADC_ReadCalibrationFactor();
       
        ADC_EnableDMA();
    ADC_DMARequestMode(ADC_DMA_MODE_CIRCULAR);
       
    ADC_Enable();

        ADC_StartConversion();
}

uint16_t AD_getvalue(uint8_t index)
{
        return adcData[index];
}


将每个通道保存到buff中,进行读取即可
uint16_t ADvalue;
float v;

int main (void)
{
        LED_init();
        Serial_Init(115200);
        AD_Init();
        printf("APM32E030\r\n");
       
        while(1)
        {
                ADvalue=AD_getvalue(0);
                v=(float)ADvalue/4095*3.3;
                printf("PA0ADC:%f\n",v);
               
                ADvalue=AD_getvalue(1);
                v=(float)ADvalue/4095*3.3;
                printf("PA1ADC:%f\n",v);
               
                ADvalue=AD_getvalue(2);
                v=(float)ADvalue/4095*3.3;
                printf("PA2ADC:%f\n",v);
               
                ADvalue=AD_getvalue(3);
                v=(float)ADvalue/4095*3.3;
                printf("PA3ADC:%f\r\n",v);
               
                ADvalue=AD_getvalue(4);
                printf("TempSensor:%d\r\n",ADvalue);
               
                ADvalue=AD_getvalue(5);
                printf("Vref:%d\r\n",ADvalue);

                LED1_turn();
                Delay_ms(1000);
               
                rx_test();        //串口接收
        }
}
ADC的使用到此基本差不多了,对于基准电压的采集,以后再找问题






6-3 APM32E030-ADC多通道.zip

177.69 KB

6-2 APM32E030-ADC中断.zip

177.23 KB

6-1 APM32E030-ADC.zip

176.18 KB

6-6 APM32E030-ADC多通道_temperature.zip

179.46 KB

6-4 APM32E030-ADC_temperature.zip

2.31 MB

使用特权

评论回复
沙发
天体书记| | 2025-7-21 11:06 | 只看该作者
这个ADC的帖子也太霸气了。
我倾向于DMA按顺序周期扫描的策略。

使用特权

评论回复
板凳
黄昏收获| | 2025-7-21 15:21 | 只看该作者
这颗小芯片的ADC功能还这么丰富啊

使用特权

评论回复
地板
永恒回声| | 2025-7-21 16:59 | 只看该作者
是不是M0内核的ADC模块都没有外部参考电压引脚。
我总觉得VCCA的电压不稳会带来ADC采样精度的偏差

使用特权

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

本版积分规则

17

主题

19

帖子

0

粉丝