定时器产生PWM

1 用两个定时器/计数器产生矩形波

这种方法的基本原理就是用T0作为矩形波的周期的定时器,每一周期产生一次中断,用T1作为矩形波的高电平的计时器,每到T0的定时中断,输出矩形波的引脚输出高电平,而到T1中断产生时,将该引脚置为低电平,这样就得到了所需要的矩形波。通过改变T0的计数值可以改变周期,而改变T1的计数值可以改变占空比。

下面通过一个例子说明这种方法。在例子中,矩形波频率为10Hz(即周期为100ms),占空比为25%(即高电平周期为25ms),通过单片机引脚P2.0输出矩形波。程序流程如图13.4所示。程序如例13-2所示,所用晶振频率为12.0MHz。

【例13-2】用MCS-51单片机的T0和T1产生矩形波。

#include <reg51.h>

typedef unsigned char uchar;

sbit signal=P2^0;

uchar counter;

void main(void)

{

    TR0=0;                   //禁止T0

    TMOD=0x11;               //T0和T1均选择工作方式1,16位定时器

    TH0=-1000/256;           //定时时间为50ms

    TL0=-1000%256;          

    signal=0;                //开始时输出为低电平

    counter=0;               //初始化T1的中断次数为0

    EA=1;                    //使能CPU中断

    ET0=1;                   //使能T0溢出中断

    ET1=1;                   //使能T1溢出中断

    TR0=1;                   //T0开始运行,注意,T1不能现在运行

    while(1)                 //无限循环

    {}

}

void isr_t0(void) interrupt 1   //T0中断服务函数

{  

    TH0=-50000/256;          //定时时间为50ms

    TL0=-50000%256;

    counter++;               //中断次数

    if(counter==2)           //若已中断两次,说明已经过去100ms

    {

        counter=0;           //中断次数归零

        signal=1;            //产生矩形波中的高电平

        TR1=1;               //唤醒T1,T1开始计数

    }

}

void isr_t1(void) interrupt 3   //T1中断服务函数

{  

    signal=0;                //矩形波中的低电平

    TR1=0;                   //禁止T1计数,等待T0将其唤醒

    TH1=-25000/256;          //25ms中断初值

    TL1=-25000%256;

}

 

2.用一个定时器/计数器产生矩形波

在使用定时器、计数器完成其他功能的场合,用两个定时器/计数器产生矩形波的方法是不合适的,因为某些MCS-51单片机内部只有两个定时器/计数器。这时候通常使用第二种方法,即只使用一个定时器/计数器产生矩形波。

这种方法的基本原理是使引脚产生一个低电平,对T1或T0设置计数初始值并运行,使之经过时间t1后产生定时中断;在中断服务函数中将引脚设置为高电平,对定时器/计数器设置另一个计数初始值,经过时间t2后产生中断,在中断服务函数中将引脚设置为低电平,对定时器/计数器设置低电平维持所需的计数初始值,如此循环往复,就产生一个高电平时间为t2、周期为(t1+t2)的矩形波。

仍以产生一个从单片机引脚P2.0输出的、输出频率为10Hz、占空比为25%的矩形波为例。程序流程如图13.5所示。程序的关键是从高电平转变到低电平以及从低电平转变到高电平,因此在程序中使用一个位变量来标志中断产生前输出的是低电平还是高电平。程序如例13-3所示:

【例13-3】用一个定时器/计数器产生输出频率为10Hz、占空比为25%矩形波。

#include <reg51.h>

typedef unsigned char uchar;

sbit signal=P2^0;

bit level;                      //用来存储产生T0中断之前输出何种电平

uchar counter;

void main(void)

{

    TMOD=0x01;                   //T0选择工作方式1,16位定时器

    TH0=-25000/256;              //定时时间为25ms

    TL0=-25000%256;         

    counter=0;signal=1;level=1;  //初始化全局变量

    EA=1;                        //使能CPU中断

    ET0=1;                       //使能T0溢出中断

    TR0=1;                       //T0开始运行    

    while(1)                     //无限循环

    {}

}

void isr_t0(void) interrupt 1   //T0中断服务函数

{  

    if(level==1)                 //如果中断产生之前输出的是高电平

    {

        signal=0;                //输出低电平

        TH0=-25000/256;          //定时时间为25ms时的初值

        TL0=-25000%256; 

        level=0;                 //保存当前输出的电平(低电平)

    }

   else                         //如果中断产生之前输出的是低电平

   {

        counter++;               //中断次数计数加1

        if(counter==3)           //如果已经输出低电平75ms

        {

            counter=0;            //中断次数计数归零

            signal=1;             //输出高电平

            TH0=-25000/256;

            TL0=-25000%256;  

            level=1;              //保存当前输出的电平(高电平)

        }

   }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值