单片机
返回首页

IIC的PCF8563实用时钟程序(iccavr)

2016-10-29 来源:eefocus

/*************************************

* PCF8563时钟程序    *
* 文 件 名:1602_8563.c     *
* 版    本:V22.02       *
* 主控芯片:Mega16L      *
* 工作频率:7.3728MHz     *
*************************************/
#include
#include
#include
#include
#include
#include
#include

//数据简化宏定义
#define uchar unsigned char
#define uint unsigned int

//全局变量定义
uchar timer[8];         //时钟数据

/**********************************
*         蜂鸣器发声函数        *
* 函数功能:蜂鸣器发出声响    *
* 入    口:n 声次数       *
*    i 声时长,i*10ms   *
* 返    回:无         *
* 发声频率:固定1KHz 无源    *
**********************************/
void spk(uchar i,uchar n)
    {
 uint a;
 for(;n;n--)
     {
  a=i*10;               //计算每声响的长度:MS
  for(;a;a--)
      {
   delay_us(500);     //响声频率为1KHZ
   SPK_TG;
   delay_us(500);
   SPK_TG;
   }
  SPK_OFF;            //响完关闭蜂鸣器
  delay_ms(100);      //每声响之间隔100MS
  }
 }

/**********************************
*          读出数据函数     *
**********************************/
uchar read_timer(void)
    {
 start();                //启动总线
 waitack();        //等待启动完成
 if(chkack()!=START)return I2C_ERR;    //检查是否启动成功
 write_tim(SLA_W);      //发送写地址
 write_tim(0x02);      //写数据地址
 
 start();
 waitack();        //等待启动完成
 if(chkack()!=RESTART)return I2C_ERR;   //检查是否启动成功
 write_tim(SLA_R);      //发送读地址
 
 timer[0]=read_tim()&0x7F;    //读出秒数据
 timer[1]=read_tim()&0x7F;    //读出分数据
 timer[2]=read_tim()&0x3F;    //读出时数据
 timer[3]=read_tim()&0x3F;    //读出日数据
 timer[4]=read_tim()&0x07;    //读出周数据
    if(timer[4]==0)timer[4]=7;
 timer[5]=read_tim();       //读出月数据
    if((timer[5]&0x80)==0)
         timer[7]=0x20;      //世纪位为0,是21世纪
    else timer[7]=0x19;     //世纪位不为0,是20世纪
 timer[5]=timer[5]&0x1F;
 timer[6]=read_tim();     //读出年数据
 stop();
 return I2C_CRR;
 }

/**********************************
*          写入时钟函数     *
**********************************/
uchar write_timer(void)
    {
 start();                //启动总线
 waitack();        //等待启动完成
 if(chkack()!=START)return I2C_ERR;    //检查是否启动成功
 write_tim(SLA_W);      //发送写地址
 write_tim(0x00);      //写数据首地址
 write_tim(0x20);      //写控制/状态寄存器1,暂停计时
 write_tim(0x00);      //写控制/状态寄存器2
 write_tim(0x00);      //写秒数据为0
 write_tim(timer[1]);     //写分数据
 write_tim(timer[2]);     //写时数据
 write_tim(timer[3]);     //写日数据
 write_tim(timer[4]);     //写周数据
 write_tim(timer[5]);     //写月数据
 write_tim(timer[6]);     //写年数据
 stop();
 return I2C_CRR;
 }
 
/**********************************
*          启动时钟函数     *
**********************************/
uchar start_timer(void)
    {
 start();                //启动总线
 waitack();        //等待启动完成
 if(chkack()!=START)return I2C_ERR;    //检查是否启动成功
 write_tim(SLA_W);      //发送写地址
 write_tim(0x00);      //写数据首地址
 write_tim(0x00);      //写控制/状态寄存器1,暂停计时
 stop();
 return I2C_CRR;
 }

/**********************************
*   将时钟数据转换后在LCD上显示   *
**********************************/ 
void timer_lcd(void)
    {
 locate(1,4);        //写指令:第1行第4列地址

 lcd_da((timer[7]>>4)+0x30);
 lcd_da((timer[7]&0x0f)+0x30);
 lcd_da((timer[6]>>4)+0x30);   //显示年
 lcd_da((timer[6]&0x0f)+0x30);
 lcd_da('/');
 lcd_da((timer[5]>>4)+0x30);   //显示月
 lcd_da((timer[5]&0x0f)+0x30);
 lcd_da('/');
 lcd_da((timer[3]>>4)+0x30);   //显示日
 lcd_da((timer[3]&0x0f)+0x30);

 locate(2,2);       //写指令:第2行地址
   
    lcd_da((timer[2]>>4)+0x30);   //时
 lcd_da((timer[2]&0x0f)+0x30);
 lcd_da(':');
 lcd_da((timer[1]>>4)+0x30);   //分
 lcd_da((timer[1]&0x0f)+0x30);
 lcd_da(':');   
 lcd_da((timer[0]>>4)+0x30);   //秒
 lcd_da((timer[0]&0x0f)+0x30);

 lcd_da(20);       //时间与星期间留1空格
 lcd_da('W');      //星期的前导字
 lcd_da('e');
 lcd_da('e');
 lcd_da('k');
 lcd_da((timer[4]&0x0f)+0x30);  //星期数据
 }

//定时器1:每秒从8563中读取4次数据,更新显示
void timer1_init(void)        //定时器1初始化:250毫秒定时,预分频256
    {
 TCCR1B = 0x00;          //停止定时器
 TCNT1H = 0x8F;      //初值高字节
 TCNT1L = 0x81;      //定时初值低字节
 TCCR1A = 0x00;
 TCCR1B = 0x03;           //启动定时器
 }

#pragma interrupt_handler timer1_ovf_isr:9
void timer1_ovf_isr(void)     //定时器1中断入口:250MS中断一次
    {
 TCNT1H = 0x8F;      //重装初值
 TCNT1L = 0x81;   
 read_timer();            //读出当前时钟
 timer_lcd();         //显示数据转换
 }

/**********************************
*          调整显示函数1    *
**********************************/
void set_xs1(uchar i)
    {
 lcd_da((timer>>4)+0x30);   //显示数据
 lcd_da((timer&0x0f)+0x30);
 }

/**********************************
*          调整显示函数2    *
**********************************/
void set_xs2(uchar data)
    {
 lcd_da((data>>4)+0x30);   //显示数据
 lcd_da((data&0x0f)+0x30);
 lcd(0x20);
 }

/**********************************
*           程序主函数        *
**********************************/
void main(void)
    {
 uchar set_flag=0;      //调整与正常工作标志
 uchar set_time;       //调整数据类型标志
 uchar set_bh=0;       //调整变化标志
 uchar a,a1;
 
 port_init();
 LED_ON;           //开LCD背光
 lcd_init();
 delay_ms(500);
 tonghe();
 delay_ms(2000);
 
 Twi_Init();
 delay_ms(100);
 CLI();         //关总中断
 timer1_init();     //定时器1初始化
 MCUCR = 0x00;
 GICR  = 0x00;
 TIMSK = 0x04;      //开放定时器0中断和比较中断
 SEI();        //开总中断
 
 cls();
 delay_ms(50);

 while(1)
     {
  a=KEY_RD;
  if(a!=0)
      {
   delay_ms(20);
   a1=KEY_RD;
   if(a1==a)
       {
    switch(a)
        {
     case 0x01:
      spk(10,1);
      if(set_flag==0)
          {
       TCCR1B=0x00;
       LED_ON;
       set_flag=1;
       cls();
       locate(1,4);     //显示“时间调整”
       xs_lcd('SET:');
       }
      else
       {
       TCCR1B=0x04;       //开启时钟
       set_flag=0;
       if(set_bh==1)
           {
        write_timer();    //写入新时间
        set_bh=0;
        }
       }
      break;
     case 0x02:
         if(set_flag==1)
          {
       spk(10,1);
       set_time++;     
       locate(2,2);      //显示待调整的数据
       switch(set_time)
              {
        case 1:
               xs_lcd('year:');
         set_xs1(6);   //显示年
         break;
        case 2:
            xs_lcd('muth:');
         set_xs1(5);   //显示月
         break;
        case 3:
            xs_lcd(' day:');
         set_xs1(3);   //显示日
         break;
        case 4:
            xs_lcd('hour:');
         set_xs1(2);   //显示时
         break;
        case 5:
            xs_lcd('mine:');
         set_xs1(1);   //显示分
         break;
        case 6:
            xs_lcd('week:');
         set_xs1(4);   //显示周
         break;
        default:set_time=0;break;
        }
       }
      break;
     case 0x04:
         if(set_flag==1)
          {
       spk(10,1);
       set_bh=1;
       locate(2,7);     //显示“时间调整”
       switch(set_time)
           {
        case 1:
            timer[6]-=0x01;
         if((timer[6]&0x0F)==0x0F)timer[6]&=0xF9;
         if(timer[6]>0x99)timer[6]=0x99;
         set_xs1(6);   //显示年
         break;
        case 2:
            timer[5]-=0x01;
         if((timer[5]&0x0F)==0x0F)timer[5]&=0xF9;
         if(timer[5]==0x00)timer[5]=0x12;
         set_xs1(5);   //显示月
         break;
        case 3:
            timer[3]-=0x01;
         if((timer[3]&0x0F)==0x0F)timer[3]&=0xF9;
         if(timer[3]==0x00)timer[3]=0x30;
         set_xs1(3);   //显示日
         break;
        case 4:
            timer[2]-=0x01;
         if((timer[2]&0x0F)==0x0F)timer[2]&=0xF9;
         if(timer[2]>0x24)timer[2]=0x23;
         set_xs1(2);   //显示时
         break;
        case 5:
            timer[1]-=0x01;
         if((timer[1]&0x0F)==0x0F)timer[1]&=0xf9;
         if(timer[1]>0x59)timer[1]=0x59;
         set_xs1(1);   //显示分
         break;
        case 6:
            timer[4]-=0x01;
         if(timer[4]>6)timer[4]=0x06;
         set_xs1(4);   //显示周
         break;
        default:set_time=0;break;
        }
       }
      else
       start_timer();
      break;
     case 0x08:
         if(set_flag==1)
          {
       spk(10,1);
       set_bh=1;
       locate(2,7);     //显示“时间调整”
       switch(set_time)
        {
        case 1:
         timer[6]+=0x01;
         if((timer[6]&0x0F)==0x0A)timer[6]=(timer[6]&0xF0)+0x10;
         if(timer[6]>0x99)timer[6]=0x00;
         set_xs1(6);   //显示年
         break;
        case 2:
         timer[5]+=0x01;
         if((timer[5]&0x0F)==0x0A)timer[5]=(timer[5]&0xF0)+0x10;
         if(timer[5]>=0x13)timer[5]=0x01;
         set_xs1(5);   //显示月
         break;
        case 3:
         timer[3]+=0x01;
         if((timer[3]&0x0F)==0x0A)timer[3]=(timer[3]&0xF0)+0x10;
         if(timer[3]>=0x31)timer[3]=0x01;
         set_xs1(3);   //显示日
         break;
        case 4:
         timer[2]+=0x01;
         if((timer[2]&0x0F)==0x0A)timer[2]=(timer[2]&0xF0)+0x10;
         if(timer[2]>=0x24)timer[2]=0x00;
         set_xs1(2);   //显示时
         break;
        case 5:
         timer[1]+=0x01;
         if((timer[1]&0x0F)==0x0A)timer[1]=(timer[1]&0xf0)+0x10;
         if(timer[1]>0x59)timer[1]=0x00;
         set_xs1(1);   //显示分
         break;
        case 6:
         timer[4]+=0x01;
         if(timer[4]>6)timer[4]=0x00;
         set_xs1(4);   //显示周
         break;
        default:set_time=0;break;
        }
       }
      else
       LED_OFF;      //关背光
      break;
     default:break;
     }
    }
   while(a!=0)
       {
    a=KEY_RD;
    delay_ms(10);
    }
   }
  }
 }

进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • 光控音效发生器电路

  • 如何利用ESP8266制作一个简单的四轴飞行器

  • 离子检测器电路分析

  • 一个简单的警笛电路图

  • 分享一个电网倾角计电路

  • 使用NE555和磁簧开关的橱柜照明电路

    相关电子头条文章