|
发表于 2007-8-29 11:49:50
|
显示全部楼层
// ***********************************************************
//软件功能描述:
//本程序的作用是输出六路三组互补对称的pwm波形,
//其中任一组波形的死区时间通过软件设定。
//在本程序中的单个pwm周期为固定的100ms
//死区时间假设为4ms
//***********************************************************
//*************************************************************
//硬件描述:
//目标mcu: ATMEGA64
//使用外部晶振: 14.7456MHZ
//*************************************************************
#include <avr\io.h>
#include <avr\interrupt.h>
#include <avr\signal.h>
#define PWM_CIRCLE 4 //PWM周期为40mS,(单位为10mS ) 注意:PWM_CIRCLE的取值范围应满足条件1152*PWM_CIRCLE<=65536
#define DEAD_TIME 1 //定义死区时间为1mS,(单位为1mS)
#define TOP 17
char i; //定义全局变量i用以调用数组
char flag1,flag2; //全局标志位变量flag2用于在主程序中判断是否该输出另外半个周期,
//而flag1则是用来标记i是否计数到TOP(17)
long y=1152;
//任意的测试数组
const char U[]={
5,10,15,20,25,30,35,40,45,45,40,35,30,25,20,15,10,5
};
const char V[]={
5,10,15,20,25,30,35,40,45,45,40,35,30,25,20,15,10,5
};
const char W[]={
5,10,15,20,25,30,35,40,45,45,40,35,30,25,20,15,10,5
};
//***********************************************************
//中断处理程序,采用定时器1的溢出中断,在相位与频率修正PWM模式下,溢出时刻发生在BOTTOM处
//***********************************************************
SIGNAL(SIG_OVERFLOW1)
{
//前一个式子用来确定比较匹配的时间点,后一个式子用来增加死区时间。
//因为OCR1A用来控制上桥臂的导通时间,由于存在死区时间,因此导通时
//间须少于实际的IPM桥臂导通时间,所以要将比较匹配时间往后推移。
OCR1A=y*PWM_CIRCLE*U/100 + 115*DEAD_TIME/2;
OCR3A=y*PWM_CIRCLE*U/100 - 115*DEAD_TIME/2;
OCR1B=y*PWM_CIRCLE*V/100 + 115*DEAD_TIME/2;
OCR3B=y*PWM_CIRCLE*V/100 - 115*DEAD_TIME/2;
OCR1C=y*PWM_CIRCLE*W/100 + 115*DEAD_TIME/2;
OCR3C=y*PWM_CIRCLE*W/100 - 115*DEAD_TIME/2;
if(i==TOP)
{i=0;flag1=1;flag2=!flag2;}
else
i++;
}
// ***********************************************************
// Main program
// ***********************************************************
void init(void)
{
//升序记数时比较匹配将置位OC1A/OC1B/OC1C,降序记数时比较匹配将清零OC1A/OC1B/OC1C
TCCR1A=(1<<COM1A1)|(1<<COM1A0)|(1<<COM1B1)|(1<<COM1B0)|(1<<COM1C1)|(1<<COM1C0)|(0<<WGM11)|(0<<WGM10);
//升序记数时比较匹配将清零OC3A/OC3B/OC3C ,降序记数时比较匹配将置位OC3A/OC3B/OC3C
TCCR3A=(1<<COM3A1)|(0<<COM3A0)|(1<<COM3B1)|(0<<COM3B0)|(1<<COM3C1)|(0<<COM3C0)|(0<<WGM31)|(0<<WGM30);
//相位与频率修正PWM TOP值为ICR1,OCR1x更新时刻BOTTOM,64分频
TCCR1B|=(1<<WGM13)|(0<<WGM12)|(0<<CS12)|(1<<CS11)|(1<<CS10);
//相位与频率修正PWM TOP值为ICR3,OCR3x更新时刻BOTTOM,64分频
TCCR3B|=(1<<WGM33)|(0<<WGM32)|(0<<CS32)|(1<<CS31)|(1<<CS30);
i = 0;
flag1= 0; //标志位开始置0
flag2= 0;
OCR1A=1152*PWM_CIRCLE;
OCR3A=0;
OCR1B=1152*PWM_CIRCLE;
OCR3B=0;
OCR1C=1152*PWM_CIRCLE;
OCR3C=0;
ICR1=1152*PWM_CIRCLE; //定义计数器1的TOP值,由于是双斜坡方式,所以周期会增大一倍
ICR3=1152*PWM_CIRCLE; //定义计数器3的TOP值
DDRB|=(1<<DDB5)|(1<<DDB6)|(1<<DDB7); //设置D口的5,6,7脚为输出,即OCR1A,OCR1B,OCR1C
DDRE|=(1<<DDE3)|(1<<DDE4)|(1<<DDE5); //设置E口的3,4,5脚为输出,即OCR3A,OCR3B,OCR3C
TIMSK|=(1<<TOIE1); //T/C1 溢出中断使能
sei(); //开中断
}
int main(void) {
init() ;
while(1)
{
while(flag1==1)
{
if(flag2==1)
{
//停止时钟源以便修改波形输出方式
TCCR1B|=(1<<WGM13)|(0<<WGM12)|(0<<CS12)|(0<<CS11)|(0<<CS10);
TCCR3B|=(1<<WGM33)|(0<<WGM32)|(0<<CS32)|(0<<CS31)|(0<<CS30);
TCCR1A=(1<<COM1A1)|(0<<COM1A0)|(1<<COM1B1)|(0<<COM1B0)|(1<<COM1C1)|(0<<COM1C0)|(0<<WGM11)|(0<<WGM10);
TCCR3A=(1<<COM3A1)|(1<<COM3A0)|(1<<COM3B1)|(1<<COM3B0)|(1<<COM3C1)|(1<<COM3C0)|(1<<WGM31)|(0<<WGM30);
//重新启动时钟源,开始继续计数
TCCR1B|=(1<<WGM13)|(0<<WGM12)|(0<<CS12)|(1<<CS11)|(1<<CS10);
TCCR3B|=(1<<WGM33)|(0<<WGM32)|(0<<CS32)|(1<<CS31)|(1<<CS30);
}
else
{
//停止时钟源以便修改波形输出方式
TCCR1B|=(1<<WGM13)|(0<<WGM12)|(0<<CS12)|(0<<CS11)|(0<<CS10);
TCCR3B|=(1<<WGM33)|(0<<WGM32)|(0<<CS32)|(0<<CS31)|(0<<CS30);
TCCR1A=(1<<COM1A1)|(1<<COM1A0)|(1<<COM1B1)|(1<<COM1B0)|(1<<COM1C1)|(1<<COM1C0)|(0<<WGM11)|(0<<WGM10);
TCCR3A=(1<<COM3A1)|(0<<COM3A0)|(1<<COM3B1)|(0<<COM3B0)|(1<<COM3C1)|(0<<COM3C0)|(1<<WGM31)|(0<<WGM30);
//重新启动时钟源,开始继续计数
TCCR1B|=(1<<WGM13)|(0<<WGM12)|(0<<CS12)|(1<<CS11)|(1<<CS10);
TCCR3B|=(1<<WGM33)|(0<<WGM32)|(0<<CS32)|(1<<CS31)|(1<<CS30);
}
flag1 = 0;
}
}
return 0;
} |
|