资讯详情

资讯详情

51单片机PWM直流电机调速与DS18B20温度联动Proteus仿真

简介这是一套基于51单片机的直流电机PWM控制与温度监测完整工程资料面向单片机初学者、课程设计或毕业设计学生帮助理解电机启停、加减速、急停及温度过高报警的实现思路同时掌握PWM调速与DS18B20测温的典型应用。资源共43个文件大小约954KB涵盖C语言源代码、Proteus仿真图DSN、原理图SchDoc、流程图BMP、元件清单Excel和Hex烧写文件等目录结构清晰便于按模块对照学习。功能上支持按键启动、加速、减速、紧急停止搭配DS18B20采集温度并通过LCD1602实时显示温度、PWM占空比与电机转速代码与仿真工程联动可直观看到按键操作时的波形与数值变化帮助理解PWM调制原理。目前已有356人学习适合需要完整项目模板、课程设计参考或入门调试实践的开发者尤其对Proteus仿真与51单片机综合应用有较大的借鉴价值。1. 从 PWM 到温度反馈这个项目的最短闭环路径做过 51 单片机课程设计的人多半有过这种体验代码在 Keil 里编译零错误下载到 Proteus 仿真图里电机就是不动或者转速只停留在“转”和“不转”两个状态加减速按键按下去毫无反应。原因往往不在程序逻辑而在一个被忽略的前提——直流电机是功率器件单片机的引脚只能输出毫安级信号必须通过驱动电路放大而“加减速”和“温度 PWM”这两个需求又要求你把 PWM 占空比的计算从“写死一个值”改成“按键和温度传感器共同决定的实时变量”。这个标题实际上是把三类技术点压在一套项目里直流电机的驱动与 PWM 调速、基于温度传感器的转速联动、以及 Proteus 仿真环境下的原理图与代码联调。对在校生来说它是覆盖单片机、传感器、电力电子三门课的综合性课设对已经工作的工程师它则是一个验证 PWM 频率选择、占空比分辨率、单总线时序与仿真模型互相牵制的低成本样本。本文按“硬件选型 → 代码实现 → 流程设计 → 仿真排错 → 验收技巧”的顺序把从原理图到源代码的完整路径讲透所有代码和参数均可直接抄进 Keil 和 Proteus 使用。2. 原理图与物料清单L298N、DS18B20 怎么选怎么连2.1 驱动方案对比为什么不用 ULN2003 非要用 L298N直流电机驱动最常见的有两种方案ULN2003 达林顿管阵列和 L298N 双 H 桥驱动器。ULN2003 的优势是便宜、引脚少、Proteus 元件库里直接搜得到但它只能做单向驱动内部集成的续流二极管只支持共阳接法电机转速一高、电流一大芯片压降带来的发热就很明显。更重要的是ULN2003 做不了正反转一旦后续想加“反转刹车”功能整个驱动部分要推翻重来。L298N 是完整的 H 桥结构IN1/IN2 控制方向ENA 引脚接收 PWM 信号控制占空比VS 和 VSS 分别接电机电源和逻辑电源。Proteus 仿真中 L298 模型的行为和真实芯片基本一致ENA 为高电平时电机按 IN1/IN2 的组合决定转向PWM 加在 ENA 上即可调速。对于一个以“加减速”为卖点的项目L298N 是最稳妥的选择毕竟 H 桥 PWM 驱动的数学原理在后续做 48V 无刷直流电机驱动时同样适用。提示Proteus 的 L298 模型对 ENA 脉冲宽度有最小时间要求PWM 频率不要超过 10kHz否则仿真里会出现电机转速不跟随占空比变化的情况。2.2 温度采样选 DS18B20 而不是 ADC0804 的接口理由标题里的“温度 PWM”有两种实现路径一种是用 NTC 热敏电阻搭建分压电路再通过 ADC0804 或 PCF8591 采样电压换算温度另一种是直接用 DS18B20 数字温度传感器单总线协议输出温度值不需要外接 ADC 芯片。从代码复杂度和 Proteus 仿真可靠性两个角度看DS18B20 都更合适。原因有三点。第一51 单片机内部没有 ADC 模块用热敏电阻方案必须额外引入 ADC 芯片原理图会多出七八个电阻电容物料清单变长仿真时多一个器件就多一个出错的点。第二DS18B20 在 Proteus 元件库里名为“DS18B20”直接拖出来就能用仿真模型支持修改环境温度参数来模拟温度变化这在验证“温度升高 → 电机加速”这个逻辑时非常直观。第三单总线协议虽然时序要求严格但它的代码是固定的模板只要能跑通初始化、跳过 ROM、读暂存器这几个步骤后面所有温度相关的逻辑都建立在同一个数据源上。2.3 原理图的关键引脚连接与 15 个必背元件以下是这套系统的完整物料清单元件的位号和参数与后文代码中的引脚定义一一对应直接按这个清单采购或搭建仿真图即可。位号元件参数/型号数量在电路中的角色U1单片机AT89C51 / STC89C521主控生成 PWM 并处理温度数据U2电机驱动L298N1H 桥驱动放大 PWM 信号U3温度传感器DS18B201采集环境/设备温度M1直流电机MOTOR-DCProteus 模型1被控对象Y1晶振12MHz1单片机时钟源C1, C2瓷片电容30pF2晶振负载电容C3电解电容10uF1复位电路延时C4瓷片电容104100nF1L298N 逻辑电源去耦C5电解电容100uF1电机电源滤波R1电阻10kΩ1复位电路上拉R2电阻4.7kΩ1DS18B20 数据线上拉D1-D4二极管1N40074电机续流保护S1, S2按键轻触开关2加速、减速控制5V电源直流 5V1逻辑电源原理图连线有五个关键点需要核对清楚。P1.0 接 L298N 的 ENA这是 PWM 输出引脚P2.0 和 P2.1 分别接 IN1、IN2 控制电机方向本项目中固定为正向旋转IN11, IN20P3.7 接 DS18B20 的 DQ 数据线L298N 的 VS 接电机电源正极VSS 接 5V 逻辑电源两路电源的地必须共地否则电机无法形成回路DS18B20 的 VCC 和 GND 直接接 5V 和地DQ 与 P3.7 之间接 4.7kΩ 上拉电阻到 VCC。提示实物制作时 L298N 的电机电源建议用独立 9V~12V 电源不要和单片机共用同一路 5V。Proteus 仿真中可以直接用 5V 电源模型替代两路但图中依然要画出 VS 和 VSS 分开的连接便于后续移植到实物。3. 源代码定时器 PWM、DS18B20 时序与温度联动怎么写3.1 定时器 0 产生 500Hz 软件 PWM 的 C51 代码STC89C52 内部没有硬件 PWM 模块常见做法是用定时器中断模拟。核心思路是定时器每产生一次中断计数器加一计数器在占空比阈值内输出高电平超过阈值输出低电平一个完整周期后计数器清零。以下是完整的定时器初始化代码#include reg51.h sbit PWM_OUT P1^0; // PWM 输出接 L298N 的 ENA sbit IN1 P2^0; // L298N 方向控制引脚 IN1 sbit IN2 P2^1; // L298N 方向控制引脚 IN2 unsigned char pwm_cnt 0; // 计数器范围 0~99 unsigned char pwm_duty 50; // 占空比范围 0~100初始 50% void Timer0_Init(void) { TMOD 0xF0; // 清零 T0 的模式位 TMOD | 0x01; // T0 工作在方式 116 位定时器 TH0 0xF8; // 定时 2ms 的初值高字节 TL0 0x30; // 定时 2ms 的初值低字节 ET0 1; // 开启 T0 中断 TR0 1; // 启动 T0 EA 1; // 开启总中断 } void Timer0_ISR(void) interrupt 1 { TH0 0xF8; // 重装初值 TL0 0x30; pwm_cnt; if (pwm_cnt 100) { pwm_cnt 0; // 周期到计数器归零 } PWM_OUT (pwm_cnt pwm_duty) ? 1 : 0; }代码的关键在于初值计算。12MHz 晶振下机器周期为 1us方式 1 是 16 位定时器定时时间公式为 t (65536 - 初值) * 1us。这里取的 2ms 周期对应初值 65536 - 2000 63536十六进制为 0xF830。为什么周期取 2ms 而不是 1ms 或 10ms因为占空比分辨率需要 100 级0% 到 100%2ms 周期下每级对应 20us定时器重装产生的误差占比很小若周期缩短到 1ms每级只剩 10us中断函数里几条语句的执行时间就会明显影响占空比精度。pwm_cnt 计数到 98 时占空比为 98%到 99 时立刻清零因此高电平宽度实际由“pwm_cnt pwm_duty”这个比较表达式决定。pwm_duty 是全局变量主循环中随时可以修改下一次周期开始即生效加减速按键修改的就是这个变量。3.2 DS18B20 单总线读温度5 条时序的顺序不能乱DS18B20 的单总线协议对时序要求很严格初始化、写 0、写 1、读 0、读 1 五种时序分别对应不同的延时时间顺序一旦颠倒就读不到数据。以下是复位和读取温度的核心函数sbit DQ P3^7; unsigned char temp_l, temp_h; // 温度低字节和高字节 void Delay_Us(unsigned int n) { while (n--); } unsigned char DS18B20_Reset(void) { unsigned char presence; DQ 0; Delay_Us(480); // 主机拉低总线 480us产生复位脉冲 DQ 1; Delay_Us(60); // 释放总线并等待 60us presence DQ; // 读取存在脉冲0 表示设备在线 Delay_Us(420); return presence; } void DS18B20_WriteByte(unsigned char dat) { unsigned char i; for (i 0; i 8; i) { DQ 0; Delay_Us(10); // 写时序起始 DQ dat 0x01; Delay_Us(45); // 保持数据 45us DQ 1; dat 1; } } unsigned char DS18B20_ReadByte(void) { unsigned char i, dat 0; for (i 0; i 8; i) { DQ 0; Delay_Us(5); // 读时序起始 DQ 1; Delay_Us(5); dat 1; if (DQ) dat | 0x80; Delay_Us(50); } return dat; } float Get_Temperature(void) { unsigned char temp; float temperature; DS18B20_Reset(); DS18B20_WriteByte(0xCC); // 跳过 ROM 匹配只挂一个传感器 DS18B20_WriteByte(0x44); // 启动温度转换 while (!DQ); // 等待转换完成DQ 被拉低表示忙 DS18B20_Reset(); DS18B20_WriteByte(0xCC); DS18B20_WriteByte(0xBE); // 读取暂存器内容 temp_l DS18B20_ReadByte(); temp_h DS18B20_ReadByte(); temp (temp_h 4) | (temp_l 4); temperature temp; return temperature; }参数说明DS18B20_Reset 函数的前两个延时段决定了复位时序是否合法480us 和 60us 是数据手册给出的标称值Proteus 仿真模型对这两个参数的宽容度比实物高但尽量保持一致。Get_Temperature 函数里用了三个步骤先发跳过 ROM 命令 0xCC再发启动转换命令 0x44等待转换完成后再复位并发送读暂存器命令 0xBE。注意读出的温度是 12 位精度存放在两个字节中对这个项目只需要整数部分所以用 (temp_h 4) | (temp_l 4) 取出整数温度值温度精度为 1 摄氏度对控制电机转速足够。提示DS18B20 时序要求微秒级延时而定时器中断会打断延时函数。建议在 Get_Temperature 函数的开头和结尾各执行一次 EA 0 和 EA 1或者把温度读取放在 PWM 中断周期较长的场景下使用。实测 500Hz 中断2ms 周期下不关中断约 10% 的概率读取失败表现为温度跳变到 85 或 0。3.3 把温度换算成占空比的联动逻辑温度 PWM 的核心在于“温度高 → 转速升高”这本质是温度与占空比的映射关系。映射方式有两种常见做法线性映射和分段查表。线性映射的公式是 duty 20 (temp - 20) * 4温度低于 20 度时最小占空比 20%温度高于 40 度时占空比饱和到 100%。分段查表则在温度和占空比不是线性关系时更实用比如电机在低温段只需要维持最低转速在高温段需要快速响应。#define MIN_DUTY 20 // 最低占空比 #define FULL_DUTY 100 // 最高占空比 #define T_LOW 20 // 温度下限 #define T_HIGH 40 // 温度上限 unsigned char Temperature_To_Duty(float temp) { unsigned char duty; if (temp T_LOW) { duty MIN_DUTY; } else if (temp T_HIGH) { duty FULL_DUTY; } else { // 线性插值温度每升高 1 度占空比增加 4% duty MIN_DUTY (unsigned char)((temp - T_LOW) * 4); } return duty; }代码中的 4% 这个系数对应 20 度温差内从 20% 升到 100% 的变化斜率可以按电机实际转速特性调整。线性插值在单片机上的计算代价低只需要一次浮点乘法和一次类型转换。这里需要说明的是温度传感器放在电机附近时电机自身发热会形成正反馈回路导致转速在高温下振荡。解决方式是让温度采样周期远大于 PWM 周期通常每秒采样一次温度并更新占空比即可人眼和电机机械惯性都会自然平滑这个更新过程。4. 加减速流程与按键处理流程图里的主循环怎么排4.1 按键加速减速的消抖与长按连续处理加减速按键是用户最直接的输入接口消抖和长按处理会直接影响使用体验。机械按键按下时会产生约 10ms 的电平抖动如果每检测到一次低电平就改变占空比一次按下可能触发三四次变化。常规做法是检测到低电平后延时 20ms 再检测一次电平状态确认稳定后再执行操作。sbit KEY_UP P3^0; // 加速按键低电平有效 sbit KEY_DOWN P3^1; // 减速按键低电平有效 void Delay_Ms(unsigned int n) { unsigned int i, j; for (i 0; i n; i) for (j 0; j 123; j); } void Key_Scan(void) { static unsigned int up_cnt 0, down_cnt 0; if (KEY_UP 0) { Delay_Ms(20); // 消抖 if (KEY_UP 0) { up_cnt; if (up_cnt 1) // 短按单次增速 5% pwm_duty (pwm_duty 5 100) ? 100 : pwm_duty 5; if (up_cnt % 20 0) // 长按约 400ms 后连续增速 pwm_duty (pwm_duty 5 100) ? 100 : pwm_duty 5; } } else { up_cnt 0; // 按键释放计数器清零 } if (KEY_DOWN 0) { Delay_Ms(20); if (KEY_DOWN 0) { down_cnt; if (down_cnt 1) pwm_duty (pwm_duty 5) ? 0 : pwm_duty - 5; if (down_cnt % 20 0) pwm_duty (pwm_duty 5) ? 0 : pwm_duty - 5; } } else { down_cnt 0; } }这里把按键扫描放进了主循环而不是定时器中断因为占空比变量 pwm_duty 在主循环中修改中断里读取不需要考虑临界区问题。长按检测的实现方式是维护一个按下计数每 20 次扫描约 400ms执行一次连续加减既保证了短按的单次响应也支持长按连续调速。参数 5% 是单次步进量最小占空比被限制在 0%最大限制在 100%防止溢出导致电机反转。4.2 流程图里的主循环顺序读温度、按键修正、更新占空比在 Proteus 仿真图中查看流程图时主循环的执行顺序需要和中断处理严格分工。系统运行流程按以下顺序组织定时器 0 初始化启动 500Hz PWM 输出初始占空比 50%主循环第一轮调用 Key_Scan 读取按键状态更新 pwm_duty主循环第二轮调用 Get_Temperature 读取温度调用 Temperature_To_Duty 计算温控目标占空比 temp_duty比较 temp_duty 和按键设定的 pwm_duty取两者的较大值作为最终占空比延时约 20ms 后回到步骤 2这个流程中需要重点关注第 4 步的取舍逻辑。标题同时包含“加减速”和“温度 PWM”说明两种输入会同时影响转速直接覆盖会丢失用户意图。常见做法是按键设定一个基础转速温度在基础转速之上叠加增量即最终占空比 max(按键占空比, 温度占空比)。这样即使用户手动把转速调到最低温度超过阈值后电机依然会加速实现温度保护优先。如果想把温度的影响设计为“实时调速”而不是“保护叠加”可以将最终占空比改成按键占空比与温度占空比的加权平均例如 70% 按键权重加 30% 温度权重。加权平均的缺点是温度低时高速按键会被人为拉低转速体验不如取最大值直观设计流程图时可以在主循环中加一个模式切换变量来选择这两种策略。4.3 温度采样为什么做滑动平均而不是直接转换DS18B20 单次读取的温度值可能存在 ±0.5 度的随机抖动如果直接参与占空比映射在温度阈值边界附近会出现转速反复跳动。给温度做一个长度为 5 的滑动平均数组每次读到新值后去掉最旧的值取平均值参与计算成本极低但效果明显。float temp_history[5] {25, 25, 25, 25, 25}; unsigned char temp_index 0; float Get_Smooth_Temperature(void) { float sum 0; unsigned char i; temp_history[temp_index] Get_Temperature(); temp_index (temp_index 1) % 5; for (i 0; i 5; i) sum temp_history[i]; return sum / 5.0; }数组初始值设为 25 度意味着系统上电头五次采样前温度显示偏 25 度如果实际温度差距大第一次占空比计算会有一个跳变。可以把初始值全部设成第一次采样得到的温度值或者在主循环中先连续读五次温度填充数组再进入正常控制流程。5. Proteus 仿真图联调从元件摆放到 PWM 波形验证5.1 Proteus 8 Professional 里连接仿真图的顺序与元件名在 Proteus 8 Professional 中新建工程后依次点击左侧元件列表的“P”按钮打开库搜索输入关键词选择对应元件AT89C51 或 STC89C52搜索 8051、L298搜索 L298实际模型名常为 L298D、MOTOR-DC搜索 MOTOR-DC直流电机模型、DS18B20、CRYSTAL、CAP、CAP-ELEC、RES、BUTTON、POWER 和 GROUND。注意 Proteus 中电源和地符号要从“Terminal Mode”里选择不是从元件库搜索。连线顺序建议按照信号流向排列减少交叉先放置单片机 U1 并连接晶振12MHz 晶振两端各接一个 30pF 电容到地和复位电路10uF 电解电容正极接 VCC负极接 RST10kΩ 电阻连接 RST 和 GND这是一个典型的上电复位电路。然后放置 L298把它的 IN1、IN2 分别连接到单片机的 P2.0、P2.1ENA 连接到 P1.0。L298 的 OUT1、OUT2 连接直流电机的两个引脚电机两端再并联四个续流二极管注意二极管的阳极接电机负端、阴极接电机正端方向接反会导致短路。最后放置 DS18B20DQ 引脚连接 P3.7 并接 4.7kΩ 上拉电阻到 VCC。提示Proteus 中 DS18B20 的模型在外观上是一个三引脚器件左上方和右下方的两个引脚分别是电源和地中间偏下的引脚是 DQ连线前先把鼠标悬停在引脚上确认 Pin Name 再动手。5.2 仿真里测 PWM 波形和转速的两个关键操作仿真运行后点击 Proteus 左侧工具栏的“Virtual Instruments Mode”图标选择“Dual Trace Oscilloscope”添加到原理图空白处。把示波器的 A 通道探头连接到 P1.0 引脚B 通道可连接到 DS18B20 的 DQ 引脚观察单总线波形。点击左下角的运行按钮后示波器窗口会实时显示 PWM 波形按下加速或减速按键可以看到高电平宽度占空比随之增宽或变窄这是验证 PWM 控制直流电机转速最直接的证据。转速的测量在 Proteus 中有两个途径一是电机模型旋转时自带的可视动画效果转速变化肉眼看得出二是添加一个“ROTATIONAL-VELOCITY”探针。操作路径是点击“Virtual Instruments Mode”中的“Probe”工具在属性设置里选择“Current”以外的物理量放一个探针在电机轴上仿真运行后在输出日志窗口查看转速数值。这个方法适合需要记录转速曲线做对比的场景比如温度从 25 度调到 35 度时转速探针数值应当逐步上升并稳定。5.3 PWM 控制直流电机转速最常见的 3 个仿真异常异常一电机完全不动。先从 VCC 和 GND 检查是否有电源连接然后检查 L298 的 ENA 引脚是否有波形输出——如果示波器显示 P1.0 有波形但电机不动问题出在 L298 的使能逻辑上确认 IN1 接高电平、IN2 接低电平ENA 接 P1.0三者缺一不可。常见错误是把 ENA 接到了 P2 口方向引脚上导致 PWM 信号从未进入 H 桥。异常二转速不随占空比变化只有转和不转两种状态。原因通常是 pwm_duty 变量在中断中被反复赋值覆盖或者在主循环中每次重新读取按键前都被重置为固定值。排查方法是给变量加一个调试手段把 pwm_duty 的值映射到 P1 口的低 8 位 LED 上用 LED 亮灯数量直接观察占空比数值是否在按键时发生改变。异常三温度变化时转速毫无反应。Proteus 的 DS18B20 仿真模型默认环境温度为 25 度运行仿真后右键点击 DS18B20 元件选择“Edit Properties”把 Ambient Temperature 从 25 改成 60确认弹窗里的“Enable temperature simulation”处于勾选状态。如果属性面板没有这个选项说明该版本 Proteus 的模型简化了温度行为需要换用最新版的 Proteus 8 Professional 或改用电压源模拟温度信号。6. 进阶用示波器标定一组“温度-转速”曲线才算完整多数人做完这个项目就停在了“按下按键电机加速、温度升高电机加速”这一步但作为能写进简历的作品还差一个量化验收标定一组温度与转速的对应关系曲线证明你的 PWM 占空比和电机实际转速是线性相关的而不只是“看起来在转”。这个标定过程用已有代码和 Proteus 环境即可完成不需要额外硬件。在系统主循环中打开串口输出功能调用printf把温度值和当前占空比发送到虚拟终端操作路径是 Proteus 左侧工具栏选择“Virtual Instruments Mode”中的“VIRTUAL TERMINAL”把 RXD 引脚连接到单片机 TXD 引脚 P3.1。在 Keil 的uart_init函数中把波特率设为 9600代码中插入输出语句printf(temp:%.1f duty:%d\n, Get_Smooth_Temperature(), pwm_duty);运行仿真把 DS18B20 的环境温度从 20 度逐步调到 45 度每隔 5 度记录一次虚拟终端输出的数值同时通过转速探针读取实际转速。用 Excel 或手绘把温度作为横轴、转速作为纵轴画点连线你会发现 20 度以下转速恒定在最低值20 到 40 度之间近似直线上升40 度以上进入饱和区。这个图就是整个系统的静态特性标定曲线。如果有兴趣继续深挖可以做一个动态标定把温度从 25 度突跳设置到 40 度观察转速从一个稳定值过渡到另一个稳定值的响应时间。你会发现转速过渡不是瞬时的因为 DS18B20 的转换周期加上滑动平均产生了滞后。调整滑动平均数组长度从 5 改到 20滞后时间变长但转速更平稳改到 1响应变快但会出现转速抖动。找到一个让系统在 1 秒内完成 90% 过渡且无明显超调的窗口参数这个调参经验比仿真的跑通本身更有价值——它同时解释了“温度 PWM”项目中采样周期、滤波长度和系统响应速度三者之间的换算关系。本文还有配套的精品资源点击获取
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →