bandgap的理解(内部带隙电压基准)

article/2025/8/15 7:23:34

转载地址:http://bbs.mydigit.cn/read.php?tid=1635508

写的非常好,想把每句话都记住。

首先了解两个英文缩写。

Abbreviations缩略语

Full spelling 英文全名

Chinese explanation 中文解释

POR

Power on reset

上电复位

Vreg

Reference Voltage

基准电压/参考电压

一、研究背景

大家都知道,stc单片机的adc(模数转换器)的基准是基于基于供电电源电压的,这样就造成了一个问题,如果供电电压发生变化,adc读得的值也会发生变化,就出现了测不准的现象,所以大家普遍的用法就是在adc的一个通道外接一个电压基准,类似tl431,通过读电压基准和测量值,换算出真实测量电压,但这样就会带来个问题,要占用一路adc通道,占用一个io,付出tl431的成本,外接还要处理电路,麻烦。所以stc15系列的单片机给我们提供了内部的基准,名字叫BandGap(内部带隙电压基准)

这两天要搞adc的应用,想到stc内部有基准,于是研读了数据手册,然而数据手册说的很不清楚,内容还分布在不同的地方,于是就搜索了下。但是在百度上的有用搜索结果很少,有一个本坛的帖子,点进去看了大部分人也是没搞懂
甚至大家都不太懂stc还有第九通道
还有人继续提tl431外部基准法
之前也看到有坛友在抱怨内部基准是垃圾,居然会随供电电压变化,完全没用什么的。
无法只好自己研究了,经过一下午的研究,终于搞了个明白,遂分享给大家,一起学习进步。
我们先说说BandGap(带隙电压)是啥。百度给出的解释是:
看上去比较复杂,我画了张简单的图表示,不是很准确,理解就好

二、经典的电路操作常识,我这种小白也听老大说了几遍,但是还是忘记了,今天自己看,估计会印象深刻。
如图,基准有两个材料串联而成,分别为温度正材料(温度升高阻值变大)和温度负材料(温度升高阻值变小)串联而成,这样,两个材料互相抵消,基准值就不会随温度发生变化。这样做的原因是在半导体制造中,几乎找不到不随温度变化的材料,所以选用了这种折中方案。
所以,和数据手册说的是一样的,基准不随芯片工作电压改变而变化
所以,内部基准读取后需要进行数学转换,就能成我们想用的值。
但是,官方给的例程貌似是有点问题的,串口出来的,数值不对,呵呵
而且,由于每片芯片的制造差异性,每个基准的比例不是相同的,每片芯片有特异性。
我的几片同款芯片的这个测量值都是有差异的,相差也不小。

stc给出的方案是这样的,在5v标准电源下测量BandGap的adc读数,然后记录在eeprom内,以后的程序不就可以读取这个值并进行比例换算了吗?
但是,大家有没有觉得这样会异常的麻烦,5v基准供电电压不好找,如果大量生产的话,每片都要读取校准会费时费力。
所以,stc还是蛮善良的,其实他们早就给我们标定好了这个值,我们只需要想点小办法吧它读出来就好。
数据手手册里面是这样的

这里要吐个槽,stc的数据手册编写者你真蛋疼,居然把两个内容分开讲,讲adc的第九通道,在数据手册第10.8节,第906页;讲怎么读取得标定值,在数据手册第1.18节,第284页,这是个大坑啊,跨度一个世纪的内容,呵呵了。
扯远了,这个标定值会储存在两个地方,一个是RAM(内存)末尾,一个是ROM(程序区)末尾。但是官方比较推荐的读取地点好像是使用程序储存器末尾,好像是因为ram的数据容易被覆盖。
不过用rom区的话,要注意以下三个问题:
程序储存区末尾会被占用那么十几二十个字节,不过一般小程序也不影响啥,写满程序区的就要注意下了。
同时,在使用rom区数据时,在下载时要勾选选项“在ID号前添加重要测试参数”(在下载选项末尾的一个选项,默认是不选的,要记得勾上)
第三,不同储存空间的单片机在程序中要定义不同的地址,我的是stc15w404as,选的是内部储存为4k(#define ID_ADDR_ROM 0x0ff7      //4K程序空间的MCU),这个的话应该大家读懂吧。

另外提一句,使用基准,不管内部外部,都能计算出供电电压,如果电压下降啥的,能在程序里做出反应,比如说记录数据如eeprom什么的,实现掉电保护,这个大家脑洞了

提醒大家的事,使用外部晶振的时候,读不到bandgap的adc值,这个非常重要,望周知

感谢@mosliu 朋友的测试和补充,详情看这贴:STC15系列 读取BandGap的一点小小补充 另外吐槽下STC的客服|http://bbs.mydigit.cn/read.php?tid=1653284

好的,讲了这么多理论的废话,还不如直接上代码实践
顺便说下,使用了部分stc的例程,按人家要求说明 : /* 如果要在文章中应用此代码,请在文章中注明使用了宏晶科技的资料及程序   */

#include <STC15F2K60S2.H> //MCU:stc15w404as
#include<stdio.h>
#include "intrins.h"
#define  uchar unsigned char  
#define uint  unsigned int
#define FOSC    11059200L
#define BAUD    9600
//工作频率11.0592MHz     串口波特率9600
//-----------------------------------------
//ADC相关设定参数
#define ADC_POWER   0x80            //ADC电源控制位
#define ADC_FLAG    0x10            //ADC完成标志
#define ADC_START   0x08            //ADC起始控制位
#define ADC_SPEEDLL 0x00            //540个时钟
#define ADC_SPEEDL  0x20            //360个时钟
#define ADC_SPEEDH  0x40            //180个时钟
#define ADC_SPEEDHH 0x60            //90个时钟
//-----------------------------------------
//BandGap相关参数
#define ID_ADDR_RAM 0xef        //对于只有256字节RAM的MCU(大部分系列)存放地址为0EFH
//#define ID_ADDR_RAM 0x6f        //对于只有128字节RAM的MCU(stc15f/w100系列)存放地址为06fH
//注意:需要在下载代码时选择"在ID号前添加重要测试参数"选项,才可在程序中获取此参数
//容量不同的单片机请更改不同数值
//#define ID_ADDR_ROM 0x03f7      //1K程序空间的MCU
//#define ID_ADDR_ROM 0x07f7      //2K程序空间的MCU
//#define ID_ADDR_ROM 0x0bf7      //3K程序空间的MCU
#define ID_ADDR_ROM 0x0ff7      //4K程序空间的MCU
//#define ID_ADDR_ROM 0x13f7      //5K程序空间的MCU
//#define ID_ADDR_ROM 0x1ff7      //8K程序空间的MCU
//#define ID_ADDR_ROM 0x27f7      //10K程序空间的MCU
//#define ID_ADDR_ROM 0x2ff7      //12K程序空间的MCU
//#define ID_ADDR_ROM 0x3ff7      //16K程序空间的MCU
//#define ID_ADDR_ROM 0x4ff7      //20K程序空间的MCU
//#define ID_ADDR_ROM 0x5ff7      //24K程序空间的MCU
//#define ID_ADDR_ROM 0x6ff7      //28K程序空间的MCU
//#define ID_ADDR_ROM 0x7ff7      //32K程序空间的MCU
//#define ID_ADDR_ROM 0x9ff7      //40K程序空间的MCU
//#define ID_ADDR_ROM 0xbff7      //48K程序空间的MCU
//#define ID_ADDR_ROM 0xcff7      //52K程序空间的MCU
//#define ID_ADDR_ROM 0xdff7      //56K程序空间的MCU
//#define ID_ADDR_ROM 0xeff7      //60K程序空间的MCU
//-----------------------------------------
//声明
void InitUart();
void InitADC();
void SendData(uchar dat);
uint GetADCResult(uchar ch);
void Delay(uint n);
void ShowResult(uchar ch);
void main()
{InitUart();                     //初始化串口InitADC();                      //初始化ADCP1M1=0X01;                        //高阻输入while (1){//ShowResult(0);              //显示通道0//ShowResult(1);              //显示通道1ShowResult(2);              //显示通道2//ShowResult(3);              //显示通道3//ShowResult(4);              //显示通道4//ShowResult(5);              //显示通道5//ShowResult(6);              //显示通道6//ShowResult(7);              //显示通道7Delay(100);}
}
/*----------------------------
发送ADC结果
----------------------------*/
void ShowResult(uchar ch)
{uint adc_res10,//测量设定通道adc值bandgap,       //bandgap预储存校准值,单位毫伏adc_9gallery_res; //测量第九通道(bandgap)值float power_voltage,        //系统供电电压,单位毫伏ADC_voltage;     //设定通道电压值,单位毫伏uchar  code *cptr; //定义ROM(代码)区指针//uchar  idata *iptr;//定义RAM(内存)区指针cptr = ID_ADDR_ROM;         //从程序区读取BandGap电压值(单位:毫伏mV)bandgap=*cptr++;bandgap<<=8;bandgap+=*cptr;/*iptr = ID_ADDR_RAM;         //从内存区读取BandGap电压值(单位:毫伏mV)bandgap=*iptr++;              //两种方法结果一样,上面的方法需要在下载式勾选"在ID号前添加重要测试参数"选项,才可在程序中获取此参数bandgap<<=8;                  //下面的方法不需要bandgap+=*iptr;    *///测量设定通道adc值ADC_RES = 0;                    //清除结果寄存器P1ASF = 0xff;                   //设置P1口为AD口GetADCResult(ch);GetADCResult(ch);                 //读三次获得稳定adc_res10= GetADCResult(ch);//测量第九通道(bandgap)值ADC_RES = 0;                    //清除结果寄存器P1ASF = 0x00;                   //设置读第九通道GetADCResult(0);                 //测bandgap时,调用此函数时通道数只能填0GetADCResult(0);                 //读三次获得稳定adc_9gallery_res=GetADCResult(0);//计算系统供电电压power_voltage=(float)bandgap*1024/adc_9gallery_res;//计算ADC通道测得电压值ADC_voltage=(float)bandgap*adc_res10/adc_9gallery_res;printf("P1.%d ADC result:%d\n",(uint)ch,adc_res10);printf("BandGap standard:%d mV\n",bandgap);printf("BandGap value:%d \n",adc_9gallery_res);printf("system power voltage:%.0f mV\n",power_voltage);printf("ADC voltage:%.0f mV\n",ADC_voltage);
}
/*----------------------------
读取ADC结果
----------------------------*/
uint GetADCResult(uchar ch)
{uint ADC_10BIT_RES;ADC_CONTR = ADC_POWER | ADC_SPEEDLL | ch | ADC_START;_nop_();                        //等待4个NOP_nop_();_nop_();_nop_();while (!(ADC_CONTR & ADC_FLAG));//等待ADC转换完成ADC_CONTR &= ~ADC_FLAG;         //关闭 ADCADC_10BIT_RES=ADC_RES;      //得到高8位ADC_10BIT_RES<<=2;ADC_10BIT_RES+=ADC_RESL;     //得到低2位return ADC_10BIT_RES;                 //返回ADC结果}
/*----------------------------
初始化串口
----------------------------*/
void InitUart()
{SCON = 0x5a;                //设置串口为8位可变波特率T2L = 0xE0;        //设定定时初值T2H = 0xFE;        //设定定时初值AUXR = 0x14;                //T2为1T模式, 并启动定时器2AUXR |= 0x01;               //选择定时器2为串口1的波特率发生器
}
/*----------------------------
初始化ADC
----------------------------*/
void InitADC()
{P1ASF = 0xff;                   //设置P1口为AD口ADC_RES = 0;                    //清除结果寄存器ADC_CONTR = ADC_POWER | ADC_SPEEDLL;Delay(2);                       //ADC上电并延时
}
/*----------------------------
软件延时
----------------------------*/
void Delay(uint n)
{uint x;while (n--){x = 5000;while (x--);}
}


 


http://chatgpt.dhexx.cn/article/0caiOerl.shtml

相关文章

带隙基准电压-Bandgap详细介绍

在模拟集成电路中需要“基准”提供稳定的直流电压、直流电流&#xff0c;这样的基准几乎不受电源电压、温度的影响&#xff0c;由Robert Widla在1971年发明带隙基准电压源技术后&#xff0c;一直广泛应用于ADC/DAC等产品中。例如&#xff0c;放大器的偏置电流采用电流镜的方式复…

电流模架构Bandgap设计与仿真

电流模架构Bandgap设计与仿真 0. Bandgap电压基准源 带隙基准作为集成电路中一个重要模块&#xff0c;被广泛应用在低压差线性稳压(LDO)、充电电池保护芯片和通信电路、射频收发器、flash存储器等多种模拟及数模混合集成电路中&#xff0c;并且是片上集成系统(SOC)芯片中不可…

微机原理 16-数据交换指令XCHG

交换指令 XCHG 的作用是把一个字节或一个字的源操作数与目的操作数相交换 注&#xff1a; 交换能在通用寄存器与累加器之间、通用寄存器之间、通用寄存器与存储器之间进行但段寄存器和立即数不能作为一个操作数&#xff0c;不能在累加器之间进行。如果需要交换两个内存操作数&…

LEA与XCHG

LEA 格式&#xff1a; LEA 通用寄存器 内存地址功能&#xff1a;取地址命令 将内存地址赋值给寄存器 lea eax,dword ptr ds:[ecx0x16]dword 双字 就是四个字节ptr pointer缩写 即指针ds 数据段版寄存器[]里的数据是一个地址值&#xff0c;这个地址指向一个双字型数据 将dwo…

X-nuca_2018_revenge(控制程序流程的新姿势+多字节的xchg指令会清零寄存器高位)

X-nuca_2018_revenge(多字节的xchg指令会清零寄存器高位) 首先&#xff0c;检查一下程序的保护机制 然后&#xff0c;我们用IDA分析一下&#xff0c;bss上存在无限溢出 由于该程序是静态编译&#xff0c;我们可以覆盖到下方某些函数指针&#xff0c;我们可以将__printf_arginf…

数据移动指令-----mov,lea,xchg

mov指令 数据传送指令 格式&#xff1a;MOV OPRD1,OPRD2 功能&#xff1a;将一个源操作数送到目的操作数中&#xff0c;即OPRD2—>OPRD1 OPRD1为目的操作数&#xff0c;可以是寄存器&#xff0c;存储器&#xff0c;累加器 OPRD2为源操作数&#xff0c;可以是寄存器&#xf…

8086汇编基础 xchg 交换数据

IDE : Masm for Windows 集成实验环境 2015     OS : Windows 10 x64typesetting : Markdown    blog : my.oschina.net/zhichengjiu    gitee : gitee.com/zhichengjiu code DATAS SEGMENT;此处输入数据段代码 DATAS ENDSSTACKS SEGMENT;此处输入堆栈段代码…

mov,xchg用法

mov是数值传送指令&#xff0c;格式为mov DST&#xff0c;SRC mov指令将源数据src传送到目的操作数dst中 传送的数据格式可以为2,16&#xff0c;32字节 xchg是数据交换指令&#xff0c;xchg实现寄存器和内存间的数据交换&#xff0c;两个交换数据的格式必须相同 欢迎使用Markd…

数据传送指令MOV、XCHG

学习过程中要重点掌握对标志寄存器的影响 数据传送类指令&#xff08;不影响标志位&#xff09; 一&#xff1a;MOV指令 先要知道图片中这几个英文表示什么 立即数&#xff08;immediaate operand&#xff09; 寄存器&#xff08;register&#xff09; 内存&#xff08;…

Java的逆序输出

如何将输入的1230&#xff0c;转换成321输出呢&#xff1f; 主要思想&#xff1a;对数进行取余获取最后一位&#xff0c;然后添加进字符串中&#xff0c;然后将字符串转化为int型。 实现方法代码&#xff1a; //逆序输出 public static int nsort(int n){String a"&quo…

一元多项式的乘法运算(C语言)实现

[PAT] 一元多项式的乘法与加法运算 C语言实现 [PAT] 02-线性结构1 一元多项式的乘法与加法运算 设计函数分别求两个一元多项式的乘积与和。 输入格式: 输入分2行&#xff0c;每行分别先给出多项式非零项的个数&#xff0c;再以指数递降方式输入一个多项式非零项系数和指数&…

一元多项式相乘

题目说明&#xff1a; 要求采用链表形式&#xff0c;求两个一元多项式的乘积&#xff1a;h3 h1*h2。函数原型为&#xff1a;void multiplication( NODE * h1, NODE * h2, NODE * h3 )。 输入&#xff1a; 输入数据为两行&#xff0c;分别表示两个一元多项式。每个一元多项式以…

多项式加法

多项式加法&#xff08;5分&#xff09; 题目内容&#xff1a; 一个多项式可以表达为x的各次幂与系数乘积的和&#xff0c;比如&#xff1a; 2x63x512x36x20 现在&#xff0c;你的程序要读入两个多项式&#xff0c;然后输出这两个多项式的和&#xff0c;也就是把对应的幂上…

【学习笔记】多项式乘法

文章目录 前置知识&#xff1a;复数引子&#xff1a;虚数定义计算性质 有关多项式点值多项式相乘大整数乘法 FFT \textit{FFT} FFT离散傅里叶变换快速傅里叶变换代码实现蝴蝶变换计算 ω n − x \omega_n^{-x} ωn−x​代码壹号 改进方案精度提升常数优化&#xff1a;二合一常…

多项式除法

多项式除法 应用场景 多项式的因式分解 使用 先试出有理根 r 多项式对线性因子 x - r 做多项式除法&#xff0c;逐步降低次数。 整除 : 结果就是商与被除数的乘积不整除 : 结果是商与余数/被除数的和 只到二次多项式&#xff0c;再利用十字相乘法或求根公式&#xff0c;即…

C语言 多项式乘法 算法

多项式乘法 什么是多项式&#xff1f; 由若干个单项式相加组成的代数式叫做多项式&#xff08;若有减法&#xff1a;减一个数等于加上它的相反数&#xff09;。 多项式中的每个单项式叫做多项式的项&#xff0c;这些单项式中的最高项次数&#xff0c;就是这个多项式的次数。 多…

多项式乘法入门

多项式乘法入门 By SemiWaker 这是一篇蒟蒻对FFT、DFT、CZT、NTT的弱鸡理解 多项式 a0xa1x1a2x2⋯an−1xn−1 上面的这个形式叫做多项式。 系数&#xff1a; a0..n−1 项&#xff1a; aixi 界&#xff1a;n 为了方便我们系数序列就可以表示多项式。 线性卷积 AB∑i02n−2(∑…

一元多项式的乘法与加法运算

题目要求 设计函数分别求两个一元多项式的乘积与和。 输入格式: 输入分2行&#xff0c;每行分别先给出多项式非零项的个数&#xff0c;再以指数递降方式输入一个多项式非零项系数和指数&#xff08;绝对值均为不超过1000的整数&#xff09;。数字间以空格分隔。 输出格式: 输…

多项式乘法运算初级版

快速傅里叶变换在信息学竞赛中主要用于求卷积&#xff0c;或者说多项式乘法。我们知道&#xff0c;多项式乘法的普通算法时间复杂度 是&#xff0c;通过快速傅里叶变换可以使时间降为&#xff0c;那么接下来会详细介绍快速傅里叶变换的原理。 首先来介绍多项式的两种表示方法&…

FFT与多项式乘法

网上关于FFT在信号处理中应用的文章并不少&#xff0c;这里尽量少说废话&#xff0c;直接说如何用FFT实现多项式乘法。 多项式乘法&#xff0c;通常是用系数乘积的方式完成&#xff0c;这样的时间复杂度是O(n^2) n为多项式项数。系数乘法可以满足大多数的乘法需求&#xff0c;然…