基于51单片机PWM(即脉冲宽度调制)调速数码管显示测速L298M芯片控制直流电机正反运转的项目

该项目使用51单片机通过PWM技术控制直流电机速度,结合LCD1602显示器显示时间并支持按键调整。详细描述了如何利用Keil软件编写C程序,以及Proteus软件仿真外围电路。通过按键操作,可以实现计时的启动、停止、修改,并控制电机正反运转。

基于51单片机PWM(即脉冲宽度调制)调速数码管显示测速L298芯片控制直流电机正反运转的项目

一、前言

1、基于51单片机PWM(即脉冲宽度调制)调速数码管显示测速L298芯片控制直流电机正反运转的项目包括用Keil软件编写单片机C语言程序和用Proteus软件仿真单片机外围电路

2、基于51单片机PWM(即脉冲宽度调制)调速数码管显示测速L298芯片控制直流电机正反运转项目构思

(1)、实现什么功能:LCD1602字符型液晶显示器先显示时分秒,在点击移位按键后,停止计时,LCD1602字符型液晶显示器光标闪烁,每次按下移位键,LCD1602字符型液晶显示器光标随每次按下移位键移位到时分秒个位十位处闪烁,当LCD1602字符型液晶显示器的时分秒个位十位有闪烁后,可修改LCD1602字符型液晶显示器的时分秒个位十位闪烁位上的数值,再通过移位按键或启停按键启动或停止计时。

(2)、如何实现功能:如何让LCD1602字符型液晶显示器先显示时分秒:采用定时器0工作方式1计时,计时得到的数值赋给LCD1602字符型液晶显示器显示时间两位数分解函数进行分解,分解得到的个位数值与十位数值用变量代替分别由LCD1602字符型液晶显示器写指令函数和LCD1602字符型液晶显示器写数据函数写入LCD1602字符型液晶显示器,通过LCD1602字符型液晶显示器显示出来。如何让LCD1602字符型液晶显示器的时分秒个位十位闪烁:采用按键扫描函数扫描,每次按下移位键(此时定时器0停止计时),执行LCD1602字符型液晶显示器光标闪烁指令和LCD1602字符型液晶显示器光标随每次按下移位键移位到时分秒个位十位处闪烁的位置指令。如何修改LCD1602字符型液晶显示器的时分秒个位十位闪烁位数值并在原计时基础上实现计时:当移位键按下后,定时器0停止计时,计时得到的数值采用两位数分解公式(如:shi=num/10,ge=num%10。)进行分解,分解得到的个位数值与十位数值用变量代替写入按键扫描函数,此时也要采用两位数合成公式(如:miao=shi+ge=(num/10)*10+num%10)求出原先的计时数值,用变量代替原先的计时数值写入按键扫描函数(原因:时分秒的个位或十位显示位的数值是在原计时数值上分解得来,当时分秒的个位或十位显示位的数值发生变化后,原计时数值也要变化,否则启动定时器0计时后,LCD1602字符型液晶显示器显示的是原计时时间,而不是修改时分秒的个位或十位显示位的数值后的计时,因此要采用两位数合成公式(miao=shi+ge=(num/10)*10+num%10)求出原先的计时数值,用变量代替原先的计时数值写入按键扫描函数。)。

二、基于51单片机PWM(即脉冲宽度调制)调速数码管显示测速L298芯片控制直流电机正反运转项目的Keil软件编写的单片机C语言程序

#include<reg52.h>//单片机头文件
#define uchar unsigned char//宏定义,用uchar表示unsigned char,叫无符号字符型数据类型,取值范围为:0到255。
#define uint unsigned int//宏定义,用uint表示unsigned int,叫无符号整数型数据类型,取值范围为:0到65535。
sbit qitingjian=P1^0;//位定义启停键
sbit zhengzhuan=P1^1;//位定义正转键
sbit fanzhuan=P1^2;//位定义反转键
sbit jiasujian=P1^3;//位定义加速键
sbit jiansujian=P1^4;//位定义减速键
sbit IN1=P1^5;//位定义数码管段码端口
sbit IN2=P1^6;//位定义数码管位码端口
sbit ENA=P1^7;//位定义L298M芯片使能端ENA
sbit duan=P3^0;//位定义L298M芯片控制端IN1
sbit wei=P3^1;//位定义L298M芯片控制端IN2
sbit qitingled=P3^4;//位定义启停指示灯
sbit zhengzhuanled=P3^5;//位定义正转指示灯
sbit fanzhuanled=P3^6;//位定义反转指示灯
sbit zhuansuled=P3^7;//位定义转速指示灯
sbit waibuzhongduanling=P3^2; //外部中断0端口
uint qian,bai,shi,ge,zhuansu;//数码管千位变量、百位变量、十位变量、个位变量以及转速变量
uint maichongcount,Time0num,Time1num,pwm,qitingnum,zhengzhuanflag,fanzhuanflag;//脉冲计数变量、定时器0定时计数变量、定时器1定时计数变量、脉冲宽度调制变量、启停键按下数次变量、正转标志位变量、反转标志位变量
uchar code table[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x27,0x7f,0x6f,0x40,0x7c,0x39,0x5e,0x79,0x71,0x00};//共阴数码管段码,高电平点亮段码,低电平熄灭段码。
uchar code weima[]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,0xff};//共阴数码管位码,低电平点亮位码,高电平熄灭位码。
void delay(uint jishi);//毫秒延时函数
void TimerInit();//定时器初始化函数
void Time0();//定时器0定时函数
void Time1();//定时器1定时函数
void KeyScan();//按键扫描函数
void waibuzhongduanlingjishu();//外部中断0计数函数
void shumaguandisplay(uint qian,uint bai,uint shi,uint ge);//数码管显示函数
void shumaguannodisplay(uint qian,uint bai,uint shi,uint ge);//数码管无显示函数
  void main()//主函数
{
   TimerInit();//定时器初始化函数
   IN1=0;//L298M芯片控制端IN1置低电平,电机不运转。
   IN2=0;//L298M芯片控制端IN2置低电平,电机不运转。
   while(1)//死循环
 {
    KeyScan();//按键扫描函数
	if(qitingnum==1)//判断启停键是否第一次按下
	shumaguandisplay(qian,bai,shi,ge);//数码管显示函数
  }
 }
  void delay(uint jishi)//延时函数
{
   uint i,j;
   for(i=jishi;i>0;i--)
    for(j=110;j>0;j--);
  }
  void TimerInit()//定时器初始化函数
{
   TMOD=0x11;//设定定时器为定时器0和定时器1,工作模式都为1。
   TH0=(65536-1000)/256;//TH0装初值为65536-100=65436,即定时100微妙,相当于0.1毫秒。
   TL0=(65536-1000)%256;//TL0装初值为65536-100=65436
   TH1=(65536-50000)/256;//TH1装初值为65536-50000=15536,即定时50000微妙,相当于50毫秒。
   TL1=(65536-50000)%256;//TL1装初值为65536-50000=15536
   EA=1;//全局中断允许
   ET0=1;//打开定时器0中断允许
   TR0=1;//开定时器0       
   EX0=1;//开外部中断0允许
   IT0=1;//设置外部中断0下降触发中断
   ET1=1;//打开定时器1中断允许
   TR1=1;//开定时器1
 }
  void Time0() interrupt 1//定时器0定时函数,每0.1毫秒产生pwm波一次。
{       
   TH0=(65536-1000)/256;//TH0重装初值为65536-100=65436,即定时100微妙,相当于0.1毫秒。
   TL0=(65536-1000)%256;//TH0重装初值为65536-100=65436
   Time0num++;//定时器0定时计数变量先赋值再自加
   if(Time0num==20)//判断定时器0定时计数变量是否大于等于20,PWM波完整周期为20ms,定时器0定时计数变量Time0num数值越大,电机运转越快。
  {
    Time0num=0;//定时器0定时计数变量等于0
   }
   if(Time0num<pwm)//判断定时器0定时计数变量还否小于脉冲宽度调制变量       
  {                               
    ENA=1;//L298M芯片使能端ENA置高电平,电机运转。
	zhuansuled=0;//开转速指示灯
   }
   else
  {
    ENA=0;//L298M芯片使能端ENA置低电平,电机不运转。
	zhuansuled=1;//关转速指示灯
   }
}
  void Time1() interrupt 3//定时器1定时函数,定时50ms,采集电机转速。       
{       
   TH1=(65536-50000)/256;//TH1装初值为65536-50000=15536,即定时50000微妙,相当于50毫秒。
   TL1=(65536-50000)%256;//TH1装初值为65536-50000=15536
   Time1num++;//定时器1定时计数变量先赋值再自加
   if(Time1num==20)//判断定时器1定时计数变量是否等于20,即每1秒测速一次。
  {       
    Time1num=0;//定时器1定时计数变量等于0
    EX0=0;//关外部中断0
    zhuansu=55*maichongcount/24;//电机转速=每分钟X脉冲计数变量/每转一圈需要的脉冲个数,即55*maichongcount/24,其中的55表示55秒,为什么不是一分钟60秒?由于Protues仿真电路图中的MOTOR-ENCODER仿真件存在误差,为了让MOTOR-ENCODER仿真件显示的转速达到数码管显示转速的效果,进行了一定秒数的修改,不过实际运用要以一分钟60秒为准,maichongcount为单片机从外部中断0端口处获取MOTOR-ENCODER仿真件旋转生产的脉冲计数变量,24为MOTOR-ENCODER仿真件每旋转一圈产生的脉冲个数。
    qian=zhuansu/1000;//数码管千位显示
	bai=zhuansu%1000/100;//数码管百位显示
    shi=zhuansu%100/10;//数码管十位显示
    ge=zhuansu%10;//数码管个位显示
    maichongcount=0;//脉冲计数变量归零
    EX0=1;//开外部中断0
   }
}
  void waibuzhongduanlingjishu() interrupt 0  using 1//外部中断0计数函数,外部脉冲计数。
{
   maichongcount++ ;//脉冲计数变量先赋值再自加
  }
  void KeyScan()//按键扫描函数
{
   if(qitingjian==0)//判断启停键是否按下
  {
    shumaguandisplay(qian,bai,shi,ge);//数码管显示函数做延时
   	if(qitingjian==0)//再次判断启停键是否按下
   {
   	 while(!qitingjian)//启停键释放
	 shumaguandisplay(qian,bai,shi,ge);//数码管显示函数
	 qitingnum++;//启停键按下数次变量先赋值再加加
	 qitingled=0;//开启停指示灯
	 if(qitingnum==2)//判断启停键按下数次变量是否为2
	{
	  qitingnum=0;//启停键按下数次变量归零
	  qitingled=1;//关启停指示灯
      zhengzhuanled=1;//关正转指示灯
      fanzhuanled=1;//关反转指示灯
      zhuansuled=1;//关转速指示灯
	  zhengzhuanflag=0;//正转标志位变量为0
	  fanzhuanflag=0;//反转标志位变量为0
	  IN1=0;//L298M芯片控制端IN1置低电平,电机不运转。
      IN2=0;//L298M芯片控制端IN2置低电平,电机不运转。
	  shumaguannodisplay(qian,bai,shi,ge);//数码管无显示函数
	 }
    }
   }
   if(qitingnum==1)//判断启停键是否第一次按下
  { 	
	if(zhengzhuan==0)//判断是否按下正转键
   {
     shumaguandisplay(qian,bai,shi,ge);//数码管显示函数做延时
	 if(zhengzhuan==0)//再次判断是否按下正转
	{
	  while(!zhengzhuan)//正转键释放
	  shumaguandisplay(qian,bai,shi,ge);//数码管显示函数做延时
	  zhengzhuanled=0;//开正转指示灯
	  fanzhuanled=1;//关反转指示灯
	  zhengzhuanflag=1;//正转标志位变量为1
	  fanzhuanflag=0;//反转标志位变量为0
	  IN1=1;//L298N芯片控制端IN1置高电平
	  IN2=0;//L298N芯片控制端IN2置低电平
	 }
    }
	if(fanzhuan==0)//判断是否按下反转键
   {
	 shumaguandisplay(qian,bai,shi,ge);//数码管显示函数做延时
     if(fanzhuan==0)//再次判断是否按下反转键
    {
      while(!fanzhuan)//反转键释放
	  shumaguandisplay(qian,bai,shi,ge);//数码管显示函数做延时
	  zhengzhuanled=1;//关正转指示灯
	  fanzhuanled=0;//开反转指示灯
	  zhengzhuanflag=0;//正转标志位变量为0
	  fanzhuanflag=1;//反转标志位变量为1
	  IN1=0;//L298N芯片控制端IN1置低电平
	  IN2=1;//L298N芯片控制端IN2置高电平
     }
    }
   }
    if(zhengzhuanflag==1||fanzhuanflag==1)//判断电机是否为正转或反转
   {
	 if(jiasujian==0)//判断是否按下加速键
    {
	  shumaguandisplay(qian,bai,shi,ge);//数码管显示函数做延时
      if(jiasujian==0)//再次判断是否按下加速键
     {
 	   while(!jiasujian)//加速键释放
	   shumaguandisplay(qian,bai,shi,ge);//数码管显示函数做延时
       if(pwm < 20)//判断脉冲宽度调制变量是否小于20
	   pwm++;//脉冲宽度调制变量先赋值再加加 
       if(pwm >= 20)//判断脉冲宽度调制变量是否大于等于20
       pwm = 19;//脉冲宽度调制变量等于20                                  
      }
     }
     if(jiansujian==0) //判断是否按下减速键
    {
	  shumaguandisplay(qian,bai,shi,ge);//数码管显示函数做延时
      if(jiansujian==0)//再次判断是否按下减键
     {
	   while(!jiansujian)//减速键释放
	   shumaguandisplay(qian,bai,shi,ge);//数码管显示函数做延时
       if(pwm > 0)//判断脉冲宽度调制变量是否大于0
	   pwm--;//脉冲宽度调制变量先赋值再减减 
       if(pwm <= 0)//判断脉冲宽度调制变量是否小于等于0
       pwm = 0;//脉冲宽度调制变量等于0 
      }
     }
	}
   }
  void shumaguandisplay(uint qian,uint bai,uint shi,uint ge)//数码管显示函数
{
   duan=1;//开数码管段码端口                      
   P0=table[qian];//数码千位显示
   duan=0;//关数码管段码端口
   P0=0x00;//关数码管段码显示
   wei=1;//开数码管位码端口
   P2=weima[0];//第1位数码管显示
   wei=0;//关数码管位码端口
   delay(1);//延时
   
   duan=1;//开数码管段码端口                      
   P0=table[bai];//数码百位显示
   duan=0;//关数码管段码端口
   P0=0x00;//关数码管段码显示
   wei=1;//开数码管位码端口
   P2=weima[1];//第2位数码管显示
   wei=0;//关数码管位码端口
   delay(1);//延时

   duan=1;//开数码管段码端口                  
   P0=table[shi];//数码管十位显示
   duan=0;//关数码管段码端口
   P0=0x00;//关数码管段码显示
   wei=1;//开数码管位码端口
   P2=weima[2];//第3位数码管显示
   wei=0;//关数码管位码端口
   delay(1);//延时

   duan=1;//开数码管段码端口                        
   P0=table[ge];//数码管个位显示
   duan=0;//关数码管段码端口
   P0=0x00;//关数码管段码显示
   wei=1;//开数码管位码端口
   P2=weima[3];//第4位数码管显示
   wei=0;//关数码管位码端口
   delay(1);//延时     
 }
  void shumaguannodisplay(uint qian,uint bai,uint shi,uint ge)//数码管显示函数
{
   duan=1;//开数码管段码端口  
   P0=table[qian];//数码千位显示
   duan=1;//关数码管段码端口
   P0=0x00;//关数码管段码显示
   wei=1;//开数码管位码端口
   P2=weima[0];//第1位数码管显示
   wei=1;//关数码管位码端口
   delay(1);//延时
   
   duan=1;//开数码管段码端口                      
   P0=table[bai];//数码百位显示
   duan=1;//关数码管段码端口
   P0=0x00;//关数码管段码显示
   wei=1;//开数码管位码端口
   P2=weima[1];//第2位数码管显示
   wei=1;//关数码管位码端口
   delay(1);//延时

   duan=1;//开数码管段码端口                  
   P0=table[shi];//数码管十位显示
   duan=1;//关数码管段码端口
   P0=0x00;//关数码管段码显示
   wei=1;//开数码管位码端口
   P2=weima[2];//第3位数码管显示
   wei=1;//关数码管位码端口
   delay(1);//延时

   duan=1;//开数码管段码端口                        
   P0=table[ge];//数码管个位显示
   duan=1;//关数码管段码端口
   P0=0x00;//关数码管段码显示
   wei=1;//开数码管位码端口
   P2=weima[3];//第4位数码管显示
   wei=1;//关数码管位码端口
   delay(1);//延时     
 }

三、基于51单片机PWM(即脉冲宽度调制)调速数码管显示测速L298芯片控制直流电机正反运转项目的Proteus软件仿真单片机外围电路

在这里插入图片描述

四、基于51单片机PWM(即脉冲宽度调制)调速数码管显示测速L298芯片控制直流电机正反运转项目的操作功能描述

(1)、不修改时分秒个位十位数值,只是启动或停止计时的情况:如果第一次按下移位键,则停止计时,启动计时可按下移位键7次或按下启停键,再次停止计时可按下移位键或按下启停键,再次启动计时可按下移位键7次或按下启停键,周而复始。如果第一次按下启停键,则停止计时,启动计时可按下移位键7次或按下启停键,再次停止计时可按下移位键或按下启停键,再次启动计时可按下移位键7次或按下启停键,周而复始。

(2)、修改时分秒个位十位数值,再启动或停止计时的情况:要修改时分秒个位十位上的数值,再启动或停止计时,首先必须按下移位键,此时停止计时,通过点击移位键让LCD1602字符型液晶显示器光标移到时分秒相应个位十位数值上,利用点击增加键或减少键修改数值,修改完毕后,启动计时可按下移位键多次让LCD1602字符型液晶显示器光标回到秒钟个位数值上或按下启停键,停止计时可按下移位键或按下启停键,当按下移位键时,又可修改时分秒个位十位上的数值,再次启动计时可按下移位键多次让LCD1602字符型液晶显示器光标回到秒钟个位数值上或按下启停键,周而复始。

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值