yangsifei 发表于 2026-4-22 22:03:42

你说的没错无论用什么公式调试出来结果都一样,关键是硬件只有4095个值啊,不争心不平。就算我明知道要死但是我每天要吃饭争口气是一个道理。

tjx588 发表于 2026-4-23 09:03:50

不如问下AI:
在将12位ADC的采样值转换为电压时,正确的做法是除以4096。
这是一个在嵌入式开发中非常经典的问题,很多开发者都会有此疑问。下面为你详细解释为什么是4096,而不是4095。
🤔 为什么是 4096?
要理解这个问题,关键在于区分两个概念:“量化区间的总数”和“数字输出的最大值”。
量化区间总数是 4096
一个12位的ADC,其分辨率是12位,意味着它可以将参考电压(Vref)范围(例如0V到3.3V)等分为 2^12 个离散的区间。
2^12 = 4096
所以,整个电压范围被切成了 4096个 小台阶,每个台阶的宽度被称为 1个LSB (Least Significant Bit,最低有效位)。
1 LSB = Vref / 4096
数字输出的最大值是 4095
ADC转换后输出的是一个数字码。由于数字系统从0开始计数,这4096个区间对应的数字码范围是 0 到 2^12 - 1。
2^12 - 1 = 4095
因此,ADC能输出的最大数字值是 4095。
⚙️ 转换公式的推导
ADC的转换过程,本质上是将输入的模拟电压(Vin)映射到它所属的那个量化区间,并输出该区间的编号(即数字码)。
数字码 (ADC_value) = 0 代表输入电压在第一个区间 [0, 1 LSB) 内。
数字码 (ADC_value) = 1 代表输入电压在第二个区间 [1 LSB, 2 LSB) 内。
...
数字码 (ADC_value) = 4095 代表输入电压在最后一个区间 [4095 LSB, 4096 LSB) 内。
所以,一个数字码 N 代表的电压值,就是 N 个LSB的宽度。由此可以推导出计算输入电压的公式:
Vin = ADC_value × 1 LSB = ADC_value × (Vref / 4096)
整理后就是我们最终使用的公式:
Vin = (ADC_value × Vref) / 4096
⚠️ 为什么除以 4095 是错的?
如果使用 Vin = (ADC_value × Vref) / 4095 这个公式,会带来一个系统性的增益误差。
当ADC采样值达到最大值4095时,我们期望它代表接近参考电压Vref的值。但用错误的公式计算:
Vin = (4095 × Vref) / 4095 = Vref
这看起来似乎是对的,但它错误地假设了数字码4095就精确地等于Vref。实际上,数字码4095代表的是一个电压范围,其中心点或理想值是 4095.5 * (Vref / 4096),而整个ADC的量程上限(即4096个区间的终点)才是Vref。
使用除以4096的正确公式,当ADC值为4095时:
Vin = (4095 × Vref) / 4096 ≈ 0.99976 × Vref
这个结果准确地反映了4095这个数字码所代表的电压是“略低于参考电压Vref”的,这与ADC的物理工作原理完全一致。

yangsifei 发表于 2026-4-23 17:30:32

{:4_199:}哦,你这么一说我突然茅塞顿开,我一直勿略了一个问题没把0当数看,
其实是0-4095是4096个LSB,也就是4097个点。
如果比较器在0.5个LSB翻转那么它的精度相对较低,但是读数更稳.
如果比较器在1个LSB翻转那么它的精度相对较高,但是读数没那么稳。

yangsifei 发表于 2026-4-23 17:37:56

当REF为5V时读出0的时候其实就是显示0.00122电压值。

yangsifei 发表于 2026-4-23 17:41:43

读出4095的时候其实就是显示0.00122X4096电压值

yangsifei 发表于 2026-4-23 17:44:19

好奇妙的感觉,看0不是零{:4_174:}

lcwswust 发表于 2026-4-28 00:01:18

杨为民 发表于 2026-4-22 14:18
我也不知怎么让你得出“耍嘴皮子”的看法,敢不敢赌一把?



简单测试了一下,或许你的说法是对的,ADC脚电压要非常接近VREF才能得到4095的值;
或许我的测试方法有问题,数值不是很稳定。
测试方法:“可编程电阻器”(接VREF,C5处,AI8051U实验箱为3.3V,与VCC相同)与10K电阻(接地,C5处)串联分压,ADC测量这个分压值(C24处)。
    代码是在例程“16-ADC检测16个按键”里改的,用数码管后四位显示ADC结果。
    代码:
测试结果:
    当“可编程电阻器”阻值设置为不大于0.2欧时(电压约0.066mV),ADC值有较大概率是4095,
    当“可编程电阻器”阻值设置为1欧时(电压约0.33mV),ADC值有较大概率是4094;
    本来按我的理论,若是电压4096等分,每份电压为3300/4096=约0.8mV,当“可编程电阻器”阻值在不大于2.4欧,ADC值就应是4095,
    实际确差得有点远,莫非ADC引脚内部的模拟开关有压降?
    以为实验箱的PCB引线比较长可能存在干扰,所以买了一块很小的核心板测试,也是差不多的结果。
    另外我也在开天斧三.2(STC8H8K64U)与屠龙刀三.2(STC32G12K128)上用类似方法测试,结果却更差,ADC脚与VREF短接时也很小概率出现4095。




另一个测试结果,想看一下10位ADC的表现如何,单片机是STC15W408AS,VCC约5V:
   代码:
   “可编程电阻器”接VCC,与10K电阻(接地)串联分压;
   当“可编程电阻器”电压不大20.0mV时,ADC值为1023;
   当“可编程电阻器”电压不大24.2mV时,ADC值为1022;
   按我的理论,若是电压1024等分,每份电压为5000/1024=约4.9mV,当“可编程电阻器”电压大于4.9mV时,ADC值就应是1022才对,
   实际却需要更大的电压降才行,莫非是VREF在内部低于了VCC?




杨为民 发表于 2026-4-28 12:53:47

lcwswust 发表于 2026-4-28 00:01
简单测试了一下,或许你的说法是对的,ADC脚电压要非常接近VREF才能得到4095的值;
或许我的测试方法有问 ...
(1)作为程序员,比在写程序的时候只能写一行程序,程序中必须选择做个唯一的选择:是4096或者是4095。所以我写了另一篇文章供你参考。

在12位ADC 计算公式是除4096还是除4095是选择题而不是对错题
https://www.stcaimcu.com/thread-23569-1-1.html
(出处: 国芯人工智能技术交流网站)

我在上面文章中列举的观点是不同身份的人有不同的选择,程序员听老板的选择。
(2)看到你的实验照片,我回想起30多年前为云南烟叶收购做的电子秤,当时使用的单片机是Intel8096,片上没有ADC(8097才有10位),购买到的ADC芯片ADC0809只有8位,而要求是300公斤量程正负10克。
因此只能利用8096的16位计数器自己设计电路制作了15位的双积分ADC。按用户要求数码管显示到XXX.ZZZ公斤,小数点后三位。
然后到质检局审批合格证,人家就是放10公斤、1公斤的 砝码,要求小数后显示的是".000",不会听你解释什么LSB的。
(3)很高兴你提供了另一种选择:工程师应该做实验来选择。也很高兴看到你的结果:
简单测试了一下,或许你的说法是对的,ADC脚电压要非常接近VREF才能得到4095的值;或许我的测试方法有问题,数值不是很稳定。
看你使用了标准电阻板,我认为你的测试方法是正确的。
(4)感谢你愿意动手来验证ADC公式的正确性,送999朵小红花


(5)不好意思,我的星愿不足


我不知道我有多少星愿,我都送给你吧


杨为民 发表于 2026-4-28 13:06:46

(1)我不知道我有多少星愿,我想知道,把它全部送出,怎么办?每次10个10个地送?

(2)菩萨把着方向盘,让我为大家展示一次ADC变换的原理:用对半法!
(3)大家可以在楼上看我的演示过程

杨为民 发表于 2026-4-28 13:11:10

lcwswust 发表于 2026-4-28 00:01
简单测试了一下,或许你的说法是对的,ADC脚电压要非常接近VREF才能得到4095的值;
或许我的测试方法有问 ...

送999不成功
送512成功,但不让送了
你回个贴,下次我送256试试?
页: 1 2 3 4 5 [6]
查看完整版本: 关于12位ADC 计算公式是除4096还是除4095的问题讨论