基于蓝桥杯的单片机模块练习——PWM脉宽调制
功能概述
用定时器模拟PWM脉宽调制信号(频率为100hz),来控制LED1的亮度。要求单片机上电后,LED全部熄灭,按下S7后,LED以10%的亮度被点亮,再按一下S7后,亮度变为50%,再次按下S7,亮度变为90%,再按一次则熄灭,以此循环。
C代码
#include "stc15f2k60s2.h"
unsigned char pwm_duty = 0;
void SelectHC573(unsigned char channel);
void SystemInit();
void Delay_1ms(unsigned int t);
void Init_Timer0();
void Scan_Key();
void main()
{
SystemInit();
SelectHC573(4);
Init_Timer0();
while(1)
{
Scan_Key();
}
}
void SelectHC573(unsigned char channel)
{
switch(channel)
{
case 0 : P2 = (P2 & 0X1F) | 0X00;break;
case 4 : P2 = (P2 & 0X1F) | 0X80;break;
case 5 : P2 = (P2 & 0X1F) | 0Xa0;break;
case 6 : P2 = (P2 & 0X1F) | 0Xc0;break;
case 7 : P2 = (P2 & 0X1F) | 0Xe0;break;
}
}
void SystemInit()
{
SelectHC573(5);
P0 = 0x00;
SelectHC573(0);
P0 = 0xff;
}
void Delay_1ms(unsigned int t)
{
unsigned int x,y;
for(x = t; x > 0; x--)
for(y = 900; y > 0; y--);
}
void Init_Timer0()
{
TMOD = 0x02;
TH0 = 256 - 100;//每隔100us进入一次中断
TL0 = 256 - 100;
EA = 1;
ET0 = 1;
}
void Service_Timer0() interrupt 1
{
static unsigned int count = 0;
count++;
if(count <= pwm_duty)
{
P00 = 0;
}
else if(count <= 100)
{
P00 = 1;
}
else
{
count = 1;P00 = 0;
}
}
unsigned char stat = 0;
void Scan_Key()
{
if(P30 == 0)
{
Delay_1ms(10);
if(P30 == 0)
{
switch(stat)
{
case 0 :
P00 = 0;
TR0 = 1;
pwm_duty = 10;
stat = 1;
break;
case 1 :
pwm_duty = 50;
stat = 2;
break;
case 2 :
pwm_duty = 90;
stat = 3;
break;
case 3 :
P00 = 1;
TR0 = 0;
stat = 0;
break;
}
while(!P30);
}
}
}
知识点总结
实现PWM脉宽调制的部分代码
void Service_Timer0() interrupt 1
{
static unsigned int count = 0;
count++;
if(count <= pwm_duty)//一个周期时间的前pwm_duty%的时间段让LED亮起
{
P00 = 0;
}
else if(count <= 100)//剩余时间让LED熄灭
{
P00 = 1;
}
else
{
count = 1;P00 = 0;//从头再来
}
}
本题要求f == 100hz,所以PWM的信号周期为T = 1/100s = 10000us。
我们把一个周期分成100份,那就得每隔100us进入一次中断函数。如下图所示:
所谓的模拟脉宽调制就是在很短的一段时间对LED的熄灭和点亮的操作。比如要求亮度为90%,也就是在一个周期时间的前90%的时间段让LED亮起,后10%的时间让LED熄灭。由于整个时间才耗费1/100s,所以肉眼看起来就是LED以一定亮度一直亮着。为了实现任意亮度,我们可以定义一个变量pwm_duty来实现。