简介:一套基于51单片机Proteus仿真的多功能断路器开发设计资料,面向单片机课程设计、电子竞赛及嵌入式入门者,解决过压、欠压、过流、温度异常时的实时监测与自动断电保护问题。系统以51单片机为核心,配合LCD1602液晶显示和按键操作,可完成智能断路器的功能演示与二次开发。压缩包共59个文件,大小68.13MB,涵盖C语言源码、头文件、hex烧录文件、Proteus仿真图(DSN)、Altium Designer原理图(SchDoc)、元件清单Excel、操作演示视频及PDF预览文档,从软件代码到硬件电路均有覆盖。目前已有58人学习下载,适合需要快速搭建同类项目或理解断路器保护逻辑的读者。资料内还附带针对Proteus变压器仿真报错的偷懒替代方案,能有效降低仿真失败概率;配套视频和原理图便于对照理解电压、电流、温度的采集与判断流程,可直接移植和修改。
1. 断不了的电:为什么一个断路器要上单片机
你可能见过配电箱里那种热磁式断路器,双金属片弯到一定程度就跳闸。但这个设计不一样——它用 STC89C52 这类 51 单片机实时盯着电压、电流和温度,过压、欠压、过流、过热四个条件只要命中一个,就主动切断负载。反直觉的地方在于:Proteus 里仿真这个系统,最容易翻车的不是 C 语言逻辑,而是变压器模型。很多人把代码调通了,却卡在变压器仿真报错上,误以为是自己电路画错了。这套开发包的价值就在于它把这个问题绕了过去,并且给出了完整的 Proteus 仿真图、Keil 源码、AD 原理图和演示视频,适合正在做 51 单片机课设、或者想把传统断路器改造成数字化采集原型的人。下面我按采样链路、软件调度、仿真排错的顺序,把这个项目拆开讲。
2. 采样链路设计:从 220V 到 ADC0832 的量程匹配
2.1 电压通道:变压器降压后还要过电阻分压
电网侧的 220V 交流不能直接进单片机,ADC0832 的模拟输入范围是 0~5V,直接接必烧。常见做法是先用变压器把 220V 降到 5~9V 的交流,再经过整流桥和滤波电容变成直流,然后通过电阻分压网络把电压压到 2~4V 之间,给 ADC 留出裕量。
这里要强调一个容易被忽略的点:分压电阻的阻值选择不是随便算的。假设整流滤波后是 5V 直流,你希望 ADC 满量程对应 300V 交流(留出 30% 的过压检测余量),那 5V 对应的分压比就是 300/220 ≈ 1.36 倍余量。我一般取分压电阻 R1=10kΩ、R2=3.3kΩ,算下来输出约 1.24V@220V,这个电压落在 ADC 线性度最好的区间。需要改量程时,优先动 R2 而不是 R1,因为 R1 太大容易引入噪声。
2.2 电流通道:互感器加采样电阻,别直接用 ADC 量
电流采样用电流互感器(CT),二次侧输出的是电流信号,必须并联一个采样电阻转成电压。这个电阻的选值决定了电流检测的灵敏度。比如额定电流 5A 的 CT,变比 1000:1,二次侧电流 5mA,如果你希望满量程 3V 输出,采样电阻就是 3V/5mA = 600Ω。实际取 510Ω 或 620Ω 都可以,用 Proteus 仿真时调到满量程不削顶就行。
采样电阻上出来的电压带交流纹波,必须加一阶 RC 低通滤波。截止频率我习惯设在 100Hz 左右,R=10kΩ、C=0.1μF,算下来截止频率约 159Hz,能把 50Hz 基波保留、高次谐波滤掉一大部分。注意滤波电容不要太大,否则响应变慢,断路器就真的变成"慢断"了。
2.3 ADC0832 双通道轮流采样
ADC0832 是 8 位双通道 ADC,正好用 CH0 采电压、CH1 采电流,温度可以接到 CH2——但 0832 只有两个输入通道,所以温度信号要么和电流通道分时复用,要么用 4051 模拟开关扩展。这个项目里温度检测用的是 NTC 热敏电阻加固定电阻分压,接到 ADC0832 的一个通道,采样率不需要高,1 秒刷一次足够。
表:典型采样通道参数
| 通道 | 信号来源 | 分压/转换 | ADC 输入范围 | 采样周期 |
|---|---|---|---|---|
| CH0 | 变压器次级整流滤波 | 10k+3.3k 分压 | 0~5V | 20ms |
| CH1 | 电流互感器 + 采样电阻 | 620Ω 采样 | 0~5V | 20ms |
| CH2/NTC | 10kΩ 分压 | 3.3k 上拉 + NTC | 0~5V | 500ms |
NTC 接法注意一点:分压电阻要放在高端、NTC 放在低端,这样温度升高时 ADC 读数变大,判断"过热"的逻辑更直观——温度越高,NTC 阻值下降,分压点电压上升。
3. 软件架构:主循环、ADC 读取与保护逻辑优先级
3.1 主循环框架:定时采样,不让保护逻辑阻塞
这个系统的软件核心不是中断多复杂,而是要让采样、显示、按键、保护判断各干各的,互不阻塞。我拆解出来的代码结构是:主循环里用while(1)轮询标志位,Timer0中断里置adc_flag,主循环检测到标志后去采 ADC、算数值、再判断阈值。
// 主循环调度框架 void main(void) { Timer0_Init(); // 定时 20ms,产生采样节拍 LCD1602_Init(); while(1) { if(adc_flag) // 20ms 到,开始一次采样 { adc_flag = 0; voltage = Read_ADC0832(CH0); // 读电压通道 current = Read_ADC0832(CH1); // 读电流通道 temp = Read_ADC0832(CH2); // 读温度通道 Process_Protection(); // 阈值判断 + 继电器控制 Display_Update(); // 刷新 LCD Key_Scan(); // 扫描按键 } } }这个框架的好处是采样周期恒定,不会因为 LCD 刷屏慢导致保护响应延迟。Process_Protection()必须在Display_Update()之前调用——如果显示用掉了 50ms,而此时电流已经过流,晚一步断电可能就让负载烧了。保护好于显示,这个顺序不能反。
3.2 ADC0832 的时序读取代码
ADC0832 用三线制 SPI 兼容时序,时钟由单片机产生。它有个特点:前三个时钟周期写 DI 配置通道,之后 DI 变为高阻,DO 输出转换结果。读数据时要先假装写一个停止位,然后才能读取。很多刚从 0809 转过来的人在这卡住。
// 读取 ADC0832 单通道数据 unsigned char Read_ADC0832(unsigned char ch) { unsigned char i, dat = 0; CS = 0; CLK = 0; DI = 1; _nop_(); // 起始位 CLK = 1; _nop_(); CLK = 0; DI = 1; _nop_(); // SGL=1,单通道模式 CLK = 1; _nop_(); CLK = 0; DI = ch; _nop_(); // ODD=ch,选择 CH0 或 CH1 CLK = 1; _nop_(); CLK = 0; DI = 1; _nop_(); // 停止位,之后 DI 释放 CLK = 1; _nop_(); CLK = 0; for(i = 0; i < 8; i++) // 读取 8 位数据 { dat <<= 1; CLK = 1; _nop_(); dat |= DO; // 在时钟高电平时采样数据 CLK = 0; _nop_(); } CS = 1; return dat; }注意第三个CLK = 1; CLK = 0;之前的DI = ch:ch 为 0 选 CH0,为 1 选 CH1。这里最容易错的是把 ch 定义成"通道编号",而 0832 的 ODD 位决定的是输入引脚对。写代码时最好注释清楚:Read_ADC0832(0)读的是电压通道,Read_ADC0832(1)读的是电流通道。如果读回来永远是 0xFF 或 0x00,先检查 CS 拉低时序,再用示波器看 CLK 是否有上升沿——Proteus 里虚拟示波器可以挂上去直接看。
3.3 阈值判断与优先级:过流必须最优先
保护逻辑不是简单的四个 if 并列,而是有优先级:过流和过压必须立刻断电,欠压可以延迟几十毫秒(避免电网瞬间波动误跳),过热可以延迟更长。原因很简单:过流可能烧线缆,过压可能击穿绝缘,这两个必须毫秒级响应;欠压对阻性负载影响小,但电机类负载欠压运行会发热,所以也要保护,只是允许一点延迟。
void Process_Protection(void) { if(current_ma > OVER_CURRENT) // 过流阈值,单位 mA { Relay = OFF; // 立即断电 buzzer = ON; // 驱动蜂鸣器 LCD_ShowString("Over Current!"); } else if(voltage_mv > OVER_VOLTAGE) // 过压阈值 { Relay = OFF; LCD_ShowString("Over Voltage!"); } else if(voltage_mv < UNDER_VOLTAGE) // 欠压阈值 { under_voltage_cnt++; if(under_voltage_cnt > 5) // 连续 5 次采样(100ms)才动作 { Relay = OFF; LCD_ShowString("Under Voltage!"); } } else if(temp_c > OVER_TEMP) // 温度阈值,单位 0.1°C { Relay = OFF; LCD_ShowString("Over Temp!"); } else { Relay = ON; // 正常状态,恢复供电 under_voltage_cnt = 0; buzzer = OFF; } }阈值用宏定义放在头文件里。值怎么定?看前面那个表:假设 ADC 参考电压 5V,8 位分辨率就是 5/255 ≈ 19.6mV 每 LSB。如果分压后 220V 对应 1.24V,那 1 LSB 对应的原边电压就是 220 / (1.24 / 0.0196) ≈ 3.48V。所以要设过压阈值 242V,就是242 / 3.48 ≈ 70,写成宏#define OVER_VOLTAGE 70。每次换算都要带这个比例系数,这是最容易出 bug 的地方。
under_voltage_cnt这个变量是消抖用的,它的存在让欠压保护不会因为负载启动瞬间的电压跌落而误跳。同理,温度采样值我做了 4 次滑动平均再判断,避免热敏电阻的接触噪声导致误报警。
4. Proteus 仿真:变压器报错的根因与"偷懒方案"
4.1 为什么 Proteus 的变压器模型总报错
Proteus 的变压器元件(TRAN-2P2S 之类)仿真时经常报Transformer primary current too high或者直接不收敛。原因是 Proteus 的变压器模型用的是理想变压器加非线性电感,当负载侧电流突变或者仿真步长不合适时,电感电流会瞬间冲高,求解器直接发散。这不是你的电路问题,是软件数值计算的问题。
常见触发场景有三种:
一是负载侧接了整流大电容,上电瞬间电容相当于短路,冲击电流远大于变压器额定电流,求解器崩掉。
二是仿真步长设置太小,Proteus 在细微时间步长里反复迭代电感微分方程,数值不收敛。
三是变压器绕组的电阻值设置不合理——零电阻或接近零电阻,导致电流无约束增长。
我验证下来的解决顺序是:先把仿真步长从默认的 10ms 改成 1ms 甚至 500us(在菜单 System > Animation Options 里改),绝大多数报错会消失。如果还报,就给变压器副边串一个 0.1Ω 的小电阻,限制冲击电流尖峰。再不行,才考虑换模型。
4.2 "偷懒仿真方案"的取舍:用可控直流源替代变压器
这套资源里的"偷懒仿真图"绕开了变压器:直接用 DC 电源接到采样分压电路的输入端,用一个电位器模拟电压波动。你旋转电位器时,单片机读到的电压值会跟着变,一旦超过阈值,继电器就跳——这完美覆盖了我们验证保护逻辑的需求。
图:偷懒方案信号链
DC 源 → 电位器 → 分压网络 → ADC0832 → 51 单片机 → 继电器 → LED/蜂鸣器
这个方案的学习价值在哪?它把"交流侧真实波形"和"控制逻辑验证"解耦了。做课设时你只需要让老师看到"电压超过 242V 时断路器跳闸",而不是"我复现了一个工频正弦波"。但代价是你验证不了整流滤波的波形真实度,更验证不了交流采样时的真有效值计算。如果想要更接近真实,用 AC 电源加整流桥自己搭一个简单的交流采样前端,然后用TRANSFORMER也不迟——但会频繁炸仿真。
4.3 仿真资源清单与关键器件选型
表:Proteus 器件清单
| 器件 | Proteus 关键字 | 参数设置 | 作用 |
|---|---|---|---|
| 单片机 | AT89C51 / STC89C52 | 晶振 12MHz | 主控 |
| ADC | ADC0832 | 参考电压 5V | 双通道采样 |
| LCD | LM016L | 16x2 字符屏 | 显示 |
| 电位器 | POT-LIN | 10kΩ 或 50kΩ | 模拟电压/温度变化 |
| 继电器 | RELAY | 线圈 5V,触点 SPST | 控制通断 |
| 蜂鸣器 | BUZZER | 5V 有源 | 报警 |
| NTC | THERMISTOR | 10kΩ@25°C | 温度传感 |
POT-LIN 是 Proteus 里最常用的线性电位器,双击可以调节阻值百分比。仿真时把电位器滑动端接到 ADC 输入,调节百分比就等于调节模拟量大小。我习惯同时放三个电位器,分别标注 "Voltage Adjust""Current Adjust""Temp Adjust",运行仿真时直接拖滑块,比改代码改源文件高效得多。
4.4 排错对照表:仿真现象与处理手段
| 现象 | 可能原因 | 处理 |
|---|---|---|
| 变压器报 primary current too high | 次级大电容上电冲击 | 副边串 0.1Ω 电阻 |
| 仿真速度极慢 | 步长太细或器件过多 | 去掉示波器,步长调到 1ms |
| LCD 无显示但有背光 | 对比度引脚悬空 | LCD 的 V0 接 1kΩ 到 GND |
| 按键无反应 | 端口没有上拉 | 使能 P0 内部上拉或外接 10k 排阻 |
| 继电器一直吸合 | 阈值宏定义错误 | 检查电流比较的单位是否一致 |
| ADC 读值恒为 0 | CS 时序提前释放 | 确保 CS 在整个读过程保持低电平 |
这六条是我在自己仿真时踩过的坑,尤其是 LCD 对比度这个,Proteus 里的 LM016L 如果 V0 不接地,显示会出现方块但是不出字符,很容易误判成代码问题。
5. 一阶校正技巧:用两点线性插值把 ADC 读数变成实际值
代码里voltage = Read_ADC0832(CH0)拿到的只是 0~255 的整数,不能直接拿来和阈值比较。前面我提到用比例系数换算,但真实情况下分压电阻有误差、ADC 有偏移误差,算出来的结果可能偏 5% 以上。我一般会写一个两点校正的线性插值函数:
// 两点校正:在 Proteus 里分别设置两个已知输入值 // 记录 ADC 输出,然后做线性映射 unsigned int Adc_To_Voltage(unsigned char adc_val) { // 校正点1:ADC值 adc1 对应 实际电压 v1 // 校正点2:ADC值 adc2 对应 实际电压 v2 #define ADC_POINT1 51 // 实际电压约 1.0V #define VOLT_POINT1 1000 // 单位 mV #define ADC_POINT2 204 // 实际电压约 4.0V #define VOLT_POINT2 4000 // 单位 mV unsigned int volt = 0; // 斜率 = (v2 - v1) / (adc2 - adc1),按 10 倍放大避免小数 volt = (unsigned int)(adc_val - ADC_POINT1) * (VOLT_POINT2 - VOLT_POINT1) * 10 / (ADC_POINT2 - ADC_POINT1); volt = volt / 10 + VOLT_POINT1; return volt; }这个函数把 ADC 的 0~255 线性映射到实际电压值(单位 mV)。两个校正点怎么取?一个取在额定值 70% 处,一个取在过压阈值上方一点,这样实际工作区间内映射误差最小。改变硬件分压比后,只需要重新标定ADC_POINT1和ADC_POINT2两个值,不用改判断逻辑——这比在Process_Protection()里直接乘比例系数好维护得多。
注意一个细节:volt的中间计算乘了 10 又除回,是为了保留一位小数精度。如果用整数直接算,(204-51)去除(4000-1000)是整除,精度直接丢到 20mV 以上。这个"先放大再缩小"的写法在 51 这种 8 位单片机上不算浪费,因为总共就几次整数乘法,运算量远小于一次 LCD 刷屏。
最后验证方法也给你:在 Proteus 里把电位器旋转到 50% 位置,读一下 LCD 显示值,再用虚拟电压表实测 ADC 引脚的电压,对照一下换算结果。两者差值在 ±30mV 以内,校正就过关了。用同样的方法标定电流通道和温度通道,三个通道都标完,这台"多功能断路器"才算真正能拿出去演示——注意标定电流通道时用电流互感器的次级电压作为标准值,不要在 Proteus 里硬造一个 20A 的电流源,那反而容易让仿真卡死。
本文还有配套的精品资源,点击获取