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

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

16F18325 には、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 0x01 0x09 0x27 0x4F

SSPxADDに設定する
baudレート ジェネレータ(BRG)の
再読み込み値

レジスタ 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 仕様 有効 無効
2 R/nW SSPx送信状況 送信中 待ち
0 BF SSPxBUFバッファフル ステータス フル

MSSPのプログラム例

PI2Cを利用したLCD表示器(LCD-AQM0802A)「LCD Test / I2C com」と表示するプログラムを作成しました。通常 I2Cラインに取り付けるプルアップ抵抗は、PIC内の弱プルアップを利用しています。雑音の大きい環境で使用するときは、別途プルアップ抵抗を回路に取り付けてください。
<回路図>

<プログラム>

/*********************************************************************
 *  データをLCDに表示する。
 *    秋月(ACM1602NI)I2C LCD表示器を使用
 *          1MHz (内部クロック)
 * RC5 SCL
 * RC4 SDA
 *
 * PIC16F18325  MPLAB X IDE with XC8
 * Copyright (c) 2017 iwamoto All Rights Reserved
 * *******************************************************************/
#define _XTAL_FREQ 1000000

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

#include <xc.h>
//******************* コンフィグレーション ****************************
#pragma config FEXTOSC = OFF,RSTOSC = HFINT1  // HFINTOSC (1MHz)
#pragma config CLKOUTEN = OFF,CSWEN = ON,FCMEN = OFF
#pragma config MCLRE = OFF,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 = OFF,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";

//    OSCFRQ  = 0b00000110;   // HFOSC  16MHz
//    OSCCON1 = 0b01100010;   // HFINT1 DIV 4
    LATA   = 0x00;
    TRISA  = 0xFF;          // Port すべて入力
    ANSELA = 0x00;          // すべてデジタル
    WPUA   = 0xFF;          // 弱プルアップ ON
    LATC   = 0x00;
    TRISC  = 0xFF;          // Port すべて入力
    ANSELC = 0x00;          // すべてデジタル
    WPUC   = 0xFF;          // 弱プルアップ ON

    ODCONC = 0b110000;      // RC4,RC5をオープンドレイン
    SSP1CLKPPS = 0x15;      // RC5をCLK入力に指定
    RC5PPS     = 24;        // RC5をCLK出力に指定
    SSP1DATPPS = 0x14;      // RC4をDATに入力指定
    RC4PPS     = 25;        // RC4を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
}