这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » 国产MCU » 【STC32G12K128】利用定时器实现PWM

共1条 1/1 1 跳转至

【STC32G12K128】利用定时器实现PWM

专家
2024-12-13 23:40:14     打赏

前面我们利用纯粹的程序代码通过循环处理,产生PWM波。处理过程中由于代码的原因,会有一定的占空比误差。另外由于单片通常还有大量的其他处理,不可能把处理时间片完全用来生成PWM波,所以这个时候,利用定时器来生成PWM波就是一种很好的选择了。

在单片机中,定时器是非常重要的一个外设。利用定时器的特点,我们可以让定时器按照固定周期(频率)使自定义变量加1或者减1,实现自动计数。这个计数步进值可以是1,也可以是其它数值。

定时器控制自动加1或者减1的处理过程中,我们控制好两边的边界以及中间计数值的某一个点,就可以用来生成技术范围的两个段,这两个端就可以作为脉冲波的高/低电平的边界。如下如图所示,让计数变量在0-9之间进行计数,在计数值为0-4之间时,使某个IO口输出低电平;在计数值为5-9之间时输出高电平。

图片1.png

那么只要定时器一直工作下去,在输出的IO口上就有占空比为50%的PWM波。改变这个中间界限值,就可以改变占空比值。

接下来,我们就用STC32G12K128来做这个测试。完成这个过程,需要启用定时器,并允许定时器中断。在中断处理中,根据当前计数值,改变某个IO口的输出电平。代码如下:

#include "../../comm/STC32G.h"  //包含此头文件后,不需要再包含"reg51.h"头文件
#define     MAIN_Fosc       24000000UL  //定义主时钟
typedef     unsigned char   u8;
typedef     unsigned int    u16;
typedef     unsigned long   u32;
// 这个值决定定时器0的中断周期
#define Timer0_Reload   (MAIN_Fosc / 1000)      //Timer 0 中断频率, 1000次/秒
unsigned long  cnt=0;          // 计数变量
unsigned long  jx=2;           // 界限值
unsigned long  max=9;          // 计数值上限
void    Timer0_init(void);
//========================================================================
// 函数: void main(void)
// 描述: 主函数.
// 参数: none.
// 返回: none.
// 版本: V1.0, 2015-1-12
//========================================================================
void main(void) {
    WTST = 0;  //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快
    EAXFR = 1; //扩展寄存器(XFR)访问使能
    CKCON = 0; //提高访问XRAM速度
    P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
    P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
    P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
    P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
    P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
    P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
    P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
    P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
    EA = 1;     //打开总中断
    
    // 初始化定时器0
    Timer0_init();
    while (1) {
    }
}
//========================================================================
// 函数: void Timer0_init(void)
// 描述: 初始化timer0
// 参数: none.
// 返回: none.
//========================================================================
void Timer0_init(void) {
    TR0 = 0;    //停止计数
    #if (Timer0_Reload < 64)    // 如果用户设置值不合适, 则不启动定时器
        #error "Timer0设置的中断过快!"
    #elif ((Timer0_Reload/12) < 65536UL)    // 如果用户设置值不合适, 则不启动定时器
    
    ET0 = 1;    //允许中断
    TMOD &= ~0x03;
    TMOD |= 0;  //工作模式, 0: 16位自动重装, 1: 16位定时/计数, 2: 8位自动重装, 3: 16位自动重装, 不可屏蔽中断
    T0_CT = 0;  // 定时模式
    T0CLKO = 0; //不输出时钟
    #if (Timer0_Reload < 65536UL)
        T0x12 = 1;  //1T mode
        TH0 = (u8)((65536UL - Timer0_Reload) / 256);
        TL0 = (u8)((65536UL - Timer0_Reload) % 256);
    #else
        T0x12 = 0;  //12T mode
        TH0 = (u8)((65536UL - Timer0_Reload/12) / 256);
        TL0 = (u8)((65536UL - Timer0_Reload/12) % 256);
    #endif
    TR0 = 1;    //开始运行
    #else
        #error "Timer0设置的中断过慢!"
    #endif
}
//========================================================================
// 函数: void timer0_int (void) interrupt TIMER0_VECTOR
// 描述:  timer0中断函数.
//========================================================================
void timer0_int (void) interrupt 1 {
    P10 = ~P10;          // 这是最简单的可以形成占空比为50%的方波
    cnt=(cnt+1)%(max+1);
    if (cnt <= jx) {
        P11 = 0;    // P11输出低电平
    } else {
        P11 = 1;    // P11输出高电平
    }
}

测试输出波形如下:

图片2.png

根据程序,在计数值为0-2时,P11输出低电平;在3-9时,P11输出高电平。PWM的占空比为7/10=70%,实测结果验证了这个结果。

在某些单片机中,能够用来产生PWM的定时器,配置了多种和PWM相关的寄存器,比如用来存贮预先设置界限值的寄存器、生成PWM用的目标通道(就是输出电平的IO口)。这样我们都不需要在定时器的在中断程序中做判断,根据当前计数值确定IO口输出什么电平了,而仅仅是在初始化时设置好对应的参数就行了,大大简化了处理过程。STC32G12K128中也有这样的寄存器设置,设计更为复杂的PWM生成处理。后面依旧会用STC32G12K128来进行说明。





关键词: 菜鸟学单片机    

共1条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]