yskwiki
ATTiny2313でキャラクタ液晶を使う
最終更新:
yskwiki
-
view
はじめに
買ったまま長いこと塩漬けになってたキャラクタ液晶(SC1602BS*B)を使ってみました。配線がごちゃごちゃしてるので、写真は載せませんw
LCDキャラクタディスプレイモジュール(16×2行バックライト無) 1個 ¥500(税込)(2012/09/07時点)
LCDキャラクタディスプレイモジュール(16×2行バックライト無) 1個 ¥500(税込)(2012/09/07時点)
2012.09.07 | 新規作成、初版 |
LCD接続
ATTiny2313とLCDの接続はこんな感じにしました。
ピン | 名称 | 接続先 | ピン | 名称 | 接続先 |
1 | VDD | 5V | 8 | DB1 | open |
2 | GND | GND | 9 | DB2 | open |
3 | Cont. | 可変抵抗 | 10 | DB3 | open |
4 | RS | PB6 | 11 | DB4 | PB0 |
5 | R/W | PB5 | 12 | DB5 | PB1 |
6 | EN | PB4 | 13 | DB6 | PB2 |
7 | DB0 | open | 14 | DB7 | PB3 |
このLCDは14本のピンのうち8本(DB0〜DB7)がデータ入出力用となっていますが、8bitモードと4bitモードがあり、4bitモードの場合は4本のピン(DB4〜DB7)をデータ入出力用として使用します。早くアクセスした場合は8bitモードを使用するんでしょうが、今回は使用ピン数の少ない4bitモードにします。
ソースコード
C版(1つのファイルにまとめてあります)
tn2313_lcd_test_c.c
関数 | 引数 | 説明 |
uint8_t lcd_read(uint8_t rs) | rs:MODE_CMD(コマンドリード),MODE_DAT(データリード) | LCDリード 戻り値はリード値(8bit) |
★void lcd_pol() | - | BusyFlag解除待ち |
★void lcd_write (uint8_t rs, uint8_t val) | rs:MODE_CMD(コマンドライト),MODE_DAT(データライト) val:ライトする値(下位4bitのみ使用) |
LCDライト |
void lcd_cmd(uint8_t cmd) | cmd:コマンドの値 | コマンド実行 |
void lcd_data(uint8_t data) | data:文字 | 文字を1つライト |
void lcd_clear() | - | 液晶をクリア |
void lcd_init() | - | 液晶を初期化 |
void lcd_putstr(char *str) | *str:文字列の先頭アドレス | *str位置から'\0'までライト |
以下はマクロとして定義 | ||
#define LcdMoveto1stLine(n) | n:位置 | カーソルを1行目のn桁目に移動 lcd_cmd(0x80+n)のalias |
#define LcdMoveto2ndLine(n) | n:位置 | カーソルを2行目のn桁目に移動 lcd_cmd(0xC0+n)のalias |
★の関数は基本的に直接呼び出すことは無いと思います。
10MHz用に作ってあるので、他の(特に10MHzよりも速い)周波数で動かす場合は、時間を調整する必要があります。10MHzより遅い周波数で動かす場合は特に変更しなくても動作すると思いますが、初期化時間が長くなります。
- 要変更箇所
- delay_100us()関数:引数*100us待機する関数。動作周波数に合わせて変更する必要があります。
- lcd_read()/lcd_write()関数:制御信号(RS,R/W,EN)のタイミングを調整する必要があります。
LCD用の関数内ではAVR依存の記述は無いと思うので、defineとdelay_100us()関数を変更すればPICでも動くと思います。僕はPICのライタを持ってないので試せませんがw
- ソースコードコピペ
#include <stdint.h> #include <avr/io.h> #include <compat/deprecated.h>// for cbi(), sbi() #include <util/delay_basic.h> // for _delay_loop_2() #include <stdlib.h> // for itoa() //-------------------------------------------------- // [6:4]をRS/RW/EN、 // [3:0]をLCDへのデータ出力に使用します。 // 汎用性はありません。 #define RS PB6 #define RW PB5 #define EN PB4 #define LCDIN PINB #define LCDPORT PORTB #define LCDDDR DDRB //-------------------------------------------------- // about 100us @10MHz void delay_100us(uint8_t n) { int i; for(i=n; i!=0; i--){ _delay_loop_2(249); } } //==================================================LCDここから //==============================H //#ifndef __AVR_LCDLIB_H__ //#define __AVR_LCDLIB_H__ //-------------------------------------------------- // busy flag #define BF 7 #define NOP() asm("nop"::) #define NOP2() {NOP();NOP();} // rjmp PC+1<-これどうやるの? #define DDR_READ 0xf0 #define DDR_WRITE 0xff #define MODE_CMD 0 #define MODE_DAT 1 #define LcdDataMode() sbi(LCDPORT, RS) #define LcdCmdMode() cbi(LCDPORT, RS) #define LcdReadMode() sbi(LCDPORT, RW) #define LcdWriteMode() cbi(LCDPORT, RW) #define LcdAccsEnable() sbi(LCDPORT, EN) #define LcdAccsDisable() cbi(LCDPORT, EN) #define LcdMoveto1stLine(n) lcd_cmd(0x80+n) #define LcdMoveto2ndLine(n) lcd_cmd(0xC0+n) //-------------------------------------------------- uint8_t lcd_read(uint8_t rs); void lcd_pol(); void lcd_write (uint8_t rs, uint8_t val); void lcd_cmd(uint8_t cmd); void lcd_data(uint8_t data); void lcd_clear(); void lcd_init(); void lcd_putstr(char *str); //#endif // __AVR_LCDLIB_H__ //==============================H //==============================C //-------------------------------------------------- // read LCDdata uint8_t lcd_read(uint8_t rs) { uint8_t ret; // set DDR for read operation LCDDDR = DDR_READ; LCDPORT &= 0xf0; if(rs==MODE_DAT) { LcdDataMode(); } else { LcdCmdMode(); } LcdReadMode(); //---------- // 1st read LcdAccsEnable(); // this requires wait-time at least 220ns ret = 0; NOP2(); ret = (LCDIN << 4); LcdAccsDisable(); //---------- NOP2(); //---------- // 2nd read LcdAccsEnable(); // this requires wait-time at least 220ns ret &= 0xf0; NOP2(); ret|= (LCDIN & 0x0f); LcdAccsDisable(); //---------- return ret; } // polling // wait until BusyFlag is cleared void lcd_pol() { //uint8_t timeout = 100; //while((lcd_read(MODE_CMD) & _BV(BF)) && (timeout-- != 0)) {} while(lcd_read(MODE_CMD) & _BV(BF)) {} } //-------------------------------------------------- // write data(for only 4bit-mode) void lcd_write (uint8_t rs, uint8_t val) { LCDDDR = DDR_WRITE; // set DDR for write operation if(rs==MODE_DAT) { LcdDataMode(); } else { LcdCmdMode(); } LcdWriteMode(); //---------- // write LcdAccsEnable(); LCDPORT = ((LCDPORT & 0xf0) | (val & 0x0f)); LcdAccsDisable(); } // command write void lcd_cmd(uint8_t cmd) { // 4bit-modeなので、2回に分けてライト lcd_write(MODE_CMD, cmd>>4); lcd_write(MODE_CMD, cmd ); lcd_pol(); } // data write void lcd_data(uint8_t data) { // 4bit-modeなので、2回に分けてライト lcd_write(MODE_DAT, data>>4); lcd_write(MODE_DAT, data ); lcd_pol(); } //-------------------------------------------------- // clear LCD void lcd_clear() { lcd_cmd(0x01); // clear display //delay_100us(16); } // initialize LCD void lcd_init() { // 最初のうちはbusy flagを利用できないので // 時間を指定して待機 delay_100us(150); lcd_write(0, 0x03); delay_100us(41); lcd_write(0, 0x03); delay_100us(1); lcd_write(0, 0x03); delay_100us(1); lcd_write(0, 0x02); delay_100us(1); lcd_cmd(0x28); // set to 4bit-mode, 2line-mode lcd_cmd(0x08); // display off lcd_clear(); // clear display lcd_cmd(0x0C); // display on lcd_cmd(0x06); // entry mode is inc, cursor-move } // put string void lcd_putstr(char *str) { // 終端文字'¥n'までライト while(*str != '¥0') { lcd_data(*(str++)); } } //==============================C //==================================================LCDここまで //-------------------------------------------------- int main() { uint8_t c=0; char num[4]; // 数値文字列変換用領域の確保(3文字分+'¥0') lcd_init(); lcd_clear(); //---------- lcd_putstr("LCD Test:"); while(1) { // "LCD Test:"の後ろ(10文字目)に移動 LcdMoveto1stLine(9); // 泥臭い方法で左詰め if(c<100) lcd_data(' '); if(c< 10) lcd_data(' '); lcd_putstr(itoa(c++, num, 10)); // 2行目の先頭に移動 LcdMoveto2ndLine(0); lcd_putstr("^^^^^^^^"); // delay_100us(250); delay_100us(250); } } //-------------------------------------------------- // EOF
今後やりたいこと
- アセンブラ版も作る
- CGRAMを使って、自作の文字を表示させる
添付ファイル