强者归来 发表于 2012-10-14 18:09:01

控制舵机的多路PWM波 最多可以达到32路

本帖最后由 强者归来 于 2012-10-14 18:16 编辑

    最经需要做个仿生六足机器人,选择ATmega16做控制,需要产生18路完全独立的PWM波。产生PWM波有很多方法,Atmega16片设就有PWM模块,但是由于产生计时器0和计时器2产生的PWM波的频率和晶振的大小有关系,大概是除一个数和分频数,所以,要得到50Hz的控制舵机的PWM不可能,不过,计时器1可以产生产生频率和相位都改变的PWM波,不过,由于只有两个比较寄存器,所以,最多只能出两路,而且是在固定的OC1A和OC1B产生,不够用。下面简单介绍一下几种不同的PWM波产生的方法,大概有三种方法产生多路PWM波。
   第一种,是我自己采用的,最多可以产生32路(所以IO口都用上)。舵机控制是用50HZ的脉冲控制的,50HZ,周期即20ms,这是,你可以将这20ms分为若干份,分得越多,精确度就越高,假设你打算分为300份(晶振越高,可以选择大些)。这是,你可以选择用一定时器,也可以用两个定时器,我选择用两个定时器。计时器0每个20ms中断一次,另一个20/N ms中断一次,在函数里设一个全局变量count ,每一个20/N ms中断里,count加一,要输出的PWM波的占空比的就是与count比,当小于count时,选择任意端口(最多32)置1,大于count时,选择置0,这样就可以产生从不同占空比的PWM波。关键在于理解count与要求的PWM占空比比较的理解,你可以这样理解,20ms,最多N份,你可以选择从0份到N份置1,到是w份时,所得的PWM波的占空比就是w/N。讲不清楚,直接上程序吧。
#include <iom16.h>
#include <intrinsics.h>
#include <iom16.inc>
#include <iomacro.h>
#include <stdio.h>
#define uchar unsigned char
#define uint unsigned int
#define PWM11 PORTA_Bit0//用两位数定义18个舵机
#define PWM12 PORTA_Bit1
#define PWM13 PORTA_Bit2
#define PWM21 PORTA_Bit3
#define PWM22 PORTA_Bit4
#define PWM23 PORTA_Bit5
#define PWM31 PORTA_Bit6
#define PWM32 PORTA_Bit7
#define PWM33 PORTD_Bit0
#define PWM41 PORTD_Bit1
#define PWM42 PORTD_Bit2
#define PWM43 PORTD_Bit3
#define PWM51 PORTD_Bit4
#define PWM52 PORTD_Bit5
#define PWM53 PORTD_Bit6
#define PWM61 PORTD_Bit7
#define PWM62 PORTC_Bit0
#define PWM63 PORTC_Bit1
void timer0_init(void);
void timer1_init(void);
void port_init(void);   
void init(void);   

voidQuickprepare(void);
void delay_ms(uint k);
void forward_go(void);
void hop_round(void);//         下面几个是不同的动作函数我在最下面贴了一个back_go的函数
void hello(void);
void back_go(void);
uchar scan_key(void);
void turn(void);
void fly(void);
void low(void);
void game_over(void);
void right_round(void);
void left_round(void);
uchar pwm11,pwm12,pwm13,pwm21,pwm22,pwm23,pwm31,pwm32,pwm33,pwm41,pwm42,pwm43,pwm51,pwm52,pwm53,pwm61,pwm62,pwm63; //分别18个pwm的值
uchar count=0;      

void main(void)   
{
      uchar keycode;
      init(); //初始化
    Quickprepare();//舵机初始复位
   
    while(1)//该不同的端口设定不同占空比的pwm波
   {      

   
   back_go();
               
      }
   }

}
void init(void)   
{   
    SREG_Bit7=0; //中断停止   
    port_init();// 端口初始化
    timer0_init();//计时器0初始化
    timer1_init();//计时器1初始化
    SREG_Bit7=1; //中断启用   
}   

void port_init(void)   
{
   DDRA = 0xFF;
   PORTA = 0x00;
   DDRD = 0xFF;   
   PORTD = 0x00;   
   DDRC = 0x3;
   PORTC = 0x00;


}   
void timer0_init(void)         //定时器0初始化程序 (产生20ms的周期)
{   
   TIMSK|=(1<<OCIE0);
   TCCR0|=(1<<WGM01);
   OCR0=233;
   TCCR0|=(1<<CS00)|(1<<CS02);//      初始化函数里计时器0开始计数}   
void timer1_init(void)         //定时器1初始化程序   
{   
   TIMSK|= (1<<OCIE1A); //定时器中断源   
   TCCR1B|= (1<<WGM12); //CTC模式
   OCR1A = 99;      /////////////////////注意初始时计时器1不要开始计数不要开始计数要到计时器0的中断函数里开始计数(产生20/Nms周期)


}   

#pragma vector= TIMER0_COMP_vect
__interrupt void timer0_compa_isr(void)
{   
    TCCR1B|= (1<<WGM12); //CTC模式
    TIMSK|= (1<<OCIE1A); //定时器中断源   
    OCR1A = 99;
    TCCR1B|=(1<<CS11);//计数器1经过8分频开始计时
    count=0;
}


//下面就是计时器0每个中断里比较输出函数



#pragma vector=TIMER1_COMPA_vect   
__interrupt void timer1_compa_isr(void)
{   
                     
    count++;      //每中断一次加1   
if (count<pwm11)   
    {   
   PWM11=1;   
    }
    else
    {   
      PWM11=0;   
    }   
if (count<pwm12)   
    {   
      PWM12=1;   
    }
    else
    {   
      PWM12=0;   
    }   
if (count<pwm13)   
    {   
      PWM13=1;   
    }
    else
    {   
      PWM13=0;
    }   
if (count<pwm21)   
    {   
      PWM21=1;   
    }
else
    {   
      PWM21=0;
    }   
if (count<pwm22)   
    {   
      PWM22=1;   
    }
else
    {   
      PWM22=0;   
    }   
if (count<pwm23)   
    {   
      PWM23=1;   
    }
else
    {   
      PWM23=0;   
    }   
if (count<pwm31)   
    {   
      PWM31=1;   
    }
else
    {   
      PWM31=0;   
    }   
if (count<pwm32)   
    {   
      PWM32=1;   
    }
else
    {   
      PWM32=0;   
    }   
if (count<pwm33)   
    {   
      PWM33=1;   
    }
else
    {   
      PWM33=0;   
    }   
if (count<pwm41)   
    {   
      PWM41=1;   
    }
    else
    {   
   PWM41=0;   
    }   
   if (count<pwm42)   
    {   
      PWM42=1;   
    }
    else
    {   
      PWM42=0;   
    }   
   if (count<pwm43)   
    {   
      PWM43=1;   
    }
    else
    {   
      PWM43=0;   
    }   
if (count<pwm51)   
    {   
      PWM51=1;   
    }
    else
    {   
      PWM51=0;   
    }   
if (count<pwm52)   
    {   
      PWM52=1;   
    }
    else
    {   
      PWM52=0;   
    }   
   if (count<pwm53)   
    {   
      PWM53=1;   
    }
    else
    {   
      PWM53=0;   
    }   
if (count<pwm61)   
    {   
      PWM61=1;   
    }
    else
    {   
      PWM61=0;   
    }   
if (count<pwm62)   
    {   
      PWM62=1;   
    }
    else
    {   
      PWM62=0;   
    }   
if (count<pwm63)   
    {   
      PWM63=1;   
    }
    else
    {   
      PWM63=0;   
    }   
   
   if(count>=37) //2.5ms脉冲后停止计数 等待到下一个20ms
   {
      TCCR1B&=~(1<<CS11);//停止计时
   }
}
   

void delay_ms(uint k)

b620126 发表于 2012-10-14 18:21:29

AVR的性能还是不错的 软件模拟精度还可以

andyw 发表于 2012-11-12 00:18:03

参考学习一下,最近正在做。

yunshuhualei 发表于 2012-11-13 09:12:03

不错,挺好的,支持一下

miyadai 发表于 2012-11-16 10:20:05

很有创造力~

Stone_up 发表于 2012-11-18 13:53:57

不错。


icewooo 发表于 2012-11-18 17:11:38

谢谢分享非常不错

jacktau 发表于 2012-11-18 18:10:27

想法很好,学习一下~~~~~~

Gost 发表于 2012-11-18 23:41:24

以前用51做过不过51太慢了

jz701209李 发表于 2013-4-8 16:37:21

学习一下....

michealzhou 发表于 2013-7-3 23:42:30

非常感谢分享

svebrs 发表于 2013-8-9 08:29:21

支持下,正准备弄个小六玩玩~~

ahnusunwu 发表于 2013-8-27 14:30:53

有没有一款强大的单片机硬件就能输出18路PWM

caiseyuzhou 发表于 2014-4-11 11:09:01

很强大很不错

lintel 发表于 2017-9-21 16:29:56

想法很好,我也学习下
页: [1]
查看完整版本: 控制舵机的多路PWM波 最多可以达到32路