STM32 的ADC使用指南

ADC简介

ADC,即模数转换器(Analog-to-Digital Converter),是一种在微控制器(如STM32)中常见的设备,它能够将模拟信号转换为数字信号。简单来说,我们的现实世界中大部分的信号都是模拟的,比如声音、光线强度、温度等,它们的变化是连续的。而微控制器是数字设备,它处理的是0和1的数字信号。 ADC让我们可以读取模拟信号的值,然后将这个连续变化的信号转换成一系列数字,微控制器就可以读取这些数字进行进一步的处理了。举个例子,如果你有一个测量温度的传感器,它输出的是电压变化,你可以用ADC读取这些电压变化,然后转换成温度值。 在STM32等微控制器中,ADC的分辨率通常是12位的,这意味着它可以将模拟信号转换为0到4095之间的数字值(2的12次方等于4096个不同的值)。如果ADC是10位的,它就可以输出0到1023之间的值(2的10次方等于1024个不同的值)

ADC可以读取哪些模拟信号?

  1. 电压信号:直接测量通过电阻分压器或其他电压源产生的电压。
  2. 电流信号:通过电流传感器如霍尔效应传感器产生的模拟输出。
  3. 压力信号:使用压力传感器将压力变化转换为电压信号读取。
  4. 光强信号:例如利用光敏电阻或光敏二极管测量环境的光线强度。
  5. 湿度信号:通过湿度传感器,将环境的湿度变化转换为可读的电压信号。
  6. 声音信号:通过麦克风传感器将环境中的声波转换为电压信号。

ADC的分辨率和采样速率有什么关系?

ADC的分辨率和采样速率是两个不同的概念,它们描述了模数转换器的不同特性:

  1. 分辨率:分辨率决定了ADC可以区分的最小电压差值。由ADC的位数决定,位数越高,分辨率越高,能够检测到的最小电压变化就越小。例如,一个12位的ADC具有2^12(4096)个不同的可能的输出值。
  2. 采样速率:采样速率(或采样频率)是ADC单位时间内可以执行的采样次数。它通常以赫兹(Hz)为单位。采样率越高,ADC就能够更频繁地采集数据,更好地跟踪快速变化的信号。

两者之间的关系是,在保持一定的分辨率的条件下,增加采样速率可能需要更强大的ADC性能和更高的处理能力。同时,根据奈奎斯特定理,为了准确地重建一个模拟信号,采样频率需要至少是信号最高频率的两倍。 总的来说,分辨率描述了ADC测量精度的能力,而采样速率描述了ADC测量频率的能力。在实际应用中,两者需要根据具体的测量需求和性能要求来平衡选择。

STM32中ADC的工作原理

在STM32微控制器中,ADC(模数转换器)的工作原理基于将模拟信号(如电压)转化为数字值的过程。以下是ADC在STM32中的基本工作方式:

  1. 采样 - ADC首先对模拟信号进行采样,即在特定的时刻捕获信号的值。STM32的ADC可以配置为手动触发采样或通过定时器等外部事件自动触发。
  2. 保持 - 模拟信号被ADC的采样保持电路捕获并保持在一定时间内,这样便于转换电路准确读取到这个值。保持时间需要足够长,以确保转换的准确性。
  3. 量化 - 模拟信号通过ADC内的量化电路转换成数字值。量化过程是将采样的模拟信号划分到一定数量的离散区间内,并将这个模拟信号转换为代表这个区间的数字值。在STM32的ADC通常可以是12位的,即4096个区间。
  4. 转换 - 量化后的数字信号是模拟信号的近似数字表示。这个数字最终通过ADC寄存器可以被微控制器读取和处理。
  5. 输出 - 微控制器通过读取ADC数据寄存器,获取转换结果。这个结果通常是以二进制或十六进制的格式表示,但可以根据需要,通过软件算法转换成相应的物理单位(比如温度、压力等)。

在STM32中,通过配置ADC寄存器,开发者可以定制化ADC工作方式,例如选择不同的采样时间、分辨率、通道,以及是否启用连续采样或单次采样等。每个STM32系列的微控制器可能有多个ADC模块,并且每个ADC模块可能有多个通道。基于具体的应用需求,开发者可以选择合适的ADC以及相应的配置来进行数据的采集和处理。

重要寄存器

  1. ADC_CommonInitTypeDef:这不是一个单独的寄存器,但它是一个结构体,用于初始化ADC的通用设置,适用于包含多个ADC模块的STM32芯片。
  2. ADC_CR1ADC_CR2(控制寄存器1和2):这些寄存器用于控制ADC的主要功能,如转换分辨率、连续转换模式、触发源选择等。
  3. ADC_SMPR1ADC_SMPR2(采样时间寄存器1和2):这些寄存器用于配置各个ADC通道的采样时间。
  4. ADC_HTRADC_LTR(看门狗高阈值和低阈值寄存器):如果使用模拟看门狗功能,将会用到这些寄存器来设置高低阈值。
  5. ADC_SQR1ADC_SQR2ADC_SQR3(规则序列寄存器):用于设置规则转换序列和每次序列要转换的通道数量。
  6. ADC_JSQR(注入序列寄存器):如果使用注入通道功能,用于设置注入序列和转换的通道。
  7. ADC_DR(数据寄存器):用于读取转换结果的电压值。
  8. ADC_CCR(公共控制寄存器):适用于一些特定的STM32芯片,用于控制与多个ADC模块相关的某些特性,如温度传感器、Vrefint引用电压等。

如何配置这些寄存器

在程序中配置STM32的ADC寄存器,一般需要以下步骤:

  1. 启用ADC和GPIO时钟 :使用RCC_APB2PeriphClockCmd()函数启用ADC和与ADC输入通道相对应的GPIO端口的时钟。

    cpp 复制代码
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOx, ENABLE);
  2. 配置ADC使用的GPIO为模拟输入模式 :将GPIO端口配置为模拟输入模式以用于ADC。

    cpp 复制代码
    GPIO_InitTypeDef GPIO_InitStructure; 
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_x; // 替换x为实际的引脚 
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; 
    GPIO_Init(GPIOx, &GPIO_InitStructure); // 替换x为实际的端口
  3. 复位并初始化ADC :创建ADC_InitTypeDef结构体并使用ADC_StructInit()函数进行初始化。

    cpp 复制代码
    ADC_InitTypeDef ADC_InitStructure; ADC_StructInit(&ADC_InitStructure);
  4. 配置特定于ADC的寄存器

    • 使用ADC_Init()函数配置ADC_CR1和ADC_CR2。

    • 根据ADC通道数配置ADC_SMPR1和ADC_SMPR2。

    • 设定ADC转换序列与转换次数(ADC_SQR1, ADC_SQR2和ADC_SQR3)。

      cpp 复制代码
      ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
      ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 或 ENABLE,取决于是单通道还是多通道 
      
      ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 或 DISABLE 
      
      ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
      ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; 
      ADC_InitStructure.ADC_NbrOfChannel = 1; // 根据需要设置通道数
      
      ADC_Init(ADC1,&ADC_InitStructure); 
      ADC_RegularChannelConfig(ADC1, ADC_Channel_x, 1, ADC_SampleTime_55Cycles5); // x是通道号
  5. 校准并启用ADC :在诸如ADC_CR2这样的寄存器中启用ADC然后启动校准过程。

    cpp 复制代码
    ADC_Cmd(ADC1, ENABLE); ADC_ResetCalibration(ADC1); 
    
    while(ADC_GetResetCalibrationStatus(ADC1)); ADC_StartCalibration(ADC1); 
    
    while(ADC_GetCalibrationStatus(ADC1));
  6. 启动ADC转换 :软件启动ADC或配置触发器自动启动转换。

    cpp 复制代码
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
  7. 读取ADC值 :从ADC_DR寄存器读取转换结果。

    cpp 复制代码
    uint16_t ADC_Value = ADC_GetConversionValue(ADC1);

请根据具体的STM32型号和库函数版本查看参考手册和标准外设库,因为不同的型号和库函数版本有一些差异。这些设置应作为指导,应根据你实际使用的STM32系列进行调整。

完整示例代码

cpp 复制代码
#include "stm32f10x.h"
#include "stm32f10x_adc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
void ADC1_Init(void) {
    ADC_InitTypeDef ADC_InitStructure;
    GPIO_InitTypeDef GPIO_InitStructure;
    // 1. 使能ADC1和GPIO端口时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);
    // 2. 配置PC.04 作为模拟输入
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
    GPIO_Init(GPIOC, &GPIO_InitStructure);
    // 3. ADC结构体初始化
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    ADC_InitStructure.ADC_ScanConvMode = DISABLE;
    ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    ADC_InitStructure.ADC_NbrOfChannel = 1;
    ADC_Init(ADC1, &ADC_InitStructure);
    // 4. 配置ADC1的通道11为顺序进行规则转换的第一个转换
    ADC_RegularChannelConfig(ADC1, ADC_Channel_14, 1, ADC_SampleTime_55Cycles5);
    // 5. 使能 ADC1
    ADC_Cmd(ADC1, ENABLE);
    // 6. 初始化ADC1的校准寄存器,并开始校准
    ADC_ResetCalibration(ADC1);
    while(ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);
    while(ADC_GetCalibrationStatus(ADC1));
    // 7. 开始转换
    ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
int main(void) {
    // 初始化ADC
    ADC1_Init();
    while (1) {
        // 检测转换结束
        while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
        // 读取ADC转换结果
        uint16_t ADC_Value = ADC_GetConversionValue(ADC1);
        // ... 使用ADC_Value进行其他操作
    }
}

这份代码是非常基础的STM32使用ADC的例子,使用标准外设库函数进行简单的ADC配置和读取。步骤如下:

  1. 使能GPIO和ADC时钟。
  2. 设置ADC使用的GPIO口为模拟输入模式。
  3. 对ADC进行基础配置,如工作模式,数据对齐方式等。
  4. 设置ADC通道,这里以通道14为例。
  5. 使能ADC并校准。
  6. 开始ADC转换。
相关推荐
yutian06061 小时前
Keil MDK下载程序后MCU自动重启设置
单片机·嵌入式硬件·keil
析木不会编程4 小时前
【小白51单片机专用教程】protues仿真独立按键控制LED
单片机·嵌入式硬件·51单片机
枯无穷肉8 小时前
stm32制作CAN适配器4--WinUsb的使用
stm32·单片机·嵌入式硬件
不过四级不改名6778 小时前
基于HAL库的stm32的can收发实验
stm32·单片机·嵌入式硬件
嵌入式科普9 小时前
十一、从0开始卷出一个新项目之瑞萨RA6M5串口DTC接收不定长
c语言·stm32·cubeide·e2studio·ra6m5·dma接收不定长
嵌入式大圣9 小时前
单片机UDP数据透传
单片机·嵌入式硬件·udp
云山工作室9 小时前
基于单片机的视力保护及身姿矫正器设计(论文+源码)
stm32·单片机·嵌入式硬件·毕业设计·毕设
嵌入式-老费9 小时前
基于海思soc的智能产品开发(mcu读保护的设置)
单片机·嵌入式硬件
qq_3975623111 小时前
MPU6050 , 设置内部低通滤波器,对于输出数据的影响。(简单实验)
单片机
liyinuo201711 小时前
嵌入式(单片机方向)面试题总结
嵌入式硬件·设计模式·面试·设计规范