2015年3月3日火曜日

秋月のキャラクタOLED(SO1602A)のお試し

JUMA送信機に使ったOLEDはパラレルインターフェースのモジュールでしたが、以前ためしに秋月で購入しておいたキャラクタOLEDはI2Cインターフェースです。しばらくパーツ箱に眠っていましたが、ようやくテストしてみました。

購入したのは白色タイプで共立エレショップで購入したものより若干お値段安めでした。ピン配置は同じでしたがインターフェースが異なるので、JUMAにはそのままでは使えません。ただし、データライン以外は大部分共通なのでファームウエアにI2Cインターフェースコードを追加変更すれば使えるかもしれません。

とりあえずその辺は置いておいて。

I2Cインターフェースと基本的なコマンドは、同じく秋月で販売されているAQM0802や1602と同じですが拡張コマンドの扱いが異なります。

たとえばコントラスト調整ですが、これは拡張コマンドに属していてもともとのコントラスト調整コマンド(0x81)の前に2つの拡張コマンドのためのコマンドを送る必要があります。そのあと、また拡張コマンドを通常に戻すコマンドを送ります。

後半にコード例を提示しますが、これは秋月製のマニュアルにも書いてありますので使ってみたい方はご一読を。

そのほかは、他のI2CタイプのLCD用コードを流用できるので表示させるだけならば容易だと思います。

というわけで、以前書いたLCD用のプログラムをちょいと直してコンパイルし初点灯。

2本の赤いジャンパ線が信号線になっています
なんだかというよりも水色なのでは?^^;

いえいえ実際目で見ると白色です。そういえばJUMAで使った白色OLEDもカメラで撮ると青っぽかったですね...どうも、LEDなどで作られる白色は青色の発光体をベースにしていて白色に見えるように加えられた波長の光がカメラでは(iPhoneのカメラですが^^;)カットされてしまって水色っぽく見えるのでしょうか。

とりあえず、色です!!(笑)

そういうわけでわりとあっさり表示されたので、次のステップに移ります。

 最後にコード公開しちゃいますが、流用は自己責任でお願いします。PIC内蔵のI2Cモジュールは使っていません。

環境:MPLAB IDE v8.93 + XC8 v1.33

【I2C OLED駆動関連】
//
//    so1602a.c
//    Akiduki's 16x2 character I2C OLED (SO1602A)display handling program
//    by JL1VNQ / HARU 20150301
//

#include <xc.h>

#define SDA    LATBbits.LATB6        // PIN No.12 example for 16F1827/1847, MCU dependent
#define SCL    LATBbits.LATB7        // PIN No.13

#define LCD_AD    0x78            // SO1602A OLED I2C address(SAO = 0)
//#define LCD_AD 0x7A            // (if SAO = 1)

#define uint8_t    unsigned char
#define uint16_t unsigned short


#define _XTAL_FREQ        4000000
 
extern void msec_delay(uint16_t time);


void I2C_init(void){
    SDA = 1;
    SCL = 1;
}

void I2C_send(uint8_t data){
    uint8_t i;
    for(i=0;i<8;i++){
        if(data & 0x80)
            SDA = 1;
//        else
//            SDA = 0;
        SCL = 1;
        SCL = 0;
        SDA = 0;
        data <<= 1;
    }
    SCL = 1;                // for ack
    SCL = 0;
}

void oled_cmd(uint8_t work){
    SDA = 0;
    SCL = 0;
    I2C_send(LCD_AD);
    I2C_send(0x80);                // Co=1, RS=0
    I2C_send(work);
    SCL = 1;
    SDA = 1;
    __delay_us(30);
}

void oled_data(uint8_t work){
    SDA = 0;
    SCL = 0;
    I2C_send(LCD_AD);
    I2C_send(0xC0);                // Co=1, RS=1
    I2C_send(work);
    SCL = 1;
    SDA = 1;
    __delay_us(30);
}

void oled_init(void){
    msec_delay(100);
    oled_cmd(0x01);                // clear diaplay
    msec_delay(20);
    oled_cmd(0x02);                // to home position
    msec_delay(2);
    oled_cmd(0X0C);                // display on
    msec_delay(2);
    oled_cmd(0x01);
    msec_delay(20);
}

void oled_position(uint8_t li, uint8_t col){
    oled_cmd(0x80 | (li << 5) | col);        // line0 columun0 = 0x00, line1 columun0 = 0x20
}

void oled_char_disp(uint8_t li, uint8_t col, uint8_t ascii){
    oled_position(li,col);
    oled_data(ascii);
}

void oled_str_disp(uint8_t li, uint8_t col, const char *string){
    uint8_t i = 0;
    oled_position(li,col);
    while(((col + i) < 16) && string[i]){
        oled_data(string[i]);
        i++;
    }
}

void oled_clear(void){
    oled_cmd(0x01);
    msec_delay(2);
}

void oled_contrast(uint8_t cont){
    oled_cmd(0x2A);                // RE = 1
    oled_cmd(0x79);                // SD = 1
    oled_cmd(0x81);                // contrast control
    oled_cmd(cont);                 // value
    oled_cmd(0x78);                // SD = 0
    oled_cmd(0x28);                // RE = 0
    msec_delay(100);
}


【サンプル表示プログラム】
//
//    oled_test.c
//    Akiduki's 16x2 Character I2C OLED display (SO1602A) tset program for 16F1847/1827
//    by JL1VNQ / HARU 20150303
//

#include <xc.h>

#pragma config CPD = OFF, BOREN = NSLEEP, IESO = OFF, FOSC = INTOSC
#pragma    config FCMEN = OFF, MCLRE = OFF, WDTE = OFF, CP = OFF, PWRTE = ON, CLKOUTEN = OFF
#pragma config PLLEN = OFF, WRT = OFF, STVREN = OFF, BORV = LO, LVP = OFF

#define EEPROM_SIZE     256
#define _XTAL_FREQ        4000000

#define uint8_t unsigned char
#define uint16_t unsigned short
#define uint32_t unsigned long

extern void I2C_init(void);
extern void oled_init(void);
//extern void I2C_send(uint8_t data);
//extern void oled_cmd(uint8_t work);
//extern void oled_data(uint8_t work);
//extern void oled_position(uint8_t li, uint8_t col);
extern void oled_char_disp(uint8_t li, uint8_t col, uint8_t ascii);
extern void oled_str_disp(uint8_t li, uint8_t col, const char *string);
extern void oled_clear(void);
extern void oled_contrast(uint8_t cont);

void msec_delay(uint16_t time);


void main(void){
    OSCCON = 0x6A;                 // 4MHz internal OSC no PLL
    TRISA = 0x00;                    // all ports are output
    TRISB = 0x00;
    ANSELA = 0x00;                  // digital
    ANSELB = 0x00;

    I2C_init();
    oled_init();

   
    while(1){
        oled_str_disp(0,0,"OLED-test!JL1VNQ");
        oled_str_disp(1,0,"ABCDEFGHI0123456");
        msec_delay(1000);
        oled_clear();
        msec_delay(900);
        oled_contrast(0xFF);
        oled_str_disp(0,0,"ContrastLevelMax");
        oled_str_disp(1,0,"ABCDEFGHI0123456");
        msec_delay(1000);
        oled_clear();
        msec_delay(900);
        oled_contrast(0x00);
        oled_str_disp(0,0,"ContrastLevelMin");
        oled_str_disp(1,0,"ABCDEFGHI0123456");
        msec_delay(1000);
        oled_clear();
        msec_delay(900);
        oled_contrast(0x7F);
    }
}

void msec_delay(uint16_t time){
    for(uint16_t i=0;i<time;i++){
        __delay_ms(1);
    }
}


ターゲットはPIC16F1827/1847ですが、ポート割り当てとポート初期化あたりを書き換えれば8ピンPICでも動作可能です。なにせOLEDとPIC間の信号線は2本しかありませんから~

気になる消費電流ですが、コントラストによって大きく変わりました。
コントラスト中央値設定で30mA、最低値で14mA、最大値で45mA、無表示で4~6mAでした。

0 件のコメント:

コメントを投稿