电子工程师技术服务社区
公告
登录
|
注册
首页
技术问答
课程
芯视听
DIY视频
厂商活动
正点原子
板卡试用
电子赛事
RM机甲大师赛
电子设计竞赛
智能汽车竞赛
资源库
下载
文章
社区首页
文章
【Proteus】单片机H桥驱动24V直流有刷电机
分 享
扫描二维码分享
【Proteus】单片机H桥驱动24V直流有刷电机
Proteus
单片机
H桥
KVIN
关注
发布时间: 2019-12-11
丨
阅读: 3458
# 前言 一般有关直流有刷电机的仿真都是直接高低电平驱动,或者ULN2003,这种电路是只能驱动小电压小功率的电机的,如果碰到电压稍高一些,电流大一些的电机,2003驱动是驱动不起来的,这时候对于大电流的电机,一般就是MOS管或者IGBT,相对来说,NMOS是经济实用之选,本节就带领大家使用单片机,搭建H桥驱动电路来驱动一个24V的直流有刷电机。 先附上完整的仿真电路图一张,再逐个讲解:  要想使用H桥,就得需要一个半桥驱动芯片,当然,在市面上的各种驱动芯片应有尽有,半桥驱动芯片,三相桥集成驱动芯片等等,但在protues中,我只找到一款IR2101驱动,这是一款高压驱动芯片,24V算是低压的,不过也没关系了,只能用这个,仿真应该是可以的。 首先就是绘制H桥驱动电路:  这是我绘制的H桥驱动电路,这个电路在驱动原理上是没有什么问题的,我做了简化,真实的驱动电路中还需要加入一些其他的电路以及二极管,如图:  这个二极管的作用更大一些。 #### G极电阻并联二极管的作用: 因为MOS管内部都是有极间电容的,也就是说,在MOS的G极与S极之间有电容,也就是说,G极出来的这个电阻与GS极间电容形成一个RC充放电电路:如图:  调节这个电阻就可以调节MOS输出的PWM由低电平到高电平的上升时间,上升实际太长或太短都不太好,根据实际情况选择电阻。 而PWM由高变低时的下降时间,同样时间常数也是由这个RC共同决定的,因此如果在G极电阻上并联一个二极管,放电的时候直接经过这个二极管把电流放出去,那么下降时间就会比较快。 当然,这个看你想不想加,想加的话按照图上自己添加即可。 #### 这里需要提一下超过5V的电源怎么添加: 1.首先在图中的位置选中电源添加一个电源:  2.随后双击电源,修改电压,一定要有“+”号:  然后就是驱动芯片电路了:  驱动信号的左边HIN与LIN也就是控制驱动芯片输出的两个输入信号了,也就是接入单片机,单片机输出是5V信号,而且电流小,是不可以直接驱动MOS管的,驱动芯片的作用实际就是增压扩流的作用,驱动芯片右边的HO也就是跟HIN的输入信号波形一致,但是是12V的,而且电流比较大,LO也是同样的。 当然,大家应该也都看到了那个C1,C2电容,这两个电容是半桥驱动的精髓,重中之重,没有这个电容,半桥是无法工作的,如图:  这两个电容俗称自举电容,或泵电容。这个不是某种特殊电容,而是按照功能给它起的名字,因为这个电容会把电压抬升上来,就像水泵一样,随意叫泵电容,驱动芯片的供电是12V,H桥的电压是24V,C1这个泵电容与D1这个二极管结合,会把电压抬升到36V,这就牵涉到另外一个知识点:为什么H桥上管的PWM不能发100%占空比。 有关自举电容或泵电容的详细解释,请自行百度,百度的解释肯定比我的解释要专业得多,电路这部分内容展开就没边了。只需要记住这个自举电容与它旁边的二极管比较重要即可,没有这两个,有可能电机也可以转,但电机是转不好的,稍后我们测试一下。 然后我们来测试一下,电路行不行,按照电机驱动的原理:  按照上图的驱动原理,Q5发送PWM控制电流,Q7,Q6关闭,Q8打开,让电流经过Q5,电机,从Q8回到负极,电机就可以正转了,如此的话,反转也是一样的道理,Q6发PWM,Q5,Q8关闭,Q7打开,那么电机就会反转了,我们先不写程序,使用proteus自带的脉冲模块来试一下:  此时电机旋转如图:  GIF看不清楚转速,我就截图了,最后转速是在600转左右:  如果我们把那个自举电容去掉呢?如图:   最后电机只能到200转,差距还是很大的。 现在我们是使用的proteus自带的脉冲模块来控制的电机,接下来就要使用单片机来控制了。因为proteus里没有东西能够测量直流电机的实际转速,所以也就只能开环控制,只能调节占空比了。因此我们使用LCD1602来显示当前的占空比,对于LCD1602的驱动说明,还有我的LCD1602源码,可以查看之前的文章:https://www.icxbk.com/article/detail/1067.html 这里就不在赘述了。 然后我们整理一下单片机发送PWM的思路,由于51单片机是没有单独的PWM模块的,因此只能使用IO口来模拟PWM,如果要控制精确一些,就需要定时器的配合,因此,我们需要选用一个定时器来计时,然后在定时器中断中自加一个变量,然后用那个变量来确定IO口发多长时间的高电平,多长时间的低电平。我们先确定控制MOS的引脚,程序中也先声明一下:   我们就先发送50%占空比,按照之前的思路,程序如下: ```c #include
#include "1602.h" #define uchar unsigned char #define uint unsigned int sbit leftH = P1^3; sbit leftL = P1^4; sbit rightH = P1^5; sbit rightL = P1^6; uint counter = 0; //定时器计数 uint pulse = 0; //占空比值 /@@*中断初始化*/ void irq_init(void) { TMOD = 0x01; //T 模式1,十六位计数器 TL0 = (65535-500)/256; TH0 = (65535-500)%256; ET0 = 1; //允许TO中断 TR0 = 1; //关闭T0 EA = 1; //允许总中断 } void main() { irq_init(); //中断初始化 while(1) { pulse = 50; } } /@@*********************************************************/ // 定时器0中断服务程序. /@@*********************************************************/ void timer0 () interrupt 1 { TH0 = (65535-500)/256; //500us TL0 = (65535-500)%256; //500us counter ++; //计数值自加 if(counter >= 100) counter = 0; if(counter < pulse) { leftH = 1; leftL = 0; rightH = 0; rightL = 1; } else { leftH = 0; leftL = 0; rightH = 0; rightL = 1; } } ``` 我们来看上面程序,定时器定时500us进入一次中断,然后counter进行自加计数,计数达到100时清零,当counter小于我们设定的pulse时,leftH就发送高电平,反之则是低电平,这样就相当于是STM32的PWM1模式了,在主函数的while循环中,设定pulse占空比为50,50/100也就是50%占空比。 然后我们仿真一下,这时候报错了:  #### 没关系,这个是proteus软件参数没有设置对,最小电导Minimum conductance设置得太小了,改一下即可:  选择System->Set Animation Options 我这里是Proteus8.6,也就是倒数第三个:  然后点SPICE Options:  就是这个GMIN出了问题,我这里是1e-012,把这个修改成1e-05就好了,就是把这个数增大点:  然后开始运行,可以看到电机已经可以转起来了,说明我们的PWM起作用了。  然后我们把占空比显示在LCD上,程序如下: ```c /@@*显示函数*/ void display(void) { char str[20]; sprintf((char *)str,"Pulse:%d",pulse); print_string(str,1); } void main(void) { irq_init(); //中断初始化 lcd_init(); //LCD初始化 while(1) { pulse = 50; display(); } } ``` 效果如图:  然后,我们这个功能不完善,因为只能在程序上调占空比,至少要有两个按键来加减速的,因此,我们在电路上再加入两个按键:  然后把按键检测的程序写上: ```c sbit key1 = P3^0; //加速 sbit key2 = P3^1; //减速 uint key_result = 0; //保存按键结果 void key_delay(uchar t) { int j; for(;t!=0; t--) for (j=0;j<255;j++); } /@@*按键检测 如果按键1被按下就返回1 如果按键2被按下就返回2 如果没有按键按下就返回0*/ uint key_scan(void) { uint result = 0; /@@*先将按键电平拉高*/ key1 = 1; key2 = 1; /@@*检测按键1是否被按下*/ if(key1 == 0) { key_delay(5); if(key1 == 0) { result = 1; } } /@@*检测按键2是否被按下*/ if(key2 == 0) { key_delay(5); if(key2 == 0) { result = 2; } } return result; } ``` 上面程序中,如果没有按键按下,就会返回0,按键1按下就会返回1,按键2按下就会返回2。然后我们在根据返回值来修改占空比即可,此时主函数修改如下: ```c void main(void) { irq_init(); //中断初始化 lcd_init(); //LCD初始化 while(1) { display(); key_result = key_scan(); /@@*按键1按下则占空比增加*/ if(key_result == 1) { pulse = pulse + 10; if(pulse > 99) pulse = 99; } /@@*按键2按下则占空比减少*/ else if(key_result == 2) { pulse = pulse - 10; if(pulse < 0) pulse = 0; } } } ``` 由于我在仿真中使用的是带惯性负载的电机,因此电机转速变化会比较慢,最后放一个综合起来的效果图:  本篇就只做了电机正转的程序,反转举一反三即可,改动不大,而且本篇对于电源部分的降压电路,24V转12V,12V转5V并没有画出,这一点注意。跟上篇一样,如果是懒癌患者,请移步下载区给作者赏点IC币,链接:https://www.icxbk.com/download/detail/48543.html 如果不是懒癌,我的工程目录如图:  关于1602的驱动程序,在之前的文章已经贴上的所有程序,链接:https://www.icxbk.com/article/detail?aid=1067 因此,这个工程我就只贴主文件的程序了。 main.c程序如下: ```c #include
#include "1602.h" #include
#define uchar unsigned char #define uint unsigned int sbit leftH = P1^3; sbit leftL = P1^4; sbit rightH = P1^5; sbit rightL = P1^6; sbit key1 = P3^0; //加速 sbit key2 = P3^1; //减速 uint counter = 0; //定时器计数 uint pulse = 0; //占空比值 uint key_result = 0; //保存按键结果 void key_delay(uchar t) { int j; for(;t!=0; t--) for (j=0;j<255;j++); } /@@*按键检测 如果按键1被按下就返回1 如果按键2被按下就返回2 如果没有按键按下就返回0*/ uint key_scan(void) { uint result = 0; /@@*先将按键电平拉高*/ key1 = 1; key2 = 1; /@@*检测按键1是否被按下*/ if(key1 == 0) { key_delay(5); if(key1 == 0) { result = 1; } } /@@*检测按键2是否被按下*/ if(key2 == 0) { key_delay(5); if(key2 == 0) { result = 2; } } return result; } /@@*中断初始化*/ void irq_init(void) { TMOD = 0x01; //T 模式1,十六位计数器 TL0 = (65535-500)/256; TH0 = (65535-500)%256; ET0 = 1; //允许TO中断 TR0 = 1; //关闭T0 EA = 1; //允许总中断wmen } /@@*显示函数*/ void display(void) { char str[20]; sprintf((char *)str,"Pulse:%d",pulse); print_string(str,1); } void main(void) { irq_init(); //中断初始化 lcd_init(); //LCD初始化 while(1) { display(); key_result = key_scan(); /@@*按键1按下则占空比增加*/ if(key_result == 1) { pulse = pulse + 10; if(pulse > 99) pulse = 99; } /@@*按键2按下则占空比减少*/ else if(key_result == 2) { pulse = pulse - 10; if(pulse < 0) pulse = 0; } } } /@@*********************************************************/ // 定时器0中断服务程序. /@@*********************************************************/ void timer0 () interrupt 1 { TH0 = (65535-500)/256; //500us TL0 = (65535-500)%256; //500us counter ++; //计数值自加 if(counter >= 100) counter = 0; if(counter < pulse) { leftH = 1; leftL = 0; rightH = 0; rightL = 1; } else { leftH = 0; leftL = 0; rightH = 0; rightL = 1; } } ``` 喜欢就点个赞喔!
原创作品,未经权利人授权禁止转载。详情见
转载须知
。
举报文章
点赞
(
5
)
KVIN
关注
评论
(0)
登录后可评论,请
登录
或
注册
相关文章推荐
Beetle ESP32 C3 蓝牙数据收发
Beetle ESP32 C3 wifi联网获取实时天气信息
开箱测评Beetle ESP32-C3 (RISC-V芯片)模块
正点原子数控电源DP100测评
DP100试用评测-----开箱+初体验
Beetle ESP32 C3环境搭建
【花雕体验】16 使用Beetle ESP32 C3控制8X32位WS2812硬屏之二
【花雕体验】15 尝试搭建Beetle ESP32 C3之Arduino开发环境之二
X
你的打赏是对原创作者最大的认可
请选择打赏IC币的数量,一经提交无法退回 !
100IC币
500IC币
1000IC币
自定义
IC币
确定
X
提交成功 ! 谢谢您的支持
返回
我要举报该内容理由
×
广告及垃圾信息
抄袭或未经授权
其它举报理由
请输入您举报的理由(50字以内)
取消
提交