SSブログ

Maruduinoで時計を作る。Wireライブラリ対応版 [アプリケーション]

このボードはハムフェア(http://bit.ly/14qQxv)のマルツさんのブースで展示予定です。触ってネー。

Img_2082.jpgもっとも自分でなんとかした訳ではなく、某所から、ロジアナまで持ち出しての動作解析をしてもらった結果です。
ある意味Wireライブラリの使い方の見本としてもどうぞ。
※Wireライブラリの中で割込みを使っている関係上、別の割り込みハンドラの中から呼んだり、割り込み禁止にしている状態では、Wireライブラリを使う事ができない様です。お気を付け。


/***********************************************************************/
/* LCD clock                                                           */
/* I2C bus control RTC()RTC8564 use                                    */
/*                                               designed by hamayan   */
/*                                               Copyright(C) hamayan  */
/***********************************************************************/
#include <string.h>
#include <LiquidCrystal.h>
#include <Wire.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  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

#define  RTC_BASE_ADDR      (0xa2 >> 1)

/*************************************************************************/
/*  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 date_print( const char *src, int x, int y );
static void time_print( const char *src, int x, int y );
static void ConvertFromRTC2DateTime( void );

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 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++;
}

/*************************************************************************/
/*  time display update                                                  */
/*************************************************************************/
static void time_disp_update( void )
{
  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." );

  Wire.begin();  /*set i2c master device*/
  TWSR &= 0xfc;  /*baud rate control. prescaler=x1*/
  TWBR = 72;     /*baud rate control. 100khz*/

  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;
    time_disp_update();  /*clock display update*/

    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;
  }
}

/*************************************************************************/
/*  I2C Write function                                                   */
/*************************************************************************/
int I2C_Write( int addr, unsigned char data )
{
  Wire.beginTransmission( addr );
  Wire.send( data );
  return Wire.endTransmission();
}

/*************************************************************************/
/*  I2C Read function                                                    */
/*************************************************************************/
int I2C_Read( int addr, unsigned char *data )
{
  Wire.requestFrom( addr, 1 );
  while( Wire.available() == 0 ) ;
  *data = Wire.receive();
  return 0;
}

/*************************************************************************/
/* I2CRTC8564_Write                                                      */
/*************************************************************************/
int I2CRTC8564_Write( unsigned char addr, char data )
{
  Wire.beginTransmission( RTC_BASE_ADDR );
  Wire.send( addr );
  Wire.send( data );
  return Wire.endTransmission();
}

/*************************************************************************/
/* I2CRTC8564_Read                                                       */
/*************************************************************************/
int I2CRTC8564_Read( unsigned char addr, char *buff )
{
  Wire.beginTransmission( RTC_BASE_ADDR );
  Wire.send( addr );
  Wire.endTransmission();

  Wire.requestFrom( RTC_BASE_ADDR, 1 );
  while( Wire.available() == 0 ) ;
  *buff = Wire.receive();
  return 0;
}

/*************************************************************************/
/* I2CRTC8564_Blk_Read                                                   */
/*************************************************************************/
int I2CRTC8564_Blk_Read( unsigned char addr, char *buff, int size )
{
  Wire.beginTransmission( RTC_BASE_ADDR );
  Wire.send( addr );
  Wire.endTransmission();

  Wire.requestFrom( RTC_BASE_ADDR, size );
  while( Wire.available() < size ) ;
  for( ; size > 0; size-- )
  {
    *buff++ = Wire.receive();
  }
  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  */
/***********************************************************************/


Prototyping Lab ―「作りながら考える」ためのArduino実践レシピ

Prototyping Lab ―「作りながら考える」ためのArduino実践レシピ

  • 作者: 小林 茂
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2010/05/27
  • メディア: 大型本



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

nice! 0

コメント 0

コメントを書く

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

※ブログオーナーが承認したコメントのみ表示されます。

トラックバック 0

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