【利用51单片机的定时器功能产生PWM信号来实现流水呼吸灯。(蓝桥杯常考PWM)】

        

题目要求:

      [1] 上电开机运行时,关闭蜂鸣器和继电器,L4和L5点亮,其余LED灯熄灭。

      [2] 点按独立按键S4松开后,开始控制CT107D板上的L1-L8八个LED小灯进行每隔1秒的呼吸流水点亮,即:L1缓慢亮->L1缓慢灭->L2缓慢亮->L2缓慢灭....L8缓慢亮->L8缓慢灭->L1缓慢亮->L1缓慢灭....循环往复。

      [3] 再次点按独立按键S4松开后,控制CT107D板上的LED灯从当前灯开始逆向呼吸流水。即:比如当前的流水是L2缓慢灭->L3缓慢亮,按下S4按键松开后,L3缓慢灭->L2缓慢亮->L2缓慢灭->L1缓慢亮->L1缓慢灭->L8缓慢亮->L8缓慢灭....循环往复。

      [4] 每个LED灯,缓慢点亮0.5秒,缓慢熄灭0.5秒。

      [5] 按下独立按键S4时,当前LED灯暂停流水变化并保持现有亮度,直至按键松开后,亮度才开始变化。待当前的亮度变化完成后,才开始调整呼吸流水的方向。

      [6] 按下独立按键S7时,在数码管上显示当前LED灯的位置和PWM信号占空比,松开后,数码管熄灭。在最左边的1位数码管显示LED灯的位置,在最右边的2位数码管显示PWM信号的占空比。例如:当前点亮L6灯光,PWM信号的占空比为30%,在数码管最左边的1位显示“6”,在最右边的2位数码管显示“30”,其余的数码管熄灭。

      [7] 按下独立按键S7时,当前LED灯暂停流水变化并保持现有亮度,直至按键松开后,亮度才开始变化。

注:仅题目要求转自小蜜蜂老师原创文章,代码是自己编写。

#include "STC15F2K60S2.h"
#include "absacc.h"
 
sbit S7 = P3^0;
sbit S4 = P3^3;
unsigned char led_lev ;//LED的亮度等级
unsigned char comp = 1 ;//亮灭时间比较
unsigned char times = 0;//中断的次数
unsigned char ZF = 0;//灭到亮还是亮到灭的判断
unsigned char led_move = 0;//第几个灯亮
unsigned char keys4_times = 0;//判断按键S4按了几次
unsigned int k = 0;//用来记录中断次数从而判断是否下一个灯开始呼吸闪烁
unsigned char m,v;//记录当前灯所处的位置

//*********************数码管显示初始配置
void DelaySMG(unsigned int t)
{
	while(t--);
}

unsigned char code SMG_duanma[18]=
		{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
		 0x88,0x80,0xc6,0xc0,0x86,0x8e,0xbf,0x7f};
 

 
void DisplaySMG_Bit(unsigned char pos, unsigned char value)
{
	XBYTE[0xE000] = 0xff;
	XBYTE[0xC000] = 0x01 << pos;
	XBYTE[0xE000] = value;
}
//**********************************8

//***********************************中断初始化和中断响应函数
void Init_Timer0()
{
	TMOD = 0x01;
	TH0 = (65535 - 1000) / 256;			//定时一毫秒
	TL0 = (65535 - 1000) % 256;
	
	ET0 = 1;
	EA = 1;
	TR0 = 1;//打开中断开关,开始定时
}

void service_init() interrupt 1
{
	TH0 = (65535 - 1000) / 256;			
	TL0 = (65535 - 1000) % 256;
	if(keys4_times == 0)                            //如果S4没有按下去那么显示初始状态
	{
		XBYTE[0X8000] = 0xe7;
		return ;
	}
	k++;
	times++;
	if(ZF == 0)                                        //从灭到慢亮
	{
			if(times <=comp*5)                            //小于比较值那么点亮
			{
					if(keys4_times == 1)         //如果按下去了S4,S4处于从L1--L8的顺序亮。
					{
						XBYTE[0X8000] = ~(0X01 << led_move);   //开始点亮
						m = led_move;                          //记录当前灯的位置
						v = 7-m;                  //记录如果灯从L8---L1点亮的话当前灯的位置
					}
					else if(keys4_times == 2)       //如果第二次按了S4,那么灯将从记录的位置逆序点亮
					{
						
						XBYTE[0X8000] = ~(0x80>>v);             //开始点亮
						
					}
			}
			else if(times <= 50)                        //大于比较值那么熄灭
			{
				XBYTE[0X8000] = 0xff;
			}
			
			if(times == 50)                             //设定一个比较周期为50次中断
			{
				times = 0;
				comp++;                                    //亮度等级加一
				if(comp == 11)                             //到达最大等级
				{
					comp  = 10;
					ZF = 1;                                   //为开始从亮到慢灭做准备
				}
			}
  }
	
	else                                            //此处的92行到133行和58到90行类似
	{
			
			if(times <=comp*5)
			{
				if(keys4_times == 1)
					{
						XBYTE[0X8000] = ~(0X01 << led_move);
					}
					else if(keys4_times == 2)
					{
						XBYTE[0X8000] = ~(0x80>>v);
						
					}
			}
			else if(times <= 50)
			{
				XBYTE[0X8000] = 0xff;
			}
			
			if(times == 50)
			{
				times = 0;
				comp--;
				if(comp == 0)
				{
					comp  = 1;
					ZF = 0;
				}
			}
	}
	
	if(k == 1000)                     //判断是否过了一秒,如果过了那么可以开始下一个灯的操作
	{
		k = 0;
		if(keys4_times == 1)
		{
			led_move++;
			if(led_move == 8)
			{
			 led_move = 0;
			}	
		}
		
		if(keys4_times == 2)
		{
			v++;
			if(v == 8)
			{
				v = 0;
			}
		}
  }
}
//*****************************

void display();
void keyscan()
{
	if(S4 == 0)
	{
		DelaySMG(100);
		if(S4 == 0)
		{
			if(keys4_times == 0)
			{
				keys4_times = 1;
			}
			  else if(keys4_times == 1)
			{
				keys4_times = 2;
			}
			else if(keys4_times == 2)
			{
				keys4_times = 1;
			}
			while(S4 == 0);
		}
	}
	
	if(S7 == 0)
	{
		DelaySMG(200);
		if(S7 == 0)
		{
			while(S7 == 0)
			{
			  display();
				TR0 = 0;                         //按下去时灯要保持状态不变,那么就要先关闭定时器
			}
			TR0 = 1;
		}
		
	}
}

void display()
{
	DisplaySMG_Bit(0, SMG_duanma[comp]);
	DelaySMG(200);
	
	DisplaySMG_Bit(1,0xff);
	DelaySMG(200);
	
	DisplaySMG_Bit(2, 0xff);
	DelaySMG(200);
	
	DisplaySMG_Bit(3, 0xff);
	DelaySMG(200);
	
	DisplaySMG_Bit(4,0xff);
	DelaySMG(200);
	
	DisplaySMG_Bit(5, 0xff);
	DelaySMG(200);
	
	DisplaySMG_Bit(6, SMG_duanma[(comp*5)/10]);
	DelaySMG(200);
	
	DisplaySMG_Bit(7, SMG_duanma[(comp*10)%10]);
	DelaySMG(200);
}

void Init_System()                                  //初始化系统
{
	XBYTE[0xA000] = 0xff;
	XBYTE[0xA000] = 0x00;
	XBYTE[0xE000] = 0xff;
	XBYTE[0xC000] = 0xff;
	
	Init_Timer0();
}

void main()
{
	Init_System();
	while(1)
	{
		keyscan();
	
	}
}

版权声明:题目为CSDN博主「小蜜蜂老师」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/ohy3686/article/details/88372244

注:仅题目要求转自小蜜蜂老师原创文章,代码是自己编写。

  • 3
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值