电机是我们日常生活中比较常用的一个工具,我们经常需要使用电机来转动和拖动,完成一些任务。本次设计便用基于51单片机完成的电机转动与调速,使得电机可以正常启停、加速、减速以及正反转。
文章末尾提供资源免费下载,包括proteus仿真文件与源码。
51单片机的最大电压为5V,最大输出电流为10mA。可想而知,我们不可能依靠单片机引脚去驱动电机,因此我们需要借助电机驱动芯片来完成这项艰难的任务。L289芯片在protues中长这个样子:
乍一看,这东西看着挺复杂,这么多引脚。其实,仔细研究过就会知道,这东西很简单。其他博主有很详细的介绍L298的引脚功能,这里就不讲,简单说下本次用到的。IN1和IN2是用来控制启停和正反转的,IN1为1,IN2为0就正转,反之则为反转,全为0或全1则制动,同时,这也是PWM输入入口,控制电机转速。ENA引脚为1,表示可以PWM调速。VCC为工作电压,5V,VS为驱动电压12V,OUT1和OUT2表示输出,连接电机正负极,1接正,2接负。此处为网上找到的资源,我测试过可以用,如有纰漏,欢迎指正。
下面介绍本次设计的主角,带编码器的直流电机。protues中,它长这个样子:
左右两边的“手”便是它的正负极,我们将他两与L298的OUT1与OUT2相连。上面的三根头发,左右两边根据设定值,每圈发出固定数量的脉冲,我们根据脉冲数即可知道转了几圈。本次设计中,每圈输出24个脉冲。那么在哪里修改呢?双击电机,可以看到下图:
相信你看到了24了吧,该怎么改,你自己决定。那电机最中间的头发呢?据说是每圈一个脉冲,感兴趣的同学可以试试。电机最下面的绿色屏幕就是转速了,单位是r/min。
至于脉冲数的统计,这里提供两个思路,一个是计数器,一个是外部中断。我们可以将其中一个定时器做计数器,计算脉冲,另一个计时,计算转速。另外一种是通过外部中断统计脉冲数,定时器计时,获得转速。
至于PWM的生成方法,我们可以这么想。IO口有两种状态,1和0。我用定时器计100us,70us我r让一个IO口为1,30us为0,我不就得到了一串方波,周期100us。程序实现就是设置一个变量comper,作为比较量,另一个变量count_pwm为累加量,10us加1,大于comper为1,小于为0,ok,得到了可调PWM。
下面是具体实现,每段代码,每个变量都有详细注释,同时欢迎留言询问,源码0error,0warning。
(1)定时器部分(timer.c)定时器T0计时,T1产生PWM
#include <reg52.h>
/************************************
函数名:timer_Init
功能:定时器初始化,T0用作50ms定时,
T1用10us定时
形参:无
返回值:无
*************************************/
void timer_Init()
{
TMOD = 0x11;
TL0 = 0xB0; //设置定时初始值50ms
TH0 = 0x3C; //设置定时初始值
TL1 = 0xF6; //设置定时初始值10us
TH1 = 0xFF; //设置定时初始值
TF0 = 0; //清除溢出标志
TF1 = 1;
ET0 = 1; //定时中断允许
ET1 = 1;
EA = 1; //总中断
IT0 =1; //外部中断
EX0 =1; //下降沿出发
TR0 = 1; //定时器开
TR1 = 0;
}
timer.h
#ifndef __TIMER_H
#define __TIMER_H
void timer_Init();
#endif
(2)按键部分,控制电机启停、正反转、加速、减速
key.c
#include <reg52.h>
#include <intrins.h> //nop所在头文件
#include "key.h" //按键头文件
/***********************************
函数名:delay_key
功能:5ms延时,用于按键消抖,此处是
为了protues仿真速度,实际应为20ms
形参:无
返回值:无
***********************************/
void delay_key()
{
unsigned char i, j;
i = 6;
j = 211;
do
{
while (--j);
} while (--i);
}
/***********************************
函数名:key_pron
功能:按键处理函数(k1:开始,k2:停止
k3:加速,k4:减速 ,k5:正转,k6:反转
形参:无
返回值:无
*************************************/
void key_pron()
{
if(K1 == 0) //开始
{
delay_key(); //消抖
if(K1 == 0)
{
TR1=1; //启动定时器
ENA = 1;
motor_flag = 0;
IN2 = 0;
comper = 50;//初始转速
while(K1 == 0) //松手检测
{
SMG_display();
}
}
}
if(K2 == 0) //停止
{
delay_key(); //消抖
if(K2 == 0)
{
TR1 = 0; //停止定时器
IN1 = 0;
IN2 = 0;
comper = 50; //初始转速
while(K2 == 0) //松手检测
{
SMG_display();
}
}
}
if(K3 == 0) //加速
{
delay_key();
if(K3 == 0)
{
comper=comper-10; //增加占空比
if(comper<0) //上限
comper = 0;
while(K3 == 0)
{
SMG_display();
}
}
}
if(K4 == 0) //减速
{
delay_key();
if(K4 == 0)
{
comper=comper+10;//减小占空比
if(comper >100)//下限
comper = 100;
while(K4 == 0)
{
SMG_display();
}
}
}
if(K5 == 0) //正转
{
delay_key();
if(K5 == 0)
{
motor_flag = 0; //正转标志
ENA = 1;
IN2 = 0;
while(K5 == 0)
{
SMG_display();
}
}
}
if(K6 == 0) //反转
{
delay_key();
if(K6 == 0)
{
motor_flag = 1; //反转标志
ENA = 1;
IN1 = 0;
while(K6 == 0)
{
SMG_display();
}
}
}
}
key.h
#ifndef __KEY_H
#define __KEY_H
//按键
sbit K1 = P1^0;
sbit K2 = P1^1;
sbit K3 = P1^2;
sbit K4 = P1^3;
sbit K5 = P1^4;
sbit K6 = P1^5;
sbit ENA = P2^5;
sbit IN1 = P2^3;
sbit IN2 = P2^4;
extern bit motor_flag;
extern void SMG_display();
void delay_key();
void key_pron();
extern char comper; //PWM占空比调节
#endif
(3)数码管显示部分,采取共阴四位数码管,保留一位小数
smg.c
#include <reg52.h>
#include "seg.h"
unsigned char code SMG_NODOT[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};//无小数点
unsigned char code SMG_DOT[10]= {0xbf,0x86,0xdb,0xcf,0x6e6,0xed,0xfd,0x87,0xff,0xef};//有小数点
/*************************************
函数名:SMG_Init
功能:数码管初始化函数
形参:pos:显示位 value:显示值
返回值:无
**************************************/
void SMG_Init(unsigned char pos,unsigned char value)
{
unsigned char dat = 0x80;
P3 = P3&(~(dat >> pos));
P0=value;
delay(2);
P0 = 0x00;
P3 = P3|0xf0;
}
/***********************************
函数名:SMG_display
功能:数码管显示函数
形参:无
返回值:无
************************************/
void SMG_display()
{
SMG_Init(0,SMG_NODOT[speed/1000]);
SMG_Init(1,SMG_NODOT[(speed%1000)/100]);
SMG_Init(2,SMG_DOT[(speed%100)/10]);
SMG_Init(3,SMG_NODOT[speed%10]);
}
smg.h
#ifndef __SEG_H
#define __SEG_H
extern void delay(unsigned char t);
extern unsigned int speed;
void SMG_Init(unsigned char pos,unsigned char value);
void SMG_display();
#endif
(4)主函数main.c
/**********************************************************
Author :sakura
Time :2023/4/22
Funcation:51单片机使用L298电机芯片驱动带编码器的电机,
通过编码器测量转速,同时使用LED数码管显示,
按键可使电机正反转并改变速度
***********************************************************/
//头文件
#include <reg52.h> //51单片机头文件
#include <intrins.h> //nop所在头文件
#include "main.h" //主函数头文件
#include "timer.h" //定时器头文件
#include "key.h" //按键头文件
#include "seg.h" //数码管头文件
/*************************************
函数名:main
功能:主函数入口
形参:无
返回值:无
**************************************/
void main()
{
timer_Init(); //定时器初始化
IN1 = 1;
IN2 = 1;
while(1)
{
SMG_display(); //数码管显示
key_pron(); //按键扫描
}
}
/***********************************
函数名:INT0_isr
功能:外部中断0入口,统计编码器脉冲
形参:无
返回值:无
************************************/
void INT0_isr() interrupt 0
{
count_f++;//每秒脉冲数
}
/*****************************
函数名:timer0_isr
功能:定时器0中断入口,定时50ms
每秒计算一次转速
形参:无
返回值:无
*****************************/
void timer0_isr() interrupt 1
{
TL0 = 0xB0; //设置定时初始值50ms
TH0 = 0x3C; //设置定时初始值
count_50ms++;
if(count_50ms == 20)
{
count_motor = count_f + count_motor;
count_f = 0;
}
if(count_50ms == 40)
{
count_50ms = 0;
count_motor = count_f + count_motor;
speed_real = (count_motor * 0.0416666);//计算每秒圈数,每圈24个秒冲 //总脉冲/24 = 圈数
speed = speed_real*300;//每秒转圈数(一位小数)
count_f = 0;
count_motor = 0;
}
}
/*******************************
函数名:timer1_isr
功能:定时器1中断入口,定时10us,
用于产生PWM波
形参:无
返回值:无
*******************************/
void timer1_isr() interrupt 3
{
TL1 = 0xF6; //设置定时初始值
TH1 = 0xFF; //设置定时初始值
count_pwm ++;
if(count_pwm == 100)
count_pwm = 0;
if(count_pwm>comper)
{
if(motor_flag == 0) //正转对IN1输出PWM
IN1 = 1;
else //反转对IN2输出PWM
IN2 = 1;
}
else
{
if(motor_flag == 0)
IN1 = 0;
else
IN2 = 0;
}
}
main.h
#ifndef __MAIN_H
#define __MAIN_H
#include <reg52.h>
#include <intrins.h> //nop所在头文件
//变量
unsigned char count_f = 0; //编码器脉冲计数
unsigned char count_50ms = 0; //50ms计数
char comper = 50; //PWM占空比调节
float speed_real = 0; //转速中间变量
unsigned int speed = 0; //转速,r/min
unsigned char count_pwm = 0; //pwm统计
bit motor_flag = 0; //正反转标志
unsigned char count_motor = 0; //滤波变量
//函数声明
void delay(unsigned char t); //延时函数
/*************************************
函数名:delay
功能:t*10us延时
形参:t:延时次数
返回值:无
*************************************/
void delay(unsigned char t)
{
unsigned char i;
while(t--)
{
_nop_();
i = 2;
while (--i);
}
}
#endif
以上就是全部代码了。仿真结果如下:
实际转速81.4,数码管81.2,低速误差是很小的。至于其他比如正反转、加减速不好展示,欢迎大家下载资源测试,仅需您小小的一个赞。
链接:https://pan.baidu.com/s/1A_J6M07DGOFI9C_JDM_NPQ?pwd=ae1v
提取码:ae1v文章来源:https://www.toymoban.com/news/detail-464083.html
文章来源地址https://www.toymoban.com/news/detail-464083.html
到了这里,关于基于51单片机的电机(L298芯片,PWM调速,可加速、减速、正转、反转)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!