×
单片机 > 单片机程序设计 > 详情

用Pic单片机控制8路MG995舵机(servo motor)的实现方法

发布时间:2020-05-29 发布时间:
|
 一个PIC16F877A单片机有1个16位定时器TIMER1,我们用来控制8个舵机(即顺序脉冲输出),这样一个单片机就可以控制8个舵机。用8个IO口来控制舵机,舵机控制的信号周期为20mS,而正脉冲最大只有2.5mS,这样有17.5mS是空的。可以采用这种方法:在RD0口输出一个0.5~2.5mS的脉冲,控制一号舵机。完成后,用端口RD1口输出另外一个脉冲,控制2号舵机,就这样下去.....在一号舵机需要第二个脉冲之前,可以输出 20/2.5=8个脉冲,可以用来控制8个舵机,当然,需要用8个IO口。但是一般来说不可能正好有8个2.5mS的脉冲来填满20mS,这样就需要对输出脉冲的总宽度进行累加补偿,然后再用低电平填满20mS中剩下的时间。一个周期让timer1工作8~9次,前8次每次根据不同舵机的脉宽要求进行定时,每次都对不同的IO口输出脉冲.第九个定时是用来填满20mS的剩余时间的. 每个口在输完脉冲后,置0 ,然后单片机就不用管他,可以进行下一个IO口的脉冲输出了. 这样一个单片机顺序对8个IO口进行脉冲输出.  虽然每个舵机的脉冲时间有一点延迟,但是不超过20mS,这对于舵机这种低速运行器件来说是完全感觉不出来的。仿真如下图:

下面就用这种方法进行编程。
#include
unsigned char servo_angle_H[8];
unsigned char servo_angle_L[8];

unsigned char compensate_TL;
unsigned char compensate_TH;
 
unsigned char p;

 
void set_servo  (unsigned char angle0,unsigned char angle1,
    unsigned char angle2,unsigned char angle3,
    unsigned char angle4,unsigned char angle5,
    unsigned char angle6,unsigned char angle7)
{
unsigned int temp,temp0,value[8];
unsigned char i;

for(i=0;i<8;i++){
  servo_angle_H[i]=64468/256;
  servo_angle_L[i]=64468%256; 
}
   
  compensate_TL=50268%256;   
  compensate_TH=50268/256;    

 temp = angle0+angle1+angle2+angle3+angle4+angle5+angle6+angle7;
value[0]=65068-(100*angle0)/9;
value[1]=65068-(100*angle1)/9;
value[2]=65068-(100*angle2)/9;
value[3]=65068-(100*angle3)/9;
value[4]=65068-(100*angle4)/9;
value[5]=65068-(100*angle5)/9;
value[6]=65068-(100*angle6)/9;
value[7]=65068-(100*angle7)/9;
for(i=0;i<8;i++){
  servo_angle_H[i]=value[i]/256; 
  servo_angle_L[i]=value[i]%256;

 

  temp0=46068+(100*temp)/9;   
  compensate_TL=temp0%256;   
  compensate_TH=temp0/256;
 

}
//主程序***********************************************************************
void main(void) 
{unsigned int a;unsigned int b;
 INTCON=0;
 GIE=1;//  ;打开总中断
 PEIE=1;//  ;打开外部中断使能位
 TMR1IE=1;//  ;打开TMR1中断
 
 TRISD=0X00;
 PORTD= 0X00;//脉冲波形起始状态 
 T1CON=0x01;//设置TMR1的控制字 
 
 TMR1IF=0;  

unsigned char i;


set_servo  (13,34,56,87,80,123,156,13);
while(1){; }
 
}
//中断服务程序*************************************************************
void  interrupt timer1(void)  
{
 TMR1IF=~TMR1IF;
 
switch(p){
 case 0: TMR1L=servo_angle_L[p];TMR1H=servo_angle_H[p];PORTD=0X01;
 break;
 case 1: TMR1L=servo_angle_L[p];TMR1H=servo_angle_H[p];PORTD=0B00000010;
 break;
 case 2: TMR1L=servo_angle_L[p];TMR1H=servo_angle_H[p];PORTD=0B00000100;
 break;
 case 3: TMR1L=servo_angle_L[p];TMR1H=servo_angle_H[p];PORTD=0B00001000;
 break; 
 case 4: TMR1L=servo_angle_L[p];TMR1H=servo_angle_H[p];PORTD=0B00010000;
 break;
 case 5: TMR1L=servo_angle_L[p];TMR1H=servo_angle_H[p];PORTD=0B00100000;
 break;
 case 6: TMR1L=servo_angle_L[p];TMR1H=servo_angle_H[p];PORTD=0B01000000;
 break;
 case 7: TMR1L=servo_angle_L[p];TMR1H=servo_angle_H[p];PORTD=0B10000000;
 break;
 default:TMR1L=compensate_TL;TMR1H=compensate_TH;PORTD=0B00000000;p=0;
 break;
  }
 p++;
}



『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
51单片机CO2检测显示程序解析