STM32F103C8T6电压测量

目录

一、前言:

二、硬件接线:

三、STM32F103C8T6中ADC的时钟树以及内部结构框图

四、STM32F103C8T6中的两个10路的ADC

规则组四个模式

规则组测ADC编程思路

五、注入组测ADC编程思路​编辑

六、最终效果:


一、前言:

学习笔记!!!

参考:视频B站铁头山羊2.1.【电池】使用ADC采集电池电压(1)_哔哩哔哩_bilibili
                  B站江科大STM32[7-1] ADC模数转换器_哔哩哔哩_bilibili

二、硬件接线:

解释:12V电压输入为3节串联的18650(理论最大电压为4.2V*3=12.6V),经过电阻串联分压到单片机PB1(ADC9)引脚可接受的电压(3.3V内),测量R3上的电压间接测量,理论最大为10/(20+20+10)*12.6 = 2.52V经过线性标定即可反推电池电压。

三、STM32F103C8T6中ADC的时钟树以及内部结构框图

部分介绍:内部18个通道:16个IO口+1个温度传感器+VREFINT内部参考电压,进入到模拟多路开关再进入到模数转换器,即逐次比较的过程。转换的12位数据结果会放置到16位数据寄存器里,读取即可获得转换值。

  • 触发ADC转换的信号:①软件触发,在程序中调用一条代码,就可以启动转换了。②硬件触发,就是这里的这些触发源(EXTI_11/EXTI15开始连接的两控制器)。

  • 参考电压:芯片的VDDA和VSSA在电路中默认接了VREF,因此没有VREF±引脚。同电源0~3.3V

  • ADCCLK:来源于外设总线预分频器,最大14MHz,因此把时钟源分频时候不能弄超了。

  • 数据寄存器:存数据,DMA数据搬运

注意转换可以多通道进行,并且分成了规则/注入两个通道组。

四、STM32F103C8T6中的两个10路的ADC


ADC12_IN0的意思是ADC1和ADC2的IN0都是在PA0上的,即引脚全都是相同的。因此ADC1和ADC2可以同时运行,即双ADC模式。比如可以配合组成同步或者交叉运行(对着一个通道交叉的采样,增大采样的频率)。

规则组四个模式

参数:单次/连续、扫描/非扫描,不细述

规则组测ADC编程思路(单次、非扫描)

  1. 开启时钟,开启ADC1和GPIOB1的时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //开启ADC1的时钟(PA0的ADC1)
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //开启GPIOA的时钟(模拟输入)
  1. 设置ADC时钟分频
    RCC_ADCCLKConfig(RCC_PCLK2_Div6); //选择时钟6分频,ADCCLK = 72MHz / 6 = 12MHz

  2. GPIO初始化
    GPIO_InitTypeDef GPIO_InitStructure;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //GPIO 无效
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure); //将PA0引脚初始化为模拟输入

  3. 规则组通道配置

    ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5); //规则组序列1的位置,PA0的ADC1配置为通道0,采样时间越大,转换越慢越稳定反之则反,ADC_SampleTime_55Cycles5表示55.5个采样周期

    若还要加入其它通道则:ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 2, ADC_SampleTime_55Cycles5); //规则组序列2的位置,配置通道3

  4. ADC初始化
    ADC_InitTypeDef ADC_InitStructure; //定义结构体变量
    ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //模式,选择独立模式,即单独使用ADC1
    ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据对齐,选择右对齐
    ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//外部触发源,使用软件触发,不需要外部触发
    ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //连续转换,失能,每转换一次规则组序列后停止(即单次模式)//ENABLE,连续转换
    ADC_InitStructure.ADC_ScanConvMode = DISABLE; //扫描模式,失能,只转换规则组的序列1这一个位置(即非扫描模式单通道)
    ADC_InitStructure.ADC_NbrOfChannel = 1; //通道数,为1,仅在扫描模式下,才需要指定大于1的数,在非扫描模式下,只能是1
    ADC_Init(ADC1, &ADC_InitStructure); //将结构体变量交给ADC_Init,配置ADC1

  5. ADC使能
    ADC_Cmd(ADC1, ENABLE); //使能ADC1,ADC开始运行

  6. ADC校准
    ADC_ResetCalibration(ADC1);//复位校准 //固定流程,内部有电路会自动执行校准
    while (ADC_GetResetCalibrationStatus(ADC1) == SET); //等待复位校准完成(会自动清0)
    ADC_StartCalibration(ADC1); //开始校准
    while (ADC_GetCalibrationStatus(ADC1) == SET); //等待开始校准完成

    (ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件触发AD转换一次,若设置为连续转换则放在这里)

  7. 触发ADC

    单次非扫描模式软件触发

    uint16_t AD_GetValue(void)
    {
    ADC_SoftwareStartConvCmd(ADC1, ENABLE); //软件触发AD转换一次
    while (ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET); //等待EOC标志位完成,即等待AD转换结束(读取ADC_DR时会自动复位)规则组转换完成标志位:ADC_FLAG_EOC

    等待时间= 5.6us

    采样周期(刚刚设置的55.5)+固定的转换周期12.5 =68个周期

    68个周期 ÷ 【72(主频) ÷ 6(分频)】=5.6us

    return ADC_GetConversionValue(ADC1); //读数据寄存器(EOC复位),得到AD转换的结果
    }

    连续非扫描模式软件触发只需要触发一次,且由于连续触发不需要看EOC标志位完成

五、注入组测ADC编程思路(单次、非扫描)

我这里是使用1ms定时器2结合定时器2的中断函数累计10次后(10ms)再软件触发ADC中断采样,当然这样子是多余的操作,这里同时学习一下定时器中断

.1 硬件初始化配置

  • TIM2定时器配置

    • 时钟源:APB1总线时钟(默认72MHz)。
    • 预分频器(PSC):设置为1,分频后时钟为36MHz(72MHz / (1+1) = 36MHz)。
    • 自动重装载值(ARR):设置为36000-1,使TIM2每1ms产生一次更新中断(36,000 / 36MHz = 1ms)。
    • 中断配置:使能更新中断,设置抢占优先级为1,子优先级为1。
  • ADC1配置

    • 时钟分频:ADC时钟配置为12MHz(72MHz / 6)。
    • GPIO配置:PB1引脚设为模拟输入模式(ADC通道9)。
    • 注入通道设置:单次转换模式,采样时间7.5个时钟周期(约0.625μs)。
    • 中断配置:使能注入转换完成中断(JEOC),抢占优先级0(最高),子优先级2。

2. 中断服务逻辑

  • TIM2中断(TIM2_IRQHandler)

    • 每1ms触发一次,累计10次后(10ms)软件触发ADC注入转换。
    • 清除中断标志,避免重复触发。
  • ADC中断(ADC1_2_IRQHandler)

    • 读取注入通道的ADC值,存入环形缓冲区adc_buffer
    • 当缓冲区填满(FILTER_WINDOW_SIZE=10)时,置位filter_ready标志。

3. 数据采集与滤波处理(可有可无)

  • 缓冲区管理
    • 使用adc_buffer存储最近10次ADC采样值,索引buffer_index循环更新。
  • 混合滤波算法(Hybrid_Filter)
    1. 数据复制:将缓冲区数据复制到临时数组,避免操作原始数据。
    2. 中值滤波冒泡排序临时数组,剔除最高和最低的25%数据(即保留中间50%)。
    3. 移动平均:对保留的数据计算平均值,进一步平滑噪声。
    • 输出:返回滤波后的ADC值,提高数据稳定性。

4. 电压计算与校准

  • 公式转换

    • 滤波后的ADC值转换为电压: Vbat=(filtered_adc4095×3.3V×5)−0.22VVbat=(4095filtered_adc​×3.3V×5)−0.22V
    • 分压比:硬件采用5:1分压(例如16.5V电池分压后为3.3V)。
    • 误差校准:减去0.22V补偿硬件偏差。
  • 数据获取

    • 主循环中检查filter_ready标志,触发滤波计算并更新Vbat

六、最终效果:

没插STlink的时候为12.18V,插了或者是直接拿电压表测是11.96V,不知道啥原因,所以我直接用最简单的方法减去0.22V补偿硬件偏差。

添加效果:电池电量显示

代码在:亿只搞学习的空大白/STM32F103C8T6平衡车

电源电压变化缓慢,实测两种效果差不多,但是第二种方法操作性多且采样时间一定,受主程序影响小,但是难度也高。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值