今天终于有空可以写第八届省赛的题目解析了,第八届(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();
	}
}

最后,有什么写的不好的地方,还希望大家指正,或者有更好的意见和想法都可以讨论。

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐