使用两个定时器实现PWM(脉宽调制)——呼吸灯

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/XiaoCaiDaYong/article/details/82866870

PWM(脉宽调制)大家可以上网查查,其原理讲解很多。为了更好的学习PWM,我特意参照别人写的文章,自己也写了一份代码来实现PWM。代码如下:

#include <stc12c5a60s2.h>

unsigned long cnt;
unsigned int cnt_T1;
unsigned int high;
unsigned int low;
unsigned char TH0_high;
unsigned char TL0_high;
unsigned char TH0_low;
unsigned char TL0_low;
unsigned char T1H1;
unsigned char T1L1;
unsigned char flag=0;

unsigned char duty[19] = {5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95};
unsigned char index=0;

void config_Fy_and_dy(unsigned char fy, unsigned char dy);
void config_Timer1(unsigned char ms);
void modify_duty(unsigned char dy);

sbit PWM_OUT = P2^5;

void main()
{
    TMOD = 0X11;    //  定时器0/1都工作在方式1,是2^16计数
    EA=1;
    config_Fy_and_dy(100, 20);
    config_Timer1(50);
    while(1);
}

void config_Fy_and_dy(unsigned char fy, unsigned char dy) // 输入频率fy,占空比dy 
{
    cnt =  (11059200/fy)/12;    //  要产生频率为fy,定时器0所要计的数值
    high = (cnt*dy)/100;        //  计算出高电平所要计的数值
    low = cnt - high;   //  计算出低电平所要计的数值
    high = 65536 - high;  //  确定定时器0,从哪个初值开始计时,记录的是高电平
    low = 65536 - low;  //  确定定时器0,从哪个初值开始计时,记录的是低电平
    TH0_high = (unsigned char)(high>>8);    //  高电平,给TH0预备重装初值
    TL0_high = (unsigned char)high;         //  高电平,给TL0预备重装初值
    TH0_low = (unsigned char)(low>>8);      //  低电平,给TH0预备重装初值
    TL0_low = (unsigned char)low;           //  低电平,给TL0预备重装初值
    TH0 = TH0_high; 
    TL0 = TL0_high;
    PWM_OUT = 1;               
    ET0 = 1;
    TR0 = 1;
}

void config_Timer1(unsigned char ms)
{
    unsigned long temp;
    temp =  11059200/1000;
    temp = (temp*ms)/12;
    cnt_T1 = 65536 - temp;
    T1H1 = (unsigned char)(cnt_T1>>8);
    T1L1 = (unsigned char)cnt_T1;
    TH1 = T1H1;
    TL1 = T1L1;
    ET1=1;
    TR1=1;
}

void modify_duty(unsigned char dy)
{
    high = (cnt*dy)/100;
    low = cnt - high;
    high = 65536 - high;
    low  = 65536 - low;
    TH0_high = (unsigned char)(high>>8);    //  高电平,给TH0预备重装初值
    TL0_high = (unsigned char)high;         //  高电平,给TL0预备重装初值
    TH0_low = (unsigned char)(low>>8);      //  低电平,给TH0预备重装初值
    TL0_low = (unsigned char)low;           //  低电平,给TL0预备重装初值
}

void T0_Timer0() interrupt 1
{
    if(PWM_OUT==0)  //  准备产生高电平
    {
        TH0 = TH0_high;         //  高电平产生  初值重装
        TL0 = TL0_high;
        PWM_OUT = 1;
    }
    else
    {
        TH0 = TH0_low;         //  低电平产生  初值重装
        TL0 = TL0_low;
        PWM_OUT = 0;
    }
}

void T1_Timer1() interrupt 3
{
    TH1 = T1H1;
    TL1 = T1L1;
    modify_duty(duty[index]);
    if(0 == flag)   //  flag=0时,表示呼吸灯由暗变亮
    {
        index++;
        if(index >=18)
        {
            flag = 1;
        }
    }
    else
    {
        index--;
        if(index <=0)
        {
            flag=0;
        }
    }
}

其实,PWM这种实现方法并不适合编程,因为它占用了两个定时器中断口,会影响程序的执行效率。

我是通过两个定时器来更好的掌握PWM的调制原理。

接下来,我将会通过单片机(STC12C5A60S2)内部模块实现PWM,实现比较简单,将在下个文章来完成。

猜你喜欢

转载自blog.csdn.net/XiaoCaiDaYong/article/details/82866870