感悟
今年的蓝桥杯单片机难吗,不是很难,但注重细心。一分付出,一分收获。今年我有幸参加了第十二届的比赛,但因为自己操作不当,优化代码的过程中删了定时器,没在主函数删了调用函数,导致已经完成的大厦轰然倒塌。自己也很难受,但没办法,希望看到文章的你们不要犯这种低级问题。
Emmmm…,不过后来拿了省一,挺意外的。
新手上路
基础部分的内容,推荐大家去看小蜜蜂老师的视频,讲的很好,网址: https://www.xmf393.com/2019/06/11/2019061103.
学习思路
以下是我的学习思路
首先:先学会LED、蜂鸣器、继电器、按键、数码管、数码管位选、串口等基本操作。
其次:ds1302,ds18b20,eeprom(24C02),PCF8591等。
然后:PWM呼吸灯,DA(因为我刚开始一直没找到)、超声波。
最关键的是一定要做省赛题!实操很重要!
赛题链接:https://pan.baidu.com/s/1ULZzd9nSA8l21VQQiDYvuQ .
提取码:1234
一些需要注意的点!!
LED
首先要说的是LED灯,比如第10届省赛题目中,如果单独点亮LED,会出现原先没有定义的灯跟着一起亮,我的解决方法如下
1 2 3 4 5 6 7 8 9 10 11 12 13
| void led() { unsigned char key1,key2,key3,key4; if(s4_stat == 0) key1 = 0x01; else if(s4_stat == 1) key1 = 0x02; if((dat_sz>=0&&dat_sz<150)||(dat_sz>=250&&dat_sz<350)) key2 = 0x04; else key2 = 0x00; if(dat_f>=0&&dat_f<1000||dat_f>=5000&&dat_f<10000) key3 = 0x08; else key3 = 0x00; if(DA_dy == 103) key4 = 0x10; else key4 = 0x00; P2 = (P2 & 0x1f) | 0x80;P0 = ~(key1|key2|key3|key4);P2 = 0x00; }
|
延迟delay
本来不想单独拿出来讲的,实在是初学者这里出问题的太多了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| void delay(unsigned char t) { while(t--); }
void delay(unsigned int t) { while(t--); }
void delay(unsigned char t) { while(t--) {数码管显示} }
|
按键消抖
有时候题目会让你只加1,但你按了按键会出现加的好多,这里推荐一种解决方法
1 2 3 4 5 6 7 8 9
| if(key == 0) { delay(100); if(key == 0) { 相关操作; while(key == 0){数码管操作;} } }
|
矩阵按键
我参考的B站一位UP主,写的很好,这里用的是reg52
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| sbit P42 = P4^2; sbit P44 = P4^4; unsigned char key_value; void scan_key() { P3 = 0x0f;P42 = 0;P44 = 0; if(P3 != 0x0f) { delay(100); if(P3 != 0x0f) { switch(P3) { case 0x0e:key_value = 0;break; case 0x0d:key_value = 4;break; case 0x0b:key_value = 8;break; case 0x07:key_value = 12;break; } P3 = 0xf0;P42 = 1;P44 = 1; switch(P3) { case 0xe0:key_value += 3;break; case 0xd0:key_value += 2;break; } if(P42 == 0) { key_value += 1; } while(P3 != 0xf0); while(P42 != 1); while(P44 != 1); } } }
|
DS13B20
关于ds13b20读取温度,onewire里面的延迟都要增大10-12倍。特别注意的就是,蜜蜂老师那的temp是16位的,LSB、MSB是8位的,还有就是老师那的delay(700)是unsigned int的而不是unsigned char,要特别注意一下。两位小数的读法我建议大家去找找相关内容看看,以免考到。
IIC
IIC这一块除了DA输出,其他没啥可说的,DA输出参考代码如下(只需要这样然后主函数调用就行,接着你去拿万用表测J3的D/A与GND两个位置就可以得到差不多的数值):
1 2 3 4 5 6 7 8 9 10 11
| void write_DA() { IIC_Start(); IIC_SendByte(0x90); IIC_WaitAck(); IIC_SendByte(0x40); IIC_WaitAck(); IIC_SendByte(DA_dy1); IIC_WaitAck(); IIC_Stop(); }
|
还有一个点就是应答和非应答。
PWM
有些小伙伴可能学了很久都没搞懂PWM是怎么搞的,我举个例子。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| unsigned char count,time,pwm_duty,led_light; void Init() { TMOD = 0x01; TH0 = (65536 - 100) / 256; TL0 = (65536 - 100) % 256; TR0 = 1; ET0 = 1; EA = 1; }
void 函数名() interrupt 1 { TH0 = (65536 - 100) / 256; TL0 = (65536 - 100) % 256; count++; if(count <= pwm_duty) {P2 = (P2 & 0x1f) | 0x80;P0 = 0xfe;P2 = 0x00;} else if(count < 10) {P2 = (P2 & 0x1f) | 0x80;P0 = 0xff;P2 = 0x00;} else {count = 0;time++;P2 = (P2 & 0x1f) | 0x80;P0 = 0xfe;P2 = 0x00;} } void pwm() { if(time == 5) { time = 0; if(led_light == 0) if(pwm_duty == 10) pwm_duty = 10,led_light = 1; else pwm_duty++; else if(led_light == 1) if(pwm_duty == 0) pwm_duty = 0,led_light = 0; else pwm_duty--; } }
|
首先我们要的是小灯缓慢亮0.5s,缓慢灭0.5s,先定义一个100us的定时器,先经过count走了10次后,time++了,五次后也就是count加了50次(换算也就是50ms),然后led灯会变一次pwm_duty,也就是小灯的亮度,总共要变10次,也就是0.5s,达到效果。
IO和MM模式
省赛我还没看到要求用MM模式的,大多数都是要求IO模式,最好都学一下,MM模式比IO模式多用一个absacc.h的头文件。
结尾
希望看到这篇文章的你,不会和我刚考完一样,感觉自己的付出和回报不成正比,自己的心态很受打击。当我知道没删那个的时候,我当时人直接懵了,手机也摔地上碎屏了,自己付出了很多,和老师与陪自己一起走过来经常交流的赛友们学到了很多,但最后因为一个很小的问题导致这样,自己真的完全接受不了。不过人生总有得有失吧,唉,大家国赛加油!
最后记得根据题目意思交压缩包,而不是只交了一份hex文件!!!
最后,青山不改,碧水长流