找回密码
 请使用中文注册

手机号码,快捷登录

手机号码,快捷登录

查看: 46|回复: 0

单片机H桥驱动24V直流有刷电机

[复制链接]
阅读字号:

1368

主题

50

回帖

2万

积分

超级版主

积分
27457
发表于 3 天前 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?请使用中文注册

×

先附上完整的仿真电路图一张,再逐个讲解:


a86d6b999a5ece9a81aa0b6ae4dd58ce.jpg


要想使用H桥,就得需要一个半桥驱动芯片,当然,在市面上的各种驱动芯片应有尽有,半桥驱动芯片,三相桥集成驱动芯片等等,但在protues中,我只找到一款IR2101驱动,这是一款高压驱动芯片,24V算是低压的,不过也没关系了,只能用这个,仿真应该是可以的。

首先就是绘制H桥驱动电路:


1c15ee0f83578a5d0b95ed5f6a631371.jpg


这是绘制的H桥驱动电路,这个电路在驱动原理上是没有什么问题的,我做了简化,真实的驱动电路中还需要加入一些其他的电路以及二极管,如图:


5a803f6b61ccec314b47161af7bc8428.jpg


这个二极管的作用更大一些。

G极电阻并联二极管的作用:

因为MOS管内部都是有极间电容的,也就是说,在MOS的G极与S极之间有电容,也就是说,G极出来的这个电阻与GS极间电容形成一个RC充放电电路:如图:


e2bf3905854d91d068a8fb48c65b50a7.jpg


调节这个电阻就可以调节MOS输出的PWM由低电平到高电平的上升时间,上升实际太长或太短都不太好,根据实际情况选择电阻。

而PWM由高变低时的下降时间,同样时间常数也是由这个RC共同决定的,因此如果在G极电阻上并联一个二极管,放电的时候直接经过这个二极管把电流放出去,那么下降时间就会比较快。

当然,这个看你想不想加,想加的话按照图上自己添加即可。

这里需要提一下超过5V的电源怎么添加:

1.首先在图中的位置选中电源添加一个电源:


526854084ac185f3a26c337693a4d5fe.jpg


2.随后双击电源,修改电压,一定要有“+”号:


b25bb13bceebd56a3d07245cc579f91f.jpg


然后就是驱动芯片电路了:


bfedc438f9e0d884d171314d97af0b07.jpg


驱动信号的左边HIN与LIN也就是控制驱动芯片输出的两个输入信号了,也就是接入单片机,单片机输出是5V信号,而且电流小,是不可以直接驱动MOS管的,驱动芯片的作用实际就是增压扩流的作用,驱动芯片右边的HO也就是跟HIN的输入信号波形一致,但是是12V的,而且电流比较大,LO也是同样的。

当然,大家应该也都看到了那个C1,C2电容,这两个电容是半桥驱动的精髓,重中之重,没有这个电容,半桥是无法工作的,如图:


a9816f49dfdd4a63fd9ee23bcc375ca6.jpg


这两个电容俗称自举电容,或泵电容。这个不是某种特殊电容,而是按照功能给它起的名字,因为这个电容会把电压抬升上来,就像水泵一样,随意叫泵电容,驱动芯片的供电是12V,H桥的电压是24V,C1这个泵电容与D1这个二极管结合,会把电压抬升到36V,这就牵涉到另外一个知识点:为什么H桥上管的PWM不能发100%占空比。

有关自举电容或泵电容的详细解释,请自行百度,百度的解释肯定比我的解释要专业得多,电路这部分内容展开就没边了。只需要记住这个自举电容与它旁边的二极管比较重要即可,没有这两个,有可能电机也可以转,但电机是转不好的,稍后我们测试一下。

然后我们来测试一下,电路行不行,按照电机驱动的原理:


14031f5a7f41bfc210c3193f5f554c5d.jpg


按照上图的驱动原理,Q5发送PWM控制电流,Q7,Q6关闭,Q8打开,让电流经过Q5,电机,从Q8回到负极,电机就可以正转了,如此的话,反转也是一样的道理,Q6发PWM,Q5,Q8关闭,Q7打开,那么电机就会反转了,我们先不写程序,使用proteus自带的脉冲模块来试一下:


78f61a772ba0732cd4e6026ee1d7dd67.jpg


此时电机旋转如图:


676e46af1980a419eecd0bf38303a2ee.jpg


GIF看不清楚转速,就截图了,最后转速是在600转左右:


1ddc06c58ed75a4aa4ac41fe9e598347.jpg


如果我们把那个自举电容去掉呢?如图:


34e255de2e9569d7bb4afa44199c4612.jpg



77fcfc5e251c395493a2e0b2dc229aff.jpg


最后电机只能到200转,差距还是很大的。

现在我们是使用的proteus自带的脉冲模块来控制的电机,接下来就要使用单片机来控制了。因为proteus里没有东西能够测量直流电机的实际转速,所以也就只能开环控制,只能调节占空比了。因此我们使用LCD1602来显示当前的占空比,对于LCD1602的驱动说明,还有LCD1602源码,可以查看之前的文章:https://www.icxbk.com/article/detail/1067.html 这里就不在赘述了。

然后我们整理一下单片机发送PWM的思路,由于51单片机是没有单独的PWM模块的,因此只能使用IO口来模拟PWM,如果要控制精确一些,就需要定时器的配合,因此,我们需要选用一个定时器来计时,然后在定时器中断中自加一个变量,然后用那个变量来确定IO口发多长时间的高电平,多长时间的低电平。我们先确定控制MOS的引脚,程序中也先声明一下:


93cdd7ed0866f8e61ae2e68e0b1dea52.jpg



6f9b5f376673558c675725e827d0ea14.jpg


我们就先发送50%占空比,按照之前的思路,程序如下:


  • #include <reg52.h>

  • #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%占空比。

然后我们仿真一下,这时候报错了:


ea0eef69d7aadaa1e1ac7ccb1805d749.jpg 没关系,这个是proteus软件参数没有设置对,最小电导Minimum conductance设置得太小了,改一下即可:



05553ec3006f0f1898c8a0245fc894bf.jpg


选择System->Set Animation Options 我这里是Proteus8.6,也就是倒数第三个:


d0ae955f2bd593b1444d8c629d153179.jpg


然后点SPICE Options:


cea4a174aa4d6019399de56cf61bbef6.jpg


就是这个GMIN出了问题,我这里是1e-012,把这个修改成1e-05就好了,就是把这个数增大点:


314ad2e10b8db6746c7784d6f2a624a2.jpg


然后开始运行,可以看到电机已经可以转起来了,说明我们的PWM起作用了。


72a7cc379aa22d5258ca60aeba1061e9.jpg


然后我们把占空比显示在LCD上,程序如下:


  • /@@*显示函数*/

  • 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();

  • }

  • }

效果如图:


d59ec84b1228286b71df35ae70f91f44.jpg


然后,我们这个功能不完善,因为只能在程序上调占空比,至少要有两个按键来加减速的,因此,我们在电路上再加入两个按键:


008a7fea0a9432e77fe9666d4764eb9c.jpg


然后把按键检测的程序写上:


  • 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。然后我们在根据返回值来修改占空比即可,此时主函数修改如下:


  • 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按下则占空比减少*/

  • elseif(key_result ==2)

  • {

  • pulse = pulse - 10;

  • if(pulse <0)

  • pulse =0;

  • }

  • }

  • }


由于我在仿真中使用的是带惯性负载的电机,因此电机转速变化会比较慢,最后放一个综合起来的效果图:


a76b835ac06a40fe837259f2941d1654.jpg


本篇就只做了电机正转的程序,反转举一反三即可,改动不大,而且本篇对于电源部分的降压电路,24V转12V,12V转5V并没有画出,这一点注意。

我的工程目录如图:


3995e72842684ff9e845e82c2a3cda56.jpg


因此,这个工程我就只贴主文件的程序了。

main.c程序如下:


  • #include <reg52.h>

  • #include "1602.h"

  • #include <stdio.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;

  • 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按下则占空比减少*/

  • elseif(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;

  • }

  • }

.
您需要登录后才可以回帖 登录 | 请使用中文注册

本版积分规则

QQ|Archiver|手机版|家电维修论坛 ( 蜀ICP备19011473号-4 川公网安备51102502000164号 )

GMT+8, 2025-5-15 03:57 , Processed in 0.198129 second(s), 24 queries .

Powered by Discuz! X3.5

© 2001-2025 Discuz! Team.

快速回复 返回顶部 返回列表