STC8G1K08 实现ADC采集电压(主要是讲解思路)

这篇具有很好参考价值的文章主要介绍了STC8G1K08 实现ADC采集电压(主要是讲解思路)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一.项目背景

使用STC8G1K08自带的10位ADC采集电池电压和电容电压,实时监测电池电压和电容电压的电量情况;

①当电池电压等于14.8V时则点亮电池电量指示灯,低于13.2V时则关闭,介于中间,则闪烁。

②当电容电压大于360V时则点亮电容电量指示灯,低于330V则关闭,介于中间,则闪烁。

电路连接情况:芯片的19脚、20脚分别连接电池和电容,16、15脚分别连接的是电池和电容指示灯。

二.相关代码

ADC.C

#include	"ADC.h"


//========================================================================
// 函数: void	ADC_Inilize(ADC_InitTypeDef *ADCx)
// 描述: ADC初始化程序.
// 参数: ADCx: 结构参数,请参考adc.h里的定义.
// 返回: none.
//========================================================================
void	ADC_Inilize(ADC_InitTypeDef *ADCx)
{
	ADCCFG = (ADCCFG & ~ADC_SPEED_2X16T) | ADCx->ADC_Speed;
	if(ADCx->ADC_Power == ENABLE)	ADC_CONTR |= 0x80;
	else							ADC_CONTR &= 0x7F;
	if(ADCx->ADC_AdjResult == ADC_RIGHT_JUSTIFIED)	ADCCFG |=  (1<<5);	//AD转换结果右对齐。
	else									ADCCFG &= ~(1<<5);	//AD转换结果左对齐。 
	if(ADCx->ADC_Interrupt == ENABLE)	EADC = 1;			//中断允许		ENABLE,DISABLE
	else								EADC = 0;
	if(ADCx->ADC_Priority > Priority_3)	return;	//错误
	ADC_Priority(ADCx->ADC_Priority);	//指定中断优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3

	if(ADCx->ADC_SMPduty > 31)	return;	//错误
	if(ADCx->ADC_CsSetup > 1)	return;	//错误
	if(ADCx->ADC_CsHold > 3)	return;	//错误
	P_SW2 |= 0x80;
	ADCTIM = (ADCx->ADC_CsSetup << 7) | (ADCx->ADC_CsHold << 5) | ADCx->ADC_SMPduty ;		//设置 ADC 内部时序,ADC采样时间建议设最大值
	P_SW2 &= 0x7f;
}


//========================================================================
// 函数: void	ADC_PowerControl(u8 pwr)
// 描述: ADC电源控制程序.
// 参数: pwr: 电源控制,ENABLE或DISABLE.
// 返回: none.
//========================================================================
void	ADC_PowerControl(u8 pwr)
{
	if(pwr == ENABLE)	ADC_CONTR |= 0x80;
	else				ADC_CONTR &= 0x7f;
}

//========================================================================
// 函数: u16	Get_ADCResult(u8 channel)
// 描述: 查询法读一次ADC结果.
// 参数: channel: 选择要转换的ADC.
// 返回: ADC结果.
//========================================================================
u16	Get_ADCResult(u8 channel)	//channel = 0~15
{
	u16	adc;
	u8	i;

	if(channel > ADC_CH15)	return	4096;	//错误,返回4096,调用的程序判断	
	ADC_RES = 0;
	ADC_RESL = 0;

	ADC_CONTR = (ADC_CONTR & 0xf0) | ADC_START | channel; 
	NOP(10);			//对ADC_CONTR操作后等待会儿再访问

	for(i=0; i<250; i++)		//超时
	{
		if(ADC_CONTR & ADC_FLAG)
		{
			ADC_CONTR &= ~ADC_FLAG;
			if(ADCCFG &  (1<<5))		//转换结果右对齐。 
			{
				adc = ((u16)ADC_RES << 8) | ADC_RESL;
			}
			else		//转换结果左对齐。 
			{
				#if ADC_RES_12BIT==1
					adc = (u16)ADC_RES;
					adc = (adc << 4) | ((ADC_RESL >> 4)&0x0f);
				#else
					adc = (u16)ADC_RES;
					adc = (adc << 2) | ((ADC_RESL >> 6)&0x03);
				#endif
			}
			return	adc;
		}
	}
	return	4096;	//错误,返回4096,调用的程序判断
}


//========================================================================
// 函数: void ADC_int(void) interrupt ADC_VECTOR
// 描述: ADC中断函数.
// 参数: none.
// 返回: none.
//========================================================================
void ADC_int (void) interrupt ADC_VECTOR
{
	ADC_CONTR &= ~ADC_FLAG;
}


ADC.h

#ifndef	__ADC_H
#define	__ADC_H

#include	"config.h"

#define ADC_RES_12BIT	1		//0: MCU为10位ADC; 1: MCU为12位ADC


#define	ADC_P10		0x01	//IO引脚 Px.0
#define	ADC_P11		0x02	//IO引脚 Px.1
#define	ADC_P12		0x04	//IO引脚 Px.2
#define	ADC_P13		0x08	//IO引脚 Px.3
#define	ADC_P14		0x10	//IO引脚 Px.4
#define	ADC_P15		0x20	//IO引脚 Px.5
#define	ADC_P16		0x40	//IO引脚 Px.6
#define	ADC_P17		0x80	//IO引脚 Px.7
#define	ADC_P1_All	0xFF	//IO所有引脚

#define ADC_POWER	(1<<7)	//ADC 电源
#define ADC_START	(1<<6)	//ADC 转换启动控制位。自动清0
#define ADC_FLAG	(1<<5)	//ADC 转换结束标志位。软件清0
#define ADC_EPWMT	(1<<4)	//使能 PWM 同步触发 ADC 功能
#define ADC_CH0		0
#define ADC_CH1		1
#define ADC_CH2		2
#define ADC_CH3		3
#define ADC_CH4		4
#define ADC_CH5		5
#define ADC_CH6		6
#define ADC_CH7		7
#define ADC_CH8		8
#define ADC_CH9		9
#define ADC_CH10	10
#define ADC_CH11	11
#define ADC_CH12	12
#define ADC_CH13	13
#define ADC_CH14	14
#define ADC_CH15	15

#define ADC_SPEED_2X1T		0			//SYSclk/2/1
#define ADC_SPEED_2X2T		1			//SYSclk/2/2
#define ADC_SPEED_2X3T		2			//SYSclk/2/3
#define ADC_SPEED_2X4T		3			//SYSclk/2/4
#define ADC_SPEED_2X5T		4			//SYSclk/2/5
#define ADC_SPEED_2X6T		5			//SYSclk/2/6
#define ADC_SPEED_2X7T		6			//SYSclk/2/7
#define ADC_SPEED_2X8T		7			//SYSclk/2/8
#define ADC_SPEED_2X9T		8			//SYSclk/2/9
#define ADC_SPEED_2X10T		9			//SYSclk/2/10
#define ADC_SPEED_2X11T		10		//SYSclk/2/11
#define ADC_SPEED_2X12T		11		//SYSclk/2/12
#define ADC_SPEED_2X13T		12		//SYSclk/2/13
#define ADC_SPEED_2X14T		13		//SYSclk/2/14
#define ADC_SPEED_2X15T		14		//SYSclk/2/15
#define ADC_SPEED_2X16T		15		//SYSclk/2/16

#define ADC_LEFT_JUSTIFIED		0		//ADC Result left-justified
#define ADC_RIGHT_JUSTIFIED		1		//ADC Result right-justified


typedef struct
{
	u8	ADC_SMPduty;		//ADC 模拟信号采样时间控制, 0~31(注意: SMPDUTY 一定不能设置小于 10)
	u8	ADC_Speed;			//设置 ADC 工作时钟频率	ADC_SPEED_2X1T~ADC_SPEED_2X16T
	u8	ADC_Power;			//ADC功率允许/关闭	ENABLE,DISABLE
	u8	ADC_AdjResult;	//ADC结果调整,	ADC_LEFT_JUSTIFIED,ADC_RIGHT_JUSTIFIED
	u8	ADC_Priority;			//优先级设置	Priority_0,Priority_1,Priority_2,Priority_3
	u8	ADC_Interrupt;	//中断允许	ENABLE,DISABLE
	u8	ADC_CsSetup;		//ADC 通道选择时间控制 0(默认),1
	u8	ADC_CsHold;			//ADC 通道选择保持时间控制 0,1(默认),2,3
} ADC_InitTypeDef;

void	ADC_Inilize(ADC_InitTypeDef *ADCx);
void	ADC_PowerControl(u8 pwr);
u16		Get_ADCResult(u8 channel);	//channel = 0~15

#endif

main.c

GPIO和ADC相关配置

#include  "Timer.h"

/******************* IO配置函数 *******************/
void	GPIO_config(void)
{
	GPIO_InitTypeDef	GPIO_InitStructure;		//结构定义
	//AD口设置为输入口,U5的19脚为电池组电量检测-P1.0,U5的20脚为电容组电量检测-P1.1
	GPIO_InitStructure.Pin  = GPIO_Pin_0 | GPIO_Pin_1 ;		//指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7
	GPIO_InitStructure.Mode = GPIO_HighZ;	//浮空输入 :被选择为ADC输入通道的IO扣,必须设置PxM0,PxM1寄存器将IO口模式设置为高阻输入模式。
	GPIO_Inilize(GPIO_P1,&GPIO_InitStructure);	//初始化

	//U5的15脚点亮CN2电容电量指示灯,低于330V时则关闭。16脚点亮CN1电池电量指示灯,低于13.2V时则关闭。15脚-P3.4,16脚-P3.5
	GPIO_InitStructure.Pin = GPIO_Pin_4 | GPIO_Pin_5;
	GPIO_InitStructure.Mode = GPIO_OUT_PP;//推挽输出
	GPIO_Inilize(GPIO_P3,&GPIO_InitStructure);
}

/******************* AD配置函数 *******************/
void	ADC_config(void)
{
	//使用的时ADC0、ADC1 - P1.0和P1.1
	ADC_InitTypeDef		ADC_InitStructure;		//结构定义
	ADC_InitStructure.ADC_SMPduty   = 31;		//ADC 模拟信号采样时间控制, 0~31(注意: SMPDUTY 一定不能设置小于 10)
	ADC_InitStructure.ADC_CsSetup   = 0;		//ADC 通道选择时间控制 0(默认),1
	ADC_InitStructure.ADC_CsHold    = 1;		//ADC 通道选择保持时间控制 0,1(默认),2,3
	ADC_InitStructure.ADC_Speed     = ADC_SPEED_2X1T;		//设置 ADC 工作时钟频率	ADC_SPEED_2X1T~ADC_SPEED_2X16T
	ADC_InitStructure.ADC_Power     = ENABLE;				//ADC功率允许/关闭	ENABLE,DISABLE 打开ADC电源
	ADC_InitStructure.ADC_AdjResult = ADC_RIGHT_JUSTIFIED;	//ADC结果调整,	ADC_LEFT_JUSTIFIED,ADC_RIGHT_JUSTIFIED
	ADC_InitStructure.ADC_Priority    = Priority_0;			//指定中断优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
	ADC_InitStructure.ADC_Interrupt = DISABLE;			//中断允许	ENABLE,DISABLE
	ADC_Inilize(&ADC_InitStructure);					//初始化
	ADC_PowerControl(ENABLE);							//单独的ADC电源操作函数, ENABLE或DISABLE
}

获取并计算电池、电容电压的方法:

这里特别注意的是:ADC采集的电压范围是0~Vmcu,即0V到芯片电压,本人使用的是10位ADC采集,即0~Vmcu分别对应0~1024,呈线性关系。那么如果采集的电压,比如我这里采集的是380V,超过了ADC采集电压,那应该如何换算呢?

原理很简单,只需要把ADC采集的电压(可以用万用表测得),最后乘以一个比例就能得到真实的电压,这个比例 是从电阻分压算得(因为一般ADC采集电路外接一个电压放大电路等),比如下图:

STC8G1K08 实现ADC采集电压(主要是讲解思路)

 这个比例就是:(R17+R14)/R17 = 83.3。也就是最后ADC采集到的电压,最后需要乘以83.3。

代码实现如下:文章来源地址https://www.toymoban.com/news/detail-506883.html

//获取电源组电量,大于14.8V点亮指示灯,低于13.2V关闭,介于中间闪烁
float Get_Vbat(void)
{
	unsigned int res;
	float Vbat;
	
	ADC_CONTR = 0x80;  //使能ADC,打开ADC电源,并选择ADC0-P1.0
	ADC_CONTR |= 0x40; //开始采集
	while(!(ADC_CONTR & 0x20)); //等待ADC转换结束
	ADC_CONTR &= ~0x20; //清空ADC转换结束标志位。
	res =  Get_ADCResult(0);//(ADC_RES << 8) | ADC_RESL; //获取ADC0采集结果。 或者寄存器操作:res = (ADC_RES <<8 ) | ADC_RESL
	//将12位ADC转换结果 反推 ADC被转换通道的输入电压Vin
	Vbat =  ((3.3 / ADC1024)*res)*11;
	return Vbat;  //
}
//获取电容组电量,大于360V 点亮指示灯,小于330V关闭,介于中间闪烁
float Get_Vcap(void)    
{
	unsigned int res;
	float Vcap;
	
	ADC_CONTR = 0x81;  //使能ADC,打开ADC电源,并选择ADC1-P1.1
	ADC_CONTR |= 0x40; //开始采集
	while(!(ADC_CONTR & 0x20)); //等待ADC转换结束
	ADC_CONTR &= ~0x20; //清空ADC转换结束标志位。
	res =  Get_ADCResult(0); //(ADC_RES<<8) | ADC_RESL; //获取ADC1采集结果。 或者寄存器操作:res = (ADC_RES <<8 ) | ADC_RESL
	Vcap = ((3.3 / ADC1024)*res)*84.33;
	return Vcap;
}

void Is_Vbat(float Vbat)
{
	if(Vbat >= 14.8)
	{
		delay_ms(10);
		if(Vbat >= 14.8)
			P35 = 0;
	}
	else if(Vbat < 13.2)
	{
		delay_ms(10);
		if(Vbat < 13.2)
		  P35 = 1;
	}
	else
	{
		P35 = 0;
		delay_ms(500);
		P35 = 1;
		delay_ms(500);
	}
}

void Is_Vcap(float Vcap)
{
	if(Vcap >= 360)
	{
		delay_ms(10);
		if(Vcap >= 360)
		P34 = 0;
	}
	else if(Vcap < 330)
	{
		delay_ms(10);
		if(Vcap < 330)
		P34 = 1;
	}
	else
	{
		P34 = 0;
		delay_ms(500);
		P34 = 1;
		delay_ms(500);
	}
}

到了这里,关于STC8G1K08 实现ADC采集电压(主要是讲解思路)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • STC8H8K64U单片机-ADC采集数

    配置单片机的ADC时一定要将IO口配置成高阻输入模式, 以下是单片机引脚对应的ADC通道  

    2024年02月07日
    浏览(42)
  • STC8h1k28六个基本实验

    实验内容: 项目1: 参考原理图,设计1位闪烁灯程序,每次亮、灭时长均为500ms。 项目2: 参考原理图,设计三色流转灯程序,GRB三种颜色的LED轮番点亮,每次只亮一盏,每次点亮时长为500ms。 原理图: 实验原理: (共阳)LED负极接单片机IO口(P00P01P02),当IO口输出低电

    2024年02月04日
    浏览(50)
  • STC8学习 ——ADC 1

    注意:  uint8_t正常左移8位是0,但如果赋值给uint16_t就占uint16_t中高8位,要保留数据就要把八位数据左移8位后赋给16数据,继续赋给8位数据,结果就是0 注意:通过ADC采集数据并输出电压的原理是  电压和对应ADC端口采集结果的比值是恒定的 ADC第15通道采集的内部参考电压值

    2023年04月24日
    浏览(71)
  • STC8H系列单片机入门教程之ADC基础知识(四)

    目录 一、A/D转换过程 二、ADC转换流程图 三、采样定理 四、ADC基本参数 4.1、分辨率 4.2、采样速率 4.3、转换时间 4.4、量程  4.5、最低有效位 五、静态参数 5.1、微分非线性 5.2、积分非线性 六、逐次逼近型模数转换器 七、ADC常用分压电路 八、示例代码 ADC即模数转换器,用来

    2024年04月11日
    浏览(59)
  • STM32 TIMER_TRGO触发+ADC采集 + DMA传输 + 中断均方根处理 实现三相电压显示

    STM32 TIMER_TRGO触发+ADC采集 + DMA传输 实现三相电压采集 首先,是实际采集的三相电压值,用excel处理了下: 采集个电压,为什么这么复杂。 开始我也是直接用ADC采集,然后delay,再采集,然后delay,再采集……最后数据处理…… 问题是如果我们用单片机裸跑,每次delay都会卡死

    2024年02月16日
    浏览(41)
  • ADC——电压采集

    STM32f103 系列有 3 个 ADC,精度为 12 位,每个 ADC 最多有 16 个外部通道。ADC1 和ADC2 都有 16 个外部通道,ADC3 根据 CPU 引脚的不同通道数也不同,一般都有 8 个外部通道。 模块1:电压输入范围 ADC电压输入范围 VREF- ≤ VIN ≤ VREF+ 。般把 VSSA 和 VREF- 接地,把 VREF+ 和 VDDA 接 3V3,得到

    2024年02月15日
    浏览(35)
  • STM32笔记_10(ADC—电压采集)

    STM32f103 系列有 3 个 ADC ,精度为 12 位 ,每个 ADC 最多有 16 个外部通道 。其中 ADC1 和ADC2 都有 16 个外部通道, ADC3 根据 CPU 引脚的不同通道数也不同,一般都有 8 个外部通道。         ADC 输入范围为: VREF- ≤ VIN ≤ VREF+ 。由 VREF-、 VREF+ 、 VDDA 、 VSSA、这四个外部引脚决定

    2024年02月04日
    浏览(43)
  • 基于51单片机的电压采集(ADC0809)

    1.ADC0809简介 IN0~IN7 : 8路模拟量输入端; D0~D7:8位数字量输出端; ADDA、ADDC、ADDC:3位地址输入线,用于选择8路模拟通道中的一路; ALE:地址锁存允许信号,输入,高电平有效; START:A/D转换启动信号,输入,高电平有效; EOC:A/D转换结束信号,输出。当启动转换时,高引脚为低电

    2023年04月18日
    浏览(52)
  • 基于51单片机的电压采集(ADC0804)

    1.ADC0804简介 工作电压:+5V,即VCC=+5V。 模拟转换电压范围:0~+5V,即0≤Vin≤+5V。 分辨率:8位,即分辨率为1/(2^8)=1/256,转换值介于0~255之间。 转换时间:100us(fCK=640KHz时)。 转换误差:±1LSB。 参考电压:2.5V,即Vref/2=2.5V。 Vin(+)、Vin(-):两个模拟信号输入端,可以接

    2023年04月08日
    浏览(41)
  • STM32F103_ADC电压采集

    ADC寄存器 STM32 的 ADC 是 12 位逐次逼近型的模拟数字转换器。 它有 18 个通道,可测量 16 个外部和 2 个内部信号源。各通道的 A/D 转换可以单次、连续、扫描或间断模式执行。ADC 的结果可以左对齐或右对齐方式存储在 16 位数据寄存器中。 模拟看门狗特性允许应用程序检测输入

    2023年04月08日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包