项目二:PWM可控灯设计
基本要求:基于单片机,采用PWM技术,进行亮度可调的可控灯制作与调试(要求同时调控2个或2个以上的多个发光二极管),编程实现可控灯的亮度增强和减弱,要求使用KEY1按键实现亮度增强调节,使用KEY2按键实现亮度减弱调节。
拓展要求:实现呼吸霓虹灯的设计,要求使用一个按键实现多花样、多呼吸频率(至少5种花样,其中至少3种不同呼吸频率)的呼吸霓虹灯花样切换变化(注意呼吸频率必须有明显变化)。

项目二:PWM可控灯设计
基本要求:基于单片机,采用PWM技术,进行亮度可调的可控灯制作与调试(要求同时调控2个或2个以上的多个发光二极管),编程实现可控灯的亮度增强和减弱,要求使用KEY1按键实现亮度增强调节,使用KEY2按键实现亮度减弱调节。
拓展要求:实现呼吸霓虹灯的设计,要求使用一个按键实现多花样、多呼吸频率(至少5种花样,其中至少3种不同呼吸频率)的呼吸霓虹灯花样切换变化(注意呼吸频率必须有明显变化)。

#include <reg51.h> // 包含51单片机的头文件
#define uchar unsigned char // 定义无符号字符类型
#define uint unsigned int // 定义无符号整数类型
#define LED P0 // 将LED灯连接到P0口
#define KEY P1 // 将按键连接到P1口
#define FREQ 100 // 定义PWM的频率为100Hz
#define MODE 5 // 定义呼吸灯的模式个数
#define DELAY 10 // 定义呼吸灯的延时常数
uchar duty[8] = {0, 25, 50, 75, 100, 75, 50, 25}; // 定义8个LED灯的占空比数组
uchar mode = 0; // 定义呼吸灯的模式变量,初始为0
uchar speed = 1; // 定义呼吸灯的速度变量,初始为1
uchar flag = 0; // 定义按键扫描的标志变量,初始为0
void delay_ms(uint ms); // 延时函数的声明
void pwm_output(); // PWM输出函数的声明
void key_scan(); // 按键扫描函数的声明
void mode_change(); // 模式切换函数的声明
void speed_change(); // 速度改变函数的声明
void main() // 主函数
{
TMOD = 0x01; // 设置定时器0为模式1
TH0 = (65536 - 1000) / 256; // 设置定时器0的初值,定时10ms
TL0 = (65536 - 1000) % 256;
EA = 1; // 开启总中断
ET0 = 1; // 开启定时器0中断
TR0 = 1; // 启动定时器0
while (1) // 主循环
{
key_scan(); // 调用按键扫描函数
mode_change(); // 调用模式切换函数
speed_change(); // 调用速度改变函数
}
}
void delay_ms(uint ms) // 延时函数,延时ms毫秒
{
uint i, j;
for (i = ms; i > 0; i--)
for (j = 110; j > 0; j--);
}
void pwm_output() // PWM输出函数,根据占空比数组控制LED灯的亮度
{
uchar i;
for (i = 0; i < 8; i++) // 循环遍历8个LED灯
{
if (duty[i] > 0) // 如果占空比大于0
{
LED = ~(1 << i); // 点亮对应的LED灯
delay_ms(duty[i] * 10 / FREQ); // 延时占空比对应的时间
}
if (duty[i] < 100) // 如果占空比小于100
{
LED = 0xFF; // 熄灭所有的LED灯
delay_ms((100 - duty[i]) * 10 / FREQ); // 延时剩余的时间
}
}
}
void key_scan() // 按键扫描函数,检测按键的状态
{
if (KEY != 0xFF) // 如果有按键按下
{
delay_ms(10); // 去抖延时
if (KEY != 0xFF) // 再次判断按键状态
{
flag = KEY; // 记录按键值
while (KEY != 0xFF); // 等待按键松开
}
}
}
void mode_change() // 模式切换函数,根据按键值改变呼吸灯的模式
{
if (flag == 0xFE) // 如果按下了KEY1
{
flag = 0; // 清除按键值
mode++; // 模式加一
if (mode == MODE) // 如果模式达到最大值
mode = 0; // 模式归零
switch (mode) // 根据模式值改变占空比数组
{
case 0: // 模式0,所有灯同时呼吸
duty[0] = duty[1] = duty[2] = duty[3] = duty[4] = duty[5] = duty[6] = duty[7] = 0;
break;
case 1: // 模式1,单个灯依次呼吸
duty[0] = 100;
duty[1] = duty[2] = duty[3] = duty[4] = duty[5] = duty[6] = duty[7] = 0;
break;
case 2: // 模式2,两个灯依次呼吸
duty[0] = duty[1] = 100;
duty[2] = duty[3] = duty[4] = duty[5] = duty[6] = duty[7] = 0;
break;
case 3: // 模式3,四个灯依次呼吸
duty[0] = duty[1] = duty[2] = duty[3] = 100;
duty[4] = duty[5] = duty[6] = duty[7] = 0;
break;
case 4: // 模式4,八个灯依次呼吸
duty[0] = duty[1] = duty[2] = duty[3] = duty[4] = duty[5] = duty[6] = duty[7] = 100;
break;
}
}
}
void speed_change() // 速度改变函数,根据按键值改变呼吸灯的速度
{
if (flag == 0xFD) // 如果按下了KEY2
{
flag = 0; // 清除按键值
speed++; // 速度加一
if (speed == 4) // 如果速度达到最大值
speed = 1; // 速度归一
}
switch (speed) // 根据速度值改变占空比数组
{
case 1: // 速度1,最慢
duty[0]++;
if (duty[0] == 100) // 如果占空比达到最大值
duty[0] = 0; // 占空比归零
break;
case 2: // 速度2,较慢
duty[0] += 2;
if (duty[0] > 100) // 如果占空比超过最大值
duty[0] = 0; // 占空比归零
break;
case 3: // 速度3,较快
duty[0] += 5;
if (duty[0] > 100) // 如果占空比超过最大值
duty[0] = 0; // 占空比归零
break;
}
if (mode > 0) // 如果模式不为0
{
uchar i;
for (i = 1; i < 8; i++) // 循环遍历后面的灯
{
duty[i] = duty[i - 1]; // 将前一个灯的占空比赋值给后一个灯
}
}
pwm_output(); // 调用PWM输出函数
}
void timer0() interrupt 1 // 定时器0中断服务函数
{
static char n; // 定义一个静态变量,用于记录PWM的状态
if (n == 0) // 如果是第一次进入中断
{
OFF; // 关闭LED灯
TH0 = (65536 - j) / 256; // 重新加载定时器0的初值,根据占空比计算低电平时间
TL0 = (65536 - j) % 256;
n = 1; // 改变状态变量
return; // 退出中断
}
if (n == 1) // 如果是第二次进入中断
{
ON; // 打开LED灯
TH0 = (65536 - k) / 256; // 重新加载定时器0的初值,根据占空比计算高电平时间
TL0 = (65536 - k) % 256;
n = 0; // 改变状态变量
return; // 退出中断
}
}