【蓝桥杯真题—02】第九届省赛程序设计题--彩灯控制器

【题目要求】

1.基本功能描述

通过单片机控制8个LED指示灯按照特定的顺序(工作模式)亮灭;指示灯的流转间隔可通过按键调整,亮度可由电位器RB2进行控制;各工作模式的流转间隔时间需在E2PROM中保存,并可在硬件重新上电后,自动载入。

2.设计说明
  • <1> 关闭蜂鸣器、继电器等与本试题程序设计无关的外设资源。
  • <2> 设备上电后默认数码管、LED指示灯均为熄灭状态。
  • <3> 流转间隔可调整范围为400ms-1200ms。
  • <4> 设备固定安照模式1、模式2、模式3、模式4的次序循环往复运行。
3.LED指示灯工作模式
  • <1> 模式1:按照L1、L2…L8的顺序,从左到右单循环点亮。

  • <2> 模式2:按照L8、L7…L1的顺序,从右到左单循环点亮。

  • <3> 模式3:
    在这里插入图片描述

  • <4> 模式4:
    在这里插入图片描述

4.亮度等级控制

检测电位器RB2的输出电压,控制8个LED指示灯的亮度,要求在0V~5V的可调区间内,实现4个均匀分布的LED指示灯亮度等级。

5.按键功能
  • <1> 按键S7定义为"启动/停止"按键,按下后启动或停止LED的流转。
  • <2> 按键S6定义为"设置"按键,按键按下后数码管进入"流转间隔"设置界面,如下图所示:
    在这里插入图片描述
  • <3> 按键S5定义为"加"按键,在设置界面下,按下该键,若当前选择的是运行模式,则运行模式编号加1,若当前选择的是流转间隔,则流转间隔增加100ms。
  • <4> 按键S4定义为"减"按键,在设置界面下,按下该键,若当前选择的是运行模式,则运行模式编号减1,若当前选择的是流转间隔,则流转间隔减少100ms。
  • <5> 按键S4、S5的"加"、"减"功能只在"设置状态"下有效,数值的调整应注意边界属性。
  • <6> 在非"设置状态"下,按键S4按键可显示指示灯当前的亮度等级,4个亮度等级从暗到亮,依次用数字1、2、3、4表示;松开按键S4,数码管显示关闭,亮度等级的显示格式如下图所示:
    在这里插入图片描述
#include <STC15F2K60S2.H>
#include <absacc.h>
#include <IIC.H>
unsigned char Read_AIN3();
void Write_24c02(unsigned char addr,unsigned char dat);
unsigned char Read_24c02(unsigned char dat);

sbit s7=P3^0; //启动/停止"按键,按下后启动或停止LED的流转。
sbit s6=P3^1; //S6定义为"设置"按键,按键按下后数码管进入"流转间隔"设置界面
sbit s5=P3^2; //S5定义为"加"按键
sbit s4=P3^3; //S4定义为"减"按键

unsigned char table[]={
    
    0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff};
unsigned char dat_rb2;		//保存电位器rb2的电压
unsigned int count=0;		//长定时计数变量
unsigned int count_smg=0;	//数码管闪烁计数变量
unsigned int time_m[4];		//四个模式的流转间隔时间数组
unsigned char stat=0;		//彩灯当前状态
unsigned char mode=1;		//彩灯工作模式
unsigned char mode_s6=1;	//彩灯设置模式
unsigned char pwm_duty=20;	//pwm的脉宽
unsigned char t_pwm=0;		//pwm的计数变量
unsigned char level=0;		//彩灯亮度等级
unsigned char dat_led=0;	//彩灯当前的工作参数
unsigned char f_set=0;		//按键s6的状态切换变量
unsigned char f_open=0;     //启动与停止变量
unsigned char f_t800=0;		//0.8秒时间间隔标志

void LED_Working(); //声明彩灯模式变换函数
/*===============================================数码管=================================================*/
void delaysmg(unsigned int n)
{
    
    
	while(n--);
}
void displaysmg_bit(unsigned char pos,unsigned char value)
{
    
    
	XBYTE[0xe000]=0xff;
	XBYTE[0xc000]=0x01<<pos;
	XBYTE[0xe000]=value;
}
void displaysmg_off()
{
    
    
	XBYTE[0xc000]=0xff;
	XBYTE[0xe000]=0xff;
}

/*========================================显示彩灯亮度等级============================================*/
void display_level()
{
    
    
	displaysmg_bit(0,0xff);
	delaysmg(100);
	displaysmg_bit(1,0xff);
	delaysmg(100);
	displaysmg_bit(2,0xff);
	delaysmg(100);
	displaysmg_bit(3,0xff);
	delaysmg(100);
	displaysmg_bit(4,0xff);
	delaysmg(100);
	displaysmg_bit(5,0xff);
	delaysmg(100);
	displaysmg_bit(6,table[10]);
	delaysmg(100);
	displaysmg_bit(7,table[level]);
	delaysmg(100);
	displaysmg_bit(7,0xff);
	delaysmg(100);
}

/*=======================================显示彩灯运行模式设置函数=======================================*/
void display_mode()
{
    
    
	if(f_t800==0)	//0.8秒闪烁,表示选中
	{
    
    
		displaysmg_bit(0,table[10]);
		delaysmg(100);
		displaysmg_bit(1,table[mode_s6]);
		delaysmg(100);
		displaysmg_bit(2,table[10]);
		delaysmg(100);
	}
	else 
	{
    
    
		displaysmg_bit(0,0xff);
		displaysmg_bit(1,0xff);
		displaysmg_bit(2,0xff);
	}
	if(time_m[mode_s6-1]/1000!=0)
	{
    
    
		displaysmg_bit(4,table[time_m[mode_s6-1]/1000]);
	}
	delaysmg(100);
	displaysmg_bit(5,table[(time_m[mode_s6-1]%1000)/100]);
	delaysmg(100);
	displaysmg_bit(6,table[0]);
	delaysmg(100);
	displaysmg_bit(7,table[0]);
	delaysmg(100);
}

/*=======================================显示彩灯流转间隔的设置函数=======================================*/
void display_time()
{
    
    
	displaysmg_bit(0,table[10]);
	delaysmg(100);
	displaysmg_bit(1,table[mode_s6]);
	delaysmg(100);
	displaysmg_bit(2,table[10]);
	delaysmg(100);
	if(f_t800==0)	//0.8秒闪烁,表示选中
	{
    
    
		if(time_m[mode_s6-1]/1000!=0)
		{
    
    
			displaysmg_bit(4,table[time_m[mode_s6-1]/1000]);
		}
		delaysmg(100);
		displaysmg_bit(5,table[(time_m[mode_s6-1]%1000)/100]);
		delaysmg(100);
		displaysmg_bit(6,table[0]);
		delaysmg(100);
		displaysmg_bit(7,table[0]);
		delaysmg(100);
	}
	else 
	{
    
    
		displaysmg_bit(4,0xff);
		displaysmg_bit(5,0xff);
		displaysmg_bit(6,0xff);
		displaysmg_bit(7,0xff);
	}
}

/*=========================================初始化定时器0的函数=========================================*/
void InitTimer0()
{
    
    
	TMOD=0X01;
	TH0=(65536-1000)/256;	//定时1ms
	TL0=(65536-1000)%256;
	
	ET0=1;
	EA=1;
	TR0=1;
}
/*=========================================定时器0中断服务函数=========================================*/
void ServiceTimer0() interrupt 1
{
    
    
	TH0=(65536-1000)/256;
	TL0=(65536-1000)%256;
	t_pwm++;   //产生PWM信号,控制灯光亮度
	if(t_pwm<pwm_duty)
		XBYTE[0X8000]=dat_led;
	else if(t_pwm<20)
		XBYTE[0X8000]=0XFF;
	else 
	{
    
    
		XBYTE[0X8000]=dat_led;
		t_pwm=0;
		LED_Working();	//彩灯工作模式控制
	}
	count++;
	if(count==time_m[mode-1]) //流转间隔处理
	{
    
    
		count=0;
		if(f_open==1)
  			stat++;
		if(stat==25)
		    stat=0;
	}
	
	count_smg++;
	if(count_smg==800) //0.8秒间隔定时
	{
    
    
		count_smg=0;
		f_t800=~f_t800;
	}
}

/*=========================================RB2电压彩灯亮度控制函数=========================================*/
void level_change()
{
    
    
	if(dat_rb2<60)
	{
    
    
		pwm_duty=5;
		level=1;
	}
	else if(dat_rb2<120)
	{
    
    
		pwm_duty=10;
		level=2;
	}
	else if(dat_rb2<180)
	{
    
    
		pwm_duty=15;
		level=3;
	}
	else
	{
    
    
		pwm_duty=20;
		level=4;
	}
}

/*=======================================彩灯的四种工作模式变化函数========================================*/
void LED_Working()
{
    
    
	switch(stat)
	{
    
    
	    //模式1的彩灯变化
		case 0:dat_led=0xff; break;
		case 1:dat_led=0xfe; break;
		case 2:dat_led=0xfc; break;
		case 3:dat_led=0xf8; break;
		case 4:dat_led=0xf0; break;
		case 5:dat_led=0xe0; break;
		case 6:dat_led=0xc0; break;
		case 7:dat_led=0x80; break;
		case 8:dat_led=0x00; break;
		//模式二的彩灯变化
		case 9:dat_led=0x7f; break;
		case 10:dat_led=0x3f; break;
		case 11:dat_led=0x1f; break;
		case 12:dat_led=0x0f; break;
		case 13:dat_led=0x07; break;
		case 14:dat_led=0x03; break;
		case 15:dat_led=0x01; break;
		case 16:dat_led=0x00; break;
		//模式三的彩灯变化
		case 17:dat_led=0x7e; break;
		case 18:dat_led=0xbd; break;
		case 19:dat_led=0xdb; break;
		case 20:dat_led=0xe7; break;
		//模式四的彩灯变化
		case 21:dat_led=0xe7; break;
		case 22:dat_led=0xdb; break;
		case 23:dat_led=0xbd; break;
		case 24:dat_led=0x7e; break;

		//四种工作模式的循环切换
		if(stat==0)
		{
    
    
			mode=1;
		}
		else if(stat==9)
		{
    
    
			mode=2;
		}
		else if(stat==17)
		{
    
    
			mode=3;
		}
		else if(stat==21)
		{
    
    
			mode=4;
		}
	}
}

/*==========================================按键扫描与处理函数===========================================*/
void scan_keys()
{
    
    
	if(s7==0)
	{
    
    
		delaysmg(100);
		if(s7==0)
		{
    
    
			if(f_open==0)  //启动彩灯变化
			{
    
    
				f_open=1;
			}
			else  //停止彩灯变化
			{
    
    
				f_open=0;
				f_set=0;
				stat=0;
				mode=1;
			}
			while(s7==0);
		}
	}
	if(s6==0)
	{
    
    
		delaysmg(100);
		if(s6==0)
		{
    
    
			f_set++;     
			while(s6==0)
			{
    
    
				if(f_set==1)
				{
    
    
					display_mode();
				}
				else if(f_set==2)
				{
    
    
					display_time();
				}
			}
		}
	}
	if(s5==0)
	{
    
    
		delaysmg(100);
		if(s5==0)
		{
    
    
			if(f_set==1)
			{
    
    
				mode_s6+=1;//模式加1
				if(mode_s6>4) //边界处理
				{
    
    
					mode_s6=4;
				}
				while(s5==0)
				{
    
    
					display_mode();
				}
			}
			else if(f_set==2)
			{
    
    
				time_m[mode_s6-1]+=100; //流转间隔加100
				if(time_m[mode_s6-1]>1200)
				{
    
    
					time_m[mode_s6-1]=1200;
				}
				while(s5==0)
				{
    
    
					display_time();
				}
			}
		}
	}
	if(s4==0)
	{
    
    
		delaysmg(100);
		if(s4==0)
		{
    
    
			if(f_set==1)
			{
    
    
				mode_s6-=1; //模式减一
				if(mode_s6<1)
				{
    
    
					mode_s6=1;
				}
				while(s6==0)
				{
    
    
					display_mode();
				}
			}
			else if(f_set==2)
			{
    
    
				time_m[mode_s6-1]-=100; //流转间隔减100
				if(time_m[mode_s6-1]<400)
				{
    
    
					time_m[mode_s6-1]=400;
				}
				while(s4==0)
				{
    
    
					display_time();
				}
			}
			else if(f_set==0)
			{
    
    
				while(s4==0)
				{
    
    
					display_level();
					LED_Working();
				}
			}
		}
	}
}

/*===============================================================================*/
unsigned char Read_AIN3() //通道3:可调电阻Rb2控制
{
    
    
    unsigned dat;
	//进行写操作,选择电位器AIN3,通道3
	IIC_Start(); 
	IIC_SendByte(0x90);	 ///PCF8591的写设备地址
	IIC_WaitAck();       
	IIC_SendByte(0x03); //写入PCF8591的控制字节
	IIC_WaitAck();
	IIC_Stop();

	//进行读操作,通道3
	IIC_Start();
	IIC_SendByte(0x91);	 //PCF8591的读设备地址
	IIC_WaitAck();
	dat=IIC_RecByte(); //读取PCF8591通道1的数据 
	IIC_Ack(0);	         //产生非应答信号
	IIC_Stop();
	return dat;
}
/*===============================================================================*/
void Write_24c02(unsigned char addr,unsigned char dat)
{
    
    
	IIC_Start(); 
	IIC_SendByte(0xa0);	 //24c02的写设备地址
	IIC_WaitAck();
	IIC_SendByte(addr);	 //24c02的内存字节,即将数据写在哪一个内存地址
	IIC_WaitAck();
	IIC_SendByte(dat);	 //写入目标数据
	IIC_WaitAck();	     
	IIC_Stop();
}
/*===============================================================================*/
unsigned char Read_24c02(unsigned char dat)
{
    
    
	unsigned char temp;
	//先进行一个伪写操作
	IIC_Start();
	IIC_SendByte(0xa0); //写设备地址
	IIC_WaitAck();
	IIC_SendByte(dat);

	//进行读字节
	IIC_Start();
	IIC_SendByte(0xa1); //写设备地址
	IIC_WaitAck();
	temp=IIC_RecByte(); 
	IIC_Ack(0); //产生一个非应答信号
	IIC_Stop();
	return temp;
}
/*=======================================运行模式与流转间隔参数保存========================================*/
void sava_config()
{
    
    
	switch(mode_s6)
	{
    
    
		case 1:Write_24c02(0x01,time_m[0]/10);break;
		case 2:Write_24c02(0x02,time_m[1]/10);break;
		case 3:Write_24c02(0x03,time_m[2]/10);break;
		case 4:Write_24c02(0x04,time_m[3]/10);break;
	}
	delaysmg(1000); //等待数据写入到24c02完成
	displaysmg_off();
	mode_s6=1;
	f_set=0;
}

/*=======================================系统初始化函数========================================*/
void init_system()
{
    
    
	XBYTE[0XA000]=0X00;
	displaysmg_off();
	dat_led=0xff;//彩灯当前状态

	time_m[0]=Read_24c02(0x01)*10; //读取模式1的流转间隔
	time_m[1]=Read_24c02(0x02)*10; //读取模式2的流转间隔
	time_m[2]=Read_24c02(0x03)*10; //读取模式3的流转间隔
	time_m[3]=Read_24c02(0x04)*10; //读取模式4的流转间隔
	InitTimer0();
}
 
/*========================================主函数==========================================*/
void main()
{
    
    
	init_system();
	while(1)
	{
    
    
		scan_keys();
		dat_rb2=Read_AIN3();
		level_change();
		switch(f_set)
		{
    
    
			case 1: display_mode(); break;
			case 2: display_time(); break;
			case 3: sava_config(); break;
		}
	}
}

猜你喜欢

转载自blog.csdn.net/z3447643805/article/details/114176123