模拟数字转换器(ADC)
1. ADC 概述
- ADC(Analog-to-Digital Converter) 是一种将模拟信号转换为数字信号的装置。它可以将连续变化的模拟电压转化为微控制器可处理的数字量,方便对模拟信号进行采集和分析。
- STM32F103 系列微控制器内置了多通道、高精度的 ADC,支持多种触发方式和工作模式,适用于各种模拟信号的采集需求。
ADC 的主要特点:
- 高分辨率:12 位分辨率,可将输入电压细分为 4096 个等级。
- 多通道:提供多达 16 个通道,可同时采集多个模拟信号。
- 多种转换模式:支持单次、连续、扫描、间断等模式,灵活满足不同应用需求。
- 触发方式多样:支持软件触发和外部触发,包括定时器、中断等。
- 支持 DMA:可与 DMA 配合,实现高速数据传输,减轻 CPU 负担。
2. ADC 配置步骤
在 STM32F103 中使用 ADC 时,一般按照以下步骤进行配置:
1. 使能 ADC 和 GPIO 时钟
首先,需要开启 ADC 和对应 GPIO 端口的时钟。
// 使能 ADC1 和 GPIOA 时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
2. 配置 GPIO 引脚为模拟输入模式
将用于 ADC 输入的 GPIO 引脚配置为模拟输入模式。
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; // 选择 PA1 引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // 模拟输入模式
GPIO_Init(GPIOA, &GPIO_InitStructure);
3. 初始化 ADC
设置 ADC 的工作模式、数据对齐方式、转换模式等参数。
ADC_InitTypeDef ADC_InitStructure;
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; // 转换通道数为 1
ADC_Init(ADC1, &ADC_InitStructure);
4. 配置 ADC 通道和采样时间
指定要转换的通道,并设置采样时间。
// 配置 ADC1 的通道 1,采样时间为 55.5 周期
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);
5. 启用 ADC
在完成上述配置后,启用 ADC。
ADC_Cmd(ADC1, ENABLE);
6. 校准 ADC
在使用 ADC 前,需要进行校准以提高转换精度。
// 复位校准
ADC_ResetCalibration(ADC1);
// 等待复位完成
while (ADC_GetResetCalibrationStatus(ADC1));
// 开始校准
ADC_StartCalibration(ADC1);
// 等待校准完成
while (ADC_GetCalibrationStatus(ADC1));
7. 启动 ADC 转换
// 启动 ADC 软件转换
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
3. 示例:读取电位器的模拟电压
以下示例演示如何使用 ADC1 读取连接在 PA1 引脚的电位器电压值。
ADC 初始化函数
void ADC1_Init(void) {
// 1. 使能时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
// 2. 配置 PA1 为模拟输入
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // 模拟输入模式
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 3. 初始化 ADC
ADC_InitTypeDef ADC_InitStructure;
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; // 通道数为 1
ADC_Init(ADC1, &ADC_InitStructure);
// 4. 配置 ADC 通道
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);
// 5. 启用 ADC
ADC_Cmd(ADC1, ENABLE);
// 6. 复位校准
ADC_ResetCalibration(ADC1);
while (ADC_GetResetCalibrationStatus(ADC1));
// 7. 开始校准
ADC_StartCalibration(ADC1);
while (ADC_GetCalibrationStatus(ADC1));
// 8. 启动转换
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
获取 ADC 转换值
uint16_t ADC1_GetValue(void) {
// 等待转换完成
while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);
// 返回转换结果
return ADC_GetConversionValue(ADC1);
}
主函数示例
int main(void) {
uint16_t adc_value;
float voltage;
ADC1_Init(); // 初始化 ADC1
while (1) {
adc_value = ADC1_GetValue(); // 获取 ADC 转换值
voltage = adc_value * (3.3 / 4096); // 计算电压值(假设参考电压 3.3V)
// 可将电压值通过串口发送或显示在屏幕上
}
}
4. 注意事项
- 参考电压稳定性:ADC 的精度受参考电压影响,确保参考电压稳定,避免噪声干扰。
- 采样时间选择:根据输入信号源阻抗选择适当的采样时间,阻抗越高,采样时间应越长。
- 通道配置:在多通道转换时,需要正确配置每个通道的顺序和采样时间。
- 校准重要性:定期校准 ADC,可提高转换精度,特别是在温度变化较大的环境中。
5. 扩展:使用 DMA 提高数据采集效率
当需要高速采集大量数据时,可使用 DMA(直接存储器访问)将 ADC 转换结果直接存储到内存,降低 CPU 负担。
DMA 配置示例
void ADC1_DMA_Config(void) {
uint16_t ADC_Buffer[10]; // 定义缓冲区
// 1. 使能 DMA、ADC 和 GPIO 时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
// 2. 配置 GPIO 和 ADC(同之前步骤)
// 3. 配置 DMA
DMA_InitTypeDef DMA_InitStructure;
DMA_DeInit(DMA1_Channel1); // ADC1 使用 DMA1 通道1
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR; // ADC 数据寄存器地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_Buffer; // 缓冲区地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // 外设作为数据源
DMA_InitStructure.DMA_BufferSize = 10; // 缓冲区大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址不增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存地址自增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 16 位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // 16 位
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 循环模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High; // 高优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 非内存到内存
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
// 4. 启用 DMA
DMA_Cmd(DMA1_Channel1, ENABLE);
// 5. 配置 ADC
ADC_InitTypeDef ADC_InitStructure;
// ...(与之前相同的 ADC 初始化步骤)
ADC_DMACmd(ADC1, ENABLE); // 启用 ADC 的 DMA 功能
// 6. 复位和校准 ADC(同之前步骤)
// 7. 启动 ADC 转换(同之前步骤)
}
Comments NOTHING