PICでCの練習 2007.06.12(火)〜 LessonC_26。 LCDキャラクターモジュールに"hello, world"を表示します。
著作者名: 中野 良知 作成開始: 2007.06.12(火) 最新更新: 2007.06.13(水) ビジーチェック時PORTBを全て入力に設定するように変更。
目次 1. 目的 2. ゼネラルフローチャート 3. プログラムソースコード 4. キーワード 4.1. HD44780 4.2. データ長 4.3. ビジーチェック 4.4. 関数 4.5. 2行表示 5. 実行結果 6. 実験回路 1. 目的 16桁4行のLCDキャラクターモジュールに"hello, world"を表示します。 プログラムは16桁4行用ですが、簡単な編集で16桁2行のLCDキャラクターモジュールを 使用できます。 2. ゼネラルフローチャート (main) ↓ TMR0割り込み許可(102usec) ↓ ポートの初期化 ↓ 21msec待機 ↓ LCDモジュール初期化 ↓ 文字列表示 ↓ ├←──┐ ↓ │ └───┘ (TMR0割り込み) ↓ TMR0=102usec ↓ 割り込みフラグリセット ↓ 102usecカウンタインクリメント ↓ (終了) 3. プログラムソースコード /****************************************************************************/ /* タイトル : LesssonC_26 */ /* 作者 : ioio */ /* 目的 : 16桁4行LCDキャラクターモジュール"hello, world"を表示します。 */ /* マイコン : PIC16F84A */ /* クロック : 20MHz */ /* Config : PROTECT=OFF, WDTE=OFF, XTAL */ /* Compiler : PICC Lite(V9.6)。 HI-TEC software製。 */ /* Compile : >picl -16f84a lesson.c */ /* ASM List : >picl -16f84a --ASMLIST lesson.c */ /* タブ : 半角4文字 */ /* 駆動用LSI: HD44780/LC7985 */ /****************************************************************************/ /* 変更履歴 */ /* 2007.06.10(日) 作成開始 */ /* 2007.06.12(火) ビジーチェック関数変更。PORTBのリセット。 */ /* 2007.06.13(水) ビジーチェック関数でPORTBを全て入力に変更。 */ /****************************************************************************/ /****************************************************************************/ /* ヘッダーファイル */ /* 作成開始 : 2007/06/10(日) */ /* 最新修正 : 2007/06/10(日) */ /****************************************************************************/ #include "pic.h" // デバイス関連の定義を展開 /****************************************************************************/ /* コンフィグレーション定義 */ /* 作成開始 : 2007/06/10(日) */ /* 最新修正 : 2007/06/10(日) */ /****************************************************************************/ __CONFIG(0x3FFA); // PROTECT=OFF, WDTE=OFF, HS_OSILLATOR /****************************************************************************/ /* 関数定義 */ /* 作成開始 : 2007/06/10(日) */ /* 最新修正 : 2007/06/10(日) */ /****************************************************************************/ void lcd_init( void ); void lcd_command_out( unsigned char command ); void lcd_command_write( unsigned char command ); void lcd_data_write( unsigned char data ); void lcd_strings_write( const char *c_otr, unsigned char position ); unsigned char lcd_busy_check( void ); void wait102u( unsigned int t ); /****************************************************************************/ /* 定数の定義 */ /* 作成開始 : 2007/06/10(日) */ /* 最新修正 : 2007/06/10(日) */ /****************************************************************************/ /* メッセージ */ const char helloworld[] = {"hello, world"}; const char ioio[] = {"ioio"}; const char date[] = {"2007.06.12 TUE"}; const char pic[] = {"PIC16F84A PICC-L"}; /* タイマー0 */ #define SET_TMR0 256-16 // TMR0設定=16*32*200ns=102.4us /* LCD表示行 */ #define LINE1 0x80 // 1行目先頭。COMMADE(0x80)+アドレス #define LINE2 0xC0 // 2行目先頭。COMMADE(0x80)+アドレス #define LINE3 0x90 // 3行目先頭。COMMADE(0x80)+アドレス #define LINE4 0xD0 // 4行目先頭。COMMADE(0x80)+アドレス /* LCDモジュールのデータ長 */ #define BIT_LENGTH 8 // データ長=8ビット /****************************************************************************/ /* グローバル変数定義 */ /* 作成開始 : 2007/06/10(日) */ /* 最新修正 : 2007/06/10(日) */ /****************************************************************************/ unsigned int t_cnt; // TMR0割込み回数 /****************************************************************************/ /* ビットフィールド構造体定義 */ /****************************************************************************/ /****************************************************************************/ /* ポートマップ */ /* 作成開始 : 2007/06/10(日) */ /* 最新修正 : 2007/06/10(日) */ /****************************************************************************/ /* NAME PIN NO I/O USE */ /* -----+--------+------+----------------------------------------- */ /* RA0 17 O RS(Register) */ /* RA1 18 O RW(Read/Write) */ /* RA2 1 O E(Enable) */ /* RA3 2 I - */ /* RA4 3 I - */ /* RB0 6 O data0 */ /* RB1 7 O data1 */ /* RB2 8 O data2 */ /* RB3 9 O data3 */ /* RB4 10 O data4 */ /* RB5 11 O data5 */ /* RB6 12 O data6 */ /* RB7 13 O/I data7。Busy */ /****************************************************************************/ /****************************************************************************/ void main(void) { INTCON = 0b10100000; // 割り込み制御初期化設定 OPTION = 0b11000100; // プリスケール=1/32 TMR0 = SET_TMR0; // タイマー0設定 TRISA = 0x18; // PortA b4,b3,=In、b2,b1,b0=Out TRISB = 0x00; // PortB b7,b6,b5,b4,b3,b2,b1,b0=Out PORTB = 0x00; // ポートB初期化。 PORTA = 0x00; // ポートA初期化。 wait102u(200); // 20.4msec wait lcd_init(); lcd_command_write( 0x01 ); // Clear display and cursor home lcd_strings_write( helloworld, LINE1+2); // 1行目に表示 lcd_strings_write( ioio, LINE2+6 ); // 2行目に表示 lcd_strings_write( date, LINE3+1 ); // 3行目に表示 lcd_strings_write( pic, LINE4 ); // 4行目に表示 while(1){ } } /****************************************************************************/ /* 機能 : TMR0割り込み関数(102.4usec毎) */ /* 引数 : なし */ /* 戻値 : なし */ /* 作成 : 2007.06.10(日) */ /****************************************************************************/ static void interrupt isr(void) { TMR0 = SET_TMR0; // タイマー0設定 T0IF = 0; // タイマー0オーバーフローフラグリセット t_cnt++; // TMR0割込み回数インクリメント } /****************************************************************************/ /* 機能 : LCDモジュール初期化関数 */ /* 関数 : void lcd_init( void ) */ /* 引数 : 無し */ /* 戻値 : int */ /* 作成開始 : 2007/06/10(日) */ /* 最新修正 : */ /* 概要 : LCDモジュールを初期化する */ /* 処理 : 1) Function Setを出力する。 */ /* : 2) 8ビット全部に0を出力。 */ /* : 3) 1)と2)を繰返す。 */ /* 注意 : */ /****************************************************************************/ void lcd_init( void ){ // Initial function set(interface is 8bit). 3 times lcd_command_out( 0x30 ); wait102u( 41 ); // Wait 4.2msec lcd_command_out( 0x30 ); wait102u( 1 ); // Wait 102usec lcd_command_out( 0x30 ); #if BIT_LENGTH == 8 // Function set while( lcd_busy_check() ); // wait for LCD ready lcd_command_write( 0x38 ); // 8BIT(b4),2LINE(b3),5*7DOT(b2) #else // Function set while( lcd_busy_check() ); // wait for LCD ready lcd_command_out( 0x20 ); // 4BIT(b4) lcd_command_write( 0x28 ); // 4BIT(b4),2LINE(b3),5*7DOT(b2) #endif // Display on control lcd_command_write( 0x0C ); // display on(b2),cursor off(b1) // blinking off(b0) // Entry mode set lcd_command_write( 0x06 ); // increment on(b1), display not shift(b0) } /****************************************************************************/ /* 機能 : LCDモジュールコマンド出力 */ /* 関数 : void lcd_command_out( unsigned char ) */ /* 引数 : コマンド */ /* 戻値 : なし */ /* 作成開始 : 2007/06/10(日) */ /* 最新修正 : */ /* 処理 : 1) コマンド出力 */ /* : 2) RSとRWを出力 */ /* : 3) Eを出力 */ /* 注意 : 4ビット長及び8ビット長で共通 */ /****************************************************************************/ /* LCDモジュール初期化ファンクション書き込み */ void lcd_command_out( unsigned char command ){ PORTB = command; // DB0-7 DATA OUTPUT NOP(); PORTA = 0x00; // E=0, RW=0, RS=0 NOP(); PORTA = 0x04; // E=1, RW=0, RS=0 NOP(); NOP(); PORTA = 0x00; // E=0, RW=0, RS=0 PORTB = 0x00; // DB0-7 DATA CLEAR } /****************************************************************************/ /* 機能 : LCDモジュールコマンド書き込み */ /* 関数 : void lcd_command_write( unsigned char ) */ /* 引数 : コマンド */ /* 戻値 : なし */ /* 作成開始 : 2007/06/10(日) */ /* 最新修正 : */ /* 処理 : 1) ビジーチェック */ /* : 2) コマンドを出力 */ /* 注意 : 4ビット長では、上位4ビット、下位4ビットの順で出力 */ /****************************************************************************/ void lcd_command_write( unsigned char command ){ while( lcd_busy_check() ); // wait for LCD ready #if BIT_LENGTH == 8 lcd_command_out( command ); #else lcd_command_out( command ); wait102u(1); // Wait 102usec lcd_command_out( command << 4 ); #endif } /****************************************************************************/ /* 機能 : LCDモジュールに表示キャラクターデータ書き込み */ /* 関数 : void lcd_data_write( unsigned char ) */ /* 引数 : 表示キャラクターコード */ /* 戻値 : なし */ /* 作成開始 : 2007/06/10(日) */ /* 最新修正 : */ /* 処理 : 1) ビジーチェック */ /* : 2) キャラクターコードを出力 */ /* 注意 : 4ビット長では、上位4ビット、下位4ビットの順で出力 */ /****************************************************************************/ void lcd_data_write( unsigned char data ){ #if BIT_LENGTH == 8 while( lcd_busy_check() ); // wait for LCD ready PORTB = data; // DB0-7 DATA OUTPUT NOP(); PORTA = 0x01; // E=0, RW=0, RS=1 NOP(); PORTA = 0x05; // E=1, RW=0, RS=1 NOP(); NOP(); PORTA = 0x01; // E=0, RW=0, RS=1 PORTA = 0x00; // E=0, RW=0, RS=0 #else unsigned char i; while( lcd_busy_check() ); // wait for LCD ready for( i = 0; i < 2; i++ ){ PORTB = data; // DB0-7 DATA OUTPUT NOP(); PORTA = 0x01; // E=0, RW=0, RS=1 NOP(); PORTA = 0x05; // E=1, RW=0, RS=1 NOP(); NOP(); PORTA = 0x01; // E=0, RW=0, RS=1 //PORTA = 0x00; // E=0, RW=0, RS=0 data <<= 4; wait102u(1); // Wait 102usec } #endif } /****************************************************************************/ /* 機能 : LCDモジュールに文字列データを書き込み */ /* 関数 : void lcd_strings_write( unsigned char* ) */ /* 引数 : 1) 文字列の先頭ポインタ */ /* : 2) LCDのアドレス */ /* 戻値 : なし */ /* 作成開始 : 2007/06/10(日) */ /* 最新修正 : */ /* 処理 : 1) LCDアドレス設定 */ /* : 1) ビジーチェック */ /* : 2) キャラクターコードを出力 */ /* : 3) 文字コード=0x00で終了 */ /* 注意 : 4ビット長では、上位4ビット、下位4ビットの順で出力 */ /****************************************************************************/ void lcd_strings_write( const char *c_ptr, unsigned char position ){ lcd_command_write( position ); while( *c_ptr ){ lcd_data_write( *c_ptr++ ); } } /****************************************************************************/ /* 機能 : LCDモジュールのビジーチェック */ /* 関数 : void lcd_busy_check( void ) */ /* 引数 : なし */ /* 戻値 : 0=ビジーオフ、1=ビジーオン */ /* 作成開始 : 2007.06.10(日) */ /* 最新修正 : 2007.06.12(火) 始めと終わりにPORTB = 0x00を追加。 */ /* : Eパルス幅拡張用にNOP()1箇追加。 */ /* 処理 : 1) ビジーチェック */ /* : 2) キャラクターコードを出力 */ /* : 3) キャラクターコードが0x00なら出力せずに終了 */ /* 注意 : 4ビット長では、上位4ビット、下位4ビットの順で入力 */ /* : DB7がビジーで、DB6-DB0がアドレスカウンタの値 */ /****************************************************************************/ unsigned char lcd_busy_check( void ){ #if BIT_LENGTH == 8 unsigned char rt = 0; TRISB = 0xFF; // PORTB b7,b6,b5,b4,b3,b2,b1,b0=In PORTA = 0x02; // E=0, RW=1, RS=0 NOP(); PORTA = 0x06; // E=1, RW=1, RS=0 NOP(); NOP(); NOP(); if( PORTB & 0x80 ){ // ビジーなら rt = 0x01; } PORTA = 0x02; // E=0, RW=1, RS=0 PORTA = 0x00; // E=0, RW=0, RS=0 TRISB = 0x00; // PORTB all output return rt; #else unsigned char rt = 0; unsigned char i; for( i = 0; i < 2; i++ ){ TRISB = 0xFF; // PORTB b7,b6,b5,b4,b3,b2,b1,b0=In PORTA = 0x02; // E=0, RW=1, RS=0 NOP(); PORTA = 0x06; // E=1, RW=1, RS=0 NOP(); NOP(); NOP(); if( !i ){ if( PORTB & 0x80 ){ // ビジーなら rt = 0x01; } } PORTA = 0x02; // E=0, RW=1, RS=0 NOP(); PORTA = 0x00; // E=0, RW=0, RS=0 TRISB = 0x00; // PORTB all output PORTB = 0x00; // PORTB All reset wait102u(1); // Wait 102usec } return rt; #endif } /****************************************************************************/ /* 機能 : ×102μsec待ち */ /* 関数 : void wait102u( unsigned int t ) */ /* 引数 : 待ち時間(102μsec単位) */ /* 戻値 : なし */ /* 作成開始 : 2007/06/10(日) */ /* 最新修正 : 2007/06/11(月) */ /* 処理 : 1) TMR0を初期化 */ /* : 2) 102.4usec毎のカウンタt_cntをクリア */ /* : 3) t_cntが引数値になるまで待ち */ /* 注意 : */ /****************************************************************************/ void wait102u( unsigned int t ){ TMR0 = SET_TMR0; // TMR0初期化 t_cnt = 0; // タイマー割込み回数カウンタクリア while( t_cnt < t ); // 待ち } //***************************************************************************** //***************************************************************************** 4. キーワード 4.1. HD44780 LCDモジュールは三洋電機製のDM1640を使用し、基板に搭載されているLC7985と同等 品の日立製HD44780のデータシートを参考にしました。 4.2. データ長 コンパイルスイッチでデータ長を8ビットと4ビットに変更できます。 4ビット長にすると、PORTBのb0-b3の4ビットが別な用途に使用可能です。 但し、PORTBのディレクションレジスター設定や、PORTBへのパラレルデータ出力の時 に下位4ビットと上位4ビットで互いに影響しない様にする必要があります。 /* LCDモジュールのデータ長 */ #define BIT_LENGTH 8 // データ長=8ビット ↓ #define BIT_LENGTH 4 // データ長=4ビット 4.3. ビジーチェック LCDモジュールからは、b0-b6にアドレスカウンタ値が出力され、b7にビジー状態が 出力されます。 ビジー=1、レディー=0。 PORTBの全ビットを入力に設定します。 4.4. 関数 LCDモジュールを駆動する為の関数です。 void lcd_init( void ); LCDモジュールへ初期化コマンドを3回発行します。 その後、 Function set :8ビット長、2ライン、5×7ドット Display on control:表示オン、カーソルオフ Entry mode set :インクリメントオン、シフトオフ を設定します。 void lcd_command_out( unsigned char command ); ビジーチェックを行わずにLCDモジュールのRS,RW,Eを制御してコマンドを出力 します。 lcd_init()で初期化コマンドの3回発行と、lcd_command_write()で使用します。 void lcd_command_write( unsigned char command ); LCDモジュールのビジーをチェックし、lcd_command_out()を使用してコマンド を書き込みます。 void lcd_data_write( unsigned char data ); LCDモジュールのビジーをチェックし、キャラクターコードを書き込みます。 void lcd_strings_write( const char *c_otr, unsigned char position ); LCDモジュールに文字列データを書きこみます。 文字列が格納されているROM領域のchar型配列のアドレスと、LCDの表示位置 (行+桁)を引数にします。 unsigned char lcd_busy_check( void ); LCDモジュールのビジーチェックを行います。 戻り値:1=ビジー。0=レディー。 void wait102u( unsigned int t ){ TMR0の102.4usec毎にカウントアップするt_cntを利用した遅延関数です。 引数×102.4usecの遅延を実行します。102.4usec〜6.71secまで遅延します。 4.5. 2行表示 2行表示用のLCDモジュールでは main関数の lcd_strings_write( helloworld, LINE1+2); // 1行目に表示 lcd_strings_write( ioio, LINE2+6 ); // 2行目に表示 lcd_strings_write( date, LINE3+1 ); // 3行目に表示 lcd_strings_write( pic, LINE4 ); // 4行目に表示 を lcd_strings_write( helloworld, LINE1+2); // 1行目に表示 lcd_strings_write( ioio, LINE2+6 ); // 2行目に表示 に変更します。 5. 実行結果 6. 実験回路 PIC16F84A ┌────┐14 │ VDD├──────●──────●────●─●───← +5V │ │ │ │0.1u │ │ │ │ R10K ┴ /50V ││┴│100u/16V │ │4 │ 0.1u/50V ┬ │└┬┘ │ -MCLR├──────●─┤├───●──────●──── 0V │ │ │ │ │ │ │16 ┌ ─ ─ ─ ┐ │ │ │ │ OSC1├───●─┤├──┐ │ │ │ │ │ │┴ ││ │ │ │ │ │ □ 20MHz │ │ │ │ │ │15 │┬ ││ │ │ │ │ OSC2├───●─┤├──● │ │ │ │ │ └ ─ ─ ─│┘ │ │ │ │ │5 ┌───────┘ │ │ │ │ Vss├─●───────────┘ │ │ │ │ │ │ │ │17 │ │ │ RA0├─────────────┐ │ │ │ │18 │ │ │ │ RA1├───────────┐ │ │ │ │ │1 │ │ │ │ │ RA2├─────────┐ │ │ │ │ │ │ ┏━┷━┷━┷━┓ │ │ │ │6 ┃ E RW RS ┃ │ │ │ RB0├───────┨D0 ┃ │ │ │ │7 ┃ VDD┠──● │ │ RB1├───────┨D1 ┃ │ │ │ │8 ┃ ┃ ┌┴┐│  │ RB2├───────┨D2 VD┠→│VR││ │ │9 ┃ ┃ └┬┘│ │ RB3├───────┨D3 ┃ │ │ │ │10 ┃ VSS┠──●─┘ │ RB4├───────┨D4 ┃VRは10KΩ半固定抵抗で │ │11 ┃ ┃コントラスト調整用です。 │ RB5├───────┨D5 ┃ │ │12 ┃ DM1640 ┃ │ RB6├───────┨D6 ┃ │ │13 ┃ ┃ │ RB7├───────┨D7(BUSY) ┃ │ │ ┗━━━━━━━┛ └────┘ 電源パスコン0.1u/50VのセラミックコンデンサーはVDDとVssの近くに接続します。 発振子のGNDはVssの直ぐ近くに接続します。
LessonCのTopへ
サイトのTopへ
法律条項 この資料により生じたいかなる障害や損害に対し、著者は全てを免責されるものとします。 この資料は、著作権法の下で保護され、入手先、著者、日付、法律条項を含んだ場合にのみ複製が可能です。
inserted by FC2 system