文書の表示以前のリビジョンバックリンクPDF の出力全て展開する/折り畳むODT 出力文書の先頭へ この文書は読取専用です。文書のソースを閲覧することは可能ですが、変更はできません。もし変更したい場合は管理者に連絡してください。 ====== KeyPad(4×4)ユニット(I2C対応) ====== ===== 概要 ===== 前回製作した、KeyPad(4×4)を、I2C対応に改良し、汎用的に使えるようにしました。 ===== 動作原理 ===== I2Cのスレーブ機能としての、基本的な構造は、前回製作した、LCDモニター(I2C対応)と同じです。 KeyPadの制御方式(キーマトリクススキャン)は、前回製作した、KeyPad(4×4)と同じです。 <メモリ構造> KeyPadの押下されたキーのデータを設定するために、1バイトのメモリを使用します。 【0x00】押下キーデータ * 押下時には、"1234567890ABCD*#"の何れかがセットされます。 * 非押下時には、0x00がセットされます。 * 本ユニットが、一定時間(200msec)経過後に自動的に0x00をセットする方法(SW_MODE(0)) * マスターからの操作によって、0x00をセットする方法(SW_MODE(1)) <処理の流れ> - KeyPadをキーマトリクススキャンする。(何れかのキーが押下されるまで繰り返す) - 押下されたキーの内容を、メモリ【0x00】にセットする。 - SW_MODE(1)の場合には、1.へ戻る。 - SW_MODE(0)の場合には、200msec後に、メモリ【0x00】に0x00をセットする。 <マスター側から、本ユニットの押下キーデータを、取得する方法> - 【0x00】押下キーデータの内容を読み込む。\\ <code> Soft_I2C_Start(); Soft_I2C_Write(0xF0); Soft_I2C_Write(0x00); Soft_I2C_Start(); Soft_I2C_Write(0xF1); kp = Soft_I2C_Read(NO_ACK);//押下キーデータを読み込んで、kpにセットする。 Soft_I2C_Stop(); </code> - キーが押されているかを確認する。 * kpが、0x00であれば、1.へ戻る。 * kpが、0x00以外であれば、キーが押されているので、3.へ。 - 【0x00】押下キーデータの内容をクリアする。\\ <code> Soft_I2C_Start(); Soft_I2C_Write(0xF0); Soft_I2C_Write(0x00); Soft_I2C_Write(0x00);//押下キーデータを、0x00でクリアする。 Soft_I2C_Stop(); </code> ===== 回路図 ===== {{:imgpaste:202004:htmikan-20200430-080935.png}} ===== ソースコード ===== <code c KeyPad_i2c.c> //********************************************************************** /* <KeyPad(4×4)(I2C対応)> */ //********************************************************************** #define LED PORTB.F5 #define SW_ADDR1 PORTB.F0 #define SW_ADDR2 PORTB.F2 #define SW_ADDR3 PORTB.F3 #define SW_MODE PORTB.F6 #define ADDR_BASE 0xF0 #define ON 0 #define OFF 1 #define DATA_SIZE 1 //********************************************************************** 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; } } //********************************************************************** static unsigned short i2c_memory[DATA_SIZE], i2c_pnt, i2c_flg, i2c_tmp; //********************************************************************** void i2c_Handler() { if (SSPSTAT.P == 1) //ストップビットを検出しても何もしない。 asm nop; if (SSPSTAT.S == 1) //スタートビットを検出しても何もしない。 asm nop; // i2c_tmp = SSPSTAT & 0b00101101; // if (i2c_tmp == 0b00001001) { //書き込みモード、デバイスアドレス i2c_tmp = SSPBUF; i2c_flg = 0; i2c_pnt = 0; return; } if (i2c_tmp == 0b00101001) { //書き込みモード、データ if (i2c_flg == 0) { i2c_pnt = SSPBUF; i2c_flg = 1; return; } if (i2c_flg == 1) { i2c_memory[i2c_pnt] = SSPBUF; i2c_pnt++; return; } } if (i2c_tmp == 0b00001100) { //読み込みモード、デバイスアドレス i2c_Write(i2c_memory[i2c_pnt]); i2c_pnt++; return; } if (i2c_tmp == 0b00101100) { //読み込みモード、データ(ACK) i2c_Write(i2c_memory[i2c_pnt]); i2c_pnt++; return; } if (i2c_tmp == 0b00101000) { //読み込みモード、データ(NO_ACK) i2c_tmp = SSPBUF; SSPCON = 0b00111110; return; } } //********************************************************************** void interrupt() { if (PIR1.SSPIF == 1) { PIR1.SSPIF = 0; // LED = ON; i2c_Handler(); LED = OFF; } } //********************************************************************** unsigned short keyPad_keySearch() { unsigned short kp; // kp = 0x00; // PORTA.F6 = 0; switch (PORTA & 0b00111100) { case 0b00111000: kp = 'D'; break; case 0b00110100: kp = 'C'; break; case 0b00101100: kp = 'B'; break; case 0b00011100: kp = 'A'; break; } PORTA.F6 = 1; // PORTA.F7 = 0; switch (PORTA & 0b00111100) { case 0b00111000: kp = '#'; break; case 0b00110100: kp = '9'; break; case 0b00101100: kp = '6'; break; case 0b00011100: kp = '3'; break; } PORTA.F7 = 1; // PORTA.F0 = 0; switch (PORTA & 0b00111100) { case 0b00111000: kp = '0'; break; case 0b00110100: kp = '8'; break; case 0b00101100: kp = '5'; break; case 0b00011100: kp = '2'; break; } PORTA.F0 = 1; // PORTA.F1 = 0; switch (PORTA & 0b00111100) { case 0b00111000: kp = '*'; break; case 0b00110100: kp = '7'; break; case 0b00101100: kp = '4'; break; case 0b00011100: kp = '1'; break; } PORTA.F1 = 1; // return (kp); } //********************************************************************** unsigned short keyPad_GetKey() { unsigned short newkp, oldkp, cnt; // oldkp = 0x00; // for (cnt = 0; cnt < 10; cnt++) { newkp = keyPad_keySearch(); if ((newkp == 0x00) || (newkp != oldkp)) cnt = 0; oldkp = newkp; Delay_ms(5); } // for (cnt = 0; cnt < 10; cnt++) { if (keyPad_keySearch() != 0x00) cnt = 0; Delay_ms(5); } // return (newkp); } //********************************************************************** static unsigned short Luminance[10] = {255, 128, 64, 32, 16, 8, 4, 2, 1, 0}; void main() { unsigned short cnt; // CMCON = 0b00000111; //コンパレータは使用しない。 ANSEL = 0b00000000; //A/Dコンバータは使用しない。 OSCCON = 0b01110000; //クロックは内臓8MHzを使用する。 TRISA = 0b00111100; //PORTAを設定する。 TRISB = 0b01011111; //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 = 1; SSPADD = ADDR_BASE + ((SW_ADDR3 == 1) ? 8 : 0) + ((SW_ADDR2 == 1) ? 4 : 0) + ((SW_ADDR1 == 1) ? 2 : 0); PIE1.SSPIE = 1; PIR1.SSPIF = 0; // // PORTA.F6 = 1; PORTA.F7 = 1; PORTA.F0 = 1; PORTA.F1 = 1; // LED = OFF; i2c_pnt = 0; i2c_flg = 0; i2c_memory[0] = 0x00; // for (cnt = 0; cnt < 10; cnt++) { LED = ON; Delay_ms(50); LED = OFF; Delay_ms(50); } // 割り込み(全体)の設定 INTCON.PEIE = 1; INTCON.GIE = 1; // while (1) { i2c_memory[0] = keyPad_GetKey(); // if (SW_MODE == 0) { Delay_ms(200); i2c_memory[0] = 0x00; } } } //********************************************************************** </code> <参考> ※テストデータ送信用(I2Cマスター/PIC16F88)のプログラムです。 <code c keyPad_i2c_master.c> //********************************************************************** /* <KeyPad(4×4)のテストデータ送信用(マスター)> */ //********************************************************************** #define ACK 1 #define NO_ACK 0 //********************************************************************** void SwitchONcheck() { while (Button(&PORTB, 3, 1, 0) == 0) ; while (Button(&PORTB, 3, 1, 1) == 0) ; } //********************************************************************** void main() { unsigned short kp, l_cnt, c_cnt, cnt; // OSCCON = 0b01110000; // クロックを8Mhzに設定する。 ANSEL = 0b00000000; // A/D変換は使用しない。 TRISA = 0b00110000; TRISB = 0b00001111; // 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); } Lcd_Custom_Cmd(LCD_CLEAR); // l_cnt = 1; c_cnt = 1; // Soft_I2C_Config(&PORTA, 2, 3); // SDA, SCL // while (1) { // Soft_I2C_Start(); Soft_I2C_Write(0xF0); Soft_I2C_Write(0x00); Soft_I2C_Start(); Soft_I2C_Write(0xF1); kp = Soft_I2C_Read(NO_ACK); Soft_I2C_Stop(); // if (kp == 0x00) { Delay_ms(100); continue; } // Soft_I2C_Start(); Soft_I2C_Write(0xF0); Soft_I2C_Write(0x00); Soft_I2C_Write(0x00); Soft_I2C_Stop(); // Lcd_Custom_Chr(l_cnt, c_cnt, kp); c_cnt++; if (c_cnt == 17) { c_cnt = 1; l_cnt++; if (l_cnt == 3) l_cnt = 1; } Delay_ms(100); } } //********************************************************************** </code> ===== 動作確認 ===== {{:imgpaste:202004:htmikan-20200430-081126.png?500}} 左側が、スレーブ(本ユニット)、右側が、マスター側です。 {{:imgpaste:202004:htmikan-20200430-081142.png?500}} KeyPadのスイッチを、横順、縦順で押していくと、その結果が、LCDに順次表示されていきます。 {{:imgpaste:202004:htmikan-20200430-081154.png}}{{:imgpaste:202004:htmikan-20200430-081159.png}} <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/100.txt 最終更新: 2025/10/17 14:29by 127.0.0.1