目次>6章 第3ステップ(実用品)>1ピンで液晶ディスプレイを制御 >ソース
1ピンで液晶ディスプレイを制御(ソース)
(シリアル制御LCD)<PIC16F84A>PICC-Lite
更新日2008.1.14
以下のソースを取り込んで、コンパイル→PIC書き込み→実行して下さい。
// ========================== ここから ============================== // PIC16F84A // CLOCK : 20MHz // 他のPICからシルアル通信風にデータを受信し、LCDに出力する // // 通信速度 以下をPBSで切り替える // ・ 4800bps // ・ 9600bps // ・19200bps // ・28800bps // ・38400bps // ・57600bps // // TMR0:ビット受信のサンプリング間隔 // 0.2μS×100=20μS : 50Kbps // 通信速度 TMR0プリスケーラ 256-TMR0 // 4800 8 130 // 9600 4 130 // 19200 2 130 // 28800 2 87 // 38400 2 65 // 57600 2 43 // // // ↓スタートビット // __ // ___| | | | | // ↑ ↑ ↑ // | 20μS毎にサンプリング // 立ち上がりから10μS遅らせる // // // // RA0:LCD_E // RA1:LCD_R/W // RA2:LCD_RS // RA3:SW1(スピード切り替え) // RA4:SW2 // RB0:LCD_DB4 // RB1:LCD_DB5 // RB2:LCD_DB6 // RB3:LCD_DB7 // RB4: // RB5:LED(データ受信時点灯,バッファオーバラン時点灯) // RB6: // RB7:他のPICからシリアル受信(ピン変化割込み) // // LCD_V0 : 350ΩでGND // LCD_DB0-3:GND // #include "pic.h" #define LCD_E RA0 #define LCD_RW RA1 #define LCD_RS RA2 #define buffsize 40 #define RS_data 0x11 #define RS_cmd 0x12 #define EEsave 0 // スピード表示文字列のアドレス(EEPROM) #define EEKbps 8 // 'Kbps' EEPROMアドレス #define EE48 13 // '4.8' EEPROMアドレス #define EE96 17 // '9.6' EEPROMアドレス #define EE192 21 // '19.2' EEPROMアドレス #define EE288 26 // '28.8' EEPROMアドレス #define EE384 31 // '38.4' EEPROMアドレス #define EE576 36 // '57.6' EEPROMアドレス static void OverRun(); static void Delay_1ms(); static void Delay_ms(unsigned char); static void pic_init(); static void LCD_send4(unsigned char); static void LCD_Busy_wait(); static void LCD_cmd(unsigned char); static void LCD_data(unsigned char); static void LCD_init(); static void bufLCD(); static void sw_RA3_on(); static void EEtoLCD(unsigned char); static void EEwrite(unsigned char, unsigned char); static unsigned char EEread(unsigned char); static void EEspeed(); static void speedDSP(); __CONFIG(HS & WDTDIS & PWRTEN & UNPROTECT); __EEPROM_DATA(0x06, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF); __EEPROM_DATA('K', 'b', 'p', 's', 0x00, '4', '.', '8'); __EEPROM_DATA(0x00, '9', '.', '6', 0x00, '1', '9', '.'); __EEPROM_DATA('2', 0x00, '2', '8', '.', '8', 0x00, '3'); __EEPROM_DATA('8', '.', '4', 0x00, '5', '7', '.', '6'); __EEPROM_DATA(0x00, ' ', ' ', ' ', ' ', ' ', ' ', ' '); __EEPROM_DATA(' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); __EEPROM_DATA(' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '); static unsigned char buff[buffsize]; static unsigned char buffR; // バッファ読み込みポインタ static unsigned char buffW; // バッファ書き込みポインタ static unsigned char SW_RS; // LCD書き込みモード static unsigned char comm_stat; // 通信状態 // 0:無通信 // 1:スタートビット受信,半ビット時間待ち // 2:データビット受信中 // 3:データビット受信完了,ストップビット待ち static unsigned char comm_char; // 受信データ static unsigned char comm_bit; // 受信データのビット数 static unsigned char T0val; // TMR0設定値 static unsigned char sw_RA3; // RA3 SW状態 static unsigned char speed; // 通信速度(1:4800,2:9600,3:19200) // =================== 割り込み処理 ==================== static void interrupt intr(void) { if (T0IF) { // TMR0割り込み? TMR0 = 256 - T0val; // TMR0 T0IF = 0; // TMR0割り込みクリア RB4 ^= 1; // DEBUG switch (comm_stat) { case 1: // ■スタートビット受信開始,半ビット待ち // if (RB7) { // スタートビット? comm_stat = 2; // データビット受信中 comm_bit = 8; // 8ビット受信開始 // } else { // comm_stat = 0; // 無通信 // } break; case 2: // ■データビット受信中 comm_char <<= 1; if (RB7) { comm_char |= 0x01; } comm_bit--; if (!(comm_bit)) { buff[buffW] = comm_char; comm_stat = 3; // データビット受信完了,ストップビット待ち // バッファ書き込みポインタの更新 buffW++; // if (buffW < buffsize) { // バッファポインタは最終位置でない // if (buffW == buffR) { // OverRun(); // オーバーラン(LED点灯し停止する) // } // } else if (buffW == buffsize) { // バッファポインタは最終位置? // if (buffR != 0) { buffW = 0; // } else { // OverRun(); // オーバーラン(LED点灯し停止する) // } } } break; case 3: // ■ストップビット待ち comm_stat = 0; // 無通信状態 if (!RB7) { RB5 = 0; // LED消灯 } RB4 = 0; // DEBUG T0IE = 0; RBIE = 1; RBIF = 0; break; } } else if (RBIF) { // PORTBピン変化割り込み? RB5 ^= 1; if (RB7) { // スタートビット? if (comm_stat == 0) { // ■無通信状態 comm_stat = 2; // データビット受信中 comm_bit = 8; // 8ビット受信開始 // comm_stat = 1; // スタートビット受信開始,半ビット待ち // RB5 = 1; // LED点灯 RB4 = 0; // DEBUG // TMR0 = 256 - (T0val >>1); // TMR0 // TMR0 = 256 - T0val + 20; // TMR0 // TMR0 = 256 - T0val - 10; // TMR0 TMR0 = 256 - T0val; // TMR0 T0IF = 0; T0IE = 1; // RBIE = 0; } } RBIF = 0; // PORTBピン変化割り込みクリア } } // ==================== メイン処理 =========================== main() { unsigned char i; unsigned char c; pic_init(); // PICの初期化 LCD_init(); // LCDの初期化 EEspeed(); buffW = 0; buffR = 0; SW_RS = 1; // LCD Data mode Delay_ms(250); Delay_ms(250); comm_stat = 0; RB7 = 0; INTCON = 0x88; // GIE=1, RBIE=1 while(1) { if (buffW != buffR) { bufLCD(); } if (RA3) { // RA3:1 (SW off) sw_RA3 = 0; } else { // RA3:0 (SW on) sw_RA3_on(); } } } // ==================== バッファオーバラン発生 ================ static void OverRun() { RB5 = 1; while(1) {} } // ==================== 1mSウェイトルーチン ================ static void Delay_1ms() { unsigned int cnt; unsigned int i; cnt = 384; for (i=0 ; i<cnt ; i++) { NOP(); } } // ==================== 1mS×ms ウェイトルーチン =========== static void Delay_ms(unsigned char ms) { unsigned char c; for (c=ms ; c>0 ; c--) { Delay_1ms(); } } // ==================== PICの初期化 =========================== static void pic_init() { OPTION = 0x00; // TMR0プリスケーラ:2 TRISA = 0xF8; // RA0-2:out TRISB = 0x80; // RB0-6:out PORTA = 0x00; PORTB = 0x00; INTCON = 0x00; // GIE:0 ,T0IE:0 ,RBIE:0 } // ==================== LCD 4ビット送信 ========================= static void LCD_send4(unsigned char c) { PORTB = (PORTB & 0xF0) | c; LCD_E = 1; NOP(); LCD_E = 0; } // ==================== LCD Busy解除を待つ ==================== static void LCD_Busy_wait() { LCD_E = 0; LCD_RW = 1; LCD_RS = 0; TRISB = TRISB | 0x0F; // PORTB(3-0):input while(1) { LCD_E = 1; // 上位4ビット読み込み NOP(); if (RB3 == 0) { // Busy = 0を待つ LCD_E = 0; break; } LCD_E = 0; NOP(); LCD_E = 1; // 下位4ビット読み込み NOP(); LCD_E = 0; NOP(); } LCD_E = 1; // 下位4ビット読み込み NOP(); LCD_E = 0; TRISB = TRISB & 0xF0; // PORTB(3-0):output } // ==================== LCDコマンドWRITE ================= static void LCD_cmd(unsigned char cmd) { LCD_Busy_wait(); // Busy解除待ち LCD_RS = 0; LCD_RW = 0; PORTB = (PORTB & 0xF0) | ((cmd >>4) & 0x0F); LCD_E = 1; // 上位4ビット書き込み NOP(); LCD_E = 0; PORTB = (PORTB & 0xF0) | (cmd & 0x0F); LCD_E = 1; // 下位4ビット書き込み NOP(); LCD_E = 0; } // ==================== LCDデータWRITE ================= static void LCD_data(unsigned char cmd) { LCD_Busy_wait(); // Busy解除待ち LCD_RS = 1; LCD_RW = 0; PORTB = (PORTB & 0xF0) | ((cmd >>4) & 0x0F); LCD_E = 1; // 上位4ビット書き込み NOP(); LCD_E = 0; PORTB = (PORTB & 0xF0) | (cmd & 0x0F); LCD_E = 1; // 下位4ビット書き込み NOP(); LCD_E = 0; } // ==================== LCDの初期化 =========================== static void LCD_init() { Delay_ms(15); LCD_E = 0; LCD_RW = 0; LCD_RS = 0; LCD_send4(0x03); // DB4-7に'3'を出力(8bitモードに)@ Delay_ms(5); LCD_send4(0x03); // DB4-7に'3'を出力(8bitモードに)@ Delay_ms(1); LCD_send4(0x03); // DB4-7に'3'を出力(8bitモードに)@ Delay_ms(1); LCD_send4(0x02); // DB4-7に'2'を出力(4bitモードに) Delay_ms(1); // ここからは4bitモードで、Busyフラグが使える LCD_cmd(0x28); // DL=0:4bit ,N=1:2lines ,F=0:5*7dot LCD_cmd(0x08); // Display off LCD_cmd(0x0C); // Display on ,cursor on ,no blink LCD_cmd(0x06); // Entry mode (Inc ,No Shift) LCD_cmd(0x01); // Clear Display } // =============== bufferの内容をLCDに出力 =================== static void bufLCD() { unsigned char c; c = buff[buffR]; switch (c) { case RS_cmd: SW_RS = 0; // Command mode set break; case RS_data: SW_RS = 1; // Data mode set break; default: if (SW_RS) {LCD_data(c);} else {LCD_cmd(c); } } buffR++; if (buffR == buffsize) { // バッファポインタは最終位置? buffR = 0; } } // ==================== RA3スイッチON処理 ============== // スピード切り替え static void sw_RA3_on() { Delay_ms(20); // チャタリングキャンセル if (!RA3) { // RA3 on 確定 if (!(sw_RA3)) { sw_RA3 = 1; if (!(speed)) {speed = 6;} LCD_cmd(0x01); // LCDクリア speedDSP(); // スピードをLCDに表示 comm_stat = 0; // 無通信状態 EEwrite(EEsave,speed); speed--; } } } // ============= EEPROMに保存したスピードをLCDに表示 ========== static void EEspeed() { speed = EEread(EEsave); LCD_cmd(0x01); // LCDクリア speedDSP(); // スピードをLCDに表示 } // ==================== スピードをLCDに表示 ================= static void speedDSP() { OPTION = 0x00; // TMR0プリスケーラ:2 switch(speed) { case 1: OPTION = 0x02; // TMR0プリスケーラ:8 T0val = 127; // 4.8Kbps EEtoLCD(EE48); break; case 2: OPTION = 0x01; // TMR0プリスケーラ:4 T0val = 124; // 9.6Kbps EEtoLCD(EE96); break; case 3: T0val = 119; // 19.2Kbps EEtoLCD(EE192); break; case 5: T0val = 54; // 38.4Kbps EEtoLCD(EE384); break; case 6: T0val = 32; // 57.6Kbps EEtoLCD(EE576); break; default: T0val = 76; // 28.8Kbps speed = 4; EEtoLCD(EE288); break; } EEtoLCD(EEKbps); } // ============= EEPROM[addr]の内容を0x00までLCDに出力 ========== static void EEtoLCD(unsigned char addr) { unsigned char c; unsigned char i; i = addr; while(1) { c = EEread(i); // EEPROMの内容を読み込み if (c == 0x00) {break;} // EEPROMの内容が0x00なら終了 LCD_data(c); // EEPROMから読み込んだ文字をLCDに表示 i++; } } // ============= EEPROM 書き込み ================================ static void EEwrite(unsigned char addr, unsigned char dat) { EEPROM_WRITE(addr , dat); // EEPROMに書き込み } // ============= EEPROM 読み込み ================================ static unsigned char EEread(unsigned char addr) { return(EEPROM_READ(addr)); } // =========================== ここまで ===============================