ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

单片机控制直流电动机:H桥驱动与PWM调速实战指南

单片机控制直流电动机:H桥驱动与PWM调速实战指南 简介这是一份单片机控制直流电动机课程设计的完整文档资料主要面向电子信息、自动化等相关专业学生以及需要完成单片机课程设计或PWM直流调速项目的初学者。内容围绕AT89C51/80C51单片机系统讲解基于PWM调压调速的设计思路包括A/D与D/A转换、L298驱动芯片、H桥功率电路和定频调宽调速方法并配有硬件图、程序框图、程序源码、调试运行及仿真截图有助于读者从原理到实现完整掌握直流电机转速控制与测量装置的设计流程。资源压缩包较小仅包含1个docx格式文档打包后229KB全文共17页章节结构清晰覆盖设计目的、任务要求、设计原理分析、硬件资源及原理、程序、调试运行、仿真截图和设计心得体会等模块可直接作为课程设计报告编写和答辩准备的参考资料。这份文档上线以来已有659人学习浏览适合作为单片机控制直流电动机方向的选题参考与实践指南。1. 单片机控制直流电动机课程设计的题眼不在电机在控制很多同学拿到“单片机控制直流电动机”这个题目第一反应是“这不就一个开关管的事吗”然后直接拿单片机 IO 口去推电机结果要么电机纹丝不动要么单片机复位。这门课程设计真正考察的不是电机本身而是三个点功率驱动怎么搭、转速怎么调、转速怎么测回来。把这三个点打通正转反转、加减速、数码管实时显示转速都是顺带的事。本文按 51 单片机课程设计最常见的方案来讲围绕 H 桥驱动、定时器 PWM 调速和测速显示展开适合正在做单片机课程设计、毕业设计以及准备蓝桥杯单片机组的读者。2. 先解决驱动问题直流电机为什么不能直接接单片机2.1 电平、电流与反向电动势的三重约束先把直流电机的等效模型摆出来一个电枢电阻 R、一个电枢电感 L再串联一个与转速成正比的反向电动势 E Ke·n。电机转动时这个反电动势方向和外部供电相反转速越高反向电动势越大。单片机的 IO 口输出高电平只有 3.3V 或 5V拉电流能力一般也就 10~20mA而普通直流电机启动瞬间的堵转电流可以达到额定电流的数倍拿 IO 口直接驱动第一个结果是电压被拉垮第二个结果是反向电动势顺着导线往单片机灌轻则复位重则烧引脚。课程设计里最常见的处理是用分立三极管搭一个开关电路或者直接上集成驱动芯片。分立方案成本低、原理图好画但只能单向调速不能换向如果题目要求“正反转”就必须用 H 桥。H 桥的四个开关管按对角线成对导通电流方向反转电机就反转四个管子全关是自由停车下桥两个同时导通是能耗制动。搞清楚这四个状态驱动部分就不难了。2.2 驱动芯片选型课程设计最常用的三个方案常见做法是优先考虑手头实验室有什么芯片而不是先定电路再买件。下面这张表把三种常见方案的边界列清楚选型时对号入座方案驱动能力是否支持正反转典型场景注意点ULN2003 达林顿管阵列单路 500mA峰值更高不支持只能单向调速小功率电机、步进电机实验内部是开集电极必须接续流二极管L298N 双 H 桥单桥 2A峰值 3A支持内置续流二极管课程设计最主流几乎人手一块压降约 2V供电电压要往上留余量TB6612 双 H 桥单桥 1.2AMOS 管工艺支持内置续流电池供电、需要低功耗的场景逻辑电平兼容 3.3V/5V常用于 STM32我这里默认选 L298N 来讲因为 51 单片机课程设计配套的电机驱动模块大多是它。需要注意 L298N 是个线性驱动芯片管压降在 2V 左右也就是说电源端给 9V电机实际得到的电压只有 7V 上下做转速标定时必须用实测值不能按 9V 去算。2.3 正反转、停止与刹车的控制真值表L298N 的每一路 H 桥有 IN1、IN2 和 ENA 三个控制脚。ENA 是使能脚很多模块上默认用跳线帽短接到高电平想用 PWM 调速时要把跳线帽拔掉把 PWM 信号接到 ENA 上。IN1 和 IN2 决定电流方向逻辑关系如下IN1IN2ENA电机状态00X自由停止绕组无电流101正转011反转111刹车绕组短路XX0停机PWM 无效对应的驱动代码可以抽象成一个独立的函数主程序里只管调用不改底层逻辑// motor.c - 电机动作控制 #define IN1 P1_0 #define IN2 P1_1 #define ENA P1_2 #define MOTOR_STOP 0 #define MOTOR_FORWARD 1 #define MOTOR_REVERSE 2 #define MOTOR_BRAKE 3 void motor_ctrl(unsigned char cmd) { switch (cmd) { case MOTOR_STOP: // 自由停止两个输入都拉低 IN1 0; IN2 0; ENA 0; break; case MOTOR_FORWARD: // 正转IN11, IN20 IN1 1; IN2 0; ENA 1; break; case MOTOR_REVERSE: // 反转IN10, IN21 IN1 0; IN2 1; ENA 1; break; case MOTOR_BRAKE: // 刹车两个输入都为1 IN1 1; IN2 1; ENA 1; break; } }这段代码里把 ENA 也纳入控制是为了后续好加 PWM 调速。注意刹车状态和正转状态只差一个 IN2很多人写程序时喜欢先把两个输入清 0 再置位这在电机高速运行时会造成一瞬间的自由停车电流突变会产生较大的反电动势冲击。正确的做法是先切换 IN1/IN2再打开 ENA把换向动作放到调速之后处理具体顺序在第 5 章还会展开。3. 用定时器产生 PWM 调平均电压转速调节的核心3.1 调速的本质是占空比而不是电压数值直流电机稳态转速近似等于电枢电压除以反电动势系数所以调电压就能调转速。但这里说的“调电压”不是让你用滑动变阻器串在电源上而是用 PWM 改变平均电压。PWM 的频率一般在 100Hz 到 20kHz 之间占空比 50% 的平均电压就是电源电压的 50%。电机绕组的电感会起到平波作用把方波电流滤成带有纹波的直流电流所以电机实际感受到的是一个略低于电源电压的等效直流电压。为什么不直接做一路 DAC 调电压因为线性调压方案里多余的能量全部消耗在调整管上大电流下发热严重课程设计里的电源和散热条件都撑不住。PWM 方式开关管要么全导通要么全截止效率高得多这也是 51 单片机课程设计里几乎所有调速方案都采用 PWM 的原因。3.2 用 51 定时计数器产生 PWM 的两种做法3.2.1 软件定时翻转通用但占用中断资源STC89C52 这类传统 51 单片机没有硬件 PWM 模块最通用的方法是让定时器产生固定周期的中断在中断服务程序里翻转电平配合一个软件计数器实现占空比调节。这种做法的优点是代码直观、任意引脚都能输出 PWM缺点是中断频率不能太高否则 CPU 大部分时间都在处理中断主循环的按键扫描和数码管刷新会卡顿。3.2.2 硬件 PWM 与 PCA 模块STC 系列的部分型号比如 STC15、STC8 系列自带硬件 PWM 或 PCA 模块配置好寄存器后占空比由硬件自动维持不占用中断。如果你的课程设计允许换主控优先用带硬件 PWM 的型号代码量能少三分之一。但很多实验室的课程设计指定用 AT89S52 或 STC89C52这两个型号没有硬件 PWM所以下面还是按定时器中断方案来讲这也是 51 单片机定时计数器知识点的核心考法。3.3 定时初值与 PWM 频率的换算定时器中断里不仅要翻转 PWM 电平还要刷新数码管、计时测速窗口所以 PWM 频率不能取得太高。工程上常见做法是 PWM 频率取 100~200Hz细分 100 级足够电机平滑调速。下面以 12MHz 晶振、定时器 T0 工作在方式 116 位定时为例算一组可以直接用的参数。12MHz 晶振在 12T 模式下机器周期是 1μs定时 100μs 需要计数 100 个机器周期定时初值为 65536 - 100 65436换算成十六进制是 0xFF9C。定时 50μs 同理PWM 频率定时周期T0 初值 (TH0, TL0)占空比步进100Hz100μs0xFF, 0x9C1%200Hz50μs0xFF, 0xCE1%1kHz10μs0xFF, 0xF61%这里要注意1kHz 虽然听不见电机啸叫但 10μs 一次中断对 12MHz 晶振的 51 来说负担偏重中断服务程序稍微写长一点就会溢出。课程设计里我一般建议用 100Hz 或 200Hz电机转动时的轻微“滋滋”声不影响演示效果系统也稳定。如果之后要通过串口打印调试数据晶振建议换成 11.0592MHz否则波特率误差会导致乱码。3.4 最小 PWM 输出代码与三个易错点下面这段代码只做 PWM 输出不掺其他逻辑方便单独验证驱动部分// pwm_test.c - 最小PWM输出测试 #include reg52.h sbit ENA P1^2; // 接L298N的ENA引脚 unsigned char duty 50; // 占空比 50% unsigned int cnt 0; void timer0_init(void) { TMOD 0xF0; // 只修改T0不动T1的方式位 TMOD | 0x01; // T0方式116位定时 TH0 0xFF; TL0 0x9C; // 100us定时初值 ET0 1; // 允许T0中断 TR0 1; // 启动T0 } void timer0_isr(void) interrupt 1 { TH0 0xFF; TL0 0x9C; // 重装初值 if (cnt 100) { // 100次中断为一个PWM周期 cnt 0; } if (duty 0) { ENA (cnt duty) ? 1 : 0; // 前duty个周期输出高 } else { ENA 0; // duty为0时直接关断 } } void main(void) { timer0_init(); EA 1; // 开总中断 while (1) { // 主循环先空转验证PWM波形 } }三个易错点先说清楚。第一TMOD赋值前要先用 0xF0保留高四位如果直接TMOD 0x01会把 T1 的配置冲掉后续测速功能就会失效。第二中断里比较的是cnt和duty当duty 100时cnt的取值范围是 0~99永远满足条件电机满速但duty 0时要单独处理否则条件永远不成立输出恒为低两种情况表现截然不同。第三TL0 的重装必须在中断入口处完成不能等 PWM 比较逻辑执行完再重装否则定时误差会累积PWM 周期会漂移。4. 组装整体系统按键、数码管、测速的一次集成4.1 资源分配把题目要求的每个功能都落到具体引脚一个标准的课程设计题目通常要求按键调速、按键换向、数码管或 LCD 显示当前转速。先把资源分配好再写代码能避免做到一半发现引脚冲突。下面是一张常见的分配表对应 STC89C52 或 AT89S52功能引脚说明电机正反转P1.0, P1.1接 L298N 的 IN1, IN2PWM 输出P1.2接 L298N 的 ENA加速按键P3.0独立按键软件消抖减速按键P3.1独立按键软件消抖换向按键P3.2按一次切换一次方向测速信号输入P3.4T1 外部计数引脚4 位数码管P0 P2P0 段选P2 位选需要上拉T1 在模式 2 下是 8 位自动重装定时器在模式 1 下是 16 位计数器这里用 T1 做外部计数P3.4 每来一个下降沿计数值加 1完全不需要主循环轮询效率最高。4.2 用光电对管和 T1 外部计数实现测速测速部分的常见做法是在电机转轴上装一个开有 20 个槽的码盘用红外对管跨在码盘两侧。码盘每转过一个槽红外接收管就被遮挡一次输出一个脉冲。这个脉冲接到 P3.4 后T1 自动累加。转速的计算公式是转速(rpm) 脉冲数 × 3000 / 码盘孔数其中 3000 来自 1 分钟除以 20ms 测速窗口20ms 内测到 N 个脉冲1 分钟就是 N × 3000 个脉冲再除以每圈脉冲数就得到每分钟转数。这段逻辑放在 T0 的中断里做T0 每中断 200 次正好是 20ms时间基准不需要额外占用定时器。4.3 整合代码PWM、测速、按键扫描一体化将 PWM 输出、20ms 测速窗口和按键消抖整合起来// system.c - 电机闭环调速整合代码 #include reg52.h #define HOLE_COUNT 20 // 码盘孔数 #define PWM_PERIOD 100 // PWM细分数 sbit IN1 P1^0; sbit IN2 P1^1; sbit ENA P1^2; sbit KEY_ADD P3^0; sbit KEY_SUB P3^1; sbit KEY_DIR P3^2; unsigned char duty 40; // 当前占空比 40% unsigned int pwm_cnt 0; // PWM分频计数 unsigned int tick_cnt 0; // 20ms测速窗口计数 unsigned int pulse_cnt 0; // 测速窗口内的脉冲数 unsigned int rpm 0; // 计算出的转速 bit motor_dir 0; // 0正转 1反转 void timer0_init(void) { TMOD 0x15; // 0001 0101: T1计数模式1, T0定时模式1 TH0 0xFF; TL0 0x9C; // 100us定时 TH1 0; TL1 0; // T1从0开始计数 ET0 1; TR0 1; TR1 1; EA 1; } void timer0_isr(void) interrupt 1 { TH0 0xFF; TL0 0x9C; // PWM输出 if (pwm_cnt PWM_PERIOD) pwm_cnt 0; ENA (pwm_cnt duty) ? 1 : 0; // 20ms测速窗口 if (tick_cnt 200) { tick_cnt 0; TR1 0; // 先停T1再读数 pulse_cnt (unsigned int)TH1 8 | TL1; TH1 0; TL1 0; TR1 1; rpm (unsigned long)pulse_cnt * 3000 / HOLE_COUNT; } } void delay_ms(unsigned int t) { unsigned int i, j; for (i 0; i t; i) for (j 0; j 125; j); } void key_scan(void) { static bit add_lock 0, sub_lock 0, dir_lock 0; if (!KEY_ADD) { delay_ms(10); // 消抖 if (!KEY_ADD !add_lock) { if (duty 95) duty 5; add_lock 1; } } else add_lock 0; if (!KEY_SUB) { delay_ms(10); if (!KEY_SUB !sub_lock) { if (duty 5) duty - 5; sub_lock 1; } } else sub_lock 0; if (!KEY_DIR) { delay_ms(10); if (!KEY_DIR !dir_lock) { motor_dir ~motor_dir; if (motor_dir) { IN1 0; IN2 1; } else { IN1 1; IN2 0; } dir_lock 1; } } else dir_lock 0; } void main(void) { timer0_init(); IN1 1; IN2 0; // 初始正转 while (1) { key_scan(); } }代码里的TMOD 0x15是关键高四位给 T1 配成 16 位外部计数低四位给 T0 配成 16 位定时两者互不干扰。测速时先TR1 0再读 TH1/TL1防止读数过程中计数继续累加造成数据撕裂。按键消抖用了带锁存标志的写法按住不放只生效一次这种写法在课程设计答辩时经常被问到建议能讲清楚锁存变量的作用。4.4 干扰与数码管乱跳的排查顺序如果数码管显示的转速值在电机转速稳定时还在乱跳优先排查顺序是先确认码盘和光电对管之间的距离是否合适码盘晃动会导致一帧多计数再看电机电源和单片机电源是不是共地电机工作时地线电位被拉偏会产生大量干扰脉冲最后检查信号线上要不要并联一个 10nF 电容滤高频。很多同学一上来就怀疑算法算错实际上 90% 的测速抖动来自硬件。5. 验收阶段的三个实用技巧校准表、串口打印与换向保护5.1 先做一张“占空比-实际转速”校准表不要在报告里只写“占空比越大转速越高”指导老师要的是数据。做法很简单占空比从 0% 以 10% 为步进调到 100%用测速代码读出的 rpm 记录下来至少取三组重复测量取平均。得到的表格长这样占空比第一次转速(rpm)第二次转速(rpm)平均转速(rpm)10%28527928230%84283083650%13951402139870%186018721866100%242024152418这组数据能反映两个信息一是占空比和转速接近线性又不是完全线性低速段有死区二是同占空比下重复测量有误差知道了重复性报告里讨论误差来源才有依据。5.2 用串口打印代替数码管读挡位数码管在演示时只能看到个位数级的变化调试阶段建议把占空比和转速通过串口发到电脑上位机看。12MHz 晶振下串口波特率误差较大调成 11.0592MHz 后 9600 波特率几乎没有误差。串口发送每个数据用换行分隔Excel 或串口助手直接按行导入就能画曲线比对着数码管记录数据高效得多。5.3 换向保护先刹车再反转最后也是最容易被指导老师抓到的一个细节电机正在高速正转时突然切换方向L298N 的 H 桥会瞬间经历短路状态冲击电流很大。正确做法是换向前先执行MOTOR_BRAKE状态保持 10ms让电机先减速然后再设置新的方向。也就是“刹车 10ms → 切换 IN1/IN2 → 恢复 PWM”的顺序。按一下换向键加 10ms 延时体感上几乎察觉不到但驱动芯片的温升和电源的跌落都会明显改善。把这一行代码写进报告评委基本不会再往下追问驱动细节了。本文还有配套的精品资源点击获取
返回列表