基于51单片机的多功能数字时钟(仿真)

        基于51单片机的多功能数字时钟设计利用AT89C51为主控,LCD12864为显示器件,使用DS1302作为时间单元,DHT11温湿度传感器获取环境温湿度,蜂鸣器和LED作为提示器件,使用按键进行模式选择等一系列功能。

一、硬件设计

1、LCD12864

        本次设计有中文显示的需求,所以普通的LCD1602、LCD1604已经无法再满足需求,目前在仿真中还剩下两个方案,一个是利用OLED,一个是LCD12864,综合考虑51单片机的性能等各方面因素,本次设计使用LCD12864实现中文显示。在Proteus中,LCD12864叫做 AMPIRE128X64。电路如下:

2、DHT11

        DHT11是一款经典的温湿度传感器,它利用单总线节省了IO口,在实际使用中大大节省了硬件资源。Proteus中提供有DHT11,如下图:

3、DS1302

        DS1302为本次系统的时间单元器件,DS1302由于在仿真系统中,如果不设置其时间,这个DS1302的时间是会和电脑时间同步的,显然会非常方便本次项目的使用,DS1302使用 SPI 的通信协议,在实际使用中我们利用SPI读写寄存器,便可以完成时间的获取。

4、串口终端 

        由于Proteus并没有语音模块,所以这次决定使用串口终端打印中文来表示语音播报。

二、软件设计

1、硬件驱动设计

        (1)DS1302使用 SPI 协议进行驱动,通过对年、月、日、时、分、秒的寄存器的读寄存器进行读操作,便可以方便的获得其值,参考代码如下:

DS1302.c

#include <REGX52.H>
sbit DS1302_SCLK=P1^0;
sbit DS1302_IO=P1^1;
sbit DS1302_CE=P1^2;
//Write:
#define DS1302_SECOND  0x80
#define DS1302_MINUTE  0x82
#define DS1302_HOUR    0x84
#define DS1302_DATA    0x86
#define DS1302_MONTH   0x88
#define DS1302_DAY     0x8a
#define DS1302_YEAR    0x8c
#define DS1302_WP      0x8e

char DS1302_Time[]={22,1,24,20,01,40,1}; 
void DS1302_Init()
{
	DS1302_CE=0;
	DS1302_SCLK=0;
}	
void DS1302_WriteByte(unsigned char Command,Data)
{
	unsigned char i;
	DS1302_CE=1;
	for(i=0;i<8;i++)
	{
		DS1302_IO=Command&(0x01<<i);
		DS1302_SCLK=1;
		DS1302_SCLK=0;
	}
	for(i=0;i<8;i++)
	{
		DS1302_IO=Data&(0x01<<i);
		DS1302_SCLK=1;
		DS1302_SCLK=0;
	}
	DS1302_CE=0;	
}	
unsigned char DS1302_ReadByte(unsigned char Command)
{
	unsigned char i,Data=0x00;
	Command|=0x01;
	DS1302_CE=1;
	for(i=0;i<8;i++)
	{
		DS1302_IO=Command&(0x01<<i);
		DS1302_SCLK=0;
		DS1302_SCLK=1;
	}
	for(i=0;i<8;i++)
	{
		DS1302_SCLK=1;
		DS1302_SCLK=0;
		if(DS1302_IO){Data|=(0x01<<i);}
	 }
	DS1302_IO=0;
	DS1302_CE=0;

	return Data;
}	
void DS1302_SetTime()
{
	DS1302_WriteByte(DS1302_WP,0x00);
	DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);
	DS1302_WriteByte(DS1302_MONTH,DS1302_Time[1]/10*16+DS1302_Time[1]%10);
	DS1302_WriteByte(DS1302_DATA,DS1302_Time[2]/10*16+DS1302_Time[2]%10);
	DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);
	DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);
	DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);
	DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);
	DS1302_WriteByte(DS1302_WP,0x80);
}	

void DS1302_ReadTime()
{
	unsigned char temp;
	temp=DS1302_ReadByte(DS1302_YEAR);
	DS1302_Time[0]=temp/16*10+temp%16;
	temp=DS1302_ReadByte(DS1302_MONTH);
	DS1302_Time[1]=temp/16*10+temp%16;
	temp=DS1302_ReadByte(DS1302_DATA);
	DS1302_Time[2]=temp/16*10+temp%16;
	temp=DS1302_ReadByte(DS1302_HOUR);
	DS1302_Time[3]=temp/16*10+temp%16;
	temp=DS1302_ReadByte(DS1302_MINUTE);
	DS1302_Time[4]=temp/16*10+temp%16;
	temp=DS1302_ReadByte(DS1302_SECOND);
	DS1302_Time[5]=temp/16*10+temp%16;
	temp=DS1302_ReadByte(DS1302_DAY);
	DS1302_Time[6]=temp/16*10+temp%16;
}	

DS1302.h

#ifndef __DS1302_H__
#define __DS1302_H__

extern char DS1302_Time[];
void DS1302_Init();
void DS1302_WriteByte(unsigned char Command,Data);
unsigned char DS1302_ReadByte(unsigned char Command);
void DS1302_ReadTime();
void DS1302_SetTime();

#endif

        LCD12864有两个CS引脚,分别控制着显示左边、右边两个部分,所以在程序运行时候,也可以看到,LCD1602会左右依次向下显示,直到显示完最后一行。LCD12864代码如下:

LCD12864.c

#include "12864.h"
#include "ziku.h"

void Delay_ms(unsigned int xms)  //@11.0592MHz
{
  unsigned int i,j;
	  for(i=xms;i>0;i--)    
		for(j=112;j>0;j--);  
}

static void LCD12864_Write(bit COM_Data,unsigned char  dat)  //12864操作函数 
{
  LCD12864_RS=COM_Data;   //指令 0 数据 1
	LCDData_Pro=dat;        //数据传输至P0扣
	LCD12864_EN=1;          //置1
	_nop_();
	LCD12864_EN=0;          //置0   产生下降沿
}

void LCD12864_Init(void)   //12864初始化
{
	Delay_ms(300);   //等待系统上电稳定
/******************************************************************************/
  LCD12864_EN=1;                       
  LCD12864_RS=1;                       
	LCD12864_CS1=1;  //仿真 0 实物 1   
	LCD12864_CS2=1;  //仿真 0 实物 1   
	Delay_ms(10);
/******************************************************************************/
	LCD12864_Write(LCD12864_COM,0x3f);   //开显示
	/*
	LCD12864_Write(LCD12864_COM,0xc0);   //这段不写也可以正常显示
	LCD12864_Write(LCD12864_COM,0xb8);
	LCD12864_Write(LCD12864_COM,0x40);
	*/
	LCD12864_Write(LCD12864_COM,0x30);   //打开基本指令
	LCD_Clear();                         //清屏
}
/*****************************************************************************
函数功能:清平函数
入口参数:空
说    明:清空整个屏幕数据
版    本:V1.0
时    间:2020年5月9日
*****************************************************************************/
void LCD_Clear(void)
{
	unsigned char  i,j; 
#if LCD_Mode
  LCD12864_CS1=1;   //选中左半屏
	LCD12864_CS2=1;   //选中右半屏
#else 
  LCD12864_CS1=0;   //选中左半屏
	LCD12864_CS2=0;   //选中右半屏
#endif
	LCD12864_Write(LCD12864_COM,0xc0);  //行
  for(i=0;i<8;i++)
	{
	  LCD12864_Write(LCD12864_COM,0xb8+i); //页
		for(j=0;j<64;j++)
		{
		  LCD12864_Write(LCD12864_COM,0x40+j); //列
			LCD12864_Write(LCD12864_DATA,0x00);
			Delay_ms(5);    //方便看清屏效果
		}
	}
}
/*****************************************************************************
函数功能:地址写入函数
入口参数:X,Y
说    明:根据地址自动切换左、右屏
版    本:V1.0
时    间:2020年5月9日
*****************************************************************************/
void LCD12864_X_Y(unsigned char X,unsigned char Y)
{
  Y=Y&0x7f;   //限定范围,列不能超过127     
	X=X&0x07;	  //限定范围,行不能超过7
	if(Y<64)
	{
#if LCD_Mode
		 LCD12864_CS1=1;   //选中左半屏
		 LCD12864_CS2=0;	 //关闭右半屏
#else
		 LCD12864_CS1=0;   //选中左半屏
		 LCD12864_CS2=1;	 //关闭右半屏
#endif
		 LCD12864_Write(LCD12864_COM,0x40+Y);  //选择列基地址+Y 一共64行
		 if(Y==63) Y=64;
	}
	else
	{
#if LCD_Mode
	  LCD12864_CS1=0;   //关闭左半屏
		LCD12864_CS2=1;	  //选中右半屏
#else
    LCD12864_CS1=1;   //关闭左半屏
		LCD12864_CS2=0;	  //选中右半屏
#endif
		Y&=0x3f;
	  LCD12864_Write(LCD12864_COM,0x40+Y);  //选择列基地址+Y   一共64列
	}
	  LCD12864_Write(LCD12864_COM,0xb8+X);  //选择页基地址+X   一共7页  
}
/*****************************************************************************
函数功能:6*16数值写入函数
入口参数:X,Y,num,*dat
说    明:X_横坐标 Y_纵坐标 num_数组的第num个数 *day_需要显示的数组
版    本:V1.5
修改时间:2022年7月10日
新    增:可实现跨左右屏
*****************************************************************************/
void LCD12864_Write_Number(unsigned char X,unsigned char Y,unsigned char num,unsigned char *dat)
{
	unsigned char  i; 
  for(i=0;i<6;i++)                
	{
	
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值