目录
一、介绍
1.DS1302介绍
2.引脚定义和应用电路
3.内部结构框图
4. 寄存器定义
?5.时序定义
6.BCD码
?二、文件内容
a.代码功能
1.代码实现功能
2.工程文件内容
b.代码详细内容
1.main.c
2.DS1302.c
3.DS1302.h
4.?Delay.c
5.?Delay.h
6.Key.c
7.Key.h
8.LCD1602.c
9.LCD1602.h
10.Timer0.c
11.Timer0.h
一、介绍
1.DS1302介绍
????????DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时且具有闰年补偿等多种功能 ????????RTC(Real Time Clock):实时时钟,是一种集成电路,通常称为时钟芯片
2.引脚定义和应用电路
? ? ? ?? ? ? ? ? ??
引脚名 | 作用 | 引脚名 | 作用 | VCC2 | 主电源 | CE | 芯片使能 | VCC1 | 备用电池 | IO | 数据输入/输出 | GND | 电源地 | SCLK | 串行时钟 | X1、X2 | 32.768KHz晶振 | | |
3.内部结构框图
4. 寄存器定义
?5.时序定义
6.BCD码
? ? ? ? BCD码(Binary Coded Decimal):用4位二进制数来表示1位十进制数
????????例:0001 0011表示13,1000 0101表示85,0001 1010不合法
? ? ? ??在十六进制中的体现:0x13表示13,0x85表示85,0x1A不合法
????????BCD码转十进制:DEC=BCD/16*10+ BCD%16;(2位BCD)
????????十进制转BCD码: BCD=DEC/10+16+DEC%10;(2位BCD)
?二、文件内容
a.代码功能
1.代码实现功能
????????显示年月日、时分秒
? ? ? ? 按下按键1选择模式【显示/更改】,按下按键2选择要更改的数,按键3【+】,按键4【-】
2.工程文件内容
b.代码详细内容
1.main.c
#include <REGX52.H>
#include "LCD1602.h"
#include "DS1302.h"
#include "Key.h"
#include "Timer0.h"
unsigned char KeyNumber,MODE,TimeSetSelect,TimeSetFlashFlag;
unsigned char YEAR(unsigned char year,month);
void TimeShow();
void TimeSet();
void main(){
LCD_Init();
DS1302_Init();
Timer0_Init();
DS1302_SetTime();
LCD_ShowString(1,1," - - ");
LCD_ShowString(2,1," : : ");
while(1){
KeyNumber = Key();
if(KeyNumber==1){
if(MODE==0)MODE=1;
else if(MODE==1){MODE=0;DS1302_SetTime();}
}
switch(MODE)
{
case 0: TimeShow();break;
case 1: TimeSet();break;
}
}
}
//显示
void TimeShow(){
DS1302_ReadTime();
LCD_ShowNum(1,1,DS1302_Time[0],2);
LCD_ShowNum(1,4,DS1302_Time[1],2);
LCD_ShowNum(1,7,DS1302_Time[2],2);
LCD_ShowNum(2,1,DS1302_Time[3],2);
LCD_ShowNum(2,4,DS1302_Time[4],2);
LCD_ShowNum(2,7,DS1302_Time[5],2);
}
//修改
void TimeSet(){
//选择需要更改的位
if(KeyNumber == 2)
{
TimeSetSelect++;
TimeSetSelect%=6;
}
//增加更改位的数,并判断是否越界
if(KeyNumber == 3)
{
DS1302_Time[TimeSetSelect]++;
if(DS1302_Time[0]>99){DS1302_Time[0]=0;}
if(DS1302_Time[1]>12){DS1302_Time[1]=1;}
if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==31)
{
if(DS1302_Time[2]>31){DS1302_Time[2]=1;}
}
if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==30)
{
if(DS1302_Time[2]>30){DS1302_Time[2]=1;}
}
if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==29)
{
if(DS1302_Time[2]>29){DS1302_Time[2]=1;}
}
if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==28)
{
if(DS1302_Time[2]>28){DS1302_Time[2]=1;}
}
if(DS1302_Time[3]>24){DS1302_Time[3]=0;}
if(DS1302_Time[4]>59){DS1302_Time[4]=0;}
if(DS1302_Time[5]>59){DS1302_Time[5]=0;}
}
//减小更改位的数,并判断是否越界
if(KeyNumber == 4)
{
DS1302_Time[TimeSetSelect]--;
if(DS1302_Time[0]>100){DS1302_Time[0]=99;}
if(DS1302_Time[1]<1){DS1302_Time[1]=12;}
if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==31)
{
if(DS1302_Time[2]<1){DS1302_Time[2]=31;}
if(DS1302_Time[2]>31){DS1302_Time[2]=1;}
}
if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==30)
{
if(DS1302_Time[2]<1){DS1302_Time[2]=30;}
if(DS1302_Time[2]>30){DS1302_Time[2]=1;}
}
if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==29)
{
if(DS1302_Time[2]<1){DS1302_Time[2]=29;}
if(DS1302_Time[2]>29){DS1302_Time[2]=1;}
}
if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==28)
{
if(DS1302_Time[2]<1){DS1302_Time[2]=28;}
if(DS1302_Time[2]>28){DS1302_Time[2]=1;}
}
if(DS1302_Time[3]>100){DS1302_Time[3]=24;}
if(DS1302_Time[4]>100){DS1302_Time[4]=59;}
if(DS1302_Time[5]>100){DS1302_Time[5]=59;}
}
//显示更改后的数据
if(TimeSetSelect==0 && TimeSetFlashFlag==1){LCD_ShowString(1,1," ");}
else{LCD_ShowNum(1,1,DS1302_Time[0],2);}
if(TimeSetSelect==1 && TimeSetFlashFlag==1){LCD_ShowString(1,4," ");}
else{LCD_ShowNum(1,4,DS1302_Time[1],2);}
if(TimeSetSelect==2 && TimeSetFlashFlag==1){LCD_ShowString(1,7," ");}
else{LCD_ShowNum(1,7,DS1302_Time[2],2);}
if(TimeSetSelect==3 && TimeSetFlashFlag==1){LCD_ShowString(2,1," ");}
else{LCD_ShowNum(2,1,DS1302_Time[3],2);}
if(TimeSetSelect==4 && TimeSetFlashFlag==1){LCD_ShowString(2,4," ");}
else{LCD_ShowNum(2,4,DS1302_Time[4],2);}
if(TimeSetSelect==5 && TimeSetFlashFlag==1){LCD_ShowString(2,7," ");}
else{LCD_ShowNum(2,7,DS1302_Time[5],2);}
/*LCD_ShowNum(2,10,TimeSetSelect,2);
LCD_ShowNum(2,13,TimeSetFlashFlag,2);*/
}
//闰年判断,月份天数判断
unsigned char YEAR(unsigned char year,month){
if(year%400==0||year%4==0&&year%100!=0)
{
if(month==2)
return 29;
}
else
{
if(month==1||month==3||month==5||month==7||month==8||month==10||month==12)
return 31;
else if(month==4||month==6||month==9||month==11)
return 30;
else
return 28;
}
return 0;
}
//定时器
void Timer0_Routine() interrupt 1
{
static unsigned int count0 = 0;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
count0++;
if(count0 == 300){
count0 = 0;
TimeSetFlashFlag=!TimeSetFlashFlag;
}
}
2.DS1302.c
#include <REGX52.H>
#define DS1302_SECOND 0x80
#define DS1302_MINUTE 0x82
#define DS1302_HOUR 0x84
#define DS1302_DATE 0x86
#define DS1302_MONTH 0x88
#define DS1302_DAY 0x8A
#define DS1302_YEAR 0x8C
#define DS1302_WP 0x8E
sbit DS1302_SCLK=P3^6;
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;
unsigned char DS1302_Time[]={22,12,31,23,59,58,2};
/**
* @brief BCD转10进制
* @param
* @retval
*/
unsigned char BCD_10(unsigned char Num){
unsigned char Temp;
Temp = Num/10*16+Num%10;
return Temp;
}
/**
* @brief 10进制转BCD码
* @param
* @retval
*/
unsigned char Ten_BCD(unsigned char Num){
unsigned char Temp;
Temp = Num/16*10+Num%16;
return Temp;
}
/**
* @brief 初始化DS1302
* @param
* @retval
*/
void DS1302_Init(){
DS1302_SCLK=0;
DS1302_CE=0;
}
/**
* @brief 写入字节
* @param
* @retval
*/
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;
}
/**
* @brief 读取字节
* @param
* @retval
*/
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_CE=0;
DS1302_IO=0;
return Data;
}
/**
* @brief 将数组内容写入
* @param
* @retval
*/
void DS1302_SetTime(){
DS1302_WriteByte(DS1302_WP,0x00);
DS1302_WriteByte(DS1302_YEAR,BCD_10(DS1302_Time[0]));
DS1302_WriteByte(DS1302_MONTH,BCD_10(DS1302_Time[1]));
DS1302_WriteByte(DS1302_DATE,BCD_10(DS1302_Time[2]));
DS1302_WriteByte(DS1302_HOUR,BCD_10(DS1302_Time[3]));
DS1302_WriteByte(DS1302_MINUTE,BCD_10(DS1302_Time[4]));
DS1302_WriteByte(DS1302_SECOND,BCD_10(DS1302_Time[5]));
DS1302_WriteByte(DS1302_DAY,BCD_10(DS1302_Time[6]));
DS1302_WriteByte(DS1302_WP,0x80);
}
/**
* @brief 读出数组内容
* @param
* @retval
*/
void DS1302_ReadTime(){
DS1302_Time[0]=Ten_BCD(DS1302_ReadByte(DS1302_YEAR));
DS1302_Time[1]=Ten_BCD(DS1302_ReadByte(DS1302_MONTH));
DS1302_Time[2]=Ten_BCD(DS1302_ReadByte(DS1302_DATE));
DS1302_Time[3]=Ten_BCD(DS1302_ReadByte(DS1302_HOUR));
DS1302_Time[4]=Ten_BCD(DS1302_ReadByte(DS1302_MINUTE));
DS1302_Time[5]=Ten_BCD(DS1302_ReadByte(DS1302_SECOND));
DS1302_Time[6]=Ten_BCD(DS1302_ReadByte(DS1302_DAY));
}
3.DS1302.h
#ifndef __SD1302_H__
#define __SD1302_H__
extern unsigned char DS1302_Time[];
void DS1302_Init();
void DS1302_ReadTime();
void DS1302_SetTime();
#endif
4.?Delay.c
void Delay(unsigned int t) //延时函数
{
unsigned char i, j;
while(t){
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
t--;
}
}
5.?Delay.h
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int t);
#endif
6.Key.c
#include <REGX52.H>
#include "Delay.h"
/**
* @brief 获取独立按键键码
* @param 无
* @retval KeyNumber 键码
*/
unsigned char Key(){
unsigned char KeyNumber = 0;
if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber = 1;}
if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber = 2;}
if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber = 3;}
if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber = 4;}
return KeyNumber;
}
7.Key.h
#ifndef __KEY_H__
#define __KEY_H__
unsigned char Key();
#endif
8.LCD1602.c
#include <REGX52.H>
//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0
//函数定义:
/**
* @brief LCD1602延时函数,12MHz调用可延时1ms
* @param 无
* @retval 无
*/
void LCD_Delay()
{
unsigned char i, j;
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
/**
* @brief LCD1602写命令
* @param Command 要写入的命令
* @retval 无
*/
void LCD_WriteCommand(unsigned char Command)
{
LCD_RS=0;
LCD_RW=0;
LCD_DataPort=Command;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}
/**
* @brief LCD1602写数据
* @param Data 要写入的数据
* @retval 无
*/
void LCD_WriteData(unsigned char Data)
{
LCD_RS=1;
LCD_RW=0;
LCD_DataPort=Data;
LCD_EN=1;
LCD_Delay();
LCD_EN=0;
LCD_Delay();
}
/**
* @brief LCD1602设置光标位置
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @retval 无
*/
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
if(Line==1)
{
LCD_WriteCommand(0x80|(Column-1));
}
else if(Line==2)
{
LCD_WriteCommand(0x80|(Column-1+0x40));
}
}
/**
* @brief LCD1602初始化函数
* @param 无
* @retval 无
*/
void LCD_Init()
{
LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
LCD_WriteCommand(0x01);//光标复位,清屏
}
/**
* @brief 在LCD1602指定位置上显示一个字符
* @param Line 行位置,范围:1~2
* @param Column 列位置,范围:1~16
* @param Char 要显示的字符
* @retval 无
*/
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
LCD_SetCursor(Line,Column);
LCD_WriteData(Char);
}
/**
* @brief 在LCD1602指定位置开始显示所给字符串
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param String 要显示的字符串
* @retval 无
*/
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=0;String[i]!='\0';i++)
{
LCD_WriteData(String[i]);
}
}
/**
* @brief 返回值=X的Y次方
*/
int LCD_Pow(int X,int Y)
{
unsigned char i;
int Result=1;
for(i=0;i<Y;i++)
{
Result*=X;
}
return Result;
}
/**
* @brief 在LCD1602指定位置开始显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~65535
* @param Length 要显示数字的长度,范围:1~5
* @retval 无
*/
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
}
}
/**
* @brief 在LCD1602指定位置开始以有符号十进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:-32768~32767
* @param Length 要显示数字的长度,范围:1~5
* @retval 无
*/
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
unsigned char i;
unsigned int Number1;
LCD_SetCursor(Line,Column);
if(Number>=0)
{
LCD_WriteData('+');
Number1=Number;
}
else
{
LCD_WriteData('-');
Number1=-Number;
}
for(i=Length;i>0;i--)
{
LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
}
}
/**
* @brief 在LCD1602指定位置开始以十六进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~0xFFFF
* @param Length 要显示数字的长度,范围:1~4
* @retval 无
*/
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i,SingleNumber;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
SingleNumber=Number/LCD_Pow(16,i-1)%16;
if(SingleNumber<10)
{
LCD_WriteData(SingleNumber+'0');
}
else
{
LCD_WriteData(SingleNumber-10+'A');
}
}
}
/**
* @brief 在LCD1602指定位置开始以二进制显示所给数字
* @param Line 起始行位置,范围:1~2
* @param Column 起始列位置,范围:1~16
* @param Number 要显示的数字,范围:0~1111 1111 1111 1111
* @param Length 要显示数字的长度,范围:1~16
* @retval 无
*/
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
unsigned char i;
LCD_SetCursor(Line,Column);
for(i=Length;i>0;i--)
{
LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
}
}
9.LCD1602.h
#ifndef __LCD1602_H__
#define __LCD1602_H__
//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
#endif
10.Timer0.c
#include <REGX52.H>
void Timer0_Init(void) //1毫秒@12.000MHz
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1;
EA = 1;
PT0 = 0;
}
/* 定时器中断函数模板
void Timer0_Routine() interrupt 1
{
static unsigned int count0 = 0;
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
count0++;
if(count0 == 1000){
count0 = 0;
}
}
*/
11.Timer0.h
#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0_Init(void);
#endif
模块化编程
|