
简介一份基于STC15W408AS单片机实现的电流表设计资料包配合LCD1602显示屏实时呈现测量电流值适合电子爱好者、硬件工程师及嵌入式相关专业学生参考学习。项目采用STC15W408AS作为主控通过ADC采集电流传感器转换后的电压信号经数据处理后在LCD1602上显示完整覆盖了单片机编程、模拟信号调理、液晶驱动以及PCB布局设计等关键环节。压缩包共23个文件大小10.35MB包含C语言源程序、汇编启动文件、Hex烧录文件、Keil工程文件、原理图SchDoc、PCB PcbDoc以及预览文件等常用类型其中源程序涵盖初始化、ADC读取、数据处理和LCD1602驱动等模块原理图与PCB文件则可直接导入Altium Designer等工具查看或修改便于二次开发。目前已有1376人学习下载。对于希望掌握微控制器应用、电流测量技术或LCD显示驱动的读者这套资料提供了从原理到实现的完整参考具有很好的学习与借鉴价值。1. STC15W408AS电流表该从哪里下手模拟链路比代码更关键把一个“基于 STC15W408AS电流表设计 LCD1602 显示”的题目落地核心不只是单片机上写几行代码。电流表测量的是毫伏量级的小信号STC15W408AS 负责把电压量化成数字并驱动 LCD1602但真正决定精度的是前面那段模拟链路采样电阻怎么选、运放增益怎么配、PCB 上采样线怎么走。只要这三点不乱源程序的复杂度其实很低一个 8KB Flash 的增强型 51 完全能应对。适合自己动手画这套方案的场景很典型维修电源时想看清输出电流、给锂电池做放电监测、或者把充电器的输出电流实时显示出来。量程通常做 0.1A 到 10AADC 用芯片自带的 10 位分辨率就够了。网上搜“STC15W408AS 单片机手册”和“stc89c52rc lcd1602 最小系统板”能看到大量参考但它们多数只讲 LCD 驱动很少有人把原理图、PCB 与源程序连成一条完整链路。这篇就从电流采样开始一步步讲透。2. STC15W408AS 电流表原理图设计采样放大、ADC 引脚与 LCD1602 接线2.1 电流采样链路选型分流电阻加运放不用霍尔传感器画原理图第一步不是连单片机而是确定电流检测器件。霍尔电流传感器 ACS712 用起来方便自带 2.5V 偏置但它温漂大、磁滞明显你在 LCD 上看到数值慢慢漂移时往往很难判断是负载变了还是传感器飘了。更常规的做法是用毫欧级精密电阻做低端采样电流流过分流电阻产生压降再用一个普通运放把压降放大到 ADC 的输入范围。成本几毛钱精度却能靠元器件选型做到 1% 以内。低端采样的含义是把采样电阻放在负载和“电源地”之间运放输入端的共模电压接近 0V电路简单安全。要避免的是用 PCB 铜箔直接代替采样电阻铜箔电阻率虽低但会随温度变化一旦电流回路上的铜箔被算进采样区读数就会随散热条件漂移。分流电阻阻值由满量程压降决定。量程 5A 时我希望满量程压降 50mV 左右那么 R 50mV / 5A 10mΩ电阻自身功耗最大 250mW选 1W 封装就能把温升压下来。运放增益按 ADC 满量程留出 20% 余量来配参考值如下表量程采样电阻满量程压降运放增益满量程输出2A20mΩ40mV100 倍4.0V5A10mΩ50mV80 倍4.0V10A5mΩ50mV80 倍4.0V增益电路用一个运放搭同相放大即可增益 G 1 Rf/Rin。以 5A 档举例Rin 取 1kΩRf 取 79kΩ满量程输出 4.0VADC 每个字约 12.2mA。如果目标分辨率是 0.01A把量程降到 2A 档20mΩ 配合 100 倍增益会让小电流信号更舒展。运放选用 LM358、LM324 这类 5V 单电源轨到轨型号输出串联 100Ω 电阻再接 STC15W408AS 的 P1.0既能抑制走线上的容性负载也给 ADC 采样保持电容留出充电缓冲。2.2 STC15W408AS 引脚分配P1.0进ADCP2口驱动LCD1602STC15W408AS 的 ADC 通道全部挂在 P1 口上。运放输出接 P1.0对应 ADC 的第 0 通道。其余 P1 脚不要接数字信号避免数字翻转时通过引脚电容串扰到模拟输入。如果要用外部晶振P1.6/P1.7 可以被配置成 XTAL1/XTAL2但 STC15 内部 RC 振荡器精度用于这种显示类仪表完全够没必要浪费两个可做模拟输入的脚位。LCD1602 用 4 线模式比 8 位模式少 4 根信号线显示刷新速度对电流表任务绰绰有余。分配方式如下信号STC15W408AS 引脚说明RSP2.0寄存器选择0命令1数据ENP2.1使能脚下降沿锁存数据DB4–DB7P2.2–P2.5数据线高四位R/WGND固定写模式节省一个 I/OP2 口默认是准双向口内部带上拉可以直接驱动 LCD1602 的 CMOS 输入。P1 和 P3 口则各有用途P3.0/P3.1 是 ISP 下载脚P1.0 做模拟采集所以让 P2 专门掌管道显示最合适。LCD 的 VO 脚接一只 10kΩ 电位器中点从 5V 分压到 GND用来调对比度这个脚不接会出现“有字但看不清”的情况总被误判成程序问题。STC15W408AS 内部集成复位电路RST 引脚经过 10kΩ 电阻下拉到地即可不要悬空。下载代码时给板上电的时序要稍微留意ISP 工具要求先点下载、再上电与接线无关。2.3 电源与基准电压让 ADC 参考电压确实等于 VCC原理图上最后一块是供电。STC15W408AS 的 10 位 ADC 参考电压默认等于 VCC也就是说芯片引脚上实际多少伏ADC 的“满量程”就是多少伏。若用 7805 之类的 LDO 从 9~12V 降压到 5VVCC 上的纹波和压降会直接折算进测量结果所以电源去耦要严格一点。我习惯在电源输入端放 10µF 钽电容或电解电容紧贴 STC15W408AS 的 VCC 引脚再放一只 100nF 陶瓷电容两者间距不超过 3mm。LCD 背光电流约 20mA不要让它单独从 VCC 引脚附近取电背光开关造成的电压跌落会反映在 ADC 结果里。如果输入已经是 5V可以在电源座附近串一个磁珠再进模拟区域能挡掉一部分高频噪声。值得一提的是运放和 ADC 共用一个 5V 电源时运放的电源脚同样需要 100nF 去耦而且去耦电容的地要回到模拟地。这样整条链路的电源回路是干净的后续 PCB 布线才会轻松。3. STC15W408AS 电流表 PCB 布线开尔文走线、地平面与 3 个关键间距3.1 分流电阻上的开尔文走线铜箔不能算进采样回路原理图正确只算完成了三分之一PCB 布线才是这套电流表最容易出问题的环节。分流电阻只有 10mΩ满量程压降 50mV。如果你从电阻焊盘的电流进出点上直接引出两条采样线走线铜箔自身的内阻也会参与分压而铜箔电阻会随温度和电流变化读数的稳定性就没法保证。正确做法是把电流主回路和大信号回路分开。电流从输入端子的铺铜进来经过一块宽铺铜到达分流电阻的一个焊盘再从另一个焊盘用同样宽的铺铜出去接负载地采样线则从两个焊盘的侧边分别引出走一条尽量短、两条线尽量靠近的路径到运放输入。采样点落在电阻本体的两端铜箔上的压降自然被排除在外。这就是四线开尔文接法几乎是所有精密电流检测板都在用的标准做法。铺铜宽度方面35µm 铜箔下 1mm 宽走线大约能承受 1A 电流3A 以上的回路我把铺铜宽度做到 3mm 以上或者直接用一层覆铜。量程 10A 时建议选择 2oz 铜厚减小发热和压降。信号线则不需要宽0.3mm 足够重点是让它贴着地平面走减小环路面积。如果使用的 EDA 工具是 AD20画完铺铜后记得检查“铜皮挖空”区域把采样线周围不要的铺铜挖掉让模拟信号线周围保持一个干净的隔离带。PCB 上还要把分流电阻的焊盘开窗不让阻焊层盖住焊盘方便焊接也利于散热。3.2 模拟地与数字地分段后单点汇接PCB 上所有地并不是同一个电位。数字电路翻转瞬间会在铜箔上产生瞬态压降LCD 数据线每次刷新时背光电流也在跳动这些噪声若进入运放的参考地ADC 采集到的电压就会出现和显示同步的跳动。常规处理是把地分成模拟地和数字地两个区域。模拟地只包括分流电阻的 B 端、运放的 GND、ADC 输入周围的地数字地覆盖 STC15W408AS、LCD 接口和下载口。两个区域在电源入口处通过 0Ω 电阻或磁珠单点连接避免数字地电流穿过模拟区域。双面板的话底层尽量铺一整块地平面不要在地平面上开长槽否则地回流路径会被拉长。背光地属于数字地返回路径不要经过分流电阻下方的模拟地我习惯先布这个地再布其他信号线。如果地平面无法保证完整至少让电流主回路的铺铜和背光返回路径不要重叠在同一条细线上。3.3 三个容易翻车的位置采样线交叉、电源入口、分流电阻朝向第一处是采样线与数字信号线平行走长线。LCD 的数据线、下载口的信号线如果在采样线旁边平行超过 2cm开关噪声会通过互感耦合进去。我一般让采样线走底层用顶层地平面做屏蔽层必要的时候在采样线两侧加一圈地过孔围起来。它与其它信号交叉时保证垂直穿过避免长距离并行。第二处是电源入口滤波电容的位置。很多板子把大电解电容放在电源座旁边把 100nF 靠近 LCD结果模拟区域高频去耦不足。更合理的顺序是电源座 → 大电容 → 磁珠 → 板内 5V然后每个芯片电源引脚旁再放一个 100nF。分流电阻和运放不要放在电流入口的散热器正下方热气流会直接改变电阻温度。第三处是分流电阻的方向和焊接。丝印层上标注清楚电阻的朝向手工焊接时把 10mΩ 装成 100Ω 的情况不在少数。所有铺铜和走线完成后跑一遍 DRC重点关注“Minimum Solder Mask Sliver”这类阻焊桥宽度检查。网上关于“pcb 布线规则和技巧”的讨论很多但电流表这类板子最值得查的其实只有两条采样回路是否被铜箔污染以及模拟地是否被数字地电流穿过。4. 源程序实现LCD1602 驱动、ADC 采集与电流换算4.1 STC15W408AS 引脚定义与 LCD1602 4线初始化时序程序在 Keil C51 环境下编写包含官方芯片头文件后把用到的特殊功能寄存器明确写出来方便阅读#include STC15.H sfr P1ASF 0x9D; sfr ADC_CONTR 0xBC; sfr ADC_RES 0xBD; sfr ADC_RESL 0xBE; #define ADC_POWER 0x80 #define ADC_START 0x40 #define ADC_FLAG 0x20 #define LCD_RS P20 #define LCD_EN P21 #define LCD_D4 P22 #define LCD_D5 P23 #define LCD_D6 P24 #define LCD_D7 P25sfr关键字在 C51 中用来声明特殊功能寄存器的地址P1ASF控制 P1 口哪些引脚作为模拟输入ADC_CONTR管理 ADC 的电源、启动和完成标志。ADC_RES和ADC_RESL保存 10 位转换结果后面会看到怎么拼成完整的数值。LCD1602 的 4 线模式一次只能传半字节一个字节要分两次送。比这更关键的是初始化顺序液晶上电后默认处于 8 位模式必须连续发送三次0x03然后发送0x02才能把它切换成 4 位模式。这个切换一旦跳过后续所有命令都会乱掉。void LCD_WriteNibble(unsigned char d) { LCD_D4 (d 0x01) ? 1 : 0; LCD_D5 (d 0x02) ? 1 : 0; LCD_D6 (d 0x04) ? 1 : 0; LCD_D7 (d 0x08) ? 1 : 0; LCD_EN 1; Delay_us(5); LCD_EN 0; Delay_us(5); } void LCD_WriteCmd(char cmd) { LCD_RS 0; LCD_WriteNibble(cmd 4); LCD_WriteNibble(cmd); } void LCD_WriteData(char dat) { LCD_RS 1; LCD_WriteNibble(dat 4); LCD_WriteNibble(dat); } void LCD_Init(void) { Delay_ms(50); LCD_WriteNibble(0x03); Delay_ms(5); LCD_WriteNibble(0x03); Delay_us(200); LCD_WriteNibble(0x03); LCD_WriteNibble(0x02); LCD_WriteCmd(0x28); // 4位、2行、5x7点阵 LCD_WriteCmd(0x0C); // 开显示、关光标 LCD_WriteCmd(0x06); // 地址自动加1 LCD_WriteCmd(0x01); // 清屏 Delay_ms(2); }LCD_WriteNibble把参数的低 4 位分别送到 DB4–DB7然后拉高再拉低 EN液晶在下降沿锁存。写命令和写数据仅差在 RS 电平上所以两个函数只是把 RS 置成不同值。初始化顺序里的延时虽然短但每一个都是给液晶内部状态机用的不能全部省略尤其上电后的 50ms 等待是 LCD1602 手册要求的开机稳定时间。4.2 STC15W408AS 的 ADC 寄存器配置与连续采样ADC 初始化只需要两步把 P1.0 设为模拟输入然后打开 ADC 电源。启动转换时置位ADC_START等待ADC_FLAG变 1再手动清标志。转换结果是 10 位高 8 位存在ADC_RES低 2 位存在ADC_RESL的低端。void ADC_Init(void) { P1ASF 0x01; // P1.0 作为模拟输入 ADC_CONTR ADC_POWER; // 打开ADC电源 Delay_ms(2); // 等待ADC内部稳定 } unsigned int ADC_GetValue(void) { unsigned int val; ADC_CONTR | ADC_START; // 启动一次转换 while (!(ADC_CONTR ADC_FLAG)); ADC_CONTR ~ADC_FLAG; // 清转换完成标志 val (unsigned int)ADC_RES; val (val 2) | (ADC_RESL 0x03); return val; }P1ASF 0x01的含义是只有 P1.0 作为模拟输入通道其余 P1 口保持数字功能。ADC_CONTR的低 4 位可用来选择通道复位后默认是 0恰好对应 P1.0所以这里没有额外赋值。每次转换耗时在微秒级别查询标志位的方式完全可以接受。如果你用的是一颗 12MHz 内部时钟一次转换最多几十微秒16 次均值也不会拖慢任何节奏。4.3 电流换算、均值滤波与 LCD 显示刷新ADC 原始值要换算成毫安公式拆开写电压 V_adc(mV) adc × 5000 / 1024分流电阻压降 V_sense V_adc / 增益电流 I(mA) V_sense / R(mΩ)。代入 10mΩ、80 倍增益的电路参数代码如下#define R_SHUNT_OHM 0.010f #define AMP_GAIN 80.0f #define VREF_MV 5000.0f void ConvertAndDisplay(unsigned int adc_val) { float current_mA; long i_mA; char buf[16]; current_mA (float)adc_val * VREF_MV / 1024.0f / AMP_GAIN / (R_SHUNT_OHM * 1000.0f); i_mA (long)(current_mA 0.5f); sprintf(buf, I%4ld mA, i_mA); LCD_WriteString(buf); }(float)adc_val的强转是必须的否则 16 位无符号整数先乘VREF_MV会溢出。R_SHUNT_OHM * 1000.0f把 0.010Ω 换算成 10mΩ使电流结果直接落在毫安单位上。0.5f是做四舍五入把浮点误差留在显示以外。sprintf在 51 上会占用较多 Flash如果编译空间不够可以改成自写的十进制拼接十几行就能代替。主循环里连续采 16 次取平均再刷新显示每轮间隔约 180msvoid main(void) { unsigned char i; unsigned int sum 0; LCD_Init(); ADC_Init(); LCD_WriteString(Current:); while (1) { sum 0; for (i 0; i 16; i) { sum ADC_GetValue(); } sum 4; ConvertAndDisplay(sum); Delay_ms(180); } }16 次累加后右移 4 位相当于除以 16 的整数均值。均值的意义是压住 50Hz 工频纹波和测量噪声单次采样直接显示时液晶上最后一位通常会跳个不停。刷新间隔设在 180ms人眼看起来是连续变化的同时避免每次刷新时 LCD 内部操作造成的电源扰动反过来影响下一次采样。5. 校准与精度验证让读数稳定到 0.01A 的 3 个调整技巧电流表画完板、烧完程序不等于就能直接读数。最后剩下的事情是校准而校准的三个动作分别是调零点、标增益、验线性度。第一步调零点。电路上电预热 2 分钟后不接负载让测量回路电流为 0记录此时 ADC 均值作为adc_offset。运放的输入失调电压、分流电阻焊盘之间的热电势都会让读数偏出零点。把这个偏移保存在变量里每次换算前先减掉。第二步标增益。用一个可调恒流源或者高精度电子负载串入被测回路给一个 1.000A 的标准电流记录当前 ADC 减去零点后的值adc_diff那么增益校准系数 k 1000.0 / adc_diff。真正显示时用I_mA (adc - adc_offset) * k。采样电阻的标称误差、运放电阻的 1% 精度、VCC 基准偏差全部会被这个系数吸收。校准结果写进 STC15W408AS 内置 EEPROM下次开机自动读回不需要每次重新烧录。第三步验证线性度。给定 0.2A、1A、2A、3A、5A 五个电流点记录显示值和数字万用表的偏差。误差若集中在低电流端问题多半是零点没校干净若高电流端偏差递增则是运放输出接近饱和或分流电阻发热改变了阻值。要让读数稳定到 0.01A软件上可以再进一步16 次均值去掉最大值和最小值后再平均能抑制偶发的尖峰干扰。硬件上可以在运放反馈电阻两端并联一只 10nF 电容把带宽限制在几十 kHz 以内却不要一上来就加大电容否则方波电流信号的边缘会被削平。最后一个做法是检查背光影响把 LCD 背光用固定电阻点亮不经过任何 PWM 控制如果此时的 ADC 跳动比背光悬空时明显增加说明背光地线走到了模拟区域去 PCB 上把地线分开比写任何滤波函数都有效。经过这几步一块自制电流表就能在 5A 量程内做到显示值连续几次读数只差 0.01A 的水平。本文还有配套的精品资源点击获取