51单片机简易充电桩设计:继电器驱动与状态机实现
简介这是一份基于51单片机的简易充电桩完整课程设计资料包主要面向单片机初学者、电类课程设计学生以及需要快速搭建充电控制实验的开发者。压缩包共含43个文件总计829KB内容编排上兼顾源码、设计与仿真C语言源程序、头文件与Keil工程文件用于编译烧录Proteus的DSN仿真图便于验证逻辑原理图与PCB文件辅助硬件制作还附带流程图、元件清单和说明文本方便从零理解项目架构。系统具体功能包括利用LCD1602显示屏实时显示充电电压充电完成后蜂鸣器主动提示以及通过串口向PC端发送当前电压值涉及ADC0832采样、显示驱动和串口通信等多个常见知识点。目前已有267人学习下载资料体量虽小但链条完整能帮助读者节省自行整理原理图、绘制流程图和搭建仿真环境的时间适合作为课程设计参考或毕业设计预研。1. 为什么“51单片机简易充电桩”仍值得手工搭一遍实验室里搭一套“简易充电桩”最花时间的往往不是51单片机编程而是继电器驱动逻辑ULN2003输入高电平时输出端才导通代码却按低电平触发去写仿真里看不出毛病一接实物继电器根本不吸合。这个题目本质上是把投币、计量、倒计时、断电四件事压成一个状态机原理图、流程图、物料清单、仿真图、源代码这五样交付物每一件都在逼你把状态机写清楚。适合正在做课设的电子、自动化方向学生也适合想快速验证“单片机继电器控制”思路的入门工程师能把这块板子调明白基本就掌握了一类强电控制产品的设计套路。2. 原理图拆解从220V入口到51单片机引脚的信号链路原理图不要一开始就画控制部分而是先按“功率链路”和“弱电链路”两路分开画。功率链路是220V进线、保险丝、继电器常开触点、输出插座弱电链路是变压器降压、整流稳压、51单片机最小系统、显示和采样。两条链路之间靠继电器隔离采样靠电流互感器隔离这样才能在答辩时讲清楚“强电与弱电分离”的设计原则。画原理图之前先确定一个关键数字负载功率。演示用的充电桩接白炽灯或电阻负载按2kW以内设计进线端串一只5A快熔保险丝控制电路单独用一只220V转9V的小变压器供电功率2W就够。如果题目要求输出侧也带隔离稳压电源部分可以再加个5W变压器但简易方案不必做那么复杂。2.1 供电链路变压器降压、整流与7805稳压的设计要点控制部分的电源拓扑是220V转9V变压器 → 全桥整流 → 7805 → 5V直流输出。整流后面建议接一个470uF/16V电解电容和0.1uF瓷片电容7805输入端再放0.33uF输出端放0.1uF去耦。整个控制电路峰值电流大约100mA其中继电器的70mA占大头7805在小负载下不需要额外散热片。这里要提醒一个常见误用不要为省成本选阻容降压。阻容降压不隔离触摸到板子任何裸露焊点都可能触电而且继电器通断瞬间会对单片机造成强烈干扰。变压器方案虽然多花十几块钱但是课设评审里最稳妥的安全设计。7805输出固定5V后AT89C52或STC89C52RC直接供电即可。节点参数说明变压器次级9V AC / 2W空载实测约11V整流后峰值约15V7805输入约12V DC电解电容470uF瓷片0.1uF7805输出5V DC输出端0.1uF去耦继电器线圈供电5V DC与单片机电平一致可直接用ULN2003驱动2.2 计量与电力采集电流互感器采样与LM393脉冲整形简易充电桩不需要高精度电能计量但要能给评审演示“充电中确实有电流在走”。常见做法是用开口式电流互感器穿在220V火线上次级并接采样电阻后得到交流电压信号再用LM393比较器把交流信号整形为方波脉冲单片机对脉冲计数即可得到与电流相关的计量事件。以变比1000:1的开口互感器为例一次侧5A满载二次侧电流为5mA采样电阻取100Ω则满载信号电压为500mV。LM393反相端用电位器设置一个250mV阈值同相端接互感器采样信号输出端接10k上拉到5V输出引脚直接连单片机INT1或P1.2。这个方案的优点是成本低且仿真阶段可以拿电位器代替互感器模拟信号后面第6章会展开讲。电流互感器二次侧务必接好采样电阻后再通电二次侧开路会产生高压这是硬件调试中最容易忽略的安全点。2.3.1 弱电采样与单片机接口INT1脉冲计数void sys_init(void) { EA 0; TMOD 0x51; /* T0为16位定时器T1为16位计数器 */ TH0 (65536 - 46080) / 256; /* 11.0592MHz12T模式约50ms */ TL0 (65536 - 46080) % 256; TH1 0; TL1 0; /* T1从0开始累计脉冲 */ IT1 1; /* INT1下降沿触发 */ EX1 1; /* 打开外部中断1 */ ET0 1; /* 打开定时器0中断 */ TR0 1; TR1 1; EA 1; }TMOD 0x51 拆开看高四位0x5对应T1模式1计数低四位0x1对应T0模式1定时。4550us的初值是按11.0592MHz晶振、12T时钟计算的约50ms产生一次中断。采样脉冲接INT1用下降沿触发每次充电电流过零翻转都会产生一次外部中断。这里使用11.0592MHz晶振还有一个好处串口波特率用9600时误差为零后面对接充电桩管理系统时不需要另外校准时钟。2.3 执行链路ULN2003驱动继电器与LCD1602扩展继电器控制是新手翻车的高发区。ULN2003是灌电流输出线圈一端接5V另一端接输出引脚输入给高电平时输出导通继电器吸合。也就是说写代码让P2.0 1继电器才动作。如果用NPN三极管电路逻辑会相反原理图上很容易看走眼。ULN2003内部自带续流二极管可以省去外接二极管这是它比三极管驱动适合入门的原因。显示用LCD1602数据总线接P0口。P0是开漏输出必须接一个10k排阻上拉否则LCD显示乱码或白屏。LCD的V0引脚接一个10k电位器到地作为对比度调节。三只按键接P1.0到P1.2分别用于投币、启动、停止按键另一端接地软件内部启用上拉电阻即可。2.3.1 原理图自查清单保险丝必须串联在220V进线火线端不要装在零线端。继电器常开触点的引脚间距要足够线圈侧和触点侧分开放置。电流互感器二次侧电阻在原理图上必须标注不能悬空。ULN2003输入端不要直接连P0口P0开漏无法提供足够驱动电流应换用P2或P1。LCD1602的R/W引脚直接接地只写不读可省去读写忙检测的代码。3. 流程图与状态机投币、充电、充满判停的边界条件流程图画大而全的单张图很难指导写代码。我一般把充电桩的流程拆成三层第一层是主循环负责按键扫描和状态处理第二层是定时器提供1秒时基第三层是外部中断和计数口负责采集计量脉冲。三层之间共享几个全局变量流程图里的每一个判断框都要能对应到某个变量。上电自检 - 显示PLEASE COIN - 等待投币 投币按键 - 金额累加 - 显示余额 - 等待START 按下START - 继电器吸合 - 进入充电状态 充电中 - 倒计时每秒减1 - 脉冲计数累加 - 刷新LCD 倒计时归零 或 按下STOP - 继电器断开 - 计算金额 - 返回待机投币环节在真实产品里是扫码或刷卡在课设里用一个按键模拟即可。流程图里最容易出错的是“充满判停”这一环简易充电桩没有电池电压采样所以判停条件就是倒计时归零。这条逻辑必须在流程图中写明避免评审老师追问“如何进行充满判断”时无言以对。3.1 状态定义与状态转换表状态定义可以压缩到四个S_IDLE、S_COIN、S_CHARGE、S_DONE。去掉故障状态是因为简易方案里异常处理统一就当作“停止并回待机”不让状态机膨胀。当前状态触发事件动作下一状态S_IDLE无显示PLEASE COINS_IDLES_IDLE投币键短按余额加1元显示余额S_COINS_COIN投币键短按余额加1元S_COINS_COIN启动键按下且余额0继电器吸合倒计时余额*60秒S_CHARGES_CHARGE每秒时基倒计时减1脉冲计数加值S_CHARGES_CHARGE倒计时0 或 停止键继电器断开记录本次消费S_DONES_DONE2秒后自动返回清空余额恢复待机显示S_IDLE这里把“余额0”作为启动条件而不是直接由投币键触发充电可以避免误触发放电。倒计时计算用整数秒不要用浮点金额初始化时直接把金额乘以60换算成秒这样状态机里只剩整数减法51单片机上执行效率更好也不会出现浮点误差。3.2 用状态机伪代码描述完整充电流程状态机落到C语言就是switch-case加事件标志。事件标志由中断和按键扫描置位主循环消费标志并改变状态值。不要在中断服务函数里直接改状态否则会出现“倒计时清零但继电器未断开”的竞态。void main_loop(void) { while (1) { if (timer_tick) /* 1秒标志由T0中断累加置位 */ { timer_tick 0; if (sys_state STATE_CHARGE) { countdown--; if (countdown 0) sys_state STATE_DONE; } } if (btn_event) /* 按键事件key_scan设置 */ { handle_key_event(); } if (sys_state STATE_DONE) { relay_off(); delay_ms(2000); balance 0; sys_state STATE_IDLE; } } }COUNTDOWN归零判断放在主循环里而不是中断里这样ISR只需做“timer_tick 1”这一件事主循环再去处理耗时器重操作。流程图中“断电”动作只会在主循环的安全位置执行不会被中断打断这是单片机控制继电器最稳妥的写法。4. 物料清单BOM关键器件选型、参数计算与替代方案物料清单的作用有两个一是控制成本二是方便画仿真图。给课设版充电桩列BOM时我会把器件分成“必买”和“可替代”两类。主控、晶振、继电器、变压器、LCD这些必买互感器和电位器在搭实物时可以先用仿真电路验证防止买错型号。4.1 元件选型与封装对照表位号器件参考型号关键参数数量备注U1单片机STC89C52RCDIP405V1AT89S52可直接替代U2继电器驱动ULN20037路达林顿管1输入高电平输出导通K1继电器SRD-05VDC-SL-C5V线圈10A/250VAC1触点容量必须覆盖负载T1变压器220V转9V2W-5W1与负载端隔离T2电流互感器开口式互感器1000:1或100A/50mA1仿真时可用电位器代替U3比较器LM393双路比较器1输出端必须接上拉V1整流桥DB1071A 1000V1或用4个1N4007U4稳压器L78055V输出1输入12V以下LCD1显示屏LCD160216x2字符1带背光R1采样电阻100Ω / 0.25W互感器次级对地1计算见4.2R2排阻10k×8接P0口上拉1SIP-9封装Y1晶振11.0592MHz附2个30pF电容1串口波特率准确S1-S3按键6x6轻触投币、启动、停止3加10k上拉以上BOM不含PCB打样元器件成本大致在40到60元之间。如果学校实验室资源充足很多项目可以用STC单片机实验板上的最小系统替代U1和晶振部分BOM就再减掉一组器件。4.2 采样电阻与比较器阈值的计算步骤互感器选型后采样电阻和比较器阈值要有个明确的对应关系。下面这段Python代码可以在进入Proteus前先把参数算好避免反复试凑。ratio 1000 # 互感器变比一次1000:二次1 rated_current 5.0 # 满载一次电流单位A sample_res 100.0 # 采样电阻单位Ω primary_sec rated_current / ratio # 二次电流单位A v_signal primary_sec * sample_res # 采样电压单位V v_thresh v_signal * 0.5 # 取半幅作为比较器阈值 print(f满载二次电流: {primary_sec * 1000:.1f} mA) print(f满载采样电压: {v_signal * 1000:.0f} mV) print(f推荐比较器阈值: {v_thresh * 1000:.0f} mV)算出来二次电流是5mA采样电压500mV阈值取250mV。这个计算把原理图、BOM和后期调试串在一起电位器拧到250mV左右比较器输出翻转位置就对应负载电流大约2.5A。仿真时只需要用万用表量一下比较器同相与反相输入就能知道阈值有没有设对。采样电阻精度至少要1%普通5%碳膜电阻会直接改变脉冲占空比。4.3 采购优先级与替代方案采购优先级上继电器和变压器不能省这是强电切换的基础LCD1602可以用OLED替代但SSD1306驱动的I2C接口写起来会更长课设图省事还是LCD更稳电流互感器如果学校不提供可以直接不买仿真阶段用滑动变阻器在LM393输入侧模拟信号实物调试时再接互感器。7805可以换成LM2596降压模块后者效率高、发热小但模块上的电感会引入噪声干扰比较器调试难度略增。能用7805就用7805器件少好查问题。5. 源代码实现把状态机拆成可移植的51工程源代码的组织方式直接影响调试效率。我一般把工程分成main.c、key.c、lcd1602.c、relay.c四个文件外加一个config.h定义引脚和状态常量。没有把中断都堆在main.c里是因为投币、计时、按键去抖三个中断各有各的时间基准分开写不容易改乱。5.1 端口分配与中断资源规划功能引脚中断资源说明LCD数据P0.0-P0.7无必须上拉排阻LCD控制P2.3 RSP2.4 E无R/W接地继电器P2.0无高电平吸合投币键P1.0无定时扫描启动键P1.1无定时扫描停止键P1.2无定时扫描计量脉冲P3.3INT1下降沿触发由LM393输出接入51单片机只有两个外部中断和两个定时器资源要按“时间基准”和“事件计数”两类分配。T0做50ms时基在中断里累加得到1秒标志T1做脉冲计数记录充电过程中的计量脉冲。INT1下降沿触发用于更精准的采样事件T1计数用于显示累计脉冲数两者可以同时接在LM393输出上互不冲突。5.2 按键去抖与LCD驱动的关键代码按键扫描采用“状态连续两次一致算确认”的方法消抖周期约20ms。去抖逻辑必须占住主循环时间不能让按键在S_CHARGE状态下切换过快。unsigned char key_scan(void) { unsigned char key KEY_NONE; static unsigned char last KEY_NONE; unsigned char now 0; if ((P1 0x07) ! 0x07) /* 有按键按下 */ { now (P1 ^ 0x07) 0x07; /* 取低三位有效位 */ } if (now last now ! KEY_NONE !key_confirm) { key now; key_confirm 1; /* 连续两次采样一致确认事件 */ } else { key_confirm 0; } last now; return key; }P1低三位接按键到地没有按下时读为高电平1。代码里取反得到有效位避免在按键松开时误判。key_confirm标志确保同一个按键在连续扫描中只上报一次事件按下保持不会重复触发投币。需要说明的是这个函数放在主循环中调用循环周期就是采样周期约几毫秒与物理按键20ms抖动不冲突。LCD1602写命令和写数据的最小函数核心是控制E引脚的下降沿void lcd_write_cmd(unsigned char cmd) { LCD_RS 0; P0 cmd; LCD_E 1; delay_us(10); LCD_E 0; /* E下降沿锁存数据 */ delay_us(120); } void lcd_write_data(unsigned char dat) { LCD_RS 1; P0 dat; LCD_E 1; delay_us(10); LCD_E 0; delay_us(120); }RS0写命令RS1写数据E脚由高变低的瞬间完成锁存。在51单片机上delay_us可以用一个短延时函数实现不需要精确到微秒只要满足LCD1602最小时序即可。这段代码可直接抄进课设注意P0开漏如果没有上拉排阻无论如何调时序都白搭。5.3 烧录参数与调试点烧录STC89C52RC使用STC-ISP软件芯片型号选STC89C5xx系列波特率9600足够晶振频率填11.0592MHz。点下载后给板子断电重新上电冷启动触发烧录。如果采用内部RC时钟定时器初值必须按实际频率重算否则倒计时不准这也是仿真与实物差别较大的一个地方。实物调试顺序建议先烧一个LED闪烁程序确认最小系统起振再调LCD显示“0”然后短接继电器线圈供电看是否吸合最后才接互感器和LM393。每加一块电路就验证一次能有效避免“所有问题同时出现”。6. Proteus仿真51单片机的经验坑从最小系统到可演示的充电流程Proteus在课程设计圈的普及度很高但它的仿真模型和真实芯片有细微差异这里讲两个可以提升演示效果的技巧。6.1 仿真最小系统的加载顺序放置AT89C52后先把Clock Frequency改为11.0592MHz再接入复位电路和30pF晶振电容。P0口务必放一个RESPACK-8上拉排阻否则LCD1602在仿真里同样花屏。LM393在Proteus里是开集输出输出引脚必须接一个10k电阻到5V否则仿真时比较器输出永远是低电平没有任何脉冲。这个上拉电阻在原理图中已存在容易掉。仿真中比较器可以用“手动调节的电位器”模拟互感器信号。接法电位器滑动端接LM393同相输入端500mV直流电压即可模拟满载电流转动电位器观察INT1引脚是否有下降沿脉冲产生。这一步验证的是“信号链路”和“中断计数链路”避开交流互感器在Proteus里难建模的问题。6.2 用DEMO_MODE把10分钟压缩成20秒的加速演示法正常课设中倒计时60分钟会拖慢演示节奏。我习惯在代码里加一个编译开关仿真时把1秒时基压缩成100毫秒投币一次对应10分钟整机20秒跑完整个充电流程#ifdef DEMO_MODE #define TIME_UNIT_MS 100 /* 仿真时1秒100ms加速10倍 */ #else #define TIME_UNIT_MS 1000 #endifT0中断里把这个宏替代固定值仿真时就能快速看到投币、倒计时、脉冲累计、断电的全过程。展示用的Hex文件用DEMO_MODE编译烧录给实物时关闭该宏不影响正常逻辑。把加速前后两张Proteus截图放进课设报告流程图和仿真图对应关系一目了然。如果后续想对接充电桩管理系统只需要用串口把状态帧已发送的形式预留出来状态机本身不用重写。整个简易充电桩的关键就是把状态机、时基、事件三者的边界画清楚。本文还有配套的精品资源点击获取