一.项目背景
使用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采集电路外接一个电压放大电路等),比如下图:
这个比例就是:(R17+R14)/R17 = 83.3。也就是最后ADC采集到的电压,最后需要乘以83.3。文章来源:https://www.toymoban.com/news/detail-506883.html
代码实现如下:文章来源地址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模板网!