---
---
18F26J50の2セットのMaster Synchronous Serial Port (MSSP)があります。MSSP を使うと周辺機器と簡単にシリアル通信を行うことができます。MSSPは、SPIとI2Cという2種類の方式をサポートしていまが、ここでは、I2Cを利用したEEPROMとLCD表示器のインターフェースだけを取り上げるため、I2C マスターモードが対象です。18F26J50にはMSSPが2セット内蔵されていますが、MSSP1 だけがI2C機能をサポートしています。
高低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接続の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
}
*注意*
I2C機能の入出力は、SCL1(RB4-pin25) SDA1(RB5-pin26)の2ピンに固定されています。I2Cモードで使うときには、この2つのピンはオープンドレインの回路にするため、TRISレジスタで入力モードに設定する必要があります。このピンは5v耐圧が考慮してあるため、接続するI2Cデバイスが5vで駆動されていても問題なく通信を行うことができます。