第十三届蓝桥杯赛前的一点总结
Posted 是七喜呀!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了第十三届蓝桥杯赛前的一点总结相关的知识,希望对你有一定的参考价值。
比赛最主要的实现功能,需要关注各个部分之间的逻辑!
赛前的一点总结
LED
整个工程中LED和数码管,按键部分其实是最主要的部分,往年省赛涉及部分也是相对较多的。
- 点亮L1
sbit L1 = P0^0;
void led_1()
P2 = (P2 & 0x1f) | 0x80;
L1 = 0;
- L1隔0.1s闪烁
#define uchar unsigned char
sbit L1 = P0^0
bit flag_L1;
void Timer0Init(void); //50毫秒@12.000MHz
void led_1()
if (flag_L1)
P2 = (P2 & 0x1f) | 0x80;
L1 = 0;
else
P2 = (P2 & 0x1f) | 0x80;
L1 = 1;
void timer0() interrupt 1
static uchar i1;
if (++i1 == 2)
i1 = 0;
flag_L1 = !flag_L1;
void Timer0Init(void) //50毫秒@12.000MHz
AUXR &= 0x7F; //定时器时钟12T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xB0; //设置定时初值
TH0 = 0x3C; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
EA = 1;
数码管
- 注意消隐和小数点处理
#define uchar unsigned char
uchar tab[] = 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff
//0 ~ 9 数码管熄灭
void Delay1ms(); //1ms@12.000MHz,延时1ms用于给足数码管足够显示时间
void dsp_smg_bit1(uchar pos, val, sta)
P2 = (P2 & 0x1f) | 0x80;
P0 = 1 << (pos - 1);
P2 = (P2 & 0x1f) | 0x80;
if (sta)//小数点
P0 = tab[val] & 0x7f;
else
P0 = tab[val];
Delay1ms();//给足显示时间
P0 = 0xff;//消隐
P2 &= 0x1f;
独立按键
- 先调到BTN模式
正常处理按键
sbit S7 = P3^0;
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;
void key_handle()
if (!S7)
delay_k(15);//灵敏度更高就消抖时间短一些
if (!S)
whlie(!S)
display();
ps:这部分处理按键
//跟S7实现一样
if (!S6)
....
if (!S5)
....
if (!S4)
....
长按键功能–规定秒数
- S7长按时间超过1s判断为长按键,否则为短按
sbit S7 = P3^0;
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;
#define uint unsigned int
bit pre_flag;//长按键标志,0为判断时间结束,1为判断开始
uint pre_cnt;//计算按下去多久
//这里利用定时器 定时1ms进入中断(ps:当然你也可以定时其他的时间)
void Timer0Init(void) //1毫秒@12.000MHz
...
//中断服务函数
void timer0() interrupt 1
if (pre_flag)//开始判断
pre_cnt++;
void key_handle()
if (!S7)
delay_k(15);//灵敏度更高就消抖时间短一些
if (!S7)
pre_flag = 1;
whlie(!S7)
display();
pre_flag = 0;
if (pre_cnt > 1000)//大于1s
...长按键操作
else
...短按键操作
//还有一点重要的是,清零!
pre_cnt = 0;
//跟S7实现一样
if (!S6)
....
if (!S5)
....
if (!S4)
....
长按键功能–不规定秒数
if (!S7)
delay_k(15);//灵敏度更高就消抖时间短一些
if (!S7)
if (1 == jm)
...界面1的操作
if (2 == jm)//界面2操作长按为显示其他内容,短按或者按完不按处于其他界面
while(!S7)//长按为显示其他内容
dsp_other();
whlie(!S7)/短按或者按完不按处于其他界面
display();
矩阵按键
- 模式选择KBD
4 * 4 矩阵按键
#define uchar unsigned char
void key_scanf()
uchar i;
P44 = P42 = P35 = P34 = 1;//初始化列线拉高
for (i = 0; i < 4; i++)
P3 |= 0x0f;//行初始化拉高,列线不变
P3 &= ~(1 << i);//从上往下依次拉低行线
if (!P44)//该行第一个键
delay_k(20);
if (!P44)
while(!P44)
display();
key_val = 4 * i + 1;
break;
剩下三个键类似
void key_handle()
key_scanf();
通过key_val做出按键处理
2 * 2 矩阵按键
- 与4 * 4类似,对应初始化某两条列线先拉高。
- 需要for循环就控制i的初始值,不需要就除了需要判断的那一行拉低,另一行拉高,判断拉低的行的两个按键,对应哪一列为低
四个按键对应于左下角四个键s5 s4 s9 s8
void key_handle()
P32 = P44 = P42 = 1;
P33 = 0;
if (!P44)//s4
delay_k(20);
if (!P44)
while(!P44)
display();
对应处理按键操作
斜按键操作
P34 = 1;
P33 = 0, P30 = 1, P31 = 1, P32 = 1;//其他行默认低电平,所以我们将其拉高
if(!P34)//s17
delay_k(10);
if(!P34)
if (2 == jm)
if (--para_temp < 10)//参数操作 + 参数检查
para_temp = 10;
if (1 == jm)
while(!P34)//s17的长按键操作
rd_time();
dsp_min_sec();
while(!P34)
display();
NE555频率测量
①NE555频率测量,要把跳线帽接在P34和SIGNAL上,使用完之后记得把跳线帽摘下来,不然就会影响矩阵按键,因为矩阵按键第4列也接在P34上
②改变Rb3可以改变输出的频率值
uint cnt_freq, curr_freq;
void timer0() interrupt 1
cnt_freq++;
void timer1() interrupt 3
static uchar i1 = 0;
if (++i1 == 20)//1s
i1 = 0;
curr_freq = cnt_freq;
cnt_freq = 0;
void sys_init()
TMOD = 0x04; //设置定时器模式,定时器0--计数器模式,定时器1--定时器模式
TL0 = 0xff;
TH0 = 0xff;//来一个脉冲就溢出计数一次
TR0 = 1;
//50ms
TL1 = 0xB0; //设置定时初值
TH1 = 0x3C; //设置定时初值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET0 = 1;
ET1 = 1;
EA = 1;
ADC
通过pcf8591读数据,省赛中一般不会太搞人心态的,记住下方模板即可。
- 从pcf8591读数据
#define uchar unsigned char
uchar rd_pcf8591(uchar addr)
uchar da;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(addr);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
da = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
return da;
需要注意的是,由于pcf8591读取电压读取的为上一次的值,当我们连续从某多个通道读取数据时,每次调用时我们需要读取两次,这样才能保证数据的正确性。
#define uchar unsigned char
float v_val;
uchar rd_pcf8591(uchar addr)
uchar da;
uchar i;
for (i = 0; i < 2; i++)
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(addr);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
da = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
return da;
//255.0是小数,整个表达式被强制类型转换为浮点数,最后赋值给浮点数v_val
v_val = rd_pcf8591(0x03) * 5 / 255.0;
DAC
切换成为DAC输出模式,允许 DAC, 使用ADC 通道 0,最后注意需要延时5ms
void dac_pcf8591(uchar da)
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x40); //DAC输出模式,允许 DAC, ADC 通道 0
IIC_WaitAck();
IIC_SendByte(da);
IIC_WaitAck();
IIC_Stop();
Delay5ms();
eeprom
省赛中一般就是对eeprom进行读写,也都是固定的代码模块,需要留意的是,为了保证一个完整的写入周期,我们需要延时5ms
- 写eeprom
#define uchar unsigned char
#define uint unsigned int
void write_eeprom(uchar addr, da)
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(addr);
IIC_WaitAck();
IIC_SendByte(da);
IIC_WaitAck();
IIC_Stop();
Delay5ms();
- 读eeprom
#define uchar unsigned char
#define uint unsigned int
uchar rd_eeprom(uchar addr)
uchar da;
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(addr);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0xa1);
IIC_WaitAck();
da = IIC_RecByte();
IIC_SendAck(1);
IIC_Stop();
return da;
DS18B20
省赛中一般对温度进行保留小数或者读取整数的操作,也是几乎固定的模板
- 读取整数
#define uchar unsigned char
uchar rd_temp()
uchar l, h, t;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
l = Read_DS18B20();
h = Read_DS18B20();
t = (h << 4);
t |= (l >> 4);
return t;
- 读取带小数的温度
#define uchar unsigned char
#define uint unsigned int
float rd_temp()
uchar l, h;
uint t;
float temp;
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0x44);
init_ds18b20();
Write_DS18B20(0xcc);
Write_DS18B20(0xbe);
l = Read_DS18B20();
h = Read_DS18B20();
t = (h & 0x0f);
t <<= 8;
t |= l;
temp = t * 0.0625;
return temp;
DS1302
省赛中一般仅仅使用秒、分、时,使用过程中主要就是需要注意,由于ds1302芯片存储的数据是BCD码,所以我们要进行BCD码与十进制之间的转换,例如0x16 的BCD码为16,十进制为1 * 16 + 6 = 32。
我个人是将这两者之间的转换放到官方给的底层代码中完成的,这样做的好处就是,我们在main.c中,只需要使用十进制,表示时间即可。
- 读时间
unsigned char Read_Ds1302_Byte ( unsigned char address )
unsigned char i,temp=0x00;
RST=0; _nop_();
SCK=0; _nop_();
RST=1; _nop_();
Write_Ds1302(address);
for (i=0;i<8;i++)
SCK=0;
temp>>=1;
if(SDA)
temp|=0x80;
SCK=1;
RST=0; _nop_();
SCK=0; _nop_();
SCK=1; _nop_();
SDA=0; _nop_();
SDA=1; _nop_();
temp = temp / 16 * 10 + temp % 16;
return (temp);
- 写时间
void Write_Ds1302_Byte( uns以上是关于第十三届蓝桥杯赛前的一点总结的主要内容,如果未能解决你的问题,请参考以下文章
《蓝桥杯真题》:2021单片机省赛第二场(第十二届第二场)暨第十三届蓝桥杯赛前模拟试题
《蓝桥杯真题》:2021单片机省赛第二场暨第十三届蓝桥杯赛前模拟试题