蓝桥杯单片机第九届初赛程序设计——“彩灯控制器”设计任务书

综述

第九届初赛赛题除了基础的独立按键、数码管显示、继电器和蜂鸣器的控制、LED灯的控制以外,难度增加的部分体现在iic的调用,同时增加了PWM波的考点。

本解析不代表标准答案或官方答案,仅做分享。若有不足或是更好的写法,望在评论区进行指正!

模板搭建

基础的功能:
1、独立按键
2、数码管显示

可以独立于赛题,提前写好,适用于各类赛题,仅做修改即可。

模板部分代码与解释在第三届赛题分享中 模板代码

程序设计

E2PROM和A/D

IIC通信(E2PROM和A/D) 链接

灯的亮度控制(PWM波)

PWM波的输出 链接

上升沿按键

上升沿按键 链接

系统设计

第九届赛题的难度感觉有大幅度提升。要求对于定时器的控制非常熟练。由于PWM波需要用到定时器(也可以用自带的),而灯的延时闪烁以及数码管的闪烁都需要用到定时器,所以最好启用多个定时器。我这里用了定时器0和定时器1,虽然用3个或者用1个都可以实现,但是个人认为用2个较为合适,对系统整体的影响较小。

第一点就是LED灯的亮度控制,其实此处是个隐藏问题,灯的亮度控制是由PWM波来间接控制的(原理可以自行了解),100Hz以上的PWM波可以控制灯的亮度,太低的话就看不到效果了,太高的话对系统整体影响比较大。

第二点是上升沿开关的问题。题目要求按下S4的时候显示亮度等级,松开的时候数码管全息,该要求跟第八届赛题一样,可以参考第八届赛题解析

第三点是题目要求存储每一种模式下的间隔长度,与第四届赛题相似,需要先初始化一遍函数(这里写的初始化函数为init() )之后将这个函数注释掉再写入一次单片机,即可保存数据。

第四点是MM模式的问题。该题我选择了MM模式进行编写。该模式的致命缺点是,只能写独立键盘,如果题目要求用矩阵键盘就GG了。但是好处在于,数码管可以消隐,LED灯不会有微光,二者都非常稳定。这是存储器映射的最大好处。

代码:

#include <stc15f2k60s2.h>
#include <intrins.h>
#include <iic.h>
#include <absacc.h>

#define uchar unsigned char

uchar keyPressFlag[4] = {0, 0, 0, 0};
uchar keyPress[4] = {0, 0, 0, 0};

uchar code shapeOfNum[11] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0xbf};
uchar numGrp[8] = {11, 0, 5, 0, 0, 0, 0, 0};

uchar LEDMod1[8] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f};
uchar LEDMod2[8] = {0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe};
uchar LEDMod3[8] = {0x7e, 0xbd, 0xdb, 0xe7, 0x7e, 0xbd, 0xdb, 0xe7};
uchar LEDMod4[8] = {0xe7, 0xdb, 0xbd, 0x7e, 0xe7, 0xdb, 0xbd, 0x7e};

uchar LED = 0x00;
uchar count = 0, lev = 0;
uchar sysMod = 0, LMod = 0;
uchar lightMod[4] = {0, 1, 2, 3};
uchar LEDGrp = 0;
int t = 0;
int cou = 0, tobu = 0;

uchar inte[4] = {4, 4, 4, 4};

void Delay5ms(){
	unsigned char i, j;

	i = 54;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}

void Delay1ms(){
	unsigned char i, j;

	_nop_();
	_nop_();
	_nop_();
	i = 11;
	j = 190;
	do
	{
		while (--j);
	} while (--i);
}

void openP2(uchar num){
	P2 &= 0x1f;
	P2 |= (num << 5);
}

void keyScan(){
	uchar i;
	for(i = 0; i < 4; i ++) keyPress[i] = 0;
	if((P3 & 0x0f) != 0x0f){
		Delay5ms();
		if((P3 & 0x0f) != 0x0f){
			switch(P3 & 0x0f){
				case 0x0e:keyPressFlag[0] = 1;break;
				case 0x0d:keyPressFlag[1] = 1;break;
				case 0x0b:keyPressFlag[2] = 1;break;
				case 0x07:keyPressFlag[3] = 1;break;
			}
		}
	}
	for(i = 0; i < 4; i ++){
		if(keyPressFlag[i] != 0){
			if((P3 & 0x0f) == 0x0f){
				keyPress[i] = 1;
				keyPressFlag[i] = 0;
			}
		}
	}
}

void showNum(){
	uchar i;
	for(i = 0; i < 8; i ++){
		if(numGrp[i] != 11){	
			XBYTE[0xc000] = (0x01 << i);
			XBYTE[0xe000] = shapeOfNum[numGrp[i]];
			Delay1ms();		
		}
		else Delay1ms();
	}
	XBYTE[0xc000] = 0x00;
}


uchar ADRead(uchar add){
	uchar dat;
	IIC_Start();
	IIC_SendByte(0x90);
	IIC_WaitAck();
	IIC_SendByte(add);
	IIC_WaitAck();
	IIC_Stop();
	
	IIC_Start();
	IIC_SendByte(0x91);
	IIC_WaitAck();
	dat = IIC_RecByte();
	IIC_WaitAck();
	IIC_Stop();
	
	return dat;
}

uchar E2PROMRead(uchar add){
	uchar dat;
	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
	IIC_SendByte(add);
	IIC_WaitAck();
	IIC_Stop();
	
	IIC_Start();
	IIC_SendByte(0xa1);
	IIC_WaitAck();
	dat = IIC_RecByte();
	IIC_WaitAck();
	IIC_Stop();
	
	return dat;
}

void E2PROMWrite(uchar add, uchar dat){
	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
	IIC_SendByte(add);
	IIC_WaitAck();
	IIC_SendByte(dat);
	IIC_WaitAck();
	IIC_Stop();
}

void Timer0Init(void){
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0xCD;		//设置定时初值
	TH0 = 0xD4;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
}

void Timer1Init(void){
	AUXR |= 0x40;		//定时器时钟1T模式
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0xCD;		//设置定时初值
	TH1 = 0xD4;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
}


void timer0() interrupt 1{ //10Hz模式
	if(count == lightMod[lev]){
		//openP2(4);P0 = 0xff;openP2(0);
		XBYTE[0x8000] = 0xff;
	}
	if(count == 9){
		//openP2(4);P0 = LED;openP2(0);
		XBYTE[0x8000] = LED;
		count = 0;
	}
	else count ++;
}

void timer1() interrupt 3{ //10Hz模式
	if((t >= (inte[LEDGrp] * 100)) && (sysMod == 0)){
		t = 0;
		sysMod = 1;
		LMod = (LMod + 1) % 8;
	}
	else if(sysMod == 0) t ++;
	
	if(cou == 799){
		cou = 0;
		tobu = !tobu;
	}
	else cou ++;
}

void setLevel(uchar light){
	if(light < (255 / 4)) lev = 0;
	else if(light < (255 / 2)) lev = 1;
	else if(light < ((255 * 3) / 4)) lev = 2;
	else lev = 3;
}

void init(){
	E2PROMWrite(0x00, 4);Delay5ms();Delay5ms();Delay5ms();
	E2PROMWrite(0x01, 4);Delay5ms();Delay5ms();Delay5ms();
	E2PROMWrite(0x02, 4);Delay5ms();Delay5ms();Delay5ms();
	E2PROMWrite(0x03, 4);Delay5ms();Delay5ms();Delay5ms();
}

void main(){
	uchar i;
	uchar mod = 0, preMod = 2;
	uchar sysLED = 0;
	P2 = 0xa0;P0 = 0x00;
	P2 = 0x80;P0 = 0xff;
	Timer0Init();
	Timer1Init();
	//init();//E2PROM初始化写入,第一次运行的时候调用,第二次运行的时候注释掉
	EA = 1;ET0 = 0;ET1 = 1;
	while(1){
		keyScan();
		setLevel(ADRead(0x03));
		if(keyPress[0] == 1){
			if(sysLED == 0){
				Timer0Init();ET0 = 1;
				sysLED = 1;
			}
			else{
				ET0 = 0;
				openP2(4);P0 = 0xff;openP2(0);
				sysLED = 0;
			}
		}
		if(sysMod == 1){
			sysMod = 0;
			switch(LEDGrp){
				case 0:LED = LEDMod1[LMod];break;
				case 1:LED = LEDMod2[LMod];break;
				case 2:LED = LEDMod3[LMod];break;
				case 3:LED = LEDMod4[LMod];break;
			}
		}
		if(mod == 0){
			if(preMod == 2){
				for(i = 0; i < 4; i ++) inte[i] = E2PROMRead(i);
				preMod = 0;                                                                                                      
			}
			numGrp[0] = 11;
			numGrp[1] = 11;
			numGrp[2] = 11;
			numGrp[3] = 11;
			numGrp[4] = 11;
			numGrp[5] = 11;
			numGrp[6] = 11;
			numGrp[7] = 11;
			if(keyPressFlag[3] == 1){
				numGrp[6] = 10;
				numGrp[7] = lev + 1;
			}
			if(keyPress[1] == 1){
				mod = 1;
			}
		}
		else if(mod == 1){
			if(preMod == 0){
				preMod = 1;
			}
			numGrp[0] = 10;
			numGrp[1] = LEDGrp + 1;
			numGrp[2] = 10;
			numGrp[3] = 11;
			numGrp[4] = inte[LEDGrp] / 10;
			numGrp[5] = inte[LEDGrp] % 10;
			numGrp[6] = 0;
			numGrp[7] = 0;
			if(tobu == 0){
				numGrp[0] = 11;
				numGrp[1] = 11;
				numGrp[2] = 11;
			}
			if(keyPress[2] == 1){
				LMod = 0;
				LEDGrp = (LEDGrp + 1) % 4;
			}
			if(keyPress[3] == 1){
				LMod = 0;
				if(LEDGrp == 0) LEDGrp = 3;
				else LEDGrp --;
			}
			if(keyPress[1] == 1) mod = 2;
		}
		else{
			if(preMod == 1){
				preMod = 2;
			}
			numGrp[0] = 10;
			numGrp[1] = LEDGrp + 1;
			numGrp[2] = 10;
			numGrp[3] = 11;
			numGrp[4] = inte[LEDGrp] / 10;
			numGrp[5] = inte[LEDGrp] % 10;
			numGrp[6] = 0;
			numGrp[7] = 0;
			if(tobu == 0){
				numGrp[4] = 11;
				numGrp[5] = 11;
				numGrp[6] = 11;
				numGrp[7] = 11;
			}
			if(keyPress[2] == 1){
				if(inte[LEDGrp] < 12) inte[LEDGrp] ++;
			}
			if(keyPress[3] == 1){
				if(inte[LEDGrp] > 0) inte[LEDGrp] --;
			}
			if(keyPress[1] == 1){
				for(i = 0; i < 4; i ++){
					E2PROMWrite(i, inte[i]);
					Delay5ms();Delay5ms();Delay5ms();
				}
				mod = 0;
			}
		}
		showNum();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值