蓝桥杯单片机第8届 电子钟

难一点的地方就是注意修改时间时数码管显示要保持不走时。两种实现方法,一是设一个标志,进入设置时不执行vRead_ds1302(),从设置退出时把设好的time写入ds1302,再允许读取ds1302。二是用另一个数组表示设置值,进入设置时把当前时间赋给该数组Save_time,设置完成后写入ds1302。这样设置时间时就算走时,改变的也是Time数组,但是我们设置状态下显示的是Save_time数组。

写的过程遇到的一些问题:数码管闪烁,设置一个count判断在设置界面按的次数,来切换不同的闪烁位置;按住与松开判断;设置时间时保存时间防止走时;显示时钟时数字有跳动原因是读取ds1302时可能被定时器打断了,可以在读取时间时EA=0关闭中断,读完再EA=1打开中断;数组元素不能用++,要用+1

main.c 

#include <STC15F2K60S2.H>
#include "onewire.h"
#include "ds1302.h"
//问题:数码管闪烁


unsigned char code smg_duanma[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
unsigned char smg_show[8];
unsigned char smg_set[8];
unsigned char Time[3];
unsigned char Save_Time[3];
unsigned char Clock[3]={0,0,0};

void vDevice_Process(unsigned char p2dat,unsigned char p0dat)
{
	P0 = p0dat;
	P2 = (P2&0x1f)|p2dat;
	P2 = (P2&0x1f)|0x00;
}

//定时器2
void Timer2Init(void)		//1毫秒@12.000MHz
{
	AUXR |= 0x04;		//定时器时钟1T模式
	T2L = 0x20;		//设置定时初值
	T2H = 0xD1;		//设置定时初值
	AUXR |= 0x10;		//定时器2开始计时
	
	EA=1;
	IE2 = IE2|0x04;
}

//读取时间  返回是16进制
void vRead_ds1302()
{
	Time[0]=Read_Ds1302_Byte(0x81);
	Time[1]=Read_Ds1302_Byte(0x83);
	Time[2]=Read_Ds1302_Byte(0x85);
}

//读取温度  返回是十进制
unsigned char temperture;
unsigned int cnt_temp; //400ms读取一次
void vRead_temperture()
{
	if(cnt_temp>=400)
	{
        cnt_temp = 0;
		temperture = rd_temperature();
	}
}

//数码管操作
unsigned char smg_mode=0; //模式0显示时间,1显示温度,2设置时间,3设置闹钟
unsigned char flash_bit=0; //闪烁的位置
unsigned int cnt_smg; // 数码管闪烁计时
bit flash;
void vSMG_Process()
{
	//显示时间
	if(smg_mode==0)
	{
		smg_show[0] = smg_duanma[Time[2]/16];
		smg_show[1] = smg_duanma[Time[2]%16];
		
		smg_show[2] = 0xbf;
		
		smg_show[3] = smg_duanma[Time[1]/16];
		smg_show[4] = smg_duanma[Time[1]%16];
		
		smg_show[5] = 0xbf;
		
		smg_show[6] = smg_duanma[Time[0]/16];
		smg_show[7] = smg_duanma[Time[0]%16];
	}
	
	//显示温度
	if(smg_mode==1)
	{
		smg_show[0] = 0xff;
		smg_show[1] = 0xff;
		
		smg_show[2] = 0xff;
		
		smg_show[3] = 0xff;
		smg_show[4] = 0xff;
		
		smg_show[5] = smg_duanma[temperture/10];
		
		smg_show[6] = smg_duanma[temperture%10];
		smg_show[7] = 0xc6;
	}
	
	//设置时间
	if(smg_mode==2)
	{
		if(flash) //亮
		{		
			smg_show[0] = smg_duanma[Save_Time[2]/10];
			smg_show[1] = smg_duanma[Save_Time[2]%10];
			smg_show[3] = smg_duanma[Save_Time[1]/10];
			smg_show[4] = smg_duanma[Save_Time[1]%10];
			smg_show[6] = smg_duanma[Save_Time[0]/10];
			smg_show[7] = smg_duanma[Save_Time[0]%10];		
		}
		
		else //灭
		{
			if(flash_bit==1)
			{
				smg_show[0] = 0xff;
				smg_show[1] = 0xff;
			}
			else  //不是让这两个数码管闪烁时保持常亮
			{
				smg_show[0] = smg_duanma[Save_Time[2]/10];
				smg_show[1] = smg_duanma[Save_Time[2]%10];
			}
			
			if(flash_bit==2)
			{
				smg_show[3] = 0xff;
				smg_show[4] = 0xff;
			}
			else
			{
				smg_show[3] = smg_duanma[Save_Time[1]/10];
				smg_show[4] = smg_duanma[Save_Time[1]%10];
			}
			
			if(flash_bit==3)
			{
				smg_show[6] = 0xff;
				smg_show[7] = 0xff;
			}
			else
			{
				smg_show[6] = smg_duanma[Save_Time[0]/10];
				smg_show[7] = smg_duanma[Save_Time[0]%10];
			}
		}
		
		smg_show[2] = 0xbf;
		smg_show[5] = 0xbf;
	}
	
	//设置闹钟
	if(smg_mode==3)
	{
		if(flash) //亮
		{		
			smg_show[0] = smg_duanma[Clock[2]/10];
			smg_show[1] = smg_duanma[Clock[2]%10];
			smg_show[3] = smg_duanma[Clock[1]/10];
			smg_show[4] = smg_duanma[Clock[1]%10];
			smg_show[6] = smg_duanma[Clock[0]/10];
			smg_show[7] = smg_duanma[Clock[0]%10];		
		}
		
		else //灭
		{
			if(flash_bit==1)
			{
				smg_show[0] = 0xff;
				smg_show[1] = 0xff;
			}
			else
			{
				smg_show[0] = smg_duanma[Clock[2]/10];
				smg_show[1] = smg_duanma[Clock[2]%10];
			}
			
			if(flash_bit==2)
			{
				smg_show[3] = 0xff;
				smg_show[4] = 0xff;
			}
			else
			{
				smg_show[3] = smg_duanma[Clock[1]/10];
				smg_show[4] = smg_duanma[Clock[1]%10];
			}
			
			if(flash_bit==3)
			{
				smg_show[6] = 0xff;
				smg_show[7] = 0xff;
			}
			else
			{
				smg_show[6] = smg_duanma[Clock[0]/10];
				smg_show[7] = smg_duanma[Clock[0]%10];
			}
		}
		
		smg_show[2] = 0xbf;
		smg_show[5] = 0xbf;
	}
}


//数码管显示
void vSMG_Display()
{
	static unsigned char i=0;
	vDevice_Process(0xc0, 0x00);
	vDevice_Process(0xe0, smg_show[i]);
	vDevice_Process(0xc0, 0x01<<i);
	i=(i+1)%8;
}

//读取按键
unsigned char Trg,Cont;  //Trg是单击,Cont是长按
void Three_Key()
{
	unsigned char ReadData = P3^0xff;
	Trg = ReadData & (ReadData ^ Cont);
	Cont = ReadData;
}

//判断按键
unsigned int cnt_key; //10ms扫描一次消抖
unsigned char key_time; //判断按了几次
unsigned char hour,min,sec;
void Judge_Key()
{
	if(cnt_key>=10)
	{
		cnt_key=0;
		Three_Key();
		
		if(Trg & 0x01) //S7
		{
			if(smg_mode==0)
			{
				smg_mode=2; //进入设置时间
				Save_Time[0]=Time[0];Save_Time[1]=Time[1];Save_Time[2]=Time[2];//保存当前时间
				Save_Time[2] = (Save_Time[2]/16*10+Save_Time[2]%16);
				Save_Time[1] = (Save_Time[1]/16*10+Save_Time[1]%16);
				Save_Time[0] = (Save_Time[0]/16*10+Save_Time[0]%16);
			}
			if(smg_mode==2)
			{
				key_time++;  //按的次数
				flash_bit++;  //要闪烁的位置
				if(key_time==4)
				{
					smg_mode=0;
					key_time=0;
					flash_bit=0;
					Write_time(Save_Time[0]/10*16+Save_Time[0]%10,Save_Time[1]/10*16+Save_Time[1]%10,Save_Time[2]/10*16+Save_Time[2]%10);//写入设置好的时间
				}
			}
		}
		if(Trg & 0x02) //S6
		{
			if(smg_mode==0)
			{
				smg_mode=3; //进入设置闹钟
			}
			if(smg_mode==3)
			{
				key_time++;
				flash_bit++;
				if(key_time==4)
				{
					smg_mode=0;
					key_time=0;
					flash_bit=0;
				}
			}
		}
		if(Trg & 0x04) //S5
		{
			if(smg_mode==2)//设置时间
			{
				switch(flash_bit)
				{
					case 1:				
						if(Save_Time[2]<23)
						{
							Save_Time[2] = Save_Time[2]+1;
						}
					break;
					case 2:
						if(Save_Time[1]<59)
						{
							Save_Time[1] = Save_Time[1]+1;
						}
					break;
					case 3:
						if(Save_Time[0]<59)
						{
							Save_Time[0] = Save_Time[0]+1;
						}
					break;
				}				
			}
			
			if(smg_mode==3)//设置闹钟
			{
				switch(flash_bit)
				{
					case 1:				
						if(Clock[2]<23)
						{
							Clock[2] = Clock[2]+1;
						}
					break;
					case 2:
						if(Clock[1]<59)
						{
							Clock[1] = Clock[1]+1;
						}
					break;
					case 3:
						if(Clock[0]<59)
						{
							Clock[0] = Clock[0]+1;
						}
					break;
				}
			}
		}
		
		if(Trg & 0x08) //S4
		{
			if(smg_mode==2)//设置时间
			{
				switch(flash_bit)
				{
					case 1:				
						if(Save_Time[2]>0)
						{
							Save_Time[2] = Save_Time[2]-1;
						}
					break;
					case 2:
						if(Save_Time[1]>0)
						{
							Save_Time[1] = Save_Time[1]-1;
						}
					break;
					case 3:
						if(Save_Time[0]>0)
						{
							Save_Time[0] = Save_Time[0]-1;
						}
					break;
				}
			}
			if(smg_mode==3)//设置闹钟
			{
				switch(flash_bit)
				{
					case 1:				
						if(Clock[2]>0)
						{
							Clock[2] = Clock[2]-1;
						}
					break;
					case 2:
						if(Clock[1]>0)
						{
							Clock[1] = Clock[1]-1;
						}
					break;
					case 3:
						if(Clock[0]>0)
						{
							Clock[0] = Clock[0]-1;
						}
					break;
				}
			}
		}
		if(Cont & 0x08)//长按S4
		{
			if(smg_mode==0)
			{
				smg_mode=1;
			}
		}
		else  //没有长按时,判断在不在模式1,在模式1下才回到模式0.如果没有这个判断会导致切换
		if(smg_mode==1)   //不到其它模式,因为没有长按时这个else是一直成立的
			{
				smg_mode=0;
			}
		}
	}
}

//闹钟
bit alarm_flag=0;
unsigned int cnt_clock;
void alarm()
{
	if((Clock[0]==Time[0])&&(Clock[1]==Time[1])&&(Clock[2]==Time[2]))
	{
		alarm_flag=1;
	}
}

void System_init()
{
	vDevice_Process(0x80,0xff);
	vDevice_Process(0xa0,0x00);
	
	Write_time(0x50,0x59,0x23);
}

unsigned char five;
void main()
{
	System_init();
	Timer2Init();
	while(1)
	{
		vSMG_Process();
		Judge_Key();
		vRead_temperture();
		if(alarm_flag==1)
		{
			if(cnt_clock<=200)
			{
				vDevice_Process(0x80,0xff);
			}
			else if(cnt_clock<=400)
			{
				vDevice_Process(0x80,0xfe);
			}
			else 
			{
				cnt_clock=0;
				five++;
				vDevice_Process(0x80,0xff);
			}
			if(five==12)
			{
				five=0;
				alarm_flag=0;
			}
		}
	}
}

void Timer2_sercive() interrupt 12
{
	cnt_key++;cnt_temp++;cnt_smg++;
	if(cnt_smg>=1000)
	{
		cnt_smg=0;
		flash = !flash;
	}
	vRead_ds1302();
	vSMG_Display();
	alarm();
	if(alarm_flag==1)
	{
		cnt_clock++;
	}
}

ds1302.c

/*
  程序说明: DS1302驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台 8051,12MHz
  日    期: 2011-8-9
*/

#include <reg52.h>
#include <intrins.h>

sbit SCK=P1^7;		
sbit SDA=P2^3;		
sbit RST = P1^3;   // DS1302复位												

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);		
 	RST=0; 
}

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_();
	return (temp);			
}

//写入时间
void Write_time(unsigned char sec,unsigned char min,unsigned char hour)
{
	Write_Ds1302_Byte(0x8e, 0x00); //关闭写保护
	Write_Ds1302_Byte(0x80, sec);
	Write_Ds1302_Byte(0x82, min);
	Write_Ds1302_Byte(0x84, hour);
	Write_Ds1302_Byte(0x8e, 0x80); //打开写保护
}

onewire.c

/*
  程序说明: 单总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台(外部晶振12MHz) STC89C52RC单片机
  日    期: 2011-8-9
*/
#include "reg52.h"

sbit DQ = P1^4;  //单总线接口

//单总线延时函数
void Delay_OneWire(unsigned int t)  //STC89C52RC
{
	t = t*12;
	while(t--);
}

//通过单总线向DS18B20写一个字节
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);
}

//从DS18B20读取一个字节
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;
}

//DS18B20设备初始化
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;
}

//获取温度
float rd_temperature(void)
{
	unsigned char low,high;
	float temp;
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0x44);
	
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0xBE);
	
	low = Read_DS18B20();
	high = Read_DS18B20();
	
	temp = ((high<<8)|low)*0.0625;
	return temp;
}





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值