本篇博文最后修改时间:2016年10月27日,12:16。
一、简介
本文介绍如何在STM32上使用ADC1的第9通道,对电池电量进行采集。
二、实验平台
库版本:STM32F10x_StdPeriph_Lib_V3.5.0
编译软件:MDK4.53
硬件平台:STM32开发板(主芯片stm32f103c8t6)
仿真器:JLINK
三、版权声明
博主:甜甜的大香瓜
声明:喝水不忘挖井人,转载请注明出处。
原文地址:http://blog.csdn.NET/feilusia
联系方式:897503845@qq.com
香瓜BLE之CC2541群:127442605
香瓜BLE之CC2640群:557278427
四、硬件原理
1)硬件原理图
由上图可知通过PB1口采集电压,其中采集的电压为锂电池经过分压后的电压。
锂电池电压范围为3V~4.2V。
2)采集电压引脚的通道
其中ADC12_IN9,是指可以是ADC1的第9通道,也可以是ADC2的第9通道。
五、基础知识
1、stm32f103c8t6的ADC是如何的?
答:
stm32f103c8t6这款芯片一共有2个ADC,每个ADC有18个通道,每个通道有12bit。
1、编写ADC的驱动
1)编写驱动GUA_ADC1.c(存放在“……\HARDWARE”)
//****************************************************************************** //name: GUA_ADC1.c //introduce: ADC1驱动 //author: 甜甜的大香瓜 //email: 897503845@qq.com //QQ group 香瓜单片机之STM8/STM32(164311667) //changetime: 2016.12.29 //****************************************************************************** #include "stm32f10x.h" #include "GUA_ADC1.h" /*********************内部函数声明************************/ static GUA_U16 GUA_ADC1_Read(GUA_U8 nGUA_Channel); //****************************************************************************** //name: GUA_ADC1_Read //introduce: ADC1的通道数值读取 //parameter: nGUA_Channel:ADC1的采集通道 //return: 该通道采集的数值 //author: 甜甜的大香瓜 //email: 897503845@qq.com //QQ group 香瓜单片机之STM8/STM32(164311667) //changetime: 2016.12.29 //****************************************************************************** static GUA_U16 GUA_ADC1_Read(GUA_U8 nGUA_Channel) { //规则采样顺序值为1,采样时间为 239.5 周期 ADC_RegularChannelConfig(ADC1, nGUA_Channel, 1, ADC_SampleTime_239Cycles5); //开始转换 ADC_SoftwareStartConvCmd(ADC1, ENABLE); //等待转换结束 while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); //返回转换结果 return ADC_GetConversionValue(ADC1); } //****************************************************************************** //name: GUA_ADC1_ReadAverage //introduce: ADC1的通道数值读取 //parameter: nGUA_Channel:ADC1的采集通道 // nGUA_times:求平均值的次数 //return: 该通道采集的数值 //author: 甜甜的大香瓜 //email: 897503845@qq.com //QQ group 香瓜单片机之STM8/STM32(164311667) //changetime: 2016.12.29 //****************************************************************************** GUA_U16 GUA_ADC1_ReadAverage(GUA_U8 nGUA_Channel, GUA_U8 nGUA_times) { GUA_U32 nGUA_Value_Sum = 0; GUA_U8 i; //累加读取到的数值 for(i = 0; i < nGUA_times; i++) { nGUA_Value_Sum += GUA_ADC1_Read(nGUA_Channel); } //求出平均值并返回 return nGUA_Value_Sum/nGUA_times; } //****************************************************************************** //name: GUA_ADC1_Init //introduce: ADC1初始化 //parameter: none //return: none //author: 甜甜的大香瓜 //email: 897503845@qq.com //QQ group 香瓜单片机之STM8/STM32(164311667) //changetime: 2016.12.29 //****************************************************************************** void GUA_ADC1_Init(void) { ADC_InitTypeDef ADC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; //开GPIOB、ADC1时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_ADC1, ENABLE); //ADC最大频率不能超过14M,否则不准,因此使用72M/6=12M RCC_ADCCLKConfig(RCC_PCLK2_Div6); //IO初始化 GPIO_InitStructure.GPIO_Pin =GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOB, &GPIO_InitStructure); //ADC1配置复位 ADC_DeInit(ADC1); //ADC1配置 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通道的数目 ADC_Init(ADC1, &ADC_InitStructure); //初始化配置 //使能 ADC_Cmd(ADC1, ENABLE); //校准 ADC_ResetCalibration(ADC1); //开启复位校准 while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束 ADC_StartCalibration(ADC1); //开启AD校准 while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束 }
2) 编写驱动头文件 GUA_ADC1.h(存放在“ …… \HARDWARE ”)
//****************************************************************************** //name: GUA_ADC1.h //introduce: ADC1驱动的头文件 //author: 甜甜的大香瓜 //email: 897503845@qq.com //QQ group 香瓜单片机之STM8/STM32(164311667) //changetime: 2016.12.29 //****************************************************************************** #ifndef _GUA_ADC1_H_ #define _GUA_ADC1_H_ /*********************宏定义************************/ #ifndef GUA_U8 typedef unsigned char GUA_U8; #endif #ifndef GUA_8 typedef signed char GUA_8; #endif #ifndef GUA_U16 typedef unsigned short GUA_U16; #endif #ifndef GUA_16 typedef signed short GUA_16; #endif #ifndef GUA_U32 typedef unsigned long GUA_U32; #endif #ifndef GUA_32 typedef signed long GUA_32; #endif #ifndef GUA_U64 typedef unsigned long long GUA_U64; #endif #ifndef GUA_64 typedef signed long long GUA_64; #endif /*********************外部函数************************/ extern GUA_U16 GUA_ADC1_ReadAverage(GUA_U8 nGUA_Channel, GUA_U8 nGUA_times); extern void GUA_ADC1_Init(void); #endif
2、编写电量采集的驱动
1)编写驱动GUA_Battery_Check.c(存放在“……\HARDWARE”)
//****************************************************************************** //name: GUA_Battery_Check.c //introduce: 电量检测驱动 //author: 甜甜的大香瓜 //email: 897503845@qq.com //QQ group 香瓜单片机之STM8/STM32(164311667) //changetime: 2016.12.28 //****************************************************************************** #include "stm32f10x.h" #include "GUA_ADC1.h" #include "GUA_Battery_Check.h" /*********************宏定义************************/ #define GUA_BATTERY_CHECK_COUNT_PER_COLLECT 5 //每次采集的次数 //****************************************************************************** //name: GUA_Battery_Check_Read //introduce: 读电量 //parameter: none //return: 返回16bit的电量,右对齐 //author: 甜甜的大香瓜 //email: 897503845@qq.com //QQ group 香瓜单片机之STM8/STM32(164311667) //changetime: 2016.12.28 //****************************************************************************** GUA_U16 GUA_Battery_Check_Read(void) { GUA_U16 nGUA_Battery_Check_Value = 0; GUA_U16 nGUA_Num = 0; //采集BATTERY_CHECK_COUNT_PER_COLLECT次,累加采集的电量值 for(nGUA_Num = 0; nGUA_Num < GUA_BATTERY_CHECK_COUNT_PER_COLLECT; nGUA_Num++) { //累加读取adc的转换值 nGUA_Battery_Check_Value += GUA_ADC1_ReadAverage(ADC_Channel_9, 1); } //求出电量平均值 nGUA_Battery_Check_Value /= GUA_BATTERY_CHECK_COUNT_PER_COLLECT; //返回 return nGUA_Battery_Check_Value; } //****************************************************************************** //name: GUA_Battery_Check_Init //introduce: 电量检测初始化 //parameter: none //return: none //author: 甜甜的大香瓜 //email: 897503845@qq.com //QQ group 香瓜单片机之STM8/STM32(164311667) //changetime: 2016.12.28 //****************************************************************************** void GUA_Battery_Check_Init(void) { //ADC1初始化 GUA_ADC1_Init(); }
2) 编写驱动头文件GUA_ Battery_Check.h(存放在“ …… \HARDWARE ”)
//****************************************************************************** //name: GUA_Battery_Check.h //introduce: 电量检测的头文件 //author: 甜甜的大香瓜 //email: 897503845@qq.com //QQ group 香瓜单片机之STM8/STM32(164311667) //changetime: 2016.12.28 //****************************************************************************** #ifndef _GUA_BATTERY_CHECK_H_ #define _GUA_BATTERY_CHECK_H_ /*********************宏定义************************/ #ifndef GUA_U8 typedef unsigned char GUA_U8; #endif #ifndef GUA_8 typedef signed char GUA_8; #endif #ifndef GUA_U16 typedef unsigned short GUA_U16; #endif #ifndef GUA_16 typedef signed short GUA_16; #endif #ifndef GUA_U32 typedef unsigned long GUA_U32; #endif #ifndef GUA_32 typedef signed long GUA_32; #endif #ifndef GUA_U64 typedef unsigned long long GUA_U64; #endif #ifndef GUA_64 typedef signed long long GUA_64; #endif /*********************外部函数声明************************/ GUA_U16 GUA_Battery_Check_Read(void); void GUA_Battery_Check_Init(void); #endif
3、工程中添加自己写的驱动
1)工程中添加GUA_ADC1.c和GUA_Battery_Check.c
2)在MDK设置中添加驱动源文件路径
4、添加库的驱动
1)添加库的驱动文件
2)添加库的驱动头文件(stm32f10x_conf.h 中)
#include "stm32f10x_adc.h"
5、在应用层中调用
1)添加驱动头文件(main.c中)
#include "GUA_Battery_Check.h"
2) 添加驱动初始化代码(main.c的main函数中)
//电源电量采集 GUA_Battery_Check_Init();
3)添加测试代码
①写测试代码(main.c中)
//****************************************************************************** //name: GUA_Test //introduce: 测试代码 //parameter: none //return: none //author: 甜甜的大香瓜 //email: 897503845@qq.com //QQ group 香瓜单片机之STM8/STM32(164311667) //changetime: 2016.12.29 //****************************************************************************** static void GUA_Test(void) { U16 nGUA_Battery_Check_Value = 0; while(1) { //读取电量 nGUA_Battery_Check_Value = GUA_Battery_Check_Read(); } }
②调用测试代码 ( main.c的main函数中 )
//测试代码 GUA_Test();
七、实验结果
仿真并查看测试代码中电量读取情况,如下图
上图可知读取到的电量数值为2760,由于adc的精度是12bit(4096)、参考电压为3.3V,因此实际读出的电量值为2760*3.3/4096=2.2236328125V
由于该采集电压是经过分压后的,代入公式“Vbat*75/(51+75)=2.2236328125”后,可计算出Vbat=3.735703125V。
用万用表实测锂电池电压为3.7V(200V档)。
因此实验成功。