I2C接続LCDをPICマイコンで使用する方法
今まではArduinoを使ってI2C接続LCDを動かしました。今回はPICマイコンで同様のことを行っていきたいと思います。
PICマイコンの場合、I2C通信の開始、終了の条件や1バイトのデータを出力するプログラムを自分で作成しなければなりません。できるだけArduinoと同じような使い方ができるプログラムを作っていきたいと思います。
- 使用する部品と配線
- I2C通信スタート条件の関数
- 1バイトのデータを出力する関数
- I2C通信ストップ条件の関数
- data及びcommand送信する関数
- サンプルプログラム
使用する部品と配線
今回のPICでI2C接続LCDを動かす実験では
・マイコン・・・PIC12F1822
・LCD・・・AE-AQM1602A(KIT)
を使用しました。ともに秋月電子で購入しました。
I2C通信スタート条件の関数
SCLが「HIGH」の時にSDAが「LOW」になると通信開始になります。もともとSCL、SDAはともにプルアップ抵抗によって「HIGH」になっています。今回作成したスタート条件の関数では「SDA = 0」にしてI2C通信スタートするとともに、「TRISA2 = 0」にしてRA2ピン(SDAピン)を出力にし、後に行うデータ送信の準備をします。
1 2 3 4 |
void start(void){ SDA = 0; TRISA2 = 0; //SDAの設定を出力にする } |
1バイトのデータを出力する関数
送信する1バイト(8bit)のデータは1bitずつ出力する必要があります。今回作成した関数では
- for文で8回処理を繰り返す
- if文で指定ビットの「1 or 0」を確認し、SDLに「HIGH or LOW」を出力
- 「BitPos = BitPos >> 1」で次のビットに移動
を組み合わせて8bitの送信を行います。
for文の処理が終わるとACKの確認準備をします。この時、スタート条件の関数でTRISA2は出力に設定されているので入力へ変更します。ACK信号(受信側が「LOW」を出力)の確認を行い、問題なければ1バイト(8bit)のデータ送信は終了となります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
unsigned char i2cTxData(unsigned char data){ int i; unsigned char BitPos, ACK; TRISA2 = 0; //SDAの設定を出力にする BitPos = 0b10000000; //bit位置初期値 for(i = 0; i < 8; i++){ //SCLがLOWになるごとに1bitずつデータをSDAに出力 SCL = 0; if((data & BitPos)!= 0){ //ビットのHIGH or LOWを確認 SDA = 1; //SCLにHIGHを出力 }else{ SDA = 0; //SCLにLOWを出力 } BitPos = BitPos >> 1; //次のbitに移動 SCL = 1; } //ACK チェック SCL = 0; //SCLがLOWにする TRISA2 = 1; //SDAの設定を入力にする __delay_us(2); SCL = 1; //クロックをHIGHに戻す __delay_us(2); ACK = SDA; //ACKの確認 return(ACK); } |
I2C通信ストップ条件の関数
SCLが「HIGH」の間にSDAが「HIGH」になることで通信終了となります。今回作成したストップ条件の関数では、最後のACK確認後、SCLとSDAともに「LOW」にするとともに、ACK確認用に入力の設定になっていたTRISA2を出力に戻します。その後、SCLとSDAを時間差でともに「HIGH」にすることでI2C通信を終了させます。
1 2 3 4 5 6 7 8 9 10 |
void stop(void){ SCL=0; //ACKを確認したら、SCLとSDAをLOWにする __delay_us(1); SDA=0; TRISA2 = 0; //SDAの設定を出力にする SCL=1; //SCLがHIGHにする __delay_us(1); SDA=1; //SCLがHIGHの時、SDAをHIGHにすると通信ストップ __delay_us(10); } |
data及びcommand送信する関数
LCDに表示するデータを「data」、LCDの制御コマンドを「command」として関数を作成しました。AE-AQM1602A のデータシートにあったプログラムを参考にしています。I2Cの通信フォーマットの通り、スレーブアドレスバイト、制御バイト、データバイトの順番にデータを送信する関数になっています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
//*****I2Cでdata送信*************************************** void Writedata(unsigned char data){ start(); i2cTxData(0x7C); // アドレス送信 i2cTxData(0x40); // 制御コード送信 i2cTxData(data); // データ送信 stop(); __delay_ms(1); } //*****I2Cでcommand送信*************************************** void Writecommand(unsigned char command){ start(); i2cTxData(0x7C); // アドレス送信 i2cTxData(0x00); // 制御コード送信 i2cTxData(command); // コマンド送信 stop(); __delay_ms(20); } |
サンプルプログラム
1.文字を点滅させる
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 |
//12F1822_I2C_LCD_blinking // PIC12F1822 コンフィグレーション設定 // CONFIG1 #pragma config FOSC = INTOSC // 発振回路選択 PIC内部発振回路を使用 #pragma config WDTE = OFF // ウォッチドッグタイマーの設定 #pragma config PWRTE = ON // 電源や周辺回路が安定するまでの一定時間、動作を停止するパワーアップタイマーのモードを設定 #pragma config MCLRE = OFF // MCLR端子を、リセット信号の入力用として機能させるかどうかを設定 #pragma config CP = OFF // コード保護の設定 #pragma config CPD = OFF // データコード保護の設定 #pragma config BOREN = ON // 電源電圧が一定電圧より下がるとリセットするブラウンアウトリセットの設定 #pragma config CLKOUTEN = OFF // CLKOUT端子の動作モードの設定 #pragma config IESO = OFF // 電源投入直後、外部クロックが安定するまでの時間、内部クロックを使う機能の設定 #pragma config FCMEN = OFF // 外部クロック監視機能「フェールセーフクロックモニター」を使い、外部クロックが停止しても、内部クロックで動作させるかのを設定 // CONFIG2 #pragma config WRT = OFF // PICはプログラム自身がメモリー領域への書き込みを行うことで、プログラムの書き換えが行えます。この書き込みを許可するかの設定 #pragma config PLLEN = OFF // PLL(Phase Locked Loop)回路によって、クロックの周波数を4倍にする「4倍クロックモード」を使用するかの設定 #pragma config STVREN = ON // 関数の引数や戻りアドレスを一時的に保存するスタック領域が、オーバーフローやアンダーフローしたときにリセットする機能を使用するかの設定 #pragma config BORV = LO // BORENで設定するブラウンアウトリセットが、動作する電源電圧を設定 #include <xc.h> #define _XTAL_FREQ 8000000 // クロック8MHzを指定 __delayの指定に必要 //*****スタート条件*************************************** void start(void){ SDA = 0; TRISA2 = 0; //SDAの設定を出力にする } //*****ストップ条件*************************************** void stop(void){ SCL=0; //ACKを確認したら、SCLとSDAをLOWにする __delay_us(1); SDA=0; TRISA2 = 0; //SDAの設定を出力にする SCL=1; //SCLがHIGHにする __delay_us(1); SDA=1; //SCLがHIGHの時、SDAをHIGHにすると通信ストップ __delay_us(10); } //*****I2Cで1バイト出力*********************************** unsigned char i2cTxData(unsigned char data){ int i; unsigned char BitPos, ACK; TRISA2 = 0; //SDAの設定を出力にする BitPos = 0b10000000; //bit位置初期値 for(i = 0; i < 8; i++){ //SCLがLOWになるごとに1bitずつデータをSDAに出力 SCL = 0; if((data & BitPos)!= 0){ //ビットのHIGH or LOWを確認 SDA = 1; //SCLにHIGHを出力 }else{ SDA = 0; //SCLにLOWを出力 } BitPos = BitPos >> 1; //次のbitに移動 SCL = 1; } //ACK チェック SCL = 0; //SCLがLOWにする TRISA2 = 1; //SDAの設定を入力にする __delay_us(2); SCL = 1; //クロックをHIGHに戻す __delay_us(2); ACK = SDA; //ACKの確認 return(ACK); } //*****I2Cでdata送信*************************************** void Writedata(unsigned char data){ start(); i2cTxData(0x7C); // アドレス送信 i2cTxData(0x40); // 制御コード送信 i2cTxData(data); // データ送信 stop(); __delay_ms(1); } //*****I2Cでcommand送信*************************************** void Writecommand(unsigned char command){ start(); i2cTxData(0x7C); // アドレス送信 i2cTxData(0x00); // 制御コード送信 i2cTxData(command); // コマンド送信 stop(); __delay_ms(20); } //*****LCD初期化******************************************** void LCD_int(void){ __delay_ms(100); Writecommand(0x39); // Function Set(機能設定) 8bitモード,2桁表示,通常フォント,コマンドグループ2の設定へ移行 Writecommand(0x14); // Internal OSC frequency(内部クロック周波数) 内部発振回路設定 通常0 , 内部発振回路周波数 通常100 Writecommand(0x52); // Power/ICONControl/Contrast set(パワー/アイコン制御/コントラスト設定) アイコン表示OFF,ブースタ回路OFF(電源5V),コントラスト設定↓ Writecommand(0x70); // Contrast set(コントラスト設定) C5~C0:100000 Writecommand(0x6C); // Follower control(フォロワ回路制御)コントラストを制御する電子回路(オペアンプ増幅回路)の設定 回路適用 通常は1,増幅度 通常は100 Writecommand(0x0C); // Display ON/OFF Control(表示ON/OFFコントロール) ディスプレイ電源ON,カーソル表示OFF,ブリンクOFF Writecommand(0x01); // Clear Display(表示をクリア) Writecommand(0x02); // Return Home(表示シフトを初期位置に戻る) } void main(void){ // PICマイコン設定 OSCCON = 0b01110010; // 内部クロック周波数を8MHzに設定 ANSELA = 0x00; // 全ピン デジタルI/Oピンとして設定 TRISA = 0x00; //全てのピンを出力 LCD_int(); // LCDを初期化 //「Word・ワード」を入力 unsigned char moji[]="\x57\x6F\x72\x64\x0D\xDC\x2D\xC4\xDE"; for (int i=0; i < 9; i++){ Writedata(moji[i]); } __delay_ms(500); Writecommand(0x01); // Clear Display(表示をクリア) __delay_ms(500); return; } |
2.左右の行き来を3回
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 |
//12F1822_I2C_LCD_round_trip_three_time // PIC12F1822 コンフィグレーション設定 // CONFIG1 #pragma config FOSC = INTOSC // 発振回路選択 PIC内部発振回路を使用 #pragma config WDTE = OFF // ウォッチドッグタイマーの設定 #pragma config PWRTE = ON // 電源や周辺回路が安定するまでの一定時間、動作を停止するパワーアップタイマーのモードを設定 #pragma config MCLRE = OFF // MCLR端子を、リセット信号の入力用として機能させるかどうかを設定 #pragma config CP = OFF // コード保護の設定 #pragma config CPD = OFF // データコード保護の設定 #pragma config BOREN = ON // 電源電圧が一定電圧より下がるとリセットするブラウンアウトリセットの設定 #pragma config CLKOUTEN = OFF // CLKOUT端子の動作モードの設定 #pragma config IESO = OFF // 電源投入直後、外部クロックが安定するまでの時間、内部クロックを使う機能の設定 #pragma config FCMEN = OFF // 外部クロック監視機能「フェールセーフクロックモニター」を使い、外部クロックが停止しても、内部クロックで動作させるかのを設定 // CONFIG2 #pragma config WRT = OFF // PICはプログラム自身がメモリー領域への書き込みを行うことで、プログラムの書き換えが行えます。この書き込みを許可するかの設定 #pragma config PLLEN = OFF // PLL(Phase Locked Loop)回路によって、クロックの周波数を4倍にする「4倍クロックモード」を使用するかの設定 #pragma config STVREN = ON // 関数の引数や戻りアドレスを一時的に保存するスタック領域が、オーバーフローやアンダーフローしたときにリセットする機能を使用するかの設定 #pragma config BORV = LO // BORENで設定するブラウンアウトリセットが、動作する電源電圧を設定 #include <xc.h> #define _XTAL_FREQ 8000000 // クロック8MHzを指定 __delayの指定に必要 //*****スタート条件*************************************** void start(void){ SDA = 0; TRISA2 = 0; //SDAの設定を出力にする } //*****ストップ条件*************************************** void stop(void){ SCL=0; //ACKを確認したら、SCLとSDAをLOWにする __delay_us(1); SDA=0; TRISA2 = 0; //SDAの設定を出力にする SCL=1; //SCLがHIGHにする __delay_us(1); SDA=1; //SCLがHIGHの時、SDAをHIGHにすると通信ストップ __delay_us(10); } //*****I2Cで1バイト出力*********************************** unsigned char i2cTxData(unsigned char data){ int i; unsigned char BitPos, ACK; TRISA2 = 0; //SDAの設定を出力にする BitPos = 0b10000000; //bit位置初期値 for(i = 0; i < 8; i++){ //SCLがLOWになるごとに1bitずつデータをSDAに出力 SCL = 0; if((data & BitPos)!= 0){ //ビットのHIGH or LOWを確認 SDA = 1; //SCLにHIGHを出力 }else{ SDA = 0; //SCLにLOWを出力 } BitPos = BitPos >> 1; //次のbitに移動 SCL = 1; } //ACK チェック SCL = 0; //SCLがLOWにする TRISA2 = 1; //SDAの設定を入力にする __delay_us(2); SCL = 1; //クロックをHIGHに戻す __delay_us(2); ACK = SDA; //ACKの確認 return(ACK); } //*****I2Cでdata送信*************************************** void Writedata(unsigned char data){ start(); i2cTxData(0x7C); // アドレス送信 i2cTxData(0x40); // 制御コード送信 i2cTxData(data); // データ送信 stop(); __delay_ms(1); } //*****I2Cでcommand送信*************************************** void Writecommand(unsigned char command){ start(); i2cTxData(0x7C); // アドレス送信 i2cTxData(0x00); // 制御コード送信 i2cTxData(command); // コマンド送信 stop(); __delay_ms(20); } //*****LCD初期化******************************************** void LCD_int(void){ __delay_ms(100); Writecommand(0x39); // Function Set(機能設定) 8bitモード,2桁表示,通常フォント,コマンドグループ2の設定へ移行 Writecommand(0x14); // Internal OSC frequency(内部クロック周波数) 内部発振回路設定 通常0 , 内部発振回路周波数 通常100 Writecommand(0x52); // Power/ICONControl/Contrast set(パワー/アイコン制御/コントラスト設定) アイコン表示OFF,ブースタ回路OFF(電源5V),コントラスト設定↓ Writecommand(0x70); // Contrast set(コントラスト設定) C5~C0:100000 Writecommand(0x6C); // Follower control(フォロワ回路制御)コントラストを制御する電子回路(オペアンプ増幅回路)の設定 回路適用 通常は1,増幅度 通常は100 Writecommand(0x0C); // Display ON/OFF Control(表示ON/OFFコントロール) ディスプレイ電源ON,カーソル表示OFF,ブリンクOFF Writecommand(0x01); // Clear Display(表示をクリア) Writecommand(0x02); // Return Home(表示シフトを初期位置に戻る) } void main(void){ // PICマイコン設定 OSCCON = 0b01110010; // 内部クロック周波数を8MHzに設定 ANSELA = 0x00; // 全ピン デジタルI/Oピンとして設定 TRISA = 0x00; //全てのピンを出力 LCD_int(); // LCDを初期化 Writecommand(0x80+0x10); //カーソル座標「10」に設定 Writecommand(0b00000111); //04 Entry Mode Set(エントリ・モード設定) カーソル移動右,表示シフトする //「Word・ワード」を入力 unsigned char moji[]="Word"; for (int i=0; i < 4; i++){ Writedata(moji[i]); __delay_ms(300); } for(int j = 0; j < 3; j++) { Writecommand(0x80+0x14);//カーソル座標「14」に設定 Writecommand(0b00000111);//04 Entry Mode Set(エントリ・モード設定) カーソル移動右,表示シフトする //「スペース」を12回入力 for(int r = 0; r < 12; r++) { Writedata(' '); __delay_ms(300); } Writecommand(0x80+0x0F);//カーソル座標「0F」に設定 Writecommand(0b00000101);//04 Entry Mode Set(エントリ・モード設定) カーソル移動左,表示シフトする //「スペース」を12回入力 for(int l = 0; l < 12; l++) { Writedata(' '); __delay_ms(300); } } __delay_ms(500); return; } |
参考資料
- 8ピンPICマイコンの使い方がよくわかる本
- AE-AQM1602A データシート
- PIC12F1822データシート