简介:这份资源面向51单片机初学者与电子设计课程实践者,提供一套基于ADS1110的4路电压测量完整方案,可解决多通道电压采集、显示与超限报警的典型设计需求。包内共41个文件,约577KB,涵盖C源码与头文件、Keil工程配置、原理图与PCB工程文件、流程图位图、元件清单表格、仿真工程及编译生成的hex文件等,从硬件设计到软件实现形成闭环。已有134人学习下载,适合课程设计、电子竞赛或自学参考。读者可据此掌握ADS1110的I2C驱动、LCD1602显示、0-10V量程处理及上下限蜂鸣器报警逻辑,并借助原理图、流程图与仿真文件快速复现和调试,省去从零搭建的时间。
1. 从一块能测四路电压的 51 板子说起:这套资源到底能干什么
如果你手头正好有一批 51 单片机,又需要同时盯住四路直流电压——比如电池组每节电芯的电压、传感器阵列的供电轨、或者实验台上几路可调电源的输出——那这套资源就是冲这个场景来的。它把 4 路电压测量做成了一个完整闭环:原理图、流程图、物料清单、仿真图、源代码全都在,核心是 STC89C52RC 这类经典 51 芯片配 ADS1110 这种 16 位 ADC,四路轮流采集,结果送显示。很多人第一反应是「51 的 IO 口不够、精度也不够」,但 ADS1110 是 I²C 接口,两根线就能挂上去,16 位分辨率对毫伏级测量完全够用,这就是它比直接用 51 内部 8 位 ADC 强的地方。这套东西适合谁?适合正在做课设、毕设、或者要快速搭一个多路电压采集原型的硬件和嵌入式从业者。你拿到手不是一堆散文件,而是一条从画板子到烧代码的完整链路,照着走就能复现。下面我按「资源是什么 → 怎么用 → 坑在哪」的顺序,把这份包拆开讲透。
2. ADS1110 与 51 的 I²C 对接:为什么选它、怎么连、代码怎么写
2.1 选型理由:16 位 ADC 挂在 51 上的现实考量
51 单片机自带的 ADC 通常只有 8 位,而且参考电压就是电源电压,测 5V 系统里 10mV 的波动基本看不清。ADS1110 是 TI 的 16 位、单通道、差分输入的 ΔΣ ADC,内部有可编程增益放大器(PGA),增益可以设成 1、2、4、8 倍,对应满量程 ±2.048V 到 ±0.256V。这意味着你测小信号时不用外加运放,直接切增益就能把分辨率压到微伏级。它用 I²C 通信,地址固定为 0x90(写)/0x91(读),51 这边用两个普通 IO 口模拟 I²C 时序就行,不需要硬件 I²C 外设——STC89C52RC 本来也没有。四路测量怎么实现?ADS1110 只有单通道,所以资源里用的是多片 ADS1110 或者外加模拟开关切换。从原理图和物料清单看,更常见的做法是四片 ADS1110 各自独立,51 通过 IO 口分时选通或者用 I²C 多路复用器。这里要留意:ADS1110 地址固定,不能像 ADS1115 那样改地址,所以四片同时挂一条 I²C 总线会冲突。资源里的方案我推测是用 74HC4052 这类模拟开关做通道切换,或者干脆用四个独立 IO 模拟四组 I²C。具体以你拿到的原理图为准,但选型逻辑是清楚的:要 16 位精度、要差分、要省 IO,ADS1110 是 51 平台上很务实的选择。
2.2 硬件连接:电源、基准与 I²C 上拉的细节
先看电源。ADS1110 的 VDD 范围是 2.7V 到 5.5V,和 51 的 5V 系统可以直接共电源。但要注意它的 REF 引脚——ADS1110 内部基准是 2.048V,REF 引脚是基准输出,不是输入,不要在外面再灌电压。I²C 的 SDA 和 SCL 必须接上拉电阻,典型值 4.7kΩ 到 10kΩ,接到 VDD。51 的 P0 口是开漏的,如果拿 P0 口做 I²C,外部上拉是必须的;用 P1/P2/P3 的话内部有弱上拉,但为了波形干净,还是建议外加 4.7kΩ。四路切换如果用模拟开关,比如 74HC4052,它的通道选通由 51 的两个 IO 控制,公共端接 ADS1110 的输入。这里有个容易翻车的地方:模拟开关的导通电阻会影响测量精度,74HC4052 的 Ron 大概几十欧姆,如果被测信号源内阻也大,分压误差就出来了。所以资源里如果用了模拟开关,前端最好加电压跟随器,或者选低 Ron 的开关。物料清单里应该列了这些器件,你对照着看。
2.3 51 端 I²C 模拟时序与 ADS1110 配置字
下面这段代码是 51 用普通 IO 模拟 I²C 读写 ADS1110 的核心逻辑。我按常见做法补全,你拿到源代码后可以对照。
// 假设 SCL 接 P1.0,SDA 接 P1.1 sbit SCL = P1^0; sbit SDA = P1^1; // I2C 起始信号 void I2C_Start() { SDA = 1; SCL = 1; delay_us(5); SDA = 0; delay_us(5); SCL = 0; delay_us(5); } // 写一个字节,返回从机应答 bit I2C_WriteByte(unsigned char dat) { unsigned char i; bit ack; for(i = 0; i < 8; i++) { SDA = (dat & 0x80) ? 1 : 0; dat <<= 1; delay_us(2); SCL = 1; delay_us(5); SCL = 0; delay_us(2); } SDA = 1; // 释放 SDA 等待应答 delay_us(2); SCL = 1; delay_us(5); ack = SDA; // 读应答位,0 为应答 SCL = 0; delay_us(2); return ack; } // 配置 ADS1110:连续转换,增益 1,16 位 void ADS1110_Config() { I2C_Start(); I2C_WriteByte(0x90); // 写地址 I2C_WriteByte(0x0C); // 配置字:连续模式,增益1,16位 I2C_Stop(); }逻辑说明:I²C 起始后先发写地址 0x90,然后发配置字。ADS1110 的配置寄存器 8 位,bit7 是状态位(只读),bit6-4 是增益设置,bit3 是模式(0 连续,1 单次),bit2-0 是数据速率。0x0C 对应二进制 0000 1100,即增益 1、连续转换、速率 15SPS。参数怎么改?要测小信号就把增益调高,比如增益 8 对应配置字 0x8C 左右,但注意输入电压不能超过满量程,否则输出会饱和。数据速率越高,噪声越大,15SPS 是最稳的。读数据时,ADS1110 输出 3 个字节:高 8 位、低 8 位、配置寄存器。转换结果是一个 16 位有符号数,正满量程 0x7FFF,负满量程 0x8000。电压换算公式:V = (code / 32768) * 2.048 / 增益。比如增益 1 时,code 为 16384 对应 1.024V。
2.4 四路轮询的软件流程与流程图对应
资源里给了流程图,我按常见实现描述一下。主循环里,51 先选通第一路模拟开关,延时让信号稳定,然后启动 ADS1110 转换,等待转换完成(连续模式下读配置寄存器 bit7 判断),读回 3 字节数据,换算成电压,存到数组。接着切到第二路,重复。四路都读完,送 LCD1602 或者数码管显示。流程图里应该有一个「通道计数」变量,0 到 3 循环。这里的关键参数是通道切换后的稳定延时,一般给 1ms 到 10ms,取决于模拟开关和前端 RC 时间常数。如果延时不够,读数会跳。源代码里这个延时通常用 delay_ms 实现,你可以根据实际信号源内阻调整。
3. 从原理图到仿真:物料清单核对与 Proteus 联调
3.1 物料清单逐项核对:别漏了去耦电容和晶振
拿到物料清单,先别急着下单,对着原理图过一遍。51 最小系统部分:STC89C52RC、11.0592MHz 或 12MHz 晶振、两个 30pF 瓷片电容、10uF 电解电容加 10kΩ 电阻做复位。ADS1110 部分:四片 ADS1110(或者一片加模拟开关)、0.1uF 去耦电容每片一个、4.7kΩ 上拉电阻两个。显示部分:LCD1602 加 10kΩ 电位器调对比度,或者数码管加 74HC595。模拟开关部分:74HC4052 加若干限流电阻。电源部分:7805 或者直接 USB 5V 供电,加 100uF 和 0.1uF 滤波。常见遗漏是 ADS1110 的 VDD 去耦电容,很多人只放一个 0.1uF 在板子边缘,离芯片远,结果读数噪声大。正确做法是每个 ADS1110 的 VDD 引脚旁边紧挨着放一个 0.1uF。另外,I²C 上拉电阻不要省,51 的 P1 口内部上拉很弱,波形上升沿会变缓,高速时通信失败。
3.2 Proteus 仿真:加载 HEX 与虚拟终端观察
资源里的仿真图是 Proteus 工程。打开后,双击 51 芯片,在 Program File 里加载编译好的 HEX 文件,晶振频率设成和代码一致。ADS1110 在 Proteus 里可能没有现成模型,常见做法是用 I²C 调试器或者用电压源加模拟开关替代。如果仿真图里用了 I²C 器件,检查一下上拉电阻有没有画上。运行仿真,观察 LCD 显示的四路电压值。你可以拖动电压源滑块改变输入,看显示是否跟着变。这里有个坑:Proteus 的 I²C 时序比较严格,如果 51 模拟 I²C 的延时太短,仿真会通信失败,但实际硬件可能能跑。所以仿真通过不代表硬件一定通过,反之亦然。我一般会在仿真里把延时调大一点,先保证逻辑通,再在硬件上优化速度。
3.3 源代码编译与下载:Keil 工程设置要点
源代码是 Keil C51 工程。打开 .uvproj 文件,检查 Target 里的晶振频率是否和你板子一致,Output 里勾选 Create HEX File。编译前确认头文件路径包含正确,比如 LCD1602 的驱动文件。如果报错「无法打开 xxx.h」,就在 C51 选项卡的 Include Paths 里加上对应目录。编译通过后,用 STC-ISP 下载工具烧录。STC89C52RC 需要冷启动:点下载按钮,然后给板子断电再上电。如果一直显示「正在检测单片机」,检查串口线、电源和晶振。下载软件的代码在资源里应该也有,但通常直接用官方 STC-ISP 就行。
4. 避坑与排查:四路电压测量里最容易翻车的五个点
4.1 读数跳动大,最后一位不稳
现象:LCD 显示电压值末位来回跳,比如 1.234V 变成 1.236V 又变回去。原因:ADS1110 的基准噪声、电源纹波、或者 I²C 通信受干扰。解决:先检查 ADS1110 的 VDD 去耦电容是否紧贴引脚,再检查模拟输入线是否远离晶振和数字信号线。如果还跳,把数据速率降到 15SPS,或者在软件里做多次采样取平均。我一般会连续读 8 次,去掉最大最小再平均,能压住大部分跳动。
4.2 某一通道读数始终为 0 或满量程
现象:四路里有一路不管怎么调输入,显示都是 0.000V 或者 2.048V。原因:模拟开关选通信号没接对,或者该通道的 ADS1110 没应答。解决:用万用表量模拟开关的控制脚,看切换时电平有没有变化。如果控制脚正常,再量 ADS1110 的输入脚电压是否跟随信号源。如果输入脚正常但读数不对,检查该片 ADS1110 的 I²C 地址是否冲突——四片地址一样的话,总线会打架。这时候要么用模拟开关共用一片 ADS1110,要么给每片单独分配 IO 模拟 I²C。
4.3 I²C 通信完全没反应
现象:上电后 LCD 无显示或者显示乱码,读 ADS1110 一直返回 0xFF。原因:上拉电阻没接、SDA/SCL 接反、或者 51 的 IO 口模式设错。解决:先量 SDA 和 SCL 在空闲时是不是高电平,如果不是,检查上拉电阻。再检查代码里 sbit 定义的引脚和原理图是否一致。STC89C52RC 的 P0 口做 I²C 必须外接上拉,P1/P2/P3 可以内部弱上拉但建议外加。如果用的是 P0 口又没加上拉,波形根本拉不高,通信必挂。
4.4 仿真通过但硬件不工作
现象:Proteus 里跑得好好的,烧到板子上没反应。原因:仿真模型和实际芯片时序差异、或者硬件焊接问题。解决:先量 51 的晶振有没有起振,用示波器看 XTAL2 脚有没有正弦波。再量复位脚电压,上电瞬间应该是高电平然后降到低。如果晶振不起振,换晶振或者调整负载电容。另外,Proteus 里 ADS1110 模型可能简化了时序,实际芯片对 I²C 的建立保持时间有要求,把代码里的 delay_us 调大一点试试。
4.5 四路切换时互相串扰
现象:第一路接 1V,第二路接 2V,但第一路显示受第二路影响。原因:模拟开关通道间隔离度不够,或者 PCB 布局时模拟走线太近。解决:在模拟开关的每个输入通道加 RC 滤波,比如 1kΩ 加 0.1uF,截止频率约 1.6kHz,能滤掉串扰。PCB 上把四路模拟走线分开,不要平行走长距离。如果还不行,换用继电器或者光耦切换,但成本高。一般课设场景,加 RC 就够了。
5. 进阶技巧:用状态机重构四路采集,顺带把精度再提一档
如果你已经跑通了基础版本,想让代码更稳、更容易扩展,我建议把主循环里的轮询改成状态机。51 单片机做状态机很合适,不占资源,逻辑清晰。下面是一个四路采集状态机的骨架:
typedef enum { CH0_SELECT, CH0_WAIT, CH0_READ, CH1_SELECT, CH1_WAIT, CH1_READ, CH2_SELECT, CH2_WAIT, CH2_READ, CH3_SELECT, CH3_WAIT, CH3_READ, DISPLAY_UPDATE } State_t; State_t state = CH0_SELECT; unsigned int voltage[4]; unsigned char ch = 0; void main() { while(1) { switch(state) { case CH0_SELECT: select_channel(0); state = CH0_WAIT; break; case CH0_WAIT: if(delay_elapsed(5)) state = CH0_READ; break; case CH0_READ: voltage[0] = read_ads1110(); state = CH1_SELECT; break; // 同理处理 CH1、CH2、CH3 case DISPLAY_UPDATE: display_voltage(voltage); state = CH0_SELECT; break; } } }逻辑说明:每个状态只做一件事,选通、等待、读取、显示分开。delay_elapsed 可以用定时器中断计数实现,不阻塞主循环。这样四路采集互不干扰,而且加一路只需要加三个状态。参数方面,等待时间根据模拟开关和 RC 常数设,我一般给 5ms。读取 ADS1110 时,连续读三次,取中间值,能进一步压噪声。另外,ADS1110 的 PGA 可以每路单独设增益——如果某路信号小,就在那个状态里改配置字,读完再改回来。这个技巧在测电池组时特别有用,每节电芯电压范围不同,动态切增益能让每一路都用到接近满量程,精度最大化。
验证方法:拿一个高精度万用表做基准,同时测同一路电压,对比 LCD 显示值。如果误差在 ±2mV 以内,说明 16 位 ADC 的性能发挥出来了。如果误差大,先查基准——ADS1110 内部基准是 2.048V,但实际芯片有初始误差,可以软件校准:测一个已知电压,算修正系数。我习惯在代码里留一个校准数组,每路一个系数,上电时从 EEPROM 读。从那以后我每次做多路采集,都强制走一遍状态机加软件校准,再也没出现过通道串扰和末位乱跳。希望帮到你。
本文还有配套的精品资源,点击获取