用AT89S52单片机、DS1302时钟芯片、1602LCD做一个电子表 。各文件例举如下:
1、main()函数所在文件部分:
/******************************************************************************
* 说明:AT89S52芯片,12M晶振
* 外设:HD44780控制的1602LCD 和 DS1302时钟芯片
* 本程序:做一个电子时钟,显示日历,时间
* K1设置确认键,K2设置位选择键,K3设置参数减,K4设置参数加
******************************************************************************/
//#include <reg52.h>
//#include <intrins.h>
#include "DELAY_FUNCTION_FELL.h"
#include "HD44780_1602LCD.h"
#include "DS1302_SPIdriver.h"
#include "DIY_clock.h"
//用户要显示的字符串
unsigned char calendar[17] = "Data:2000-00-00" ; //calendar[i] 年:i = 7,8 月:i= 10,11 日:i=13,14
unsigned char clock_time[17] = "00:00:00" ; //clock_time[i] 时:i=0,1 分:i=3,4 秒i=6,7
/******************************************************************************
===============================================================================
void main(void)函数部分
===============================================================================
*******************************************************************************/
void main(void)
{
//1、定义相关变量
// unsigned char i ;
//2、初始化
HD44780_1602LCD_Init() ;
DS1302_Init() ;
//3、在HD44780控制的1602LCD上显示时钟信息
Clear_Screen() ;
while(1)
{
Get_Curren_Time() ; //获取当前时间
Dis_Str(0 , 1 , calendar) ;
Dis_Str(1 , 5 , clock_time) ;
User_Set_Time() ; //用户通过按键设置时间
}
}
/******************************************************************************
* 名称:
* 功能:
* 参数:
* 返回:
******************************************************************************/
2、实现电子时钟功能设置部分的函数
//DIY_clock.c
#include "DIY_clock.h"
//定义字符数组显示数字
unsigned char code digit[10]={"0123456789"};
//用户自定义的字符编码方式:在8*8的点阵中选“右上角”的“5列*7行”点阵 存放数据
//unsigned char code user_str0[] = {0x10,0x06,0x09,0x08,0x08,0x09,0x06,0x00};/* 自定义字符 ℃ */
/******************************************************************************
* 名称:Get_Curren_Time()
* 功能:获取当前时间
* 参数:无
* 返回:无
******************************************************************************/
void Get_Curren_Time(void)
{
int temp ;
temp = Read_DS1302_Year() ;
calendar[7] = digit[temp / 10] ;
calendar[8] = digit[temp % 10] ;
temp = Read_DS1302_Month() ;
calendar[10] = digit[temp / 10] ;
calendar[11] = digit[temp % 10] ;
temp = Read_DS1302_Day() ;
calendar[13] = digit[temp / 10] ;
calendar[14] = digit[temp % 10] ;
temp = Read_DS1302_Hour() ;
clock_time[0] = digit[temp / 10] ;
clock_time[1] = digit[temp % 10] ;
temp = Read_DS1302_Minute() ;
clock_time[3] = digit[temp / 10] ;
clock_time[4] = digit[temp % 10] ;
temp = Read_DS1302_Second() ;
clock_time[6] = digit[temp / 10] ;
clock_time[7] = digit[temp % 10] ;
}
/******************************************************************************
* 名称:User_Set_Time_Second()
* 功能:本地用户通过按键设置 秒位
* 参数:无
* 返回:无
******************************************************************************/
void User_Set_Time_Second(void)
{
int temp , switch_temp ;
switch_temp = 1 ; //程序停留在某一个设置为的开关
/*------按一次 K1 设置:时、分、秒-------------------*/
/*``````设置:second`````````````````````*/
temp = Read_DS1302_Second() ;
while(switch_temp)
{
if(K4 == 0) //增加 秒
{
delay1ms(15) ;
if(K4 == 0)
{
while(K4 == 0) { ; } //等待按键释放
temp++ ;
if(temp == 60)
{
temp = 0 ;
}
}
}
if(K3 == 0) //减少 秒
{
delay1ms(15) ;
if(K3 == 0)
{
while(K3 == 0) { ; } //等待按键释放
temp-- ;
if(temp == 0)
{
temp = 60 ;
}
}
}
DS1302_Set_Second(temp) ;
Get_Curren_Time() ;
Dis_Str(1 , 5 , clock_time) ;
//按 K1 键 跳出设置 秒 的循环
if(K1 == 0)
{
delay1ms(15) ;
if(K1 == 0)
{
while(K1 == 0) { ; } //等待按键释放
switch_temp = 0 ;
}
}
}
}
/******************************************************************************
* 名称:User_Set_Time_Minute()
* 功能:本地用户通过按键设置 分钟位
* 参数:无
* 返回:无
******************************************************************************/
void User_Set_Time_Minute(void)
{
int temp , switch_temp ;
switch_temp = 1 ; //程序停留在某一个设置为的开关
/*------按一次 K1 设置:时、分、秒-------------------*/
/*``````设置:minute`````````````````````*/
temp = Read_DS1302_Minute() ;
while(switch_temp)
{
if(K4 == 0) //增加 分钟值
{
delay1ms(15) ;
if(K4 == 0)
{
while(K4 == 0) { ; } //等待按键释放
temp++ ;
if(temp == 60)
{
temp = 0 ;
}
}
}
if(K3 == 0) //减少 分钟值
{
delay1ms(15) ;
if(K3 == 0)
{
while(K3 == 0) { ; } //等待按键释放
temp-- ;
if(temp == 0)
{
temp = 60 ;
}
}
}
DS1302_Set_Minute(temp) ;
Get_Curren_Time() ;
Dis_Str(1 , 5 , clock_time) ;
//按 K1 键 跳出设置 分钟 的循环
if(K1 == 0)
{
delay1ms(15) ;
if(K1 == 0)
{
while(K1 == 0) { ; } //等待按键释放
switch_temp = 0 ;
}
}
}
}
/******************************************************************************
* 名称:User_Set_Time_Hour()
* 功能:本地用户通过按键设置 分钟位
* 参数:无
* 返回:无
******************************************************************************/
void User_Set_Time_Hour(void)
{
int temp , switch_temp ;
switch_temp = 1 ; //程序停留在某一个设置为的开关
/*------按一次 K1 设置:时、分、秒-------------------*/
/*``````设置:hour`````````````````````*/
temp = Read_DS1302_Hour() ;
while(switch_temp)
{
if(K4 == 0) //增加 分钟值
{
delay1ms(15) ;
if(K4 == 0)
{
while(K4 == 0) { ; } //等待按键释放
temp++ ;
if(temp == 24)
{
temp = 0 ;
}
}
}
if(K3 == 0) //减少 分钟值
{
delay1ms(15) ;
if(K3 == 0)
{
while(K3 == 0) { ; } //等待按键释放
temp-- ;
if(temp == 0)
{
temp = 24 ;
}
}
}
DS1302_Set_Hour(temp) ;
Get_Curren_Time() ;
Dis_Str(1 , 5 , clock_time) ;
//按 K1 键 跳出设置 分钟 的循环
if(K1 == 0)
{
delay1ms(15) ;
if(K1 == 0)
{
while(K1 == 0) { ; } //等待按键释放
switch_temp = 0 ;
}
}
}
}
/******************************************************************************
* 名称:User_Set_Time_Day()
* 功能:本地用户通过按键设置 分钟位
* 参数:无
* 返回:无
******************************************************************************/
void User_Set_Time_Day(void)
{
int temp , switch_temp ;
switch_temp = 1 ; //程序停留在某一个设置为的开关
/*------按一次 K1 设置:时、分、秒-------------------*/
/*``````设置:day`````````````````````*/
temp = Read_DS1302_Day() ;
while(switch_temp)
{
if(K4 == 0) //增加 分钟值
{
delay1ms(15) ;
if(K4 == 0)
{
while(K4 == 0) { ; } //等待按键释放
temp++ ;
if(temp == 31)
{
temp = 0 ;
}
}
}
if(K3 == 0) //减少 分钟值
{
delay1ms(15) ;
if(K3 == 0)
{
while(K3 == 0) { ; } //等待按键释放
temp-- ;
if(temp == 0)
{
temp = 31 ;
}
}
}
DS1302_Set_Day(temp) ;
Get_Curren_Time() ;
Dis_Str(1 , 5 , clock_time) ;
Dis_Str(0 , 1 , calendar) ;
//按 K1 键 跳出设置 分钟 的循环
if(K1 == 0)
{
delay1ms(15) ;
if(K1 == 0)
{
while(K1 == 0) { ; } //等待按键释放
switch_temp = 0 ;
}
}
}
}
/******************************************************************************
* 名称:User_Set_Time_Month()
* 功能:本地用户通过按键设置 分钟位
* 参数:无
* 返回:无
******************************************************************************/
void User_Set_Time_Month(void)
{
int temp , switch_temp ;
switch_temp = 1 ; //程序停留在某一个设置为的开关
/*------按一次 K1 设置:时、分、秒-------------------*/
/*``````设置:month`````````````````````*/
temp = Read_DS1302_Month() ;
while(switch_temp)
{
if(K4 == 0) //增加 分钟值
{
delay1ms(15) ;
if(K4 == 0)
{
while(K4 == 0) { ; } //等待按键释放
temp++ ;
if(temp == 12)
{
temp = 0 ;
}
}
}
if(K3 == 0) //减少 分钟值
{
delay1ms(15) ;
if(K3 == 0)
{
while(K3 == 0) { ; } //等待按键释放
temp-- ;
if(temp == 0)
{
temp = 12 ;
}
}
}
DS1302_Set_Month(temp) ;
Get_Curren_Time() ;
Dis_Str(1 , 5 , clock_time) ;
Dis_Str(0 , 1 , calendar) ;
//按 K1 键 跳出设置 分钟 的循环
if(K1 == 0)
{
delay1ms(15) ;
if(K1 == 0)
{
while(K1 == 0) { ; } //等待按键释放
switch_temp = 0 ;
}
}
}
}
/******************************************************************************
* 名称:User_Set_Time_Year()
* 功能:本地用户通过按键设置 分钟位
* 参数:无
* 返回:无
******************************************************************************/
void User_Set_Time_Year(void)
{
int temp , switch_temp ;
switch_temp = 1 ; //程序停留在某一个设置为的开关
/*------按一次 K1 设置:时、分、秒-------------------*/
/*``````设置:year`````````````````````*/
temp = Read_DS1302_Year() ;
while(switch_temp)
{
if(K4 == 0) //增加 分钟值
{
delay1ms(15) ;
if(K4 == 0)
{
while(K4 == 0) { ; } //等待按键释放
temp++ ;
if(temp == 99)
{
temp = 0 ;
}
}
}
if(K3 == 0) //减少 分钟值
{
delay1ms(15) ;
if(K3 == 0)
{
while(K3 == 0) { ; } //等待按键释放
temp-- ;
if(temp == 0)
{
temp = 99 ;
}
}
}
DS1302_Set_Year(temp) ;
Get_Curren_Time() ;
Dis_Str(1 , 5 , clock_time) ;
Dis_Str(0 , 1 , calendar) ;
//按 K1 键 跳出设置 分钟 的循环
if(K1 == 0)
{
delay1ms(15) ;
if(K1 == 0)
{
while(K1 == 0) { ; } //等待按键释放
switch_temp = 0 ;
}
}
}
}
/******************************************************************************
* 名称:User_Set_Time()
* 功能:本地用户通过按键设置时钟日历
* 参数:无
* 返回:无
******************************************************************************/
void User_Set_Time(void)
{
int temp , switch_temp ;
int set_bit = 0 ;
/*------1、按一次 K1 键,进入设置环节------------------------------*/
if(K1 == 0)
{
delay1ms(15) ; //按键消抖
if(K1 == 0)
{
while(K1 == 0) { ; } //等待按键释放
/*------2、按 K2 键,通过设置num,确定设置的是时钟的哪一位---*/
switch_temp = 1 ;
while(switch_temp)
{
//将set_bit打印到1602lcd上,判断要设置哪一位时钟信息
Dis_Char(1,0,'F') ;
Dis_Char(1,1,digit[set_bit]) ;
Dis_Char(1,2,':') ;
if(K2 == 0)
{
delay1ms(10) ;
if(K2 == 0)
{
delay1ms(7) ;
if(K2 == 0)
{
while(K2 == 0) { ; } //等待按键释放
set_bit++ ;
if(set_bit == 6)
{
set_bit = 0 ;
}
}
}
}
//按 K1 跳出设置num的循环
if(K1 == 0)
{
delay1ms(15) ;
if(K1 == 0)
{
while(K1 == 0) { ; } //等待按键释放
switch_temp = 0 ;
}
}
}
/*------3、根据 set_bit 的值调用不同的函数,对时钟进行设置---*/
switch(set_bit)
{
case 0 ://设置second位
User_Set_Time_Second() ;
break;
case 1 ://设置minute位
User_Set_Time_Minute() ;
break;
case 2 ://设置hour位
User_Set_Time_Hour() ;
break;
case 3 ://设置day位
User_Set_Time_Day() ;
break;
case 4 ://设置month位
User_Set_Time_Month() ;
break;
case 5 ://设置year位
User_Set_Time_Year() ;
break;
default ://其他值不设置
break;
}
}
}
/*------4、清除1602LCD屏幕上的设置标志位-----------------------------*/
Dis_Char(1,0,' ') ;
Dis_Char(1,1,' ') ;
Dis_Char(1,2,' ') ;
}
/******************************************************************************
* 名称:
* 功能:
* 参数:
* 返回:
******************************************************************************/
//DIY_clock.h
#ifndef __DIY_CLOCK_H__
#define __DIY_CLOCK_H__
#include <reg52.h>
#include <intrins.h>
#include "DELAY_FUNCTION_FELL.h"
#include "HD44780_1602LCD.h"
#include "DS1302_SPIdriver.h"
sbit K1 = P1^4 ; //User设置时间的开关
sbit K2 = P1^5 ; //设置参数,确定具体设置时钟的哪一位
sbit K3 = P1^6 ; //设置位的值递减
sbit K4 = P1^7 ; //设置位的值递增
extern unsigned char calendar[17] ;
extern unsigned char clock_time[17] ;
void Get_Curren_Time(void) ;
void User_Set_Time_Second(void) ;
void User_Set_Time_Minute(void) ;
void User_Set_Time_Hour(void) ;
void User_Set_Time_Day(void) ;
void User_Set_Time_Month(void) ;
void User_Set_Time_Year(void) ;
void User_Set_Time(void) ;
#endif
3、DS1302时钟芯片配置文件
//DS1302_SPIdriver.c
#include "DS1302_SPIdriver.h"
/*****************************************************
函数功能:向1302写一个字节数据
入口参数:x
***************************************************/
void Write1302(unsigned char dat)
{
unsigned char i;
SCLK=0; //拉低SCLK,为脉冲上升沿写入数据做好准备
delay1us(2); //稍微等待,使硬件做好准备
for(i=0;i<8;i++) //连续写8个二进制位数据
{
DATA=dat&0x01; //取出dat的第0位数据写入1302 低位在前,高位在后
delay1us(2); //稍微等待,使硬件做好准备
SCLK=1; //上升沿写入数据
delay1us(2); //稍微等待,使硬件做好准备
SCLK=0; //重新拉低SCLK,形成脉冲
dat>>=1; //将dat的各数据位右移1位,准备写入下一个数据位
}
}
/*****************************************************
函数功能:根据命令字,向1302写一个字节数据
入口参数:Cmd,储存命令字;dat,储存待写的数据
***************************************************/
void WriteSet1302(unsigned char Cmd,unsigned char dat)
{
RST=0; //禁止数据传递
SCLK=0; //确保写数居前SCLK被拉低
RST=1; //启动数据传输
delay1us(2); //稍微等待,使硬件做好准备
Write1302(Cmd); //写入命令字
Write1302(dat); //写数据
SCLK=1; //将时钟电平置于高电平状态
RST=0; //禁止数据传递
}
/*****************************************************
函数功能:从1302读一个字节数据
入口参数:x
***************************************************/
unsigned char Read1302(void)
{
unsigned char i,dat;
delay1us(2); //稍微等待,使硬件做好准备
for(i=0;i<8;i++) //连续读8个二进制位数据
{ dat>>=1;
if(DATA==1) //如果读出的数据是1
dat|=0x80; //将1取出,写在dat的最高位
SCLK=1; //将SCLK置于高电平,为下降沿读出
delay1us(2); //稍微等待
SCLK=0; //拉低SCLK,形成脉冲下降沿
delay1us(2); //稍微等待
}
return dat; //将读出的数据返回
}
/*****************************************************
函数功能:根据命令字,从1302读取一个字节数据
入口参数:Cmd
***************************************************/
unsigned char ReadSet1302(unsigned char Cmd)
{
unsigned char dat;
RST=0; //拉低RST
SCLK=0; //确保写数居前SCLK被拉低
RST=1; //启动数据传输
Write1302(Cmd); //写入命令字
dat=Read1302(); //读出数据
SCLK=1; //将时钟电平置于已知状态
RST=0; //禁止数据传递
return dat; //将读出的数据返回
}
/******************************************************************************
* 名称:DS1302_Set_Second()
* 功能:设置时钟 秒 位
* 参数:int second
* 返回:无
******************************************************************************/
void DS1302_Set_Second(int second)
{
WriteSet1302(0x8E,0x00); //根据写状态寄存器命令字,写入不保护指令
WriteSet1302(0x80,((second/10)<<4|(second%10))); //根据写秒寄存器命令字,写入秒的初始值
WriteSet1302(0x8E,0x80); //根据写状态寄存器命令字,写入保护指令
}
/******************************************************************************
* 名称:DS1302_Set_Minute()
* 功能:设置时钟 分 位
* 参数:int minute
* 返回:无
******************************************************************************/
void DS1302_Set_Minute(int minute)
{
WriteSet1302(0x8E,0x00); //根据写状态寄存器命令字,写入不保护指令
WriteSet1302(0x82,((minute/10)<<4|(minute%10))); //根据写分寄存器命令字,写入分的初始值
WriteSet1302(0x8E,0x80); //根据写状态寄存器命令字,写入保护指令
}
/******************************************************************************
* 名称:DS1302_Set_Hour()
* 功能:设置时钟 时 位
* 参数:int hour
* 返回:无
******************************************************************************/
void DS1302_Set_Hour(int hour)
{
WriteSet1302(0x8E,0x00); //根据写状态寄存器命令字,写入不保护指令
WriteSet1302(0x84,((hour/10)<<4|(hour%10))); //根据写小时寄存器命令字,写入小时的初始值
WriteSet1302(0x8E,0x80); //根据写状态寄存器命令字,写入保护指令
}
/******************************************************************************
* 名称:DS1302_Set_Day()
* 功能:设置时钟 日 位
* 参数:int day
* 返回:无
******************************************************************************/
void DS1302_Set_Day(int day)
{
WriteSet1302(0x8E,0x00); //根据写状态寄存器命令字,写入不保护指令
WriteSet1302(0x86,((day/10)<<4|(day%10))); //根据写日寄存器命令字,写入日的初始值
WriteSet1302(0x8E,0x80); //根据写状态寄存器命令字,写入保护指令
}
/******************************************************************************
* 名称:DS1302_Set_Month()
* 功能:设置时钟 月 位
* 参数:int month
* 返回:无
******************************************************************************/
void DS1302_Set_Month(int month)
{
WriteSet1302(0x8E,0x00); //根据写状态寄存器命令字,写入不保护指令
WriteSet1302(0x88,((month/10)<<4|(month%10))); //根据写月寄存器命令字,写入月的初始值
WriteSet1302(0x8E,0x80); //根据写状态寄存器命令字,写入保护指令
}
/******************************************************************************
* 名称:DS1302_Set_Weekday()
* 功能:设置时钟 星期 位
* 参数:int weekday
* 返回:无
******************************************************************************/
void DS1302_Set_Weekday(int weekday)
{
WriteSet1302(0x8E,0x00); //根据写状态寄存器命令字,写入不保护指令
WriteSet1302(0x8a,( weekday%7 )); //根据写星期寄存器命令字,写入星期的初始值
WriteSet1302(0x8E,0x80); //根据写状态寄存器命令字,写入保护指令
}
/******************************************************************************
* 名称:DS1302_Set_Year()
* 功能:设置时钟 年 位
* 参数:int year
* 返回:无
******************************************************************************/
void DS1302_Set_Year(int year)
{
WriteSet1302(0x8E,0x00); //根据写状态寄存器命令字,写入不保护指令
WriteSet1302(0x8c,((year/10)<<4|(year%10))); //根据写年寄存器命令字,写入年的初始值
WriteSet1302(0x8E,0x80); //根据写状态寄存器命令字,写入保护指令
}
/*****************************************************
函数功能: 1302进行初始化设置
***************************************************/
void DS1302_Init(void)
{
unsigned char flag;
flag= ReadSet1302(0x81);
if(flag&0x80)
{ //判断时钟芯片是否关闭
WriteSet1302(0x8E,0x00); //根据写状态寄存器命令字,写入不保护指令
WriteSet1302(0x80,((55/10)<<4|(55%10))); //根据写秒寄存器命令字,写入秒的初始值
WriteSet1302(0x82,((59/10)<<4|(59%10))); //根据写分寄存器命令字,写入分的初始值
WriteSet1302(0x84,((23/10)<<4|(23%10))); //根据写小时寄存器命令字,写入小时的初始值
WriteSet1302(0x86,((5/10)<<4|(5%10))); //根据写日寄存器命令字,写入日的初始值
WriteSet1302(0x88,((4/10)<<4|(4%10))); //根据写月寄存器命令字,写入月的初始值
WriteSet1302(0x8a,( 6%7 )); //根据写星期寄存器命令字,写入星期的初始值
WriteSet1302(0x8c,((14/10)<<4|(14%10))); //根据写年寄存器命令字,写入年的初始值
WriteSet1302(0x90,0xa5); //打开充电功能 选择2K电阻充电方式
WriteSet1302(0x8E,0x80); //根据写状态寄存器命令字,写入保护指令
}
}
/******************************************************************************
* 名称:Read_DS1302_Second()
* 功能:读DS1302的 秒 位
* 参数:无
* 返回:second
******************************************************************************/
int Read_DS1302_Second(void)
{
int second ;
unsigned char ReadValue ;
ReadValue = ReadSet1302(0x81); //从秒寄存器读数据
second=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);//将读出数据转化十进制数
return second ;
}
/******************************************************************************
* 名称:Read_DS1302_Minute()
* 功能:读DS1302的 分 位
* 参数:无
* 返回:minute
******************************************************************************/
int Read_DS1302_Minute(void)
{
int minute ;
unsigned char ReadValue ;
ReadValue = ReadSet1302(0x83); //从分寄存器读
minute = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //将读出数据转化
return minute ;
}
/******************************************************************************
* 名称:Read_DS1302_Hour()
* 功能:读DS1302的 时 位
* 参数:无
* 返回:hour
******************************************************************************/
int Read_DS1302_Hour(void)
{
int hour ;
unsigned char ReadValue ;
ReadValue = ReadSet1302(0x85); //从分寄存器读
hour = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //将读出数据转化
return hour ;
}
/******************************************************************************
* 名称:Read_DS1302_Day()
* 功能:读DS1302的 日 位
* 参数:无
* 返回:day
******************************************************************************/
int Read_DS1302_Day(void)
{
int day ;
unsigned char ReadValue ;
ReadValue = ReadSet1302(0x87); //从分寄存器读
day = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //将读出数据转化
return day ;
}
/******************************************************************************
* 名称:Read_DS1302_Month()
* 功能:读DS1302的 月 位
* 参数:无
* 返回:month
******************************************************************************/
int Read_DS1302_Month(void)
{
int month ;
unsigned char ReadValue ;
ReadValue = ReadSet1302(0x89); //从月寄存器读
month = ((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F); //将读出数据转化
return month ;
}
/******************************************************************************
* 名称:Read_DS1302_Weekday()
* 功能:读DS1302的 星期 位
* 参数:无
* 返回:weekday
******************************************************************************/
int Read_DS1302_Weekday(void)
{
int weekday ;
unsigned char ReadValue ;
ReadValue = ReadSet1302(0x81); //从星期寄存器读数据
weekday = ReadValue&0x0F ;//将读出数据转化
return weekday ;
}
/******************************************************************************
* 名称:Read_DS1302_Year()
* 功能:读DS1302的 年 位
* 参数:无
* 返回:year
******************************************************************************/
int Read_DS1302_Year(void)
{
int year ;
unsigned char ReadValue ;
ReadValue = ReadSet1302(0x8d); //从年寄存器读
year = ((ReadValue&0xf0)>>4)*10 + (ReadValue&0x0F); //将读出数据转化
return year ;
}
//DS1302_SPIdriver.h
#ifndef __SPIDRIVER_H__
#define __SPIDRIVER_H__
#include<reg52.h> //包含单片机寄存器的头文件
#include<intrins.h> //包含_nop_()函数定义的头文件
#include "DELAY_FUNCTION_FELL.h"
sbit SCLK=P1^0; //位定义1302芯片的接口,时钟输出端口定义在P1.0引脚
sbit DATA=P1^1; //位定义1302芯片的接口,数据输出端定义在P1.1引脚
sbit RST=P1^2; //位定义1302芯片的接口,复位端口定义在P1.2引脚
void Write1302(unsigned char dat) ; //向DS1302写一个字节的数据(或指令)
unsigned char Read1302(void) ; //从DS1302中读一个字节的数据
void WriteSet1302(unsigned char Cmd,unsigned char dat) ;//根据命令字,向1302写一个字节数据
unsigned char ReadSet1302(unsigned char Cmd) ; //根据命令字,从1302读取一个字节数据
void DS1302_Set_Second(int second) ; //设置秒
void DS1302_Set_Minute(int minute) ; //设置分
void DS1302_Set_Hour(int hour) ; //设置时
void DS1302_Set_Day(int day) ; //设置日
void DS1302_Set_Month(int month) ; //设置月
void DS1302_Set_Weekday(int weekday) ; //设置星期
void DS1302_Set_Year(int year) ; //设置年
void DS1302_Init(void) ; //对1302进行初始化设置
int Read_DS1302_Second(void) ;
int Read_DS1302_Minute(void) ;
int Read_DS1302_Hour(void) ;
int Read_DS1302_Day(void) ;
int Read_DS1302_Month(void) ;
int Read_DS1302_Weekday(void) ;
int Read_DS1302_Year(void) ;
#endif
4、HD44780控制的1602LCD部分的配置文件
/**************************************************************************************************
* HD44780_1602LCD配置文件名:HD44780_1602LCD.c
* 和HD44780_1602LCD.h配套使用
* 本程序当时是依据AT89S52单片机开发板写的
* RS R/W E 这三位引脚分别和单片机引脚 P2^0 P2^1 P2^2 相连
* 八位数据引脚DB0……DB7分别和单片机的P0端口的P0^0……P0^7相连 (BF位其实就对应DB7引脚和P0^7相连)
* 将此文件来驱动1602LCD时,只需更改下面的位定义和数据线的端口号即可
* 对于HD44780控制的1602LCD的详细资料和11条指令的描述参考一下连接
* http://blog.csdn.net/dragon12345666/article/details/22819827
**************************************************************************************************/
#include"HD44780_1602LCD.h"
/******************************************************************************
* 名称:Busy_Test()
* 功能:检测HD44780控制的1602LCD是否处于忙状态
* 参数:无
* 返回:bit result 忙则返回 1 , 不忙则返回 0 。
******************************************************************************/
bit Busy_Test(void)
{
//1、定义变量,存储返回值
bit result ;
//2、读状态位
RS = 0 ; RW = 1 ;
E = 1 ;
_nop_() ; _nop_() ; _nop_() ; _nop_() ; //延时4个机器周期,给硬件响应,
//即:使E=1;稳定
result = BF ; //将忙状态位BF的值读给函数要返回的变量
//3、将时能位E复位到低电平
E = 0 ;
//4、将忙状态位读的结果作为函数的参数返回
return result ;
}
/******************************************************************************
* 名称:Write_Com()
* 功能:向HD44780写控制1602LCD的控制指令
* 参数:unsigned char dictate
* 返回:无
******************************************************************************/
void Write_Com(unsigned char dictate)
{
//1、检测LCD忙状态,忙,则等待
while(Busy_Test() == 1) { ; }
//2、向HD44780控制的1602LCD写控制指令
/*----2.1、操作对象是指令,执行对象:写入----------------------------*/
RS = 0 ;
RW = 0 ;
/*----2.2、在E 为 0 时,先将指令数据写到P0口的DB0--DB7数据线上-------*/
E = 0 ;
_nop_() ; //给硬件反应时间,等待E = 0 ;稳定
_nop_() ;
P0 = dictate ; //将指令先暂时写到数据线上
_nop_() ; //确保硬件把指令数据写完了
_nop_() ;
_nop_() ;
_nop_() ;
/*----2.3、在E 为 1 时,将数据线上的指令数据写到DH44780的寄存器里----*/
E = 1 ;
_nop_(); _nop_(); _nop_(); _nop_(); //等待 E = 1 稳定
/*----2.4、在E 为 下降沿 时,执行写入的指令--------------------------*/
E = 0 ; //从 E = 1 到 E = 0 产生下降沿,HD44780执行指令
}
/******************************************************************************
* 名称:Write_Address()
* 功能:通过指令来控制第一个要显示的字符或下一个即将要显示的字符在LCD上的位置
* 参数:unsigned char addr 在LCD上要显示的位置
* 返回:无
******************************************************************************/
void Write_Address(unsigned char addr)
{
//向HD44780写指令8:设定DDRAM地址的指令。
//即:即将要显示的字符在1602LCD上的指令需要的地址 = 0x80|(字符在LCD屏幕上的位置)
Write_Com(0x80|addr) ;
}
/******************************************************************************
* 名称:Write_Data()
* 功能:1、向HD44780控制的1602LCD写要显示的字符数据;
* 2、向CGRAM中,对应地址的存储单元写用户自定义的字符数据
* 参数:unsigned char char_data 要显示的字符(其实字符的值和它的ASCII码值一样)
* 返回:无
******************************************************************************/
void Write_Data(unsigned char char_data)
{
//1、检测HD44780控制的1602LCD忙状态位,忙,则等待
while(Busy_Test() == 1) { ; }
//2、向HD44780控制的1602LCD写要显示的字符数据
/*----2.1、操作对象是数据,执行对象:写入----------------------------*/
RS = 1 ;
RW = 0 ;
/*----2.1、在E 为 0 时,先将字符数据写到P0口的DB0--DB7数据线上-------*/
E = 0 ;
_nop_() ; _nop_() ; //给硬件反应时间,等待E = 0 ;稳定
P0 = char_data ; //将字符数据先暂时写到数据线上
_nop_() ; _nop_() ; _nop_() ; _nop_() ; //确保硬件把字符数据写完了
/*----2.2、在E 为 1 时,将数据线上的字符数据写到DH44780的寄存器里----*/
E = 1 ;
_nop_(); _nop_(); _nop_(); _nop_(); //等待 E = 1 稳定
/*----2.3、在E 为 下降沿 时,执行写入的指令--------------------------*/
E = 0 ; //从 E = 1 到 E = 0 产生下降沿,HD44780执行指令
}
/******************************************************************************
* 名称:HD44780_1602LCD_Init()
* 功能:对HD44780控制的1602LCD进行初始化 (包含硬件类型,屏显,光标)
* 参数:无
* 返回:无
******************************************************************************/
void HD44780_1602LCD_Init(void)
{
//1、首次写指令前,给LCD硬件一段较长的反应时间
delay1ms(15) ;
//2、显示模式设置
/*----1、匹配硬件的设置: 指令6:8位数据线,2行显示,5*7点阵------------*/
Write_Com(0x38) ; delay1ms(5) ; //3次写指令,确保硬件匹配成功
Write_Com(0x38) ; delay1ms(5) ;
Write_Com(0x38) ; delay1ms(5) ;
/*----2、显示屏、光标、闪烁的设置: 指令4:开显示,不开光标,光标不闪烁------*/
Write_Com(0x0c) ; delay1ms(5) ;
/*----3、光标、屏幕移动的设置: 指令3:光标右移,屏幕整体不移动----------*/
Write_Com(0x06) ; delay1ms(5) ;
//3、清屏。指令1
Write_Com(0x01) ; delay1ms(5) ;
}
/******************************************************************************
* 名称:Write_User_char()
* 功能:将一个用户自定义的字符写入CGRAM中(CGRAM最多写8个字符)
* 参数:unsigned char addr_num : 存入CGRAM中的第addr_num个8字节存储块 (0--8)
* 参数:unsigned char *str : 指向存放用户自定义字符的数组
* 返回:无
******************************************************************************/
void Write_User_char(unsigned char addr_num , unsigned char *str)
{
/*----1、定义变量--------------------------------------------------------*/
unsigned char i ;
unsigned char CGRAM_addr ;
/*----2、处理地址,CGRAM存储单元有8*8==64个字节,可存入8个自定义字符-----*/
//指令7的指令码 01 xxx 000 :第一个 xxx 表示自定义字符存入 第xxx个8字节的存储空间
// 000 表示第xxx个8字节存储空间的首地址
addr_num = _crol_(addr_num,3) ;
CGRAM_addr = 0x40 | addr_num ;
/*----1、指令7:设定将自定义字符数据存入CGRAM中存储单元的地址------------*/
//指令固定值01、第n个自定义字符、存储第n个自定义字符的数组的首地址(8byte)
Write_Com(CGRAM_addr) ; //
delay1ms(5) ;
/*----2、将用户自定义的字符写入CGRAM中对应地址的存储单元中----------------*/
i = 0 ;
for(i = 0 ; i < 8 ; i++)
{
Write_Data(str[i]) ;
}
}
/******************************************************************************
* 名称:Dis_User_char()
* 功能:显示自定义字符:在1602LCD屏幕指定位置上显示第num个自定义字符
* 参数:unsigned char line , unsigned char x 在屏幕的第line行第x列显示
* 参数:unsigned char num :显示CGRAM中8个自定义字符的第num个 num = 0-->7
* 返回:无
******************************************************************************/
void Dis_User_char(unsigned char line , unsigned char x ,unsigned char num)
{
//3.2.2
/*----1、设定在1602LCD屏幕上显示的坐标位置(地址)------------*/
Write_Address(0x40 * line + x) ; //显示在第line行的第x位
delay1ms(5) ;
/*----2、将CGROM/CGRAM对应地址中的数据,显示在屏幕对应的位置---*/
Write_Data(num) ; //显示CGRAM中8个自定义字符的第num个 num = 0-->7
//和显示CGROM中数据不同之处在于:不用和0x80相与
}
/******************************************************************************
* 名称:Switch_Screen()
* 功能:控制显示屏开关,(不显示光标)
* 参数:unsigned char scr_key = 1:开 ; = 0:关
* 返回:无
******************************************************************************/
void Switch_Screen(unsigned char scr_key)
{
delay1ms(50) ;
if(scr_key == 1)
{
Write_Com(0x0c) ; //指令4 ,0000 1100 :开屏幕显示 ,无光标
}
if(scr_key == 0)
{
Write_Com(0x08) ; //指令4 ,0000 1100 :关屏幕显示
}
delay1ms(50) ;
}
/******************************************************************************
* 名称:Switch_Cursor()
* 功能:控制光标开关和闪烁
* 参数:unsigned char cursor_key
* 参数:unsigned char twinkle_key
* 返回:无
******************************************************************************/
void Switch_Cursor(unsigned char cursor_key , unsigned char twinkle_key)
{
delay1ms(50) ;
if(cursor_key == 1)
{
if(twinkle_key == 1)
{
Write_Com(0x0f) ; //指令4 ,0000 1111 :开屏幕显示,开光标,光标闪烁
}
else
{
Write_Com(0x0e) ; //指令4 ,0000 1110 :开屏幕显示 ,开光标
}
}
if(cursor_key == 0)
{
Write_Com(0x0c) ; //指令4 ,0000 1100 :开屏幕显示
}
delay1ms(50) ;
}
/******************************************************************************
* 名称:Move_Screen()
* 功能:控制屏幕整体左右移动
* 参数:unsigned char r_l = 1 :右移 ; = 0 :左移
* 参数:unsigned char move_bit_num :屏幕向右或向左移动多少位
* 参数:unsigned char move_delay :每移动一位后,延时多少 ms
* 返回:无
******************************************************************************/
void Move_Screen(unsigned char r_l,unsigned char move_bit_num,unsigned char move_delay)
{
unsigned char i ;
delay1ms(move_delay) ;
if(r_l == 1) //屏幕整体右移
{
for(i = 0 ; i < move_bit_num ; i++)
{
Write_Com(0x1c) ; //指令5 : 0001 1100 屏幕整体右移一位
delay1ms(move_delay) ;
}
}
if(r_l == 0) //屏幕整体左移
{
for(i = 0 ; i < move_bit_num ; i++)
{
Write_Com(0x18) ; //指令5 : 0001 1000 屏幕整体左移一位
delay1ms(move_delay) ;
}
}
}
/******************************************************************************
* 名称:Dis_Str()
* 功能:在显示HD44780控制的1602LCD上显示一个字符串
* 参数:unsigned char line , unsigned char x 在LCD上显示的位置
* 参数:unsigned char *str 要显示的字符串的指针(首地址)
* 返回:无
******************************************************************************/
void Dis_Str(unsigned char line , unsigned char x , unsigned char *str)
{
unsigned char i ;
//1、 设置在LCD1602上显示字符的开始位置 : 从 第line行 坐标x 开始显示
Write_Address(0x40 * line + x) ; delay1ms(5) ;
//2、 显示要显示的字符串
i = 0 ;
while(str[i] != '\0')
{
Write_Data(str[i]) ;
i++ ;
delay1ms(1) ;
}
}
/******************************************************************************
* 名称:Dis_Char()
* 功能:在显示HD44780控制的1602LCD上显示一个字符
* 参数:unsigned char line , unsigned char x 在LCD上显示的位置
* 参数:unsigned char ch 要显示的字符
* 返回:无
******************************************************************************/
void Dis_Char(unsigned char line , unsigned char x , unsigned char ch)
{
//1、 设置在LCD1602上显示字符的开始位置 : 从 第line行 坐标x 开始显示
Write_Address(0x40 * line + x) ; delay1ms(5) ;
//2、 显示要显示的字符串
Write_Data(ch) ;
delay1ms(10) ;
}
/******************************************************************************
* 名称:Clear_Screen()
* 功能:清屏
* 参数:无
* 返回:无
******************************************************************************/
void Clear_Screen(void)
{
delay1ms(5) ;
Write_Com(0x01) ;
delay1ms(5) ;
}
/**************************************************************************************************
* HD44780_1602LCD配置文件:HD44780_1602LCD.h
* 本程序当时是依据AT89S52单片机开发板写的
* RS R/W E 这三位引脚分别和单片机引脚 P2^0 P2^1 P2^2 相连
* 八位数据引脚DB0……DB7分别和单片机的P0端口的P0^0……P0^7相连 (BF位其实就对应DB7引脚和P0^7相连)
* 将此文件来驱动1602LCD时,只需更改下面的位定义和数据线的端口号即可
* 对于HD44780控制的1602LCD的详细资料和11条指令的描述参考一下连接
* http://blog.csdn.net/dragon12345666/article/details/22819827
**************************************************************************************************/
#ifndef __HD44780_1602LCD_H__
#define __HD44780_1602LCD_H__
#include<reg52.h>
#include<intrins.h>
#include "DELAY_FUNCTION_FELL.h"
sbit RS = P2^0 ; //对象标志位: = 0(对象是指令或状态位);= 1(对象是数据)
sbit RW = P2^1 ; //读写标志位: = 0(写);= 1(读)
sbit E = P2^2 ; //使能位:为 1 时,读写信息,为 负跳变 时,执行指令
sbit BF = P0^7 ; //HD44780控制的1602LCD的 忙 状态位(只能通过指令读取)
bit Busy_Test(void) ;
void Clear_Screen(void) ;
void Dis_Str(unsigned char line , unsigned char x , unsigned char *str) ;
void Dis_User_char(unsigned char line , unsigned char x ,unsigned char num) ;
void Dis_Char(unsigned char line , unsigned char x , unsigned char ch) ;
void HD44780_1602LCD_Init(void) ;
void Move_Screen(unsigned char r_l,unsigned char move_bit_num,unsigned char move_delay) ;
void Switch_Cursor(unsigned char cursor_key , unsigned char twinkle_key) ;
void Switch_Screen(unsigned char scr_key) ;
void Write_Address(unsigned char addr) ;
void Write_Com(unsigned char dictate) ;
void Write_Data(unsigned char char_data) ;
void Write_User_char(unsigned char addr_num , unsigned char *str) ;
#endif
5、延时函数部分配置文件
//DELAY_FUNCTION_FELL.c
#include "DELAY_FUNCTION_FELL.h"
/******************************************************************************
* 名称:dlcd_delay1us()
* 功能:延时若干1ns
* 参数:int t
* 返回:无
******************************************************************************/
void delay1us(int t)
{
while(t--)
{
_nop_() ;
}
}
/******************************************************************************
* 名称:dlcd_delay1ms()
* 功能:延时若干1ms
* 参数:int t
* 返回:无
******************************************************************************/
void delay1ms(int t)
{
unsigned char i ;
while(t--)
{
for(i = 0 ; i < 125 ; i++)
{
;
}
}
}
//DELAY_FUNCTION_FELL.h
#ifndef __DELAY_FUNCTION_FELL_H__
#define __DELAY_FUNCTION_FELL_H__
#include<reg52.h> //包含单片机寄存器的头文件
#include<intrins.h> //包含_nop_()函数定义的头文件
extern void delay1us(int t) ;
extern void delay1ms(int t) ;
#endif