【STM32】STM32之电量采集

时间:2022-08-06 14:42:18

本篇博文最后修改时间: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

香瓜BLE之Android群:541462902

香瓜单片机之STM8/STM32群:164311667
甜甜的大香瓜的小店(淘宝店):https://shop217632629.taobao.com/?spm=2013.1.1000126.d21.hd2o8i

四、硬件原理

1)硬件原理图

【STM32】STM32之电量采集

【STM32】STM32之电量采集

由上图可知通过PB1口采集电压,其中采集的电压为锂电池经过分压后的电压。

锂电池电压范围为3V~4.2V。


2)采集电压引脚的通道

【STM32】STM32之电量采集

其中ADC12_IN9,是指可以是ADC1的第9通道,也可以是ADC2的第9通道。


五、基础知识

1、stm32f103c8t6的ADC是如何的?

答:

stm32f103c8t6这款芯片一共有2个ADC,每个ADC有18个通道,每个通道有12bit。

最大的转换速率为1MHz(转换时间1us),时钟不要超过14M,否则准确度会下降。

2、什么是规则通道组和注入通道组?
答:规则通道组是普通的ADC组,而注入通道组具有优先级更高的抢占式权利,能随时打断规则通道组的ADC通道,获得ADC转换的优先权。
类似于我们在买票时,规则通道组是普通老百姓,而注入通道组是老人、军人,他们可以任意插队……

六、实验步骤

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

【STM32】STM32之电量采集


2)在MDK设置中添加驱动源文件路径

【STM32】STM32之电量采集


4、添加库的驱动

1)添加库的驱动文件

【STM32】STM32之电量采集


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();

七、实验结果

仿真并查看测试代码中电量读取情况,如下图

【STM32】STM32之电量采集

上图可知读取到的电量数值为2760,由于adc的精度是12bit(4096)、参考电压为3.3V,因此实际读出的电量值为2760*3.3/4096=2.2236328125V

由于该采集电压是经过分压后的,代入公式“Vbat*75/(51+75)=2.2236328125”后,可计算出Vbat=3.735703125V。

用万用表实测锂电池电压为3.7V(200V档)。

因此实验成功。