找回密码
 立即注册
查看: 56|回复: 3

在12位ADC 计算公式是除4096还是除4095是选择题而不是对错题

[复制链接]
  • 打卡等级:常住居民I
  • 打卡总天数:76
  • 最近打卡:2026-04-30 21:57:39

151

主题

1324

回帖

4902

积分

荣誉版主

积分
4902
发表于 2026-4-23 20:43:48 | 显示全部楼层 |阅读模式
ADC变换在单片机控制甚至在整个自动化控制领域都占有重要的一席之地,ADC变换也是一切数字探测器的基础。
对于在ADC转换公式ADCn通道的输入电压  = (转换结果 /4096)  * ADC_VRef+中的除法分母究竟应该是“除4096还是除4095”的问题一直是一个存在争议的问题。在网络上,在AI问答中,实际应用中、在教科书中,在各种手册中,选哪一个的都有。
本文是讨论单片机ADC变换的第3篇文章,在头两个帖子里,大家都对“除4096还是除4095”谁对谁错进行了讨论:

12位ADC 计算公式是/4096还是/4095;10位ADC 计算公式是/1024还是/1023
https://www.stcaimcu.com/thread-2438-1-1.html
(出处: 国芯人工智能技术交流网站)

关于12位ADC 计算公式是除4096还是除4095的问题讨论
https://www.stcaimcu.com/thread-23497-1-1.html
(出处: 国芯人工智能技术交流网站)

本文介绍了笔者用STC的打狗棒核心板实际做ADC转换实验的结果,通过实际实验结果想说明:
究竟是“除4096还是除4095”不是一道“谁对谁错”的对错题,而是一道“选谁或者不选谁”的选择题。
1)将P01管脚直接连接到VCC上,对应ADC09测量通道。
P02管脚直接连接到GND上,对应ADC10测量通道。
Fig_01_连接.jpg
2)直接使用打狗棒的STC官方例程中的“05-16ADC转换-串口2返回结果”,见附件1
3)将例程中的串口2程序修改为串口1输入输出(具体程序见附件2),运行程序得到以下的结果:               
[10:59:22.975]接收←ADC00=2760
[10:59:23.179]接收←ADC01=2783
[10:59:23.379]接收←ADC02=0613
[10:59:23.583]接收←ADC03=2803
[10:59:23.787]接收←ADC04=2768
[10:59:23.991]接收←ADC05=2771
[10:59:24.195]接收←ADC06=2767
[10:59:24.395]接收←ADC07=2746
[10:59:24.599]接收←ADC08=2773
[10:59:24.803]接收←ADC09=4092  
[10:59:25.007]接收←ADC10=0000  
[10:59:25.208]接收←ADC11=2772
[10:59:25.410]接收←ADC12=2777
[10:59:25.614]接收←ADC13=2764
[10:59:25.818]接收←ADC14=2766
[10:59:26.022]接收←Bandgap=1100
从中可以看到在这轮采样中,12ADC输入端的测量值连接VCC的为ADC09=4092,连接GND的为ADC10=0000
4)修改范例程序(修改后的程序见附件3),假定VCC=5.0000V,也就是假定在ADC转换公式ADCn通道的输入电压  = (转换结果 /4096)  * ADC_VRef+中的ADC_VRef+等于“VCC=5.0000V”,然后编程分别输出除以40954096的结果。
程序修改分两个地方,一个地方是只输出91015通道:
Fig_02_main.jpg
另一个地方是分别输出不同除数计算得到电压值:
Fig_03_ADC.jpg
1)修改了第143行,不进行16次采样平均,因为采样平均值很难到达4095.
2)增加了第164行和165行程序,分别计算了用40954096作为除数得到的电压结果。
3)修改第166行程序输出计算出来的结果。
5)下面是计算VCC5V电压的输出结果,由于有噪声,对VCC的采样结果不是每次都得到同样的值:
      ADC09=4095  4095->5.000000  4096->4.998779
      ADC10=0000  4095->0.000000  4096->0.000000
      Bandgap=1138  
     ------------
      ADC09=4095  4095->5.000000  4096->4.998779
      ADC10=0000  4095->0.000000  4096->0.000000
      Bandgap=1127  
      ------------
      ADC09=4093  4095->4.997558  4096->4.996338
      ADC10=0000  4095->0.000000  4096->0.000000
      Bandgap=1139  
      ------------
     ADC09=4095 4095->5.000000  4096->4.998779
      ADC10=0000  4095->0.000000  4096->0.000000
      Bandgap=1135  
6)从上面可以看到,如果是除以“4095”,则可以显示对VCC的采样的计算值是“5.000000”,而如果是除以“4096”,则可以显示对VCC的采样的计算值是“4.998779”。
7)假如一个工厂需要生产一款“数字电压表”,那么具体承担编写程序的工程师就需要做出一个具体的选择“是除4096还是除4095”,所以这实际上是一道选择题而不是对错题
8)既然是选择题,那么选什么答案就会依选择者的身份或者立场不同而不同:1)比如作为用户,我认为他肯定选择除“4095的那一款,原因是他明明已经知道被测电压是VCC,他明明已经知道VCC的电压值是VCC=5.0000V,他为什么不选择测量显示值已经等于“5.000000”的产品,非要选择一个测量显示值不等于5.000000”而是等于4.998779”的产品。
2)比如作为卖产品的售货员,我认为她肯定选择除“4095的那一款。毕竟向顾客解释清楚“4.998779”就等于“5.000000”是只差一个LSB的正常现象是一个高超难度的困难,这个难度不亚于向顾客推销一款新年钟声响起时却只显示时间“23:59:00”的电子钟的难度,那也是只差一个LSB
3)比如作为生产产品的老板,我认为他肯定选择除“4095”,因为电压表不过是一个日常工具,为什么要故意选择显示4.998779”人用户怀疑产品的质量呢?
4)比如作为上大学生“ADC原理”课的老师,我认为他肯定选择除“4096”,因为他当初学的书本上就那么写的。
5)比如作为上“ADC原理”课的大学生,我认为他肯定选择除“4096”,毕竟谁一定要跟考试成绩过不去呢?
9)既然是选择题,如果你是具体编写程序的程序员,或者你是一名研究生,我认为你应该像我一样,具体编写实验程序,同时給出两种选择的效果,然后交给你的老板或者老师,请他做出选择。
10)各位看官,你们就是我的老师,请你们告诉我你们的选择,最好能把你选择的原因也告诉我,谢谢!


附件1_05-16路ADC转换-串口2返回结果.rar (23.59 KB, 下载次数: 2)

附件2_ADC转换测试-串口1返回结果.rar (53.91 KB, 下载次数: 2)

附件3_ADC转换测试-5V_计算.rar (58.06 KB, 下载次数: 2)

回复

使用道具 举报 送花

  • 打卡等级:以坛为家III
  • 打卡总天数:784
  • 最近打卡:2026-05-01 00:00:40
已绑定手机

19

主题

3383

回帖

7207

积分

论坛元老

积分
7207
发表于 2026-4-23 23:31:18 | 显示全部楼层
个人感觉12位是除以4095
回复

使用道具 举报 送花

  • 打卡等级:以坛为家I
  • 打卡总天数:261
  • 最近打卡:2026-05-01 07:39:25

18

主题

246

回帖

568

积分

高级会员

积分
568
发表于 7 天前 | 显示全部楼层
12位ADC测电压时有个分辨率,5V*1/4096,ADC把转换结果分成了4096份,从0开始,到4095,总共4096个数,
当检测到电压>0,且没达到5*1/4096时,转换结果是0,
当检测到电压>5*1/4096,且<5*2/4096时,转换结果是1,
当检测到电压>5*2/4096,且<5*3/4096时,转换结果是2,


当检测到电压>5*4095/4096,且<5*4096/4096时,转换结果是4095,
总共0-4095,4096个数据,每个数据代表的不是一个绝对的电压值,而是很小区间的一个电压范围,
从实事求是角度看,我认为应是/4096,得出来的结果是否要给它+5*1/4096,就看个人喜好了,反正一个LSB也不是啥大事
从数据好看角度说,就直接/4095也行,把一个LSB的误差,均摊到整个转换结果宽度,也是不错的选择
回复

使用道具 举报 送花

  • 打卡等级:偶尔看看I
  • 打卡总天数:13
  • 最近打卡:2026-04-24 21:04:12

0

主题

21

回帖

250

积分

中级会员

积分
250
发表于 7 天前 | 显示全部楼层
上次查询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的物理工作原理完全一致。
回复

使用道具 举报 送花

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

本版积分规则

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

GMT+8, 2026-5-1 10:31 , Processed in 0.118488 second(s), 67 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

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