Maruduinoで時計を作る。Wireライブラリ対応版 [アプリケーション]
このボードはハムフェア(http://bit.ly/14qQxv)のマルツさんのブースで展示予定です。触ってネー。
もっとも自分でなんとかした訳ではなく、某所から、ロジアナまで持ち出しての動作解析をしてもらった結果です。
ある意味Wireライブラリの使い方の見本としてもどうぞ。
※Wireライブラリの中で割込みを使っている関係上、別の割り込みハンドラの中から呼んだり、割り込み禁止にしている状態では、Wireライブラリを使う事ができない様です。お気を付け。
もっとも自分でなんとかした訳ではなく、某所から、ロジアナまで持ち出しての動作解析をしてもらった結果です。
ある意味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実践レシピ
- 作者: 小林 茂
- 出版社/メーカー: オライリージャパン
- 発売日: 2010/05/27
- メディア: 大型本
2010-08-16 21:43
nice!(0)
コメント(0)
トラックバック(0)
コメント 0