文書の表示以前のリビジョンバックリンクPDF の出力全て展開する/折り畳むODT 出力文書の先頭へ この文書は読取専用です。文書のソースを閲覧することは可能ですが、変更はできません。もし変更したい場合は管理者に連絡してください。 ====== LCDモニター(I2C対応) ====== ===== 概要 ===== LCD(Liquid Crystal Display:液晶ディスプレイ)を制御するには、少なくとも、7本のポートが必要となります。 そのため、PIC12F683(8ピン)等のようにポート数が少ないPICでは、LCDを制御することができません。 そこで、以前に、RS232Cのインターフェイスを持った、LCDモニターを製作しました。 必要なポート数は、1本のみと、とても便利なのですが、この方法では、1台のLCDへの表示しかできません。 そこで、今回は、1台のPICから、複数のLCDへメッセージを表示できる方法を実現してみました。 ===== 動作原理 ===== <PIC16F88が内蔵するSSPモジュール> Synchronous Serial Port(SSP)モジュールは、他の周辺機器やマイクロコントローラ装置とコミュニケートするのに役立つ、シリアルインタフェースです。 これらの周辺機としては、EEPROM、シフトレジスタ、ディスプレイドライバ、A/Dコンバータ、D/Aコンバータ等が考えられます。 SSPモジュールは、次の2つの動作モードを持っています。 * Serial Peripheral Interface (SPI) * Inter-Integrated Circuit (I2C) I2C(Inter-Integrated-Circuit )インターフェースは、同期式のシリアル通信の規格で、非同期式シリアル通信(RS-232C等)に比べて、 * 高速通信 * 複数スレーブ(Slave)接続 等の特長があり、今回の仕様には打って付けです。 接続できるスレーブの数は、0x00~0xFF迄の偶数の番号のアドレスが指定できるので、最大128台となります。 但し、予約されているアドレス(下表参照)がありますので、この分が使えないことになります。 <I2Cモード時のSSPブロックダイアグラム> {{:imgpaste:202004:htmikan-20200430-072751.png}} <接続例> {{:imgpaste:202004:htmikan-20200430-072814.png?500}} <予約されているアドレス> {{:imgpaste:202004:htmikan-20200430-072825.png?400}} <I2Cバスを応用した2つの製品例>※「I2Cバス仕 様 書バージョン 2.1」より (a) 高性能高集積テレビ (b) DECTコードレス電話基地局 {{:imgpaste:202004:htmikan-20200430-072840.png?500}} <今回製作した、LCDモニターの仕組み> マスター側から見ると、スレーブのメモリ(32バイト)にデータをセットするだけです。 スレーブ側では、メモリにセットされたデータを、LCDに表示させます。 * 32バイトの前半の16バイトが1行目のデータになります。 * 32バイトの後半の16バイトが2行目のデータになります。 {{:imgpaste:202004:htmikan-20200430-072853.png?500}} ===== 回路図 ===== {{:imgpaste:202004:htmikan-20200430-072909.png?500}} ===== ソースコード ===== <code c LcdMonitor_I2C.c> //********************************************************************** /* <LCDモニター(I2C対応)> */ //********************************************************************** #define LED PORTA.F4 #define SW_ADDR1 PORTB.F2 #define SW_ADDR2 PORTB.F3 #define ADDR_BASE 0xB0 #define ON 1 #define OFF 0 #define DATA_SIZE 32 //********************************************************************** static unsigned short data[DATA_SIZE], pnt, flg, tmp, stat; //********************************************************************** void i2c_Write(unsigned short dat) { while (SSPSTAT.BF == 1) ; while (1) { SSPCON.WCOL = 0; SSPBUF = dat; if (SSPCON.WCOL == 1) continue; // SSPCON.CKP = 1; return; } } //********************************************************************** void i2c_Handler() { stat = SSPSTAT; tmp = SSPSTAT & 0b00101101; // if (tmp == 0b00001001) { //書き込みモード、デバイスアドレス tmp = SSPBUF; flg = 0; pnt = 0; return; } if (tmp == 0b00101001) { //書き込みモード、データ if (flg == 0) { pnt = SSPBUF; flg = 1; return; } if (flg == 1) { data[pnt] = SSPBUF; pnt++; return; } } if (tmp == 0b00001100) { //読み込みモード、デバイスアドレス i2c_Write(data[pnt]); pnt++; return; } if (tmp == 0b00101100) { //読み込みモード、データ(ACK) i2c_Write(data[pnt]); pnt++; return; } if (tmp == 0b00101000) { //読み込みモード、データ(NO_ACK) tmp = SSPBUF; SSPCON = 0x36; return; } LED = ON; Delay_ms(100); LED = OFF; } //********************************************************************** void interrupt() { if (PIR1.SSPIF == 1) { PIR1.SSPIF = 0; // LED = ON; i2c_Handler(); LED = OFF; } } //********************************************************************** void ByteToBit(unsigned short number, char *output) { short cnt; // for (cnt = 0; cnt < 8; cnt++) { if ((number & 0x80) != 0) output[cnt] = '1'; else output[cnt] = '0'; number <<= 1; } output[8] = 0x00; } //********************************************************************** void main() { unsigned short cnt, buf[10], mode; // CMCON = 0b00000111; //コンパレータは使用しない。 ANSEL = 0b00000000; //A/Dコンバータは使用しない。 OSCCON = 0b01110000; //クロックは内臓8MHzを使用する。 TRISA = 0b00101100; //PORTAを設定する。 TRISB = 0b00011111; //PORTBを設定する。 OPTION_REG.NOT_RBPU = 0; //PORTBをプルアップする。 //I2Cを設定する。 SSPSTAT.SMP = 1; SSPSTAT.CKE = 1; SSPCON.WCOL = 0; SSPCON.SSPOV = 0; SSPCON.SSPEN = 1; SSPCON.CKP = 1; SSPCON.SSPM0 = 0; SSPCON.SSPM1 = 1; SSPCON.SSPM2 = 1; SSPCON.SSPM3 = 0; SSPADD = ADDR_BASE + ((SW_ADDR2 == 1) ? 4 : 0) + ((SW_ADDR1 == 1) ? 2 : 0); PIE1.SSPIE = 1; PIR1.SSPIF = 0; // LED = OFF; pnt = 0; flg = 0; for (cnt = 0; cnt < 32; cnt++) { data[cnt] = ' '; } //LCDを初期化する。 Lcd_Custom_Config(&PORTA,1,0,7,6,&PORTB,5,6,7); Lcd_Custom_Cmd(LCD_CURSOR_OFF); Lcd_Custom_Cmd(LCD_CLEAR); // for (cnt = 0; cnt < 16; cnt++) { Lcd_Custom_Chr(1, cnt + 1, 0xFF); Delay_ms(50); } for (cnt = 0; cnt < 16; cnt++) { Lcd_Custom_Chr(2, cnt + 1, 0xFF); Delay_ms(50); } // 割り込み(全体)の設定 INTCON.PEIE = 1; INTCON.GIE = 1; // while (1) { for (cnt = 0; cnt < 16; cnt++) { Lcd_Custom_Chr(1, cnt + 1, data[cnt]); } for (cnt = 0; cnt < 16; cnt++) { Lcd_Custom_Chr(2, cnt + 1, data[cnt + 16]); } } } //********************************************************************** </code> <参考> ※テスト用(PIC12F683)のプログラムです。 <code c LcdMonitor_I2C_master.c> //********************************************************************** /* 『LCDモニターのテストデータ送信用(マスター)』 */ //********************************************************************** #define SW GPIO.F3 #define LED GPIO.F2 #define ON 1 #define OFF 0 #define ACK 1 #define NO_ACK 0 //********************************************************************** void SwitchONcheck() { while (Button(&GPIO, 3, 1, 0) == 0) ; while (Button(&GPIO, 3, 1, 1) == 0) ; } //********************************************************************** void main() { unsigned short cnt, dat; // CMCON0 = 0b00000111; ANSEL.ANS0 = 0; ANSEL.ANS1 = 0; ANSEL.ANS2 = 0; ANSEL.ANS3 = 0; ADCON0.VCFG = 0; TRISIO = 0b00001011; OSCCON = 0b01110000; // for (cnt = 0; cnt < 10; cnt++) { LED = ON; Delay_ms(50); LED = OFF; Delay_ms(50); } // Soft_I2C_Config(&GPIO, 4, 5); // SDA, SCL // while (1) { SwitchONcheck(); // Soft_I2C_Start(); Soft_I2C_Write(0xB4); Soft_I2C_Write(0x00); for (cnt = 0; cnt < 32; cnt++) { Soft_I2C_Write('0' + cnt); } Soft_I2C_Stop(); // Soft_I2C_Start(); Soft_I2C_Write(0xB4); Soft_I2C_Write(0x00); Soft_I2C_Start(); Soft_I2C_Write(0xB5); for (cnt = 0; cnt < 32; cnt++) { if (cnt < 31) dat = Soft_I2C_Read(ACK); else dat = Soft_I2C_Read(NO_ACK); // if (dat != ('0' + cnt)) { LED = ON; Delay_ms(1000); LED = OFF; } } Soft_I2C_Stop(); // for (cnt = 0; cnt < 10; cnt++) { LED = ON; Delay_ms(50); LED = OFF; Delay_ms(50); } // Soft_I2C_Start(); Soft_I2C_Write(0xB6); Soft_I2C_Write(0x00); for (cnt = 0; cnt < 32; cnt++) { Soft_I2C_Write('P' + cnt); } Soft_I2C_Stop(); // Delay_ms(1000); // Soft_I2C_Start(); Soft_I2C_Write(0xB6); Soft_I2C_Write(0x00); Soft_I2C_Start(); Soft_I2C_Write(0xB7); for (cnt = 0; cnt < 32; cnt++) { if (cnt < 31) dat = Soft_I2C_Read(ACK); else dat = Soft_I2C_Read(NO_ACK); // if (dat != ('P' + cnt)) { LED = ON; Delay_ms(1000); LED = OFF; } } Soft_I2C_Stop(); // for (cnt = 0; cnt < 10; cnt++) { LED = ON; Delay_ms(50); LED = OFF; Delay_ms(50); } } } //********************************************************************** </code> ===== 動作確認 ===== 小さなブレッドボードなので、LCDを1台接続し、手動で結線をし直して、動作を確認しました。 {{:imgpaste:202004:htmikan-20200430-073120.png?500}} 左側から、PIC12F683(LCD表示データ送信用)、PIC16F88(アドレス=0xB4)、PIC16F88(アドレス=0xB6) {{:imgpaste:202004:htmikan-20200430-073131.png?500}} 左側のPIC16F88(アドレス=0xB4)にLCDを接続し、表示データを送信したところです。 {{:imgpaste:202004:htmikan-20200430-073143.png}}{{:imgpaste:202004:htmikan-20200430-073146.png}} 右側のPIC16F88(アドレス=0xB6)にLCDを接続し、表示データを送信したところです。 {{:imgpaste:202004:htmikan-20200430-073229.png}}{{:imgpaste:202004:htmikan-20200430-073232.png}} 如何ですか? 1台のPICから、複数のLCDに対して、表示メッセージを送信することができるので、電子工作の範囲が広がりそうですね! 今回は、最大4台のLCDを接続できるようにしましたが、PIC16F88のポートには、まだ余裕がありますので、プログラムを少し修正するだけで、8台、16台と増やすことができます。 <callout type="warning" title="著作権表示 copyright notice"> このページは稲崎様の閉鎖したHPのコピーで、著作権は稲崎様にあります。[[elechobby:picdic:picdic|詳細]] This page is a copy of Mr. Inasaki's closed website, and the copyright is held by him.[[elechobby:picdic:picdic|Details]] </callout> elechobby/picdic/pic16f88/94.txt 最終更新: 2025/10/17 14:29by 127.0.0.1