實現硬件PWM控制電機旋轉和經過編碼器計算所轉圈數的簡單例程

 

 

該例程所用的硬件設備:算法

直流電機驅動模塊YYH-LWZ: H橋 大功率 正反轉 剎車 PWM 調速 5/12/24Vide

12V直流減速電機JGB37-520B:ASLONG JGB37-520B編碼器減速電機直流減速馬達A/B相碼盤信號測速    帶編碼器 A/B相輸出 噪音小函數

芯片:IAP15w4k58s4編碼

電機控制:

因該電機驅動模塊沒法直接經過單片機的IO口位的拉高,拉低來控制,故用PWM來控制。軟件模擬PWM不夠穩定快速,故採用硬件PWM,然而硬件PWM只可以使用IAP15w4k58s4芯片固定的PWM輸出IO口,來輸出PWM波形:spa

P0.6/P0.7/P1.6/P1.7/P2.1/P2.2
P2.3/P2.7/P3.7/P4.2/P4.4/P4.5code

芯片資料:http://www.stcmcudata.com/datasheet/stc/STC-AD-PDF/STC15.pdf(要用自取)blog

 

PWM波形輸入到電機驅動模塊的IO口後,被MOC管放大,在輸出到電機電源線it

 

硬件PWM的PWM.C程序以下:io

 

#include "STC15W.H"        //單片機頭文件
#include "Uart.h"
#include "PWM.h"


/*系統晶振頻率爲28Mhz ,PWM輸出信號頻率爲20khz之內*/
//參考stc15系列單片機指南1056頁,  

 void PWM_Init(void)
{ 
   P_SW2 |= 0x80; 
   PWMCFG = 0x00;                  //PWM的輸出初始電平爲低電平
   PWMCKS = 0x0f;                  //PWM的時鐘爲Fosc/(0+1)
   PWMC = CYCLE;                   //PWM週期,定義PWM週期(最大值爲32767)

   PWM2CR = 0x00;                  //PWM2波形輸出到P37,不使能PWM2中斷   
   PWM3CR = 0x00;                  //PWM3波形輸出到P21,不使能PWM3中斷  
   PWM4CR = 0x00;                  //PWM4波形輸出到P22,不使能PWM4中斷  
   PWM5CR = 0x00;                  //PWM5波形輸出到P23,不使能PWM5中斷  

   PWM2T1 = 0x0001;               
   PWM2T2 = 0; 
           
   PWM3T1 = 0x0001;               
   PWM3T2 = 0;
            
   PWM4T1 = 0x0001;               
   PWM4T2 = 0;
            
   PWM5T1 = 0x0001;               
   PWM5T2 = 0;
    
   PWMCR |= 0x80;                  //使能PWM模塊
   P_SW2 &=~0x80; 
}
void  IN_1( unsigned int DUTY)           //PWM2
{   
        if(DUTY==0)                         //經過DUTY來控制佔空比,進而控制PWM輸出電壓,最終實現轉速的變化
        {
           PWMCR &=~0x01;
           PWM2=0; 
        }
        else if(DUTY==100)
        {
           PWMCR &=~0x01;
           PWM2=1; 
        }
        else
        {
           P_SW2 |= 0x80;                  //使能訪問PWM在擴展RAM區的特殊功能寄存器XSFR
           PWM2T1 = 0x0001;                //設置PWM2第1次反轉的PWM計數
           PWM2T2 = CYCLE * DUTY / 100;    //設置PWM2第2次反轉的PWM計數
           P_SW2 &=~0x80;                  //佔空比爲(PWM2T2-PWM2T1)/PWMC
           PWMCR |= 0x01;                  //使能PWM信號輸出

        }

}
void IN_2(unsigned int DUTY)                //PWM3
{         
        if(DUTY==0)
        {
           PWMCR &=~0x02;
           PWM3=0; 
        }
        else if(DUTY==100)
        {
           PWMCR &=~0x02;
           PWM3=1; 
        }        
        else
        { 
           P_SW2 |= 0x80;          
           PWM3T1 = 0x0001;                
           PWM3T2 = CYCLE * DUTY / 100;                                     
           P_SW2 &=~0x80;                 
           PWMCR |= 0x02;                   

        }        
}
void IN_3(unsigned int  DUTY)                  //PWM4
{         
         if(DUTY==0)
        {
          PWMCR &=~0x04;
          PWM4=0; 
        }
        else if (DUTY==100)
        {
          PWMCR &=~0x04;
          PWM4=1; 
        }
        else
        {         
          P_SW2 |= 0x80;                 
          PWM4T1 = 0x0001;               
          PWM4T2 = CYCLE * DUTY / 100;                                
          P_SW2 &=~0x80;                  
          PWMCR |= 0x04;                   

        }
}


void IN_4(unsigned int  DUTY)                  //PWM5
{         
         if(DUTY==0)
        {
           PWMCR &=~0x08;
           PWM5=0; 
        }
        else if (DUTY==100)
        {
           PWMCR &=~0x08;
           PWM5=1; 
        }
        else
        {         
           P_SW2 |= 0x80;                 
           PWM5T1 = 0x0001;               
           PWM5T2 = CYCLE * DUTY / 100;                                
           P_SW2 &=~0x80;                  
           PWMCR |= 0x08;                   

        }
}


//功能:電機驅動模塊的輸入端口控制函數   
void IN_SetPwm(int wide_1,int wide_2,int wide_3,int wide_4,int uDir)
{
   if(uDir==1)
   {
     IN_1(wide_1);
     IN_2(wide_2);
     IN_3(wide_3);
     IN_4(wide_4);
   }
}

 

 硬件PWM的PWM.h程序以下:ast

#ifndef _PWM_H_
#define _PWM_H_

#include "STC15W.H"    


 //芯片晶振頻率設置爲28mhz

#define CYCLE   0x6500L     //定義PWM週期(最大值爲32767)
        
sbit PWM2=P3^7;                                         
sbit PWM3=P2^1;                                           
sbit PWM4=P2^2;                                        
sbit PWM5=P2^3;



extern void PWM_Init(void);extern void IN_SetPwm(int wide_1,int wide_2,int wide_3,int wide_4,int uDir);


 #endif

 

 編碼器計數:

 

該電機自帶的編碼器爲A/B相霍爾計數編碼器,根據編碼器的旋轉產生A,B相的不一樣方波,每有A相的4個方波,編碼器轉了90度,轉一圈故有12個方波信號。根據旋轉方向的不一樣,A波產生的上升降低沿時,B波同時刻處於不一樣的電平。電機輸出軸轉一圈的時間內,根據電機的轉速,減速比和PWM的頻率不一樣,編碼器所轉的圈數是不固定的,要精確計數要使用算法,該例程只是前提量不變的估量值。

編碼器的encoder.c程序:

#include "STC15W.H"        //單片機頭文件
#include "Uart.h"
#include "encoder.h"
#include "center.h"

unsigned char Last_io=0;     
unsigned char Curr_io=0;



 //編碼器結構體的初始化
void Encoder_Init(Encoder_HandleTypeDef * encoder)
{
    encoder-> zheng_count =0;
    encoder-> fan_count   =0;
    encoder-> end_count   =0;

}




void Delay50us()        //@28MHz
{
    unsigned char i, j;

    i = 2;
    j = 89;
    do
    {
        while (--j);
    } while (--i);
}




 void Initial_INT0(void)      //用外部中斷來實現A波的觸發
{    
       
    IT0=0;      // 設置成上升沿和降低沿均觸發  
    EX0=1;      //使能INT0中斷
    EA=1;   
    
}

int exint0() interrupt 0  //外部中斷入口

{  
    Delay50us();    
    if(PIN_A==1)          //上升沿觸發
    {   
     
      Curr_io=PIN_B;      //記錄PIN_B的觸發信號
        
    }
    else if(PIN_A==0)     //降低沿觸發
    {   
     
      Last_io=PIN_B;      //記錄PIN_B的觸發信號
           
        
    }

}


//掃描編碼器的計數
void scan_encoder(Encoder_HandleTypeDef *encoder)
{
   

        if((Curr_io==1)&&(Last_io==0))       //編碼器逆時針旋轉時,A波上升沿時,B波爲1,A波降低沿時,B波爲0;
        {
             
             encoder->zheng_count++;         //每有12個判斷信號,編碼器轉一圈

             SendString(" 證 轉 \n");     

             Curr_io=0;                         // 判斷信號置0,若是不置0會有偏差
             Last_io=0;    
    
        }
       if((Curr_io==0)&&(Last_io==1))        //編碼器順時針旋轉時,A波上升沿時,B波爲0,A波降低沿時,B波爲1;
       {
       
             encoder->fan_count++;             //每有12個判斷信號,編碼器轉一圈

             SendString(" 反 轉  \n");
                                      
             Curr_io=0;                         // 判斷信號置0
             Last_io=0;    
            
        }    
   
    if(encoder->zheng_count==360*15)         //當編碼器所轉圈數到達必定數量時,電機的輸出軸轉一圈,該數字爲估量值
    {
          
        //  SendString("輸出軸 證 轉 了 一  圈\n");      
          
          encoder->zheng_count=0;

          encoder->end_count++;
          
    }    
    if(encoder->fan_count==360*15)
    {
          
     //       SendString("輸出軸 反 轉 了 一  圈\n");          
         
         encoder->fan_count=0;
         
         encoder->end_count++;                  
         
    }    
    
         
}

編碼器的encoder.h程序:

#ifndef _ENCODER_H_
#define _ENCODER_H_

#include "STC15W.H"    

 sbit PIN_B=P4^1;               //B相接P41
 sbit PIN_A=P3^2;               //A相接外部中斷使能端口P41




 typedef struct Encoder         //編碼器結構體
{

  unsigned int zheng_count;     //編碼器正轉圈數            
  unsigned int fan_count;       //編碼器反轉圈數
  unsigned int end_count;       //輸出軸已轉圈數
      
}Encoder_HandleTypeDef;          


extern void scan_encoder(Encoder_HandleTypeDef *motor);
extern void Encoder_Init(Encoder_HandleTypeDef * encoder);
extern void Initial_INT0(void);


 #endif

電機控制:

控制電機正轉或反轉,並旋轉指定圈數

控制電機的motor.c程序 

 

#include "STC15W.H"        //單片機頭文件
#include "Uart.h"
#include "encoder.h"
#include "PWM.h"
#include"motoc.h"




void Motor_Init(Motor_HandleTypeDef *motor)
{
       
    motor->H_PWM       =0;
    motor->L_PWM       =0;
    motor->number       =0;
    motor->flag           =1;
}

                                                                                   
void Motor_Start(Motor_HandleTypeDef *motor,int tack)                            //啓動電機
{                                                                            
   motor->H_PWM=20;                                                                //佔空比恆爲20%
   if(tack==1)
   {

        IN_SetPwm(motor->H_PWM, motor->L_PWM, motor->L_PWM, motor->H_PWM,1);    //MOC管顯示爲 (1 0 0 1)     電機正轉
        
   }
   if(tack==2)
   {
    
        IN_SetPwm(motor->L_PWM, motor->H_PWM, motor->H_PWM, motor->L_PWM,1);    //MOC管顯示爲 (0 1 1 0)     電機反轉
    
   }

}

void Motor_Stop(Motor_HandleTypeDef *motor,int tack)                            //關閉電機
{ 
   motor->H_PWM=0;
   if(tack==1)
   {       
         
        IN_SetPwm(motor->H_PWM,motor->H_PWM,motor->L_PWM,motor->L_PWM,1);        //MOC管顯示爲 (0 0 0 0)     電機剎車
   }
   if(tack==2)
   {
        
        IN_SetPwm(motor->L_PWM,motor->L_PWM,motor->H_PWM,motor->H_PWM,1);        //MOC管顯示爲 (0 0 0 0)     電機剎車
   }
}


//電機開關函數
void Motor_key(Motor_HandleTypeDef *motor)

{
       if( motor->flag==0)
    {
        motor->flag=1; 
    }


}



//tack:電機方向       count:目的圈數
void Motor_control(Motor_HandleTypeDef *motor,Encoder_HandleTypeDef * encoder,int tack,int count)
{
 
       if(motor->flag==1)                         //flag=1時,電機才能運行
       {
         Motor_Start(motor,tack);                 //啓動電機

         motor->number=encoder->end_count ;

         if(motor->number >= count)                 //當輸出軸轉的圈數到達目的圈數時,中止旋轉
         {
             Motor_Stop(motor,tack);             //關閉電機

             encoder->end_count=0;                 //編碼器圈數置0

             motor->flag=0;                         //flag=0

             motor->number=0;                     //電機圈數置0
         }

       }
}

 

 

 控制電機的motor.h程序

#ifndef _MOTOR_H_
#define _MOTOR_H_

#include "STC15W.H"    

                                   

typedef struct Motor          //電機結構體
{
 
  int L_PWM;                 //PWM低電位
  int H_PWM;                 //PWM高電位
  int number;                 //電機已轉圈數
  int flag;                     //電機開關
                     
}Motor_HandleTypeDef;



 extern  void Motor_Init(Motor_HandleTypeDef  *motor);
 extern  void Motor_key(Motor_HandleTypeDef *motor);
 extern  void Motor_Start(Motor_HandleTypeDef *motor,int tack);
 extern  void Motor_Stop(Motor_HandleTypeDef *motor,int tack);
 extern  void Motor_control(Motor_HandleTypeDef *motor,Encoder_HandleTypeDef * encoder,int tack,int count);

 

主函void main()

{ Motor_HandleTypeDef motor; Encoder_HandleTypeDef encoder; STC15W_IOinit(); //單片機初始化 
   Core_Init_Uart();         //串口初始化
   PWM_Init();               //PWM初始化
   Encoder_Init(&encoder);   //編碼器初始化
   Motor_Init(&motor);       //電機初始化
   Initial_INT0();           //外部中斷初始化



    while(1) { Motor_control(&motor,&encoder,1,5); scan_encoder(&encoder);  } }

結語

只不過一個簡簡單單的控制電機和計算圈數的程序,就前先後後花了我兩個多星期的業餘時間。如今看來,單片機有不少硬件功能是我瞭解不足的,差很少是從零開始寫的。學不以至用不可取以。指望對後來者有參考幫助。

看官們以爲好,有用就給個推薦,若是何處不足,有錯請大方留言指出。

謝謝瀏覽。

相關文章
相關標籤/搜索