DS1302时钟+单片机+普中+江科大自化协

1、现象:

 

2、参考程序

2.1 主程序

#include <REGX52.H>
#include "LCD1602.H"
#include "DS1302.H"

void main()
{
    LCD1602_Init();
    DS1302_Init();
    LCD1602_ShowString(1,1,"  -  -  ");    //静态字符初始化显示
    LCD1602_ShowString(2,1,"  :  :  ");
    
    DS1302_SetTime( );                    //设置时间
    
    while(1)
    {
        DS1302_ReadTime( );                //读取时间
        LCD1602_ShowNum(1,1,DS1302_Time[0],2);    //显示年
        LCD1602_ShowNum(1,4,DS1302_Time[1],2);    //显示月
        LCD1602_ShowNum(1,7,DS1302_Time[2],2);    //显示日
        LCD1602_ShowNum(2,1,DS1302_Time[3],2);    //显示时
        LCD1602_ShowNum(2,4,DS1302_Time[4],2);    //显示分
        LCD1602_ShowNum(2,7,DS1302_Time[5],2);    //显示秒
    }
}

2.2 DS1302源程序及头文件

#include <REGX52.H>

//引脚定义,与硬件原理图有关
sbit DS1302_SCLK    = P3^6;
sbit DS1302_IO        = P3^4;
sbit DS1302_CE        = P3^5;

#define DS1302_SECOND_ADDR    0x80    //DS1302秒寄存器写地址
#define DS1302_MINUTE_ADDR    0x82    //DS1302分寄存器写地址
#define DS1302_HOUR_ADDR    0x84    //DS1302时寄存器写地址
#define DS1302_DATE_ADDR    0x86    //DS1302日寄存器写地址
#define DS1302_MONTH_ADDR    0x88    //DS1302月寄存器写地址
#define DS1302_DAY_ADDR        0x8A    //DS1302星期寄存器写地址
#define DS1302_YEAR_ADDR    0x8C    //DS1302年寄存器写地址
#define DS1302_WP_ADDR        0x8E    //DS1302控制寄存器写地址

unsigned char DS1302_Time[]={22,8,7,20,8,55,7};
//时间数字,索引0-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;    //SCLK上升沿,MCU向DS1302写入数据
        DS1302_SCLK = 0;    //一个完整的脉冲
    }
    
    for(i=0;i<8;i++)        //写数据
    {
        DS1302_IO = Data & (0x01<<i); //从最低位开始,一次取出相应位的数据
        DS1302_SCLK = 1;    //SCLK上升沿,MCU向DS1302写入数据
        DS1302_SCLK = 0;    //一个完整的脉冲
    }
    
    DS1302_CE = 0;
}

/**
  * @brief  DS1302读一个字节
  * @param  Command 命令字/地址
  * @retval 读出的数据
  */
unsigned char DS1302_ReadByte(unsigned char Command)
{
    unsigned char i;
    unsigned char Data = 0x00;
    
    Command = Command | 0x01;    //将读地址指令转换为相应的读地址指令
    
    DS1302_CE = 1;
    
    for(i=0;i<8;i++)        //写地址/命令
    {
        DS1302_IO = Command & (0x01<<i); //从最低位开始,一次取出相应位的数据
        DS1302_SCLK = 0;    //一个完整的脉冲,与写地址写数据相反
        DS1302_SCLK = 1;    //SCLK上升沿,MCU向DS1302写入数据        
    }
    
    for(i=0;i<8;i++)
    {
        DS1302_SCLK = 1;    //写地址读数据
        DS1302_SCLK = 0;    //SCLK下降沿,MUC读取DS1302的数据
        if(DS1302_IO) {Data = 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_ADDR,0x00);    //解除芯片写保护
    DS1302_WriteByte(DS1302_YEAR_ADDR,        DS1302_Time[0]/10*16+DS1302_Time[0]%10);    //写入年数据,十进制转为十六进制
    DS1302_WriteByte(DS1302_MONTH_ADDR,        DS1302_Time[1]/10*16+DS1302_Time[1]%10);    //写入月数据
    DS1302_WriteByte(DS1302_DATE_ADDR,        DS1302_Time[2]/10*16+DS1302_Time[2]%10);    //写入日数据
    DS1302_WriteByte(DS1302_HOUR_ADDR,        DS1302_Time[3]/10*16+DS1302_Time[3]%10);    //写入小时数据
    DS1302_WriteByte(DS1302_MINUTE_ADDR,    DS1302_Time[4]/10*16+DS1302_Time[4]%10);    //写入分钟数据
    DS1302_WriteByte(DS1302_SECOND_ADDR,    DS1302_Time[5]/10*16+DS1302_Time[5]%10);    //写入秒钟数据
    DS1302_WriteByte(DS1302_DAY_ADDR,        DS1302_Time[6]/10*16+DS1302_Time[6]%10);    //写入星期数据
    DS1302_WriteByte(DS1302_WP_ADDR,0x80);    //开启芯片写保护
}

/**
  * @brief  DS1302读取时间,调用之后,DS1302中的数据会被读取到DS1302_Time数组中
  * @param  无
  * @retval 无
  */
void DS1302_ReadTime(void)
{
    unsigned char Temp;
    Temp = DS1302_ReadByte(DS1302_YEAR_ADDR);     DS1302_Time[0]=Temp/16*10+Temp%16;
    Temp = DS1302_ReadByte(DS1302_MONTH_ADDR);     DS1302_Time[1]=Temp/16*10+Temp%16;
    Temp = DS1302_ReadByte(DS1302_DATE_ADDR);     DS1302_Time[2]=Temp/16*10+Temp%16;
    Temp = DS1302_ReadByte(DS1302_HOUR_ADDR);     DS1302_Time[3]=Temp/16*10+Temp%16;
    Temp = DS1302_ReadByte(DS1302_MINUTE_ADDR); DS1302_Time[4]=Temp/16*10+Temp%16;
    Temp = DS1302_ReadByte(DS1302_SECOND_ADDR);    DS1302_Time[5]=Temp/16*10+Temp%16;
    Temp = DS1302_ReadByte(DS1302_DAY_ADDR);     DS1302_Time[6]=Temp/16*10+Temp%16;
}
#ifndef __DS1302_H__
#define __DS1302_H__

//外部可调用时间数组,索引0~6分别为年、月、日、时、分、秒、星期    
    extern unsigned char DS1302_Time[];
    
    
    void DS1302_Init(void);
    void DS1302_WriteByte(unsigned char Command,Data);
    unsigned char DS1302_ReadByte(unsigned char Command);
    void DS1302_SetTime(void);
    void DS1302_ReadTime(void);
    
#endif

2.3 LCD1602源程序及头文件

#include <REGX52.H>
#include "intrins.h"

//引脚配置,硬件原理图,普中A2
sbit LCD1602_RS = P2^6;
sbit LCD1602_RW = P2^5;
sbit LCD1602_E  = P2^7;
#define LCD1602_DATAPORT P0


/**
  * @brief  LCD1602延时函数
  * @param  xms=1, 延时1ms
  * @retval 无
  */
void LCD1602_Delayms(unsigned char xms)        //@11.0592MHz
{
    unsigned char i, j,k;

    for(k=0;k<xms;k++)
    {
        _nop_();
        i = 2;
        j = 199;
        do
        {
            while (--j);
        } while (--i);
    }

}

/**
  * @brief  LCD1602写命令,时序图
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD1602_WriteCommand(unsigned char Command)
{
    LCD1602_RS = 0;
    LCD1602_RW = 0;
    LCD1602_DATAPORT  = Command;
    LCD1602_E  = 1;
    LCD1602_Delayms(1);    //延时1ms
    LCD1602_E  = 0;
    LCD1602_Delayms(1);    //延时1ms
}

/**
  * @brief  LCD1602写数据,时序图
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD1602_WriteData(unsigned char Data)
{
    LCD1602_RS = 1;
    LCD1602_RW = 0;
    LCD1602_DATAPORT  = Data;
    LCD1602_E  = 1;
    LCD1602_Delayms(1);    //延时1ms
    LCD1602_E  = 0;
    LCD1602_Delayms(1);    //延时1ms
}

/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD1602_Init(void)
{
    LCD1602_WriteCommand(0x38);    //0011_1000 功能设置,设置16x2显示,5x7点阵,8位数据接口
    LCD1602_WriteCommand(0x0C);    //0000_1100 显示开关控制,显示开,光标关,闪烁关    
    LCD1602_WriteCommand(0x06);    //0000_0110 输入方式设置,数据写后,AC自动加一,画面不动
    LCD1602_WriteCommand(0x01);    //0000_0001 清屏,数据指针清零、所有显示清零
}
/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD1602_SetCursor(unsigned char Line,unsigned char Column)
{
    if(Line == 1)
    {
        LCD1602_WriteCommand(0x80|(Column-1)); //设置要存入数据的DDROM地址,第一行地址
    }
    else
    {
        LCD1602_WriteCommand(0x80|(Column-1)+0x40); //设置要存入数据的DDROM地,第二行地址
    }
}
    

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD1602_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char)
{
    LCD1602_SetCursor(Line,Column);
    LCD1602_WriteData(Char);
}

/**
  * @brief  在LCD1602指定位置上显示所给字符串
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符串
  * @retval 无
  */
void LCD1602_ShowString(unsigned char Line,unsigned char Column,unsigned char *String)        //指针
{
    unsigned char i;
    LCD1602_SetCursor(Line,Column);
    for(i=0;String[i]!='\0';i++)    //字符串结束标志'\0'
    {
        LCD1602_WriteData(String[i]);
    }
    
}

/**
  * @brief  返回值=X的Y次方,指数运算
  */
int LCD_Power(int X,int Y)
{
    unsigned char i;
    int result = 1;
    for(i=0;i<Y;i++)
    {
        result = result * X;
    }
    return result;
}

/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD1602_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
    unsigned char i;
    LCD1602_SetCursor(Line,Column);
    for(i=Length;i>0;i--)
    {
        LCD1602_WriteData('0'+Number/LCD_Power(10,i-1)%10); // '0'=0x30,转换为字符显示;
        
        /** 
          * 789, 789/100%10, 取出百位
          * 789, 789/10%10, 取出十位
          * 789, 789/1%10, 取出个位
         */
    }
}

/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD1602_ShowSignedNum(unsigned char Line,unsigned char Column, int Number,unsigned char Length)
{
    unsigned char i;
    unsigned int Number1; 
    LCD1602_SetCursor(Line,Column);
    if(Number >= 0)
    {
        LCD1602_WriteData('+');
        Number1 = Number;
    }
    else
    {
        LCD1602_WriteData('-');
        Number1 = -Number;     //-32768
    }
    for(i=Length;i>0;i--)
    {
        LCD1602_WriteData('0'+Number1/LCD_Power(10,i-1)%10); 
    }
}

/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xffff
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD1602_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
    unsigned char i;
    unsigned char SingleNumber;
    LCD1602_SetCursor(Line,Column);
    for(i=Length;i>0;i--)
    {
        SingleNumber = Number/LCD_Power(16,i-1)%16; //从高位到低位,取出每一个十六进制数字
        if(SingleNumber < 10)
            LCD1602_WriteData('0'+SingleNumber); 
        else
            LCD1602_WriteData('A'+SingleNumber-10); //SingleNumber已含有10+x
    }
}

/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111_1111_1111_1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD1602_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
    unsigned char i;
    LCD1602_SetCursor(Line,Column);
    for(i=Length;i>0;i--)
    {
        LCD1602_WriteData('0'+Number/LCD_Power(2,i-1)%2); //从高位到低位,取出每一个二进制数字
    }
}
#ifndef __LCD1602_H__
#define __LCD1602_H__
    
    void LCD1602_WriteCommand(unsigned char Command);
    void LCD1602_WriteData(unsigned char Data);

    void LCD1602_Init(void);
    void LCD1602_ShowChar(unsigned char Line,unsigned char Column,unsigned char Char);
    void LCD1602_ShowString(unsigned char Line,unsigned char Column,unsigned char *String);
    void LCD1602_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
    void LCD1602_ShowSignedNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
    void LCD1602_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
    void LCD1602_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
    
#endif

 

posted @ 2022-08-07 22:29  豌豆茶  阅读(341)  评论(0编辑  收藏  举报