stm32-4-ADC


1 ADC简介

  1. ADC(Analog-Digital Converter, 模拟-数字转换器)可以将连续变化的模拟电压转换为内存中存储的数字变量,建立模拟电路到数字电路的桥梁。
  2. 分辨率:与ADC的位数相关,位数越高分辨率越高。如果12位的ADC的转换范围为0 ~ 4095,如果输入电压为0 ~ 3.3V,就是将0 ~ 3.3映射到0 ~ 4095.
  3. 具有18个输入通道,其中包括16个外部(对应16个GPIO口PIN脚)和2个内部信号源.
  4. 转换组分为注入通道组和规则通道组两种,其中规则通道组最多能够组织16个通道,但存放转换结果的寄存器只有一个,因而需要配合DMA来运输数据防止数据被覆盖;而注入通道组则最多组织4个通道,存放转换结果的寄存器有4个,与注入通道一一对应。
  5. 转换触发:分为软件触发和硬件触发两种,前者就是代码中直接调用进行转换,而后者则是通过TIM或者EXTI来实现。ADC转换通常是周期性的进行转换,因而很直觉地知道可以用TIM中断来实现,当TIM产生中断时在中断处理函数中调用ADC转换;然后,频繁地中断会影响主程序的运行,也可能导致部分数据来不及转换,因而TIM可以选择TRGO,当产生中断时,通过TRGO传到ADC模块从而实现硬件触发转换。转换完成的标志存放在EOC中,可以传送到NVIC中申请中断。

  6. 规则组转换模式:通过初始化结构体进行配置

    • 单次转换、非扫描模式:只有序列1有效,单次转换完成后就结束并将EOC转换,如果需要继续转换需要继续调用
    • 单次转换、扫描模式:按序列进行转换,且单次转换会转换整个序列然后产生EOC信号并结束转换
    • 连续转换、非扫描模式:只有序列1有效并且可以进行连续转换,只需要触动一次
    • 连续转换、扫描模式:连续扫描整个序列进行转换

2 ADC初始化

  1. 使能时钟(ADC+GPIO)、配置ADCCLK分频器(最高为14MHz)
  2. 配置GPIO输入模式
  3. 配置多路开关
  4. 配置ADC转换器
  5. 配置模拟看门狗、中断
  6. 开关控制

3 ADC库函数实现

  1. 使能时钟(ADC+GPIO)、配置ADCCLK分频器(最高为14MHz)
  • 函数原型:void RCC_ADCCLKConfig(uint32_t RCC_PCLK2);
  • 输入: RCC_PCLK2
  • 功能:配置ADCCLK分分频器
  1. 配置GPIO输入模式为模拟输入模式
  2. 配置多路开关
  • 函数
    • 函数原型:void ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState);
    • 功能:使能DMA
  1. 配置ADC转换器
  • 函数1
    • 函数原型:void ADC_StructInit(ADC_InitTypeDef* ADC_InitStruct);
    • 功能:初始化ADC转换器初始化结构体成员。
  • 函数2
    • 函数原型:void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
    • 功能:初始化ADC转换器
  • 函数3
    • 函数原型:void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState);
    • 功能:配置ADC触发模型为软件触发
  • 函数4
    • 函数原型:void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
    • 功能:配置规则通道,channel为通道,rank为序列
  1. 配置模拟看门狗、中断
  • 函数1
    • 函数原型:void ADC_ITConfig(ADC_TypeDef* ADCx, uint16_t ADC_IT, FunctionalState NewState);
    • 功能:使能中断
  • 函数2
    • 函数原型:void ADC_AnalogWatchdogCmd(ADC_TypeDef* ADCx, uint32_t ADC_AnalogWatchdog);
    • 功能:开启看门狗
  • 函数3
    • 函数原型:void ADC_AnalogWatchdogThresholdsConfig(ADC_TypeDef* ADCx, uint16_t HighThreshold, uint16_t LowThreshold);
    • 功能:设置高低阈值
  • 函数4
    • 函数原型:void ADC_AnalogWatchdogSingleChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel);
    • 功能:看门狗通道配置
  • 函数5
    • 函数原型:void ADC_TempSensorVrefintCmd(FunctionalState NewState);
    • 使能内部温度传感器
  1. 开关控制
  • 函数1
    • 函数原型:void ADC_Cmd(ADC_TypeDef* ADCx, FunctionalState NewState);
    • 功能:使能或失能ADC
  • 函数2
    • 函数原型:uint16_t ADC_GetConversionValue(ADC_TypeDef* ADCx);
    • 功能:获取ADC转换结果
  1. 校准
  • 函数1:void ADC_ResetCalibration(ADC_TypeDef* ADCx);
  • 函数2:FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);
  • 函数3:void ADC_StartCalibration(ADC_TypeDef* ADCx);
  • 函数4:FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);
  1. 代码实现

  使用ADC1并配置为单通道、单次非扫描、软件触发模式

void ADC_Init(void){
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);

    GPIO_InitType GPIO_InitStructrue;
    GPIO_InitStructrue.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_InitStructrue.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructrue.GPIO_Pin = GPIO_Pin_0;
    GPIO_Init(GPIOA, &GPIO_InitStructrue);

    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_1Cycles5);
    // 如果要多通道则多次调用ADC_RegularChannelConfig函数
    ADC_DMACmd(ADC1, ENABLE);

    ADC_InitTypeDef ADC_InitStructrue;
    ADC_StructInit(&ADC_InitStructrue);
    ADC_InitStructrue.ADC_Mode = ADC_Mode_Independent;       // 工作模式:独立?双adc?
    ADC_InitStructrue.ADC_ScanConvMode = DISABLE;
    ADC_InitStructrue.ADC_ContinuousConvMode = DISABLE;
    ADC_InitStructrue.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;   // 定义用于启动规则组转换的外部触发源
    ADC_InitStructrue.ADC_DataAlign = ADC_DataAlign_Right;  // 数据对齐模式
    ADC_InitStructrue.ADC_NbrOfChannel = 1; // 通道数目
    // 多通道需要修改通道数目
    ADC_Init(ADC1, &ADC_InitStructrue);

    ADC_Cmd(ADC1, ENABLE);

    ADC_ResetCalibration(ADC1);
    while(ADC_GetResetCalibrationStatus(ADC1) == SET); // 等待复位校准完成
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1) == SET);      // 获取校准状态
}

uint16_t ADC_GetValue(void){
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
    return ADC_GetConversionValue(ADC1);    // 自动清除了EOC
}

多通道模式下一般需要用扫描模式,但是需要DMA来传输数据结果。也可以采用单次非扫描,只要每次读取数据的时候对通道进行修改即可,代码如下:

void ADC_Init(void){
  //...
  GPIO_InitStructrue.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
  //...
}

// 采用单次非扫描模式对指定通道进行转换
uint16_t(uint8_t ADC_Channel){
  ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_1Cycles5);
  ADC_SoftwareStartConvCmd(ADC1, ENABLE);
  while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
  return ADC_GetConversionValue(ADC1);    // 自动清除了EOC
}


文章作者: Vyron Su
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Vyron Su !