电子时钟(基于51单片机)

        日程生活中,时间和温度是我们比较关心的两个量。我们通过DS1302和DS18B20这两个简单的传感器,就可以获取我们想知道的两个量。

        本次我们通过DS18B20获取当前环境温度,DS1302获取时间,8位数码管显示时间和温度。

1、8位数码管

        本次我们选择8位共阴数码管作为显示,如图1-1所示。A-DP是数据显示,1-8是位选。共阴数码管的段码如下,上一行为不带小数点,下一行为带小数点。位选为,当1接的引脚为低电平时,第一个数码管显示。

u8 code SMG_NODOT[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
u8 code SMG_DOT[10]= {0xbf,0x86,0xdb,0xcf,0x6e6,0xed,0xfd,0x87,0xff,0xef};

                                                                       图1-1

2.DS18B20

        DS18B20是一款比较常用的温度传感器,它采取单总线传输数据,接线简单,使用非常方便。但总线对时序要求是比较严格的,我们应关注其底层驱动。底层驱动代码如下(本次借鉴蓝桥杯单片机组的底层代码)。

#include <reg52.h>
#include "INTRINS.H"

sbit DQ = P1^4;

void Delay_OneWire(unsigned int t)  
{
	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;
}

3.DS1302

        DS1302是一款常用的时间芯片。它的结构也是比较简单的,一个数据引脚,一个时钟引脚,一个数据引脚。底层驱动如下( 本次借鉴蓝桥杯单片机组的底层代码)。


#include "reg52.h"
#include "INTRINS.H"

sbit RST = P1^0; 
sbit SCK = P1^1;
sbit SDA = P1^2;

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);			
}

4.总体设计,代码如下。通过按键可以切换界面,初始界面为温度界面,显示温度,2位小数(C做标志符)。之后为时分秒界面、年月日界面、星期界面(E做标志符)

/**********************************************************************
Author : sakura
Time   : 2023/4/20
***********************************************************************/
#include <reg52.h>
#include "ds1302.h"
#include "onewire.h"
#include "main.h"

void main()
{
	DS1302_Init();
	while(1)
	{
		Clock_Read();
		Temp_Read();
		display();
		key_proc();
	}
}

//温度读取函数
void Temp_Read()
{
	u8 MSB;
	u8 LSB;
	u16 TEMP;
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0x44);
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0xbe);
	LSB = Read_DS18B20();
	MSB = Read_DS18B20();
	TEMP = MSB;
	TEMP = (TEMP << 8) | LSB;    			//数据合成
	if((TEMP & 0xf8000) == 0x0000)			//正数判断
	{
		temp = TEMP * 0.0625;				//温度值(0.0625为分辨率)
		temp_symbol = 0;
	}
	else
	{
		temp = (65535-TEMP)*0.0625;
		temp_symbol = 1;
	}
	SMG_temp = temp * 100;					//数码管显示2位小数
}
void DS1302_Init()
{
	u8 i = 0;
	Write_Ds1302_Byte(0x8e,0x00);
	for (i = 0;i < 7;i++)
	{
		Write_Ds1302_Byte(WRITE[i],TIME[i]);
	}
	Write_Ds1302_Byte(0x8e,0x80);	
}
//时钟读取函数
void Clock_Read()
{
	sec =    Read_Ds1302_Byte(READ[0]);
	min =    Read_Ds1302_Byte(READ[1]);
	hour =   Read_Ds1302_Byte(READ[2]);
	day =   Read_Ds1302_Byte(READ[3]);
	month =    Read_Ds1302_Byte(READ[4]);
	week =  Read_Ds1302_Byte(READ[5]);
	year =   Read_Ds1302_Byte(READ[6]);
}
void delay(u16 t)
{
	while(t--);
}
//数码管初始化函数
void SMG_Init(u8 pos,u8 value)
{
	P2 = ~(0x01 << pos);
	P0 = value;
	delay(600);
	P2 = ~(0x01 << pos);
	P0 = 0x00;
}
void display()
{
	switch(interface)
	{
		case 0:
		{
			SMG_Init(0,0x39);
			if(temp_symbol == 0)
			{
				if(SMG_temp >= 1000)
				{
					SMG_Init(4,SMG_NODOT[SMG_temp/1000]);
				}
				SMG_Init(5,SMG_DOT[(SMG_temp%1000)/100]);
				SMG_Init(6,SMG_NODOT[(SMG_temp%100)/10]);
				SMG_Init(7,SMG_NODOT[SMG_temp%10]);
			}
			else
			{
				SMG_Init(3,0x40);
				if(SMG_temp >= 1000)
				{
					SMG_Init(4,SMG_NODOT[SMG_temp/1000]);
				}
				SMG_Init(5,SMG_DOT[(SMG_temp%1000)/100]);
				SMG_Init(6,SMG_NODOT[(SMG_temp%100)/10]);
				SMG_Init(7,SMG_NODOT[SMG_temp%10]);
			}
			break;
		}
		case 1:
		{
			SMG_Init(0,SMG_NODOT[hour >> 4]);
			SMG_Init(1,SMG_NODOT[hour & 0x0f]);
			SMG_Init(2,0x40);
			SMG_Init(3,SMG_NODOT[min >> 4]);
			SMG_Init(4,SMG_NODOT[min & 0x0f]);
			SMG_Init(5,0x40);
			SMG_Init(6,SMG_NODOT[(sec >> 4) & 0x07]);
			SMG_Init(7,SMG_NODOT[sec & 0x0f]);
			break;
		}
		
		case 2:
		{
			SMG_Init(0,SMG_NODOT[year >> 4]);
			SMG_Init(1,SMG_NODOT[year & 0x0f]);
			SMG_Init(2,0x40);
			SMG_Init(3,SMG_NODOT[month >> 4]);
			SMG_Init(4,SMG_NODOT[month & 0x0f]);
			SMG_Init(5,0x40);
			SMG_Init(6,SMG_NODOT[day >> 4]);
			SMG_Init(7,SMG_NODOT[day & 0x0f]);
			break;
		}
		
		case 3:
		{
			SMG_Init(0,0x79);
			SMG_Init(7,SMG_NODOT[week & 0x0f]);
			break;
		}
	}
}
void key_proc() 
{
	u8 time_object = 0;
	if(P32 == 0)
	{
		delay(600);
		if(P32 == 0)
		{
			while(P32 == 0);
			interface ++;
			if(interface == 4)
			interface = 0;
		}
	}
}

5.其余头文件

(1)ds1302.h

#ifndef __DS1302_H
#define __DS1302_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 );
#endif

(2)onewire.h

#ifndef __ONEWIRE_H
#define __ONEWIRE_H

unsigned char rd_temperature(void); 
bit init_ds18b20(void);
unsigned char Read_DS18B20(void);
void Write_DS18B20(unsigned char dat);
void Delay_OneWire(unsigned int t);

#endif

(3)main.h

#include <reg52.h>

#define u8 unsigned char
#define u16 unsigned int
sbit P32 = P3^2;
//数码管 0 - 9,NODOT表示无小数点,DOT表示有小数点
u8 code SMG_NODOT[10] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
u8 code SMG_DOT[10]= {0xbf,0x86,0xdb,0xcf,0x6e6,0xed,0xfd,0x87,0xff,0xef};
//ds1302 秒、分、时、日、月、周、年
u8 code READ[7] = {0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
u8 code WRITE[7] ={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
u8 TIME[7] = {0x45,0x59,0x23,0x03,0x01,0x04,0x20};
float temp = 0;      //实际温度值
u16 SMG_temp = 0;        //数码管显示值
u8 sec = 0;          //秒
u8 min = 0;          //分
u8 hour = 0;         //时
u8 week = 0;         //周
u8 day = 0;          //日
u8 month = 0;        //月
u8 year = 0;         //年
u8 interface = 0;   //界面切换
bit temp_symbol = 0; //温度正负标志   
//函数声明
void display();
void Temp_Read();
void DS1302_Init();
void Clock_Read();
void delay(u16 t);
void SMG_Init(u8 pos,u8 value);
void key_proc();

6.仿真测试

链接:https://pan.baidu.com/s/1hCZCc-i6afVDqIBIdB_b9Q?pwd=96pn 
提取码:96pn

  • 1
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

sakura(划水)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值