资讯详情

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

前言

一般直流刷电机的模拟是直接高低电平驱动的,或者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 <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)%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 <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按下则占空比减少*/
        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;        
    }
}

喜欢就点个赞喔!

标签: 480v三相电容103j1600v电容器电机电容器500v电容220vhg628电机电容器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台