
简介面向单片机学习者与电力电子方向师生的一套完整设计方案基于51单片机与Proteus仿真实现功率因数矫正电路。资料包含电路仿真图、单片机源代码、设计论文与Altium Designer原理图系统可实现电网电压电流测量、无功功率因数检测、电容组自动投切和人机交互显示并支持手动、自动两种模式通过电容阵列补偿功率因数仿真验证了可靠性与实用性。压缩包共52个文件约3.32MB主要包含Proteus工程、AD原理图、C语言源码、Hex烧录文件、Word论文、PDF预览、元件清单及流程图源码涉及LCD1602显示、ADC0832采集、I2C通信等模块便于对照原理图理解功率因数测量与投切逻辑。已有40人学习浏览适合课程设计、毕业设计或工程入门下载后可直接仿真并基于源码和论文进行二次开发。1. 先把功率因数矫正跑进 Proteus用 51 单片机做功率因数矫正电路最容易卡住的不是算法而是“怎么验证”总不能为一次课程设计真的去拉一个感性负载网。这套基于 51 单片机 Proteus 仿真的功率因数矫正电路资料恰好把这个问题一次性解决了。工程里同时包含 Keil 的 C 源码、Proteus 8.7 仿真图、Altium Designer 原理图、论文文档和元件清单应用场景很清晰实时测量电网电压电流、计算功率因数、按需要自动或手动投切电容阵列并把电压、电流、目标补偿值和实际补偿值显示在 LCD1602 上。对刚做完单片机基础实验的学生来说它是完整的综合案例对正在调无功补偿装置的工程师来说Proteus 里那套过零检测加 ADC 采样的组合也很值得对照实物做快速原型验证。2. 测量与控制从过零检测到电容阵列2.1 电压电流相位差是核心测量量功率因数低多数情况下是因为交流电路里带上了感性负载电流滞后电压一个角度 φ。功率因数就是 cosφ等于有功功率和视在功率的比值。测量 cosφ 最直接的办法并不是去采功率而是先测出电压和电流的过零时刻差。把电压过零和电流过零分别整形为方波送入 51 单片机的外部中断 INT0 和 INT1。单片机用定时器计量两个过零沿之间的时间差再除以一个工频周期就能得到相位差角度。这套方案不用专门加电能计量芯片ADC0832 只要负责把电压和电流的有效值采回来软件里再做乘法精度对学生设计和功能验证来说完全够用。2.2 整条采样链路的器件划分工程里频繁出现的几个文件分别是这样分工的main.c做状态调度ADC0832.C负责双通道直流电压采样i2c.c用来读写外部存储或者扩展 IOlcd1602.c驱动显示。仿真图画到了 Proteus 8.7晶振频率取 12MHz配合 51 单片机每条指令周期固定为 12 个时钟定时器计数分辨率记到微秒级测 50Hz 工频的相位差足够。ADC0832 是 8 位逐次逼近型 ADC双通道输入转换速度不高但逻辑简单非常适合 51 这种没有硬件 SPI 的 MCU。电压采样的输入先经电阻分压和运放跟随送到 CH0电流通道则通过采样电阻或电流互感器变换成电压送到 CH1。过零比较器用 LM393 这类开漏输出比较器输出端加上拉电阻接单片机能直接适配 TTL 电平。2.3 补偿电容容量怎么估算假设实测负载端有功功率为 P当前功率因数为 cosφ1希望补偿到 cosφ2需要投入的无功容量 Q 满足Q P × (tanφ1 − tanφ2)仿真中为了简化通常固定一组已知的阻感负载系统显示当前电压电流和 cosφ。需要补偿的电容值由单片机换算成法拉再按电容阵列的步进来量化。电容阵列的每个支路用继电器控制投切继电器线圈由 P2 口部分引脚驱动每个电容权重做成 1、2、4、8 的关系就能覆盖较宽的补偿范围。3. 51 单片机软件实现采样、计算、投切、显示3.1 主循环状态机设计工程里main.c的任务可以拆成四个状态采样、计算、投切、显示。初始化时关闭看门狗配置外部中断触发方式和定时器之后主循环只做调度。中断里只放“记时间差”这种短任务立即把结果丢给全局变量避免在中断里做浮点运算。void main(void) { unsigned int vol, cur; float cos_phi; system_init(); while (1) { vol adc0832_read(0); // 读取电压有效值对应的直流电平 cur adc0832_read(1); // 读取电流通道对应的直流电平 cos_phi calc_power_factor(); // 用中断里锁存的相位差数据计算 update_display(vol, cur, cos_phi); if (run_mode MODE_AUTO) // 手动模式时不进入自动投切 { auto_switch_capacitor(vol, cur, cos_phi); } } }代码里把每个功能剥成独立函数出问题时能单独定位。adc0832_read的返回值是 0 到 255 的原始采样值calc_power_factor内部会做相位差到角度的换算。主循环不要频繁做昂贵运算保持刷新显示和投切的节奏稳定。3.2 ADC0832 的通道切换时序ADC0832 是串行接口控制系统通过普通 IO 口模拟它的时钟和数据时序。选通哪一路输入由启动序列里的通道配置位决定。下面这段代码是简化但可用的读时序sbit ADC_CS P1^0; sbit ADC_CLK P1^1; sbit ADC_DIO P1^2; unsigned char adc0832_read(unsigned char ch) // ch0 为电压通道ch1 为电流通道 { unsigned char i; unsigned char dat 0; ADC_CS 0; ADC_CLK 0; ADC_DIO 1; // 起始位第一个时钟周期前拉高 ADC_CLK 1; ADC_CLK 0; // 第1个时钟上升沿采样起始位 ADC_DIO 1; // 极性位单端模式 ADC_CLK 1; ADC_CLK 0; // 第2个时钟 ADC_DIO ch; // 通道选择为 0 选 CH0为 1 选 CH1 ADC_CLK 1; ADC_CLK 0; // 第3个时钟 ADC_DIO 1; // 之后 DIO 转为数据输出方向 for (i 0; i 8; i) { ADC_CLK 1; dat (dat 1) | ADC_DIO; ADC_CLK 0; } ADC_CS 1; return dat; }注意这段代码必须在每次读取前调用且连续读取两个通道时中间要留一点延时避免 ADC 内部保持电容没有完全放电。如果发现电压显示跳动可以在通道切换前多拉几次时钟清掉残留状态。另外ADC_DIO引脚的输入输出方向切换在标准 51 里需要配合端口配置Proteus 仿真可以运行做实际电路时最好加上三态门或确认 IO 模式寄存器的设置。3.3 相位差测量与 cosφ 计算过零检测的两个外部中断一个负责电压信号一个负责电流信号。标准做法是电压过零时启动定时器 0记录当前周期起点电流过零时读取定时器 0 的计数值得到时间差tdiff。下一次电压过零时再读一次周期period。unsigned int tdiff 0; unsigned int period 0; void INT0_ISR(void) interrupt 0 // 电压过零启动计时 { if (period_flag 1) // 上一次周期已经完整记录 { period (TH0 8) | TL0; // 保存工频周期计数值 TH0 0; TL0 0; } TR0 1; // 重新开始计数 period_flag 1; } void INT1_ISR(void) interrupt 2 // 电流过零锁存相位差 { if (period_flag 1 current_flag 0) { tdiff (TH0 8) | TL0; current_flag 1; } }这里把period和tdiff定义为全局变量计算函数读取后立即恢复状态。周期period对应 360°因此相位差角度为tdiff / period × 360。电流滞后电压时角度为正表示感性负载角度为负则可能是容性负载或接线接反。计算 cosφ 用math.h里的cos函数注意角度要转弧度。Proteus 仿真中浮点运算会占一些时间但显示刷新在 200ms 以上没大问题float calc_power_factor(void) { float angle, rad; if (period 0) return 0.0f; angle (float)tdiff * 360.0f / (float)period; rad angle * 0.0174532925f; if (rad 3.14f || rad -3.14f) { rad 0.0f; // 明显异常说明比较器抖动或采样通道接反 } return (float)cos(rad); }边界条件一定要做因为 Proteus 里的波形起点和真实电路不同过零比较器容易在零点附近产生多次翻转。软件上可以加一个最小时间差阈值比如定时器计数值小于 10 就丢弃本次结果默认按上次值显示。3.4 手动自动投切逻辑与电容步进自动模式和手动模式通过一个按键切换。手动模式允许用户直接增加或减少一组电容调试时很方便自动模式则根据当前 cosφ 和目标值决定投切方向。void auto_switch_capacitor(unsigned int vol, unsigned int cur, float cos_phi) { float p, q_need; unsigned char cap_code; float target_cos 0.92f; // 目标功率因数 if (cos_phi 0.7f) // 低于下阈值才动作防止频繁投切 { p (float)vol * (float)cur / 255.0f * 0.8f; // 按电压电流系数折算 q_need p * (tan(acos(cos_phi)) - tan(acos(target_cos))); cap_code (unsigned char)(q_need / CAP_STEP); P2 cap_code; // P2 口低 8 位直接驱动继电器阵列 actual_cap_code cap_code; } }CAP_STEP是每组电容对应无功容量的量化步长。实际工程里可将计算所得浮点补偿容量四舍五入到最接近的电容组合并用一个局部变量保存上一次输出避免继电器反复吸合。Proteus 中继电器用线圈加单刀双掷开关即可P2 输出低电平时线圈吸合。3.5 LCD1602 显示哪些内容显示内容分成两行第一行显示电压、电流值和当前 cosφ第二行显示目标补偿电容和实际投入电容。写字符时可以用sprintf把浮点转成字符串但 51 单片机内存较小更建议自己写一个浮点转字符串的小函数或者把电压电流转成整数后按照个位、十位、小数位拼接。工程里的lcd1602.c已经处理好了底层时序改显示内容时只要调用在指定位置写字符串的函数就行。4. Proteus 仿真搭建与联调参数4.1 仿真图里的关键元器件Proteus 工程名叫New Project.pdsprj打开后能直接看到完整原理图。自己重新搭的话元器件对照表如下功能模块Proteus 内器件名作用与参数主控AT89C5112MHz 晶振复位电路带 10μF 电容和 10kΩ 电阻显示LM016LLCD1602 模型数据口接 P0 并加上拉排阻ADCADC0832双通道 8 位 ADCVref 接 5V过零比较LM393双路电压比较器输出上拉 4.7kΩ交流源VSINE220V/50Hz配合变压器模型降压负载RES INDUCTOR串联或并联成阻感负载功率因数约 0.7继电器阵列RELAY CAP多个继电器控制不同容值电容投切如果找不到继电器模型也可以用 Proteus 里的开关SW-SPST代替手动拨动开关检验电容投切效果。电容阵列的容值不建议直接用微法级大电容仿真里 10μF 左右就能看出来电压电流角度变化。4.2 比较器输入和采样输入怎么接电压通道采样点和过零比较器必须从同一个分压点引出。常见做法是用 220V 交流源经小型变压器变成 6V 左右交流再用两个 10kΩ 电阻分压分压点作为 ADC 输入同时送到 LM393 的同相端。LM393 的反相端接一个由 5V 和 GND 分出的 2.5V 参考电平。这样交流信号的正半周高于 2.5V 时比较器输出低电平负半周输出高电平就得到了工频方波。电流通道不能用纯电阻分压需要加一个 1Ω 左右的采样电阻串联在负载低端采样电阻上的电压就是与电流同相位的微小交流信号再用运放放大到幅值合适的范围。比较器的参考电平也放在 2.5V保证电流过零点能被可靠检测。如果直接用两个独立的交流源分别模拟电压和电流虽然也能产生相位差但和真实电网情况差别较大调试出来的投切逻辑缺少说服力。4.3 仿真调试顺序与常见失败表现拿到仿真工程后建议按三步走先确认 LCD1602 有显示再确认 ADC0832 电压读数变化最后观察投切继电器动作。如果 LCD 只有背光没有字符检查 P0 口上拉电阻是否接上以及 LCD 的对比度电位器中间抽头是否接到 VL 引脚。晶振频率在 12MHz 时定时器初值清零即可周期计数值在 20000 左右。如果发现cosφ一直显示 1.00八成是中断没有触发。用 Proteus 的数字示波器看 LM393 输出端如果方波频率是 50Hz 而不是 100Hz说明比较器参考电平不对导致半波被忽略。另一种情况是中断里tdiff和period相乘超出整型范围把变量改成unsigned long就能解决。4.4 模拟量显示波动问题ADC0832 只有 8 位分辨率电压通道和电流通道直接显示原始值会跳变。工程里若看到个位数一直抖不是硬件坏了而是分辨率不够。可以在软件里做简单滤波连续采样四次去掉最大值和最小值再取平均。继电器动作瞬间电网波形会被拉一下Proteus 中也会有微小毛刺建议在采样函数和主循环之间加入 20ms 延时让显示刷新不跟着继电器动作一起变。5. 从 Proteus 移植到 AD 原理图的关键检查点拿到资料里的Sheet1.SchDoc后真正画 AD 原理图时会发现两边的库名和封装叫法不一样。Proteus 里用的是通用模型AD 工程里则需要给每个器件指定具体封装。最稳妥的办法是先打开附带元件清单.xlsx按里面的型号和封装一一对应继电器选用常见 5V 线圈 1 路继电器封装为 JQC-3F共生电容电阻都用直插封装便于焊接ADC0832 用 DIP-8AT89C51 用 DIP-40。这样才能保证实物焊接的时候不用临时改板。过零比较器是移植时最容易出问题的地方。Proteus 中 LM393 输出端直接接到单片机引脚没有影响但实际电路板上的导线更长干扰更明显必须在比较器输出和单片机引脚之间加一个 10kΩ 上拉电阻在对地并联一个 100pF 小电容滤掉边沿抖动。中断线走线也和普通 IO 不同尽量短不要把它和继电器控制线并排走否则吸合瞬间产生的电磁干扰会直接触发外部中断导致tdiff记录错误。做实物验证时先用一个已知的功率因数表或万用表对比 LCD 上显示的 cosφ 值。很多第一次做这个项目的人会发现Proteus 里放一个纯电阻负载时 cosφ 显示 1.00换成阻感负载后显示值会稳定在 0.7 到 0.85 之间这就说明过零检测和相位差计算是通的。如果显示值和万用表差太多先检查 ADC0832 的参考电压 Vref 是否精确因为电压电流幅值会直接影响补偿容量计算而相位差计算本身并不依赖 Vref 精度。另外一个验证技巧把自动模式的目标功率因数从 0.92 改成 0.99观察电容阵列是否多投一两组这比反复看显示数字更能判断控制逻辑是否正常。资料里的中断0流程图.bmp和中断1流程图.bmp最好打印出来贴在工作台上。调试时按流程图的顺序比对实际中断状态能快速确认到底是过零事件没触发还是通道选择错误。最后把 Proteus 仿真通过后生成的cos.hex烧进实物 51 单片机用示波器抓一组继电器动作瞬间的波形确认 P2 口对应位电平变化与预期电容代码一致这个项目就可以收尾了。本文还有配套的精品资源点击获取