51单片机电流检测仿真:基于Proteus的采样电阻与ADC0832方案
2026/9/12 13:18:23 网站建设 项目流程

简介:51单片机作为嵌入式学习与工业控制中的经典芯片,结合电流检测能有效实现过流告警、负载监测等常见功能,在课程设计和毕业设计中应用广泛。这份Protues仿真实例面向单片机初学者与电子类专业学生,提供了一套无需真实硬件即可运行的51单片机电流检测完整仿真工程,覆盖电流采样、A/D转换、数据处理和阈值报警等关键环节。压缩包共12个文件,约30KB,包含Protues工程文件(DSN)、Keil C语言程序(C)、编译输出文件(HEX、OBJ、LST)以及工程配置文件(Uv2、Opt、Plg、M51等),打包了从电路搭建、源码编写到编译仿真的全部素材,解压后可直接打开仿真验证。目前已有578人浏览学习,说明该实例在同类资源中具备一定的参考价值。通过该实例可以直观理解霍尔效应等电流传感器将电流信号转换为电压信号,再由51单片机A/D转换器读取和计算的完整链路;同时也能学习到Keil工程创建、元件选型、参数设置与Protues联调等实操细节,适合用来对照练习、快速复现实验,或为后续扩展双路电流检测、串口上传等功能提供可移植的模板。

1. 用 Proteus 跑 51 单片机电流检测,先把仿真思路立起来

很多人第一次看到“Protues仿真实例-51单片机-电流检测”这个文件名,第一反应是打开Proteus放一个直流电流表,看表头读数。但一个能交作业的电流检测仿真,不是让你看表,而是让单片机自己把电流大小“读”回来:电流流过采样电阻产生电压,这个电压被放大后送给ADC,单片机读回数字量,再换算成安培数显示到LCD上。Protues只是Proteus的常见笔误,这在下载包里很常见,不用纠结。

这条链路里,最难的不是程序,而是“采样电阻、放大倍数和量程怎么配”。很多人把仿真跑完,程序也正常,就是显示值跟表头对不上,原因就是电阻分压和ADC参考电压没算清楚。这里按一个最常见、最可靠的仿真方案来讲:51单片机 + 采样电阻 + LM358 + ADC0832 + LCD1602。适合51单片机课程设计,也适合想搞明白电流检测信号链的新手工程师。

2. 电流检测的采样原理与 Proteus 元件选型

2.1 采样电阻法为什么最适合仿真

电流检测有三条常规路线:霍尔传感器、电流互感器和采样电阻。霍尔电流传感器需要磁芯和调理电路,Proteus里的模型不像真实芯片那样好配;电流互感器适合交流大电流,低频直流根本测不了。51单片机课程设计里测的通常都是低压直流回路,采样电阻法是物理上最直观、仿真里最好配的。

采样电阻法就是在电流回路里串一个小电阻,电流流过电阻后产生电压降,这个压降和电流成正比,测电压就等于测电流。如果一个0.1Ω电阻流过1A电流,两端电压是0.1V,这个电压太小,直接送ADC分辨率不够,所以要先经过运放放大到接近ADC参考电压,然后交给单片机。这就是“采样电阻+运放+ADC”的结构。

低侧检测和高侧检测的区别也要明白。低侧把采样电阻放在负载的接地端,电阻对地电压接近0,运放电路简单;高侧把采样电阻放在电源正极端,电阻两端都有较高共模电压,需要差分放大器。Proteus仿真和实际电路都建议先用低侧,等调通了再改高侧。

2.2 Proteus 里搭电流检测电路的元件清单

下面这张表是搭这个电路时常用的元件表,关键词和参数都列好,直接在拾取时搜就行。

作用Proteus关键词参数说明
主控AT89C5112MHz晶振51最小系统会自动复位
采样电阻RES0.1Ω功率选大一点,仿真没影响
可变负载POT10k可调仿真里被当作电位器变阻
运放LM358单电源5V双运放只用其中一路
ADCADC08328位串行3线控制,时序简单
稳压源DC POWER5V主电源给单片机和运放供电
显示LM016L16x2Proteus里面叫LM016L
电流表DC AMMETER-用来验证仿真结果

这里特别注意两个坑。第一,POT在Proteus里是电位器,不是固定电阻,点击上下箭头能改变阻值,用来模拟负载变化。第二,采样电阻阻值不能拍脑袋,0.1Ω适合2A级量程;如果手头的例子是用1Ω电阻做小电流毫安级检测,那负载和电源电压要跟着改,否则电阻压降会让负载端电位直接丢一半。

2.3 用 INA219 还是用 ADC+采样电阻?仿真里的取舍

很多人在搜INA219电压电流检测,想用I2C接口的电流检测芯片。这个方案在硬件上精度好,但在Proteus仿真里,你要写完整的I2C底层时序、读寄存器、换算数据,容易把真实目的带偏。ADC0832只需要CS、CLK、DI/DO三根线,逻辑简单,量程也够用。仿真阶段把ADC0832跑通,后面要换INA219时,采样电阻和放大倍数的设计逻辑完全不变,变的只是接口读写。

选ADC0832还有一个原因:它是8位串行ADC,51单片机可以直接用普通I/O模拟时钟时序。相比并行ADC,少占用8个引脚,程序也好调。下面这段Python算一下采样电阻和放大倍数怎么选,先解决量程问题:

I_max = 2.0 # 要测的最大电流,单位 A R_shunt = 0.1 # 采样电阻,单位 Ω V_ref = 5.0 # ADC 参考电压,单位 V s_v = I_max * R_shunt # 0.2 V gain_max = V_ref / s_v # 25 倍 print(f"采样电压 = {s_v} V") print(f"最大放大倍数 = {gain_max:.1f}")

这段代码先算出最大电流时采样电阻上的压降,再用ADC参考电压除以压降,得到运放最大放大倍数。比如2A配0.1Ω,Vref是5V,最大只能放大25倍。实际工程里我会留20%余量,取20倍以内,这样万一电流超一点,ADC也不会早早进满量程截断。如果要测200mA小电流,0.1Ω压降只有0.02V,放大25倍后也只有0.5V,ADC分辨率浪费大半,这时就把采样电阻换成1Ω,压降变大,信噪比也好。这就是为什么采样电阻和放大倍数要成对调整。

3. 在 Proteus 中搭出 51 单片机电流检测电路

3.1 最小系统与仿真工程初始化

Proteus画51电路最快的方式不是从零开始拖然后接一堆电阻,而是先放AT89C51,再放一个复位电路和一个电源终端。具体步骤:新建Design,在工具栏点Component Mode搜索AT89C51并放置,双击芯片把Clock Frequency改成12MHz;接着从Terminal Mode选择Power和Ground,给40脚VCC接电源、20脚GND接地。复位电路用一个10μF电解电容和10kΩ电阻,把RST引脚接到电容正极和电阻一端的交点,电阻另一端接地,这样上电时RST先高后低,单片机才正常启动。

在Proteus里做51单片机仿真,P0口必须接一个排阻上拉,否则P0输出高电平驱动不了LCD显示。我一般会用一个RESPACK-8排阻,公共端接VCC,8个引脚分别接P0.0-P0.7。这一步是Proteus和真实单片机最不一样的地方:真实板子上P0默认开漏,仿真里不加也会不稳定。最小系统搭完先放一个LED在P1口,跑一个点灯程序确认系统活了,再往后走。

3.2 采样电阻 + 运放放大 + ADC0832 的接线

电流检测主回路这样接:12V直流电源正极接负载(用POT代替)的一端,负载另一端接采样电阻,采样电阻下端接GND,这样电流就从12V正极流经负载、采样电阻回到地。因为采用低侧检测,采样电阻上端对地的电压就是我们要测的电压信号,LM358的同相输入端接到采样电阻上端,反相输入端直接接地,运放接成同相比例放大电路。反馈电阻用20kΩ,输入电阻用1kΩ,放大倍数约为21倍。

运放输出接到ADC0832的CH0,ADC0832的CS、CLK、DI、DO分别接51单片机的P1.0-P1.3。具体引脚关系列在下表:

ADC0832 引脚51单片机引脚作用
CSP1.0片选,低电平有效
CLKP1.1时钟信号,由单片机产生
DIP1.2配置输入
DOP1.3数据输出
CH0LM358 输出被测电压
VCC+5V供电
GNDGND接地

注意:Proteus里ADC0832的DI和DO是分开的,所以不用像网上有些图那样把两根线并在一起。如果你的模型只有一个数据脚,那也可以并,但这里用两引脚更省心。接到这里后,先用直流电压表点一下LM358输出脚,确认电位器从最小转到最大时,运放输出在0V到接近5V之间变化,如果超出了,说明放大倍数偏大,要减小反馈电阻。

3.3 把电流值换算成二进制编码的公式

ADC0832输出来的是一个8位二进制数,范围0-255,数值和电压是线性关系。假设ADC参考电压Vref=5V,那么读取到的电压V = adc_val * 5 / 255。放大前的采样电压 = V / Gain,电流I = 采样电压 / R_shunt。把三段合并,得到完整电流公式:

I = (adc_val * Vref / 255) / (Gain * R_shunt)

写成C语言宏就是:

#define VREF 5.0f #define R_SHUNT 0.1f #define AMP_GAIN 21.0f #define ADC_TO_CURRENT(adc) ((adc) * VREF / 255.0f / (AMP_GAIN * R_SHUNT))

有人问为什么不用乘法要连除,因为这里没有可以合并的整数系数。如果用ADC0832的满量程对照一下:adc=255时,V=5V,回推输入电压为5/21≈0.238V,电流=0.238/0.1≈2.38A,说明这个方案在12V电源下可以测到2A以上。要换量程时,改宏定义里的R_SHUNT和AMP_GAIN就行,其他代码不用动。

4. 51 单片机读取 ADC 并显示电流值的 Keil 代码

4.1 主循环与 ADC 读取时序

Keil工程里先定义引脚,再用普通IO模拟时序读ADC0832。读函数按channel选择CH0或CH1,代码里使用独立DI/DO引脚:

sbit ADC_CS = P1^0; sbit ADC_CLK = P1^1; sbit ADC_DI = P1^2; sbit ADC_DO = P1^3; unsigned char read_adc0832(unsigned char ch) { unsigned char i, dat = 0; ADC_CS = 0; ADC_CLK = 0; ADC_DI = 1; ADC_CLK = 1; ADC_CLK = 0; // 起始位 ADC_DI = 1; ADC_CLK = 1; ADC_CLK = 0; // SGL=1,单端模式 ADC_DI = ch; ADC_CLK = 1; ADC_CLK = 0; // ODD=ch,CH0或CH1 ADC_DI = 1; // 释放DI,准备读DO for (i = 0; i < 8; i++) { ADC_CLK = 1; dat = (dat << 1) | ADC_DO; // 上升沿后读数据位 ADC_CLK = 0; } ADC_CS = 1; return dat; }

这段时序的核心是先发送3位配置:第1位启动位固定1,第2位选择单端/差分模式,固定1表示单端,第3位选择通道,ch为0则选CH0。发送完配置后ADC0832的DO开始在主时钟上升沿逐个输出8位数据,最高位在前。Proteus模型对这个时序的宽容度比较高,但如果你发现读出来的数一直在255或0附近抖动,先查CLK线是不是连到P1.1了,再查读数据的时刻,有的模型需要在下降沿读。

这里有几个参数值得注意:ch取值只能是0或1,大于1会读到错通道;函数里dat初始为0,每读一位向左移一次,所以不要漏掉移位。返回的8位数据就是ADC原始值。

4.2 电流换算与 LCD1602 显示

拿到ADC值后,用前面定义的宏换算成电流。因为要显示小数,我用一个整型变量存储毫安值,避免在单片机里频繁做浮点打印。具体做法是先扩大1000倍算成毫安,再拆成整数部分和小数部分:

unsigned int current_mA = (unsigned int)(ADC_TO_CURRENT(read_adc0832(0)) * 1000.0f); // 例如 0.63A -> 630mA lcd_write_int(current_mA / 1000); lcd_write_char('.'); lcd_write_int(current_mA % 1000); lcd_write_char('A');

这块代码的逻辑是:先用浮点位运算得到以安培为单位的电流值,再乘1000转成整数毫安,这样就能避开printf库和浮点格式化输出。注意current_mA % 1000如果不足3位会显示成6,而不是006,所以显示前要对商补零,简单办法是判断小于100补'0',小于10补两个'0'。LCD1602的底层初始化函数和写数据函数用你手头现成的就行,Proteus里的LM016L和真实LCD1602指令兼容。

我没有在仿真里直接用%f,因为C51编译器对大格式浮点支持很别扭,函数库占空间不说,仿真速度还会变慢。按毫安整数显示,既满足课程设计的精度要求,又不用动printf全家桶。如果要求显示两位小数,就把倍数改成10000,补零逻辑不变。

4.3 仿真调试:用虚拟终端观测数据

LCD显示容易看出整体对不对,但想精确地看转换曲线,还是串口方便。在Proteus里给51单片机接一个Virtual Terminal,通过P3.0和P3.1做UART输出。Keil中初始化串口后,直接调用printf发送ADC值和毫安数:

void uart_init(void) { SCON = 0x50; TMOD |= 0x20; TH1 = 0xFD; // 9600bps @ 11.0592MHz TL1 = 0xFD; TR1 = 1; TI = 1; } void main(void) { unsigned char adc; unsigned int ma; uart_init(); while (1) { adc = read_adc0832(0); ma = (unsigned int)(ADC_TO_CURRENT(adc) * 1000.0f); printf("ADC=%d mA=%d\r\n", adc, ma); delay_ms(200); } }

这段代码里TH1=0xFD是针对11.0592MHz晶振的9600波特率,如果前面最小系统用的是12MHz晶振,串口频率会有误差,虚拟终端能看到乱码。解决方法是不要把晶振改回去,直接保留12MHz但把波特率重算成4800,或者干脆在Proteus里把晶振改成11.0592MHz重新仿真,代码不用动。P3.0和P3.1分别接虚拟终端的RXD和TXD,注意交叉连接。

5. 校准 Proteus 电流表与硬件实测的三点经验

5.1 在 Proteus 里放置电流表验证仿真精度

把DC AMMETER串到采样电阻和负载之间的支路上,运行仿真,旋转POT时记下电流表的安培数,和LCD上显示的值对比。正常情况下误差应该来自放大倍数的小数位,例如用21倍计算,但实际电阻标称是20k和1k,正好21倍,偏差很小。如果发现测量值固定偏大或偏小,优先级最高的是检查运放反馈电阻阻值,其次是LCD补零逻辑是否把中间的小数位吞掉了。可以在虚拟终端同时打印ADC原始值和电流值,对比电流表读数,这样能快速区分是硬件接线错还是换算错。

5.2 采样电阻的温漂与量程选择

仿真里电阻是理想器件,实际硬件里0.1Ω功率电阻温度升高后阻值会漂,影响满量程精度。如果你要把仿真搬去比赛,采样电阻要选低温漂的合金电阻,放大倍数不要顶满计算值,留20%裕量。量程也尽量往中段留:电位器旋到大半时,ADC值最好落在200左右,不要每次都在250以上跑,否则接近满量程时分辨率不够,显示值会一跳一跳的。

5.3 把仿真工程改造成可硬件下载的版本

把Proteus里AT89C51换成STC89C52或AT89S52,接线基本不变,下载用STC-ISP。晶振建议换成11.0592MHz,这样串口波特率才准,LCD1602和ADC部分不用改。负载端要加一个功率电阻,不能像仿真里那样直接用POT,否则电位器会烧。烧录前把P1.0到P1.3测量一遍确认没有接反,再上电看LCD第一行有没有稳定电流值,如果没有,先用万用表测LM358输出脚和ADC0832的CH0电压,确保0到5V的变化确实送到了ADC前端。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询