【代码介绍】
在观看小蜜蜂老师的进阶强化PWM控制呼吸灯部分代码时,由于代码缺少注释,所以在第一次理解时比较吃力,没理解代码块之间的关联性以及各变量作用。所以这里对代码给出自己的理解注释。
注:本代码基于小蜜蜂老师进阶强化07改编而来,但是不同的是使用的是IO模式而并非是MM模式。
代码部分:
#include <REG52.H>
sbit S4 = P3 ^ 3;
sbit S7 = P3 ^ 0;
unsigned char code Array[18] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90,
0x88, 0x80, 0xc6, 0xc0, 0x86, 0x8e, 0xbf, 0x7f};
unsigned char Count; //定时器计数
unsigned char Flag; // S4按键模式切换
unsigned char Pause; //用于在按键长按停止灯光以及数码管
unsigned char direction; // LED灯闪烁方向
unsigned char Position; // LED灯亮的位置
unsigned char PWM; //用于记录占空比,同时控制亮度
unsigned char Times; //用于计次(在LED_Control函数)中,与PWM变量结合使用
void Delay(unsigned int x)
{
while (x--)
;
}
void HC573(unsigned char channel)
{
switch (channel)
{
case 4:
P2 = (0x1f & P2) | 0x80;
break;
case 5:
P2 = (0x1f & P2) | 0xa0;
break;
case 6:
P2 = (0x1f & P2) | 0xc0;
break;
case 7:
P2 = (0x1f & P2) | 0xe0;
break;
case 0:
P2 = (0x1f & P2);
break;
}
}
void Nixie(unsigned char column, unsigned char row)
{
P0 = 0xff;
HC573(7);
HC573(0);
P0 = 0x01 << column;
HC573(6);
HC573(0);
P0 = row;
HC573(7);
HC573(0);
}
void Display(unsigned char column, unsigned char row)
{
Nixie(0, Array[column]);
Delay(500);
Delay(500);
Nixie(6, Array[row / 10]);
Delay(500);
Nixie(7, Array[row % 10]);
Delay(500);
Nixie(0, 0xff);
Delay(500);
Nixie(6, 0xff);
Delay(500);
Nixie(7, 0xff);
Delay(500);
}
void System_Init()
{
HC573(5);
P0 = 0x00;
HC573(4);
P0 = 0xFF;
HC573(0);
}
void Timer_Init() //定时器
{
TMOD = 0x01;
TH0 = (65535 - 1000) / 256;
TL0 = (65535 - 1000) % 256;
TF0 = 0;
TR0 = 1;
EA = 1;
ET0 = 1;
}
void San_Key()
{
if (S4 == 0)
{
Delay(100);
if (S4 == 0)
{
while (S4 == 0)
{
Pause = 1; //按键S4长按,暂停呼吸灯,显示数码管,标志位置1;
}
Pause = 0; //松开S4,呼吸灯继续运行
Flag++; //模式切换标志位
if (Flag == 3) //模式只有正向闪烁和逆向闪烁两种模式
{
Flag = 1;
}
}
}
if (S7 == 0)
{
Delay(100);
if (S7 == 0)
{
while (S7 == 0)
{
Pause = 1; // S7按下,同样暂停呼吸灯
Display(Position + 1, PWM * 10); //在数码管上显示当前亮灯以及占空比
}
Pause = 0; //松开继续运行
}
}
}
void LED_Control() // LED呼吸灯
{
//这里的Times和定时器中的PWM变量相互结合。
/*定时器每10ms(Count》10),Times加1,而Times加到5之后,置0,组合一起为50ms。
也即是每50ms使PWM占空比+1,当占空比为10时,总共为500ms也即是0.5s,实现缓慢亮0.5s*/
if (Times == 5)
{
Times = 0;
if (direction == 0)
{
PWM += 1; //占空比,50ms+1,总共时间为500ms,所以在数码管显示阶段会将占空比*10。
if (PWM == 11) // PWM达到10之后,完成0.5s亮,置0,进行0.5s灭操作
{
PWM = 10;
direction = 1;
}
}
else if (direction == 1)
{
PWM -= 1;
if (PWM == 255) // PWM类型为unsigned char(范围0~256),等价于(PWM<0)
{
PWM = 0;
direction = 0;
if (Flag == 1) //正向闪烁模式
{
Position++; //亮灯位置加1,使下一位灯开始亮
if (Position == 8)
{
Position = 0;
}
}
else if (Flag == 2) //逆向闪烁模式
{
Position--;
if (Position == 255) //等价于(Position<0)
{
Position = 7;
}
}
}
}
}
}
void main()
{
System_Init();
Timer_Init();
while (1)
{
San_Key();
LED_Control();
}
}
void Timer() interrupt 1
{
TH0 = (65535 - 1000) / 256;
TL0 = (65535 - 1000) % 256;
if (Flag == 0) //初始化L4,L5亮
{
HC573(4);
P0 = 0xe7;
return;
}
Count++;
/*这里PWM为一个标识量,Count小于PWM时亮,大于PWM小于10时灭,
10ms使Times++,5次后PWM变化(即亮度进行变化)*/
if (Count <= PWM)
{
P0 = ~(0x01 << Position);
HC573(4);
HC573(0);
}
else if (Count <= 10)
{
P0 = 0xff;
HC573(4);
HC573(0);
}
else
{
//这一步亮灯操作不加好像也没影响
P0 = ~(0x01 << Position);
HC573(4);
HC573(0);
Count = 0;
if (Pause == 0)
{
Times++;
}
}
}
最后运行时,在长按按键显示数码管时,还是会导致数码管轻微闪烁,没有完全做到消影。