技术热线: 4007-888-234

QLdsPIC3]实时时钟[C30+dsPIC30F6014A]

更新时间: 2019-03-23
阅读量:3559

深圳市英锐恩科技有限公司:台湾麦肯单片机(Micon MDT单片机)亚太地区A级代理商

QLdsPIC3]实时时钟[C30+dsPIC30F6014A]
//实验目的:熟悉时钟芯片PCF8583以及IIC通信
//软件规划:
//         1,通过按下按键K7往时钟芯片内写入预设时间和日期为,包括毫秒、秒、分、时、日、月、年、星期
//         2、通过查询时钟芯片触发的中断读取时间(1秒执行一次)
//         3、时间和日期送LCD1602显示,显示格式如下:
//                     ------------------------
//                     |      HH:MM:SS      |
//                     |   Y:y M:mm D:dd  W   |
//                     ------------------------
//硬件要求:拨码开关S13全部置ON
//          拨码开关S2第2位置ON
//          跳线J18全部接通

#include             //dsPIC30F6014标准头文件

  _FOSC(CSW_FSCM_OFF & XT_PLL4);  //4倍频晶振,Failsafe 时钟关闭
  _FWDT(WDT_OFF);                 //关闭看门狗定时器
  _FBORPOR(PBOR_OFF & MCLR_EN);   //掉电复位禁止,MCLR复位使能。
  _FGS(CODE_PROT_OFF);            //代码保护禁止


#define i_o   PORTGbits.RG3       //定义DS1302的数据口
#define sclk  PORTGbits.RG2       //定义DS1302的时钟口
#define intr  PORTAbits.RA12      //定义DS1302的复位口

#define rs LATBbits.LATB4         //定义LCD控制位(注意这里只能用LATB寄存器,不能直接用PORTB寄存器)
#define rw LATBbits.LATB5
#define e  LATBbits.LATB6


// unsigned char time_rx;
  unsigned char __attribute__((address(0x900))) rd_data[6]={0,0,0,0,0,0};       //定义接收寄存器
// LCD显示数据
  unsigned char __attribute__((address(0x920))) lcd[16]={' ',' ',' ',' ',0,0,':',0,0,':',0,0,' ',' ',' ',' '};
  unsigned char __attribute__((address(0x940))) lcd1[16]={'Y',':',0,' ','M',':',0,0,' ','D',':',0,0,' ',' ',0};

//定义待设置的时间:豪秒、 秒、 分、 时、    日/年、     月/星期
const char table[]={ 0,    88,  88,  18       ,41        ,50};
//                 0豪秒;58秒;58分;12时   0年29日     12月星期1


//****************************延时程序**************************************
void  delay()              //延时程序
    {
     int i;                 //定义整形变量
     for(i=0;i<10;i++);     //延时
    }

//***************************写PCF8583程序**********************************
void wr_data(unsigned char temp)
{
 I2CTRN=temp;                      //数据送IIC的发送寄存器       
    while(!IFS0bits.MI2CIF);          //等待发送完成
    IFS0bits.MI2CIF=0;
}
 
//**************************等待总线空闲为空程序****************************
void finish()
{
    while(!IFS0bits.MI2CIF);         //等待总线空闲
    IFS0bits.MI2CIF=0; 
}

//*************************写LCD程序****************************************
//写一个字节数据函数
//在电平发生改变后需要插入一段延时时间,否则LCD反应不过来。
void write(unsigned int x)
 {
  PORTD=x;                   //待显示数据送PORTD口
  delay();                  
  rs=1;                      //该字节数据为数据,而不是命令
  delay();
  rw=0;                      //此次操作为写,而不是读
  delay();
  e=0;                       //拉低使能信号
  delay();                   //保持使能信号为低一段时间
  e=1;                       //拉高使能信号,建立LCD操作所需要的上升沿
  delay();
 }

//********************LCD显示设置函数**************************************
//在电平发生改变后需要插入一段延时时间,否则LCD反应不过来。
void lcd_enable()
 {
   delay();
   rs=0;                     //该字节数据为命令,而不是数据
   delay();
   rw=0;                     //此次操作为写,而不是读
   delay();
   e=0;                      //拉低使能信号
   delay();                  //保持使能信号为低一段时间
   e=1;                      //拉高使能信号,建立LCD操作所需要的上升沿
   delay();
}

//**********************IIC初始化函数***************************************
void i2c_init()
{
    TRISB=0X0000;              //设置B口为输出
    TRISD=0X0000;              //设置D口为输出
    TRISC=0XFFFF;
 TRISG=0XFFFF;
    I2CCON=0;
    I2CSTAT=0;
    I2CBRG=15;                //400K
    I2CCONbits.I2CEN=1;       //使能IIC
}

//*********************LCD初始化函数**************************************
void lcd_init()
 {
    PORTD=0X1;                 //清除显示
    lcd_enable();
    PORTD=0X38;                //8位2行5*7点阵
    lcd_enable();
    PORTD=0X0e;                //显示开,光标开,闪烁
    lcd_enable();
    PORTD=0X06;                //文字不动,光标右移
    lcd_enable();
 }

//*******************PCF8583中断使能函数***********************************
void i2c_interrupt_init()
{
//    IPC4=7;                    //优先级别最高
    IEC1bits.INT1IE=0;           //使用查询方式
    IFS1bits.INT1IF=0;           //清除中断标志位
    INTCON2bits.INT1EP=1;        //负边沿触发

    I2CCONbits.SEN=1;            //发送起始位
    finish();                    //等待完成

    wr_data(0xa0);               //发送控制命令和写命令
    wr_data(0);                  //写8583的第0单元
    wr_data(4);                  //写入数据4(使能中断功能)

    I2CCONbits.RSEN=1;           //发重启动位
    finish();                    //等待完成

    wr_data(0xa0);               //发送控制命令和写命令
    wr_data(8);                  //写8583的第8单元
    wr_data(9);                  //写入数据9(计时中断功能)
    
    I2CCONbits.PEN=1;            //发停止位
    finish();                    //等待完成
}

//***********************LCD显示函数************************************
void lcd_display()
 { 
    unsigned char i,j;
    PORTD=0X80;                  /显示地址
    lcd_enable();
    for(i=0;i<16;i++)            //一共16字节数据
       {
         write(lcd[i]);          //查表获取数据并调用写一个字节数据函数送LCD显示
         for(j=0;j<5;j++)        //延时一段时间(主要是为了控制显示的速度)
          {delay();}
       }

    PORTD=0X00c0;                //日期时间显示地址
    lcd_enable();
    for(i=0;i<16;i++)            //一共16字节数据
       {
         write(lcd1[i]);         //查表获取数据并调用写一个字节数据函数送LCD显示
         for(j=0;j<5;j++)        //延时一段时间(主要是为了控制显示的速度)
          {delay();}
       }
 }

//***********************设置初始时间函数******************************
void i2c_write()
{
    unsigned char i;

 I2CCONbits.SEN=1;            //发送启动位
    finish();                    //等待完成

    wr_data(0xa0);               //发送控制命令和写命令
    wr_data(1);                  //待修改的8583起始单元地址(毫秒单元;地址自动+1)
 for(i=0;i<6;i++)             //共修改6个单元(时间跟日期)
      {
      wr_data(table[i]);      //查表写数据
      }
  
    I2CCONbits.PEN=1;            //发送停止位
    finish();                    //等待完成
}

//************************读时间函数***********************************
void i2c_read()
{
 unsigned char i;
   
    I2CCONbits.SEN=1;           //发送起始位
    finish();                   //等待完成

    wr_data(0xa0);              //发送控制命令和写命令
    wr_data(2);                 //读时间的起始单元
   
    I2CCONbits.RSEN=1;          //发重启动位
    finish();                   //等待完成
    wr_data(0xa1);              //发送控制命令和读命令

 for(i=0;i<7;i++)            //读取时间
      {
         I2CCONbits.RCEN=1;     //使能IIC的读功能
      rd_data[i]=I2CRCV;     //保存读取到的时间
      finish();              //等待完成
         I2CCONbits.ACKEN=1;    //使能应答功能
         if(i==6) I2CCONbits.ACKDT=1;   //不是最好一个数据,应答信号为0,继续读数据
         else I2CCONbits.ACKDT=0;       //做后一个数据,应答信号为1

         while(!IFS0bits.MI2CIF);
         IFS0bits.MI2CIF=0;  
      }
  
    I2CCONbits.PEN=1;           //发送停止位
    finish();                   //等待完成
}

//*************读取时间转换成BCD码并存储到LCD显示缓冲单元*************
void hex2bcd()
{
 lcd[11]=(rd_data[1]&0xf)+0x30;        // 1/10 second
    lcd[10]=(rd_data[1]>>4)+0x30;         // second
   
    lcd[8]=(rd_data[2]&0xf)+0x30;         // 1/10 minute
    lcd[7]=(rd_data[2]>>4)+0x30;          // minute
 
    lcd[5]=(rd_data[3]&0xf)+0x30;         // 1/10 hour
    lcd[4]=(rd_data[3]>>4)+0x30;          // hour


    lcd1[12]=(rd_data[4]&0xf)+0x30;         // 1/10 date
    lcd1[11]=((rd_data[4]>>4)&3)+0x30;      // data
    lcd1[2]=(rd_data[4]>>6)+0x30;          // year

    lcd1[7]=(rd_data[5]&0xf)+0x30;         // 1/10 month
    lcd1[6]=((rd_data[5]>>4)&1)+0x30;     // month
    lcd1[15]=(rd_data[5]>>5)+0x30;         // weekday
}

//***********************主函数**************************************
int main(void)
{
 i2c_init();                 //系统初始化
    lcd_init();                 //LCD初始化
    i2c_interrupt_init();       //芯片中断使能
    while(1)
    {
     while(!PORTCbits.RC3)   
      {
  i2c_write();            //设置初始时间
        while(!PORTCbits.RC3);
      }
       
    while(IFS1bits.INT1IF)      //等待中断
       {
       
        IFS1bits.INT1IF=0;     
        i2c_interrupt_init();  //重新初始化中断,以便清除8583芯片内中断标志位
        i2c_read();            //读取时间
        hex2bcd();             /结果转换成BCD码
        lcd_display();         /送LCD显示
       }
     }
}