找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 749|回复: 23
打印 上一主题 下一主题
收起左侧

STC15W408AS 利用bandgap计算VCC电压不准确的问题

  [复制链接]
跳转到指定楼层
楼主

STC15W408AS 利用bandgap计算VCC电压。 我的VCC电压是5V,但计算出来确实9.3V,请大家帮忙看看代码问题。谢谢

//初始化ADC
void AdInit()
{       
        P1ASF = 0x00;
        ADC_RES = 0;        ADC_RESL = 0;                                        //清除ADC结果寄存器
        ADC_CONTR = 0x88;
        _nop_();_nop_();
        ADC_CONTR |= 0x08;
        delay_ms(20);                                                                                                //等待ADC稳定
        EADC = 1;                                                                                                 //允许AD转换中断
}


unsigned int read_bandgap_voltage(){
        uchar idata *iptr;                                //定义RAM内存区指针
        iptr = ID_ADDR_RAM;
        bandgap=*iptr++;
        bandgap<<=8;
        bandgap+=*iptr;                                                //从内存区读取BandGap电压值(单位毫伏)
        return bandgap;
}


void adc_isr() interrupt 5{
                ADC_CONTR &= ~0x10;               
               adc_val=(ADC_RES<<2)|(ADC_RESL);
              VFt=(float)((long)(read_bandgap_voltage()*1024)/adc_val);  
           //VFt的电压值与实际VCC电压值相差甚远,是什么问题引起的。       
               
                                ADC_CONTR = 0x88;
                                _nop_();_nop_();_nop_();_nop_();        //等待四个机器周期
                                while(!(ADC_CONTR&ADC_FLAG));

}

VFt的值是9.3V,
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏3 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:327265 发表于 2025-12-29 12:39 | 只看该作者
添加一个基准电压比较再采集计算
回复

使用道具 举报

板凳
ID:327265 发表于 2025-12-29 12:40 | 只看该作者
添加一个基准电压再采样计算
回复

使用道具 举报

地板
ID:705846 发表于 2025-12-29 19:24 | 只看该作者
经过反复排查
void adc_isr() interrupt 5{
                ADC_CONTR &= ~0x10;               
                     uint vcc_voltage=(float)(5.0*bandgap/adc_val);

     串口打印出来 bandgap是D7, adc_val是02, vcc_voltage结果是十进制24, 为什么vcc_voltate不是十进制537呢。

回复

使用道具 举报

5#
ID:624769 发表于 2025-12-29 20:51 | 只看该作者
保存在 RAM 的 基准点压参考值,开机后有可能被改写,建议从 CODE中读取。 或者,开机后,优先读取 RAM中的参考值,再执行其他代码。
回复

使用道具 举报

6#
ID:163139 发表于 2025-12-29 21:55 | 只看该作者
请教:STC15W408AS如何使用外部基准电压,接哪个引脚,还是P1口随便接?
回复

使用道具 举报

7#
ID:163139 发表于 2025-12-29 21:57 | 只看该作者
请教:stc15w408as如何使用外部基准电压?
回复

使用道具 举报

8#
ID:1152330 发表于 2025-12-30 08:31 | 只看该作者
这里提出另外一个问题:计算读取的电压时,1024应该为1023,STC手册中给出的是1024,也是错误的。请大家讨论。
回复

使用道具 举报

9#
ID:155507 发表于 2025-12-30 19:05 | 只看该作者
shuiquan3 发表于 2025-12-29 21:55
请教:STC15W408AS如何使用外部基准电压,接哪个引脚,还是P1口随便接?

A/D 转换模块的参考电压源
STC15 系列单片机的参考电压源是输入工作电压 Vcc,所以一般不用外接参考电压源。如 7805 的输
出电压是 5V,但实际电压可能是 4.88V 到 4.96V,用户需要精度比较高的话,可在出厂时将实际测出的
工作电压值记录在单片机内部的 EEPROM 里面,以供计算。
如果有些用户的 Vcc 不固定,如电池供电,电池电压在 5.3V--4.2V 之间漂移,则 Vcc 不固定,就需
要在 8 路 A/D 转换的一个通道外接一个稳定的参考电压源,来计算出此时的工作电压 Vcc,再计算出其
他几路 A/D 转换通道的电压。如下图所示,可在 ADC 转换通道的第二通道外接一个 2.5V( 或 1V,或...)
的基准参考电压源,由此求出此时的工作电压 Vcc,再计算出其它几路 A/D 转换通道的电压( 理论依据
是短时间之内, Vcc 不变)。





回复

使用道具 举报

10#
ID:1133081 发表于 2026-1-1 21:06 | 只看该作者
samxon 发表于 2025-12-29 19:24
经过反复排查
void adc_isr() interrupt 5{
                ADC_CONTR &= ~0x10;               

//                当前VCC_mV = 标准电压mV * 标准电压BandGap转换值 / 当前电压BandGap转换值
                VCC        = 5000       * (long)BGV5            / BGVx;
回复

使用道具 举报

11#
ID:891686 发表于 2026-1-2 01:14 | 只看该作者
测量 VCC 的步骤:
① 给定一个比较精确的电源电压 VCCA ,得到 BandGap (间隙基准源)的 ADC 读数 BGVA。据此可计算出 BandGap 的基准电压 VBG 。
② 当电源电压为 VCCX 时,得到另一个 BandGap 的 ADC 读数为 BGVX。则 VCCX = BGVX * VBG / BGVA 。

10 位 ADC  的值范围为:0x000 ~ 0x3FF (十进制:0~1023)。
假设 VCCA = 5.00V,间隙基准源的基准电压为 VBG = 1.25V,则 BGVA 的值为:1.25V / 5.00V * 1023 = 255.75。
四舍五入得到 256。即此时的 ADC 读数应为 BGVA = 0x100 (十进制:256)。

假设在待测电源电压下 BandGap 的 ADC 读数为 BGVX = 0x266 (十进制:614),
则 VCCX = BGVX * VBG / BGVA = 614 * 1.25 / 256 = 2.998V

【说明】
① 注意到测量 VBG 时,ADC 的量化作用导致了测量误差:5.00V * 256 / 1023 = 1.251222V 。为提高测量精度,可用不同的 VCCA 进行测量,然后对计算出的 VBG 值求平均作为 VBG 的 “精确” 值。

② 注意到 10位 ADC 的读数需要三个 Nibble(半字节),比较方便的类型为双字节的无符号整数(可以定义为 UInt16)。
以上述假设的数据为例:
UInt16 BGVA = 0x0100、UInt16 BGVX = 0x0266、float VBG = 1.25;
float VCCX = (float) BGVX * VBG / (float) BGVA 。
假设要用 UInt16 来表示 VCCX ,可以先将 VCCX 乘以一个适当的常数 (float) C,以保留足够的输出精度:
UInt16 Result = (UInt16) (VCCX * C) 。
若最大 VCCA = 5.5V 时,输出为 0xFFFF,则 C 可取为 65535 / 5.5 = 11915.4545454545 。
回复

使用道具 举报

12#
ID:705846 发表于 2026-1-2 17:37 | 只看该作者
Jack315 发表于 2026-1-2 01:14
测量 VCC 的步骤:
① 给定一个比较精确的电源电压 VCCA ,得到 BandGap (间隙基准源)的 ADC 读数 BGVA ...

VCC供电是5V, 以下代码还是无法获取到真实电压值。请大家帮忙看看是什么问题导致的。


void AdInit()
{       
        P1ASF = 0x00;
        ADC_RES = 0;        ADC_RESL = 0;
        CLK_DIV = 0x20;                                                                        
        ADC_CONTR = 0x88;
        _nop_();_nop_();
        ADC_CONTR |= 0x08;
        delay_ms(20);
        EADC = 1;
}

unsigned int read_bandgap_voltage(){
        return (*(unsigned char idata *)ID_ADDR_RAM <<8) |*(unsigned char idata *)(ID_ADDR_RAM + 1);
}

void adc_isr() interrupt 5{

        uint adc_val=(ADC_RES*256+ADC_RESL);
        uint vcc_voltage=5.0*((float)read_bandgap_voltage()/(float)adc_val);

        P1ASF=0x00;
        ADC_CONTR = 0x88|0x00;
        _nop_();_nop_();_nop_();_nop_();        //等待四个机器周期
        while(!(ADC_CONTR&ADC_FLAG));
        ADC_CONTR &=~ADC_FLAG;
}
回复

使用道具 举报

13#
ID:891686 发表于 2026-1-3 11:04 | 只看该作者
中断函数 adc_isr() 中:
adc_val 值是多少?
read_bandgap_voltage() 函数的返回值是多少?
最后得到的 vcc_voltage 是多少?

能不能上传一个 STC15W408AS 的数据手册,或给个链接。
想具体看看 BandGap 和 ADC 相关部分的硬件结构和编程信息。

回复

使用道具 举报

14#
ID:1133081 发表于 2026-1-3 11:14 | 只看该作者
samxon 发表于 2026-1-2 17:37
VCC供电是5V, 以下代码还是无法获取到真实电压值。请大家帮忙看看是什么问题导致的。

测量ADC的第9通道推算VCC电压计算INV.rar (19.65 KB, 下载次数: 0)



回复

使用道具 举报

15#
ID:705846 发表于 2026-1-4 09:43 | 只看该作者
Jack315 发表于 2026-1-3 11:04
中断函数 adc_isr() 中:
adc_val 值是多少?
read_bandgap_voltage() 函数的返回值是多少?

串口打印出来, adc_val值是0x02, read_bandgap_voltage()值是0x04D7, 反正最后得到的就不是VCC的真实电压。谢谢。
回复

使用道具 举报

16#
ID:705846 发表于 2026-1-4 12:59 | 只看该作者
这个读取BGV 的地址为什么不是0xef ,而是0x0000呢

我定义的地址是#define ID_ADDR_RAM 0xef                                //BandGap地址

#define IAP_ADDRESS 0x0000                                //测试地址
回复

使用道具 举报

17#
ID:1133081 发表于 2026-1-4 16:37 | 只看该作者
发表于 2026-1-4 12:59
这个读取BGV 的地址为什么不是0xef ,而是0x0000呢

我定义的地址是#define ID_ADDR_RAM 0xef                                //BandG ...

STC15W408AS的EEPROM共有10个扇区,各扇区首地址分别为0x0000、0x0200、0x0400......。BGV就2个字节的数据,只要没搞错你爱存哪里都可以。BGV不是凭空来的,必须是此芯片在某特定电源电压下测得的。这与STC8系列有所不同。STC8系列出厂时已将内部1.19V参考信号源电压值保存在指定地址:BGV = (int idata *)0xef;,前者保存的是ADC转换值,后者保存的是电压值,易混淆。后期处理不当会出错。
回复

使用道具 举报

18#
ID:891686 发表于 2026-1-5 00:10 | 只看该作者
samxon 发表于 2026-1-4 09:43
串口打印出来, adc_val值是0x02, read_bandgap_voltage()值是0x04D7, 反正最后得到的就不是VCC的真实电 ...

10-位 ADC 的值范围为 0x0000 ~ 0x03FF。0x04D7 不是一个有效的 ADC 数据。
说明:
① 数据本身错误,或者
② read_bandgap_voltage() 中的代码有问题。
回复

使用道具 举报

19#
ID:705846 发表于 2026-1-5 11:12 | 只看该作者
WL0123 发表于 2026-1-4 16:37
STC15W408AS的EEPROM共有10个扇区,各扇区首地址分别为0x0000、0x0200、0x0400......。BGV就2个字节的数 ...

STC15W408AS 读取0xef  的值为0x04D7, 明显是 1239mv,这个应该怎样处理。谢谢。


#define ID_ADDR_RAM 0xef                                //BandGap地址
unsigned int read_bandgap_voltage(){
        return (*(unsigned char idata *)ID_ADDR_RAM <<8) |*(unsigned char idata *)(ID_ADDR_RAM + 1);
}
回复

使用道具 举报

20#
ID:1133081 发表于 2026-1-5 13:32 | 只看该作者
samxon 发表于 2026-1-5 11:12
STC15W408AS 读取0xef  的值为0x04D7, 明显是 1239mv,这个应该怎样处理。谢谢。

STC15W408AS 读取0xef  的值为0x04D7,你凭什么说 明显是 1239mv。你根据什么理由或资料证明地址0xef 里的数据是内部参考电压值?STC15W用户手册哪里有此说明?官方示例程序也没有类似应用。不可能凭空找一个数据就能得到正确结果。
回复

使用道具 举报

21#
ID:883242 发表于 2026-1-5 21:08 来自触屏版 | 只看该作者
samxon 发表于 2025-12-29 19:24
经过反复排查
void adc_isr() interrupt 5{
                ADC_CONTR &= ~0x10;               

如果read_bandgap_voltage()读到的0x4d7是Vbg的mV数,那么这句:
(long)(read_bandgap_voltage()*1024)/adc_val);
就是对的,现在的问题是adc_val应该在255左右,检查下为什么这个值错的离谱吧!
回复

使用道具 举报

22#
ID:891686 发表于 2026-1-5 22:09 | 只看该作者
samxon 发表于 2026-1-5 11:12
STC15W408AS 读取0xef  的值为0x04D7, 明显是 1239mv,这个应该怎样处理。谢谢。

假设 0x04D7 (十进制:1239) 是间隙基准源的电压值 (1239mV),则读取这个电压值的代码可以改成:
  1. float read_bandgap_voltage()
  2. {
  3.                 unsigned int bg_voltage;

  4.                 bg_voltage = *(unsigned char idata *)ID_ADDR_RAM << 8;
  5.                 bg_voltage |= *(unsigned char idata *)(ID_ADDR_RAM + 1);

  6.                 return (float) bg_voltage / 1000.0;
  7. }
复制代码
这段代码应该就能得到间隙基准源的电压值为 1.239V ,与典型值 1.25V 相比,这个值的相对误差为 0.88%,是个合理的值。

“adc_val 值是 0x02” :这个数据应该是双字节,所以这个数据是有问题的。假设完整的数据是 adc_val = 0x0102 (十进制:258),则电源电压的值为:1.239V * 1023 / 258 = 4.9128 V 。
即 adc_val = 0x0102 是在 Vcc = 4.9128V 时,测量间隙基准源电压所得到到 ADC 读数。

参考 11# 的说明。


回复

使用道具 举报

23#
ID:705846 发表于 2026-1-6 09:13 | 只看该作者
WL0123 发表于 2026-1-5 13:32
STC15W408AS 读取0xef  的值为0x04D7,你凭什么说 明显是 1239mv。你根据什么理由或资料证明地址0xef 里 ...


手册上的读取地址




回复

使用道具 举报

24#
ID:1133081 发表于 2026-1-6 16:33 | 只看该作者
samxon 发表于 2026-1-6 09:13
手册上的读取地址


回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表