秋月でSG12864Aという128x64ドットのグラフィック液晶が売られています(通販番号P-02159)。発売当時はもっと高かったのですが、いつのまにか値下げしています(2100円→1700円)。発売当時に書いた記事です。
この液晶の特長はなんといっても5Vで動かせることです。他に手に入るものは3.3V系のものが多いです。どうして5Vかというと、ATmarquinoで動かしたかったからです。でもって、慣れないせいもあってか、未だに動かせていません。しかたないので、配線やロジックの確認のために素のATMega168を使ってCでプログラムを書いてみました。一応、以前V850用に書いたことがあったので、すんなり動きました。そのときは、サイキットさんの液晶用だったのですが、秋月のも互換性があります。って、久々にサイキットさんを見たら液晶が値下がりしてます。
出力例です。
ネギは振りません。とりあえず静止画です。
配線はもじゃー
データが8本、制御が6本です。
コードです。<と>は全角になっています。
Arduinoを使って分かったことは、デジタル出力の0と1はなるべく使わない方がいいということです。RXとTXなのでプログラミングするのにも使われているからです。あとは、DDRB、PORTB、PINBといったポートへのバイト入出力が普通に使えることです。
回路図は後で描きます。
ATMega168って、実質的に連続して8ビットとれるポートがPORTDしかないです。Arduinoだとデジタル出力の0~7です。
うーん、せっかくのArduinoなのに、全然プロトタイプしてないです><
この液晶の特長はなんといっても5Vで動かせることです。他に手に入るものは3.3V系のものが多いです。どうして5Vかというと、ATmarquinoで動かしたかったからです。でもって、慣れないせいもあってか、未だに動かせていません。しかたないので、配線やロジックの確認のために素のATMega168を使ってCでプログラムを書いてみました。一応、以前V850用に書いたことがあったので、すんなり動きました。そのときは、サイキットさんの液晶用だったのですが、秋月のも互換性があります。って、久々にサイキットさんを見たら液晶が値下がりしてます。
出力例です。
ネギは振りません。とりあえず静止画です。
配線はもじゃー
データが8本、制御が6本です。
コードです。<と>は全角になっています。
#include <avr/io.h> #include <util/delay.h> #include <avr/pgmspace.h> #define DC PB5 // 19→4 #define RW PB4 // 18→5 #define E PB3 // 17→6 #define D0 PD0 // 2→7 #define D1 PD1 // 3→8 #define D2 PD2 // 4→9 #define D3 PD3 // 5→10 #define D4 PD4 // 6→11 #define D5 PD5 // 11→12 #define D6 PD6 // 12→13 #define D7 PD7 // 13→14 #define CS1 PB2 // 15→16 #define CS2 PB1 // 14→17 #define RST PB0 // 13→18 #define lcd_d() PORTB |= _BV(DC) #define lcd_c() PORTB &= ~_BV(DC) #define lcd_r() PORTB |= _BV(RW) #define lcd_w() PORTB &= ~_BV(RW) #define lcd_e1() PORTB |= _BV(E) #define lcd_e0() PORTB &= ~_BV(E) #define busy (PIND & 0x80) void busywait(void) { DDRD = 0x00; lcd_c(); lcd_r(); do { lcd_e1(); lcd_e0(); } while(busy); DDRD = 0xff; lcd_w(); } void left(void) { PORTB &= ~_BV(CS2); PORTB |= _BV(CS1); } void right(void) { PORTB &= ~_BV(CS1); PORTB |= _BV(CS2); } void lcd_cmd(uint8_t c) { busywait(); lcd_c(); PORTD = c; lcd_e1(); lcd_e0(); } void lcd_data(uint8_t c) { busywait(); lcd_d(); PORTD = c; lcd_e1(); lcd_e0(); } void lcd_locate(uint8_t x, uint8_t y) { lcd_cmd(0x40 | (x & 0x3f)); lcd_cmd(0xb8 | (y & 7)); } void lcd_init(void) { DDRD = 0xff; DDRB = 0xff; // リセット PORTB = 0x00; _delay_ms(1); PORTB |= _BV(RST); left(); lcd_cmd(0xc0); lcd_cmd(0x3f); right(); lcd_cmd(0xc0); lcd_cmd(0x3f); } PROGMEM uint8_t pic[128*8] = { 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0xe0,0xf0,0xfc,0xf8,0xf0,0xe0,0xe0,0x80,0x00,0x00,0x00,0x00,0xe0,0xe0,0xf0,0xf0,0xf8,0xc0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x09,0x1b,0x17,0x3f,0x7f,0xff,0xff,0xff,0xfe,0xfc,0xf8,0xf1,0xff,0xff,0xff,0xff,0xff,0xfc,0xe0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xe0,0xf0,0xf8,0xf8,0xfc,0xfe,0xfd,0xfd,0xfd,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfe,0xfe,0xfe,0xfc,0xfc,0xfc,0xf8,0xf0,0xf0,0xf0,0xf8,0xfc,0xf4,0xfc,0xfc,0xf0,0xe0,0xc0,0x80,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x03,0x07,0x0f,0x1f,0x3f,0x7f,0xff,0xff,0xff,0x7f,0x3f,0x3e,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xf0,0xf8,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x7f,0x3f,0x1f,0x0f,0x0f,0x07,0x07,0x03,0xff,0xff,0xff,0xff,0xff,0x0f,0x03,0x07,0x0f,0x1f,0x3f,0x7f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfc,0xf0,0xc0,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc0,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xdf,0x47,0x27,0x20,0x42,0x82,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x1f,0x7f,0xff,0xff,0x00,0x04,0x84,0x40,0x48,0x48,0x81,0x17,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x08,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xe0,0xfc,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3f,0x9f,0x0f,0x00,0x03,0x06,0x04,0x04,0x06,0x03,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x03,0x03,0x03,0x07,0x0c,0x08,0x08,0x07,0x00,0x00,0x07,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x08,0xe0,0xff,0xfc,0xfc,0xfe,0xfe,0xfe,0xfe,0xfe,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xf8,0xf9,0xf0,0x80,0x80,0x00,0x00,0x00,0x00,0xff,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0xc1,0x3f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xc0,0xe0,0xff,0xff,0xff,0xff,0x7f,0x3f,0x1f,0x0f,0x0f,0x0f,0x07,0x07,0xff,0xff,0xff,0xff,0xff, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3f,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x24,0x40,0x4e,0x59,0x10,0x90,0x90,0x90,0x90,0x90,0xf0,0xf0,0x7f,0x70,0x70,0xf0,0xf0,0xf0,0xf8,0xf8,0xf0,0x7c,0x0c,0x0f,0x0f,0x1f,0x1f,0x3f,0x23,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xff,0xff,0xff,0xff, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xc3,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x0f,0x0f,0x0f,0x1f,0x98,0xd0,0x70,0x30,0xfc,0xfe,0xff,0xff,0xff,0xff,0x3f,0xfc,0xf8,0xf8,0x3e,0x0f,0x07,0x07,0x7f,0xe3,0x80,0x80,0x00,0x20,0x20,0x00,0x82,0x8c,0xf0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, }; int main() { uint8_t *p = pic; uint8_t x, y; DDRC = _BV(PC5); lcd_init(); for(y = 0; y < 8; y++){ left(); lcd_locate(0, y); for(x = 0; x < 64; x++) lcd_data(pgm_read_byte(p++)); right(); lcd_locate(0, y); for(x = 0; x < 64; x++) lcd_data(pgm_read_byte(p++)); } while(1){ PORTC ^= _BV(PC5); _delay_ms(200); } }
Arduinoを使って分かったことは、デジタル出力の0と1はなるべく使わない方がいいということです。RXとTXなのでプログラミングするのにも使われているからです。あとは、DDRB、PORTB、PINBといったポートへのバイト入出力が普通に使えることです。
回路図は後で描きます。
ATMega168って、実質的に連続して8ビットとれるポートがPORTDしかないです。Arduinoだとデジタル出力の0~7です。
うーん、せっかくのArduinoなのに、全然プロトタイプしてないです><
なんだ、そうだったのか。悩んじゃったけれど、普通にCで書いて良いんですね。
一つ質問
PROGMEM uint8_t pic[128*8]
この後0でFILLしているけれど、AVRのGCCってmainが動く前に0クリアされないのですか?。
ええ、「Arduinoをはじめよう」(聖書)のp.111に書かれていました。
picは、初音さんの絵の左側が空白だったので0x00が続いていますが、右の方に行くと0以外も登場してます。
普通のCだと、外部変数は0クリアされるはずですが、avr-gccのランタイムもそうなっているかどうかは知らないです。こういうとき、オンチップのデバッガがほしくなりますね。フリースタンディング環境でも0クリアされると期待していいんでしたっけ?
「なんでこんな事が」と思っていたけれど、今日例の本が来て判りました。112ページの話ですね。
しかし112ページの例の文は問題が有るぞ。
はい、SG12864Aをつなげたままだと、プログラミングできない状態になってしまいました。
あう、例題の問題ってなんでしょう?分かりませんでした><
http://hamayan.blog.so-net.ne.jp/2009-03-29-2
それはそれとして、制御線、EとかRWには少なくともプルアップやプルダウンを入れておいた方が良いかと。
ありがとうございます。
LEDチカチカのときは、全然問題なかったんですが、SG12864Aだと、うまくいきませんでした。1ピン(RxD)をはずすと、なんとかプログラミングできました。
横着して、リセットだけしちゃいました。初期化の順番ができちゃうので、やっぱりつけといた方がよさそうですね。
探して、こちらにたどり着きました
ATmega664PとSG12864Aをつないでサンプルを参考にして
ほぼ、動くようになったのですがDisplay Start Line で0に設定できないようで
立ち上げるたびに0以外のいろんな場所から
Dataを書き込み、左端に戻って始まった位置の1アドレスス前で終わります、ページを変更しても、同じ位置で始まり左右で始まる位置が異なっています
開発中に同様なことで、工夫されたことなどありましたら
ご教授いただけないでしょうか
その症状はなったことがないですが、なんとなく、こうじゃないかなというのはあります。はずしてたらすみません。
この液晶にのっているグラフィックコントローラは事実上初期化をしなくても使えます。それというのもリセットのときに自動的に初期化されるからです。立ち上げるたびに症状が変わるのはリセットがうまくかかっていないのではないかと思いました。
対策としては、(1)リセット信号にプルダウン抵抗をつける(私は10kΩのをつけています)、(2)リセット後の待ち時間を変える、(3)E、R/W、DCあたりをプルアップもしくはプルダウンする、あたりが考えられます。
(1)のプルダウンですが、逆にプルアップした方がいいかもしれません。データシートには立ち上がりでリセットを認識するみたいなことが書いてあったので、プルダウンにしています。
とりあえず、(1)から順に試してみる感じでしょうか。うまくいったら教えてください。
lcd_locateで
lcd_cmd(0xc0 | (x & 0x3f));ではなく
lcd_cmd(0x40 | (x & 0x3f));で不具合がなくなりましたことご報告いたします
ディスプレースタートラインではなくColumn Address Setで
うまく動くとは不思議なのですが。
また、サンプルのように左右画面を同時に描画すると問題はないのですが、上記の描画後、右画面だけにFONTを用いた文字を描画すると、過去に書いた絵が右側全画面1ドット上に動いて左右がずれず不具合を発見しました
また、何かわからないことがありましたら、ご教授お願いします
動いたようでよかったです。
いつものごとく私は思いっきりはずしてましたね。RawとかColumnってよく分からなくなります><。
こちらこそ、よろしくお願いします。