51单片机控制步进电机

         将自己大学做的为数不多的编程学习进行记录,选修嵌入式之前,师兄提醒我这作业量大,还是选了,因为对编程有一种向往。差点挂掉这门课,每周要交作业,学习一到两个硬件知识,真的比想象中吃力,到最后还是顺利交完作业,通过了课程。这个课程正逢《流浪地球》热播,老师第一节课说了其中电影中有一点很真实:“没有硬件支撑和配合,程序不管用。”通过这个课程,确实了解到了硬件的重要性,以前看到的黑客电影一下子分为严谨和糊弄观众两种了。

  1. 使用Keil 4编写C语言程序,编译生成.hex文件,使用Proteus7.8进行仿真
  2.  

     

  3. 使用了51单片机,按键,电机等一系列硬件
  4. #include <reg52.h>
    #include <intrins.h>
    #include <string.h>
    #define uint unsigned int
    #define uchar unsigned char
    
    sbit IN1 = P1^0;
    sbit IN2 = P1^1;
    sbit ENA = P1^2;
    sbit RS = P2^5;
    sbit RW = P2^6;
    sbit EN = P2^7;    
    sbit k1 = P2^0;       //正转
    sbit k2 = P2^1;       //反转
    sbit k3 = P2^2;       //加速
    sbit k4 = P2^3;       //减速
    sbit k5 = P2^4;       //暂停
    sbit inter0    =P3^2;
    
    
    int g,s,b,q,t,e;                    //定义转速各位
    int m,n,num,PWM=100,PWMH=50;      
    int ZS=0,PWMH_1,PWMH_2,PWMH_3;        //转速
    
    uchar LCD_DSY_BUFFER1[]={"ZS 040 PWM 050%"};    //  buffer缓冲器 
    
    
    /*******************************************************************************
    * 函 数 名         : Timer0Init
    * 函数功能           : 定时器0初始化
    *******************************************************************************/
    void Timer0Init()
    {
        TMOD|=0X01;//选择为定时器0模式,工作方式1,仅用TR0打开启动。
        TH0=0XFC;    //给定时器赋初值,定时1ms
        TL0=0X18;    
        TR0=1;//打开定时器
        ET0=1;//打开定时器1中断允许
        EA=1;  //打开总中断            
    }
    
    /*******************************************************************************
    * 函 数 名         : Int1Init()
    * 函数功能           : 设置外部中断1
    *******************************************************************************/
    void Int0Init()       //设置INT0
    {
        
        IT0=1;//1-跳变沿出发方式(下降沿)0-低电平触发
        EX0=1;//打开INT0的中断允许。    
        EA=1;//打开总中断    
    }
    
    /*================测量转速,利用外部中断INT0和定时器T0,每1s计算一次============*/
     /*============定时器0 PWM输出,调节转速    ============*/
    
     void X0_time() interrupt 0      //外部中断0部分
     {
         inter0=0;
        m++;      //计算脉冲
        inter0=1;
     }
    
    //定时器T0中断部分
     void T0_time() interrupt 1     // interrupt 1 为定时器中断0; 0-外部中断0;  2-外部中断1;3-定时器1;4-串口 
     {
        TH0 = 0XFC;                   //      TH0=(65536-1000)/256;      定时1ms
        TL0 = 0x18;    
            
        num++;                       //这是计算溢出次数(脉冲宽度)
        t++;
    
        if(num>=100)                      //周期100ms,num=1 表示1ms
        num=0;
    
    
        if(num<=PWMH)
            ENA=1;                          //置高电平
        else    
            ENA=0;
    
    
            
        if(t==970)                           //1s时间到,计算转速      1000ms
        {
    
            ZS=m*60/24;               //一转2脉冲
            b=ZS%1000/100;
            s=ZS%100/10;
            g=ZS%10;                   
            ZS=m*60/2;                 
            m=0;        
            t=0;                 
        }
    
     }
    
    
    void delay(uchar z)        //延时0.5MS
    {    uchar y;
        for(z;z>0;z--)
             for(y=243;y>0;y--);
    }
    
    void keyscan()
    {
    
        if(k1==0)     //正转
        {
            e=1;
            while(!k1);
        }
        if(k2==0)    //反转
        {
            e=2;
            while(!k2);        
        }
    
         if(k3==0)     //加速
        {
            PWMH=PWMH+10;
            if(PWMH>=110)
            { PWMH=30; }
            while(!k3);
        }
        if(k4==0)    //减速
        {
            PWMH=PWMH-10;
            if(PWMH<=-10)
            { PWMH=30; }
            while(!k4);                    
        }
        if(k5==0)     //暂停、启动
        {
            e=0;
            while(!k5);
        }
        PWMH_1=PWMH/100;
        PWMH_2 =   PWMH    %100/10;
        PWMH_3    =PWMH%10;
    
    }                   
    
    /****************LCD显示部分********************/
    uchar Read_LCD_State()                    //    6  1602
    {
         uchar state;
        RS=0;RW=1;EN=1;delay(1);
        state=P0;
        EN = 0;delay(1);
        return state;
    }
    
    void LCD_Busy_Wait()                        // 7
    {
         while((Read_LCD_State()&0x80)==0x80);       //当最高位为1时,延时5秒
        delay(5);
    }
    
    void Write_LCD_Data(uchar dat)                 // 8
    {
         LCD_Busy_Wait();
        RS=1;RW=0;EN=0;P0=dat;EN=1;delay(1);EN=0;          //dat为
    }
    
    void Write_LCD_Command(uchar cmd)    // 9  command命令 控制
    {
         LCD_Busy_Wait();
        RS=0;RW=0;EN=0;P0=cmd;EN=1;delay(1);EN=0;         //cmd为地址
    }
    
    
    void Init_LCD()                                 //  10     初始化
    {
         Write_LCD_Command(0x38);           //显示16*2显示,5*7点阵,8位数据接口
        delay(1);                           
        Write_LCD_Command(0x01);           //显示清零,数据指针清零
        delay(1);    
        Write_LCD_Command(0x06);           //写一个字符后地址指针加一
        delay(1);    
        Write_LCD_Command(0x0c);            //设置开显示,不显示光标
        delay(1);    
    }
    
    void Set_LCD_POS(uchar p)                     // 11
    {
         Write_LCD_Command(p|0x80);      //
    }
    
    void Display_LCD_String(uchar p,uchar *s)        //12 在LCD显示    Display_LCD_String(0x00,LCD_DSY_BUFFER1);
    {
         uchar i;
        Set_LCD_POS(p);            //p为液晶屏地址0x00
        for(i=0;i<25;i++)
        {
            Write_LCD_Data(s[i]);
            delay(1);     
        }
    }
    
    void Display_LCD_String2(uchar p,uchar *s)        //12 在LCD显示
    {
         uchar i;
        Set_LCD_POS(p);            //p为液晶屏地址0x00
        for(i=0;i<16;i++)
        {
            Write_LCD_Data(s[i]);
            delay(1);     
        }     
    }
    
    void Format_Date(uchar d,uchar *a)            // 13  
    {     
        a[1]=d+'0';     //0’的ASCII值为48      
    }
    
    void main()
    {
        Timer0Init(); //初始化T0
        Int0Init();      //初始化外部中断
        Init_LCD();      
         while(1)
         {
             keyscan();
                  
            Format_Date(b,LCD_DSY_BUFFER1+2);    // 
            Format_Date(s,LCD_DSY_BUFFER1+3);   // 
            Format_Date(g,LCD_DSY_BUFFER1+4);    //
                
            Format_Date(PWMH_1,LCD_DSY_BUFFER1+10);
            Format_Date(PWMH_2,LCD_DSY_BUFFER1+11);
            Format_Date(PWMH_3,LCD_DSY_BUFFER1+12);
            Display_LCD_String(0x00,LCD_DSY_BUFFER1);
    
             if(e==0)
             {IN1=1;IN2=1;ENA=1;}
             if(e==1)
             {IN1=0;IN2=1;ENA=1;}
             if(e==2)
             {IN1=1;IN2=0;ENA=1;}         
         }
    }

     

  5. 难点是按键控制电机转速时使用PWM,将电机转速传递到液晶显示屏并显示
  6.  

     

  7. 每一次接触新的硬件,就要查它的相关信息,才能顺利编程,真是很宝贵的自己学习经历
posted @ 2020-07-23 11:49  何时悠长假期  Views(998)  Comments(0Edit  收藏  举报