常见问题

当前位置:主页 > 服务支持 > 常见问题 >

APM32F003系列外设ADC单通道和多通道应用

作者: admin 时间:2023-04-01 来源:未知
摘要:01 ADC简介 APM32F003的ADC是一个12位,ADC时钟最高可选择Fmaster时钟的一半。带有9个通道,可测量8个外部和1个内部信号源。各通道的A/D转换可选择单次、连续和扫描模式执行。而ADC的转换结...

ADC 代表模数转换,它用于将模拟值从现实世界转换为数字值,如 1 和 0。

01 ADC简介
 
APM32F003的ADC是一个12位,ADC时钟最高可选择Fmaster时钟的一半。带有9个通道,可测量8个外部和1个内部信号源。各通道的A/D转换可选择单次、连续和扫描模式执行。而ADC的转换结果也可以以左对齐或右对齐的方式存储在16位数据寄存器中。
 
02 ADC特点
 
APM32F003的ADC相比于F0x,F10x,F4x系列有所简化,但也保留了相对核心的功能,能够满足普通场合下的应用需求。
  ADC特点示意图
 
03 ADC应用
## 单通道转换
### 定义公共信息
/** ADC Channel Definition*/
#define ADC_CH0_CHANNEL                     ADC_CHANNEL_0
 
/** ADC GPIO Definition*/
#define ADC_CH0_GPIO_PIN                    GPIO_PIN_5
#define ADC_CH_GPIO_PORTC                   GPIOC
 
/** ADC Info*/
#define VDD_VOLTAGE                         ((uint32_t)3300)
#define ADC_RANGE                           ((uint32_t)4095)
 
### 设置ADC通道和方式
/** ADC Single Convert Init*/
void ADC_SingleConvInit(void)
{
    ADC_Config_T adcConfig;
 
    ADC_GPIOConfig();
 
    ADC_SetMode(ADC_MODE_SINGLE_END);
 
    /** ADC Configuration*/
    ADC_ConfigStructInit(&adcConfig);
    adcConfig.channel = ADC_CH0_CHANNEL;
    adcConfig.convMode = ADC_CONV_MODE_CONTINUOUS;
    adcConfig.interrupt = ADC_INT_CC;
    ADC_Config(&adcConfig);
 
    /** Calibration*/
    ADC_Calibration();
 
    ADC_Enable();
    ADC_StartConversion();
}
 
### 轮询转换值
/** ADC Poll for Single Conversion*/
void ADC_PollSingleConv(void)
{
    uint16_t adcData;
    uint16_t voltage;
 
    if(ADC_ReadStatusFlag(ADC_FLAG_CC) == SET)
    {
        ADC_ClearStatusFlag(ADC_FLAG_CC);
 
        adcData = ADC_ReadData();
 
        voltage = (adcData * VDD_VOLTAGE) / ADC_RANGE;
 
        printf("ADC Channel 0 Voltage: %d\r\n",adcData);
    }
}
 
## 多通道扫描
### 定义公共信息
/** ADC Channel Definition*/
#define ADC_CH0_CHANNEL                     ADC_CHANNEL_0
#define ADC_CH1_CHANNEL                     ADC_CHANNEL_1
#define ADC_CH2_CHANNEL                     ADC_CHANNEL_2
 
/** ADC GPIO Definition*/
#define ADC_CH0_GPIO_PIN                    GPIO_PIN_5
#define ADC_CH1_GPIO_PIN                    GPIO_PIN_6
#define ADC_CH2_GPIO_PIN                    GPIO_PIN_4
#define ADC_CH_GPIO_PORTC                   GPIOC
 
/** ADC Info*/
#define VDD_VOLTAGE                         ((uint32_t)3300)
#define ADC_RANGE                           ((uint32_t)4095)
 
### 设置ADC通道和方式
> 注意扫描的通道数量和所设置的通道一致,比如设置了通道CH2,则ADC会从ADC CH0扫描到ADC CH2,共三个通道。
 
/** ADC GPIO Config*/
void ADC_GPIOConfig(void)
{
    GPIO_Config_T gpioConfig;
 
    gpioConfig.intEn = GPIO_EINT_DISABLE;
    gpioConfig.mode = GPIO_MODE_IN_FLOATING;
    gpioConfig.pin = ADC_CH0_GPIO_PIN | ADC_CH1_GPIO_PIN | ADC_CH2_GPIO_PIN;
    GPIO_Config(ADC_CH_GPIO_PORTC, &gpioConfig);
}
 
/** ADC Continuous Scan Init*/
void ADC_ContinuousScanInit(void)
{
    ADC_Config_T adcConfig;
 
    ADC_GPIOConfig();
 
    ADC_SetMode(ADC_MODE_SINGLE_END);
 
    /** ADC Configuration*/
    ADC_ConfigStructInit(&adcConfig);
    adcConfig.div = ADC_DIV_4;
    adcConfig.channel = ADC_CH2_CHANNEL;
    adcConfig.convMode = ADC_CONV_MODE_CONTINUOUS;
    adcConfig.scanMode = ADC_SCAN_MODE_ENABLE;
    adcConfig.interrupt = ADC_INT_CC;
    ADC_Config(&adcConfig);
 
    /** Calibration*/
    ADC_Calibration();
 
    ADC_Enable();
    ADC_StartConversion();
}
 
### 轮询转换值
/** ADC Poll for Conversion*/
void ADC_PollForConv(void)
{
    uint16_t adcArray[10] = {0};
    uint16_t voltage;
    uint8_t bufferIndex;
 
    if(ADC_ReadStatusFlag(ADC_FLAG_CC) == SET)
    {
        ADC_ClearStatusFlag(ADC_FLAG_CC);
 
        for(bufferIndex = 0; bufferIndex < 10; bufferIndex)
        {
            adcArray[bufferIndex] = ADC_ReadBufferData((ADC_BUFFER_IDX_T)(bufferIndex));
        }
 
        for(bufferIndex = 0; bufferIndex < 3; bufferIndex++)
        {
            voltage = (adcArray[bufferIndex] * VDD_VOLTAGE) / ADC_RANGE;
 
            printf("ADC Channel %d Voltage: %d\r\n",bufferIndex, voltage);
        }
    }
}
 
## 软件滤波
在硬件抗干扰能力不足的情况下,我们可以牺牲采用速率,采用软件方法进行滤波,从而得到更加稳定的采样值。一般应用的情况下,“抗脉冲干扰均值滤波”算法就能够满足需求。
/** Anti-interference Average Filtering*/
uint16_t Anti_AverageFilter(uint16_t *buffer, uint16_t length)
{
    uint16_t temp;
    uint16_t i,j;
 
    /**Bubbling Sort*/
    for(j = 0; j < length - 1; j++)
    {
        for(i = 0; i < length - j - 1; i++)
        {
            if(buffer > buffer[i + 1])
            {
                temp = buffer;
                buffer = buffer[i + 1];
                buffer[i + 1] = temp;
            }
        }
    }
 
    temp = 0;
 
    for(i = 1; i < length - 1; i++)
    {
        temp += buffer;
    }
    temp /= (length - 2);
 
    return temp;
}
## 软件校准
如果采样值较为固定,但离目标值相差大,还可以利用线性拟合(线性校准曲线)的方式让采样值更接近目标值。
 
### 采样
首先基于标准源表采样足够多的点(点数越多,拟合越准确)。
采样参考值
 
### 拟合
在数学工具(Matlab或Excel等)中做线性拟合(线性、多项式、指数皆可),得到校准公式和相关系数R值。
 
ADS采样样品
### 校准
用拟合步骤中得到的校准公式对采样值进行校准。
采样样品校准
 

[向上]