使用编译器以及仿真工具 编译器 keil5 C 51 仿真工具 Proteus 8.15 任务名称:花式点灯 硬件平台:STC89C52(仿真内可用AT89S52替代),四个独立按键,八颗LED、 矩阵键盘,根据个人情况选择添加 任务需求: 1.系统上电后(开始仿真后)八颗LED流水闪烁一次(闪烁顺序为0123456780876543210)流水灯闪烁间隔时间为200ms 2.按下按键1,LED灯全部点亮,点亮1S后,自动熄灭 3.按下按键2,LED灯持续流水灯,(流水顺序1234567876543212345678765……)闪烁间隔100ms,再次按下按键2时,流水灯停止,所有LED灯熄灭 4.按下按键3,使用定时器控制8颗LED灯,实现呼吸灯效果,要求PWM频率为500hz,占空比动态变化实现呼吸灯,呼吸灯效果不做要求(占空比范围和变化时间),但要实现亮暗的变化 5.按下按键4,8颗LED灯随机点亮并闪烁(查阅随机数函数原理) 6.按下其他功能按键时,停止当前功能的运行,执行对应功能(程序的打断)
#include <reg52.h>
#include <intrins.h>
#define uchar unsigned char
#define uint unsigned int
sbit LED1 = P1^0;
sbit LED2 = P1^1;
sbit LED3 = P1^2;
sbit LED4 = P1^3;
sbit LED5 = P1^4;
sbit LED6 = P1^5;
sbit LED7 = P1^6;
sbit LED8 = P1^7;
sbit KEY1=P3^5;
sbit KEY2=P3^4;
sbit KEY3 = P3^3;
sbit KEY4 = P3^2;
bit Direct_flag = 0; //LED的呼吸方向的开关
bit LED_flag = 0; //LED工作状态的标志
/****全局变量****/
uchar flag = 0; // 定义标志变量,控制流水灯的循环
uchar cnt = 0; // 定义计数变量,控制流水灯的速度
uchar i = 0; // 定义循环变量,控制流水灯的顺序
unsigned int PWM_wanttime=0; //想要多长时间改变的占空比一次
unsigned int Breath_wanttime=0; //想要多长时间改变呼气或者吸气的值时间
unsigned int PWM_value = 0; //占空比的大小
unsigned char led_num = 0;//用于存储当前随机点亮的LED灯的编号
unsigned char last_led_num = 0;//用于存储上一次随机点亮的LED灯的编号
/****函数声明****/
void T1init();
void KeyScan();
uchar GetRandomLED();//随机生成函数声明
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
void Timer0_Init()
{
TMOD = 0x01; // 设置定时器工作方式为方式1
TH0 = (65536 - 20000) / 256; // 设置定时器初值,定时20ms
TL0 = (65536 - 20000) % 256;
ET0 = 1; // 开启定时器中断
EA = 1; // 开启总中断
}
void T1init()
{
TMOD |= 0x10; //设置定时器为工作方式1
TH1=0XFC; //1ms定时,装入初值
TL1=0X66;
ET1 = 1; //开定时器的中断
TR1 = 1; //开定时器
EA = 1; //开总中断
}
/*********************************************************
* 函数说明 :按键扫描函数
* 入口参数 :void
* 返回值 :void
*********************************************************/
void KeyScan()
{
if(KEY1 == 0)
{
delay(10);
if(KEY1 == 0)
{
P1 = 0x00;
delay(1000);
P1 = 0xff;
}
while(!KEY1);
}
if(KEY2 == 0)
{
while(!KEY2);
flag = !flag;
if(flag)
{
TR0 = 1;
}
else
{
TR0 = 0;
P1 = 0xff;
i = 0;
}
}
if(KEY3 == 0) //如果按键被按下
{
delay(10); //消抖动处理
if(KEY3 == 0) //再次确认按键是否被按下
{
while(KEY3 == 0); //等待按键释放
if(LED_flag == 0) //如果LED灯当前是关闭状态,则打开LED灯并开始呼吸效果
{
TR1 = 1; //打开定时器,开始呼吸效果
LED_flag = 1; //更新LED灯工作状态标志位
}
else if(LED_flag == 1) //如果LED灯当前是打开状态,则关闭LED灯并停止呼吸效果
{
TR1 = 0; //关闭定时器,停止呼吸效果
PWM_wanttime = 0; //清零PWM计数器
Breath_wanttime = 0; //清零呼吸计数器
PWM_value = 0; //清零PWM值
Direct_flag = 0; //重置方向标志位
P1 = 0xFF; //熄灭所有LED灯
LED_flag = 0; //更新LED灯工作状态标志位
}
}
}
//此处编写按键4的函数逻辑代码
if(KEY4 == 0) //如果按键被按下
{
delay(10); //消抖动处理
if(KEY4 == 0) //再次确认按键是否被按下
{
while(KEY4 == 0); //等待按键释放
if(last_led_num != 0) //如果之前有点亮的LED,则熄灭它
{
switch(last_led_num)
{
case 1:
LED1 = 1;
break;
case 2:
LED2 = 1;
break;
case 3:
LED3 = 1;
break;
case 4:
LED4 = 1;
break;
case 5:
LED5 = 1;
break;
case 6:
LED6 = 1;
break;
case 7:
LED7 = 1;
break;
case 8:
LED8 = 1;
break;
default:
break;
}
}
led_num = GetRandomLED(); //获取随机LED编号
switch(led_num) //根据随机LED编号点亮对应的LED灯
{
case 1:
LED1 = 0;
break;
case 2:
LED2 = 0;
break;
case 3:
LED3 = 0;
break;
case 4:
LED4 = 0;
break;
case 5:
LED5 = 0;
break;
case 6:
LED6 = 0;
break;
case 7:
LED7 = 0;
break;
case 8:
LED8 = 0;
break;
default:
break;
}
last_led_num = led_num; //保存当前点亮的LED编号
}
}
}
unsigned char GetRandomLED()
{
return (rand() % 8) + 1; //生成一个范围在1~8之间的随机数
}
void main()
{
uchar i;
Timer0_Init(); // 定时器0初始化
T1init();//定时器1初始化
for(i=0;i<8;i++)
{
P1 = ~(0x01 << i);
delay(200);
}
for(i=0;i<7;i++)
{
P1 = ~(0x40 >> i);
delay(200);
P1=0XFF;
}
while(1)
{
KeyScan(); //在主循环中调用按键扫描函数
}
}
void timer0() interrupt 1 // 定时器0中断服务函数
{
TH0 = (65536 - 20000) / 256; // 设置定时器初值,定时20ms
TL0 = (65536 - 20000) % 256;
cnt++; // 计数变量自增
if(cnt == 10) // 每隔200ms执行一次
{
cnt = 0; // 清零计数变量
if(flag) // 检查标志变量的值
{
if(i < 8)
{
P1 = ~(0x01 << i);
i++;
}
else if(i < 15)
{
P1 = ~(0x40 >> (i - 8));
i++;
}
else
{
i = 0;
}
}
}
}
void Time1(void) interrupt 3
{
if(LED_flag == 1) //如果LED灯处于打开状态,则执行呼吸效果代码
{
TH1=0XFC; //1ms定时,装入初值
TL1=0X66;
PWM_wanttime++; //改变的占空比一次的标志
Breath_wanttime++; //呼气或者吸气的时间改变的标志
if(PWM_wanttime == PWM_value) //判断是否到了点亮LED的时候
{
LED1 = 0; //点亮LED1
LED2 = 0;
LED3 = 0;
LED4 = 0;
LED5 = 0;
LED6 = 0;
LED7 = 0;
LED8 = 0;
}
if(PWM_wanttime == 10) //当前周期结束
{
//熄灭所有LED
LED1 = 1;
LED2 = 1;
LED3 = 1;
LED4 = 1;
LED5 = 1;
LED6 = 1;
LED7 = 1;
LED8 = 1;
PWM_wanttime = 0; //重新计时,去改变占空比
}
if((Breath_wanttime == 200) && (Direct_flag == 0)) //200ms 改一次占空比,占空比每次增加10%
{
Breath_wanttime = 0;
PWM_value++; //改变占空比的值
if(PWM_value == 9) //占空比更改方向
Direct_flag = 1;
}
if((Breath_wanttime == 200) && (Direct_flag == 1)) //200ms 改一次占空比,占空比每次减少10%
{
Breath_wanttime = 0;
PWM_value--; //改变占空比的值
if(PWM_value == 1) //占空比更改方向
Direct_flag = 0;
}
}
}
实验现象