基于LPC2124的温度模糊控制系统Proteus仿真
一、系统概述
本系统采用NXP LPC2124(ARM7TDMI-S内核)微控制器作为核心,结合模糊控制算法实现对温度的智能调节。系统通过温度传感器采集实时温度,经模糊控制器处理后输出PWM信号驱动加热/制冷装置,形成闭环控制。整个系统可在Proteus 8中完成软硬件联合仿真。
二、系统架构
1. 系统框图
┌─────────────────────────────────────────────────────┐
│ 温度模糊控制系统 │
├─────────────────────────────────────────────────────┤
│ 温度传感器 → ADC采集 → LPC2124 → PWM输出 → 执行机构 │
│ (DS18B20/LM35) │ 模糊控制算法 │ (加热器/风扇) │
│ ↓ │ │
│ LCD显示模块 │ │
└─────────────────────────────────────────────────────┘
2. 核心组件
| 模块 | 器件型号 | 功能说明 |
|---|---|---|
| 主控制器 | LPC2124 | ARM7内核,主频60MHz |
| 温度传感器 | DS18B20或LM35 | 温度采集,精度±0.5°C |
| 显示模块 | LCD1602 | 显示当前温度和设定温度 |
| 执行机构 | 加热电阻+风扇 | 双向温度调节 |
| 驱动电路 | 三极管/继电器 | 功率放大与控制 |
| 仿真环境 | Proteus 8.9+ | 电路设计与程序仿真 |
| 开发环境 | Keil MDK-ARM | ARM程序开发与编译 |
三、硬件电路设计(Proteus)
1. Proteus元件清单
| 元件类别 | 元件名称 | Proteus库中名称 |
|---|---|---|
| 微控制器 | LPC2124 | LPC2124 |
| 温度传感器 | DS18B20 | DS18B20 |
| 显示模块 | LCD1602 | LM016L (16×2字符LCD) |
| 加热元件 | 加热电阻 | RESISTOR (100Ω/10W) |
| 冷却元件 | 直流风扇 | MOTOR-DC |
| 驱动器件 | 三极管 | 2N2222 (NPN) |
| 驱动器件 | 继电器 | RELAY-SPST |
| 电源 | 直流电源 | BATTERY (5V/12V) |
| 调试接口 | 虚拟终端 | VIRTUAL TERMINAL |
| 测量仪器 | 电压表/电流表 | DC VOLTMETER/AMMETER |
2. Proteus电路原理图设计
主控电路
LPC2124引脚分配:
P0.0-P0.7 → LCD数据线D0-D7
P0.8 → LCD RS (寄存器选择)
P0.9 → LCD RW (读写控制)
P0.10 → LCD EN (使能信号)
P0.28 → DS18B20数据线 (单总线)
P0.29 → 加热控制PWM输出
P0.30 → 风扇控制PWM输出
P0.31 → ADC输入 (LM35模拟输入)
VDD → 3.3V电源
VSS → GND
温度采集电路
-
方案A:DS18B20数字传感器
DS18B20引脚: 1 - GND 2 - DQ (数据) → LPC2124 P0.28 + 4.7kΩ上拉电阻到VCC 3 - VCC (3.3V-5V) -
方案B:LM35模拟传感器
LM35引脚: 1 - VCC (4V-20V) 2 - Vout → LPC2124 P0.31 (ADC输入) 3 - GND
功率驱动电路
加热控制:
LPC2124 P0.29 → 1kΩ电阻 → 2N2222基极
2N2222集电极 → 加热电阻 → 12V电源
2N2222发射极 → GND
风扇控制:
LPC2124 P0.30 → 1kΩ电阻 → 继电器线圈
继电器常开触点 → 12V风扇
3. Proteus仿真文件设置
- 创建新工程:选择"LPC2124"作为微控制器
- 添加元件:从库中搜索并放置上述元件
- 连线:按照原理图连接各元件
- 电源配置:添加+3.3V和+12V电源
- 添加虚拟仪器:用于监测温度和控制信号
四、模糊控制算法设计
1. 模糊控制器结构
输入变量:
E (误差) = 设定温度 - 实际温度
EC (误差变化率) = dE/dt
输出变量:
U (控制量) = PWM占空比 (0-100%)
模糊集定义:
E: {NB, NM, NS, ZO, PS, PM, PB} (负大,负中,负小,零,正小,正中,正大)
EC: {NB, NM, NS, ZO, PS, PM, PB}
U: {NB, NM, NS, ZO, PS, PM, PB}
2. 隶属度函数设计
// 三角形隶属度函数
typedef struct {
float a; // 左边界
float b; // 中心点
float c; // 右边界
} TriangleMF;
// 误差E的隶属度函数 (-10°C ~ +10°C)
TriangleMF E_mf[7] = {
{-10, -10, -6}, // NB
{-8, -5, -2}, // NM
{-4, -2, 0}, // NS
{-1, 0, 1}, // ZO
{0, 2, 4}, // PS
{2, 5, 8}, // PM
{6, 10, 10} // PB
};
// 误差变化率EC的隶属度函数 (-5°C/s ~ +5°C/s)
TriangleMF EC_mf[7] = {
{-5, -5, -3}, // NB
{-4, -2, -1}, // NM
{-2, -1, 0}, // NS
{-0.5, 0, 0.5}, // ZO
{0, 1, 2}, // PS
{1, 2, 4}, // PM
{3, 5, 5} // PB
};
3. 模糊规则库(49条规则)
// 模糊规则表 [E][EC] → U
uint8_t fuzzy_rule[7][7] = {
// EC: NB NM NS ZO PS PM PB
{ 6, 6, 5, 5, 4, 3, 2 }, // E: NB (温度过低)
{ 6, 5, 5, 4, 3, 2, 1 }, // E: NM
{ 5, 5, 4, 3, 2, 1, 0 }, // E: NS
{ 4, 3, 2, 0, -2, -3, -4 }, // E: ZO (接近设定)
{ 0, -1, -2, -3, -4, -5, -5 }, // E: PS
{ -1, -2, -3, -4, -5, -5, -6 }, // E: PM
{ -2, -3, -4, -5, -5, -6, -6 } // E: PB (温度过高)
};
// 注:输出值0-6对应模糊集{NB...PB},实际控制量需去模糊化
4. 模糊推理与去模糊化
// 重心法去模糊化
float defuzzify(float *membership, float *output_values) {
float numerator = 0.0;
float denominator = 0.0;
for(int i = 0; i < 7; i++) {
numerator += membership[i] * output_values[i];
denominator += membership[i];
}
if(denominator == 0) return 0.0;
return numerator / denominator;
}
参考代码 基于LPC2124的温度模糊控制系统Proteus仿真 www.youwenfan.com/contentcnt/135550.html
五、软件程序设计
1. 主程序框架(main.c)
#include "LPC21xx.h"
#include "fuzzy.h"
#include "lcd.h"
#include "ds18b20.h"
#include "pwm.h"
// 全局变量
float set_temp = 25.0; // 设定温度
float current_temp = 0.0; // 当前温度
float last_temp = 0.0; // 上次温度
float error = 0.0; // 误差
float error_change = 0.0; // 误差变化率
float control_output = 0.0; // 控制输出
// 系统初始化
void SystemInit(void) {
// 1. 系统时钟初始化
PLL_init();
// 2. GPIO初始化
GPIO_Init();
// 3. 定时器初始化(用于PWM和采样)
Timer0_Init();
Timer1_Init();
// 4. ADC初始化(如果使用LM35)
ADC_Init();
// 5. PWM初始化
PWM_Init();
// 6. LCD初始化
LCD_Init();
// 7. DS18B20初始化
DS18B20_Init();
// 8. 中断初始化
Interrupt_Init();
}
// 主循环
int main(void) {
SystemInit();
LCD_DisplayString("Temp Ctrl System");
delay_ms(1000);
LCD_Clear();
while(1) {
// 1. 温度采集
current_temp = Read_Temperature();
// 2. 计算误差和误差变化率
error = set_temp - current_temp;
error_change = (current_temp - last_temp) / SAMPLE_TIME;
last_temp = current_temp;
// 3. 模糊控制计算
control_output = Fuzzy_Controller(error, error_change);
// 4. 输出控制信号
if(control_output > 0) {
// 需要加热
Set_Heater_PWM(control_output);
Set_Fan_PWM(0);
} else {
// 需要冷却
Set_Heater_PWM(0);
Set_Fan_PWM(-control_output);
}
// 5. 显示更新
Display_Update();
// 6. 延时(采样周期)
delay_ms(SAMPLE_PERIOD);
}
return 0;
}
2. 模糊控制核心代码(fuzzy.c)
#include "fuzzy.h"
// 计算隶属度
void calculate_membership(float input, TriangleMF *mf, float *membership) {
for(int i = 0; i < 7; i++) {
if(input <= mf[i].a || input >= mf[i].c) {
membership[i] = 0.0;
} else if(input > mf[i].a && input <= mf[i].b) {
membership[i] = (input - mf[i].a) / (mf[i].b - mf[i].a);
} else {
membership[i] = (mf[i].c - input) / (mf[i].c - mf[i].b);
}
}
}
// 模糊控制器
float Fuzzy_Controller(float e, float ec) {
float e_membership[7], ec_membership[7];
float rule_strength[7][7];
float output_membership[7] = {0};
// 1. 模糊化
calculate_membership(e, E_mf, e_membership);
calculate_membership(ec, EC_mf, ec_membership);
// 2. 规则评估(Mamdani推理,取小运算)
for(int i = 0; i < 7; i++) {
for(int j = 0; j < 7; j++) {
rule_strength[i][j] = (e_membership[i] < ec_membership[j]) ?
e_membership[i] : ec_membership[j];
}
}
// 3. 规则聚合(取大运算)
for(int i = 0; i < 7; i++) {
for(int j = 0; j < 7; j++) {
int output_index = fuzzy_rule[i][j] + 3; // 映射到0-6
if(rule_strength[i][j] > output_membership[output_index]) {
output_membership[output_index] = rule_strength[i][j];
}
}
}
// 4. 去模糊化(重心法)
float output_values[7] = {-100, -66, -33, 0, 33, 66, 100}; // 输出论域
return defuzzify(output_membership, output_values);
}
3. DS18B20驱动代码(ds18b20.c)
#include "ds18b20.h"
// DS18B20初始化
void DS18B20_Init(void) {
DS18B20_Reset();
DS18B20_WriteByte(0xCC); // 跳过ROM
DS18B20_WriteByte(0x44); // 启动温度转换
}
// 读取温度
float Read_Temperature(void) {
uint8_t temp_l, temp_h;
int16_t temp;
float temperature;
DS18B20_Reset();
DS18B20_WriteByte(0xCC); // 跳过ROM
DS18B20_WriteByte(0xBE); // 读暂存器
temp_l = DS18B20_ReadByte();
temp_h = DS18B20_ReadByte();
temp = (temp_h << 8) | temp_l;
temperature = temp * 0.0625; // 12位分辨率
return temperature;
}
// 单总线延时函数
void DS18B20_Delay_us(uint32_t us) {
uint32_t i;
for(i = 0; i < us * 10; i++);
}
// 复位DS18B20
uint8_t DS18B20_Reset(void) {
uint8_t presence = 0;
DS18B20_OUTPUT();
DS18B20_LOW();
DS18B20_Delay_us(480);
DS18B20_INPUT();
DS18B20_Delay_us(60);
presence = !DS18B20_READ();
DS18B20_Delay_us(420);
return presence;
}
4. PWM控制代码(pwm.c)
#include "pwm.h"
// PWM初始化
void PWM_Init(void) {
// 配置P0.29为PWM1输出(加热控制)
PINSEL0 |= (1 << 26); // 选择PWM1功能
// 配置P0.30为PWM2输出(风扇控制)
PINSEL0 |= (1 << 28); // 选择PWM2功能
// PWM预分频设置
PWMPR = 0; // 不分频
// 设置PWM周期(决定PWM频率)
PWMMR0 = 10000; // 假设系统时钟60MHz,PWM频率=60MHz/10000=6kHz
// 设置PWM匹配控制
PWMMCR = (1 << 1); // MR0匹配时复位计数器
// 使能PWM输出
PWMPCR = (1 << 9) | (1 << 10); // 使能PWM1和PWM2输出
// 启动PWM
PWMTCR = (1 << 0) | (1 << 3); // 计数器使能,PWM使能
}
// 设置加热器PWM占空比
void Set_Heater_PWM(float duty) {
if(duty < 0) duty = 0;
if(duty > 100) duty = 100;
uint32_t match_value = (uint32_t)(PWMMR0 * duty / 100.0);
PWMMR1 = match_value; // PWM1匹配值
PWMLER = (1 << 1); // 锁存MR1新值
}
// 设置风扇PWM占空比
void Set_Fan_PWM(float duty) {
if(duty < 0) duty = 0;
if(duty > 100) duty = 100;
uint32_t match_value = (uint32_t)(PWMMR0 * duty / 100.0);
PWMMR2 = match_value; // PWM2匹配值
PWMLER = (1 << 2); // 锁存MR2新值
}
5. LCD显示代码(lcd.c)
#include "lcd.h"
// LCD初始化
void LCD_Init(void) {
delay_ms(15);
LCD_WriteCommand(0x38); // 8位数据,2行显示,5×7点阵
LCD_WriteCommand(0x0C); // 显示开,光标关,闪烁关
LCD_WriteCommand(0x06); // 写入后光标右移
LCD_WriteCommand(0x01); // 清屏
delay_ms(2);
}
// 显示温度信息
void Display_Update(void) {
char buffer[16];
// 第一行:当前温度
LCD_SetCursor(0, 0);
sprintf(buffer, "Temp:%5.1fC", current_temp);
LCD_DisplayString(buffer);
// 第二行:设定温度和控制输出
LCD_SetCursor(0, 1);
sprintf(buffer, "Set:%3.1f Out:%3.0f%%", set_temp, control_output);
LCD_DisplayString(buffer);
}
// LCD写命令
void LCD_WriteCommand(uint8_t cmd) {
LCD_RS = 0;
LCD_RW = 0;
LCD_DATA = cmd;
LCD_EN = 1;
delay_us(1);
LCD_EN = 0;
delay_ms(2);
}
// LCD写数据
void LCD_WriteData(uint8_t dat) {
LCD_RS = 1;
LCD_RW = 0;
LCD_DATA = dat;
LCD_EN = 1;
delay_us(1);
LCD_EN = 0;
delay_us(100);
}
六、Proteus仿真步骤
1. 仿真环境搭建
-
安装软件:
- Proteus 8.9或更高版本
- Keil MDK-ARM(用于编译代码)
- LPC2124设备库(Proteus自带)
-
创建Proteus工程:
- 新建工程,选择"LPC2124"作为微控制器
- 添加所需元件并连接电路
- 设置电源:VDD=3.3V,VCC=5V(传感器)
2. 程序编译与加载
-
Keil工程配置:
目标设备:LPC2124 编译器:ARM Compiler V5 优化等级:Level 2 (-O2) 输出文件:生成HEX文件 -
编译程序:
- 将上述C代码文件添加到Keil工程
- 配置正确的头文件路径
- 编译生成
fuzzy.hex文件
-
加载到Proteus:
- 双击Proteus中的LPC2124元件
- 在"Program File"中选择生成的HEX文件
- 设置时钟频率为12MHz(外部晶振)
3. 仿真运行与调试
-
启动仿真:
- 点击Proteus左下角的"运行"按钮
- 系统开始运行,LCD显示初始化信息
-
温度设置:
- 通过虚拟终端发送命令设置温度
- 示例命令:
SET 30.0(设置目标温度为30°C)
-
监测信号:
- 使用Proteus示波器观察PWM波形
- 使用电压表监测温度传感器输出
- 观察LCD显示的温度变化
-
性能测试:
- 改变环境温度(修改DS18B20的温度值)
- 观察系统的响应速度和稳态误差
- 记录超调量和调节时间
七、系统测试与优化
1. 性能测试指标
| 测试项目 | 期望值 | 测试方法 |
|---|---|---|
| 稳态误差 | ±0.5°C以内 | 保持环境温度稳定,记录偏差 |
| 调节时间 | < 60秒 | 从阶跃响应开始到进入稳态的时间 |
| 超调量 | < 5% | 最大超调温度与设定温度的比值 |
| 温度分辨率 | 0.1°C | 观察最小可分辨的温度变化 |
| 控制范围 | 0-50°C | 测试系统在不同设定温度下的性能 |
2. 模糊规则优化
根据仿真结果调整模糊规则:
// 优化后的规则表(减少超调)
uint8_t fuzzy_rule_optimized[7][7] = {
{ 6, 6, 5, 4, 3, 2, 1 },
{ 5, 5, 4, 3, 2, 1, 0 },
{ 4, 4, 3, 2, 1, 0, -1 },
{ 3, 2, 1, 0, -1, -2, -3 },
{ -1, 0, -1, -2, -3, -4, -4 },
{ 0, -1, -2, -3, -4, -5, -5 },
{ 1, -2, -3, -4, -5, -6, -6 }
};
3. PID-模糊复合控制
// 结合PID提高稳态精度
float PID_Fuzzy_Controller(float e, float ec) {
float fuzzy_output = Fuzzy_Controller(e, ec);
float pid_output = PID_Controller(e);
// 模糊控制主导动态过程,PID控制主导稳态
float weight = fabs(e) / 10.0; // 误差越大,模糊权重越高
if(weight > 1.0) weight = 1.0;
return weight * fuzzy_output + (1 - weight) * pid_output;
}
八、常见问题与解决
1. Proteus仿真问题
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| LPC2124无法运行程序 | HEX文件未正确加载 | 检查HEX文件路径,重新编译 |
| DS18B20温度读取失败 | 单总线时序不准确 | 调整延时函数,检查上拉电阻 |
| LCD显示乱码 | 初始化时序不正确 | 增加初始化延时,检查命令顺序 |
| PWM输出无波形 | 引脚功能未正确配置 | 检查PINSEL寄存器设置 |
| 仿真运行缓慢 | 计算机性能不足 | 关闭不必要的虚拟仪器,简化电路 |
2. 程序调试技巧
-
使用虚拟终端:输出调试信息
void UART_SendString(char *str) { while(*str) { while(!(U0LSR & 0x20)); U0THR = *str++; } } -
添加软件断点:在关键位置添加LED指示
void Debug_LED(uint8_t state) { if(state) IO0SET = (1 << 11); // P0.11 LED亮 else IO0CLR = (1 << 11); // P0.11 LED灭 } -
变量监视:通过LCD显示关键变量值
九、扩展应用
1. 多区域温度控制
// 扩展为多路温度控制
#define ZONE_COUNT 3
float zone_temp[ZONE_COUNT];
float zone_setpoint[ZONE_COUNT];
float zone_output[ZONE_COUNT];
void MultiZone_Control(void) {
for(int i = 0; i < ZONE_COUNT; i++) {
float error = zone_setpoint[i] - zone_temp[i];
float ec = (zone_temp[i] - last_zone_temp[i]) / SAMPLE_TIME;
zone_output[i] = Fuzzy_Controller(error, ec);
last_zone_temp[i] = zone_temp[i];
}
}
2. 网络通信功能
- 添加以太网模块(ENC28J60)
- 实现TCP/IP通信,远程监控温度
- 支持Web界面设置参数
3. 数据记录与分析
- 添加SD卡模块存储温度历史数据
- 实现温度曲线显示
- 导出数据到Excel分析
总结
本设计实现了基于LPC2124的温度模糊控制系统Proteus仿真,具有以下特点:
- 完整的软硬件方案:提供从电路设计到程序代码的全套解决方案
- 智能控制算法:采用模糊控制,适应非线性温度系统
- 可视化仿真:Proteus环境下实时观察系统运行状态
- 易于扩展:模块化设计,便于功能扩展和修改
- 教学实用:适合嵌入式系统、自动控制原理等课程设计
通过本仿真系统,可以深入理解:
- ARM7微控制器的应用开发
- 模糊控制算法的实现与调试
- 温度控制系统的设计与优化
- Proteus软硬件联合仿真技术
后续改进方向:
- 增加PID-模糊复合控制提高精度
- 添加触摸屏人机界面
- 实现物联网远程监控
- 优化节能控制策略