ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于51单片机的温度控制电机Proteus仿真设计与实现

基于51单片机的温度控制电机Proteus仿真设计与实现 简介一套基于51单片机的温度控制电机仿真项目资料面向单片机初学者、电子类课程设计或毕业设计人群解决“如何根据环境温度自动启停/调速电机”的典型控制问题。压缩包共34个文件约123KB主要包含C语言源码.c/.h、Keil工程文件.uvproj/.uvopt、Proteus仿真文件.pdsprj/.pdsbak、HEX烧录文件及编译中间产物源码、工程、仿真与输出文件分目录存放便于直接打开工程查看代码并运行仿真。已有106人学习下载。项目完整覆盖温度采集DS18B20/DHT11、ADC转换、温度阈值判断、PWM电机调速、LCD1602显示等关键环节介绍了根据温度变化控制电机启停与速度的核心逻辑并配有Proteus仿真电路便于无硬件环境下验证控制流程。资料中的代码包含初始化、中断服务、主循环与LCD交互等模块结构清晰注释明确适合作为课程设计、毕业设计或单片机入门进阶的参考模板。1. 为什么“温度控制电机”值得用51单片机在Proteus里先搭一遍课程设计答辩现场最常出现的尴尬场面是Proteus 里的电机空转LCD 上温度在跳但问一句“温度和转速之间到底是谁决定的”答不上来。原因很统一——只把 DS18B20 的读数显示出来了电机是另外单独接的电源中间根本没有算法在起作用。“基于51单片机的温度控制电机仿真”这个题目真正要做的不是点亮一颗 LED而是把“温度采集 → 控制逻辑 → 电机驱动”这条闭环链路完整跑通。用 51 单片机做这个闭环性价比很高DS18B20 的数字温度接口只有一根线定时器可以顺便生成 PWMProteus 里又能直接观察占空比变化对电机转速的影响。对于课程设计、毕业设计或者想复习自动控制基础概念的嵌入式工程师这套仿真环境最大的价值是“改参数不用动烙铁”。你在 Proteus 里能把比例系数调明白上了实物板之后面对的现象基本都能对上号。2. 温度控制电机的系统拆解与 Proteus 选型2.1 信号链路从 DS18B20 到直流电机的完整回路先把这个仿真拆成四段后面写代码、接线、排错都按这条链路走温度感知DS18B20 挂在 P2.0 口通过单总线协议把 16 位温度数据送给 51 单片机。控制决策单片机读温度后用比较器、线性映射或者增量式 PID 计算出一个 0100 的占空比目标值。PWM 输出定时器中断按目标值生成 200Hz 的 PWM给到电机驱动芯片的使能端。电机执行直流电机的平均电压随占空比变化转速跟着温度走。显示部分属于辅助链路用 LCD1602 把当前温度、目标占空比打出来主要是让仿真现象更直观答辩时也好讲。这条链路的顺序感很重要。写程序时如果先写了 PWM 和电机再回头补 DS18B20很容易出现“温度值还没读出来电机已经在全速转”这种逻辑混乱。我在工程里的习惯是先单独调通温度采集打印温度再单独调通 PWM看占空比最后才把两边接起来。2.2 器件选型为什么是 DS18B20 和普通直流电机温度传感器有两个选择NTC 热敏电阻加 ADC或者 DS18B20。在 51 上做 NTC 方案要额外处理 ADC 的基准电压、分压电阻和电阻-温度换算表Proteus 里也要多接一个 ADC 芯片整个链路的坑会多一倍。DS18B20 是数字输出占用一个 IO 口Proteus 自带模型12 位分辨率下精度是 0.0625℃课程设计要求完全够用。电机也分两类直流电机和步进电机。步进电机的控制语义是“位置”需要持续发脉冲而温度控制电机的场景通常表达的是“风速”或者“搅拌速度”用直流电机的转速更直观。Proteus 元件库里搜MOTOR-DC就能找到直流电机模型PWM 平均电压和转速近似线性正好用来展示温度变化。元件选型对照表如下模块Proteus 中查找名说明单片机AT89C51 / AT89C52课程设计常用型号外部晶振 12MHz温度传感器DS18B20单总线数字接口需要 4.7k 上拉电阻直流电机MOTOR-DCProteus 自带模型靠平均电压调速电机驱动L293D双 H 桥驱动可用 PWM 控制使能端LCD 显示LM016L16 字符两行液晶Proteus 里替代 LCD1602晶振CRYSTAL12MHz需与 Keil 工程设置一致2.3 引脚分配与最小系统搭建在写代码之前先把引脚映射固定下来。下面这段宏定义是整篇程序的硬件基础Keil 工程里的引脚网络标号必须和 Proteus 原理图一一对应// 温度控制电机仿真 -- 引脚分配 sbit DQ P2^0; // DS18B20 数据线单总线 sbit MOTOR_EN P1^2; // L293D 使能端接单片机 PWM 输出 sbit MOTOR_A P1^0; // L293D 输入 1控制方向 sbit MOTOR_B P1^1; // L293D 输入 2控制方向 #define PWM_MAX 100 // 占空比上限单位% #define PWM_MIN 0 // 占空比下限引脚分配的原则是PWM 输出尽量放在可同时驱动 L293D 使能端的 IO 上方向引脚放在相邻位方便接线排查。用 12MHz 晶振而不是 11.0592MHz是因为温度采集和 PWM 不需要精确波特率12MHz 的机器周期正好是 1us延时换算方便。最小系统的搭建顺序在 Proteus 左侧元件列表里依次搜索并放置上述元件连好复位电路10uF 电容加 10k 电阻到 VCC和晶振电路再把 DS18B20 的数据脚通过 4.7k 上拉电阻接到 P2.0。Keil 工程要选择 AT89C51 或兼容设备编译生成 hex 文件后双击原理图中的单片机芯片把 hex 加载进去点左下角运行按钮。提示Proteus 原理图里的晶振频率必须和 Keil 工程 Options for Target 里的 Xtal 设置一致否则仿真里所有延时都会偏离预期DS18B20 容易初始化失败。3. 用51单片机读取DS18B20仿真里的单总线时序与代码3.1 单总线协议的核心窗口复位、写、读DS18B20 只有一根数据线所有操作靠严格的时序完成。有的朋友在实物上碰巧能读到 Proteus 里却不工作原因往往是模型对时序的检查比真实器件更“较真”。三个基本操作必须吃透复位主机拉低总线 480960us释放后等待 1560us从机会拉低 60240us 作为应答脉冲。写 1主机拉低 115us然后释放总线整个时隙持续 60120us。写 0主机拉低 60120us时隙后半段才能释放。读主机拉低至少 1us 释放然后在 15us 内采样电平。这些时间参数可以整理成一张速查表写延时函数时对照着调操作主机动作关键时间参数从机行为复位拉低总线480960us1560us 后拉低应答写 0拉低保持60120us采样低电平写 1拉低后快速释放115us采样高电平读拉低后释放15us 内采样拉高表示 13.2 12MHz晶振下的机器周期与延时换算51 单片机标准架构下机器周期是晶振频率的 12 分频12MHz 晶振对应机器周期 1us。软件延时用_nop_()空操作实现一次_nop_()约为 1us但嵌入 C 语言后循环判断有额外开销所以实际延时时间需要留余量。// 粗略延时函数12MHz 下 1 个循环约 4~5us void delay_us(unsigned int us) { unsigned int i; for(i 0; i us; i) { _nop_(); _nop_(); _nop_(); _nop_(); } }这个函数不追求精确因为 DS18B20 的时序容忍范围是几十到几百微秒只要保证最小时序大于协议要求、最大时序小于协议上限即可。Proteus 仿真里哪怕主频设置和延时略有误差也会反映为读出来的温度异常所以每次改晶振后要重新校准延时。3.3 DS18B20 驱动代码初始化、读写、拼接温度下面是一套可直接放进 Keil C51 工程的 DS18B20 驱动只保留核心逻辑// DS18B20 复位函数返回 0 表示有应答 unsigned char ds18b20_reset(void) { unsigned char presence; DQ 0; delay_us(500); // 拉低 500us满足 480us 最小时长 DQ 1; delay_us(60); // 等待从机应答窗口 presence DQ; // 采样低电平表示存在 delay_us(240); return presence; } // 写一个字节低位在前 void ds18b20_write_byte(unsigned char dat) { unsigned char i; for(i 0; i 8; i) { DQ 0; _nop_(); // 写时隙起始 DQ dat 0x01; delay_us(60); // 保持整个写时隙 DQ 1; dat 1; } } // 读一个字节低位在前 unsigned char ds18b20_read_byte(void) { unsigned char i, dat 0; for(i 0; i 8; i) { dat 1; DQ 0; _nop_(); // 读时隙开始 DQ 1; _nop_(); // 释放总线让从机输出 if(DQ) dat | 0x80; delay_us(60); } return dat; } // 读取温度并拼接为 16 位整数 unsigned int ds18b20_read_temp(void) { unsigned char temp_l, temp_h; unsigned int temp; ds18b20_reset(); ds18b20_write_byte(0xCC); // 跳过 ROM 匹配总线上只有一个设备 ds18b20_write_byte(0x44); // 启动温度转换12 位精度约 750ms while(!DQ); // 等待转换完成转换中为低电平 ds18b20_reset(); ds18b20_write_byte(0xCC); ds18b20_write_byte(0xBE); // 读取暂存器中 9 字节数据 temp_l ds18b20_read_byte(); temp_h ds18b20_read_byte(); temp (temp_h 8) | temp_l; return temp; }参数说明0xCC是跳过 ROM 指令只适合总线上挂一颗传感器0x44启动转换0xBE读取暂存器。读回来的 16 位数据高字节在高位低字节在低位实际温度由temp * 0.0625得到。while(!DQ)这条循环在仿真和实物里都有效但注意转换期间 DS18B20 会拉低总线如果程序卡在这里先检查复位时序是不是太短。3.4 仿真里温度卡在25℃或85℃的排查Proteus 仿真中温度读数固定不动是高频问题。85℃是 DS18B20 上电后暂存器的默认复位值如果读到 0x0550 附近说明 ROM 和功能指令根本没执行25℃ 则是 Proteus 模型的默认环境温度如果收回来的数一直是它多半是启动了转换但没有等待完成就读取了暂存器。遇到这两种情况先查三处DS18B20 数据脚有没有接 4.7k 上拉Keil 工程晶振和 Proteus 晶振是否都是 12MHzdelay_us里的循环次数是否因为优化级别被编译器裁掉了。最笨但最有效的验证方式是在初始化完成后读一次暂存器如果读出来的高字节是 0x05说明时序链路没有通。4. 温度到电机转速的控制策略与整数化PID4.1 三种常见控制方式开关量、线性映射、PID控制逻辑是这个仿真题目的核心评审老师问的问题基本都集中在这一块。第一种是开关量控制温度超过 30℃ 就启动电机满转低于 30℃ 就停。逻辑最简单但电机频繁启停对直流电机和继电器都不友好而且没有中间状态。第二种是线性映射把温度区间映射到占空比区间比如 20℃ 对应 0%40℃ 对应 100%中间线性增长。这种方案在课程设计里最常见因为现象直观温度升高转速平滑上升。第三种是 PID 闭环把温度作为被控量占空比作为执行量通过温差实时修正输出电压。需要说清楚一个容易误解的点Proteus 自带的 MOTOR-DC 模型一般没有转速反馈端子做不了真正的转速闭环常见做法是把 PID 放在“温度 → 占空比”这条路径上电机是执行机构控制目标是温度稳定。如果你课题要求的是转速闭环需要另加测速模型或者自己模拟编码器信号但课程设计答辩时把“温度闭环”讲透彻已经足够。4.2 增量式PID的整数化实现51 单片机没有硬件浮点单元直接写浮点 PID 在仿真里勉强能跑但到了实物上计算耗时会让 PWM 输出抖动。我一般用整数增量式 PID输出的是占空比增量每次只变化一个步长天然有抗积分饱和的效果// 增量式 PID 参数放大 10 倍后取整 #define KP 10 // 实际 Kp 1.0 #define KI 0 // 实际 Ki 0 #define KD 20 // 实际 Kd 2.0 int pid_increment(int target_temp, int current_temp) { static int last_error 0; int error target_temp - current_temp; int inc; // 增量式公式Kp*(E-E1) Ki*E Kd*(E-2*E1E2) // 这里简化为 PI 结构D 项按需扩展 inc KP * error - KP * last_error KI * error; last_error error; // 限制单次增量防止占空比突变 if(inc 5) inc 5; if(inc -5) inc -5; return inc; }参数说明KP10表示放大 10 倍后的比例系数实际为 1.0KI0先禁掉积分方便观察纯比例下的震荡趋势增量限幅在 ±5 之间避免温度瞬间波动导致电机转速大幅跳变。这个函数在主循环里每个控制周期调用一次返回值叠加到当前占空比上经过上下限裁剪后作为 PWM 的新目标值。注意限幅只限制单次增量还要在占空比赋值时做 0100 的全局限幅否则 PWM 脉宽可能反向翻转。4.3 用51单片机定时器生成200Hz PWM51 单片机没有硬件 PWM 外设用定时器中断翻转 IO 输出是最常用的替代方案。以 50us 中断一次为例100 次中断组成一个 5ms 周期对应 200Hzunsigned char pwm_duty 30; // 占空比初始值 30% void timer0_init(void) { TMOD 0x02; // 定时器0方式28位自动重装 TH0 0xCE; // 12MHz 下 50us 中断一次 TL0 0xCE; ET0 1; TR0 1; EA 1; } void timer0_isr(void) interrupt 1 { static unsigned char cnt 0; cnt; if(cnt 100) cnt 0; if(cnt pwm_duty) MOTOR_EN 1; // 使能 L293D电机通电 else MOTOR_EN 0; // 关闭使能电机惯性运转 }参数说明TH00xCE对应 256-50206加上定时器重装和中断跳转开销实际周期接近目标值cnt每递增到 100 清零形成 100 份的时基占空比分辨率是 1%pwm_duty是一个全局变量PID 或者线性映射函数修改它就能直接改变电机转速中断里只做比较不需要除法节省时钟周期。200Hz 这个频率对仿真里的 MOTOR-DC 模型足够直流电机的机械惯性会滤掉大部分脉动。如果发现电机一顿一顿优先提高中断频率比如改成 20us 中断一次PWM 频率升到 500Hz但注意 51 在中断里做比较运算的耗时占比频率过高会影响主循环。4.4 Kp、Ki、Kd在温控仿真中的整定方向PID 参数不能拍脑袋填在 Proteus 里整定一样要先看现象再动参数。先用纯比例把系统调到临界震荡再引入积分消除余差最后用微分处理过冲。下面是参考方向参数增大后的效果过大的后果仿真中观察方式Kp响应加快温度逼近目标更快震荡加剧占空比反复跳变观察 LCD 温度曲线上下波动Ki消除稳态误差最终靠近目标温度积分饱和超调明显观察温度是否长时间偏低于目标Kd抑制超调和震荡放大噪声占空比抖动观察升温阶段首次过冲幅度在仿真里整定的经验是Kp 从 0.5 开始逐步翻倍每次修改后让系统重新升温一次看响应出现等幅震荡时记下当前 Kp再按振荡周期的三分之一左右设置 Ki。这套顺序放到实物板同样成立唯一区别是实物热惯性大震荡周期更长需要多点耐心。5. Proteus仿真搭建、波形验证与常见故障5.1 两种电机驱动接法直驱与L293DProteus 里驱动 MOTOR-DC 有两种接法。一种是直接把 PWM 引脚接电机正极、负极接地这种接法只适用于微小功率电机模型而且数字 IO 的高电平电压有限转速的区分度不高。做课程设计更稳妥的接法是 L293D 驱动芯片和实物方案一致L293D 引脚接法作用EN1/2 (Pin1)接单片机 P1.2 的 PWM 输出使能通道控制平均电压IN1 (Pin2)接 P1.0方向控制IN2 (Pin7)接 P1.1方向控制OUT1/OUT2接 MOTOR-DC 两端输出到电机VS接 12V 电源电机侧供电VSS接 5V 电源逻辑侧供电IN1/IN2 都为低电平时电机停转一高一低时正转或反转。方向引脚接固定电平就是单方向调速如果要演示正反转需要再加按键切换逻辑。5.2 Proteus 中从原理图到运行的完整步骤在 Proteus 里从零搭建这套仿真的步骤按顺序执行基本不会乱新建工程元件模式中搜索 AT89C51、MOTOR-DC、L293D、DS18B20、LM016L、RES、CAP、CRYSTAL依次放置到原理图。给 51 单片机画复位电路和晶振电路晶振参数改为 12MHz。连 DS18B20数据脚接 P2.0同时加 4.7k 上拉电阻到 VCC。连 L293D按 5.1 表格接线逻辑地 GND 全部接到同一个地网络。双击 AT89C51在 Program File 里加载 Keil 编译生成的 hex 文件。点击仿真运行按钮先观察 DS18B20 温度是否变化再观察电机是否随温度变化转动。第 6 步建议分两次做。第一次只加载只含温度采集的固件确认 LCD 或调试窗口有温度输出第二次再加载完整固件。这样做的好处是如果电机不转至少能排除温度采集部分的嫌疑。5.3 用示波器验证PWM波形与占空比鼠标左键点住 MOTOR_EN 引脚上的导线拖出探针再从左侧工具栏选择虚拟示波器把探针接到示波器通道上。运行仿真后示波器上能看到一组矩形波脉冲宽度的变化直接反映占空比调整。没有示波器时用虚拟终端观察串口输出也能判断控制逻辑是否在工作// 串口发送一个字符用于调试输出 void uart_send_char(unsigned char c) { SBUF c; while(!TI); TI 0; } // 将温度和占空比按字节发送到虚拟终端 void debug_report(unsigned int temp, unsigned char duty) { uart_send_char((temp 8) 0xFF); uart_send_char(temp 0xFF); uart_send_char(duty); }参数说明Proteus 里的 Virtual Terminal 虚拟终端接在 P3.0(RXD) 和 P3.1(TXD) 上波特率通过串口初始化设置常见用 9600。debug_report把温度和占空比按原始字节发送虚拟终端里看到的是 ASCII 码对应的字符如果想直接看数值可以改成十六进制字符串发送。5.4 仿真故障排查表仿真跑不起来时90% 的问题集中在接线和晶振配置上。下面这份排查表基本覆盖了常见的课程设计症状现象可能原因处理方式电机完全不转L293D 的 VS 没接电源或 EN 脚没有 PWM确认 VS 接 12VEN 脚有矩形波输出电机一直全速转PWM 的pwm_duty没有更新或者 EN 直接接了 VCC检查定时器中断是否开启pwm_duty 是否被修改温度读数固定 85℃DS18B20 初始化时序异常检查上拉电阻、复位延时、晶振频率LCD 花屏或无显示对比度引脚没调好或者 EW/RS 接错LM016L 的 VEE 接电位器调对比度查引脚映射仿真运行发散或异常跳变数字 PWM 直接驱动模拟电机信号类型冲突改用 L293D 隔离或在输出加滤波电容温度读取周期太长12 位转换需 750ms主循环有阻塞将转换启动和读取拆到两个循环阶段提示如果 Proteus 弹出“Simulation is not converging”一类的错误先把仿真步长调小再检查驱动芯片电源和地是否形成负反馈回路仿真发散多半是模型里的数值迭代超出了收敛范围不是代码问题。6. 从仿真到实物控制周期、映射校准与整定顺序6.1 把DS18B20的750ms转换时间与PID控制周期解耦温度控制电机仿真里有一个容易被忽略的时间概念DS18B20 精度设为 12 位时一次温度转换最快也要 750ms而 PID 的控制周期通常希望更短。如果程序里每次循环都读温度然后立刻算 PID控制周期就会被传感器锁死而且while(!DQ)等待转换期间整个主循环都卡住了PWM 中断虽然还能跑但控制逻辑完全停止响应。我一般会在工程里拆两个时间槽定时器中断负责 PWM 输出这个周期固定不变主循环维护一个 1 秒的软件计时标志时间到了才启动一次温度转换转换完成再读温度并计算 PID。物理上可以接受的方案是设定目标温度 700ms 才更新一次但 PID 输出仍然每 50ms 根据最近的温度值修正一次占空比只是修正幅度很小。这样温度响应不会因为传感器采样慢而变得“一卡一卡”。6.2 温度与转速的映射曲线改造成查表线性映射公式duty (temp - T_min) / (T_max - T_min) * 100在仿真里演示足够但它的缺点是没有上下限保护温度低于 T_min 时占空比变成负数必须额外裁剪。更好的做法是分段查表加线性插值把温度区间拆成几段拐点// 温度-占空比查找表第一列温度第二列占空比 const unsigned char code temp_table[][2] { {20, 0}, {25, 20}, {30, 50}, {35, 80}, {40, 100} }; unsigned char calc_duty(int temp) { unsigned char i; if(temp 20) return 0; if(temp 40) return 100; for(i 0; i 4; i) { if(temp temp_table[i][0] temp temp_table[i1][0]) { // 两点之间线性插值直接按比例计算 return temp_table[i][1] (temp - temp_table[i][0]) * (temp_table[i1][1] - temp_table[i][1]) / (temp_table[i1][0] - temp_table[i][0]); } } return 0; }参数说明code关键字让数组存放在程序存储区不占宝贵的数据 RAM插值公式里先乘 100 再除整型差避免小数浮点运算。查表法的好处是答辩时改一个拐点温度只需要改数组数值不用重写控制逻辑评委问“40℃以上怎么办”也能直接指着头尾两个边界回答。6.3 实物板前的三个修正与一套整定顺序从 Proteus 切到真实硬件有几个仿真永远暴露不出来的差异需要提前修正。第一实物电机的启动电流远大于逻辑 IO 的驱动能力L293D 的 VS 侧要加续流二极管电源入口并联一个大电容。第二Proteus 里 4.7k 上拉可能刚好能用实物上一段长线缆就会引入干扰建议 4.7k 换成 1k 到 4.7k 之间实际测试。第三仿真里 200Hz 的 PWM 不吵实物上可能会有啸叫把频率提到 1kHz 以上通常能解决。调参顺序我建议固定成一个流程先把 PID 的 Kd 置零、Ki 置零只保留 Kp观察温度到达目标后有没有过冲然后逐步加 Ki 直到稳态误差消失最后加 Kd 压首次超调。每调一步都让电机重新经历一次完整升温过程记录下占空比变化和历史温度漂移。把 Proteus 的示波器接在 PWM 输出上就能同时看到控制器输出波形和温度变化趋势——这套验证方法可以直接带到实物调试里换任何执行机构都能沿用。本文还有配套的精品资源点击获取
返回列表