1. 项目概述
这个基于51单片机的智能洗衣机控制系统是我最近完成的一个嵌入式硬件项目。作为一名有多年单片机开发经验的工程师,我想分享一下这个项目的完整实现过程和关键技术要点。
这个系统的核心功能是通过51单片机控制洗衣机的完整工作流程,包括时间设置、状态显示、电机驱动和流程控制。相比传统洗衣机控制电路,这个设计具有以下特点:
- 采用数码管直观显示洗涤次数和剩余时间
- 使用L298N电机驱动模块实现正反转控制
- 通过按键实现10-30分钟的时间设置和启停控制
- 按照预设比例自动分配三次洗涤时间
- 完整的进水-洗涤-放水-脱水工作流程
2. 硬件设计详解
2.1 核心器件选型
主控芯片选用经典的STC89C52RC单片机,这是国内最常用的51内核单片机,具有以下优势:
- 8KB Flash存储器,足够存储控制程序
- 512B RAM,满足变量存储需求
- 4个8位I/O口,便于连接外设
- 价格低廉,开发资源丰富
电机驱动选用L298N双H桥驱动模块,主要考虑:
- 最大驱动电流2A,足以驱动小型洗衣机电机
- 可同时控制两个直流电机或一个步进电机
- 内置续流二极管,保护电路简单
- 支持PWM调速,方便控制电机转速
数码管显示采用共阳4位一体数码管,选择理由:
- 亮度高,显示清晰
- 仅需8个I/O口控制段选,4个I/O口控制位选
- 驱动电路简单,可直接用单片机I/O口驱动
2.2 电路原理图设计
使用Altium Designer绘制完整电路原理图,主要包含以下部分:
-
单片机最小系统电路:
- 12MHz晶振提供时钟
- 10kΩ上拉电阻保证复位可靠
- 0.1μF去耦电容稳定电源
-
数码管驱动电路:
- P0口通过74HC245缓冲器驱动段选
- P2.0-P2.3通过PNP三极管控制位选
- 220Ω限流电阻保护数码管
-
电机驱动电路:
- L298N的IN1-IN4连接P1.0-P1.3
- 使能端ENA/ENB接高电平
- 输出端OUT1-OUT4接电机
- 续流二极管选用1N4007
-
按键输入电路:
- 5个独立按键接P3口
- 10kΩ上拉电阻保证按键释放时高电平
- 0.1μF电容硬件消抖
注意:L298N模块需要单独12V供电,不能与单片机共用5V电源,否则可能导致驱动能力不足。
2.3 PCB布局要点
在设计PCB时特别注意以下几点:
-
电源部分:
- 电机驱动电源与数字电源分开走线
- 在电源入口处放置100μF电解电容
- 每个IC附近放置0.1μF陶瓷电容
-
信号线处理:
- 电机控制线尽量短而粗
- 晶振靠近单片机放置
- 敏感信号线避免平行走线
-
散热考虑:
- L298N下方铺铜并开散热孔
- 电机驱动走线加宽到1mm以上
- 避免元器件密集摆放
3. 软件设计实现
3.1 主程序流程设计
系统软件采用模块化设计,主程序流程图如下:
-
系统初始化:
- I/O口模式设置
- 定时器0配置为50ms中断
- 变量初始值设置
-
主循环任务:
- 按键扫描处理
- 数码管动态显示
- 工作状态机处理
c复制void main()
{
sys_init(); // 系统初始化
while(1)
{
key_scan(); // 按键扫描
display(); // 数码管显示
fsm_process(); // 状态机处理
}
}
3.2 定时器中断设计
使用定时器0产生50ms时基,用于系统计时:
c复制void timer0_init(void)
{
TMOD |= 0x01; // 模式1,16位定时器
TH0 = (65536-50000)/256; // 50ms定时初值
TL0 = (65536-50000)%256;
ET0 = 1; // 允许定时器0中断
EA = 1; // 开总中断
TR0 = 1; // 启动定时器0
}
void timer0_isr() interrupt 1
{
TH0 = (65536-50000)/256; // 重装初值
TL0 = (65536-50000)%256;
system_tick++; // 系统时基计数
}
3.3 数码管显示实现
数码管采用动态扫描方式显示,主要显示内容:
- 设置模式:显示预设时间(10-30)
- 工作模式:显示洗涤次数和剩余时间(分:秒)
c复制void display(void)
{
static uchar pos = 0;
P0 = 0xFF; // 消隐
switch(pos)
{
case 0: // 显示洗涤次数
P0 = seg_table[wash_count];
smg1 = 0; delay(1); smg1 = 1;
break;
case 1: // 显示分钟十位
P0 = seg_table[remain_min/10];
smg3 = 0; delay(1); smg3 = 1;
break;
case 2: // 显示分钟个位
P0 = seg_table[remain_min%10] | 0x80; // 带小数点
smg4 = 0; delay(1); smg4 = 1;
break;
case 3: // 显示秒钟十位
P0 = seg_table[remain_sec/10];
smg5 = 0; delay(1); smg5 = 1;
break;
case 4: // 显示秒钟个位
P0 = seg_table[remain_sec%10];
smg6 = 0; delay(1); smg6 = 1;
break;
}
pos = (pos+1)%5;
}
3.4 电机控制逻辑
电机控制实现正反转交替运行,每个方向运行10秒后切换:
c复制void motor_control(void)
{
static uchar dir = 0;
static uint count = 0;
if(++count >= 200) // 10秒切换
{
count = 0;
dir = !dir;
if(dir) {
P1 = 0x05; // 正转:IN1=1, IN2=0, IN3=1, IN4=0
} else {
P1 = 0x0A; // 反转:IN1=0, IN2=1, IN3=0, IN4=1
}
}
}
4. 工作流程状态机
4.1 状态定义与转换
系统采用有限状态机(FSM)实现洗衣流程控制,定义以下状态:
c复制enum {
STATE_IDLE, // 待机状态
STATE_WATER_IN, // 进水
STATE_WASH, // 洗涤
STATE_WATER_OUT,// 排水
STATE_SPIN, // 脱水
STATE_ALARM // 完成报警
};
状态转换条件:
- 进水:水位传感器信号或定时
- 洗涤:按预设时间比例分配
- 排水:定时完成
- 脱水:排水完成后进入
- 报警:三次洗涤循环完成后触发
4.2 状态机实现代码
c复制void fsm_process(void)
{
static uchar state = STATE_IDLE;
static uchar cycle = 0;
switch(state)
{
case STATE_IDLE:
if(start_flag) {
state = STATE_WATER_IN;
water_valve = 1; // 打开进水阀
}
break;
case STATE_WATER_IN:
if(water_level || timeout) {
water_valve = 0;
state = STATE_WASH;
set_wash_time(); // 设置本次洗涤时间
}
break;
case STATE_WASH:
if(timeout) {
state = STATE_WATER_OUT;
drain_valve = 1; // 打开排水阀
}
break;
case STATE_WATER_OUT:
if(timeout) {
drain_valve = 0;
state = STATE_SPIN;
motor_speed = HIGH_SPEED; // 高速脱水
}
break;
case STATE_SPIN:
if(timeout) {
motor_speed = STOP;
if(++cycle >= 3) {
state = STATE_ALARM;
} else {
state = STATE_WATER_IN;
}
}
break;
case STATE_ALARM:
if(timeout) {
state = STATE_IDLE;
cycle = 0;
}
break;
}
}
5. 关键问题与解决方案
5.1 数码管显示闪烁问题
初期测试发现数码管显示有闪烁现象,通过以下措施解决:
- 调整扫描频率到200Hz以上
- 在段选数据变化前先关闭位选
- 增加延时确保显示稳定
c复制// 优化后的显示函数
void display_optimized(void)
{
P0 = 0xFF; // 先关闭所有段
switch(pos)
{
case 0:
smg1 = 1; // 先关闭上一个位选
P0 = seg_table[wash_count];
smg1 = 0; // 再打开当前位选
break;
// 其他位类似处理
}
delay_ms(2); // 适当延时
}
5.2 电机干扰问题
电机启停时会导致单片机复位,解决方案:
- 在电机电源端增加1000μF电解电容
- 单片机电源增加LC滤波电路
- 所有信号线增加100Ω电阻缓冲
- 优化PCB布局,缩短电机驱动走线
5.3 时间分配算法优化
原始时间分配采用整数运算,导致累计误差:
c复制// 改进前
void set_wash_time(void)
{
switch(wash_count) {
case 1: remain_time = total_time/2; break;
case 2: remain_time = total_time/3; break;
case 3: remain_time = total_time/6; break;
}
}
// 改进后 - 使用余数补偿
void set_wash_time_optimized(void)
{
static uint remainder = 0;
switch(wash_count) {
case 1:
remain_time = total_time/2 + remainder;
remainder = total_time%2;
break;
case 2:
remain_time = total_time/3 + remainder;
remainder = total_time%3;
break;
case 3:
remain_time = total_time/6 + remainder;
break;
}
}
6. 系统测试与优化
6.1 Proteus仿真测试
在Proteus中搭建完整仿真电路,测试内容包括:
- 按键功能测试:设置时间、启停控制
- 显示测试:验证数码管显示内容正确性
- 电机驱动测试:检查正反转控制逻辑
- 完整流程测试:模拟三次洗涤循环
仿真中发现的问题:
- 数码管显示残影 → 增加消隐处理
- 电机启动瞬间电流过大 → 增加软启动控制
- 状态切换不流畅 → 调整状态机时序
6.2 实物测试数据
实际测试记录的关键数据:
| 测试项目 | 预期结果 | 实测结果 | 偏差分析 |
|---|---|---|---|
| 时间设置范围 | 10-30分钟 | 10-30分钟 | 符合 |
| 第一次洗涤时间 | 预设1/2 | 预设1/2 | 符合 |
| 电机正转周期 | 10秒 | 9.8秒 | 定时器误差 |
| 脱水转速 | 1200rpm | 1150rpm | 负载影响 |
| 整机功耗 | <50W | 48W | 符合 |
6.3 最终优化措施
根据测试结果实施的优化:
- 校准定时器参数,补偿0.2秒误差
- 增加电机转速反馈,实现闭环控制
- 优化显示刷新算法,降低CPU占用率
- 添加看门狗电路,提高系统稳定性
c复制// 增加看门狗初始化
void wdt_init(void)
{
WDT_CONTR = 0x35; // 预分频256,约1.6秒复位
}
// 主循环中喂狗
void main()
{
wdt_init();
while(1) {
WDT_CONTR |= 0x10; // 喂狗
// ...其他代码
}
}
7. 项目总结与扩展
在实际开发过程中,我总结了以下几点经验:
-
电源设计至关重要,特别是同时包含数字电路和电机驱动的系统,必须做好隔离和滤波。
-
状态机是控制类程序的最佳实践,相比线性流程更易于维护和扩展。我在项目中采用了查表法实现状态机,大幅简化了流程控制逻辑。
-
时间分配算法要注意整数除法的截断问题,采用余数累积法可以避免时间分配误差。
这个系统还可以进一步扩展:
- 增加温度传感器,实现加热洗涤功能
- 添加蓝牙模块,支持手机APP控制
- 改用步进电机,实现更精确的转速控制
- 增加EEPROM存储,记忆常用洗涤程序
对于想尝试类似项目的开发者,我建议先从Proteus仿真开始,验证基本功能后再制作实物,可以节省大量调试时间。电机驱动部分要特别注意PCB布局和电源设计,这是最容易出问题的环节。