51单片机-DS1302(江科大学习总结)

          关于学习在B站上学习江科大的51单片机,DS1302这一部分的学习总结和思路梳理。用DS1302和LCD1602实现了江科大视频所展示的效果。

        实现的功能:用DS1302进行计时,并用LCD1602进行显示,可以使用独立按键进行设置,K1按键进行显示模式和设置时间模式切换,K2:当为设置时间模式时,可以按下K2选取任意时间位,K3:当K2选取了某时间位后,按下K3该位的时间会加1,K4:同理K3,按下后该时间位会减1.

首先先实现,DS1302芯片的写入时间和读取时间的功能。

 

这是DS1302的寄存器地址和单字节读、写的时序图。可知,无论读写,都是要先将要读的那个寄存器地址由单片机发送到DS1302,之后便能进行读或写数据的操作。

由晋中51-实验板原理图,对这3个引脚进行命名,方便编写代码。因为单片机上电所有引脚为高电平,又由DS1302时序图可知三个引脚都是低电平,所以要对这三个引脚进行初始化,将它们设置为低电平。

这是写数据的代码部分,定义两个形参来接受要写入DS1302的哪个寄存器和写入的数据,因为时序图是一个数一个数的写入,所以使用了按位与的方法来确保8个位只有一个数有效,然后通过左移和for循环把这八个位在每一次的时钟上升沿中,写入到DS1302。要注意的是,手册中当单字节    读或者写完成后,CE、SCLK都要置为低电平。

这是读取数据代码的部分。 

此上,写入和读取的函数功能就已经完成了。现在可以来写入时间,并读取时间了,并使用LCD1602显示出来。首先先宏定义一下这些寄存器的地址,以便使用。

 

 定义一个char类型的数组来存放初始时间,分别是年、月、日、时、分、秒。

 时间初始化函数,将初始时间,分别写入DS1302的对应寄存器,因为DS1302要写入的是BCD码,所以要将10进制数,通过这种方式转换成BCD码再按位写入,Write_WP是DS1302的写保护位,在写入数据之前要置0,写完后置1.

读数据并显示数据函数,去读已经写入的寄存器的时间,并在LCD上合适的位置显示出来 。

为了更好观看,用“—”和“:”字符把时间隔离起来。 

目前显示的时间的功能已经完成了,如果想要修改时间,只能去修改数组的内容,重新将文件烧录进单片机才能完成,很不方便,接下来是去完成通过用按键修改时间的功能。

定义一个Mode变量,如果Mode为0则是显示模式,显示时间,如果Mode为1 ,则进入校时模式,可以修改时间,再定义一个Num变量,来接收独立按键的置,当k1按下时返回1,再通过一个if判断,当按键按下时就能改变Mode。全局变量Mode为0。再用一个switch,case来选择这两个模式。

现在只差修改某位时间和修改时间的时候修改位的闪烁提示功能。

定义一个全局变量Timeselect,作为时间位选变量,按键2按下可以位选会加1,因为只有年、月、日、时、分、秒,所以当它大于5时,就会越界,要将它清零。因为这个timeselect是用来选数组的某个元素的,所以是从0开始,0-5刚好6个数。

 

当按下第三个按键或者第四个按键时,对应的选择位的时间就会被修改,修改时间的功能已经完成,现在要对时间的越界进行判断。

 

 

这是时间越界判断部分。

这部分是校时模式中,实时显示修改之后时间,并对应修改位有闪烁提示。闪烁功能的完成是用了一个Timeflag变量,并用了定时中断,每500ms进行取反,再用if,else判断,让选择时间位在LCD上来回 显示数字和空格就达到了闪烁提示的效果。

 

当从校时模式切换到显示模式时,又调用一次Set_ time()函数,对修改之后的时间,又写入DS1302,就能完成修改功能了。

        定时器代码、LCD模块、独立按键代码都是直接用的江科大的。

DS1302和主函数代码如下:

#include <REGX52.H>
sbit SCLK=P3^6;
sbit CE=P3^5;
sbit IO=P3^4;
void DS1302_init()
{
    SCLK=0;
    CE=0;
    IO=0;
}
void DS1302_Write(unsigned char Command,unsigned char Data)
{
    unsigned char i=0;
    CE=1;
    for(i=0;i<8;i++)
    {
        IO=Command&(0x01<<i);    
        SCLK=1;
        SCLK=0;
    }
    for(i=0;i<8;i++)
    {    
        IO=Data&(0x01<<i);
        SCLK=1;
        SCLK=0;
    }
    CE=0;
}
unsigned char DS1302_Read(unsigned char Command)
{
    unsigned char i=0;
    unsigned char Data=0x00;
    CE=1;
    for(i=0;i<8;i++)
    {
        IO=Command&(0x01<<i);
        SCLK=0;
        SCLK=1;
    }
    for(i=0;i<8;i++)
    {
        SCLK=1;
        SCLK=0;
        if(IO)
        {
            Data|=(0x01<<i);//读取DS1302某个寄存器的数据,在SCLK上升沿读取数据,判断IO口为高电平还是低电平
        }                    //由Data作为一个临时的存储站,用按位或的方法去记录这8次上升沿IO口的电平情况,
                            //并将Data返回,就能得到此时DS1302数据        
    }
    CE=0;
    IO=0;
    return Data;
}

主函数代码:

#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
#include "DS1302.h"
#include "key.h"
#include "Timer0.h"
#define Read_Year 0x8D
#define Read_Month 0x89
#define Read_Date 0x87
#define Read_Hour 0x85
#define Read_Min 0x83
#define Read_Second 0x81
#define Write_WP 0x8E
#define Write_Year 0x8C
#define Write_Month 0x88
#define Write_Date 0x86
#define Write_Hour 0x84
#define Write_Min 0x82
#define Write_Second 0x80
char Time[]={23,8,17,20,44,55};
unsigned char Mode,Num,Timeselect;//0是显示模式,1是校时模式
unsigned char Timeflag;
void Gap();
void Read_Show();
void Change_time();
void Set_time();
void main()
{
    DS1302_init();
    Timer0Init();
    LCD_Init();
    Gap();
    Set_time();
    while(1)
    {
        Num=key();
        if(Num==1)
        {
            if(Mode==0){Mode=1;Num=0;}
            else if(Mode==1){Mode=0;Set_time();Num=0;Timeselect=0;}
        }
        switch(Mode)
        {
            case 0:
                Read_Show();
                break;
            case 1:
                Change_time();
                break;
        }
    }
}
void Gap()
{
    LCD_ShowString(1,1,"  -  -  ");
    LCD_ShowString(2,1,"  :  :  ");

}
void Read_Show()
{
    unsigned char Temp;
    Temp=DS1302_Read(Read_Year);
    Time[0]=Temp/16*10+Temp%16;//BCD码转十进制后读取
    Temp=DS1302_Read(Read_Month);
    Time[1]=Temp/16*10+Temp%16;
    Temp=DS1302_Read(Read_Date);
    Time[2]=Temp/16*10+Temp%16;
    Temp=DS1302_Read(Read_Hour);
    Time[3]=Temp/16*10+Temp%16;
    Temp=DS1302_Read(Read_Min);
    Time[4]=Temp/16*10+Temp%16;
    Temp=DS1302_Read(Read_Second);
    Time[5]=Temp/16*10+Temp%16;
    LCD_ShowNum(1,1,Time[0],2);     
    LCD_ShowNum(1,4,Time[1],2);         
    LCD_ShowNum(1,7,Time[2],2);                 
    LCD_ShowNum(2,1,Time[3],2);     
    LCD_ShowNum(2,4,Time[4],2);         
    LCD_ShowNum(2,7,Time[5],2);     
}
void Set_time()
{
    DS1302_Write(Write_WP,0x00);
    DS1302_Write(Write_Year,Time[0]/10*16+Time[0]%10);
    DS1302_Write(Write_Month,Time[1]/10*16+Time[1]%10);
    DS1302_Write(Write_Date,Time[2]/10*16+Time[2]%10);    
    DS1302_Write(Write_Hour,Time[3]/10*16+Time[3]%10);
    DS1302_Write(Write_Min,Time[4]/10*16+Time[4]%10);
    DS1302_Write(Write_Second,Time[5]/10*16+Time[5]%10);    
    DS1302_Write(Write_WP,0x80);
}
void Change_time()
{
    if(Num==2)
    {
        Timeselect++;
        if(Timeselect>5){Timeselect=0;}
    }
    if(Num==3)
    {
        Time[Timeselect]++;
        if(Time[1]>12){Time[1]=1;}//月越界判断
        //日越界判断
        if(Time[1]==1||Time[1]==3||Time[1]==5||Time[1]==7||Time[1]==8||Time[1]==10||Time[1]==12)
        {
            if(Time[2]>31){Time[2]=1;}
        }
        else if(Time[1]==4||Time[1]==6||Time[1]==9||Time[1]==11)
        {
            if(Time[2]>30){Time[2]=1;}
        }            
        else if(Time[1]==2)
        {
            if(Time[0]%4==0)
            {
                if(Time[2]>29){Time[2]=1;}
            }
            else 
            {
                if(Time[2]>28){Time[2]=1;}
            }
        }
        if(Time[3]>23){Time[3]=0;}//时越界判断
        if(Time[4]>59){Time[4]=0;}//分越界判断
        if(Time[5]>59){Time[5]=0;}//秒越界判断
    }
    if(Num==4)
    {
        Time[Timeselect]--;
        if(Time[1]<1){Time[1]=12;}//月越界判断
        //日越界判断
        if(Time[1]==1||Time[1]==3||Time[1]==5||Time[1]==7||Time[1]==8||Time[1]==10||Time[1]==12)
        {
            if(Time[2]<1){Time[2]=31;}
            if(Time[2]>31){Time[2]=1;}
        }
        else if(Time[1]==4||Time[1]==6||Time[1]==9||Time[1]==11)
        {
            if(Time[2]<1){Time[2]=30;}
            if(Time[2]>30){Time[2]=1;}
        }            
        else if(Time[1]==2)
        {
            if(Time[0]%4==0)
            {
                if(Time[2]<1){Time[2]=29;}
                if(Time[2]>29){Time[2]=1;}
            }
            else 
            {
                if(Time[2]<1){Time[2]=28;}
                if(Time[2]>28){Time[2]=1;}
            }
        }
        if(Time[3]<0){Time[3]=23;}//时越界判断
        if(Time[4]<0){Time[4]=59;}//分越界判断
        if(Time[5]<0){Time[5]=59;}//秒越界判断
    }
    
    if(Timeflag==1&&Timeselect==0){LCD_ShowString(1,1,"  ");}
    else {LCD_ShowNum(1,1,Time[0],2);}
    
    if(Timeflag==1&&Timeselect==1){LCD_ShowString(1,4,"  ");}
    else {LCD_ShowNum(1,4,Time[1],2);}
    
    if(Timeflag==1&&Timeselect==2){LCD_ShowString(1,7,"  ");}
    else {LCD_ShowNum(1,7,Time[2],2);}
    
    if(Timeflag==1&&Timeselect==3){LCD_ShowString(2,1,"  ");}
    else {LCD_ShowNum(2,1,Time[3],2);}
    
    if(Timeflag==1&&Timeselect==4){LCD_ShowString(2,4,"  ");}
    else {LCD_ShowNum(2,4,Time[4],2);}
    
    if(Timeflag==1&&Timeselect==5){LCD_ShowString(2,7,"  ");}
    else {LCD_ShowNum(2,7,Time[5],2);}
}
void Timer0_Routine() interrupt 1
{
    static unsigned int T0Count;
    TL0 = 0x18;        //设置定时初值
    TH0 = 0xFC;        //设置定时初值
    T0Count++;
    if(T0Count>=500)//每500ms进入一次
    {
        T0Count=0;
        Timeflag=!Timeflag;//闪烁标志位取反
    }
}

 

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例 基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例 基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例 基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例 基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例基于51单片机开发的小程序,学习资料,用于学习51单片机的嵌入式开发,应用案例
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值