2012年8月26日日曜日

GR-SAKURA I2C編3 ストリナI2C LCD

 今回は、GR-SAKURAでストロベリー・リナックスさんのI2C LCDを動かしてみました。というのも、以前に秋月のI2C LCDがArduinoでは簡単に動いたのに、SAKURAでは失敗したので、(原因追求するのも面倒なので)別のI2C LCD試してみようという、安易な発想からです。
 で結論。あっさり動いた。


 ソースは、前回のもののLCDのI2Cアドレスとか初期化の制御コマンドの辺りを変更しただけのもの。

#define RXDUINO

#ifdef RXDUINO
#include <rxduino.h>
#else
#include <Arduino.h>
#endif

#include <Wire.h>

#define LCD_ADDRESS    (0b0111110)
#define LCD_CONTRAST    100

#define LCD_RS_CMD    (0x00)
#define LCD_RS_DATA    (0x40)
#define LCD_CMD_CLEAR    (0x01)
#define LCD_CMD_HOME    (0x03)

// 関数プロトタイプ宣言。
void LCD_init();
void LCD_write(uint8_t rs, uint8_t data);
void LCD_clear();
void LCD_setCursor(byte col, byte row);
void LCD_putc(uint8_t c);
void LCD_puts(char *str);


void setup()
{
    // シリアルポートを9600bpsで開始。
    Serial.begin(9600);
    // 受信バッファにデータが入るまで待機。
    while (Serial.available() == 0);
    Serial.println("Initializing...");
    // 一旦、受信バッファにデータがあれば、
    if (Serial.available() > 0) {
        // 読み込んで、廃棄。
        char c = Serial.read();
    }
    
    // Bus-MasterとしてI2Cを開始。
    Wire.begin();

    delay(500);
    
    // LCDの初期化。
    LCD_init();
    
    // メッセージ表示。
    LCD_setCursor(0, 0);
    LCD_puts("Hello!!");
    LCD_setCursor(5, 1);
    LCD_puts("I2C LCD!!");

}

void loop()
{
    
}

// LCD初期化。
void LCD_init()
{
    delay(40);
    // Function Set。8bit bus mode, 2-line mode,normal font,normal instruction mode。
    LCD_write(LCD_RS_CMD, 0b00111000);
    // Function Set。extension instruction modeへ。
    LCD_write(LCD_RS_CMD, 0b00111001);
    // Internal OSC frequency(extension instruction mode)設定。
    LCD_write(LCD_RS_CMD, 0b00010100);
    // Contrast set(extension instruction mode)。コントラスト値下位4bit設定。
    LCD_write(LCD_RS_CMD, 0b01110000 | (LCD_CONTRAST & 0xF));
    // Power/ICON/Contrast set(extension instruction mode)。
    // アイコン On,booster On,コントラスト値上位2bit設定。
    LCD_write(LCD_RS_CMD, 0b01011100 | ((LCD_CONTRAST >> 4) & 0x3));
    // Follower control。internal follower on, 
    LCD_write(LCD_RS_CMD, 0b01101100);
    // 時間待ち。
    delay(300);
    
    // Function Set。normal instruction mode。
    LCD_write(LCD_RS_CMD, 0b00111000);
    // Display On/Off。Display Onに設定。
    LCD_write(LCD_RS_CMD, 0b00001100);
    // Clear Display。
    LCD_write(LCD_RS_CMD, 0b00001100);
    // 時間待ち。
    delay(2);
}

// LCDへデータ書き込み。
void LCD_write(uint8_t rs, uint8_t data)
{
    int rtnValue;
    
    if (rs == LCD_RS_CMD || rs == LCD_RS_DATA)
    {
        // LCD_RS_CMD ならコマンドモード。LCD_RS_DATA ならデータモード。
        
        // LCDへの送信準備開始。
        Wire.beginTransmission(LCD_ADDRESS);
        // モード(RS)送信。
        Wire.write(rs);
        // データ送信。
        Wire.write(data);
        // キューの送信。通信終了。
        rtnValue = Wire.endTransmission();
        Serial.print(rtnValue);
        
    }
    else
    {
        // rsの指定が0x00,0x80以外ならなにもしない。
    }
}

void LCD_clear()
{
    LCD_write(LCD_RS_CMD, LCD_CMD_CLEAR);
    delay(2);
    LCD_write(LCD_RS_CMD, LCD_CMD_HOME);
    delay(2);
}

void LCD_setCursor(byte col, byte row)
{
    byte offset[] = {0x00, 0x40};
    
    if (row > 1)    row = 1;
    if (col > 16)    col = 16;
    
    LCD_write(LCD_RS_CMD, 0x80 | (col + offset[row]));
}

void LCD_putc(uint8_t c)
{
    LCD_write(LCD_RS_DATA, c);
}

void LCD_puts(char *str)
{
    int i;
    for (i = 0; i < 16; i++)
    {
        if (str[i] == 0x00)
        {
            break;
        }
        else
        {
            LCD_putc((unsigned int)str[i]);
        }
    }
}

 いつものように RXDUINO のdefineをコメントアウトしてArduinoと兼用できるような書き方にしていますが、今回はArudino側での動作確認はしていませんので、あしからず。
 しかし、じゃあ、なんで、秋月のI2C LCDは動かないのさ、ということになるんですが。まあ、しらべる元気もないんだけど・・・。あした、そのうち、いつか・・・調べようかな・・・。明日っていつの明日よっ?
 もうひとつ気になることが・・・。上のソースのI2Cに送信してendTranmission()する戻り値をコンソールに出力しているんだけど、全部"2"(アドレス送信時にNACKを受信)となっているんだけど、いいのかな?成功(ACKを受信というかLCD側が応答)せずに文字だけ表示している?