第九届初赛赛题除了基础的独立按键、数码管显示、继电器和蜂鸣器的控制、LED灯的控制以外,难度增加的部分体现在iic的调用,同时增加了PWM波的考点。
本解析不代表标准答案或官方答案,仅做分享。若有不足或是更好的写法,望在评论区进行指正!
基础的功能:
1、独立按键
2、数码管显示
可以独立于赛题,提前写好,适用于各类赛题,仅做修改即可。
模板部分代码与解释在第三届赛题分享中
模板代码
IIC通信(E2PROM和A/D)
链接
PWM波的输出
链接
上升沿按键
链接
第九届赛题的难度感觉有大幅度提升。要求对于定时器的控制非常熟练。由于PWM波需要用到定时器(也可以用自带的),而灯的延时闪烁以及数码管的闪烁都需要用到定时器,所以最好启用多个定时器。我这里用了定时器0和定时器1,虽然用3个或者用1个都可以实现,但是个人认为用2个较为合适,对系统整体的影响较小。
第一点就是LED灯的亮度控制,其实此处是个隐藏问题,灯的亮度控制是由PWM波来间接控制的(原理可以自行了解),100Hz以上的PWM波可以控制灯的亮度,太低的话就看不到效果了,太高的话对系统整体影响比较大。
第二点是上升沿开关的问题。题目要求按下S4的时候显示亮度等级,松开的时候数码管全息,该要求跟第八届赛题一样,可以参考第八届赛题解析
第三点是题目要求存储每一种模式下的间隔长度,与第四届赛题相似,需要先初始化一遍函数(这里写的初始化函数为init() )之后将这个函数注释掉再写入一次单片机,即可保存数据。
第四点是MM模式的问题。该题我选择了MM模式进行编写。该模式的致命缺点是,只能写独立键盘,如果题目要求用矩阵键盘就GG了。但是好处在于,数码管可以消隐,LED灯不会有微光,二者都非常稳定。这是存储器映射的最大好处。
代码:
#include
#include
#include
#include
#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();
}
}