【STM32】STM32之电量采集

本篇博文最后修改时间: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)硬件原理图



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

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


2)采集电压引脚的通道


其中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



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档)。

因此实验成功。




根据您提供的引用内容,您正在使用STM32L151开发一个项目,需要通过ADC采集电池电量,并通过DMA通道传送出来。您的需求是每1秒钟使用TIM4定时器去读取采样得到的电池数据并显示出来。您在网上找到了一些关于通过ADC通道采集电池电量的代码,但是没有找到符合您需求的。因此,您根据其他人的代码,并结合您的特殊需求,编写了一份功能相符的代码。 在主函数(main)中,您使用了TIM4定时器触发读取电池电量的任务。在该任务中,您开启了DMA搬运数据并开启了ADC转换。在等待ADC允许使用之后,您启动了ADC转换,并等待转换结束。然后,您将采样得到的电池数据进行处理,并显示出来。具体的代码如下所示: ```c void AdcTransfer(void) { u32 powervalue; ADC_DMACmd(ADC1, ENABLE); //开启DMA搬运数据 ADC_Cmd(ADC1, ENABLE); //开启ADC转换 while(ADC_GetFlagStatus(ADC1, ADC_FLAG_ADONS) == RESET) {}; //等待ADC允许使用 ADC_SoftwareStartConv(ADC1); //开启ADC转换 while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)); //等待ADC转换结束 powervalue = (uint16_t)((After_Filter*3300*3)>>12); } ``` 另外,您还编写了DMA中断函数用于处理DMA传输完成的事件。在该中断函数中,您停止了DMA搬运ADC数值和ADC转换。然后,您对采样得到的数据进行处理,计算出电量,并将其显示出来。具体的代码如下所示: ```c void DMA1_Channel1_IRQHandler(void) { u32 i; u32 After_Buff=0; if (DMA_GetITStatus(DMA_IT_TC) != RESET) { DMA_ClearITPendingBit(DMA1_IT_TC1); //清除DMA中断标志位 ADC_DMACmd(ADC1, DISABLE); //停止DMA搬运ADC数值 ADC_Cmd(ADC1,DISABLE); //停止ADC转换,我是通过Tim4定时器产生的中断来开关DMA和ADC。 for(i = 0;i < buff_size;i++) { After_Buff = After_Buff + ADC_ConvertedValue[i]; } After_Filter=After_Buff/10; //强制转换后电量显示正常 After_Buff=0; } } ``` 以上是根据您提供的引用内容总结出的与STM32 ADC电量相关的代码部分。如果您有其他问题,请随时提问。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [stm32l151 ADC通过DMA通道定时采样电池电量](https://blog.csdn.net/hongshengguang/article/details/88950376)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值