×
单片机 > 单片机程序设计 > 详情

基于ATMEGA16的DS1302可调万年历程序

发布时间:2020-06-06 发布时间:
|


 

程序:

main函数:

/*
程序功能:DS1302实时时钟显示
作者:朱波
时间:2012年2月3日
通信方式:3线串行通信
使用说明:本程序模仿家用万年历,能够进行时间的设定
时间设定方法:1.按下设置键进入设置模式
                        2.按选择键对要设置的项进行选择
                        3.按加一键对选择项加一
                        4.完成全部选择后出现"please check OK!"
       此时按下确定键就回到时间模式
备注:可以通过主函数中的宏定义进行时间设置
*/
#include 
#include 
#include "delay.h" 
#include "display.h"
#include "ds1302.h"
#include "key.h"
#define  uchar unsigned char
#define  uint  unsigned int
//用于校准时间
#define year 12//年份
#define week 4//星期
#define month 12//月
#define daytime 23//日
#define hour  12//小时
#define minute 59//分钟
#define seconds 55//秒
uint time_data[7]={year,week,month,daytime,hour,minute,seconds};
//年星期月日时分秒(设置初始时间)
void  main()
{ 
     int_init();//中断初始化
  SEI();//开启总中断
     LCD_init();//1602液晶初始化
  SCK_OUT;//对时钟进行操作将SCK设置成输出
  RST_OUT;//对时钟进行操作将RST设置成输出
  
  set_rtc();//设置时间
  hour_mode(24);//时间显示模式设定,12小时显示没有做好处理
                //只是注意此函数的写法
  while(1)
  {
      read_rtc();//读取时间
   time_pro();//时间处理
  
   display();//显示时间
  }
}

delay.c:

#include"delay.h"
void delay(unsigned int ms)
{
        unsigned int i,j;
 for(i=0;i
#include 

#include "key.h"
#include "display.h"
#define  uchar unsigned char
#define  uint  unsigned int

#define SCK_CLR PORTA&=~BIT(6)
#define SCK_SET PORTA|=BIT(6)
#define SCK_OUT DDRA|=BIT(6)

#define RST_CLR PORTC&=~BIT(7)
#define RST_SET PORTC|=BIT(7)
#define RST_OUT DDRC|=BIT(7)

#define IO_CLR PORTA&=~BIT(7)//IO引脚输出低电平
#define IO_SET PORTA|=BIT(7)//IO引脚输出高电平
#define IO_OUT DDRA|=BIT(7)//IO引脚设置为输出
#define IO_IN DDRA&=~BIT(7)//IO引脚设置为输入
#define IO_R PINA&BIT(7)//IO引脚进行读取操作


extern int time_data[7];

uchar write_add[7]={0X8C,0X8A,0X88,0X86,0X84,0X82,0X80};//写地址(最低位为0)
uchar read_add[7]={0x8d,0x8b,0x89,0x87,0x85,0x83,0x81};//读地址(最低位为1)

uchar table[];//用于计算
void write_ds1302_byte(uchar dat)//在ds1302中写指令字节
{
     uint i;
   IO_OUT;
  for(i=0;i<8;i++)//一位一位往里写,共写8位
  {
     SCK_CLR;//开始时时序为0
     //先准备好数据,在给上升沿
    if(dat&0x01)//如果数据位为1
  {
    IO_SET;//IO为1
  }
  else//如果数据位为0
  {
    IO_CLR;//IO为0
  }
  SCK_SET;//SCLK拉高开始传输数据
  dat=dat>>1;//移位进行下一个字节的传输(写的时候放到后面)
  }
}

uchar read_ds1302(uchar add)//单字节读
{
      uchar i,value;//定义变量
    RST_CLR;
   SCK_CLR;//开始RET和SCLK时序为低
   RST_SET;
   //根据时序要传输命令
   write_ds1302_byte(add);//执行完此句后,SCLK时序到下降沿处开始读数据
   IO_IN;//IO设置成输入
   for(i=0;i<8;i++)//一个字节为8位,一位一位的读
   {
     SCK_CLR;//时钟拉低开始传输
     value=value>>1;//读的时候放到前面
     if(IO_R)//读的结果如果为1
  {
    value=value|0X80;//从低位开始读取
  }
  SCK_SET;//时钟拉高结束传输
  
   }//循环结束后SCLK时序到了最后,将RST拉低
   RST_CLR;
   return value;//将数据返回  
}
void write_ds1302(uchar add,uchar dat)//单字节写(传递两个参数一个是地址一个是数据)
{
    RST_CLR;
   NOP();
   SCK_CLR;//开始RET和SCLK时序为低
   RST_SET;//根据时序开始写入东西时将RST拉高
   write_ds1302_byte(add);//写入地址
   write_ds1302_byte(dat);//写入数据
   RST_CLR;//根据时序,当写完东西时RST拉低
}[page]

void set_rtc(void)//设置时间(初始化时间)
{
    uchar i,k;
   for(i=0;i<7;i++)//将十进制转换为16进制
   {
     k=time_data[i]/10;//得到十位
  time_data[i]=time_data[i]%10;//得到个位
  time_data[i]=time_data[i]+k*16;//变成BCD码
   }
   write_ds1302(0x8e,0x00);//去除写保护(control寄存器)
   for(i=0;i<7;i++)//对时
   {
     write_ds1302(write_add[i],time_data[i]);
   }
   write_ds1302(0x8e,0x80);//(wp位置1)加入写保护
}


void read_rtc(void)//读时钟
{
   uchar i;
  for(i=0;i<7;i++)
  {
    time_data[i]=read_ds1302(read_add[i]);//把时钟放到数组里
  }
}

void time_pro(void)//时间处理函数(16进制转换为十进制)
{
  table[0]=time_data[6]%16;//显示秒个位
 table[1]=time_data[6]/16;//显示秒十位
 
    table[2]=time_data[5]%16;//显示分个位
 table[3]=time_data[5]/16;//显示分十位
 
 table[4]=time_data[4]%16;//显示小时个位
 table[5]=time_data[4]/16;//显示小时十位
 
 table[6]=time_data[3]%16;//显示日个位
 table[7]=time_data[3]/16;//显示日十位
 
 table[8]=time_data[2]%16;//显示月个位
 table[9]=time_data[2]/16;//显示月十位
 
 table[10]=time_data[1]%16;//显示星期
 
 
 table[12]=time_data[0]%16;//显示年个位
 table[13]=time_data[0]/16;//显示年十位
}
void hour_mode(uchar mode)//mode为12时为12小时格式,为24时为24小时格式
{
    uint value;
  write_ds1302(0x8e,0x00);//去除写保护(control寄存器)
 if(mode==12)
 {
    value=read_ds1302(0x85);//读取小时当前值
    value=value|0x80;       //将小时数据最高位置1
    write_ds1302(0x84,value);//将置1后的小时数据写入小时寄存器
    //变为12小时格式
 }
 if(mode==24)
 {
    value=read_ds1302(0x85);//读取小时当前值
    value=value&0x7F;       //将小时数据最高位置0
    write_ds1302(0x84,value);//将置1后的小时数据写入小时寄存器
    //变为24小时格式
 }

}
 void int_init(void)
{
 MCUCR |= 0x00;
 MCUCSR|= 0x00;
 GICR  |= 0x40;
}

#pragma interrupt_handler int0_isr:2
void int0_isr(void)//在外部中断中进行时间设置
{
    uchar i=0,num=0,n=0,m=0,u=0,k=0,j=0,h=0;
    CLI();//进制中断
    LCD_init();//清屏
 showprompt();//显示提示信息
   write_ds1302(0x80,0x80);//时钟停止
   write_ds1302(0x8e,0x00);//去除写保护(control寄存器)
 while(!(num==4)) //num含义:1(加一),2(选择),3(设置),4(确定)
 {  
       if(key_press())    //检测是否有按键按下
        {
          num=key_scan();   //扫描并返回翻译后的键码
       if(num==2)//进入选择状态
    {
      i++;
   switch(i)
   { 
     case 1://设置年
       LCD_init();//清屏
 &nbs设置年
       LCD_init();//清屏
    while(!(n==2))//再次按选择键就进入下个项目的设置
    {
      if(key_press())
      {
      n=key_scan();   //扫描并返回翻译后的键码
      if(n==1)
      time_data[0]++;//按一下年加一
      }
    //以下是时间微调,因为在DS1302中写入的是BCD码,所以在实际中
    //可以用下面的调整方式,以下只处理到60年
         if(time_data[0]==0x0a)
         {
           time_data[0]=0x10;
         }
         if(time_data[0]==0x1a)
         {
           time_data[0]=0x20;
         }
         if(time_data[0]==0x2a)
         {
           time_data[0]=0x30;
         }
         if(time_data[0]==0x3a)
         {
           time_data[0]=0x40;
         }
         if(time_data[0]==0x4a)
         {
           time_data[0]=0x50;
         }
      write_ds1302(write_add[0],time_data[0]);//写入地址和数据
      time_pro();//时间处理
      showyear();//显示年
    }
       // break;不用终止程序,当程序跳出上边循环时,会进入下边程序
    case 2://月设置
    LCD_init();//清屏
    while(!(m==2))//再次按选择键就进入下个项目的设置
    {
      if(key_press())
      {
        m=key_scan();   //扫描并返回翻译后的键码
        if(m==1)
         time_data[2]++;//按一下月加一
     if(time_data[2]==0x13)//一年有12个月
      time_data[2]=1;
      }
        //BCD码处理
         if(time_data[2]==0x0a)
         {
           time_data[2]=0x10;
         }
         if(time_data[2]==0x1a)
         {
           time_data[2]=0x20;
         }       
      write_ds1302(write_add[2],time_data[2]);
      time_pro();//时间处理
      showmonth();//显示月
    }
    //break;
     case 3: //日设置
    LCD_init();//清屏
    while(!(u==2))//再次按选择键就进入下个项目的设置
    {
      if(key_press())
      {
        u=key_scan();   //扫描并返回翻译后的键码
        if(u==1)
         time_data[3]++;//按一下日加一
     if(time_data[3]==0x32)//一个月最多有31天
      time_data[3]=1;
      }
        //BCD码处理
         if(time_data[3]==0x0a)
         {
           time_data[3]=0x10;
         }
         if(time_data[3]==0x1a)
         {
           time_data[3]=0x20;
         } 
       if(time_data[3]==0x2a)
         {
           time_data[3]=0x30;
         }          
      write_ds1302(write_add[3],time_data[3]);
      time_pro();//时间处理
      showdaytime();//显示日
    }
    //break;
     case 4: //小时设置
    LCD_init();//清屏
    while(!(k==2))//再次按选择键就进入下个项目的设置
    {
      if(key_press())
      {
        k=key_scan();   //扫描并返回翻译后的键码
        if(k==1)
         time_data[4]++;//按一下小时加一
     if(time_data[4]==0x25)//一天24小时
      time_data[4]=1;
      }
        //BCD码处理
         if(time_data[4]==0x0a)
         {
           time_data[4]=0x10;
         }
         if(time_data[4]==0x1a)
         {
           time_data[4]=0x20;
         }          
      write_ds1302(write_add[4],time_data[4]);
      time_pro();//时间处理
      showhour();//显示小时
      } 
      //break; 
     case 5: //分钟设置
    LCD_init();//清屏
    while(!(j==2))//再次按选择键就进入下个项目的设置
    {
      if(key_press())
      {
        j=key_scan();   //扫描并返回翻译后的键码
        if(j==1)
         time_data[5]++;//按一下分钟加一
     if(time_data[5]==0x5a)//一小时60分钟
      time_data[5]=0x00;
      }
        //BCD码处理
         if(time_data[5]==0x0a)
         {
           time_data[5]=0x10;
         }
         if(time_data[5]==0x1a)
         {
           time_data[5]=0x20;
         }
      if(time_data[5]==0x2a)
         {
           time_data[5]=0x30;
         }
         if(time_data[5]==0x3a)
         {
           time_data[5]=0x40;
         }
      if(time_data[5]==0x4a)
         {
           time_data[5]=0x50;
         }
         if(time_data[5]==0x5a)
         {
           time_data[5]=0x60;
         }                   
      write_ds1302(write_add[5],time_data[5]);
      time_pro();//时间处理
      showminute();//显示分钟
       } [page]
    //break;
     case 6: //星期设置
    LCD_init();//清屏
    while(!(h==2))//再次按选择键就进入下个项目的设置
    {
      if(key_press())
      {
        h=key_scan();   //扫描并返回翻译后的键码
        if(h==1)
         time_data[1]++;//按一下小时加一
     if(time_data[1]==0x08)//一天24小时
      time_data[1]=1;
      }
              
      write_ds1302(write_add[2],time_data[2]);
      time_pro();//时间处理
      showweek();//显示星期
      } 
      default:
      LCD_init();//清屏
      showmessage();
      break;
     } 
    
      }
    
       }
   }
 
    write_ds1302(0x8e,0x80);//(wp位置1)加入写保护
    write_ds1302(0x80,0x00);//时钟开始
    LCD_init();//清屏
    SEI();
}

key.c:

#include 
#include 
#include "delay.h"

#define  uchar unsigned char
#define  uint&n月设置
    LCD_init();//清屏
    while(!(m==2))//再次按选择键就进入下个项目的设置
    {
      if(key_press())
      {
        m=key_scan();   //扫描并返回翻译后的键码
        if(m==1)
         time_data[2]++;//按一下月加一
     if(time_data[2]==0x13)//一年有12个月
      time_data[2]=1;
      }
        //BCD码处理
         if(time_data[2]==0x0a)
         {
           time_data[2]=0x10;
         }
         if(time_data[2]==0x1a)
         {
           time_data[2]=0x20;
         }       
      write_ds1302(write_add[2],time_data[2]);
      time_pro();//时间处理
      showmonth();//显示月
    }
    //break;
     case 3: //日设置
    LCD_init();//清屏
    while(!(u==2))//再次按选择键就进入下个项目的设置
    {
      if(key_press())
      {
        u=key_scan();   //扫描并返回翻译后的键码
        if(u==1)
         time_data[3]++;//按一下日加一
     if(time_data[3]==0x32)//一个月最多有31天
      time_data[3]=1;
      }
        //BCD码处理
         if(time_data[3]==0x0a)
         {
           time_data[3]=0x10;
         }
         if(time_data[3]==0x1a)
         {
           time_data[3]=0x20;
         } 
       if(time_data[3]==0x2a)
         {
           time_data[3]=0x30;
         }          
      write_ds1302(write_add[3],time_data[3]);
      time_pro();//时间处理
      showdaytime();//显示日
    }
    //break;
     case 4: //小时设置
    LCD_init();//清屏
    while(!(k==2))//再次按选择键就进入下个项目的设置
    {
      if(key_press())
      {
        k=key_scan();   //扫描并返回翻译后的键码
        if(k==1)
         time_data[4]++;//按一下小时加一
     if(time_data[4]==0x25)//一天24小时
      time_data[4]=1;
      }
        //BCD码处理
         if(time_data[4]==0x0a)
         {
           time_data[4]=0x10;
         }
         if(time_data[4]==0x1a)
         {
           time_data[4]=0x20;
         }          
      write_ds1302(write_add[4],time_data[4]);
      time_pro();//时间处理
      showhour();//显示小时
      } 
      //break; 
     case 5: //分钟设置
    LCD_init();//清屏
    while(!(j==2))//再次按选择键就进入下个项目的设置
    {
      if(key_press())
      {
        j=key_scan();   //扫描并返回翻译后的键码
        if(j==1)
         time_data[5]++;//按一下分钟加一
     if(time_data[5]==0x5a)//一小时60分钟
      time_data[5]=0x00;
      }
        //BCD码处理
         if(time_data[5]==0x0a)
         {
           time_data[5]=0x10;
         }
         if(time_data[5]==0x1a)
         {
           time_data[5]=0x20;
         }
      if(time_data[5]==0x2a)
         {
           time_data[5]=0x30;
         }
         if(time_data[5]==0x3a)
         {
           time_data[5]=0x40;
         }
      if(time_data[5]==0x4a)
         {
           time_data[5]=0x50;
         }
         if(time_data[5]==0x5a)
         {
           time_data[5]=0x60;
         }                   
      write_ds1302(write_add[5],time_data[5]);
      time_pro();//时间处理
      showminute();//显示分钟
       } 
    //break;
     case 6: //星期设置
    LCD_init();//清屏
    while(!(h==2))//再次按选择键就进入下个项目的设置
    {
      if(key_press())
      {
        h=key_scan();   //扫描并返回翻译后的键码
        if(h==1)
         time_data[1]++;//按一下小时加一
     if(time_data[1]==0x08)//一天24小时
      time_data[1]=1;
      }
              
      write_ds1302(write_add[2],time_data[2]);
      time_pro();//时间处理
      showweek();//显示星期
      } 
      default:
      LCD_init();//清屏
      showmessage();
      break;
     } 
    
      }
    
       }
   }
 
    write_ds1302(0x8e,0x80);//(wp位置1)加入写保护
    write_ds1302(0x80,0x00);//时钟开始
    LCD_init();//清屏
    SEI();
}

key.c:

#include 
#include 
#include "delay.h"

#define  uchar unsigned char
#define  uint  unsigned int

uchar key_press()//判断按键是否被按下(按下返回1,没按下返回0)
{  
  uchar j;
   DDRD|=0X0F;//低四位为输出
  PORTD|=0X0F;//低四位输出低电平
 
  DDRD&=0XF0;//低四位为输入
  j=PIND;//读一下输入寄存器
  j&=0X0F;//屏蔽高四位
  if(j==0X0F)//如果j没变化,则返回0,否则返回1
  {
   return 0;
  }
  else
  {
   return 1;
  }
}
uchar key_scan()//按键扫描函数
{    
      uchar key;
    delay(10);
   if(key_press())//有按键按下时key_press()的值为1
   {
     key=PIND;//读取PIND值
     key&=0X0F;//去掉高4位
     switch(key)//开关语句,用于判断
     {
      case 0X0E://1110连接PD0的按键按下
    key=1;break;
   case 0X0D://1101连接PD1的按键按下
    key=2;break; 
   case 0X0B://1011连接PD2的按键按下
    key=3;break;
   case 0X07://0111连接PD3的按键按下
    key=4;break;
   default://都不是时随便返回一个值
    key=16;       
     }
    while(key_press());//在按键按下时执行完上边的程序后就执行此循环
                     //当按键松开时就跳出循环,目的是按一下就执行一次程序
   }
   else//没有按下时随便返回一个值
   {
   key=16;
   }
     return key;
}




『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
STM32单片机的复用端口初始化的步骤及方法