 
		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)の
再読み込み値