1. ADC核心特性
分辨率:12位,输出范围 0~4095。
转换速率:最高 1 MSPS(ADC时钟为14MHz时,转换时间约1μs)。
输入通道:
16个外部通道(实际可用数量受芯片引脚限制,例如PA0-PA7、PB0-PB1等)。
2个内部通道:温度传感器(通道16)和内部参考电压 VREFINT(通道17)。
工作模式:
单次/连续转换:单次模式下只转换一次,连续模式下自动重启转换。
扫描模式:自动按顺序转换一组预配置的通道。
间断模式:通过触发信号分段转换通道。
触发源:
软件触发、定时器触发、外部中断(如EXTI)。
数据对齐:
右对齐(默认,结果直接为 0~4095)或左对齐(便于快速计算)。
参考电压:
由 VDDA 和 VSSA 引脚提供,需稳定电源(通常接3.3V和GND)。
2. 关键配置选项
规则组与注入组:
规则组:用于常规转换,支持多通道扫描。
注入组:可打断规则组转换,支持高优先级任务。
校准:
上电后需执行校准以减小误差(HAL库自动处理,寄存器操作需手动校准)。
模拟看门狗:
可设置阈值范围,超出范围时触发中断。
3.上代码,复制可用,想修改数据的看代码下面的关键代码解析,根据介绍修改函数参数即可。
/* 头文件包含 */
#include "stm32f10x.h" // 标准外设库
#include "stm32f10x_gpio.h" // GPIO库
#include "stm32f10x_adc.h" // ADC库
#include "stm32f10x_dma.h" // DMA库
#include "stm32f10x_rcc.h" // 时钟库
/* 全局变量定义 */
#define ADC1_DR_Address ((uint32_t)0x4001244C) // ADC1数据寄存器地址
uint16_t adc_dma_buffer[3]; // 存储3个通道ADC值的数组
/* 系统时钟配置 */
void RCC_Configuration(void)
{
// 1. 使能外部高速时钟(HSE)
RCC_HSEConfig(RCC_HSE_ON); // 开启外部晶振
while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET); // 等待HSE就绪
// 2. 配置PLL(倍频至72MHz)
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9); // HSE不分频,9倍频(8MHz*9=72MHz)
// 3. 启动PLL并等待就绪
RCC_PLLCmd(ENABLE);
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
// 4. 切换系统时钟源到PLL
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
while(RCC_GetSYSCLKSource() != 0x08); // 等待时钟切换完成
// 5. 配置外设总线时钟
RCC_HCLKConfig(RCC_SYSCLK_Div1); // AHB时钟72MHz
RCC_PCLK1Config(RCC_HCLK_Div2); // APB1时钟36MHz
RCC_PCLK2Config(RCC_HCLK_Div1); // APB2时钟72MHz
}
/* ADC1单通道初始化(PA1) */
void ADC1_Single_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
// 1. 使能GPIOA和ADC1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
// 2. 配置PA1为模拟输入模式
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; // 模拟输入模式
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 3. 配置ADC参数
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; // 独立模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE; // 单通道禁用扫描
ADC_InitStructure.ADC_ContinuousConvMode = 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);
// 4. 配置通道1(PA1)的采样时间
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5); // 55.5周期采样
// 5. 开启ADC并校准
ADC_Cmd(ADC1, ENABLE); // 使能ADC
ADC_ResetCalibration(ADC1); // 复位校准寄存器
while(ADC_GetResetCalibrationStatus(ADC1)); // 等待复位完成
ADC_StartCalibration(ADC1); // 开始校准
while(ADC_GetCalibrationStatus(ADC1)); // 等待校准完成
}
/* ADC1多通道DMA初始化(PA0,PA1,PA2) */
void ADC1_DMA_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
DMA_InitTypeDef DMA_InitStructure;
// 1. 使能GPIOA、ADC1和DMA1时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC1, ENABLE);
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
// 2. 配置PA0-PA2为模拟输入
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(GPIOA, &GPIO_InitStructure);
// 3. 配置DMA通道1(ADC1规则组)
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; // 外设地址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)adc_dma_buffer; // 内存地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // 外设到内存
DMA_InitStructure.DMA_BufferSize = 3; // 传输数据量
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;
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. 配置ADC多通道参数
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
ADC_InitStructure.ADC_ScanConvMode = ENABLE; // 启用扫描模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; // 连续转换模式
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStructure.ADC_NbrOfChannel = 3; // 3个通道
ADC_Init(ADC1, &ADC_InitStructure);
// 5. 配置各通道顺序和采样时间
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); // PA0
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2, ADC_SampleTime_55Cycles5); // PA1
ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3, ADC_SampleTime_55Cycles5); // PA2
// 6. 开启DMA和ADC
DMA_Cmd(DMA1_Channel1, ENABLE); // 使能DMA
ADC_DMACmd(ADC1, ENABLE); // ADC启用DMA传输
ADC_Cmd(ADC1, ENABLE); // 使能ADC
// 7. ADC校准
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
// 8. 启动连续转换
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
}
/* 单通道ADC读取函数 */
uint16_t ADC_ReadSingleChannel(void)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE); // 启动转换
while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); // 等待转换完成
return ADC_GetConversionValue(ADC1); // 返回转换结果
}
/* 主函数 */
int main(void)
{
// 1. 系统初始化
RCC_Configuration(); // 配置系统时钟
ADC1_Single_Init(); // 初始化单通道ADC
// ADC1_DMA_Init(); // 如果需要多通道DMA,取消注释
while(1)
{
// 2. 单通道读取示例
uint16_t adc_value = ADC_ReadSingleChannel(); // 读取PA1电压值
// 3. 多通道DMA数据访问(数据在adc_dma_buffer数组中)
// 例如:
// uint16_t ch0 = adc_dma_buffer[0]; // PA0
// uint16_t ch1 = adc_dma_buffer[1]; // PA1
// uint16_t ch2 = adc_dma_buffer[2]; // PA2
// 4. 添加用户处理代码(例如电压转换)
// float voltage = (adc_value / 4095.0) * 3.3;
}
}
-------------------------------------------------------我是分割线---------------------------------------------------------
4.关键代码逐行解析
1. 系统时钟配置
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
将外部8MHz晶振作为PLL输入(不分频),9倍频后得到72MHz系统时钟
2. ADC单通道初始化
ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 1, ADC_SampleTime_55Cycles5);
参数说明:
ADC1: 选择ADC1外设
ADC_Channel_1: 使用通道1(对应PA1)
1: 规则组转换序列中的第1个位置
ADC_SampleTime_55Cycles5: 采样时间为55.5个ADC时钟周期
3. DMA配置
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
循环模式:当DMA传输完成指定数量的数据后,自动重新开始传输
4. 多通道配置
ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);
规则组转换顺序:
第1个转换:通道0(PA0)
第2个转换:通道1(PA1)
第3个转换:通道2(PA2)
5. 启动转换
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
软件触发启动ADC转换
在连续模式下只需调用一次即可持续转换
6.使用场景说明
单通道模式:
适用于需要精确控制采样时机的场景(如按键触发采样)
典型应用:电池电压检测、电位器读取
多通道DMA模式:
适用于需要同时监测多个传感器的场景
典型应用:
三相电压监测
多路温度传感器采集
工业控制中的多参数采集
7.注意事项
电源稳定性:
// 建议在VDDA和VSSA之间并联10uF+0.1uF电容
采样时间计算:
总转换时间 = 采样时间 + 12.5周期
当ADC时钟为12MHz时,55.5周期对应:tconv=(55.5+12.5)/12MHz≈5.67μs
数据对齐:
// 若使用左对齐,数据寄存器高12位有效
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Left;
内部参考电压:
// 读取VREFINT(通道17)可计算实际VDDA电压
ADC_RegularChannelConfig(ADC1, ADC_Channel_17, 1, ADC_SampleTime_239Cycles5);
中断使用:
// 添加转换完成中断
ADC_ITConfig(ADC1, ADC_IT_EOC, ENABLE);
NVIC_EnableIRQ(ADC1_2_IRQn);
————————————————
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/haoyangyun/article/details/145938483
|
|