はじめてのPICマイコン - LCD表示 2 -
前回のコードはデータ書き込み毎に一定時間
待つ様にしていたけどBusyフラグがあるので
処理完了をポーリングする方式に変更。
前はWriteのみだったのでR/W端子をGNDに落としていた。
これをRA2に接続。
プログラムは以下の様に変更
9/9追記::未使用ポートの処理を修正
// ファイル名 LCD_test2.c // 作成日 2012/09/08 // 機種 PIC16F84A // CLOCK 4MHz // コンパイラ MPLAB XC8 // //PortA bit0 ----- LCD RS pin //PortA bit1 ----- LCD E pin //PortA bit2 ----- LCD R/W pin // //PortB bit4 ----- LCD 11pin //PortB bit5 ----- LCD 12pin //PortB bit6 ----- LCD 13pin //PortB bit7 ----- LCD 14pin #include "pic.h" #include "string.h" __CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & CP_OFF ); //LCD制御ポート #define RS_P(x) PORTA = (PORTA & (0xFE)) | (x) #define E_P(x) PORTA = (PORTA & (0xFD)) | ((x) << 1) #define RW_P(x) PORTA = (PORTA & (0xFB)) | ((x) << 2) // ---------------- 1ms Wait ---------------- static void Delay_1ms() { unsigned int cnt; unsigned int i; cnt = 51; for (i=0 ; i<cnt ; i++) { NOP(); } } // ---------------- 100us Wait ---------------- static void Delay_100us() { unsigned int cnt; unsigned int i; cnt = 4; for (i=0 ; i<cnt ; i++) { NOP(); } } // ---------------- n ms Wait ---------------- static void Delay_ms(unsigned char ms) { unsigned char c; for (c=ms ; c>0 ; c--) { Delay_1ms(); } } // ---------------- LCD Busy polling ---------------- static void lcd_polling(){ unsigned char flag; RW_P(0x1); TRISB = 0xF0; do { E_P(0x1); NOP(); //このNOPがないとLCDの更新が間に合わない。(750usほど) flag = (PORTB >> 7) & 0x01; E_P(0x0); E_P(0x1);//10MHz以上で間にNOPを入れる。 E_P(0x0); }while(flag != 0x00); RW_P(0x0); TRISB = 0x0; } static void write4(unsigned char dat) { //PORTB = ( dat << 4 ); PORTB = (PORTB & 0x0F) | (( dat << 4 ) & 0xF0); E_P(0x1); E_P(0x0); //10MHz以上で間にNOPを入れる。 } static void write_LCD_IR(unsigned char dat1){ lcd_polling(); write4((dat1 >> 4) & 0x0F); write4(dat1 & 0x0F); } static void write_LCD_data(unsigned char dat1){ lcd_polling(); RS_P(0x1); write4((dat1 >> 4) & 0x0F); write4(dat1 & 0x0F); RS_P(0x0); } static void print_str(unsigned char *str){ unsigned char n; for(n = 0; n < strlen(str); n++){ write_LCD_data(str[n]); } } // ---------------- main処理 ---------------- main() { unsigned char c; TRISA = 0x0; TRISB = 0x0; // RB3:output PORTA = 0x00; PORTB = 0x00; //本処理 Delay_ms(15); write4(0x3); Delay_ms(10); write4(0x3); Delay_ms(5); write4(0x3); Delay_100us(); write4(0x2); //4bit mode Delay_100us(); write_LCD_IR(0x28); //Function Set (2行表示) write_LCD_IR(0x0C); //LCD表示ON write_LCD_IR(0x01); //ディスプレイクリア write_LCD_IR(0x06); //Entry Mode Set(カーソル右移動、文字シフトなし) write_LCD_IR(0x01); //ディスプレイクリア print_str("Hello World !!"); while(1) { NOP(); } }
なかなか動作しなかったのでロジアナ使って
原因を探ったのが以下波形
Read時にEnableを1にしてから(A)データが変化するまで(B)
LCDを買った時についていた仕様書には160nsって書いてあったけど
ここは500ns位かかっている。
場所によってバラツキがあり、データが変化する前にReadしていたっぽい。
初めはEnableを1にしてすぐにデータ取得していたが
do { E_P(0x1); //Enable=1 flag = (PORTB >> 7) & 0x01; //すぐに取得 E_P(0x0);
NOPを入れて遅らせる事でうまく動作した。
do { E_P(0x1); NOP(); //このNOPがないとLCDの更新が間に合わない。(500usほど) flag = (PORTB >> 7) & 0x01; E_P(0x0);