51单片机——DS1302可调时钟
目录
一、功能介绍
在LCD1602上显示时钟,其中的年,月,日和时钟,分钟,秒钟还有星期都是可调的。
二、主要模块介绍
2.1 DS1302模块
为什么要用DS1302芯片来计时呢?定时器不可以吗?
2.1.1 DS1302芯片介绍
单片机的CPU三个引脚分别连接DS1302的使能端CE、数据输入/输出端I/O、串行时钟端SCLK三个端口。
2.1.2 DS1302的使用
操作 DS1302 的大致过程,就是将各种数据写入 DS1302 的寄存器,以设置 它当前的时间的格式。然后使 DS1302 开始运作,DS1302 时钟会按照设置情况 运转,再用单片机将其寄存器内的数据读出。
1.日历/时钟寄存器
DS1302 共有 12 个寄存器,其中有 7 个与日历、时钟相关,存放的数据为 BCD 码形式。
2.控制命令字
命令字简单来说就是,控制时钟寄存器的读写。比如要写入秒钟,那么操作的命令字就是0x80对应上面图中的80h;要读出秒钟,操作的命令字是0x81,对应81h。以此类推,可以控制所有时钟数据的读写。
3.时序图
上面是单字节读,下面是单字节写。根据时序图来写入数据和读出数据。
单字节写,是把单片机内存里的数据,也就是把定义的变量写入DS1302的寄存器中。有两个变量,一个是要操作的命令字(写秒钟还是写分钟…),另一个是要写入的数据。
- 初始化时CE=0;SCLK=0。
- 使能端CE=1;先SCLK=1由0->1,再SCLK=0由1->0,模拟一个写入脉冲周期。
- 命令字和数据写入完成后要把使能端CE=0;SCLK=0。
单字节读,分两个过程,一个是写入命令字,一个是读出数据。
- 初始化时CE=0;SCLK=0。
- 同样也是使能端CE=1;SCLK先置0(因为初始化的时候SCLK=0,这里置0是方便循环),再置1,模拟上升沿信号,写入控制字。读出数据时SCLK先置1(这里也是方便循环),再置0,模拟下降沿信号。
- 命令字和数据写入完成后要把使能端CE=0;SCLK=0。
单字节读写中,SCLK的设置方式不同,主要是因为时序脉冲的不同,单字节读只有15个脉冲,单字节写有16个脉冲,平均分成命令字写和数据的读/写两部分。
三、程序汇总
3.1测试文件test.c
#include <REGX52.H>
#include"LCD1602.h"
#include"DS1302.h"
#include"Independentkey.h"
#include"Timer0_Init.h"
unsigned char count;
unsigned char flash;
void showtime()
{
LCD_ShowNum(1,1,DS1302_time[0],2);
LCD_ShowString(1,3,"-");
LCD_ShowNum(1,4,DS1302_time[1],2);
LCD_ShowString(1,6,"-");
LCD_ShowNum(1,7,DS1302_time[2],2);
LCD_ShowNum(2,1,DS1302_time[3],2);
LCD_ShowString(2,3,":");
LCD_ShowNum(2,4,DS1302_time[4],2);
LCD_ShowString(2,6,":");
LCD_ShowNum(2,7,DS1302_time[5],2);
LCD_ShowString(2,10,"week:");
LCD_ShowNum(2,15,DS1302_time[6],1);
}
void num_flash()
{
if(count==0){if(flash==0){LCD_ShowString(1,1," ");}
if(flash!=0){LCD_ShowNum(1,1,DS1302_time[count],2);}
LCD_ShowNum(2,15,DS1302_time[6],1);}
if(count==1){if(flash==0){LCD_ShowString(1,4," ");}
if(flash!=0){LCD_ShowNum(1,4,DS1302_time[count],2);}
LCD_ShowNum(1,1,DS1302_time[0],2);}
if(count==2){if(flash==0){LCD_ShowString(1,7," ");}
if(flash!=0){LCD_ShowNum(1,7,DS1302_time[count],2);}
LCD_ShowNum(1,4,DS1302_time[1],2);}
if(count==3){if(flash==0){LCD_ShowString(2,1," ");}
if(flash!=0){LCD_ShowNum(2,1,DS1302_time[count],2);}
LCD_ShowNum(1,7,DS1302_time[2],2);}
if(count==4){if(flash==0){LCD_ShowString(2,4," ");}
if(flash!=0){LCD_ShowNum(2,4,DS1302_time[count],2);}
LCD_ShowNum(2,1,DS1302_time[3],2);}
if(count==5){if(flash==0){LCD_ShowString(2,7," ");}
if(flash!=0){LCD_ShowNum(2,7,DS1302_time[count],2);}
LCD_ShowNum(2,4,DS1302_time[4],2);}
if(count==6){if(flash==0){LCD_ShowString(2,15," ");}
if(flash!=0){LCD_ShowNum(2,15,DS1302_time[count],1);}
LCD_ShowNum(2,7,DS1302_time[5],2);}
}
//定时500ms中断
void Timer0_ISR() interrupt 1
{
static int num=0;
num++;
TH0=0xfc;
TL0=0x18;
if(num==500)//每隔500ms闪烁一下
{
num=0;
flash=!flash;
}
}
void setlimit()
{
//年:2000-2099年
if(DS1302_time[0]>99){DS1302_time[0]%=100;}
if(DS1302_time[0]<0){DS1302_time[0]=99;}
//月:1-12月
if(DS1302_time[1]>12){DS1302_time[1]%=13;DS1302_time[1]++;}
if(DS1302_time[1]<1){DS1302_time[1]=12;}
//日:分闰年二月,分大小月
if(DS1302_time[0]%4==0)//闰年二月 1-29号
{
if(DS1302_time[1]==2)
{
if(DS1302_time[2]>29){DS1302_time[2]%=30;DS1302_time[2]++;}
if(DS1302_time[2]<1){DS1302_time[2]=29;}
}
}
if(DS1302_time[0]%4!=0)//不是闰年的二月 1-28号
{
if(DS1302_time[1]==2)
{
if(DS1302_time[2]>28){DS1302_time[2]%=29;DS1302_time[2]++;}
if(DS1302_time[2]<1){DS1302_time[2]=28;}
}
}
//大月: 1,3,5,7,8,10,12 1-31号
if(DS1302_time[1]==1||DS1302_time[1]==3||DS1302_time[1]==5||DS1302_time[1]==7||DS1302_time[1]==8||DS1302_time[1]==10||DS1302_time[1]==12)
{
if(DS1302_time[2]>31){DS1302_time[2]%=32;DS1302_time[2]++;}
if(DS1302_time[2]<1){DS1302_time[2]=31;}
}
//小月:4,6,9,11 1-30号
if(DS1302_time[1]==4||DS1302_time[1]==6||DS1302_time[1]==9||DS1302_time[1]==11)
{
if(DS1302_time[2]>30){DS1302_time[2]%=31;DS1302_time[2]++;}
if(DS1302_time[2]<1){DS1302_time[2]=30;}
}
//时钟 0-23
if(DS1302_time[3]>23){DS1302_time[3]%=24;}
if(DS1302_time[3]<0){DS1302_time[3]=23;}
//分钟 0-59
if(DS1302_time[4]>59){DS1302_time[4]%=60;}
if(DS1302_time[4]<0){DS1302_time[4]=59;}
//秒钟 0-59
if(DS1302_time[5]>59){DS1302_time[5]%=60;}
if(DS1302_time[5]<0){DS1302_time[5]=59;}
//星期 1-7
if(DS1302_time[6]>7){DS1302_time[6]%=7;}
if(DS1302_time[6]<1){DS1302_time[6]=7;}
}
int main()
{
unsigned char keynum=0;
unsigned char mode=0;
LCD_Init();
DS1302_Init();
settime();
Timer0_Init();
while(1)
{
keynum=Independentkey();
if(keynum!=0)
{
if(keynum==1)//选择位
{
count++;
if(count>=7)
{
count=0;
}
}
if(keynum==2)//加一
{
DS1302_time[count]++;
setlimit();//对DS1302_time[count]进行调整
settime();
}
if(keynum==3)//减一
{
DS1302_time[count]--;
setlimit();
settime();
}
if(keynum==4)//设置时间和走时显示切换
{
mode=!mode;
}
}
if(mode==0)//走时模式
{
readtime();
showtime();
}
if(mode==1)//设置时间模式
{
num_flash();
}
}
}
3.2 LCD1602模块程序
3.2.1 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
3.2.2 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');
}
}
3.3 DS1302模块程序
3.3.1 DS1302.h
#ifndef __DS1302_H__
#define __DS1302_H__
#define Year_command 0x8C
#define Day_command 0x8A
#define Month_command 0x88
#define Date_command 0x86
#define Hour_command 0x84
#define Minute_command 0x82
#define Second_command 0x80
#define Wp_command 0x8E
extern char DS1302_time[];
void DS1302_Init();
void DS1302_writebyte(unsigned char command,unsigned char byte);
unsigned char DS1302_readbyte(unsigned char command);
void settime();
void readtime();
#endif
3.3.2 DS1302.c
#include <REGX52.H>
#include"LCD1602.h"
#include"DS1302.h"
#include"Independentkey.h"
#include"Timer0_Init.h"
unsigned char count;
unsigned char flash;
void showtime()
{
LCD_ShowNum(1,1,DS1302_time[0],2);
LCD_ShowString(1,3,"-");
LCD_ShowNum(1,4,DS1302_time[1],2);
LCD_ShowString(1,6,"-");
LCD_ShowNum(1,7,DS1302_time[2],2);
LCD_ShowNum(2,1,DS1302_time[3],2);
LCD_ShowString(2,3,":");
LCD_ShowNum(2,4,DS1302_time[4],2);
LCD_ShowString(2,6,":");
LCD_ShowNum(2,7,DS1302_time[5],2);
LCD_ShowString(2,10,"week:");
LCD_ShowNum(2,15,DS1302_time[6],1);
}
void num_flash()
{
if(count==0){if(flash==0){LCD_ShowString(1,1," ");}
if(flash!=0){LCD_ShowNum(1,1,DS1302_time[count],2);}
LCD_ShowNum(2,15,DS1302_time[6],1);}
if(count==1){if(flash==0){LCD_ShowString(1,4," ");}
if(flash!=0){LCD_ShowNum(1,4,DS1302_time[count],2);}
LCD_ShowNum(1,1,DS1302_time[0],2);}
if(count==2){if(flash==0){LCD_ShowString(1,7," ");}
if(flash!=0){LCD_ShowNum(1,7,DS1302_time[count],2);}
LCD_ShowNum(1,4,DS1302_time[1],2);}
if(count==3){if(flash==0){LCD_ShowString(2,1," ");}
if(flash!=0){LCD_ShowNum(2,1,DS1302_time[count],2);}
LCD_ShowNum(1,7,DS1302_time[2],2);}
if(count==4){if(flash==0){LCD_ShowString(2,4," ");}
if(flash!=0){LCD_ShowNum(2,4,DS1302_time[count],2);}
LCD_ShowNum(2,1,DS1302_time[3],2);}
if(count==5){if(flash==0){LCD_ShowString(2,7," ");}
if(flash!=0){LCD_ShowNum(2,7,DS1302_time[count],2);}
LCD_ShowNum(2,4,DS1302_time[4],2);}
if(count==6){if(flash==0){LCD_ShowString(2,15," ");}
if(flash!=0){LCD_ShowNum(2,15,DS1302_time[count],1);}
LCD_ShowNum(2,7,DS1302_time[5],2);}
}
//定时500ms中断
void Timer0_ISR() interrupt 1
{
static int num=0;
num++;
TH0=0xfc;
TL0=0x18;
if(num==500)//每隔500ms闪烁一下
{
num=0;
flash=!flash;
}
}
void setlimit()
{
//年:2000-2099年
if(DS1302_time[0]>99){DS1302_time[0]%=100;}
if(DS1302_time[0]<0){DS1302_time[0]=99;}
//月:1-12月
if(DS1302_time[1]>12){DS1302_time[1]%=13;DS1302_time[1]++;}
if(DS1302_time[1]<1){DS1302_time[1]=12;}
//日:分闰年二月,分大小月
if(DS1302_time[0]%4==0)//闰年二月 1-29号
{
if(DS1302_time[1]==2)
{
if(DS1302_time[2]>29){DS1302_time[2]%=30;DS1302_time[2]++;}
if(DS1302_time[2]<1){DS1302_time[2]=29;}
}
}
if(DS1302_time[0]%4!=0)//不是闰年的二月 1-28号
{
if(DS1302_time[1]==2)
{
if(DS1302_time[2]>28){DS1302_time[2]%=29;DS1302_time[2]++;}
if(DS1302_time[2]<1){DS1302_time[2]=28;}
}
}
//大月: 1,3,5,7,8,10,12 1-31号
if(DS1302_time[1]==1||DS1302_time[1]==3||DS1302_time[1]==5||DS1302_time[1]==7||DS1302_time[1]==8||DS1302_time[1]==10||DS1302_time[1]==12)
{
if(DS1302_time[2]>31){DS1302_time[2]%=32;DS1302_time[2]++;}
if(DS1302_time[2]<1){DS1302_time[2]=31;}
}
//小月:4,6,9,11 1-30号
if(DS1302_time[1]==4||DS1302_time[1]==6||DS1302_time[1]==9||DS1302_time[1]==11)
{
if(DS1302_time[2]>30){DS1302_time[2]%=31;DS1302_time[2]++;}
if(DS1302_time[2]<1){DS1302_time[2]=30;}
}
//时钟 0-23
if(DS1302_time[3]>23){DS1302_time[3]%=24;}
if(DS1302_time[3]<0){DS1302_time[3]=23;}
//分钟 0-59
if(DS1302_time[4]>59){DS1302_time[4]%=60;}
if(DS1302_time[4]<0){DS1302_time[4]=59;}
//秒钟 0-59
if(DS1302_time[5]>59){DS1302_time[5]%=60;}
if(DS1302_time[5]<0){DS1302_time[5]=59;}
//星期 1-7
if(DS1302_time[6]>7){DS1302_time[6]%=7;}
if(DS1302_time[6]<1){DS1302_time[6]=7;}
}
int main()
{
unsigned char keynum=0;
unsigned char mode=0;
LCD_Init();
DS1302_Init();
settime();
Timer0_Init();
while(1)
{
keynum=Independentkey();
if(keynum!=0)
{
if(keynum==1)//选择位
{
count++;
if(count>=7)
{
count=0;
}
}
if(keynum==2)//加一
{
DS1302_time[count]++;
setlimit();//对DS1302_time[count]进行调整
settime();
}
if(keynum==3)//减一
{
DS1302_time[count]--;
setlimit();
settime();
}
if(keynum==4)//设置时间和走时显示切换
{
mode=!mode;
}
}
if(mode==0)//走时模式
{
readtime();
showtime();
}
if(mode==1)//设置时间模式
{
num_flash();
}
}
}
#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
#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');
}
}
#ifndef __DS1302_H__
#define __DS1302_H__
#define Year_command 0x8C
#define Day_command 0x8A
#define Month_command 0x88
#define Date_command 0x86
#define Hour_command 0x84
#define Minute_command 0x82
#define Second_command 0x80
#define Wp_command 0x8E
extern char DS1302_time[];
void DS1302_Init();
void DS1302_writebyte(unsigned char command,unsigned char byte);
unsigned char DS1302_readbyte(unsigned char command);
void settime();
void readtime();
#endif
这里要注意的是:
#include <REGX52.H>
#include"DS1302.h"
sbit DS1302_SCLK=P3^6;
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;
char DS1302_time[]={23,2,24,12,0,0,5};//2023/2/24,12:00:00,星期5
/*
*函数名: DS1302_Init()
*函数功能:初始化DS1302
*输入: 无
*输出: 无
*/
void DS1302_Init()
{
DS1302_CE=0;
DS1302_SCLK=0;
}
/*
*函数名: DS1302_writebyte(unsigned char command,unsigned char byte)
*函数功能:DS1302的单字节写
*输入: command:命令字 byte:要写入的数据
*输出: 无
*/
void DS1302_writebyte(unsigned char command,unsigned char byte)
{
unsigned char i=0;
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=byte&(0x01<<i);
DS1302_SCLK=1;
DS1302_SCLK=0;
}
DS1302_CE=0;
}
/*
*函数名: DS1302_readbyte(unsigned char command)
*函数功能:DS1302的单字节读
*输入: command:命令字
*输出: byte:要读出的数据
*/
unsigned char DS1302_readbyte(unsigned char command)
{
unsigned char i=0;
unsigned char byte=0x00;
DS1302_CE=1;
command++;
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)
{
byte|=(0x01<<i);
}
}
DS1302_CE=0;
DS1302_IO=0;
return byte;
}
/*
*函数名: settime()
*函数功能:把命令字和DS1302_time[]数组中的年、月、日、时钟、分钟、秒钟、星期一起写入DS1302
*输入: 无
*输出: 无
*/
void settime()
{
DS1302_writebyte(Wp_command,0x00);
DS1302_writebyte(Year_command,DS1302_time[0]/10*16+DS1302_time[0]%10);//16进制0x23转十进制23
DS1302_writebyte(Day_command,DS1302_time[6]/10*16+DS1302_time[6]%10);
DS1302_writebyte(Month_command,DS1302_time[1]/10*16+DS1302_time[1]%10);
DS1302_writebyte(Date_command,DS1302_time[2]/10*16+DS1302_time[2]%10);
DS1302_writebyte(Hour_command,DS1302_time[3]/10*16+DS1302_time[3]%10);
DS1302_writebyte(Minute_command,DS1302_time[4]/10*16+DS1302_time[4]%10);
DS1302_writebyte(Second_command,DS1302_time[5]/10*16+DS1302_time[5]%10);
}
/*
*函数名: readtime()
*函数功能:把年、月、日、时钟、分钟、秒钟、星期一起读出到数组DS1302_time[]中
*输入: 无
*输出: 无
*/
void readtime()
{
unsigned char tmp=0;
tmp=DS1302_readbyte(Year_command);//BCD码转十进制数
DS1302_time[0]=tmp/16*10+tmp%16;
tmp=DS1302_readbyte(Month_command);
DS1302_time[1]=tmp/16*10+tmp%16;
tmp=DS1302_readbyte(Date_command);
DS1302_time[2]=tmp/16*10+tmp%16;
tmp=DS1302_readbyte(Hour_command);
DS1302_time[3]=tmp/16*10+tmp%16;
tmp=DS1302_readbyte(Minute_command);
DS1302_time[4]=tmp/16*10+tmp%16;
tmp=DS1302_readbyte(Second_command);
DS1302_time[5]=tmp/16*10+tmp%16;
tmp=DS1302_readbyte(Day_command);
DS1302_time[6]=tmp/16*10+tmp%16;
}
3.4 独立按键模块程序
3.4.1 Independentkey.h
#ifndef __INDEPENDENTKEY_H__
#define __INDEPENDENTKEY_H__
unsigned char Independentkey();
#endif
3.4.2 Independentkey.c
#include <REGX51.H>
#include"Delay.h"
unsigned char Independentkey()
{
unsigned char keynum=0;
if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);keynum=1;}
if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);keynum=2;}
if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);keynum=3;}
if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);keynum=4;}
return keynum;
}
3.5 T0定时器模块
3.5.1 Timer0_Iint.h
#ifndef __TIMER0_INIT_H__
#define __TIMER0_INIT_H__
void Timer0_Init();
#endif
3.5.2 Timer0_Iint.c
#include <REGX51.H>
void Timer0_Init()//定时器0,工作方式1
{
TMOD=0x01;
TH0=0xfc;//1ms
TL0=0x18;
EA=1;
ET0=1;
TR0=1;
}
//定时1s中断
//void Timer0_ISR() interrupt 1
//{
// static int count=0;
// count++;
// TH0=0xfc;
// TL0=0x18;
// if(count==1000)
// {
// count=0;
//
// }
//}
3.6 延时函数
3.6.1 Delay.h
#ifndef __DELAY_H__
#define __DELAY_H__
void Delay(unsigned int Xms);
#endif
3.6.2 Delay.c
void Delay(unsigned int Xms) //@12.000MHz
{
unsigned char i, j;
while(Xms--)
{
i = 12;
j = 169;
do
{
while (--j);
} while (--i);
}
}
四、效果演示
把23年2月24日12:00:00 星期5 改成23年3月1日13:55:00 星期3。
DS1302可调时钟演示