问题
第九届蓝桥杯单片机设计与开发项目省赛有这一部分
灯的亮度变化是使用PWM实现的
解决思路
1.了解PWM的原理
PWM:脉冲宽度调制技术
可视为一种数模转换,单片机中可以通过快速对器件进行开关动作来实现PWM。
占空比是指在一个脉冲循环内,高电平时间相对于总时间所占的比例。
开发者可以通过调节占空比实现相应功能。
据此我们可以简单画出下图(以占空比为80%为例):
2.PWM如何运用到调光?(此处引用知乎大神麦一的回答)
在一秒钟内,灯亮0.5秒灭0.5秒的亮度和灯亮0.9秒灭0.1秒的亮度是不一样的。
当这个1s的时间缩短,让它变化的次数在1s中达到一定次数(频率)。
人眼无法察觉到灯的闪烁,只能察觉到灯的亮度强弱。
这就是pwm调光,控制灯在一个周期内的亮灭的比例来完成对灯亮度的调节。
3.根据原理写出相关代码
设置两个变量
一个(Time)主要是在中断服务函数里面计数
周期一到就清0
一个设置占空比(PWM),是全局变量
用于和Time进行比较,Time一到占空比,
相应的变量电平就反转
if(time >= 100)//把周期分成100份
time = 0;
if (time < PWM)
L1 = 0;
else
L1 = 1;
整体代码参考
试验现象:通过S7控制L1的亮度,占空比分别为20%,50%,70%,100%
#include <reg52.h>
#include <absacc.h>
int time = 0; //控制周期
int PWM = 20; //占空比控制 占空比初始值:20%
sbit L1 = P0^0;
sbit S7 = P3^0;
void select_573(unsigned char channal)
{
switch (channal)
{
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 Init_Sys()
{
select_573(5);
P0 = 0x00;
select_573(0);
select_573(4);
P0 = 0xff;
select_573(0);
}
void Init_Time0()
{
TMOD = 0X01;
TH0 = (65536 - 100)/256;
TL0 = (65536 - 100)%256;
EA = 1;
ET0 = 1;
TR0 = 1;//可以适时开启
}
/*--------提示------------------
设置两个变量
一个(Time)主要是在中断服务函数里面计数
周期一到就清0
一个设置占空比(PWM),是全局变量
用于和Time进行比较,Time一到占空比,
相应的变量电平就反转
--------------------------*/
void Time0_serve()interrupt 1
{
TH0 = (65536 - 100)/256;
TL0 = (65536 - 100)%256;
time++;//记录周期
if(time >= 100)//把周期分成100份
time = 0;
if (time < PWM)
L1 = 0;
else
L1 = 1;
}
void Delay(unsigned char i)
{
while(i--);
}
void key_scanf()
{
if(S7 == 0)
{
Delay(100);
if(S7 == 0)
{
if(PWM == 20)
PWM = 50;
else if(PWM == 50)
PWM = 70;
else if(PWM == 70)
PWM = 100;
else if(PWM == 100)
PWM = 20;
while( S7 == 0 );
}
}
}
void main()
{
Init_Sys();
Init_Time0();
select_573(4);
while(1)
{
key_scanf();
}
}
一些建议
1.最好用定时器0产生PWM,以免被其他定时器打断
2.把数据处理部分写入定时器中断,以产生稳定的PWM方波
参考资料:
链接:作者:麦一 来源:知乎 https://www.zhihu.com/question/310820091/answer/587765664