PIC18F14K50の基本動作から応用プログラムまでを学びます。

ホーム
16F18313
16F18325
16F18346
16F1619
Curiosity
---
---
    
12F1822
16F1455
16F1459
18F14K50
18F26J50
dsPIC
その他
MSSP I2C

18F26J50の2セットのMaster Synchronous Serial Port (MSSP)があります。MSSP を使うと周辺機器と簡単にシリアル通信を行うことができます。MSSPは、SPIとI2Cという2種類の方式をサポートしていまが、ここでは、I2Cを利用したEEPROMとLCD表示器のインターフェースだけを取り上げるため、I2C マスターモードが対象です。18F26J50にはMSSPが2セット内蔵されていますが、MSSP1 だけがI2C機能をサポートしています。

*注意*
I2C機能の入出力は、SCL1(RB4-pin25) SDA1(RB5-pin26)の2ピンに固定されています。I2Cモードで使うときには、この2つのピンはオープンドレインの回路にするため、TRISレジスタで入力モードに設定する必要があります。このピンは5v耐圧が考慮してあるため、接続するI2Cデバイスが5vで駆動されていても問題なく通信を行うことができます。

高低2レベルの優先度を使用するI2C に関連するレジスターを一覧で説明します。

レジスタ bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
RCON IPEN SBOREN RI TO PD POR BOR
INTCON GIE/GIEH PEIE/GIEL TMR0IE INTIE RABIE TMR0IF INT0IF RABIF
PIR1 - ADIF RCIF TXIF SSP1IF CCP1IF TMR2IF TMR1IF
PIE1 - ADIE RCIE TXIE SSP1IE CCP1IE TMR2IE TMR1IE
IPR1 ADIP RCIP TXIP SSPIP CCP1IP TMR2IP TMR1IP
PIR2 OSCFIF C1IF C2IF EEIF BCLIF USBIF TMR3IF CCP2IF
PIE2 OSCFIE C1IE C2IE EEIE BCLIE USBIE TMR3IE CCP2IE
IPR2 OSCFIP C1IP C2IP EEIP BCLIP USBIP TMR3IP CCP2IP
SSP1CON1 WCOL SSPOV SSPEN CKP SSPM<3:0>
SSP1CON2 GCEN ACKSTAT ACKDT ACKEN RCEN PEN RSEN SEN
SSP1CON3 ACKTIM PCIE SCIE BOEN SDAHT SBCDE AHEN DHEN
SSP1STAT SMP CKE D/A P S WnR UA BF
SSP1ADD ADD<7:0>
SSP1BUF MSSP Receive Buffer/Transmit Register
TRISB TRISB7 TRISB6 TRISB5 TRISB4
レジスタ BIT 説明 1 0
RCON 7 IPEN 2レベルのインタラプト優先度 使用
INTCON 7 GIEH 高優先度インタラプトを使用許可 許可
6 GIEL 低優先度インタラプトを使用許可 許可
PIR1 3 SSPIF SSP フラグ 発生 待ち
PIE1 3 SSPIE SSP インタラプトを使用許可 許可
IPR1 3 SSPIP SSP インタラプト優先度
PIR2 3 BCLIF バス衝突 フラグ 発生 待ち
PIE2 3 BCLIE バス衝突 インタラプトを使用許可 許可
IPR2 3 BCLIP バス衝突 インタラプト優先度
SSP1CON1 7 WCOL 送信時バス衝突 発生 なし
6 SSPOV 受信時SSPBUFオーバーラン 発生 なし
5 SSPEN MSSPの動作許可 許可
4 CKP   同期 非同期
3 SSPM3 SSPM ModeSelect Bits::
I2C マスターモードのときは、
  SSPM <3 : 0> = 1000 をセットする。
2 SSPM2
1 SSPM1
0 SSPM0
SSP1CON2 7 GCEN General Cell Add (Slaveのみ)    
6 ACKSTAT ACKを受信 受信
5 ACKDT NACK/ACK指示 NACK ACK
4 ACKEN ACKDTを送信開始 開始 待ち
3 RCEN 受信開始 開始 待ち
2 PEN STOP シーケンス開始 開始 待ち
1 PSEN RepeatSTART シーケンス開始 開始 待ち
0 SEN START シーケンス開始 開始 待ち
SSP1STAT 7 SMP バス速度指定 100k 400k
6 CKE クロックエッジ指定 (SPIモードのみ)    
5 D/A Data/Address 表示 (Slaveモードのみ)    
4 P STOP ビット状況 (Read Only) 検出
3 S START ビット状況 (Read Only) 検出
2 R/W 送信状況 (Read Only) 送信中 待ち
1 US Update Address (Slaveモードのみ)    
0 BF SSPBUF状況 (Read Only) フル

I2C クロック周波数 Fosc
48MHz 16MHz 4MHz
400 KHz 0x1D 0x18 ---
100 KHz 0x77 0x63 0x09

I2Cクロック周波数と、SSPADDへの設定値

I2Cのプログラム例

文字やアイコンをI2C接続のLCD画面に表示するプログラムです。ストロベリーリナックス社I2C を接続していますが、LCDの制御ICが共通の使用を持つ秋月電子のI2C液晶表示器でも動作します。

<回路図>

<プログラム>

//*********************************************************
//  PIC18F26J50 I2C Program//        :  MPLAB xc8
//  ストロベリーリナックス社I2C LCD表示器への書き込みテスト
//    「LCD Test」と液晶表示する。
//  Note:  4MHzシステムクロック
//         PORTB(5)pin26    :  SDA1
//         PORTB(4)pin25    :  SCL1
//
//*********************************************************

#include    <xc.h>
#define     _XTAL_FREQ 4000000      // delay_ms(x) のための定義

//*********************************************************************
//  調整用定数
//*********************************************************************
#define CONTRAST  0x28          // for 3.3V

//-------------- コンフィグレーション ----------------------
//
     #pragma config WDTEN = OFF, PLLDIV = 2, STVREN = ON, XINST = OFF
     #pragma config CPUDIV = OSC1, CP0 = OFF
     #pragma config OSC = INTOSC, T1DIG = OFF
     #pragma config LPT1OSC = OFF, FCMEN = OFF, IESO = OFF
     #pragma config WDTPS = 32768
     #pragma config DSWDTOSC = INTOSCREF, RTCOSC = T1OSCREF
     #pragma config DSBOREN = OFF, DSWDTEN = OFF, DSWDTPS = 8192
     #pragma config IOL1WAY = OFF, MSSP7B_EN = MSK7
     #pragma config WPFP = PAGE_1, WPEND = PAGE_0, WPCFG = OFF
     #pragma config WPDIS = 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 *);

//*********************************************************
void main(void){
    char msgStart[] ="LCD Test";
    OSCCON = 0b01100011;       // 内部クロック4Mhz
    ANCON0 = 0b00011111;       // すべてのポートをデジタルに設定
    ANCON1 = 0b00011111;       //

    TRISBbits.TRISB4 = 1;      // SCL1(RB4)を入力に設定
    TRISBbits.TRISB5 = 1;      // SDA1(RB5)を入力に設定
    INTCON2bits.RBPU = 0;      // 弱プルアップ ON

    // SSP1設定 -----------------------------------------------
    SSP1STAT = 0b10000000;     // スルーレート制御はOff
    SSP1ADD  = 9;              // クロック設定 100k@4MHz
    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
}