本设计以单片机AT89C51为核心,通过软件编程利用其定时器产生PWM信号从而实现对直流电机转速控制。硬件设计主要包括按键电路模块、电机驱动模块、测速模块和转速显示模块。其中采用独立式键盘通过按键将命令输入到单片机,改变PWM信号占空比,再将单片机输出的信号通过光电耦合器和由IGBT组成的H型桥式功率放大驱动电路,根据不同占空比的PWM信号达到电机启停、正反转和加减速控制。测速模块采用非接触式的霍尔传感器对直流电机的转速进行测量,将测得的转速传送到单片,再通过LCD显示出来。本论文主要介绍了直流电机调速系统的原理和方案设计,单片机如何产生PWM信号,H桥驱动电路设计,硬件电路图的设计与连接,实现功能的流程图和程序,系统的仿真和调试。

单片机程序源码:
#include <reg52.h>
  • #define uchar unsigned char
  • #define uint unsigned int
  • void displaym();
  • sbit en=P2^5;                //1602  6管脚
  • sbit rs=P2^7;         //1602端口        4管脚
  • sbit rw=P2^6;//lcd1602控制端口 5管脚
  • sbit num1=P1^0;                                                //占空比加1
  • sbit num2=P1^1;                                                                   //占空比减一
  • sbit num3=P1^2;                                                                                           //正传
  • sbit num4=P1^3;                                                                                                         //反转
  • sbit num5=P1^4;                                                                                                                   //开始停止切换
  • sbit out=P3^4;                                                         //PWM输出用于正传
  • sbit out1=P3^7;                        //PWM输出用于反转
  • uint zhuansu,flag,z1,z2,m,flag_1,zheng,fan,kai;
  • void delay(uint z)//延时1ms函数
  • {
  • uint x,y;
  • for(x=0;x<z;x++)
  •      for(y=0;y<110;y++);
  • }
  • void write_com(uchar com)//向1602写一字节(控制指令)
  • {
  •   rs=0;
  •   P0=com;
  •   delay(5);
  •   en=0;
  •   delay(10);
  •   en=1;
  • }
  • void write_data(uchar date)//向1602写一字节(数据)
  • {
  •   rs=1;
  •   P0=date;
  •   delay(5);
  •   en=0;
  •   delay(5);
  •   en=1;
  • }
  • void init()//初始化函数
  • {
  •   en=0;
  •   rw=0;
  •   write_com(0x01);         //lcd初始化
  •   write_com(0x38);                                           //5X7显示
  •   write_com(0x0c);                         //关闭光标
  •   TMOD=0x01;               //定时器方式1           
  •   TH0=0xdc;
  •   TL0=0x00;                //定时器装入初值
  •   EA=1;                    //开总中断
  •   ET0=1;                   //定时器0开中断
  •   TR0=1;
  •   EX1=1;
  • IT1=1;                 //定时器启动  
  • TH1=0xfc;
  •   TL1=0x66;//定时100us
  •   ET1=1;                   //定时器1开中断
  •   TR1=1;
  •   write_com(0x80);
  •   write_data('V');
  •   write_data(':');
  •   write_com(0x87);                 //第一行显示转速
  •   write_data('r');
  •   write_data('p');
  •   write_data('m');
  •   write_com(0xc0);
  •   write_data('z');
  •   write_data('h');
  •   write_data('a');
  •   write_data('n');
  •   write_data('k');
  •   write_data('o');
  •   write_data('n');
  •   write_data('g');
  •   write_data('b');
  •   write_data('i');          //在第二行显示zhankongbi:
  •   write_data(':');
  •   displaym();
  • }
  • void keyscan()  //键盘扫描函数
  • {
  •   if(num1==0)     
  •   {
  •     delay(5);      //消除抖动
  •          if(num1==0)
  •          {
  •                 if(m<=199)
  •                  m++;
  •                         displaym();                                                                  //设定占空比加一
  •      }
  •   }
  •   if(num2==0)
  •   {
  •     delay(5);
  •          if(num2==0)
  •          {
  •                   if(m>=1)
  •                 m--;
  •                         displaym();                                        //设定占空比减一
  •         
  •          }
  •   }
  •     if(num3==0)
  •   {
  •     delay(5);
  •          if(num3==0)
  •          {
  •           zheng=1;                //正传标志置1
  •           fan=0;          // 反转标志置0
  •         
  •          }
  •   }
  •       if(num4==0)
  •   {
  •     delay(5);
  •          if(num4==0)
  •          {
  •           zheng=0;                 //正传标志置0
  •           fan=1;          // 反转标志置1
  •         
  •          }
  •   }
  •       if(num5==0)
  •   {
  •     delay(5);
  •          if(num5==0)
  •          {
  •          while(num5==0)         ;
  •           kai=1-kai;
  •          }
  •   }
  • }
  • void display()
  • {
  •   write_com(0x82);
  •   zhuansu=zhuansu*30;          //将两秒内的计数乘以30得到转每分
  •   if(zhuansu/10000!=0)
  •    write_data(zhuansu/10000+0x30);                                                  //如果转速的万位不为0        正常显示否则显示空格
  •    else
  •    write_data(' ');
  •   if(zhuansu/1000==0)
  •   write_data(' ');
  •   else
  •   write_data(zhuansu%10000%1000+0x30);                                                                //如果转速小于1000 千位为空格 否则正常显示
  •   
  •   if(zhuansu/100==0)
  •   write_data(' ');
  •   else
  •   write_data(zhuansu%10000%1000/100+0x30);                                           //如果转速小于100 百位为空格 否则正常显示
  •     if(zhuansu/10==0)
  •   write_data(' ');
  •   else
  •   write_data(zhuansu%10000%1000%100/10+0x30);                                  //如果转速小于10 十位为空格 否则正常显示
  •   write_data(zhuansu%10000%1000%100%10+0x30);
  •   write_com(0xd0);                          //如果没有这句,当中断内的显示函数执行完,就会在转速的位置显示占空比数据,导致乱码
  • }
  • void displaym()
  • {
  • write_com(0xcb);
  •    if(m/200%10!=0)
  •   write_data(m/200%10+0x30);                           //如果占空比百位不为0则显示百位否则显示空格
  •   else
  •   write_data(' ');
  •   
  •   if(m/200%10==0&&m/20%10==0)
  •   write_data(' ');
  •   else
  •   write_data(m/20%10+0x30);                                 //如果占空比小于10 十位正常显示  否则显示空格
  •   
  •   write_data(m/2%10+0x30);                                 //显示个位
  • }
  • void main()
  • {
  •     flag_1=0;
  •         m=100;                                                         //占空比为100
  •         zhuansu=0;                                           //转速初值0
  •         flag=0;
  •         zheng=1;                                  //初始化电机正转动
  •         fan=0;
  •     init();              //初始化
  •         while(1)
  •         {
  •         keyscan();                                //键盘扫描程序
  •          
  •         }
  • }
  • void int1()interrupt 2                                //外部中断1脉冲技术记录电机的转速 电机转一圈zhuansu加一
  • {
  •   zhuansu++;
  • }
  • void int2()interrupt 3                                  //定时器0显示转速
  • {
  •   TH0=0xdc;
  •   TL0=0x00;//定时10ms
  •   flag++;
  •          
  •   if(flag==200)                                   //计时到达2s
  •     {
  •         display();                                        //显示转速
  •         zhuansu=0;                                          //转速置0
  •         flag=0;
  •         }
  • }
  • void int3()interrupt 1                                         //产生PWM
  • {
  •   
  •   TH1=0xff;
  •   TL1=0x00;//定时100us
  •   
  •           flag_1++;
  •         if(flag_1>199)
  •         flag_1=1;
  •         if(kai==1)                  //如果kai==1电机启动
  •         {
  •         if(zheng==1)                                //电机正转
  •         {
  •         if(flag_1<m)                                          //小于占空比m输出PWM=0输出电压为1
  •      {out=0;
  •          out1=1;}
  •          else
  •          {
  •            out=1;
  •            out1=1;
  •          }
  •          }
  •                  if(fan==1)                           //电机反转
  •         {
  •         if(flag_1<m)                                //小于占空比m输出PWM=0输出电压为1
  •           {
  •             out=1;
  •                 out1=0;
  •           }
  •          else                                                                         //大于m输出PWM=1输出电压为0
  •           {
  •             out=1;
  •                 out1=1;
  •           }
  •          }
  •          }
  •          if(kai==0)                          //kai=0电机停止转动
  •          {
  •            out=1;
  •            out1=1;
  •          
  •          }
  • }
  • 复制代码