第八届蓝桥杯单片机省赛题目解析
今天終于有空可以寫第八屆省賽的題目解析了,第八屆(2017)總體也不算難,我們一起來看看吧。
題目
這次題目還是一樣用到了三大模塊(按鍵、LED、數碼管),還用了實時時鐘(DS1302)和DS18B20。其中DS18B20上一屆也考過。這里面的單個模塊都不難,題目也很好理解,寫題目最重要的就是自己的思路和邏輯是否正確了。
1 數碼管顯示
數碼管就只有兩種模式顯示,一種是時鐘顯示,另一種是鬧鐘顯示,分別通過按鍵s7,s6來控制。
2 LED顯示
當時鐘和鬧鐘的值一致時,L1以0.2秒為間隔閃爍持續5秒然后關閉,或者是在閃爍期間按任意鍵關閉。
3按鍵模塊
題目用到的是一個獨立按鍵,s7可以時鐘的調整時、分、秒,就可以定義一個變量mode1,當mode1為0顯示時鐘,為1時鐘的時開始以一秒為間隔閃爍,為2分開始以一秒為間隔閃爍,為3秒開始以一秒為間隔閃爍。s6定義一個變量mode2,功能和s7一樣。s5、s4就是加減,但是只有在時鐘或鬧鐘的時分秒閃爍時有用。另外s4還有一個功能在時鐘顯示界面(也就是mode1==0)按下顯示溫度,松開回到時鐘顯示界面。
4 DS18B20
?就是改寫底層驅動代碼部分(onewire),然后放在定時器里,每隔一段時間去測量一次。
?5 DS1302
也是改寫底層驅動代碼部分(SPI),然后放在定時器里,每隔一段時間去測量一次。
6 代碼
onewire.c
#include"onewire.h"sbit DQ = P1^4; void Delay_OneWire(unsigned int t) {t*=12;while(t--); }void Write_DS18B20(unsigned char dat) {unsigned char i;for(i=0;i<8;i++){DQ = 0;DQ = dat&0x01;Delay_OneWire(5);DQ = 1;dat >>= 1;}Delay_OneWire(5); }unsigned char Read_DS18B20(void) {unsigned char i;unsigned char dat;for(i=0;i<8;i++){DQ = 0;dat >>= 1;DQ = 1;if(DQ){dat |= 0x80;} Delay_OneWire(5);}return dat; }bit init_ds18b20(void) {bit initflag = 0;DQ = 1;Delay_OneWire(12);DQ = 0;Delay_OneWire(80);DQ = 1;Delay_OneWire(10); initflag = DQ; Delay_OneWire(5);return initflag; }unsigned int get_temp() {unsigned char high,low;unsigned int result;init_ds18b20();Write_DS18B20(0xcc);Write_DS18B20(0x44);init_ds18b20();Write_DS18B20(0xcc);Write_DS18B20(0xbe);low=Read_DS18B20();high=Read_DS18B20();result=(high<<8)|low;result*=6.25;return result; }onewire.h
#ifndef _ONEWIRE_H_ #define _ONEWIRE_H_#include<stc15f2k60s2.h> #include"intrins.h"void Delay_OneWire(unsigned int t); void Write_DS18B20(unsigned char dat); unsigned char Read_DS18B20(void); bit init_ds18b20(void); unsigned int get_temp();#endifds1302.c
建議讀取時鐘的數據就放在時鐘初始化的數組里,不然如果新建一個數組來放讀取時間的數據,就會出現每次在加、減時鐘的時分秒后,時鐘都會從初始化開始。
#include"ds1302.h"unsigned char Time_Init[]={50,59,23,1,1,1,1};sbit SCK=P1^7; sbit SDA=P2^3; sbit RST = P1^3; void Write_Ds1302(unsigned char temp) {unsigned char i;for (i=0;i<8;i++) { SCK=0;SDA=temp&0x01;temp>>=1; SCK=1;} } void Write_Ds1302_Byte( unsigned char address,unsigned char dat ) {RST=0; _nop_();SCK=0; _nop_();RST=1; _nop_(); Write_Ds1302(address); Write_Ds1302((dat/10<<4)|(dat%10)); RST=0; }unsigned char Read_Ds1302_Byte ( unsigned char address ) {unsigned char i,temp=0x00;unsigned char dat1,dat2;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_();dat1=temp/16;dat2=temp%16;temp=dat1*10+dat2;return (temp); }void ds1302_Init(void) {unsigned char add=0x80,i=0;Write_Ds1302_Byte( 0x8e,0x00 );for(i=0;i<7;i++){Write_Ds1302_Byte( add,Time_Init[i] );add+=2;}Write_Ds1302_Byte( 0x8e,0x80 ); }void ds1302_Read(void) {unsigned char add=0x81,i=0;Write_Ds1302_Byte( 0x8e,0x80 );for(i=0;i<7;i++){Time_Init[i]=Read_Ds1302_Byte( add );add+=2;}Write_Ds1302_Byte( 0x8e,0x80 ); }ds1302.h
#ifndef __DS1302_H #define __DS1302_H#include <STC15F2K60S2.h> #include <intrins.h>void Write_Ds1302(unsigned char temp); void Write_Ds1302_Byte( unsigned char address,unsigned char dat ); unsigned char Read_Ds1302_Byte( unsigned char address ); void ds1302_Init(void); void ds1302_Read(void); #endifinit.c
#include"init.h" #include"jm.h"#define u8 unsigned char #define u16 unsigned int #define state_0 0 #define state_1 1 #define state_2 2u8 tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff,0xc6}; u8 seg[]={11,11,11,11,11,11,11,11};static u8 segadder=0,key_state=0;extern u8 mode1,mode2,c,d; // extern表示此變量是在別處定義的,要在此處引用u8 key_num,num1,key_press;void close_init() //關閉無關外設 {P2=(P2&0x1f)|0x80;P0=0xff;P2&=0x1f;P2=(P2&0x1f)|0xa0;P04=0;P06=0;P2&=0x1f;P2=(P2&0x1f)|0xc0;P0=0x00;P2&=0x1f;P2=(P2&0x1f)|0xe0;P0=0xff;P2&=0x1f; }void Timer0Init(void) //1ms的定時器0 {AUXR |= 0x80; TMOD &= 0xF0; TL0 = 0xCD; TH0 = 0xD4; TF0 = 0; TR0 = 1; ET0 = 1;EA = 1; }void display() //數碼管顯示函數 {P2=(P2&0x1f)|0xe0;P0=0xff;P2&=0x1f; //消隱P2=(P2&0x1f)|0xc0;P0=1<<segadder;P2&=0x1f; //位選P2=(P2&0x1f)|0xe0;P0=tab[seg[segadder]];P2&=0x1f; // 段選if(++segadder==8) segadder=0; }u8 read_key() //獨立鍵盤 {key_press=P3&0x0f;switch(key_state){case state_0:if(key_press!=0x0f)key_state=state_1;break;case state_1:if(key_press!=0x0f){if((key_press & 0x08)==0){if(mode1==0&&c==0&&d==1) //在時鐘顯示界面按下顯示溫度{jm3();d=0;}key_num=4;}if((key_press & 0x04)==0) key_num=5;if((key_press & 0x02)==0) key_num=6;if((key_press & 0x01)==0) key_num=7;key_state=state_2;}elsekey_state=state_0;break;case state_2:if(key_press==0x0f){if(mode1==0&&c==0&&d==0)d=1; //松開回到時鐘顯示界面key_state=state_0;}break; }num1=key_num;key_num=0;return num1; }init.h
#ifndef _INIT_H_ #define _INIT_H_#include<stc15f2k60s2.h> #include"intrins.h"void close_init(); void Timer0Init(void); void display(); unsigned char read_key();#endifjm.c
#include"jm.h" #include"init.h" #include"onewire.h"#define u8 unsigned char #define u16 unsigned int extern u8 seg[],mode1,mode2,Time_Init[]; // extern表示此變量是在別處定義的,要在此處引用 extern u8 mode1_flag,temp_flag,mode2_flag; u8 ac[]={0,0,0}; //鬧鐘的初始值 u16 temp;void jm3() //顯示溫度 {if(temp_flag==1){temp_flag=0;temp=get_temp();}seg[0]=11;seg[1]=11;seg[2]=11;seg[3]=11;seg[4]=11;seg[5]=temp/1000;seg[6]=temp/100%10;seg[7]=12; }void jm4() {if(mode1==1){if(Time_Init[2]==0) Time_Init[2]=23;else Time_Init[2]--;}if(mode1==2){if(Time_Init[1]==0) Time_Init[1]=59;else Time_Init[1]--;}if(mode1==3){if(Time_Init[0]==0) Time_Init[0]=59;else Time_Init[0]--;}if(mode2==1){if(ac[2]==0) ac[2]=23;else ac[2]--;}if(mode2==2){if(ac[1]==0) ac[1]=59;else ac[1]--; }if(mode2==3){if(ac[0]==0) ac[0]=59;else ac[0]--;} }void jm5() {if(mode1==1){if(Time_Init[2]==23) Time_Init[2]=0;else Time_Init[2]++;}if(mode1==2){if(Time_Init[1]==59) Time_Init[1]=0;else Time_Init[1]++;}if(mode1==3){if(Time_Init[0]==0) Time_Init[0]=0;else Time_Init[0]++;}if(mode2==1){if(ac[2]==23) ac[2]=0;else ac[2]++;}if(mode2==2){if(ac[1]==59) ac[1]=0;else ac[1]++; }if(mode2==3){if(ac[0]==59) ac[0]=0;else ac[0]++;} }void jm6() {if(mode2==0) //鬧鐘顯示界面{seg[0]=ac[2]/10;seg[1]=ac[2]%10;seg[2]=10;seg[3]=ac[1]/10;seg[4]=ac[1]%10;seg[5]=10;seg[6]=ac[0]/10;seg[7]=ac[0]%10;}if(mode2==1) //時以一秒為間隔閃爍{if(mode2_flag==1){seg[0]=11;seg[1]=11;}else{seg[0]=ac[2]/10;seg[1]=ac[2]%10;}seg[2]=10;seg[3]=ac[1]/10;seg[4]=ac[1]%10;seg[5]=10;seg[6]=ac[0]/10;seg[7]=ac[0]%10;}if(mode2==2) //分以一秒為間隔閃爍{if(mode2_flag==1){seg[3]=11;seg[4]=11;}else{seg[3]=ac[1]/10;seg[4]=ac[1]%10;}seg[0]=ac[2]/10;seg[1]=ac[2]%10;;seg[2]=10;seg[5]=10;seg[6]=ac[0]/10;seg[7]=ac[0]%10;}if(mode2==3) //秒以一秒為間隔閃爍{if(mode2_flag==1){seg[6]=11;seg[7]=11;}else{seg[6]=ac[0]/10;seg[7]=ac[0]%10; }seg[0]=ac[2]/10;seg[1]=ac[2]%10;seg[2]=10;seg[3]=ac[1]/10;seg[4]=ac[1]%10;seg[5]=10;} }void jm7() {if(mode1==0) //時鐘顯示界面{seg[0]=Time_Init[2]/10;seg[1]=Time_Init[2]%10;seg[2]=10;seg[3]=Time_Init[1]/10;seg[4]=Time_Init[1]%10;seg[5]=10;seg[6]=Time_Init[0]/10;seg[7]=Time_Init[0]%10;}if(mode1==1) //時以一秒為間隔閃爍{if(mode1_flag==1){seg[0]=11;seg[1]=11;}else{seg[0]=Time_Init[2]/10;seg[1]=Time_Init[2]%10;}seg[2]=10;seg[3]=Time_Init[1]/10;seg[4]=Time_Init[1]%10;seg[5]=10;seg[6]=Time_Init[0]/10;seg[7]=Time_Init[0]%10;}if(mode1==2) //分以一秒為間隔閃爍{if(mode1_flag==1){seg[3]=11;seg[4]=11;}else{seg[3]=Time_Init[1]/10;seg[4]=Time_Init[1]%10;}seg[0]=Time_Init[2]/10;seg[1]=Time_Init[2]%10;seg[2]=10;seg[5]=10;seg[6]=Time_Init[0]/10;seg[7]=Time_Init[0]%10;}if(mode1==3) //秒以一秒為間隔閃爍{if(mode1_flag==1){seg[6]=11;seg[7]=11;}else{seg[6]=Time_Init[0]/10;seg[7]=Time_Init[0]%10;}seg[0]=Time_Init[2]/10;seg[1]=Time_Init[2]%10;seg[2]=10;seg[3]=Time_Init[1]/10;seg[4]=Time_Init[1]%10;seg[5]=10;} }jm.h
#ifndef _JM_H_ #define _JM_H_#include<stc15f2k60s2.h> #include"intrins.h"void jm3(); void jm4(); void jm5(); void jm6(); void jm7();#endifmain.c
#include"init.h" #include"onewire.h" #include"ds1302.h" #include"jm.h"#define u8 unsigned char #define u16 unsigned intextern u8 ac[],seg[],Time_Init[]; // extern表示此變量是在別處定義的,要在此處引用u8 num,mode1=0,mode2=0; u8 temp_count=0,ac_count=0; u8 c,d; u8 cd_flag=0,ac_flag=0,mode1_flag=0,mode2_flag=0,temp_flag=0; u16 cd_count=0,mode1_count=0,mode2_count=0,time_count=0;void main() {close_init();Timer0Init();ds1302_Init();while(1){num=read_key();switch(num){case 4:if(c==1||d==1) //在時鐘界面或者鬧鐘界面{if((mode1!=0)||(mode2!=0)) //在時鐘或者鬧鐘的時分秒{jm4();ds1302_Init();}}cd_flag=0; //當L1閃爍時按任意按鍵停止閃爍break;case 5:if(c==1||d==1){if((mode1!=0)||(mode2!=0)){jm5();ds1302_Init();}}cd_flag=0; //當L1閃爍時按任意按鍵停止閃爍break;case 6:if(++mode2==4) mode2=0;c=1,d=0;cd_flag=0; //當L1閃爍時按任意按鍵停止閃爍break;case 7:if(++mode1==4) mode1=0;c=0,d=1;cd_flag=0; //當L1閃爍時按任意按鍵停止閃爍break;}num=0;if(c==1&&d==0)jm6();if(d==1&&c==0)jm7();if((Time_Init[2]==ac[2])&&(Time_Init[1]==ac[1])&&(Time_Init[0]==ac[0]))cd_flag=1; //當cd_flag為1時L1開始閃爍if(ac_flag==1&&cd_flag==1){P2=(P2&0x1f)|0x80;P0=0xfe;P2&=0x1f; //L1亮}else{P2=(P2&0x1f)|0x80;P0=0xff;P2&=0x1f; //L1滅}} }void Timer0() interrupt 1 {display();if(++temp_count==200) //每200ms獲取一次溫度的值{temp_count=0;temp_flag=1;}if(cd_flag==1){if(++ac_count==200) //L1以0.2s開始閃爍{ac_count=0;ac_flag^=1;}if(++cd_count>=5000) //5s后L1滅{cd_count=0;cd_flag=0;}}if(mode1!=0) //不在時鐘顯示界面,時分秒以1s開始閃爍{if(++mode1_count==1000){mode1_count=0;mode1_flag^=1;}}if(mode2!=0) //不在鬧鐘顯示界面,時分秒以1s開始閃爍{if(++mode2_count==1000){mode2_count=0;mode2_flag^=1;}}if(++time_count==1000) //每秒讀取一次時間的值{time_count=0;ds1302_Read();} }最后,有什么寫的不好的地方,還希望大家指正,或者有更好的意見和想法都可以討論。
總結
以上是生活随笔為你收集整理的第八届蓝桥杯单片机省赛题目解析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: pandas保存csv乱码
- 下一篇: jconsole进行java死锁检测