SSブログ

Maruduinoで時計を作る。リアルタイムクロック(RTC MRX-8564)の利用。 [アプリケーション]

組み立て編はこちらです。
http://maruduino.blog.so-net.ne.jp/2010-08-07

Img_2082.jpg組み立てが完了したので、簡単な?スケッチを記述してみました。ご参考になれば幸いです。
Wireライブラリを使って通信してみたのですが、あまり安定しない、読み出しがおかしい?などがあったので、ソフトウエアでI2C通信を実現しています。
Arduinoは勿論マスターモードとしています。

操作方法を書いておきます。

時刻設定モード:
SW1とSW3の同時押しで時刻設定モードに入ります。
LCDの上段には変更する日付または時刻が表示され、下段には変更位置を示すポインターが表示されています。
SW2で数字を増やし、SW3で数字を減らしますが、上限、下限まで達すると循環します。
数字が確定したらSW4で次の項目に移動します。最後の項目である秒の変更が完了してSW4を押すと、その時点で時刻設定が確定します。
※SW1を押すと入力を取りやめ、通常の時刻表示モードに戻ります。
日付や時刻の整合性はあまりチェックしていませんので、注意してください。

アラーム設定モード:
SW1とSW2の同時押しでアラーム設定モードに入ります。
時刻設定モードと同様上段には時刻、下段にはポインターが表示されます。
その他操作も時刻設定モードと同じです。
時刻の整合性はあまりチェックしていませんので、注意してください。
※アラームを鳴らしたくない時は24:00に設定してください。

アラーム鳴動解除:
アラーム鳴動中にSW1を押す事で鳴動を解除できます。

バッテリーバックアップがされているので、電源を落としても時刻の更新やアラーム時刻の保持は行われています。


こうやってプロトタイピングして、もっとコンパクトであったり、電池で駆動できるものを作って日々の生活に役立てるとか良いですよね。
実際、Arduinoではありませんが、別のOne Chipマイコンで作った自作の目覚まし時計に日々起こされていますヨ。

以下にスケッチを記述しておきます。
※関数time_adjust_mode、Alarm_set_modeにアトミックな処理を追加 2010/08/07 18:35
/***********************************************************************/
/* LCD clock                                                           */
/* I2C bus control RTC()RTC8564 use                                    */
/*                                               designed by hamayan   */
/*                                               Copyright(C) hamayan  */
/***********************************************************************/
#define  _SOFT_I2C_
  
#if defined( _SOFT_I2C_ )
#else
#include <Wire.h>
#endif

#include <string.h>
#include <LiquidCrystal.h>
#include <avr/io.h>

/*************************************************************************/
/* defines                                                               */
/*************************************************************************/
#define  DI13     13
#define  DI12     12
#define  DI11     11
#define  DI10     10
#define  DI9      9
#define  DI8      8
#define  DI7      7
#define  DI6      6
#define  DI5      5
#define  DI4      4
#define  DI3      3
#define  DI2      2
#define  DI1      1
#define  DI0      0
#define  AN0      14
#define  AN1      15
#define  AN2      16
#define  AN3      17
#define  AN4      18
#define  AN5      19

#define  SW1      AN3
#define  SW2      AN2
#define  SW3      AN1
#define  SW4      AN0

#define  SCL_BIT         0b00100000   /*PC5=SCL*/
#define  SDA_BIT         0b00010000   /*PC4=SDA*/
#define  SCL_IS_HIGH     PORTC |= SCL_BIT  /*about 120ns swittching*/
#define  SCL_IS_LOW      PORTC &= ~SCL_BIT  /*about 120ns swittching*/
#define  SDA_IS_HIGH     PORTC |= SDA_BIT  /*about 120ns swittching*/
#define  SDA_IS_LOW      PORTC &= ~SDA_BIT  /*about 120ns swittching*/
#define  SDA_OUTPUT      DDRC |= SDA_BIT
#define  SDA_INPUT       DDRC &= ~SDA_BIT
#define  SCL_OUTPUT      DDRC |= SCL_BIT

#define  ACK             0  /*ACK Bit*/
#define  NACK            1  /*NACK Bit*/

#define  RTC8564_CTRL1      0x00
#define  RTC8564_CTRL2      0x01
#define  RTC8564_SEC        0x02
#define  RTC8564_MIN        0x03
#define  RTC8564_HOUR       0x04
#define  RTC8564_DAY        0x05
#define  RTC8564_WEEK       0x06
#define  RTC8564_MONTH      0x07
#define  RTC8564_YEAR       0x08
#define  RTC8564_MIN_ALM    0x09
#define  RTC8564_HOUR_ALM   0x0A
#define  RTC8564_DAY_ALM    0x0B
#define  RTC8564_WEEK_ALM   0x0C
#define  RTC8564_CLK_FREQ   0x0D
#define  RTC8564_TIM_CTRL   0x0E
#define  RTC8564_TIMER      0x0F

#if defined( _SOFT_I2C_ )
#define  RTC_BASE_ADDR      (0xa2)
#else
#define  RTC_BASE_ADDR      (0xa2 >> 1)
#endif

/*************************************************************************/
/*  global parameter                                                     */
/*************************************************************************/
enum RTC8564Str {SECONDS,MINUTES,HOURS,DAYS,WEEKDAYS,MONTHS,YEARS};

/* 0123456789012345678 */
/* 2007/11/21 15:12:00 */
char date[ 20 ];  /**/
char alarm_set_time[] = "00:00";

unsigned long sectim;
unsigned long lasttim;
unsigned char switches[3];
boolean  clock_disp = false;

const char date_limit[][2] = /*offset = 2*/
{
  {'0','9'},  /*year 10*/
  {'0','9'},  /*year 1*/
  {'/','/'},  /**/
  {'0','1'},  /*month 10*/
  {'0','9'},  /*month 1*/
  {'/','/'},  /**/
  {'0','3'},  /*day 10*/
  {'0','9'},  /*day 1*/
};
const char time_limit[][2] = /*offset = 0*/
{
  {'0','2'},  /*hour 10*/
  {'0','9'},  /*hour 1*/
  {':',':'},  /**/
  {'0','5'},  /*monite 10*/
  {'0','9'},  /*monite 1*/
  {':',':'},  /**/
  {'0','5'},  /*second 10*/
  {'0','9'},  /*second 1*/
};

LiquidCrystal lcd(DI8, DI9, DI4, DI5, DI6, DI7);

/*************************************************************************/
/*  prototype                                                            */
/*************************************************************************/
static void clk100( void );
static void I2C_Terminate( void );
static void StartCondition( void );
static void StopCondition( void );
static int RcvAck( void );
static void ResAck( int ack );
static void BitWrite( int data );
static int BitRead( void );
static int ByteWrite( int data );
static int ByteRead( int ack );

static void date_print( const char *src, int x, int y );
static void time_print( const char *src, int x, int y );
static void ConvertFromRTC2DateTime( void );

void I2C_Init( void );
int I2C_Block_Write( int addr, const char *data, int size );
int I2C_Block_Read( int addr, char *data, int size );
int I2C_Write( int addr, unsigned char data );
int I2C_Read( int addr, unsigned char *data );

int InitRTC8564( int force );
unsigned char *DateStr2RTC8564Str( unsigned char *dest, const char *source );
char *RTC8564Str2DateStr( char *dest, const unsigned char source[] );
int I2CRTC8564_Write( unsigned char addr, char data );
int I2CRTC8564_Read( unsigned char addr, char *buff );
int I2CRTC8564_Blk_Read( unsigned char addr, char *buff, int size );
int I2CRTC8564_Blk_Write( unsigned char addr, const char *data, int size );
int RTC8564_CalenderSet( const char *date_time );

#define  CalenderRead(buf)  I2CRTC8564_Blk_Read(RTC8564_SEC, buf, 7)

/*************************************************************************/
/*  digital2 external int handler                                        */
/*************************************************************************/
static void di2_int_hdr( void )
{
  sectim++;
  ConvertFromRTC2DateTime();  /*update clock*/
  if( clock_disp == true )
  {
    date_print(date,0,0);
    time_print(date,2,1);
  }
}

/*************************************************************************/
/*  Switch down detection                                                */
/*************************************************************************/
static unsigned char detect_sw_down( unsigned char *sw )
{
  unsigned char temp = PINC & 0x0f;

  sw[0] = sw[1];
  sw[1] = sw[2];
  sw[2] = temp ^ 0x0f;

  return sw[0] & sw[1] & temp;
}

/*************************************************************************/
/*  RTC8564 data convert to date time strings.                           */
/*************************************************************************/
static void ConvertFromRTC2DateTime( void )
{
  char buf[10];

  CalenderRead( buf );
  RTC8564Str2DateStr( date, (const unsigned char *)buf );  /**/
}

/*************************************************************************/
/*  Date lcd print                                                       */
/*************************************************************************/
static void date_print( const char *src, int x, int y )
{
  char buf[16];

  memcpy( buf, src, 10 );
  buf[10] = '\0';
  lcd.setCursor(x,y);
  lcd.print( buf );
}

/*************************************************************************/
/*  Time lcd print                                                       */
/*************************************************************************/
static void time_print( const char *src, int x, int y )
{
  char buf[16];

  memcpy( buf, &src[11], 8 );
  buf[8] = '\0';
  lcd.setCursor(x,y);
  lcd.print( buf );
}

/*************************************************************************/
/*  Time adjust                                                          */
/*************************************************************************/
static void time_adjust_mode( void )
{
  int pos = 2;
  char copy_date[20];
  boolean loop = true;

  memcpy( copy_date, date, sizeof(copy_date) );
  lcd.clear();
  date_print(copy_date,0,0);
  lcd.setCursor(pos,1);
  lcd.print( '^' );

  while( loop )
  {
    delay( 100 );
    switch ( detect_sw_down( switches ) )
    {
      case 0b00000001:  /*confirm*/
        lcd.setCursor(pos,1);
        lcd.print( ' ' );
        if( ++pos == 10 )
        {
          loop = false;
          break;
        }
        if( pos == 4 || pos == 7 ) pos++;
        lcd.setCursor(pos,1);
        lcd.print( '^' );
        break;
      case 0b00000010:  /*down number*/
        if( --copy_date[pos] < date_limit[pos - 2][0] ) copy_date[pos] = date_limit[pos - 2][1];
        lcd.setCursor(pos,0);
        lcd.print( copy_date[pos] );
        break;
      case 0b00000100:  /*up number*/
        if( ++copy_date[pos] > date_limit[pos - 2][1] ) copy_date[pos] = date_limit[pos - 2][0];
        lcd.setCursor(pos,0);
        lcd.print( copy_date[pos] );
        break;
      case 0b00001000:  /*abort*/
        return;
      default:
        break;
    }
  }

  pos = 0;
  loop = true;
  lcd.clear();
  time_print(copy_date,0,0);
  lcd.setCursor(pos,1);
  lcd.print( '^' );

  while( loop )
  {
    delay( 100 );
    switch ( detect_sw_down( switches ) )
    {
      case 0b00000001:  /*confirm*/
        lcd.setCursor(pos,1);
        lcd.print( ' ' );
        if( ++pos == 8 )
        {
          loop = false;
          break;
        }
        if( pos == 2 || pos == 5 ) pos++;
        lcd.setCursor(pos,1);
        lcd.print( '^' );
        break;
      case 0b00000010:  /*down number*/
        if( --copy_date[pos + 11] < time_limit[pos][0] ) copy_date[pos + 11] = time_limit[pos][1];
        lcd.setCursor(pos,0);
        lcd.print( copy_date[pos + 11] );
        break;
      case 0b00000100:  /*up number*/
        if( ++copy_date[pos + 11] > time_limit[pos][1] ) copy_date[pos + 11] = time_limit[pos][0];
        lcd.setCursor(pos,0);
        lcd.print( copy_date[pos + 11] );
        break;
      case 0b00001000:  /*abort*/
        return;
      default:
        break;
    }
  }

  noInterrupts();  /*global interrupt disable*/
  EIMSK &= ~0x01;  /*int0 interrupt disable*/
  interrupts();    /*global interrupt enable*/
  memcpy( date, copy_date, sizeof(date) );
  RTC8564_CalenderSet( date );  /*update calender.*/
  EIMSK |= 0x01;   /*int0 interrupt enable*/
}

/*************************************************************************/
/*  Alarm set                                                            */
/*************************************************************************/
static void Alarm_set_mode( void )
{
  int pos = 0;
  unsigned char temp;
  boolean loop = true;

  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print( alarm_set_time );
  lcd.setCursor(pos,1);
  lcd.print( '^' );

  while( loop )
  {
    delay( 100 );
    switch ( detect_sw_down( switches ) )
    {
      case 0b00000001:  /*confirm*/
        lcd.setCursor(pos,1);
        lcd.print( ' ' );
        if( ++pos == 5 )
        {
          loop = false;
          break;
        }
        if( pos == 2 ) pos++;
        lcd.setCursor(pos,1);
        lcd.print( '^' );
        break;
      case 0b00000010:  /*down number*/
        if( --alarm_set_time[pos] < time_limit[pos][0] ) alarm_set_time[pos] = time_limit[pos][1];
        lcd.setCursor(pos,0);
        lcd.print( alarm_set_time[pos] );
        break;
      case 0b00000100:  /*up number*/
        if( ++alarm_set_time[pos] > time_limit[pos][1] ) alarm_set_time[pos] = time_limit[pos][0];
        lcd.setCursor(pos,0);
        lcd.print( alarm_set_time[pos] );
        break;
      case 0b00001000:  /*abort*/
        return;
      default:
        break;
    }
  }

  temp = ((alarm_set_time[3] & 0x0f) << 4) + (alarm_set_time[4] & 0x0f);
  noInterrupts();  /*global interrupt disable*/
  EIMSK &= ~0x01;  /*int0 interrupt disable*/
  interrupts();    /*global interrupt enable*/
  I2CRTC8564_Write( RTC8564_MIN_ALM, temp );
  EIMSK |= 0x01;   /*int0 interrupt enable*/

  temp = ((alarm_set_time[0] & 0x0f) << 4) + (alarm_set_time[1] & 0x0f);
  noInterrupts();  /*global interrupt disable*/
  EIMSK &= ~0x01;  /*int0 interrupt disable*/
  interrupts();    /*global interrupt enable*/
  I2CRTC8564_Write( RTC8564_HOUR_ALM, temp );
  EIMSK |= 0x01;   /*int0 interrupt enable*/
}

/*************************************************************************/
/*  setup                                                                */
/*************************************************************************/
void setup()
{
  char buf[16];
  unsigned char temp;
//  static const char date_time[] = "2010/08/07 02:04:00";

  lcd.begin(16, 2);
  lcd.clear();
  lcd.println( "designed by hamayan." );

#if defined( _SOFT_I2C_ )
  I2C_Init();
#else  /*_SOFT_I2C_*/
  Wire.begin();  /*set i2c master device*/
  TWSR &= 0xfc;  /*baud rate control. prescaler=x1*/
  TWBR = 72;     /*baud rate control. 100khz*/
#endif  /*_SOFT_I2C_*/

  delay( 1000 );
  if( InitRTC8564( 0 ) < 0 )
  {
    lcd.clear();
    lcd.println( "rtc init error." );
    while(1) ;
  }

  I2CRTC8564_Read( RTC8564_MIN_ALM, (char *)&temp );
  if( !(temp & 0x80) )
  {
    alarm_set_time[3] = ((temp >> 4) & 0x07) + '0';
    alarm_set_time[4] = (temp & 0x0f) + '0';
    I2CRTC8564_Read( RTC8564_HOUR_ALM, (char *)&temp );
    alarm_set_time[0] = ((temp >> 4) & 0x03) + '0';
    alarm_set_time[1] = (temp & 0x0f) + '0';
  }

//  RTC8564_CalenderSet( date_time );  /*force setting calender.*/

  pinMode( SW1, INPUT );  /*set port at input mode*/
  pinMode( SW2, INPUT );  /*set port at input mode*/
  pinMode( SW3, INPUT );  /*set port at input mode*/
  pinMode( SW4, INPUT );  /*set port at input mode*/

  /*enable edge trigger interrupt*/
  attachInterrupt(0, di2_int_hdr, FALLING);
  DDRD &= ~0b00000100;  /*direction input*/
  PORTD |= 0b00000100;  /*enable pullup*/

  /*display alarm set time*/
  lcd.clear();
  lcd.setCursor(11,1);
  lcd.print( alarm_set_time );
  clock_disp = true;
  lasttim = millis() + 100;
}

/*************************************************************************/
/*  main loop                                                            */
/*************************************************************************/
void loop()
{
#define  ALARM_PERIOD  (60 * 5)
  unsigned char temp;
  static unsigned long oldsec;
  static int alarm_time;

  if( millis() > lasttim )
  {
    lasttim = millis() + 100;  /*next sample time update.*/
    switch ( detect_sw_down( switches ) )
    {
      case 0b00001010 :  /*time adjust mode*/
        clock_disp = false;
        time_adjust_mode();
        lcd.clear();
        lcd.setCursor(11,1);
        lcd.print( alarm_set_time );
        clock_disp = true;
        break;
      case 0b00001100 :  /*alarm set mode*/
        clock_disp = false;
        Alarm_set_mode();
        lcd.clear();
        lcd.setCursor(11,1);
        lcd.print( alarm_set_time );
        clock_disp = true;
        break;
      case 0b00001000 :  /*stop alarm*/
        alarm_time = 0;
        break;
      default :
        break;
    }
  }

  if( oldsec != sectim )
  {
    oldsec = sectim;

    if( date[18] == '0' &&
        date[17] == '0' &&
        alarm_set_time[4] == date[15] &&
        alarm_set_time[3] == date[14] &&
        alarm_set_time[1] == date[12] &&
        alarm_set_time[0] == date[11] )
      alarm_time = ALARM_PERIOD;  /*? minutes*/

    if( --alarm_time > 0 )
    {
      if( alarm_time % 3 ) tone( DI13, 1000, 800 );
    }
    else alarm_time = 0;
  }
}

/*************************************************************************/
/*  wait functions                                                       */
/*************************************************************************/
#define  wait1u()    delayMicroseconds(1)
#define  wait5u()    delayMicroseconds(5)

/*************************************************************************/
/*  100 clocks function                                                  */
/*************************************************************************/
static void clk100( void )
{
  int i;

  /*i2c lock release*/
  for( i = 0; i < 100; i++ )
  {
    SCL_IS_LOW;
    wait1u();
    SCL_IS_HIGH;
    wait1u();
  }
}

/*************************************************************************/
/*  initialize function                                                  */
/*************************************************************************/
void I2C_Init( void )
{
  int i;

  PORTC |= SDA_BIT | SCL_BIT;
  DDRC |= SDA_BIT | SCL_BIT;  /*pc4=sda,pc5=scl*/

  for( i = 0; i < 100; i++ )
  {
    SCL_IS_LOW;
    wait1u();
    SCL_IS_HIGH;
    wait1u();
  }
  SDA_IS_LOW;

  StopCondition();
  wait5u();
}

/*************************************************************************/
/*  I2C Terminate function                                               */
/*************************************************************************/
static void I2C_Terminate( void )
{
  SCL_OUTPUT;
  SDA_OUTPUT;

  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/

  SDA_IS_HIGH;
}

/*************************************************************************/
/*  start condition                                                      */
/*************************************************************************/
static void StartCondition( void )
{
  I2C_Terminate();
  wait1u();

  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/

  SCL_IS_LOW;
}

/*************************************************************************/
/*  stop condition                                                       */
/*************************************************************************/
static void StopCondition( void )
{
  SCL_OUTPUT;
  SDA_OUTPUT;

  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/

  SDA_IS_HIGH;
}

/*************************************************************************/
/*  ACK confirm function                                                 */
/*************************************************************************/
static int RcvAck( void )
{
  int ret;

  SCL_IS_LOW;  /*about 120ns*/
  SDA_INPUT;
  wait1u();
  SCL_IS_HIGH;
  ret = (PINC & SDA_BIT) ? 1 : 0;
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SDA_OUTPUT;
  SCL_IS_LOW;

  return ret;
}

/*************************************************************************/
/*  ACK responce function                                                */
/*************************************************************************/
static void ResAck( int ack )
{
  SCL_IS_LOW;  /*about 120ns*/
  if(ack) SDA_IS_HIGH;
  else SDA_IS_LOW; 
  wait1u();
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_LOW;
  SDA_IS_LOW;
}

/*************************************************************************/
/*  Bit Write function                                                   */
/*************************************************************************/
static void BitWrite( int data )
{
  SCL_IS_LOW;  /*about 120ns*/
  if(data) SDA_IS_HIGH;
  else SDA_IS_LOW; 
  wait1u();
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_LOW;
  SDA_IS_LOW;
}

/*************************************************************************/
/*  Bit Read function                                                    */
/*************************************************************************/
static int BitRead( void )
{
  int ret;

  SCL_IS_LOW;  /*about 120ns*/
  wait1u();
  SCL_IS_HIGH;
  ret = (PINC & SDA_BIT) ? 1 : 0;
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_LOW;

  return ret;
}

/*************************************************************************/
/*  Byte Write function                                                  */
/*************************************************************************/
static int ByteWrite( int data )
{
  BitWrite( data & 0x80 );
  BitWrite( data & 0x40 );
  BitWrite( data & 0x20 );
  BitWrite( data & 0x10 );
  BitWrite( data & 0x08 );
  BitWrite( data & 0x04 );
  BitWrite( data & 0x02 );
  BitWrite( data & 0x01 );
//  SDA_IS_LOW;

  return ( RcvAck() == 0 ) ? 0 : (-1);
}

/*************************************************************************/
/*  Byte Read function                                                   */
/*************************************************************************/
static int ByteRead( int ack )
{
  int data = 0;

  SDA_INPUT;
  data |= ( BitRead() ) ? 0x80 : 0x00;
  data |= ( BitRead() ) ? 0x40 : 0x00;
  data |= ( BitRead() ) ? 0x20 : 0x00;
  data |= ( BitRead() ) ? 0x10 : 0x00;
  data |= ( BitRead() ) ? 0x08 : 0x00;
  data |= ( BitRead() ) ? 0x04 : 0x00;
  data |= ( BitRead() ) ? 0x02 : 0x00;
  data |= ( BitRead() ) ? 0x01 : 0x00;
  SDA_OUTPUT;
  ResAck( ack );

  return data;
}

/*************************************************************************/
/*  I2C Block Write function                                             */
/*************************************************************************/
int I2C_Block_Write( int addr, const char *data, int size )
{
  StartCondition();

  if( ByteWrite( addr ) == (-1) )
  {
    I2C_Terminate();
    return (-1);
  }

  for( ; size > 0; size-- )
  {
    if( ByteWrite( *data++ ) == (-1) )
    {
      I2C_Terminate();

      return (-1);
    }
  }

  StopCondition();

  return 0;
}

/*************************************************************************/
/*  I2C Block Read function                                              */
/*************************************************************************/
int I2C_Block_Read( int addr, char *data, int size )
{
  StartCondition();
  if( ByteWrite( addr | 0x01 ) == (-1) )
  {
    I2C_Terminate();
    return (-1);
  }

  for( ; size > 0; size-- ) *data++ = ByteRead( (size == 1) ? 1 : 0 );

  StopCondition();

  return 0;
}

/*************************************************************************/
/*  I2C Write function                                                   */
/*************************************************************************/
int I2C_Write( int addr, unsigned char data )
{
#if defined( _SOFT_I2C_ )
  StartCondition();

  if( ByteWrite( addr ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  if( ByteWrite( data ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  StopCondition();

  return 0;

#else  /*_SOFT_I2C_*/
  Wire.beginTransmission( addr );
  Wire.send( data );
  return Wire.endTransmission();
#endif  /*_SOFT_I2C_*/
}

/*************************************************************************/
/*  I2C Read function                                                    */
/*************************************************************************/
int I2C_Read( int addr, unsigned char *data )
{
#if defined( _SOFT_I2C_ )
  StartCondition();

  if( ByteWrite( addr | 0x01 ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  *data = ByteRead( 1 );

  StopCondition();

  return 0;
#else  /*_SOFT_I2C_*/
  Wire.requestFrom( addr, 1 );
  while( Wire.available() == 0 ) ;
  *data = Wire.receive();
  return Wire.endTransmission();
#endif  /*_SOFT_I2C_*/
}

/*************************************************************************/
/* I2CRTC8564_Write                                                      */
/*************************************************************************/
int I2CRTC8564_Write( unsigned char addr, char data )
{
#if defined( _SOFT_I2C_ )
  StartCondition();

  if( ByteWrite( RTC_BASE_ADDR ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  if( ByteWrite( addr ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  if( ByteWrite( data ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  StopCondition();

  return 0;
#else  /*_SOFT_I2C_*/
  Wire.beginTransmission( RTC_BASE_ADDR );
  Wire.send( addr );
  Wire.send( data );
  return Wire.endTransmission();
#endif  /*_SOFT_I2C_*/
}

/*************************************************************************/
/* I2CRTC8564_Read                                                       */
/*************************************************************************/
int I2CRTC8564_Read( unsigned char addr, char *buff )
{
#if defined( _SOFT_I2C_ )
  StartCondition();

  if( ByteWrite( RTC_BASE_ADDR ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  if( ByteWrite( addr ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  SDA_IS_HIGH;
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/

  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/

  if( ByteWrite( RTC_BASE_ADDR | 0x01 ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  *buff = ByteRead( 1 );

  StopCondition();

  return 0;

#else  /*_SOFT_I2C_*/
  Wire.beginTransmission( RTC_BASE_ADDR );
  Wire.send( addr );

  Wire.requestFrom( RTC_BASE_ADDR, 1 );
  while( Wire.available() == 0 ) ;
  *buff = Wire.receive();
  return Wire.endTransmission();
#endif  /*_SOFT_I2C_*/
}

/*************************************************************************/
/* I2CRTC8564_Blk_Read                                                   */
/*************************************************************************/
int I2CRTC8564_Blk_Read( unsigned char addr, char *buff, int size )
{
#if defined( _SOFT_I2C_ )
  char *ptr = buff;
  char *limit = &buff[ size - 1 ];

  StartCondition();

  if( ByteWrite( RTC_BASE_ADDR ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  if( ByteWrite( addr ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  SDA_IS_HIGH;
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/
  SCL_IS_HIGH;  /*about 120ns*/

  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/
  SDA_IS_LOW;  /*about 120ns*/

  if( ByteWrite( RTC_BASE_ADDR | 0x01 ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  while( ptr < limit )
  {
    *ptr++ = ByteRead( 0 );
  }
  *ptr = ByteRead( 1 );

  StopCondition();

  return 0;

#else  /*_SOFT_I2C_*/
  Wire.beginTransmission( RTC_BASE_ADDR );
  Wire.send( addr );

  Wire.requestFrom( RTC_BASE_ADDR, size );
  while( Wire.available() < size ) ;
  for( ; size > 0; size-- )
  {
    *buff++ = Wire.receive();
  }
  return Wire.endTransmission();
#endif  /*_SOFT_I2C_*/
}

/*************************************************************************/
/* I2CRTC8564_Blk_Write                                                  */
/*************************************************************************/
int I2CRTC8564_Blk_Write( unsigned char addr, const char *data, int size )
{
#if defined( _SOFT_I2C_ )
  const char *ptr = data;
  const char *limit = &data[ size ];

  StartCondition();

  if( ByteWrite( RTC_BASE_ADDR ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  if( ByteWrite( addr ) == (-1) )
  {
    I2C_Terminate();
    clk100();
    return (-1);
  }

  while( ptr < limit )
  {
    if( ByteWrite( *ptr++ ) == (-1) )
    {
      I2C_Terminate();
      clk100();
      return (-1);
    }
  }

  StopCondition();
  return 0;

#endif  /*_SOFT_I2C_*/
  return 0;
}

/*************************************************************************/
/* RTC-8564 initialize                                                   */
/*************************************************************************/
int InitRTC8564( int force )
{
  int i,ret;
  char temp,date_time[ 7 ],work[ 8 ];
  unsigned char rtc_adr;
  static const unsigned char RTC8564_Init_Code[] =
    {0x20, 0x11, 0x00,0x10,0x18,0x07,0x04,0x05, 0x10,0x80, 0x80,  0x80, 0x80,  0x00,0x81,63  };
   /*ctrl1,ctrl2,sec, min, hour,day, week,month,year,min_a,hour_a,day_a,week_a,freq,cont,timer*/

  /*RTC8564 confirmed VLbit*/
  if( I2CRTC8564_Read( RTC8564_SEC, &date_time[ SECONDS ] ) != 0 ) return (-1);

  if( date_time[ SECONDS ] & 0x80 || force )  /*VLbit was 1 then detected low voltage*/
  {
    for( rtc_adr = 0; rtc_adr <= sizeof( RTC8564_Init_Code ); rtc_adr++ )
    {
      if( I2CRTC8564_Write( rtc_adr, RTC8564_Init_Code[ rtc_adr ] ) != 0 ) return (-1);
    }
    if( I2CRTC8564_Write( RTC8564_CTRL1, 0x00 ) != 0 ) return (-1);  /*timer start*/

    for( i = 0; i < 100; i++ )
    {
      if( I2CRTC8564_Read( RTC8564_YEAR, &date_time[ YEARS ] ) != 0 ) return (-1);  /*RTC is not there.*/

      if( date_time[ YEARS ] == RTC8564_Init_Code[ RTC8564_YEAR ] )  /**/
      {
        break;
      }
      else
      {
        for( rtc_adr = 0; rtc_adr <= sizeof( RTC8564_Init_Code ); rtc_adr++ )
        {
          if( I2CRTC8564_Write( rtc_adr, RTC8564_Init_Code[ rtc_adr ] ) != 0 ) return (-1);
        }
        if( I2CRTC8564_Write( RTC8564_CTRL1, 0x00 ) != 0 ) return (-1);
      }
    }
    if( i != 100 ) ret = 1;  /**/
    else ret = (-2);  /*initialize error*/
  }
  else ret = 0;

  if( ret > (-1) )
  {
    if( I2CRTC8564_Blk_Read( RTC8564_SEC, work, 7 ) != 0 ) return (-1);
    RTC8564Str2DateStr( date, (const unsigned char *)work );  /**/
  }

  return ret;
}

/*************************************************************************/
/*   0123456789012345678                                                 */
/*   2007/11/21 15:12:00                                                 */
/* DateStr2RTC8564Str( (unsigned char *)work, "2007/12/31 23:59:00" );   */
/* I2CRTC8564_Blk_Write( RTC8564_SEC, (const char *)work, 7 );           */
/*************************************************************************/
unsigned char *DateStr2RTC8564Str( unsigned char *dest, const char *source )
{
  dest[ 0 ] = ((source[ 17 ] & 0x07) << 4) | (source[ 18 ] & 0x0f);  /*second*/
  dest[ 1 ] = ((source[ 14 ] & 0x07) << 4) | (source[ 15 ] & 0x0f);  /*minute*/
  dest[ 2 ] = ((source[ 11 ] & 0x03) << 4) | (source[ 12 ] & 0x0f);  /*hour*/
  dest[ 3 ] = ((source[ 8 ] & 0x03) << 4) | (source[ 9 ] & 0x0f);  /*day*/
  dest[ 4 ] = 0;  /*week*/
  dest[ 5 ] = ((source[ 5 ] & 0x01) << 4) | (source[ 6 ] & 0x0f);  /*month*/
  dest[ 6 ] = ((source[ 2 ] & 0x0f) << 4) | (source[ 3 ] & 0x0f);  /*year*/

  return dest;
}

/*************************************************************************/
/*   0123456789012345678                                                 */
/*   2007/11/21 15:12:00                                                 */
/*************************************************************************/
char *RTC8564Str2DateStr( char *dest, const unsigned char source[] )
{
  dest[ 0 ] = '2';
  dest[ 1 ] = '0';
  dest[ 2 ] = (source[YEARS] >> 4) + '0';
  dest[ 3 ] = (source[YEARS] & 0x0f) + '0';
  dest[ 4 ] = '/';
  dest[ 5 ] = ((source[MONTHS] >> 4) & 0x01) + '0';
  dest[ 6 ] = (source[MONTHS] & 0x0f) + '0';
  dest[ 7 ] = '/';
  dest[ 8 ] = ((source[DAYS] >> 4) & 0x03) + '0';
  dest[ 9 ] = (source[DAYS] & 0x0f) + '0';
  dest[ 10 ] = ' ';
  dest[ 11 ] = ((source[HOURS] >> 4) & 0x03) + '0';
  dest[ 12 ] = (source[HOURS] & 0x0f) + '0';
  dest[ 13 ] = ':';
  dest[ 14 ] = ((source[MINUTES] >> 4) & 0x07) + '0';
  dest[ 15 ] = (source[MINUTES] & 0x0f) + '0';
  dest[ 16 ] = ':';
  dest[ 17 ] = ((source[SECONDS] >> 4) & 0x07) + '0';
  dest[ 18 ] = (source[SECONDS] & 0x0f) + '0';
  dest[ 19 ] = '\0';

  return dest;
}

/*************************************************************************/
/* RTC-8564 Calender Set                                                 */
/*************************************************************************/
int RTC8564_CalenderSet( const char *date_time )
{
  int i;
  unsigned char rtc_adr,work[ 8 ];

  DateStr2RTC8564Str( work, date_time );

  /*timer stop*/
  if( I2CRTC8564_Write( RTC8564_CTRL1, 0x20 ) != 0 ) return (-1);

  /*date and time write*/
  for( rtc_adr = RTC8564_SEC, i = 0; rtc_adr <= RTC8564_YEAR; rtc_adr++ )
  {
    if( I2CRTC8564_Write( rtc_adr, work[ i++ ] ) != 0 ) return (-1);
  }

  /*timer start*/
  if( I2CRTC8564_Write( RTC8564_CTRL1, 0x00 ) != 0 ) return (-1);

  return 0;
}

/***********************************************************************/
/*                                               designed by hamayan   */
/*                                               Copyright(C) hamayan  */
/***********************************************************************/


Arduinoをはじめよう

Arduinoをはじめよう

  • 作者: Massimo Banzi
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2009/03/27
  • メディア: 単行本(ソフトカバー)



ITRONプログラミング入門―H8マイコンとHOSで始める組み込み開発

ITRONプログラミング入門―H8マイコンとHOSで始める組み込み開発

  • 作者: 濱原 和明
  • 出版社/メーカー: オーム社
  • 発売日: 2005/04/25
  • メディア: 単行本



nice!(0)  コメント(0)  トラックバック(0) 

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。