|
本帖最后由 强者归来 于 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);
void Quickprepare(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/N ms周期)
}
#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) |
|