【Proteus】单片机H桥驱动24V直流有刷电机
时间:2022-08-17 15:30:02
前言
一般直流刷电机的模拟是直接高低电平驱动的,或者ULN2003年,这种电路只能驱动小电压、小功率的电机。如果遇到电压稍高、电流较大的电机,2003年无法驱动。此时,对于大电流电机,通常是MOS管或者IGBT,相对来说,NMOS这是经济实用的选择,本节带领大家使用单片机,搭建H桥驱动电路驱动24V直流有刷电机。我会把整个程序附在最后,或者懒得复制粘贴,需要整个项目和模拟给我一些欣赏。
先附上上一张完整的模拟电路图,然后逐一解释:
如果你想使用H桥,你需要一个半桥驱动芯片。当然,市场上有各种各样的驱动芯片,如半桥驱动芯片、三相桥集成驱动芯片等,但在protues我只找到一个IR2101驱动是一款高压驱动芯片,24V是低压的,但也没关系,只能用这个,仿真应该可以。
一是绘制H桥驱动电路:
这是我画的H桥驱动电路。这个电路的驱动原理没有问题。我简化了它。在真正的驱动电路中还需要添加一些其他电路和二极管,如图所示:
二极管的作用更大。
G极电阻并联二极管的作用:
因为MOS管内有极间电容,也就是说,在MOSG极和S极之间有电容,也就是说,G极出的电阻和GS形成极间电容RC如图:
调以调节此电阻MOS输出的PWM根据实际情况选择电阻,从低电平到高电平的上升时间实际上太长或太短。
而PWM从高到低的下降时间,同样的时间常数也是由这个RC共同决定,如果G极电阻上并联二极管,放电时直接通过二极管释放电流,下降时间会更快。
当然,这取决于你是否想添加它。如果你想添加它,你可以根据图片添加它。
这里需要提的是超过5V如何添加电源:
1.首先在图中选择电源并添加电源:
2.然后双击电源,修改电压,必须有 ”号:
然后驱动芯片电路:
左侧驱动信号HIN与LIN即控制驱动芯片输出的两个输入信号,即接入单片机,单片机输出为5V信号,电流小,不能直接驱动MOS管道驱动芯片的作用实际上是增压扩流,驱动芯片右侧HO也就是跟HIN但12V而且电流比较大,LO也一样。
当然,每个人都应该看到那个C1,C两个电容器,这两个电容器是半桥驱动的精髓,最重要的是,没有这个电容器,半桥就不能工作,如图所示:
这两个电容器通常被称为自举电容器或泵电容器。这不是一个特殊的电容器,而是根据功能命名的,因为电容器会提高电压,就像泵一样,随意称为泵电容器,驱动芯片的电源是12V,H桥的电压是24V,C泵电容和D1种二极管的组合将电压提升到36V,这涉及到另一个知识点:为什么H桥管理PWM不能发100%的空比。
对于自举电容器或泵电容器的详细解释,请自行使用百度。百度的解释肯定比我的解释专业得多,电路的这部分是无限的。只要记住,这个自举电容器比它旁边的二极管更重要。没有这两个,电机也可以转动,但电机转动不好。让我们稍后测试一下。
然后,让我们根据电机驱动的原理来测试电路是否工作:
按照上图的驱动原理,Q5发送PWM控制电流,Q7,Q6关闭,Q打开,让电流通过Q5,电机,从Q8回到负极,电机就可以正转,所以,反转也是如此,Q6发PWM,Q5,Q8关闭,Q如果7打开,电机会反转。我们不会先写程序并使用它proteus自带脉冲模块试试:
此时电机旋转如图:
GIF看不清转速,我就截图,最后转速在600转左右:
如何去除自举电容?如图所示:
最后电机只能转200转,差距还是很大的。
现在我们用了proteus自带的脉冲模块来控制的电机,接下来就要使用单片机来控制了。因为proteus直流电机的实际转速无法测量,只能开环控制,只能调节占空比。所以我们用它LCD1602显示了当前的空比,对于LCD1602的驱动说明,还有我的LCD1602源码,您可以查看以前的文章:https://www.icxbk.com/article/detail/1067.html这里就不赘述了。
然后我们整理一下单片机发送PWM因为51单片机没有单独的想法PWM只能使用模块IO口来模拟PWM,如果要精确控制,需要定时器的配合。因此,我们需要选择定时器进行计时,然后在定时器中断中添加一个变量,然后使用该变量进行确定IO口发高电平多久,低电平多久。先确定控制MOS程序中还首先声明了引脚:
根据之前的想法,程序如下:
#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)%6; 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)%6; //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.也就是倒数第三:
然后点SPICE Options:
就是这个GMIN出了问题,我这里是1e-012将此修改为1e-05就是增加这个数字:
然后开始运行,你可以看到电机可以转动,表明我们的PWM起作用了。
然后我们将占空比显示。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(); } }
效果如图:
然后,我们的功能并不完美,因为我们只能在程序上增加空间,至少有两个按钮来加减速,所以我们在电路上增加了两个按钮:
然后检测按钮程序写上:
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按下则占空比减少*/
else if(key_result == 2)
{
pulse = pulse - 10;
if(pulse < 0)
pulse = 0;
}
}
}
由于我在仿真中使用的是带惯性负载的电机,因此电机转速变化会比较慢,最后放一个综合起来的效果图:
本篇就只做了电机正转的程序,反转举一反三即可,改动不大,而且本篇对于电源部分的降压电路,24V转12V,12V转5V并没有画出,这一点注意。
我的工程目录如图:
关于1602的驱动程序,在之前的文章已经贴上的所有程序。链接:【Proteus】单片机配合矩阵键盘LCD1602制作简易计算器 - 知乎
因此,这个工程我就只贴主文件的程序了。
main.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;
}
}
喜欢就点个赞喔!