今天终于有空可以写第八届省赛的题目解析了,第八届(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(); #endif
ds1302.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); #endif
init.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 2 u8
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; } else key_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(); #endif
jm.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(); #endif
main.c
#include"init.h" #include"onewire.h" #include"ds1302.h" #include"jm.h" #define
u8 unsigned char #define u16 unsigned int extern 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(); } }
最后,有什么写的不好的地方,还希望大家指正,或者有更好的意见和想法都可以讨论。

技术
下载桌面版
GitHub
Gitee
SourceForge
百度网盘(提取码:draw)
云服务器优惠
华为云优惠券
腾讯云优惠券
阿里云优惠券
Vultr优惠券
站点信息
问题反馈
邮箱:[email protected]
吐槽一下
QQ群:766591547
关注微信