STM32F103C8 AD采样
/*初始化ADC1 */
void ADC1_Init(void)
{//开启时钟GPIO_InitTypeDef GPIO_InitStructure;ADC_InitTypeDef ADC_InitStructure; //定义结构体变量RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //开启ADC1的时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //开启GPIOA的时钟//设置ADC时钟RCC_ADCCLKConfig(RCC_PCLK2_Div6); //选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz//GPIO初始化GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 ;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure); //将PA0、PA1、PA2和PA3引脚初始化为模拟输入//ADC初始化ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //模式,选择独立模式,即单独使用ADC1ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐,选择右对齐ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //外部触发,使用软件触发,不需要外部触发ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //连续转换,失能,每转换一次规则组序列后停止ADC_InitStructure.ADC_ScanConvMode = DISABLE; //扫描模式,失能,只转换规则组的序列1这一个位置ADC_InitStructure.ADC_NbrOfChannel = 1; //通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1ADC_Init(ADC1, &ADC_InitStructure); //将结构体变量交给ADC_Init,配置ADC1// 5. 配置 ADC 通道和采样时间(关键!)//不在此处配置规则组序列,而是在每次AD转换前配置,这样可以灵活更改AD转换的通道//ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);//ADC使能ADC_Cmd(ADC1, ENABLE); //使能ADC1,ADC开始运行/*ADC校准*/ADC_ResetCalibration(ADC1); //固定流程,内部有电路会自动执行校准while (ADC_GetResetCalibrationStatus(ADC1) == SET);ADC_StartCalibration(ADC1);while (ADC_GetCalibrationStatus(ADC1) == SET);
}//获取AD转换的值
uint16_t AD_GetValue(uint8_t ADC_Channel)
{uint32_t timeout = 1000; // 超时计数器(避免死循环)uint16_t adc_value = 0;// 1. 参数校验(可选)if (ADC_Channel > 17) return 0; // STM32F103C8 最大通道号为 17(如 ADC_Channel_17)// 2. 配置通道和采样时间(根据需求调整)ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_239Cycles5);// 3. 启动转换并等待结果(带超时机制)ADC_SoftwareStartConvCmd(ADC1, ENABLE);while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) && timeout--);if (timeout == 0) return 0; // 超时处理// 4. 读取结果并清除标志位adc_value = ADC_GetConversionValue(ADC1);ADC_ClearFlag(ADC1, ADC_FLAG_EOC); // 清除标志位return adc_value;
}#define VREF 3.25f // 根据实际参考电压调整/*实测AD点电压=1.56V*/
/*VPA0≈1.603V*/
uint8_t Calculate_VCC() {uint32_t adcV = 0; // 初始化累加器uint16_t AD_valueV;float tempf1 = 0;int i = 0;uint8_t ya = 0;// 1. 采样10次取平均for(i=0; i<10; i++) {AD_valueV = AD_GetValue(ADC_Channel_0);if (AD_valueV == 0) continue; // 跳过错误值adcV += AD_valueV;delayms(10);}// 2. 计算电压(合并公式)tempf1 = (adcV / 10.0f) * VREF * 11 / 4095; // VCC = (ADC_avg × 3.3 × 11) / 4095//3. 加入两个二极管压降(0.3*2= 0.6V),硬件设计tempf1 = tempf1 + 0.6;// 4. 四舍五入并放大10倍ya = (uint8_t)((int)(tempf1 * 10.0f + 0.5f)); // 手动四舍五入// 4. 存储结果//pkt.voltage_x10 = ya;return ya;
}
如果采样出来的值有误差:
1. 考虑电阻的精度
2. 考虑参考电压,要校准参考电压
电阻的精度的检查:
实测AD点电压=1.56V
计算理论电压值:VPA0≈1.603V,如果两个值差的多了,换高精度的电阻。
STM32F103芯片内置了1-3个12位逐次逼近型模数转换器(ADC),下面是其ADC采样的详细过程:
1. ADC基本特性
-
12位分辨率
-
转换时间:1μs(在56MHz ADC时钟下)
-
多达18个复用通道(16个外部通道+2个内部通道)
-
单次或连续转换模式
-
扫描模式
-
数据对齐方式可选(左对齐或右对齐)
-
模拟看门狗功能
2. ADC采样过程步骤
2.1 初始化配置
2.2 采样过程
-
通道选择:通过ADC_SQRx或ADC_JSQRx寄存器选择要转换的通道
-
采样时间配置:通过ADC_SMPRx寄存器设置每个通道的采样时间
-
触发转换:软件触发或硬件触发
-
采样保持:在采样时间内保持输入信号稳定
-
逐次逼近转换:12位转换过程
-
数据存储:转换结果存入ADC_DR寄存器
3. 关键参数说明
3.1 采样时间
STM32F103的ADC采样时间可配置为:
-
1.5周期
-
7.5周期
-
13.5周期
-
28.5周期
-
41.5周期
-
55.5周期
-
71.5周期
-
239.5周期
采样时间 = (设置值 + 12.5)个ADC时钟周期
3.2 时钟配置
ADC时钟最大为14MHz,通常由APB2时钟分频得到:
4. 注意事项
-
首次上电后需要等待一段时间再校准
-
输入信号阻抗应足够低以满足采样要求
-
注意参考电压的稳定性
-
模拟输入电压范围:0-VREF+
-
转换期间应避免频繁操作相关寄存器
通过以上配置和步骤,STM32F103可以有效地完成模拟信号的数字化转换。