之前使用555搭建PWM电路,需要一些阻容器件配合,能产生周期改变、占空比改变的PWM波,与我们经常谈及的PWM有些不同。由于需要改变外围器件的值,这种方式还是比较麻烦的。这次,我们在学习单片机的基础上,利用单片内部的定时器来实现PWM波。
在实验开始之前,先理解PWM,以及利用定时器产生PWM的原理。
PWM是脉冲宽度调制的英语缩写,通过改变信号的脉冲宽度来控制电路的技术。在PWM中,信号的周期保持恒定不变,但脉冲的宽度可以调节。PWM被广泛用于电机控制、LED调光、电源变换等系统中。通过改变占空比(高电平的时间与脉冲周期的比值),实现对输出功率的精确控制。
相对于NE555,单片机可以进行编程,完成灵活控制。下面我们在不使用单片机定时器的基础上实现PWM波。基本原理是:在程序的主循环中对变量不断进行加1计数,技术范围是0到99。当计数值处于0~49之间时,使某个GPIO口输出0;在计数值处于50~99之间时,使某个GPIO口输出1,这样我们就得到了占空比为50% 的脉冲波。这里50就可以作为阈值使用,改变这个阈值,就能改变脉冲波的占空比。这是最简单、最容易理解的实现方式。代码如下:
typedef unsigned charu8; typedef unsigned intu16; typedef unsigned longu32; // 工作主频 #define MAIN_Fosc 24000000UL sbit PWMOUT = P2^0; // PWM输出 // 计数变量 u8 cnt = 0; u8 threshold=50; void delay_ms(u8 ms); void delay_us(u8 us); /******************** 主函数 **************************/ void main(void) { WTST = 0; //设置程序指令延时参数,赋值为0可将CPU执行指令的速度设置为最快 EAXFR = 1; //扩展寄存器(XFR)访问使能 CKCON = 0; //提高访问XRAM速度 P2M1 = 0x00; P2M0 = 0x00; // 准双向口 P40 = 0;//LED Power On cnt=0; while(1) { if (cnt<threshold) PWMOUT = 0; delay_us(5); // 改变延时数据,可以改变脉冲波的周期 if (cnt>(threshold-1)) PWMOUT = 1; delay_us(5); // 这里的值一定要和前面的一致,否则会改变占空比 cnt=(cnt+1)%100; } } //======================================================================== // 函数: void delay_ms(unsigned char ms) // 描述: 延时函数。 // 参数: ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟. //======================================================================== void delay_ms(u8 ms) { u16 i; do { i = MAIN_Fosc / 6000; while(--i); } while(--ms); } void delay_us(u8 us) { u16 i; do { i = MAIN_Fosc / 6; while(--i); } while(--us); }
实际上上记程序中的处理,还是有一点误差的。就是判断值范围的那个地方,条件成立和条件不成立时,执行的代码是不一样的。条件成立时多之心了一个代码,尽管代码执行的周期很短。但如果这个周期相对于整个脉冲波的周期的比例很低的时候,可以忽略不计。在程序中,改变阈值threshold就可以改变占空比。
下次实验,我将使用定时器完成PWM波的生成。