PIC16F1827を使用したキャパシティブセンシングのi2cスレーブのコードです。キーパッド使用したi2cスレーブのプログラムに、簡易式カウンタのプログラムをマージした感じで作りました。
i2cスレーブを作ったとき心を入れ替え、MCCPの割り込みハンドラーを作り直したのが、良かったのかも。
ただし、LCD表示が遅いためLCD表示とi2c制御とキャパシティブセンシングが両立しないのが残念なところです。
デバッグ用のダンプ表示機能などがコンパイルオプションとかコメントアウトで残っておりますが、デバッグ時苦労の後のご愛嬌と思ってください。
/* //////////////////////////////////////////////////////// ///// * PIC16F1827にSC1602互換LCD表示パネルとm-touch仕様のcsmを備え * i2cのスレーブとして表示を行う実験用ルーチンです。 * sc1602とは4ビットモード接続されます。 * * i2cの状態管理はマイクロチップ社AN-734を参考にしました。 * 状態1-5でmsspからの割り込みをハンドリングします。 * * PIC16F88 V0.1 2011.09.30 V1.0 11.10.03 をベースに改造 * PIC16F1823 V2.1 2011.11.10 2 NiH operation(CLK OUT) * PIC16F1827 V3.0 2012.8.30 * PIC16F1827 V4.0 2012.9.25 LCD+KeyPad Status 1-5 * timing tunig for LCD & Key pad connection * PIC16F1827 V5.0 2012.10.5 LCD+4Key csm * * MPLAB v8.85 & HI-TECH C V9.83 * by nobcha (c)2012 * * i2c経由LCDデータは必ず2バイト単位でくるとする。MAX6(2,4,6) * 1バイト目はRSビット(コマンド0x0、データ0x40)、2バイト目が * LCDに書き込むデータです * ストロベリーリナックスの拡張コマンドはサポートしてません * * コマンドで0x11がキースキャンスタート、0x10がキースキャン * ストップ,キースキャン中はLCDデータを渡してはいけない * i2cのREADコマンドに応答して現在管理しているキーパッドの * 情報を返事する。下位の7ビットはキーパッドのasciiコードを示す。 * 数字は0x30から0x34、 * キー入力は20mS間隔のスキャン2回同じコードが続けば有効とする * * RA0-3:SC1602は4bit * RA4:CSM1 * RA5:MCLR * RA7:動作確認用LED * RB1:SDA1 MSSP * RB2:CSM2 * RB3:CSM3 * RB4:SCL1 MSSP * RB5:CSM4 * RB6:LCD EN bit (enable)はRB6につなぎます。 * RB7:LCD RS bit(RS)はRB7につなぎます。 * * SC1602 pin connection via 4bit mode * #1 Vdd=5V * #2 Vss=GND * #3 LCD contrust center of 5k VOL * #4 RS RB7 * #5 R/W GND * #6 EN RB6 * * #11-14 DATA RA0-3 * * TMR1 is gate time controller as set (65536-20000) for 5ms * * CLK INT 16MHz * * /////////////////////////////////////////////////////////// */ #include <htc.h> #include "lcd.h" #define _XTAL_FREQ 16000000 #define PIC_CLCK 1600000 #define I2C_ADR 0x7C #define DEBUG 0 // 1:debug #define MON_LED LATA7 #define DEF 30 __CONFIG( FOSC_INTOSC & WDTE_OFF & PWRTE_ON & MCLRE_ON & CP_OFF & CPD_OFF & BOREN_OFF & CLKOUTEN_ON & IESO_OFF & FCMEN_OFF ); __CONFIG( WRT_OFF & PLLEN_OFF & STVREN_ON & LVP_OFF ); /* ///////////////////////////////////////////////// */ // Function prototyping void lcd_dispch( unsigned char); /* 1バイトを2ヘキサでLCDへ */ unsigned char hextoascii(unsigned char); /* ニブルをヘキサ変換 */ void init(void); /* PORT OSC */ void mssp_init(void); /* MSSP SSP1CON1 SSP1ADD */ void csm_init(void); /* CSM */ int csm_scan(unsigned char); void cnt_setup(void); void cnt_reset(void); void ssp_handler(void); void disp_freq(int); interrupt i2c_slave(void); // variable unsigned char buffer[20]; /* 受信バッファ */ unsigned char stat[20]; /* デバッグ用ステイタスバッファ*/ char rcv_count=0 ,cnt=0, kint_on, ssp_int_on, lcd_rs_rcv; unsigned char lcdrs, key_in_p, key_in=0, csm_ch, scan_comp; char key_in_cnt=0, cnt_start=0, cnt_of; int nom_freq[4]; int cur_freq[4]; unsigned char MSG1[] = "i2c csm_key v4"; unsigned char MSG2[] = "K="; void main(void){ char i, j=0; init(); /* ポート初期化 */ __delay_ms(200); // Slow LCD start up lcd_init(); /* LCDの初期化 */ MON_LED=0; ssp_int_on=0; __delay_ms(200); MON_LED=1; if (DEBUG==1){ /* debug mode */ lcd_goto(0x0); /* 1行目にLCD動作表示 */ lcd_puts(MSG1); /* LCDに初期表示 */ for(i=0;i<8;i++){ MON_LED != RA7; /* 動作モニター用LED点灯 */ __delay_ms(200); } } mssp_init(); /* SSPの初期化 */ SSP1IF = 0; /* SSPIF clear */ key_in=0; rcv_count=0; // i2c receive counting // For debugging set 1 // cnt_start=1; // csm_ch=1; for(i=0;i<4;i++) cur_freq[i]=0; while(1){ /* 繰り返し */ SSP1IE=1; // MSSP INT ENABLE PEIE=1; GIE=1; if(scan_comp==1){ // all channels scanned end cnt_reset(); // counter stop GIE=0; // INT disable switch(cnt_start){ // cnt_start=status ;2-5:nominal cal, 6:key check case 2: for(i=0;i<4;i++) nom_freq[i]=cur_freq[i]; cnt_start=3; break; case 3: case 4: case 5: for(i=0;i<4;i++) nom_freq[i]=(nom_freq[i]*3)/4+cur_freq[i]/4; // calculate nominal freq // for csm debug if (DEBUG==1){ /* debug mode */ __delay_ms(20); lcd_goto(0x4); // go to top __delay_ms(20); for(i=0;i<4;i++){ disp_freq(nom_freq[i]); __delay_ms(2); lcd_putch(0x2F); // delimitter __delay_ms(2); } } // debug cnt_start++; break; case 6: for(i=0;i<4;i++){ if(DEF<(nom_freq[i]-cur_freq[i])) key_in=(i+1)|0x30; // defference is more than DEF // for csm debug if (DEBUG==1){ /* debug mode */ __delay_ms(20); lcd_goto(0x44+(i)*5); // go to every position of 2nd line __delay_ms(20); disp_freq(cur_freq[i]); lcd_putch(0x2F); lcd_goto(0x40); // go to 2nd pos of 2nd line lcd_putch(0x30|(j++&0xF0)>>4); // op countig lcd_putch(key_in); lcd_putch(key_in_p); } // debug } break; } scan_comp=0; csm_ch=1; cnt_setup(); } if(key_in!=00){ key_in_p=key_in; kint_on=1; } if(cnt_start==1){ // csm activated csm_ch=1; // csm ch initilized cnt_setup(); // Start TMR1 gating and TMR0 counting cnt_start=2; // getting csm nominal freq CPSCON1bits.CPSCH=4; // CPS 4 selected CPSCON0bits.CPSRNG=0b11; // high current } if(kint_on&DEBUG){ // Key in occuered? // GIE=0; // lcd_goto(0x51); // KEY IN MSG // lcd_puts(MSG2); // K= // lcd_dispch(key_in_p); // 2 HEXA for key code // lcd_dispch(key_in_cnt); // Long keying counter // kint_on=0; // Key in int flag reset // GIE=1; } if(SSP1STATbits.P & rcv_count){ /* 受信のストップ状態チェック */ GIE=0; /* for i2c debug if(DEBUG){ // debug mode & received for(i=0;i<(rcv_count+1);i++){ lcd_goto(i*3 ); lcd_putch(0x23); // # lcd_dispch(buffer[i]); // lcd_dispch(stat[i]); } lcd_goto(0x53); // 2行目にLCD動作表示 lcd_putch(cnt++|0x30); // display count if(cnt>0x05){cnt=0;} lcd_putch(0x3C); lcd_dispch(rcv_count); // 下位4ビット取り出しASCII lcd_putch(0x3E); lcd_putch(0x20); for(j=0;j<2;j++){ // 表示時間を待たせる __delay_ms(100); } } i2c debug end */ rcv_count=0; MON_LED ^= 1; } } } // Displaying 1 byte via 2 Asciis void lcd_dispch( unsigned char ch_code){ lcd_putch(hextoascii((ch_code>>4)&0xF)); lcd_putch(hextoascii(ch_code&0xF)); } // Converting 4 bits to hexadicimal asciis unsigned char hextoascii(unsigned char hex_data){ hex_data = hex_data | '0'; // ASCII code if(hex_data>0x39)hex_data=hex_data+7; // alphabet return hex_data; } // Displaying INT freq data as 4 hex void disp_freq(int freq){ unsigned char freq1,freq2; freq1=(unsigned char)((freq>>8)&0xFF); freq2=(unsigned char)(freq&0xFF); lcd_putch(hextoascii((freq1>>4)&0xF)); lcd_putch(hextoascii((freq1)&0xF)); lcd_putch(hextoascii((freq2>>4)&0xF)); lcd_putch(hextoascii(freq2&0xF)); } // Initializing ports and osc void init(void){ ANSELA=0; // all degital ANSELB=0; PORTA = 0; // 0 level PORTB = 0b11000000; // TRISA = 0; // all output TRISB = 0; // __delay_us(10); // 10us discharge PORTA = 0b00000000; // PORTB = 0b11000000; // // port direction: 1:input TRISA = 0b01110000; /* RA0-3は出力、RA4-6入力、RA7出力 */ TRISB = 0b00111111; /* RB0−5は、sw、i2c用で入力、RB6-7出力設定 */ OSCCON = 0b01111000; /* 内部クロック16MHz */ ANSELA = 0x10; /* CPS4:RA4 ANALOGUE */ ANSELB = 0x2C; /* CPS10,9,7:RB2,3,5 ANALOGUE */ OPTION_REG = 0x80; /* オプション設定なし ~WPUA=1 */ } // Initializing MSSP function void mssp_init(void){ SSP1CON1 = 0x36; // b5:SSP1EN,b4:CKP,b3-0:SSP_slave_7bit SSP1ADD = I2C_ADR; // SSP ADDRESS SET PEIE = 1; // PEIE enable SSP1IE = 1; } // Setting TMR1 up void cnt_setup(void){ TMR1ON=0; // TMR1 OFF CPSON=0; TMR0 = 0 ; // TMR0 clear TMR1L = 0; // Clear Low Byte of TMR1 // 16MHz 62.5nS*4 250nS 5ms 20000 count TMR1H = 177; // Set 177*256 + 224 TMR1L = 224; // Set (177*256+224) =45536=65536-20000 TMR1IF=0; // TMR1 flag off TMR1IE=1; // TMR1 INT ENABLE TMR0IF=0; // TMR0 flag off TMR0IE=1; // TMR0 INT ENABLE PEIE=1; // PEIE 1 TMR1ON=1; // TMR1ON 1 cnt_of=0; // TMR0 over flow count T0XCS=1; // TMR0 = CPSCLK TMR0CS=1; // select CPS for TMR0 input CPSCON0bits.CPSRNG=0b11; // OSC is mid CPSON=1; // CPS enable } // Stop TMR1,0 void cnt_reset(void){ TMR1IE=0; // TMR1 INT DISABLE // TMR0 INT DISABLE PEIE=0; // PEIE 0 TMR1ON=0; // TMR1ON 0 TMR0=0; TMR1L=0; TMR1H=0; cnt=0; cnt_of=0; // TMR0 over flow count } // ssp int handling function void ssp_handler(void) { unsigned char s_state,dummy; s_state=SSP1STAT&0b00101101; // SMP,CKE,-D/A,P,-S,-R/W,UA,-BF switch(s_state){ case 0b00001001: // State1 address,S,write,buffer full dummy=SSP1BUF; // if address, read SSPBUF as dummy rcv_count=0; break; case 0b00101001: // State2 data,write,buffer full buffer[rcv_count]=SSP1BUF ; // if((rcv_count&0x1)==0){ // receiving RS byte and DATA byte as pair lcd_rs_rcv=((buffer[rcv_count]>>6)&0x1); // Set lcd_rs bit } else if((buffer[rcv_count]==0x10)&(lcd_rs_rcv==0)) { cnt_start=0; } else if((buffer[rcv_count]==0x11)&(lcd_rs_rcv==0)) { cnt_start=1; key_in=0; } else if(DEBUG==0) lcd_write_rs(buffer[rcv_count],lcd_rs_rcv); // Data byte stat[rcv_count]=SSP1STAT; // status buffering rcv_count++; // next buffer break; case 0b00001100: // State3 address,S, read,buffer empty case 0b00001101: // State3 address,S, read,buffer full SSP1CON1bits.CKP=0; // CKP clear dummy=SSP1BUF; // dummy address read if(key_in_p==key_in){ SSP1BUF=key_in_p; // key in data transmitting } else SSP1BUF=0; // No key in SSP1CON1bits.CKP=1; // CKP releas break; case 0b00101100: // State4 data,S, read,buffer empty SSP1CON1bits.CKP=0; // CKP clear SSP1CON1bits.CKP=1; // CKP releas break; case 0b00101000: // State5 data,S, read,buffer empty &full case 0b00101101: SSP1CON1bits.CKP=1; // CKP release break; default: lcd_puts("ERR"); break; } } // Interrupu service interrupt i2c_slave(void){ // i2c slave receive int func unsigned char pos=0; GIE=0; // R/W detect? needed if read send KB_status if(TMR1IF==1){ // Gate timeout cur_freq[(csm_ch++)-1]=(int)(TMR0)+(int)(cnt_of)*256; // Count freq next ch++ cnt_reset(); if(csm_ch>5){ // Next ch > 5, scan end (csn_ch:0-3) csm_ch=1; // csm_ch 1-4 going around scan_comp=1; // scan end } switch(csm_ch){ // select cpsch case 1: CPSCON1bits.CPSCH=4; break; case 2: CPSCON1bits.CPSCH=10; break; case 3: CPSCON1bits.CPSCH=9; break; case 4: CPSCON1bits.CPSCH=7; break; } cnt_setup(); // next counting } if(TMR0IF==1){ cnt_of++; // TMR0 over flow TMR0IF=0; } if(SSP1IF==1){ SSP1IE=0; SSP1IF=0; ssp_handler(); SSP1IE=1; } GIE=1; }
はてなダイヤリーでのソースコードの貼り付け方という掟があって、今回対応いたしました。ばんとさんご指導ありがとうございます。調べていただき感謝します。