一、DS1302时序及命令字
两个操作:写操作和读操作
写操作:
(由我们单片机一个控制引脚控制DS1302的IO口写入)首先就是通过时序图把我们的命令字写入,命令字是控制我们对应要写入的年月日,时分秒等配置的关键寄存器,只有设置好命令字相关参数才能写入相关的年月日等时间信息,一个写时序共2个字节,第一个字节是我们的命令字,第二个字节是我们要写入的数据(此数据为16进制写入,最后读的时候我们需要转换成十进制读出),数据和命令字一样通过RCLK的上升沿将数据和命令字(数据就是我们的日期如24年这个数据,写入的时候先转16进制,命令字就是控制时分秒等的寄存器)写入。如下代码:
//单字节写
void DS1302_WriteByte(unsigned char Command,Data)
{
unsigned char i;
DS1302_CE = 1; //使能开始
for(i=0; i<8; i++)
{
DS1302_IO = Command & (0X01 <<i); //取出第0位
DS1302_SCLK = 1;
DS1302_SCLK = 0;
}
for(i=0; i<8; i++)
{
DS1302_IO = Data & (0X01 <<i); //取出第0位
DS1302_SCLK = 1;
DS1302_SCLK = 0;
}
DS1302_CE = 0; //使能结束
}
读操作:
同理,单片机读DS1302中的数据就比较简单了,只要我们第一个字节读出对应的命令字(81H:秒的地址)读的地址,第二个字节我们就会利用时序将IO口上的数据一位一位的读出,并保存到指定变量中,即可将数据存入,接下来我们就利用LCD1602的显示函数将其显示出来,(注意:读的时候也是读的16进制,因此,我么显示的时候也需要16进制转换为10进制显示)。代码如下:
//单字节读
unsigned char DS1302_ReadByte(unsigned char Command)
{
unsigned char i,Data=0X00;
Command |= 0X01; //将写的命令字转换为或的命令字(方便单片机读取DS1302的时间)
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); //或等于是有1才1,不会影响Data本身其他位,通过0X01移i位来与Data原来的值相或,Data的第i位会被置0或置1,而不影响其他位(Data本身是一个字节)
}
}
DS1302_CE = 0; //使能结束
DS1302_IO = 0;
return Data;
}
个人理解:写操作:首先,我们CE和RCLK置为低电平进行时序的初始化,然后,我们就需要配置命令字,第一步就要取出命令字的第0位,将该位放置到IO口上,第二步,我们开始控制SCLK拉高再降低,把数据写入,读就是就比较简单了,自己可以理解看着时序图想一下(Whappy鼓励你)
二、不可调节时钟程序(软件程序初始设置完成)
可以用GPT解释代码(比较简单)(一定要模块化)
main.c
#include <REGX52.H>
#include "LCD1602.h"
#include "DS1302.h"
#include "Delay.h"
unsigned char Second,Minute;
void main(void)
{
LCD_Init();
DS1302_Init();
DS1302_SetTime();
LCD_ShowString(1,1," - -");
LCD_ShowString(2,1," : :");
while(1)
{
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);
}
}
DS1302.c
#include <REGX52.H>
#include "DS1302.h"
unsigned char DS1302_Time[] = {24,9,5,11,12,00,6};
sbit DS1302_SCLK = P3^6;
sbit DS1302_CE = P3^5;
sbit DS1302_IO = P3^4;
//写入时间的命令字寄存器配置
#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
//初始化
void DS1302_Init(void)
{
DS1302_CE = 0;
DS1302_SCLK = 0;
}
/**
* @brief DS1302写一个字节
* @param Command 命令字/地址
* @param Data 要写入的数据
* @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); //取出第0位
DS1302_SCLK = 1;
DS1302_SCLK = 0;
}
for(i=0; i<8; i++)
{
DS1302_IO = Data & (0X01 <<i); //取出第0位
DS1302_SCLK = 1;
DS1302_SCLK = 0;
}
DS1302_CE = 0; //使能结束
}
//void DS1302_WriteByte(unsigned char Command,Data)
//{
// unsigned char i;
// DS1302_CE=1;
// for(i=0;i<8;i++)
// {
// DS1302_IO=Command&(0x01<<i);
// DS1302_SCLK=1;
// DS1302_SCLK=0;
// }
// for(i=0;i<8;i++)
// {
// DS1302_IO=Data&(0x01<<i);
// DS1302_SCLK=1;
// DS1302_SCLK=0;
// }
// DS1302_CE=0;
//}
//单字节读
unsigned char DS1302_ReadByte(unsigned char Command)
{
unsigned char i,Data=0X00;
Command |= 0X01; //将写的命令字转换为或的命令字(方便单片机读取DS1302的时间)
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); //或等于是有1才1,不会影响Data本身其他位,通过0X01移i位来与Data原来的值相或,Data的第i位会被置0或置1,而不影响其他位(Data本身是一个字节)
}
}
DS1302_CE = 0; //使能结束
DS1302_IO = 0;
return Data;
}
//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; //读取后将IO设置为0,否则读出的数据会出错
// return Data;
//}
void DS1302_SetTime()
{
DS1302_WriteByte(DS1302_WP,0X00);//打开写保护,不然烧录不正确
DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);
DS1302_WriteByte(DS1302_MONTH,DS1302_Time[1]/10*16+DS1302_Time[1]%10);
DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16+DS1302_Time[2]%10);
DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);
DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);
DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);
DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);
DS1302_WriteByte(DS1302_WP,0X80);//关闭写保护,不然烧录不正确
}
void DS1302_ReadTime()
{
unsigned char Temp;
Temp = DS1302_ReadByte(DS1302_YEAR);
DS1302_Time[0] = Temp/16*10+Temp%16;
Temp = DS1302_ReadByte(DS1302_MONTH);
DS1302_Time[1] = Temp/16*10+Temp%16;
Temp = DS1302_ReadByte(DS1302_DATE);
DS1302_Time[2] = Temp/16*10+Temp%16;
Temp = DS1302_ReadByte(DS1302_HOUR);
DS1302_Time[3] = Temp/16*10+Temp%16;
Temp = DS1302_ReadByte(DS1302_MINUTE);
DS1302_Time[4] = Temp/16*10+Temp%16;
Temp = DS1302_ReadByte(DS1302_SECOND);
DS1302_Time[5] = Temp/16*10+Temp%16;
Temp = DS1302_ReadByte(DS1302_DAY);
DS1302_Time[6] = Temp/16*10+Temp%16;
}
///*
//参考代码
//#include <REGX52.H>
引脚定义
//sbit DS1302_SCLK=P3^6;
//sbit DS1302_IO=P3^4;
//sbit DS1302_CE=P3^5;
寄存器写入地址/指令定义
//#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
时间数组,索引0~6分别为年、月、日、时、分、秒、星期
//unsigned char DS1302_Time[]={19,11,16,12,59,55,6};
///**
// * @brief DS1302初始化
// * @param 无
// * @retval 无
// */
//void DS1302_Init(void)
//{
// DS1302_CE=0;
// DS1302_SCLK=0;
//}
///**
// * @brief DS1302写一个字节
// * @param Command 命令字/地址
// * @param Data 要写入的数据
// * @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 DS1302读一个字节
// * @param Command 命令字/地址
// * @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; //读取后将IO设置为0,否则读出的数据会出错
// return Data;
//}
///**
// * @brief DS1302设置时间,调用之后,DS1302_Time数组的数字会被设置到DS1302中
// * @param 无
// * @retval 无
// */
//void DS1302_SetTime(void)
//{
// DS1302_WriteByte(DS1302_WP,0x00);
// DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);//十进制转BCD码后写入
// DS1302_WriteByte(DS1302_MONTH,DS1302_Time[1]/10*16+DS1302_Time[1]%10);
// DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16+DS1302_Time[2]%10);
// DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);
// DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);
// DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);
// DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);
// DS1302_WriteByte(DS1302_WP,0x80);
//}
///**
// * @brief DS1302读取时间,调用之后,DS1302中的数据会被读取到DS1302_Time数组中
// * @param 无
// * @retval 无
// */
//void DS1302_ReadTime(void)
//{
// unsigned char Temp;
// Temp=DS1302_ReadByte(DS1302_YEAR);
// DS1302_Time[0]=Temp/16*10+Temp%16;//BCD码转十进制后读取
// Temp=DS1302_ReadByte(DS1302_MONTH);
// DS1302_Time[1]=Temp/16*10+Temp%16;
// Temp=DS1302_ReadByte(DS1302_DATE);
// DS1302_Time[2]=Temp/16*10+Temp%16;
// Temp=DS1302_ReadByte(DS1302_HOUR);
// DS1302_Time[3]=Temp/16*10+Temp%16;
// Temp=DS1302_ReadByte(DS1302_MINUTE);
// DS1302_Time[4]=Temp/16*10+Temp%16;
// Temp=DS1302_ReadByte(DS1302_SECOND);
// DS1302_Time[5]=Temp/16*10+Temp%16;
// Temp=DS1302_ReadByte(DS1302_DAY);
// DS1302_Time[6]=Temp/16*10+Temp%16;
//}
//*/
DS1302.h
#ifndef __DS1302_H__
#define __DS1302_H__
extern unsigned char DS1302_Time[];
void DS1302_WriteByte(unsigned char Command,Data); //单片机写操作
unsigned char DS1302_ReadByte(unsigned char Command); //单片机读操作
void DS1302_Init(void);
void DS1302_ReadTime(); //单片机读出时间
void DS1302_SetTime(); //设置时间
#endif
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');
}
}
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
Whappy:下一篇文章(可调时钟)