16F18346 には、2本の Master Synchronous Serial Port (MSSP) があり、MSSP を使うと周辺機器と簡単にシリアル通信を行うことができます。MSSPは、SPIとI2Cという2種類の方式をサポートしていまが、ここでは、I2Cを利用したLCD表示器とのインターフェースだけを取り上げます。このため、I2C マスターモードが対象です。I2Cに関連するレジスター一覧を下表に示します。
*注意*
SCL SDAの2ピンで通信を行いますが、これらは、PPSでどのピンを使用するかを指定できます。これらは双方向で使うため、ピンはオープンドレイン回路にし、TRISレジスタは入力モードに設定する必要があります。
I2C クロック | PIC クロック | |||
---|---|---|---|---|
1M | 4M | 16M | 32M | |
400 kHz | - | - | 0x09 | 0x13 |
100 kHz | - | 0x09 | 0x27 | 0x4F |
レジスタ | bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 |
---|---|---|---|---|---|---|---|---|
INTCON | GIE | PEIE | - | - | - | - | - | INTEDG |
PIE1 | TMR1GIE | ADIE | RCIE | TXIE | SSP1IE | BCL1IE | TMR2IE | TMR1IE |
PIR1 | TMR1GIF | ADIF | RCIF | TXIF | SSP1IF | BCL1IF | TMR2IF | TMR1IF |
PIE2 | TMR6IE | C2IE | C1IE | NVMIE | SSP2IE | BLC2IE | TMR4IE | NCO1IE |
PIR2 | TMR6IF | C2IF | C1IF | NVMIF | SSP2IF | BLC2IF | TMR4IF | NCO1IF |
SSPxCON1 | WCOL | SSPOV | SSPEN | CKP | SSPM<3:0> | |||
SSPxCON2 | GCEN | ACKSTAT | ACKDT | ACKEN | RCEN | PEN | RSEN | SEN |
SSPxSTAT | SMP | CKE | D/nA | P | S | R/nW | UA | BF |
SSPxADD | baud レートクロック分周値 | |||||||
SSPxBUF | 同期シリアルポート受信バッファ/ 送信レジス | |||||||
SSPxCLKPPS | - | - | - | SSPxCLKPPS<4:0> | ||||
SSPxDATPPS | - | - | - | SSPxDATPPS<4:0> | ||||
RxyPPS | - | - | - | RxyTPPS<4:0> |
レジスタ | BIT | 名 | 説明 | 1 | 0 |
---|---|---|---|---|---|
INTCON | 7 | GIE | 全インタラプトの使用許可 | 許可 | 否 |
6 | PEIE | 周辺機能インタラプトの使用許可 | 許可 | 否 | |
PIE1 | 3 | SSP1IE | SSP1 インタラプトを使用許可 | 許可 | 否 |
PIR1 | 3 | SSP1IF | SSP1 フラグ | 発生 | 未発生 |
SSPxCON1 | 7 | WCOL | 書き込みコリジョン検出 | 発生 | 未発生 |
6 | SSPOV | 受信オーバーフロー | 発生 | 未発生 | |
5 | SSPEN | SSP イネーブルビット | 有効 | 無効 | |
4 | CKP | クロック ストレッチ制御 | Open | LOW | |
3 | SSPM3 | 1000 = I2C マスタモード、 クロック = FOSC / (4 * (SSPxADD+1))(4) |
|||
2 | SSPM2 | ||||
1 | SSPM1 | ||||
0 | SSPM0 | ||||
SSPxCON2 | 7 | GCEN | ジェネラルコール アドレス | 有効 | 無効 |
6 | ACKSTAT | 肯定応答(ACK)信号を受信 | YESS | NO | |
5 | ACKDT | マスタ受信モード肯定応答(ACK) シーケンス | 開始 | アイドル | |
4 | ACKEN | 受信イネーブルビット (I2C マスタモードのみ) | 有効 | 無効 | |
3 | PEN | ストップ条件 (I2C マスタモードのみ) | 開始 | アイドル | |
2 | RSEN | 反復スタート条件 (I2C マスタモードのみ) | 開始 | アイドル | |
0 | SEN | スタート条件 (I2C マスタモードのみ) | 開始 | アイドル | |
SSPxSTAT | 7 | SMP | スルーレート制御 (400 kHzは有効「0」にする) | 無効 | 有効 |
6 | CKE | SMBus 仕様 | 有効 | 無効 | |
0 | BF | SSPxBUFバッファフル ステータス | フル | 空 |
<回路図>
I2Cを利用したLCD表示器(LCD-AQM0802A)「LCD Test / I2C com」と表示するプログラムを作成しました。通常 I2Cラインに取り付けるプルアップ抵抗は、PIC内の弱プルアップを利用しています。雑音の大きい環境で使用するときは、別途プルアップ抵抗を回路に取り付けてください。
<プログラム>
/************************************* * File: ADC sample * データをLCDに表示する。 * 秋月(ACM1602NI)I2C LCD表示器を使用 * 1MHz (内部クロック) * RB4 SDA * RB6 SCL * PIC16F18346 MPLAB XC8 v2.10 * Created on May 22, 2020, 2:37 PM **************************************/ //********************************************************************* // 調整用定数 //********************************************************************* #define CONTRAST 0x28 // for 3.3V // #define CONTRAST 0x18 // for 5.0V #include <xc.h> #define _XTAL_FREQ 1000000 // delay_ms(x) のための定義 #pragma config FEXTOSC = OFF,RSTOSC = HFINT1 // HFINTOSC (1MHz) #pragma config CLKOUTEN = OFF,CSWEN = OFF,FCMEN = OFF #pragma config MCLRE = ON,PWRTE = OFF,WDTE = OFF,LPBOREN = OFF #pragma config BOREN = OFF,BORV = LOW,PPS1WAY = OFF,STVREN = ON #pragma config DEBUG = OFF #pragma config WRT = OFF,LVP = ON,CP = OFF,CPD = OFF //******************* プロトタイプ ******************************* void i2cByteWrite(char, char, char); void i2cTxData(char); void LCD_dat(char); void LCD_cmd(char); void LCD_clr(void); void LCD_posyx(char,char); void LCD_int(void); void LCD_str(char *); void LCD_ROMstr(const char *); // ******************* main ****************************************** void main() { char msgStart[] ="LCD Test"; TRISB4 = 1; // RB4を入力 TRISB6 = 1; // RB6を入力 ANSB4 = 0; // RB4をデジタル ANSB6 = 0; // RB6をデジタル ODCB4 = 1; // RB4をオープンドレイン ODCB6 = 1; // RB6をオープンドレイン SSP1CLKPPS = 0x0E; // RB6をCLK入力に指定 RB6PPS = 24; // RB6をCLK出力に指定 SSP1DATPPS = 0x0C; // RB4をDATに入力指定 RB4PPS = 25; // RB4をDAT出力に指定 // SSP1設定 ----------------------------------------------- SSP1STAT = 0b10000000; // スルーレート制御はOff SSP1ADD = 1; // クロック設定 125k@1MHz SSP1CON1 = 0b00101000; // I2C Master modeにする // -------------------------------------------------------- LCD_int(); // LCDを初期化 LCD_str(msgStart); // LCD上段に"LCD Disp Test" LCD_posyx(1,1); // 下段にカーソル移動 LCD_ROMstr("I2C com"); // 下段に追記 while(1); } //******************************************************************** // I2C 関連 //******************************************************************** //-------- ByteI2C送信 void i2cByteWrite(char addr, char cont, char data){ SSP1CON2bits.SEN = 1; // Start condition 開始 while(SSP1CON2bits.SEN); // Start condition 確認 i2cTxData(addr); // アドレス送信 i2cTxData(cont); // 制御コード送信 i2cTxData(data); // データ送信 SSP1CON2bits.PEN = 1; // Stop condition 開始 while(SSP1CON2bits.PEN); // Stop condition 確認 } //-------- Data送信 void i2cTxData(char data){ PIR1bits.SSP1IF = 0; // 終了フラグクリア SSP1BUF = data; // データセット while(!PIR1bits.SSP1IF); // 送信終了待ち } //******************************************************************** // LCD 関連 //******************************************************************** //-------- 1文字表示 void LCD_dat(char chr){ i2cByteWrite(0x7C, 0x40, chr); __delay_us(50); // 50μsec } //-------- コマンド出力 void LCD_cmd(char cmd){ i2cByteWrite(0x7C, 0x00, cmd); if(cmd & 0xFC) // 上位6ビットに1がある命令 __delay_us(50); // 50usec else __delay_ms(2); // 2msec ClearおよびHomeコマンド } //-------- 全消去 void LCD_clr(void){ LCD_cmd(0x01); //Clearコマンド出力 } //-------- カーソル位置指定 void LCD_posyx(char ypos, char xpos){ unsigned char pcode; switch(ypos & 0x03){ case 0: pcode=0x80;break; case 1: pcode=0xC0;break; } LCD_cmd(pcode += xpos); } //-------- 初期化 void LCD_int(void){ __delay_ms(100); LCD_cmd(0x38); // 8bit 2行 表示命令モード LCD_cmd(0x39); // 8bit 2行 拡張命令モード LCD_cmd(0x14); // OSC BIAS 設定1/5 // コントラスト設定 LCD_cmd(0x70 + (CONTRAST & 0x0F)); LCD_cmd(0x5C + (CONTRAST >> 4)); LCD_cmd(0x6B); // Ffollwer __delay_ms(100); __delay_ms(100); LCD_cmd(0x38); // 表示命令モード LCD_cmd(0x0C); // Display On LCD_cmd(0x01); // Clear Display } //-------- 文字列出力 void LCD_str(char *str){ while(*str) //文字列の終わり(00)まで継続 LCD_dat(*str++); //文字出力しポインタ+1 } //-------- Rom 文字列出力 void LCD_ROMstr(const char *str){ while(*str) //文字列の終わり(00)まで継続 LCD_dat(*str++); //文字出力しポインタ+1 }
SSPxADDに設定する baudレート ジェネレータ(BRG)の
再読み込み値