找回密码
 立即注册
查看: 99|回复: 1

使用AI8G1K08A,读取flash内的BG电压数据,直接计算VCC

[复制链接]
  • 打卡等级:初来乍到
  • 打卡总天数:7
  • 最近打卡:2025-06-27 22:35:18
已绑定手机

3

主题

8

回帖

57

积分

注册会员

积分
57
发表于 2025-6-17 14:33:43 | 显示全部楼层 |阅读模式
stc单片机内部有一个电压接近1.19v的带隙基准电压(后文简称BG),出厂校准值直接存储在flash中,具体位置可以在手册中“存储器”章节寻找。通过读取这个电压,再使用ADC测量15通道的回报值,就可以直接计算VCC,这一过程完全在单片机内部实现,不需要外部连线。
具体原理为,adc测量电压后会回报一个数值,叫做码数,adc是靠比较测量电压的,参考源是vcc。如果是十位adc,码数范围为0~1023,12位为4096。stc单片机adc的15通道固定测量内部bg电压值,读取这个电压,可以得到1.19v bg电压对应的码数,通过除法计算,可以直接得到毫伏每码这个值。而adc测量vcc,由于参考的就是vcc,所以回报的是满量程值,那么就可以省去测量vcc的过程,直接用满量程码数1024乘以毫伏每码,直接得到vcc电压。
而bg电压是一个在1.19v左右的值,会因为制造过程产生差异,烧录程序时我们可以看到软件会回报带隙电压校准值,实际上这个值就是直接存储在flash中的,所以可以手动读取。这个值为一个分为高八位和低八位的十六位二进制数,高字节在前,分为4个四位二进制组,读取之后可以直接组合为毫伏整数值。可以直接用于计算。
以下为示范代码,使用stc8g1k08a单片机,主频6MHZ,通过一个连接到P30的外部led表示电压状态,如果vcc大于4v,则亮起,如果小于4v,则熄灭,使用迟滞比较,防止震荡。其实我一开始照着范例写的代码一堆报错,让ai改了下就好了。本代码可以用于验证adc功能。


#include "STC8G.H"
#include "intrins.h"

// 函数声明
unsigned int BGV_READ(void);
unsigned int ADC_READ(void);
unsigned int ADC_FILTER(void);
void VCC_CAL(void);
void LED_CONFIG(void);

// 全局变量声明
unsigned int bg_mv;          // 存储带隙电压值
unsigned int nADC_BUFF[8];   // 存储ADC采样值的数组
unsigned int vcc_value;      // 存储计算出的VCC值

// 从idata读取带隙电压值
unsigned int BGV_READ(void) {
    unsigned int temp = *((unsigned int idata *)0xEF);
    return temp;
}

// ADC读取函数
unsigned int ADC_READ(void) {
    unsigned int res;
    ADC_CONTR |= 0x40;       // 启动ADC转换
    _nop_(); _nop_(); _nop_(); _nop_(); // 短暂延时
    while (!(ADC_CONTR & 0x20)); // 等待转换完成
    ADC_CONTR &= ~0x20;      // 清除完成标志
    res = (ADC_RES << 8) | ADC_RESL; // 合并高8位和低8位
    return res;
}

// ADC滤波函数(冒泡排序 + 中值平均滤波)
unsigned int ADC_FILTER(void) {
    unsigned char i, j;
    unsigned int k;
    unsigned long sum = 0;
    unsigned int vcc; // 声明放在作用域开头

    // 采集8个样本
    for(i = 0; i < 8; i++) {
        nADC_BUFF = ADC_READ(); // 调用ADC读取
    }

    // 冒泡排序
    for(j = 0; j < 7; j++) {
        for(i = 0; i < 7 - j; i++) {
            if(nADC_BUFF > nADC_BUFF[i+1]) {
                k = nADC_BUFF;
                nADC_BUFF = nADC_BUFF[i+1];
                nADC_BUFF[i+1] = k;
            }
        }
    }

    // 取中间4个值(索引3-6)求平均
    for(i = 3; i <= 6; i++) { // 修正:索引3-6共4个值
        sum += nADC_BUFF;
    }
    sum = (sum + 2) / 4; // 四舍五入并求平均

    // 计算VCC(使用带隙电压bg_mv),1024对应10位ADC
    vcc = (unsigned int)(1024UL * bg_mv / sum);
    return vcc;
}

// 初始化ADC并计算VCC
void VCC_CAL(void) {
    // 初始化ADC
    P_SW2 = 0x80; // 访问扩展寄存器
    ADCTIM = 0x3F; // 设置ADC采样时间
    P_SW2 = 0x7F; // 关闭扩展寄存器访问
    ADCCFG = 0x2F; // ADC时钟 = 系统时钟/2/16
    ADC_CONTR = 0x8F; // 使能ADC,选择通道15(带隙电压)

    // 读取带隙电压(如果未读取过)
    if (bg_mv == 0) {
        bg_mv = BGV_READ();
    }

    // 计算VCC
    vcc_value = ADC_FILTER();
}

// LED初始化
void LED_CONFIG(void) {
    P3M1 = 0x00;   // P3模式设置
    P3M0 = 0x01;   // P3.0推挽输出
    P30 = 1;       // 初始LED灭
}

// 主函数
void main() {
    unsigned int current_vcc; // 声明放在作用域开头
   
    LED_CONFIG();   // 初始化LED
    BGV_READ();     // 读取带隙电压(存储在bg_mv)
    VCC_CAL();      // 初始化ADC并计算VCC

    while(1) {
        VCC_CAL();  // 更新VCC值
        current_vcc = vcc_value; // 使用全局变量值

        // 迟滞比较:电压>4000mV时开LED;电压<3900mV且LED亮时关LED
        if (current_vcc >= 4000) {
            P30 = 0; // LED亮
        }
        else if ((P30 == 0) && (current_vcc < 3900)) {
            P30 = 1; // LED灭
        }
    }
}

回复

使用道具 举报 送花

3

主题

523

回帖

-243

积分

等待验证会员

积分
-243
发表于 2025-6-17 14:38:00 | 显示全部楼层
使用STCG1K08A单片机读取BG电压的原理及代码示例

1. 单片机基本配置
型号:STCG1K08A  
内部参数:  
带隙基准电压(BG):119V  
ADC位数:15位(16位二进制数)  
满量程值(VCC):5V  
内部特性:  
BG电压通过存储器存储并校准,校准值通过 flash存储  
ADC读数基于VCC电压  

2. 原理分析
1. 读取BG电压  
ADC读数基于VCC电压进行比较,代码中直接读取BG电压对应的码数。  
BG电压为119V,通过十六位二进制数表示:49650(高八位4965,低八位650)。  

2. 读取VCC电压  
ADC满量程为1024(对应5V)。  
VCC电压读取为1024 × 毫伏每码。  

3. 示例代码修改说明
以下为修正后的示例代码,用于验证ADC功能:

```cpp
include "STC8GH"
include "intrinsh"

void ADCREAD(void) {
    unsigned int VCC = ADC.Read(0x00, 0x7F); // ADC读取5V值,对应1024
    unsigned int BG = ADC.Read(0x80, 0x7F);  // ADC读取119V值,对应512(5V=1024/2)
    // 转换BG电压为毫伏
    VCC >>= 8; // 除以2,得到1024/2 = 512
    VCC >>= 8; // 除以2,得到1024/4 = 256
    VCC >>= 8; // 除以2,得到1024/8 = 128
    VCC >>= 8; // 除以2,得到1024/16 = 64
    VCC >>= 8; // 除以2,得到1024/32 = 32
    VCC >>= 8; // 除以2,得到1024/64 = 16
    VCC >>= 8; // 除以2,得到1024/128 = 8
    VCC >>= 8; // 除以2,得到1024/256 = 4
    VCC >>= 8; // 除以2,得到1024/512 = 2
    VCC >>= 8; // 除以2,得到1024/1024 = 1
    // 转换为毫伏
    VCC

[本文内容由国芯人工智能辅助生成,仅供参考]
回复 支持 反对

使用道具 举报 送花

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

本版积分规则

QQ|手机版|小黑屋|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2025-6-29 20:35 , Processed in 0.122476 second(s), 55 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

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