zl程序教程

您现在的位置是:首页 >  其他

当前栏目

PWM控制直流电机的正转、反转、加速和减速

2023-03-20 15:32:15 时间

文章目录

一、设计要求

使用 PWM 电路来控制直流电机的正转、反转、加速和减速,并将转向和转速显示出来。

  • 设置按键控制直流电机的启动/停止的开关
  • 设置按键控制直流电机的加速、减速
  • 设置按键控制直流电机的正转、反转
  • 设置显示模块可以直观地了解到直流电机的转速和转向

二、设计思路

  • 直流电机 PWM 控制系统的主要功能包括:直流电机的加速、减速以及电机的正转和反转,并且可以调整电机的转速,还可以方便地读出电机转速的大小和转向,从而实现电机的智能控制。其中还包括直流电机的直接清零、启动(置数)、暂停等功能。
  • 该直流电机系统由以下电路模块组成:振荡器和时钟电路,这部分电路主要由 AT89C51 单片机和一些电容、晶振组成。
  • 设计输入部分:这一模块主要是利用带中断的独立按键来实现。
  • 设计控制部分:主要由 AT89C51 单片机的外部中断扩展电路组成。
  • 设计显示部分:包括液晶显示部分和 LED 数码显示部分。液晶显示部分由 LCD 液晶显示模块组成;LED数码显示部分由七段数码显示管组成。
  • 直流电机 PWM 控制实现部分:主要由一些二极管、电机和 L298 直流电机驱动模块组成。

三、仿真电路设计

  • AT89C51单片机、外接晶振、复位电路
  • P2口 P0-P7 接 LCD 的D0-D7,P0.5、P0.6、P0.7分别接 LCD 的RS、RW、E,且要接上拉电阻,P0口无上拉电阻,不然点不亮,实际应用中也要接。
  • 独立按键通过 7 输入与门与 P3.3 口 (外部中断1) 相连
  • P1.0接IN1,P1.1接IN2,P1.2接 L298 使能信号ENA,初始化ENA=0;TR0=0,启动,使能ENA,TR0=~TR0,开启定时,输出PWM波。
  • P3.3口引起外部中断,调用按键扫描函数,进入按键处理程序。
  • 在定时器中断服务子程序中,direc=1,为正转,IN1=1,IN2=0;direc=0,IN1=0,IN2=1,为反转,控制电机正转、反转,通过条件控制,可以改变输出 PWM 矩形波的占空比,从而实现调速效果。

四、KeilC51程序设计

1. 初始化参数

#include<reg52.h>
#define uint unsigned int 
#define uchar unsigned char
	
sbit k1=P3^4;	  //启动/停止按键
sbit k2=P3^5;	  //减速按键
sbit k3=P3^6;	  //加速按键
sbit k4=P3^7;	  //正反转按键
sbit k5=P3^2;	  //模式控制

//LCD1602控制引脚,其中P2为数据口
sbit RS=P0^5;
sbit RW=P0^6;
sbit E=P0^7;

sbit ENA=P1^2;		//IN1,IN2使能信号
sbit IN1=P1^0;		//电机输入线
sbit IN2=P1^1;

bit model=1;		//手动/自动,默认启动时显示自动
bit direc=1;		//转向标志,默认启动时为正转 L
int rate=1;		  //高电平时间常数
int num=0;			//1ms中断记录   统计脉冲个数
int count=0;		//1ms中断记录,自动模式加速时间常数

uchar code tab1[]="     Welcome  ";
uchar code tab2[]="    2020/12/9";
uchar code tab3[]="  Motor Control ";
uchar code tab4[]="Team:ZHL YYQ ZYY";
uchar code tab5[]="Dire:    Mode: ";
uchar code tab6[]="Rate:    T:29 ";

2. LCD显示

/********************** LCD显示 ****************************/
void w_com(uint com)	 //写指令
{
	RS=RW=E=0;
	P2=com;
	E=1;            //写指令的操作时序:RS=0,RW=0,EN=高电平
	delay_xus(1);
	E=0;
}
void w_data(uint dat)	 //写数据
{
	RS=1;RW=E=0;
	P2=dat;
	E=1;   //写数据的操作时序:RS=0,RW=0,EN=高电平
	delay_xus(1);
	E=0;
}
void w_shuzu(int addr,uchar code *p)  //显示字符串
{
	int i;
	w_com(0x80+addr);
	delay_xus(1);
	for(i=0;p[i]!='';i++)    //串口发送字符串时,可以通过''判断字符串是否结束
	{
			w_data(p[i]);
			delay_xus(1);		
	}	
}

void disp()			  //显示速度、转向、模式
{
	//显示数值   转成ASCII码表
	if(rate<10)             //小于10的时候  只有个位
	{
		w_com(0x80+0x45);	 
		delay_xus(1);
		w_data(' ');
		delay_xus(1);
		w_com(0x80+0x46);	 
		delay_xus(1);
		w_data(rate%10+0x30);  //查ASCII码表  这一位的数字+0x30  数字转换成ASCII码才能显示
		delay_xus(1);
	}
	else									 
	{
		w_com(0x80+0x45);	 
		delay_xus(1);
		w_data(rate/10+0x30);    //十位
		delay_xus(1);
		w_com(0x80+0x46);	 
		delay_xus(1);
		w_data(rate%10+0x30);   //个位
		delay_xus(1);
	}
	if(direc==1)           //正转
	{
		w_shuzu(0x06,"L");
	}
	else                  //反转
  { 
	  w_shuzu(0x06,"R");
  }
	if(model==0)    //手动按键控制
	{
		w_shuzu(0x0f,"H");
	}
	else           //自动
	{
		w_shuzu(0x0f,"A");
	}
}

3. 主程序初始化

/************* 主程序初始化 ************************/
void init()
{
	//LCD显示初始化
	w_com(0x38);	   //设置16*2显示 
	delay_xus(1);
	w_com(0x0c);		 //开显示 显示光标,光标闪烁
	delay_xus(1);
	w_shuzu(0x00,tab1);	   //显示字符串
	w_shuzu(0x40,tab2);
	delay(500);
	w_com(0x01);		  //清屏
	delay_xus(1);
	delay(2);			   //忙碌
	w_shuzu(0x00,tab3);
	w_shuzu(0x40,tab4);
	delay(1000);
	w_com(0x01);		   //清屏
	delay_xus(1);
	delay(2);
	w_shuzu(0x00,tab5);
	w_shuzu(0x40,tab6);
	disp();
	
	ENA=0;
	TMOD=0X01;     //定时器0工作在方式1
	TH0=0XFC;	   //(65536-1000)=FC18(12MHz定时的1ms)  
	TL0=0X18;
	ET0=1;        //定时器0中断允许
	TR0=0;
	EX1=1;        //外部中断INT1
	IP=0X02;	  //设置定时器0为高优先级中断 T0的中断级别为高,因为PWM的脉冲宽度就是在中断程序里设定,如果此时被其他更高级别的中断打断,那么脉冲宽度将不准确,从而导致控制转速失败。
	EA=1;       //开总中断
}

4. 主程序

/*********************** 主程序 ***************************/
void main()
{
	init();
	while(1) ;
}

5. 延时子程序

/***************** 延时子程序 **************************/
void delay_xus(uint x)   //小延时  us
{
	while(x--);
}

void delay(uint x)			//为12MHz晶振提供延时函数 ms级
{
	uint y;
	for(;x>0;x--)
		for(y=110;y>0;y--) ;
}

6. 按键处理程序

/******************* 按键处理程序 ************************/
void keyscan()
{
	if(k1==0)			//启停
	{
		delay(120);
		if(k1==0)
		{
			TR0=~TR0;  //开启定时   输出PWM波
			ENA=~ENA;  //使能   电机转
			rate=1;	
		}
	}
	if(k2==0&&model==0)	  //减速  减速键按下
	{
		delay(120);
		if(k2==0&&model==0)
		{
			rate-=2;		 //为之后改变输出PWM波的占空比
			if(rate<=1) rate=1;
		}
	}
	if(k3==0&&model==0)		  //加速  加速键按下
	{
		delay(120);   //软件延时
		if(k3==0&&model==0)
		{
			rate+=2;         //为之后改变输出PWM波的占空比
			if(rate>=29) rate=29;
		}
	} 
	if(k4==0&&model==0)		  //转向
	{
		delay(120);
		if(k4==0&&model==0)
		{
			direc=~direc;    //取反
		}
	}
	if(k5==0&&ENA==0)		 //模式选
	{
		delay(120);
		if(k5==0&&ENA==0)
		{
			model=~model;
		}
	}
	disp();	  //状态改变,更新显示数据
}

7. 中断服务子程序

/******************* 中断服务程序 *************************/
void extern1() interrupt 2		  //外部中断INT1   按键扫描
{
	keyscan();
}

void timer0() interrupt 1		   //定时器0中断
{
	num++;   //计数
	if(num>=29) num=0;	//超过范围  num=0
	if(direc==1)		//通过direc判断  为正转
	{
		if(num<=rate)	//跟rate比较   高电平持续时间   
		{
			IN1=1;     //正转
			IN2=0;
		}
		else IN1=IN2=0;	 //低电平持续时间
	}
	else				   //否则   反转
	{	
		if(num<=rate)
		{
			IN1=0;		//反转
			IN2=1;
		}
		else IN1=IN2=0;
	}
	
	if(model==1)		    //自动模式下,执行,加速时间常数
	{
		count++;
		if(count==1500) 	//1.5s后占空常数增加,加速
		{
			rate+=2;
			if(rate>=29) rate=29;
			count=0;
			disp();
		}
	}
	TH0=0XFC;	  		 //重装初值   (65536-1000)=FC18(12MHz的定时1ms)  
	TL0=0X18;	  
}

五、测试效果

刚启动时,电机转速较慢,转向显示L,逆时针在转动,加速到转速较大时,再改变电机的转向,转向显示R,顺时针转动,实现控制电机正转、反转。

控制电机加速,输出 PWM 矩形波高电平持续时间变长

控制电机减速,输出 PWM 矩形波高电平持续时间变短

控制电机正转、反转

转向显示 L 时,P1.0口输出 PWM 波,正转;转向显示 R 时,P1.1口输出 PWM 波,反转

设计符合要求,仿真效果也挺好。

作者:叶庭云 CSDN:https://yetingyun.blog.csdn.net/