用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