bluehacker

实时时钟DS1307的PIC程序

0
阅读(34812)

这是以前做的一个项目中的一部分,ds1307的驱动程序,用PIC C语言写的,采用的单片机是PIC16F628,因为不支持硬件I2C,所以用软件模拟的i2c协议.

/**************************************************************
** FileName: i2c_protocol.h
** author: bluehacker<KernelPanicCrash at gmail.com>
** data: 2006-1-04
*************************************************************/

#ifndef __LZP_TM_I2C_H_
#define __LZP_TM_I2C_H_
void i2c_start();
void i2c_stop();
bit i2c_check_ack(void);
void i2c_send_byte(unsigned char _data);
unsigned char i2c_receive_byte(unsigned char ack);
#endif
/*********************************************************
** FileName: i2c_protocol.c
** author: bluehacker<KernelPanicCrash at gmail.com>
** Date:2006-1-04
********************************************************/
#include "common.h"
#include "delay.h"
#include "i2c_protocol.h"
/* generate a start condition*/
void i2c_start()
{
 TRISA1=0;//SDA output
 SDA=1;
 asm("nop");
 SCL=1;
  DelayUs(5);
 SDA=0;
 DelayUs(5);
 SCL=0;
 asm("nop");
  asm("nop");
}
void i2c_stop()
{
 TRISA1=0;//SDA output
 SDA=0;
  asm("nop");
  SCL="1";
  DelayUs(5);
 SDA=1;
  DelayUs(5);
}
/*check ack*/
bit i2c_check_ack(void)
{
 
 TRISA1=0;//SDA output
 asm("nop");
 SDA=1;
 asm("nop");
 asm("nop");
 SCL=1;
  DelayUs(3);
  TRISA1=1;//SDA input
  if(SDA)/*error*/
  return 1;
 SCL=0;
 return 0;
}
void i2c_send_byte(unsigned char _data)
{
 unsigned char i;
 
 TRISA1=0;//SDA output
 for(i=0;i<8;i++)
 {
  asm("nop");
  if((_data<<i)&0x80)
   SDA=1;
  else
   SDA=0;
    asm("nop");
    SCL=1;
    DelayUs(5);
  SCL=0;
 }
}
/*receive a byte from i2c device
* Argument:
* ack---if 1,means after receive a byte, generate a '1' ack to terminate receive operation
* if 0,means after receive a byte ,generate a '0' ack(NOACK),then we can receive more bytes
*return value;
* return the byte we receive from i2c device
*/
unsigned char i2c_receive_byte(unsigned char ack)
{
 unsigned char i;
 unsigned char result="0";
 TRISA1=1;//SDA input
 SDA=1;//release SDA
 for(i=0;i<8;i++)
 {
 
    asm("nop");
    SCL=0;
    DelayUs(5);
  SCL=1;
 
    asm("nop");
    asm("nop");
   result<<=1;
    if(SDA)
     result=result+1;
  asm("nop");
  asm("nop");
 }
 SCL=0;
 TRISA1=0;//SDA output
 asm("nop");
 asm("nop");
 SDA=ack;
 
  DelayUs(5);
 SCL=1;
 
  DelayUs(5);
 SCL=0;
 asm("nop");
 return result;
}
/******************************************************
** FileName:ds1307.h
** ds1307 operation function define
** Author: Li Zheng-ping<KernelPanicCrash at gmail.com>
** date: 2006-1-19
************************************************************/
#ifndef __LZP_TM_DS1307_H__
#define __LZP_TM_DS1307_H__
#define WR1307  0xD0
#define RD1307  0xD1
void  init_ds1307( unsigned char _data);
bit read_ds1307(unsigned char addr,unsigned char *_data);
bit write_ds1307(unsigned char addr, unsigned char _data);
bit get_cmos_time(unsigned char *buf, unsigned char flag);
bit set_cmos_time(unsigned char *buf);
#endif

/******************************************************
** FileName: ds1307.c
**ds1307 related function implementation,(ds1307 driver)
* *Author: Li Zheng-ping<KernelPanicCrash at gmail.com>
* *date: 2006-1-19
*******************************************************/
#include "common.h"
#include "i2c_protocol.h"
#include "ds1307.h"
///////////////////////////////////////////////////////////////////////////
/* read a byte data from ds1307 RAM
* Arguments:
* addr----the address of RAM we need read
* *_data----return the data contained in "addr" RAM
*return value:
* 0----sucess,the *_data contains the data we need
* 1----failed, there are error(s) occurred
*/
bit read_ds1307(unsigned char addr,unsigned char *_data)
{
 
 i2c_start();
 /*send WR1307 to ds1307,select ds1307 work in write mode*/
 i2c_send_byte(WR1307);
 /*check the ds1307's ACK*/
 if(i2c_check_ack())//error
  return 1;
 
 //send address to ds1307, set the point to this address
 i2c_send_byte(addr);
 
 /*check the ds1307's ACK*/
 if(i2c_check_ack())//error
  return 1;
 /*stop*/
// i2c_stop();
/*restart*/
 i2c_start();
/*send RD1307 to select ds1307 to read mode*/
 i2c_send_byte(RD1307);
 /*check the ds1307's ACK*/
 if(i2c_check_ack())//error
  return 1;
/*now receive a byte from "addr"*/
 *_data=i2c_receive_byte(1);
 i2c_stop();
 return 0;
}
/* write data(usually time) to ds1307's register or RAM*/
bit write_ds1307(unsigned char addr, unsigned char _data)
{
 i2c_start();
 i2c_send_byte(WR1307);
 /*check the ds1307's ACK*/
 if(i2c_check_ack())//error
  return 1;
 i2c_send_byte(addr);
 /*check the ds1307's ACK*/
 if(i2c_check_ack())//error
  return 1;
 i2c_send_byte(_data);
 /*check the ds1307's ACK*/
 if(i2c_check_ack())//error
  return 1;
 i2c_stop();
 return 0;
}
/* initialize ds1307 real time clock*/
void init_ds1307(unsigned char i)
{
   unsigned char tmp;
  
  i2c_start();
  i2c_send_byte(WR1307);
  i2c_send_byte(0x07);
  i2c_send_byte(i);
  i2c_stop();
  read_ds1307(0x02,&tmp);
  tmp&=0xBF;
  write_ds1307(0x02,tmp);//select 24 hours mode
  read_ds1307(0x00,&tmp);
  tmp&=0x7f;
  write_ds1307(0x00,tmp);
}
/* get cmos time
* time format:
* buf[0]--year,
* buf[1]---month
* buf[2]---date;
* buf[3]---if flag="1", day of week, otherwise, hour
* buf[4]--- if flag="1", hour;otherwise, minute
* byf[5]---if flag="1", minute;otherwise second
* buf[6]---if flag="1",second
*return:
* 1---failed
* 0--success
*/
bit get_cmos_time(unsigned char *buf, unsigned char flag)
{
 unsigned char i;
 
 for(i=0;i<3;i++)
   {
    if(read_ds1307(6-i,&buf[i]))
     return 1;//failed
  if(read_ds1307(2-i,&buf[3+i+flag]))
   return 1;//failed
 }
 if(flag)
 {
  if(read_ds1307(3,&buf[3]))
   return 1;
 }
 return 0;
}

bit set_cmos_time(unsigned char *buf)
{
 unsigned char i;
 
 for(i=0;i<7;i++)
 {
  if(write_ds1307(i,buf[6-i]))
   return 1;
 }
 return 0;
}