はじめに
当サイトでは、がた老さんが作られたI2Cを持たないATtiny用のUSIを利用したI2Cライブラリィを改良(改悪)して公開している。
木村さんからTinyI2CMasterの使い方の問い合わせのメールをいただいた。
使い方がわかりにくいとのこと、確かに公開しているライブラリィはI2Cデバイスをドライバを作るためのソフトウェアであって、使用例としてパッケージに一部ドライバを同封しているがこれはおまけである。
TinyI2CMasterとは
さて肝心のTinyI2CMasterだが、改めて書くが、これはハードウェアの抽象化・I2Cプロトコルの抽象化を実現したソフトウエアです。
構成は以下の通り
+----------------+ | 各ドライバ | ==> 各人が用意 +----------------+ ↓↑ +----------------+ | 中層レイア | +----------------+ ==> ここがTinyI2CMasterライブラリィ | 下層レイア | +----------------+
下層レイア部分のソフトウェアは、USIのハードウェアやポートを直接弄る関数群です。これはがた老さんが書かれました。
I2Cのプロトコルは複雑で下層レイア部分のソフトウェアを組み合わせて実現します。
これが中層レイアのソフト群です。中層レイア部分に当たるソフトウェアは、デットロックしないよう考慮したI2Cデバイスの読み出し・書き込み関数と、レジスタ経由でデータの送受信を行うI2Cデバイス専用の関数で構成されてます。
これはばんとが書きました。
TinyI2CMasterライブラリィ関数説明
■void TinyI2C_Master_init( void )
機能: USIインタフェースの初期化(対応ポートも初期化)
引数: なし
戻値: なし
【補足説明】
プロジェクトで適切なMPU(ATtiny2313等)が選択されていれば、適切なポートが選択される。
対応MPUや対応ポートなどはヘッダファイルを参照するのこと。
ポートなどハードウェアを初期化する。詳細はソースを参照すること。
【分類】
下層レイアに含まれる関数
■uint8_t TinyI2C_start( void )
機能: スタートコンディション送信
引数: なし
戻値: 0=正常終了 それ以外I2C通信エラー
【補足説明】
I2Cバスにスタートコンディションを発行する。
詳細はソースを参照すること。
【分類】
下層レイアに含まれる関数
■uint8_t TinyI2C_stop( void )
機能: ストップコンディションの送信
引数: なし
戻値: 0=正常終了 それ以外I2C通信エラー
【補足説明】
I2Cバスにストップコンディションを発行する。
詳細はソースを参照すること。
【分類】
下層レイアに含まれる関数
■uint8_t TinyI2C_read( uint8_t more )
機能: I2Cのパスからの1バイト読み込み
引数: uint8_t more: more が MORE_READのときACK送信、それ以外はNACK送信
戻値: 読み込まれた1バイトのデータ
【補足説明】
I2Cのパスからの1バイト読み込みをする。更にデータを読み込むときにはACKを送信する。
詳細はソースを参照すること。
【分類】
下層レイアに含まれる関数
■uint8_t TinyI2C_write( uint8_t data )
機能: I2Cバスへの1バイト書き込み
引数: uint8_t data 書き込むデータ
戻値: 0=正常終了 それ以外I2C通信エラー
【補足説明】
詳細はソースを参照すること。
【分類】
下層レイアに含まれる関数
■uint8_t TinyI2C_Transfer( uint8_t data )
機能: USIインタフェースによるデータ送受信 8ビットも1ビットも同じ
引数: uint8_t data: 送受信データ
戻値: 0=正常終了 それ以外I2C通信エラー
【補足説明】
詳細はソースを参照すること。
【分類】
下層レイアに含まれる関数
■uint8_t TinyI2C_read_data(uint8_t slave_7bit_addr, void* data, int size, uint8_t send_stop )
機能: データ連続読み込み
引数: uint8_t slave_7bit_addr : ターゲットの7ビットアドレス
void* data : 読み込むデータ
int size : 読み込むデータサイズ
uint8_t send_stop : 非0なら読込後にSTOPコンディション送信する
戻値: 0=正常終了 それ以外I2C通信エラー
【補足説明】
I2Cプロトコルに従ってターゲットデバイスからデータを受信する。
リトライ3回(デフォルト)でデットロックを回避している。
詳細はソースを参照すること。
【分類】
中間レイアに含まれる関数
■uint8_t TinyI2C_write_data(uint8_t slave_7bit_addr, void* data, int size, uint8_t send_stop)
機能: データ連続書き込み
引数: uint8_t slave_7bit_addr : ターゲットの7ビットアドレス
void* data : 書き込むデータ
int size : 書き込むデータサイズ
uint8_t send_stop : 非0なら読込後にSTOPコンディション送信する
戻値: 0=正常終了 それ以外I2C通信エラー
【補足説明】
I2Cプロトコルに従ってターゲットデバイスにデータを送信する。
リトライ3回(デフォルト)でデットロックを回避している。
詳細はソースを参照すること。
【分類】
中間レイアに含まれる関数
■uint8_t TinyI2C_readReg( uint8_t slave_7bit_addr, uint8_t mem_addr, uint8_t *data )
機能: I2Cデバイスのレジスタ読み込み
引数: uint8_t slave_7bit_addr : ターゲットの7ビットアドレス
uint8_t mem_addr : レジスタのメモリアドレス
uint8_t* data : 読み込むデータ
戻値: 0=正常終了 それ以外I2C通信エラー
【補足説明】
レジスタアドレス送信すればレジスタデータが戻ってくるI2Cデバイス専用である。
詳細はソースを参照すること。
【分類】
中間レイアに含まれる関数
■uint8_t TinyI2C_masksetRegBit( uint8_t slave_7bit_addr, uint8_t mem_addr, uint8_t mask, uint8_t set_bit )
機能: レジスタマスク書き込み
引数: uint8_t slave_7bit_addr : ターゲットの7ビットアドレス
uint8_t mem_addr : レジスタのメモリアドレス
uint8_t mask : 設定するビットのマスクデータ
uint8_t set_bit : 設定データ
戻値: 0=正常終了 それ以外I2C通信エラー
【補足説明】
レジスタアドレス送信すればレジスタデータが戻ってくるI2Cデバイス専用である。
レジスタのマスクされた特定ビットのみを書き換えることができる。
詳細はソースを参照すること。
【分類】
中間レイアに含まれる関数
■uint8_t TinyI2C_setRegBit( uint8_t slave_7bit_addr, uint8_t mem_addr, uint8_t set_bit, uint8_t set_clear )
機能: 特定ビット設定
引数: uint8_t slave_7bit_addr : ターゲットの7ビットアドレス
uint8_t mem_addr : レジスタのメモリアドレス
uint8_t set_bit : 設定するビットの位置
uint8_t set_clear : 0ならビットクリア 非0ならビットセット
戻値: 0=正常終了 それ以外I2C通信エラー
【補足説明】
レジスタ経由でデータの送受信を行うI2Cデバイス専用の関数である。
レジスタアドレス送信すればレジスタデータが戻ってくるI2Cデバイス専用である。
レジスタの特定の1ビットのみを書き換えることができる。
詳細はソースを参照すること。
【分類】
中間レイアに含まれる関数
ドライバは各自が用意
I2Cプロトコルの規定はあるがI2Cデバイスの使い方には規定はない。
ハードウェアメーカが独自に実装しているので、各自がTinyI2CMasterの関数を用いてデバイスドライバを書く必要がある。
例題1 RTC8564ドライバ
リアルタイムクロックRTC8564は、レジスタを介して設定・時刻データの取得をする典型的なデバイスである。RTC8564は日本メーカー製なので、日本語のデータシート・アプリケーションノートが存在するので、全機能が使えるドライバを書いた。
データシート
http://www.epsondevice.com/docs/qd/ja/DownloadServlet?id=ID000711
アプリケーションノート
http://www.epsondevice.com/docs/qd/ja/DownloadServlet?id=ID000514
詳細はソースを見ていただきたい。
例題2 ST7032iドライバ
ST7032iはRTC8564のようなレジスタというものはない。ST7032iで表示させるにはHD44780と同じ制御コードで表示を行えるが、データモード・コマンドモードの信号をI2Cバス上に送ることにより表示する。
ST7032iドライバのソースは、壊れたXP環境からサルベージしたものである。
もしかしたら間違えがあるかもしれないのだが公開する。
まずはヘッダファイル(ST7032i.h)
#ifndef __ST7032I__H__ #define __ST7032I__H__ #include <stdbool.h> #define ST7032I_ADDR 0x3E //#define STRAWBERRY_LINUX_16x2_LCD #undef STRAWBERRY_LINUX_16x2_LCD #undef USE_ST7032I_INIT_PORT #undef USE_ST7032I_WAKEUP #ifdef USE_ST7032I_INIT_PORT #define ST7032i_WAKE_UP_DDR DDRB #define ST7032i_WAKE_UP_DDR_NO DDB0 #define ST7032i_WAKE_UP_PORT PORTB #define ST7032i_WAKE_UP_PORT_NO PORTB1 #endif //======= Command/flag defenitions ======= #define LCD_CLEARDISPLAY 0x01 // Command (HD44780) Page 21 #define LCD_RETURNHOME 0x02 // Command (HD44780) // flags for display entry mode #define LCD_ENTRYMODESET 0x04 // Command (HD44780) #define LCD_ENTRYSHIFTINCREMENT 0x01 // Setting (HD44780)* #define LCD_ENTRYSHIFTDECREMENT 0x00 // Setting (HD44780) #define LCD_ENTRYLEFT 0x02 // Setting (HD44780)* #define LCD_ENTRYRIGHT 0x00 // Setting (HD44780) // flags for display on/off control #define LCD_DISPLAYCONTROL 0x08 // Command (HD44780) Page 22 #define LCD_DISPLAYON 0x04 // Setting (HD44780)* #define LCD_DISPLAYOFF 0x00 // Setting (HD44780) #define LCD_CURSORON 0x02 // Setting (HD44780) #define LCD_CURSOROFF 0x00 // Setting (HD44780)* #define LCD_BLINKON 0x01 // Setting (HD44780) #define LCD_BLINKOFF 0x00 // Setting (HD44780)* // flags for display/cursor shift #define LCD_CURSORSHIFT 0x10 // Command (HD44780) #define LCD_DISPLAYMOVE 0x08 // Setting (HD44780) #define LCD_CURSORMOVE 0x00 // Setting (HD44780) #define LCD_MOVERIGHT 0x04 // Setting (HD44780) #define LCD_MOVELEFT 0x00 // Setting (HD44780) #define LCD_FUNCTIONSET 0x20 // Command (HD44780) Page 23 #define LCD_INSTRUCTION_SET_BASIC 0x00 // Setting (ST7032) #define LCD_INSTRUCTION_SET_EXTENDED 0x01 // Setting (ST7032) #define LCD_2LINE 0x08 // Setting (HD44780)* #define LCD_1LINE 0x00 // Setting (HD44780) #define LCD_8BITMODE 0x10 // Setting (HD44780)* //#define LCD_4BITMODE 0x00 // Setting (HD44780) Not used in I2C mode //#define LCD_5x10DOTS 0x04 // Setting (HD44780) Not supported by ST7032 #define LCD_5x8DOTS 0x00 // Setting (HD44780)* #define LCD_SETCGRAMADDR 0x40 // Command (HD44780) Page 24 #define LCD_SETDDRAMADDR 0x80 // Command (HD44780) #define LCD_BIAS_OSC_CONTROL 0x10 // Command (ST7032) Page 26 #define LCD_BIAS1_4 0x08 // Setting (ST7032) #define LCD_BIAS1_5 0x00 // Setting (ST7032)* // Internal frequency adjust for VDD = 3.0 V #define LCD_OSC_122 0x00 // Setting (ST7032) #define LCD_OSC_131 0x01 // Setting (ST7032) #define LCD_OSC_144 0x02 // Setting (ST7032) #define LCD_OSC_161 0x03 // Setting (ST7032) #define LCD_OSC_183 0x04 // Setting (ST7032) #define LCD_OSC_221 0x05 // Setting (ST7032) #define LCD_OSC_274 0x06 // Setting (ST7032) #define LCD_OSC_347 0x07 // Setting (ST7032) // Internal frequency adjust for VDD = 5.0 V #define LCD_OSC_120 0x00 // Setting (ST7032) #define LCD_OSC_133 0x01 // Setting (ST7032) #define LCD_OSC_149 0x02 // Setting (ST7032) #define LCD_OSC_167 0x03 // Setting (ST7032) #define LCD_OSC_192 0x04 // Setting (ST7032)* #define LCD_OSC_227 0x05 // Setting (ST7032) #define LCD_OSC_277 0x06 // Setting (ST7032) #define LCD_OSC_347 0x07 // Setting (ST7032) #define ICON_RAMADDRESSSET 0x40 // Command (ST7032) #define LCD_ICON_CONTRAST_HIGH_BYTE 0x50 // Command (ST7032) #define LCD_ICON_ON 0x08 // Setting (ST7032) #define LCD_ICON_OFF 0x00 // Setting (ST7032) #define LCD_BOOSTER_ON 0x04 // Setting (ST7032)* #define LCD_BOOSTER_OFF 0x00 // Setting (ST7032) #define LCD_CONTRAST_HIGH_BYTE_MASK 0x03 // Only used for bit masking (ST7032) #define LCD_FOLLOWER_CONTROL 0x60 // Command (ST7032) Page 27 #define LCD_FOLLOWER_ON 0x08 // Setting (ST7032)* #define LCD_FOLLOWER_OFF 0x00 // Setting (ST7032) #define LCD_Rab_1_00 0x00 // Setting (ST7032) #define LCD_Rab_1_25 0x01 // Setting (ST7032) #define LCD_Rab_1_50 0x02 // Setting (ST7032) #define LCD_Rab_1_80 0x03 // Setting (ST7032) #define LCD_Rab_2_00 0x04 // Setting (ST7032)* #define LCD_Rab_2_50 0x05 // Setting (ST7032) #define LCD_Rab_3_00 0x06 // Setting (ST7032) #define LCD_Rab_3_75 0x07 // Setting (ST7032) #define LCD_CONTRAST_LOW_BYTE 0x70 // Command (ST7032) #define LCD_CONTRAST_LOW_BYTE_MASK 0x0F // Only used for bit masking (ST7032) #define ST7032_NUM_LINES 2 //======= End of command/flag defenitions ======= /*======================================*/ /* 関数定義 */ /*======================================*/ extern uint8_t ST7032i_Write( uint8_t data, uint8_t mode ); extern void ST7032i_Init( void ); extern void ST7032i_Clear( void ); extern void ST7032i_Home( void ); extern void ST7032i_setCursor(uint8_t col, uint8_t row); extern void ST7032i_onDisplay( void ); extern void ST7032i_offDisplay( void ); extern void ST7032i_onCursor( void ); extern void ST7032i_offCursor( void ); extern void ST7032i_onBlink( void ); extern void ST7032i_offBlink( void ); extern void ST7032i_scrollDisplayLeft( void ); extern void ST7032i_scrollDisplayRight( void ); extern void ST7032i_rightToLeft( void ); extern void ST7032i_onAutoscroll( void ); extern void ST7032i_offAutoscroll( void ); extern void ST7032i_createChar(uint8_t location, uint8_t charmap[]); extern void ST7032i_setContrast(uint8_t new_val); extern void ST7032i_puts(const char *s); extern void ST7032i_puts_p(const char *progmem_s); #define ST7032i_WriteCmd(data) ST7032i_Write(data,0x00) #define ST7032i_WriteData(data) ST7032i_Write(data,0x40) #define ST7032i_putc(data) ST7032i_Write(data,0x40) #ifdef STRAWBERRY_LINUX_16x2_LCD extern void ST7032i_Icon( uint8_t icon, bool flag ); extern void ST7032i_Power_Icon(uint8_t power, bool flag); #define ST7032i_ANTENA_Icon(flag) ST7032i_Icon(0, flag) #define ST7032i_Tel_Icon(flag) ST7032i_Icon(1, flag) #define ST7032i_Denpa_Icon(flag) ST7032i_Icon(2, flag) #define ST7032i_ExitPower_Icon(flag) ST7032i_Icon(3, flag) #define ST7032i_Up_Icon(flag) ST7032i_Icon(4, flag) #define ST7032i_Down_Icon(flag) ST7032i_Icon(5, flag) #define ST7032i_KeyLock_Icon(flag) ST7032i_Icon(6, flag) #define ST7032i_Mute_Icon(flag) ST7032i_Icon(7, flag) #define ST7032i_Coin_Icon(flag) ST7032i_Icon(8, flag) #endif #endif
そしてソースファイル(ST7032i.c)
//============================================================================= // File Name : ST7032i.c // // Title : ST7032i I2C LCD ドライバ // Revision : 0.1 // Notes : // Target MCU : AVR ATtiny // Tool Chain : // // Revision History: // When Who Description of change // ----------- ----------- ----------------------- // 2013/02/06 ばんと 修正完了 //============================================================================= /* Includes ------------------------------------------------------------------*/ #include <stdbool.h> #include <avr/io.h> #include <avr/pgmspace.h> #include "delay.h" #include "ST7032i.h" #include "TinyI2CMaster.h" /* local typedef -------------------------------------------------------------*/ //アイコンのアドレスとビットの関係 #ifdef STRAWBERRY_LINUX_16x2_LCD typedef struct { uint8_t adr; uint8_t data; } T_ICON; #endif /* local define --------------------------------------------------------------*/ /* local macro ---------------------------------------------------------------*/ /* local variables -----------------------------------------------------------*/ uint8_t _display_basic; uint8_t _display_extended; uint8_t _displaymode; uint8_t _displaycontrol; uint8_t _rab; #ifdef STRAWBERRY_LINUX_16x2_LCD const uint8_t Icon_Table[9][2] = { {0x00, 0b10000}, {0x02, 0b10000}, {0x04, 0b10000}, {0x06, 0b10000}, {0x07, 0b10000}, {0x07, 0b01000}, {0x09, 0b10000}, {0x0B, 0b10000}, {0x0F, 0b10000} }; #endif /* local function prototypes -------------------------------------------------*/ /*======================================*/ /* ST7032i 書き込み関数 */ /*======================================*/ uint8_t ST7032i_Write( uint8_t data, uint8_t mode ) { uint8_t buf[2]; buf[0] = mode; // モード buf[1] = data; // データ return TinyI2C_write_data(ST7032I_ADDR, buf, sizeof(buf), SEND_STOP)); } /*======================================*/ /* ST7032i ポート初期化関数 */ /*======================================*/ #ifdef USE_ST7032I_INIT_PORT void ST7032i_InitPort( void ) { ST7032i_WAKE_UP_DDR = _BV(ST7032i_WAKE_UP_DDR_NO); // ST7032i_WAKE_UP_PORT &= ~_BV(ST7032i_WAKE_UP_PORT_NO); // wait_ms(1); } #endif /*======================================*/ /* ST7032i ウェイクアップ関数 */ /*======================================*/ #ifdef USE_ST7032I_WAKEUP void ST7032i_WakeUp( void ) { ST7032i_WAKE_UP_PORT &= ~_BV(ST7032i_WAKE_UP_PORT_NO); wait_ms(1); ST7032i_WAKE_UP_PORT |= _BV(ST7032i_WAKE_UP_PORT_NO); wait_ms(10); } #endif /*======================================*/ /* ST7032i 初期化関数 */ /*======================================*/ void ST7032i_Init( void ) { uint8_t contrast = 45; _display_basic = LCD_INSTRUCTION_SET_BASIC | LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS; _display_extended = LCD_INSTRUCTION_SET_EXTENDED | LCD_8BITMODE | LCD_1LINE | LCD_5x8DOTS; _displaycontrol = LCD_DISPLAYON; _display_basic |= LCD_2LINE; _display_extended |= LCD_2LINE; #ifdef USE_ST7032I_INIT_PORT ST7032i_InitPort( ); #endif #ifdef USE_ST7032I_WAKEUP ST7032i_WakeUp( ); #endif wait_ms(40); // function set basic ST7032i_WriteCmd(LCD_FUNCTIONSET | _display_basic ); wait_ms(30); // function set extended ST7032i_WriteCmd(LCD_FUNCTIONSET | _display_extended); wait_ms(30); // interval osc ST7032i_WriteCmd(LCD_BIAS_OSC_CONTROL | LCD_BIAS1_5 | LCD_OSC_192); wait_ms(30); // contrast low nible ST7032i_WriteCmd(LCD_CONTRAST_LOW_BYTE | (contrast & LCD_CONTRAST_LOW_BYTE_MASK)); wait_ms(30); // contrast high nible / icon / power ST7032i_WriteCmd(LCD_ICON_CONTRAST_HIGH_BYTE | LCD_ICON_ON | LCD_BOOSTER_ON | (contrast >> 4 & LCD_CONTRAST_HIGH_BYTE_MASK)); wait_ms(30); // follower control _rab = LCD_Rab_2_00; ST7032i_WriteCmd(LCD_FOLLOWER_CONTROL | LCD_FOLLOWER_ON | _rab); wait_ms(200); // function set basic ST7032i_WriteCmd(LCD_FUNCTIONSET | _display_basic); wait_ms(30); // display on ST7032i_WriteCmd(LCD_DISPLAYCONTROL | LCD_DISPLAYON | LCD_CURSOROFF | LCD_BLINKOFF ); wait_ms(30); // entry mode set _displaymode=LCD_ENTRYLEFT | LCD_ENTRYSHIFTDECREMENT; ST7032i_WriteCmd(LCD_ENTRYMODESET | _displaymode); wait_ms(30); } /*======================================*/ /* ST7032i 画面消去関数 */ /*======================================*/ void ST7032i_Clear( void ) { ST7032i_WriteCmd(LCD_CLEARDISPLAY); wait_ms(2); } /*======================================*/ /* ST7032i ホームポジション関数 */ /*======================================*/ void ST7032i_Home( void ) { ST7032i_WriteCmd(LCD_RETURNHOME); // set cursor position to zero wait_ms(2); // this command takes a long time! } /*======================================*/ /* ST7032i カーソル表示関数 */ /*======================================*/ void ST7032i_setCursor(uint8_t col, uint8_t row) { int row_offsets[] = { 0x00, 0x40, 0x14, 0x54 }; if ( row > ST7032_NUM_LINES ) { row = ST7032_NUM_LINES - 1; // we count rows starting w/0 } ST7032i_WriteCmd(LCD_SETDDRAMADDR | (col + row_offsets[row])); wait_ms(30); } /*======================================*/ /* ST7032i 表示オン関数 */ /*======================================*/ void ST7032i_onDisplay( void ) { _displaycontrol |= LCD_DISPLAYON; ST7032i_WriteCmd(LCD_DISPLAYCONTROL | _displaycontrol); wait_ms(30); } /*======================================*/ /* ST7032i 表示オフ関数 */ /*======================================*/ void ST7032i_offDisplay( void ) { _displaycontrol &= ~LCD_DISPLAYON; ST7032i_WriteCmd(LCD_DISPLAYCONTROL | _displaycontrol); wait_ms(30); } /*======================================*/ /* ST7032i カーソルオン関数 */ /*======================================*/ void ST7032i_onCursor( void ) { _displaycontrol |= LCD_CURSORON; ST7032i_WriteCmd(LCD_DISPLAYCONTROL | _displaycontrol); wait_ms(30); } /*======================================*/ /* ST7032i カーソルオフ関数 */ /*======================================*/ void ST7032i_offCursor( void ) { _displaycontrol &= ~LCD_CURSORON; ST7032i_WriteCmd(LCD_DISPLAYCONTROL | _displaycontrol); wait_ms(30); } /*======================================*/ /* ST7032i ブリンクオン関数 */ /*======================================*/ void ST7032i_onBlink( void ) { _displaycontrol |= LCD_BLINKON; ST7032i_WriteCmd(LCD_DISPLAYCONTROL | _displaycontrol); wait_ms(30); } /*======================================*/ /* ST7032i ブリンクオフ関数 */ /*======================================*/ void ST7032i_offBlink( void ) { _displaycontrol &= ~LCD_BLINKON; ST7032i_WriteCmd(LCD_DISPLAYCONTROL | _displaycontrol); wait_ms(30); } /*======================================*/ /* ST7032i 左スクロール関数 */ /*======================================*/ // These commands scroll the display without changing the RAM void ST7032i_scrollDisplayLeft( void ) { ST7032i_WriteCmd(LCD_FUNCTIONSET | _display_basic); wait_ms(30); ST7032i_WriteCmd(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVELEFT); wait_ms(30); } /*======================================*/ /* ST7032i 右スクロール関数 */ /*======================================*/ void ST7032i_scrollDisplayRight( void ) { ST7032i_WriteCmd(LCD_FUNCTIONSET | _display_basic); wait_ms(30); ST7032i_WriteCmd(LCD_CURSORSHIFT | LCD_DISPLAYMOVE | LCD_MOVERIGHT); wait_ms(30); } /*======================================*/ /* ST7032i 左→右・文字あふれ関数 */ /*======================================*/ // This is for text that flows Left to Right void ST7032i_leftToRight( void ) { _displaymode |= LCD_ENTRYLEFT; ST7032i_WriteCmd(LCD_ENTRYMODESET | _displaymode); wait_ms(30); } /*======================================*/ /* ST7032i 右→左・文字あふれ関数 */ /*======================================*/ // This is for text that flows Right to Left void ST7032i_rightToLeft( void ) { _displaymode &= ~LCD_ENTRYLEFT; ST7032i_WriteCmd(LCD_ENTRYMODESET | _displaymode); wait_ms(30); } /*======================================*/ /* ST7032i オートスクロール・オン関数 */ /*======================================*/ // This will 'right justify' text from the cursor void ST7032i_onAutoscroll( void ) { _displaymode |= LCD_ENTRYSHIFTINCREMENT; ST7032i_WriteCmd(LCD_ENTRYMODESET | _displaymode); wait_ms(30); } /*======================================*/ /* ST7032i オートスクロール・オフ関数 */ /*======================================*/ // This will 'left justify' text from the cursor void ST7032i_offAutoscroll( void ) { _displaymode &= ~LCD_ENTRYSHIFTINCREMENT; ST7032i_WriteCmd(LCD_ENTRYMODESET | _displaymode); wait_ms(30); } /*======================================*/ /* ST7032i ユーザ文字作成関数 */ /*======================================*/ // Allows us to fill the first 8 CGRAM locations with custom characters void ST7032i_createChar(uint8_t location, uint8_t charmap[]) { int i; location &= 0x7; // we only have 8 locations 0-7 ST7032i_WriteCmd(LCD_SETCGRAMADDR | (location << 3)); wait_ms(30); for (i=0; i<8; i++) { ST7032i_WriteData(charmap[i]); wait_ms(30); } } /*======================================*/ /* ST7032i コントラスト設定関数 */ /*======================================*/ void ST7032i_setContrast(uint8_t new_val) { ST7032i_WriteCmd(LCD_FUNCTIONSET | _display_extended); wait_ms(30); //Needed ?? ST7032i_WriteCmd(LCD_ICON_CONTRAST_HIGH_BYTE | LCD_ICON_ON | LCD_BOOSTER_ON | (new_val >> 4 & LCD_CONTRAST_HIGH_BYTE_MASK)); wait_ms(30); ST7032i_WriteCmd(LCD_CONTRAST_LOW_BYTE | (new_val & LCD_CONTRAST_LOW_BYTE_MASK)); wait_ms(30); } /*======================================*/ /* 文字例出力関数 */ /*======================================*/ void ST7032i_puts(const char *s) { register char c; while ((c = *s++)) { ST7032i_WriteData(c); } } /*======================================*/ /* 文字例出力関数2 */ /*======================================*/ void ST7032i_puts_p(const char *progmem_s) /* print string from program memory on lcd (no auto linefeed) */ { register char c; while ( (c = pgm_read_byte(progmem_s++)) ) { ST7032i_WriteData(c); } }/* lcd_puts_p */ #ifdef STRAWBERRY_LINUX_16x2_LCD /*======================================*/ /* アイコン表示関数 */ /*======================================*/ /** * @brief Put icon. value is to be 0 - 12 * @param numbet : icon number * @retval None */ void ST7032i_Icon(uint8_t number, bool flag) { ST7032i_WriteCmd(0b00111001); // コマンド //icon address set ST7032i_WriteCmd(0b01000000 | Icon_Table[number][0] ); if(flag) { //icon data set ST7032i_WriteData(Icon_Table[number][1]); } else { //icon data reset ST7032i_WriteData(0x00); } ST7032i_WriteCmd(0b00111000); // } /*======================================*/ /* 電源アイコン表示関数 */ /*======================================*/ void ST7032i_Power_Icon(uint8_t power, bool flag) { uint8_t tmp; tmp = 0b00010; // 枠 switch(power) { case 0: break; case 1: tmp |= 0b10000; break; case 2: tmp |= 0b11000; break; case 3: tmp |= 0b11100; break; default: break; } ST7032i_WriteCmd(0b00111001); // コマンド //icon address set ST7032i_WriteCmd(0b01000000 | 0x0D ); //icon data set if(flag) { ST7032i_WriteData(tmp); } else { ST7032i_WriteData(0x00); } ST7032i_WriteCmd(0b00111000); // } #endif
応用
RTC8564ドライバとST7032iドライバを使うなら、以下のように書けば動くだろう。
#include <avr/io.h> #include "TinyI2CMaster.h" #include "ST7032i.h" #include "RTC8564.h" #include "delay.h" int main(void) { char buf[10]; RTC_TIME rtc_time; TinyI2C_Master_init(); ST7032i_Init(); ST7032i_setContrast(30); RTC8564_backup_return(); ST7032i_setCursor(0,0); ST7032i_puts("TEST!"); /* 時刻合わせ */ rtc_time.year = 2013; rtc_time.month = 10; rtc_time.day = 8; rtc_time.hour = 11; rtc_time.min = 5; rtc_time.sec = 0; RTC8564_adjust( &rtc_time ); while(1) { //TODO:: Please write your application code RTC8564_now(&rtc_time); xsprintf_p(buf,PSTR("%02d-%02d-%02d"), rtc_time.year-2000, rtc_time.month, rtc_time.day ); ST7032i_setCursor(0, 0); ST7032i_puts(buf); xsprintf_p(buf,PSTR("%02d:%02d:%02d"), rtc_time.hour, rtc_time.min, rtc_time.sec ); ST7032i_setCursor(0, 1); ST7032i_puts(buf); wait_sec(1); } }
ばんとさん、こんばんは。
TinyI2CMasterの解説、ありがとうございます。これから、実験してみますね。
木村さん、毎度です。
TinyI2CMasterライブラリィは、ドライバを書くためのソフトなので、
ドライバそのものを説明できなくってすみません。
メールで書かれてたADT7410のドライバも、データシート(PDF)を読まれたり、
arduinoの実装例(WsNakさんのブログ)を参考にしたら、TinyI2CMaster
で作れると思います。
完成したら木村さん、ぜひとも公開してください。
↓WsNakさんのブログ
http://www.wsnak.com/wsnakblog/?p=323
「ドライバ」という言葉が気になりました。ここで説明されている、下層レイヤの部分を指す用例の方が多いんじゃないかなと。あくまで、素人の印象ですが。
きゅうる村さん、毎度です。
ドライバが気持ちわるいですか?
申し訳ないです。適切な言葉が思い浮かばなかったのです。
きゅうる村さんの言葉に読み替えてください。
MS-DOSで言うと下層・中層はBIOSで、ドライバはデバイスドライバのイメージな
んです。
要するに、下層・中層というのはMPUをターゲットにプログラムを書いてる部分
ドライバは、I2Cなどのデバイスをターゲットにプログラムを書いている部分です。
I2CだけでなくSPIとかもありますが、I2CやSPIのようなプロトコル上で動作する
多様なデバイスがあるので、分離してプログラムを組んだ方が使い回し
(あえてこのように書きます)が可能になります。
ああ。確かに。通信プロトコルのライブラリ自体は、デバイスに特化されていませんね。
それはユーザが作るんですね。i2cデバイス用汎用ドライバという言い方はできるかもしれませんが。
ばんとさん、こんばんは。
最初、応用として掲載していただいたプログラムから、RTC8564の部分を取り除き、ST7032iのI2C LDCに”TEST”と表示させるようにして、code.google.comのTinyI2CMaster 0.11と組み合わせて、エラーが出ないように修正していたのですが、理解出来ないところでエラーが出てしまい、試しに、こちらに掲載してあるTinyI2CMaster 0.1を使ったら、問題なく動作してくれました。
また、時間があるときに、0.1と0.11の違いをじっくり見てみたいと思います。
修正は主に、ウェイトに使っていたwait_msを_delay_msに変更することでした。
これで、ATtiny85、INA226、ST7032iのI2C LDCの組み合わせの電圧、電流計が出来そうです。
>>完成したら木村さん、ぜひとも公開してください。
私に出来るのは、誰かが公開しているものを、自分用に多少手を加える事ぐらいなので、中々、公開は考えられないですね。もう少し、やっている事が理解出来ていれば良いのですが。今回も、INA226とATmega328やArduinoと組み合わせている方のソースを丸写しです。デバイスのデータシートからドライバを書ける人がうらやましい。
今回は、本当にありがとうございました。
木村さん、毎度です。ばんとです。
v0.1からv0.11で、どこを変更したの覚えてないのですが…f(^_^;;;
確認してみます。
ところで、AVRは8ビットのMPUでアーキテクチャーは比較的単純に出来てるので、AVR使いの
方の中には、MPUを直接弄ってプログラミングする人が多いです。
他方、同じAVRを使うArduinoは、アーキテクチャーに絡む部分はプログラミング済みで抽象化
されてて使いやすく初心者でもハードルが低くなってます。
同じ8ビットMPUのpicの市販C言語でもSPI用の関数とかI2C用の関数とかが用意されてて、
初心者でもハードルが低くなってます。
“TinyI2CMaster”もATtinyのI2Cを初心者でも使えるようにするライブラリィです。
ですから、どんどん使ってください。
>>私に出来るのは、誰かが公開しているものを
と仰らず、遠慮無く利用してください。
>これで、ATtiny85、INA226、ST7032iのI2C LDCの組み合わせの電圧、電流計が出来そうです。
木村さんも、INA226を持ってるのですね。当方も手元にあるのですが端子をハンダ付けしてま
せん。当然ながらINA226のドライバは書いてません。
デバイスドライバの作り方そのものが、もしかしたら初心者には難しいかもしれませんので、
例題として書きましょうか。
では…