硬件平台:C8051F340单片机(利用其扩展功能--PCA定时器/计数器的高速输出模式)
软件平台:SILION(keil的一个相似版本新华龙单片机专用的)
(注:SPWM是就是在PWM的基础上改变了调制脉冲方式,脉冲宽度时间占空比按正弦规率排列,这样输出波形经过适当的滤波可以做到正弦波输出。)
目的波形:脉冲宽度按数组内容变化。数组元素个数为一个周期。比如:数组元素为100,200,300,200,100;这样可以形成“窄-中-宽-中-窄-窄-中-宽-中-窄……”的波形
失败波形:脉冲虽按数组内容变化。但每一组(窄-中-宽-中-窄)之间相隔大约有5.4ms的低电平,大约算了一下,好像正好是65536个时钟时间。但从程序中却找不到这个时间流失到哪里去了。
#include
unsigned char counter=0;
sfr16 PCA0CP0 = 0xFB; // 定义比较器0的地址。这样就可以操作这个16位的比较器了(不用高低8位分别操作了)。
unsigned int code PWM[10]={100,500,200,400,300,300,200,400,100,500};
unsigned int NEXT_COMPARE_VALUE; // 定义变量(下一次放入的值)
void OSCILLATOR_Init (void);
void PORT_Init (void);
void PCA0_Init (void);
void main (void)
{
PCA0MD = 0x00;// 关看门狗
PORT_Init (); // 初始化端口
OSCILLATOR_Init (); // 初始化时钟//不熟悉此单片机的可以不用管这两步设置,此单片机的例程中都用的这两步。
PCA0_Init (); // 初始化PCA0定时器/计数器
EA = 1; // 开总中断
while (1)
{
if(counter==10)// 如果数组遍历完,重新开始
{
counter=0;
NEXT_COMPARE_VALUE=0;//PWM[0];
PCA0L=0;
PCA0H=0;
}
}
}
void OSCILLATOR_Init (void)//时钟设置:设为使用系统时钟12MHZ
{
OSCICN = 0x83; // Set internal oscillator to run
// at its maximum frequency
CLKSEL = 0x00; // Select the internal osc. as
// the SYSCLK source
}
void PORT_Init (void)//端口设置:设置内部的PWM通过P0.0输出
{
XBR0 = 0x00;
XBR1 = 0x41; // Route CEX0 to P0.0,
// Enable crossbar and weak pull-ups
P0MDOUT |= 0x01; // Set CEX0 (P0.0) to push-pull
}
void PCA0_Init (void)//设置PCA定时计数器。工作方式为高速输出模式。允许匹配翻转,允许匹配中断。
{
PCA0CN = 0x00; // 停止PCA定时器/计数器,并清除各种中断标志
PCA0MD = 0x08; // PCA定时器/计数器使用系统时钟,即12MHZ
PCA0CPM0 = 0x4D; //此处用的是比较模块0// 高速输出模式(当计数器值与比较器值相等时P0.0电平发生翻转),
// 使能比较器的匹配中断功能(当计数器值与比较器值相等时产生中断-可以在中断中放入下次值以产生PWM),
// 使能比较器的匹配标志(当计数器值与比较器值相等时此位由硬件置1,但需软件清0-需在中断中清0)
PCA0L = 0x00; // 初始化PCA定时器/计数器初值
PCA0H = 0x00;
PCA0CPL0 = PWM[0] & 0x00FF; // 放入比较器0初始值(此处我放入数组第一元素)
PCA0CPH0 = (PWM[0] & 0xFF00) >> 8;
NEXT_COMPARE_VALUE = PCA0CP0 + PWM[1];//设置下一次放入比较器0的值
counter=2;
EIE1 |= 0x10; // 使能PCA定时器/计数器全局中断
CR = 1; // 启动PCA定时器/计数器
}
void PCA0_ISR (void) interrupt 11
{
if (CCF0) // 如果模块0匹配中断标志为1
{
//CR=0;
CCF0 = 0; // 清模块0中断标志.
PCA0CPL0 = (NEXT_COMPARE_VALUE & 0x00FF);//放入比较器0下一次的值
PCA0CPH0 = (NEXT_COMPARE_VALUE & 0xFF00)>>8;
NEXT_COMPARE_VALUE = PCA0CP0 + PWM[counter];//计算下一次的值
counter++;
//CR=1;
}
else // 如果是其它模块产生的中断.
{
PCA0CN &= ~0x86; // 清除这些模块的中断标志
}
}