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

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

16F145xのMaster Synchronous Serial Port (MSSP) を使うと周辺機器と簡単にシリアル通信を行うことができます。MSSPは、SPIとI2Cという2種類の方式をサポートしていまが、ここでは、I2Cを利用したLCD表示器のインターフェースだけを取り上げます。このため、I2C マスターモードが対象です。 SCL SDAの2ピンが対応しています。I2Cモードで使うときには、この2つのピンはオープンドレインの回路にする必要があるため、TRISレジスタで入力モードに設定しておく必要があります。 I2Cに関連するレジスター一覧を下表に示します。

*注意*
I2Cピンは、ICSP と共通ピンを使用しています。PICkitは内部でこの端子をプルダウンしているため、PICkit を接続したままでは、I2C機能が働きません。

プログラムの動作確認をするときには、必ずPICkitを回路から取り外します。

レジスタ bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
INTCON GIE PEIE TMR0IE INTE IOCIE TMR0IF INTF IOCIF
PIE1 TMR1GIE ADIE RCIE TXIE SSP1IE - TMR2IE TMR1IE
PIR1 TMR1GIF ADIF RCIF TXIF SSP1IF - TMR2IF TMR1IF
PIE2 OSFIE C2IE C1IE - BCL1IE USBIE ACTIE -
PIR2 OSFIF C2IF C1IF - BCL1IF USBIF ACTIF -
SSPCON1 WCOL SSPOV SSPEN CKP SSPM<3:0>
SSPCON2 GCEN ACKSTAT ACKDT ACKEN RCEN PEN RSEN SEN
SSPCON3 ACKTIM PCIE SCIE BOEN SDAHT SBCDE AHEN DHEN
SSPSTAT SMP CKE D/A P S WnR UA BF
SSPADD ADD<7:0>
SSPBUF MSSP Receive Buffer/Transmit Register
TRISC TRISC7 TRISC6 TRISC5 TRISC4 TRISC3 TRISC2 TRISC1 TRISC
レジスタ BIT 説明 1 0
INTCON 7 GIE 全インタラプトの使用許可 許可
6 PEIE 周辺機能インタラプトの使用許可 許可
PIE1 3 SSP1IE SSP インタラプトを使用許可 許可
PIR1 3 SSP1IF SSP インタラプト フラグ 発生 未発生
PIE2 3 BCL1IE バス衝突 インタラプトを使用許可 許可
PIR2 3 BCL1IF バス衝突 インタラプト フラグ 発生 未発生
SSPCON1 7 WCOL 送信時Bus衝突 発生 なし
6 SSPOV 受信時SSPBUFオーバーラン 発生 なし
5 SSPOV MSSPの動作 ON OFF
<3:0> SSPM I2C Master modeは、0b1000 に設定
SSPCON2 6 ACKSTAT ACK受信状況 受信済
5 ACKDT マスタ受信時のNACK/ACK指示 NACK ACK
4 ACKEN マスタ受信時のACKシーケンス開始 (自動リセット) 開始 待ち
3 RCEN 受信機能を許可 許可 禁止
2 PEN Stop 状況開始 (完了で自動リセット) 開始 待ち
1 RSEN Repeat Start 状況開始 (完了で自動リセット) 開始 待ち
0 SEN Start 状況開始 (完了で自動リセット) 開始 待ち
SSPCON3 7 ACKTIM ACKタイミング状況 ACK内 ACK外
6 PCIE Stop 状況割込み 許可 禁止
5 SCIE Start 状況割込み 許可 禁止
3 SDAHT SCL立下り後のSDA Hold Time 300 nS 100 nS
SSPSTAT 7 SMP Slew rate 制御の無効(100k用)/有効(400k用) 100Hzk 400kHz
6 CKE スレッシュホールド電圧の異なるbusを使用 SMbus 標準
5 D/A (Read only) 直前Byteの内容 data address
4 P (Read only) 直前にStop bit なし 検出
3 S (Read only) 直前にStart bit なし 検出
2 R/W (Read only) 送信状況 送信中 待機
1 UA (Read only) 10-bit I2C mode only
0 BF (Read only) SSPBUF状況 フル

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

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

I2Cのプログラム例

秋月(ACM1602NI)I2C LCD表示器へ文字を表示するプログラムです。 i2cは双方向性バスで受信(スレーブ)側の応答を確認したり、送受信信号が衝突した場合などのエラーを検出する機能を持っています。しかし、このプログラムでは、これら機能をすべて省略し、表示データや制御コードを一方的にLCD表示器に送信しています
<回路図>

<プログラム>

//  データをLCDに表示する。
//    秋月(ACM1602NI)I2C LCD表示器への書き込み
//    「LCD Disp Test」と液晶表示する。
//     1)Define I/O PORT
//                   --PIC16F1455--  --PIC16F1459--
//           SDA  :  PORTC(1) pin 9  PORTB(4) pin13
//           SCL  :  PORTC(0) pin10  PORTB(6) pin11
//     2)OSC
//         4MHz (内部クロック)
//
//    Language: MPLABX XC8
//    Target: PIC16F1455
// Copyright (c) 2012 iwamoto All Rights Reserved
//*********************************************************
#include <xc.h>
#define _XTAL_FREQ 4000000

//************* Config  ***********************************
#pragma config FOSC  = INTOSC, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP  = OFF
#pragma config BOREN = ON, CLKOUTEN = OFF, IESO  = OFF, FCMEN = OFF
#pragma config WRT = OFF, CPUDIV = NOCLKDIV, USBLSCLK = 48MHz, PLLMULT = 3x
#pragma config PLLEN = DISABLED, STVREN = ON, BORV = LO, LPBOR = OFF, LVP = OFF

//********************************************************
void i2cByteWrite(char, char, char);    // i2c byte送信
void i2cTxData(char);                   // i2c SSPBUF セット
void LCD_dat(char);                     // 1文字表示
void LCD_cmd(char);                     // コマンド出力
void LCD_clr(void);                     // 全消去
void LCD_int(void);                     // 初期化
void LCD_str(char *);                   // 文字列表示
void LCD_ROMstr(const char *);          // ROM文字列表示
void LCD_posyx(char,char);              // カーソル位置指定
void LCD_hex(char);                     // 16進文字変換表示

//////////// Main //////////////////////////////////
void main(void){
    char msgStart[] ="LCD Test";
    unsigned char num = 0;
    OSCCON = 0b00110100;           // 内部クロック4Mhz
    ANSELC = 0;                    // PortCをデジタルI/Oにする
    TRISC  = 0b11111111;           // PortCを入力I/Oにする
    SSPCON1 = 0x28;                // I2Cマスターモード指定
    SSPSTAT = 0x00;
    SSPADD  = 0x09;                // I2Cクロック周波数100KHz for 4MHz
    LCD_int();                     // LCD初期化
       // ------------------------------------------------------
    LCD_str(msgStart);             // 1行目に表示
    LCD_dat(' ');
    LCD_dat('!');
    // ------------------------------------------------------
    LCD_posyx(1,0);                // 2行目に表示
    LCD_ROMstr("1234567890123456");
    while(1){
        LCD_posyx(0,14);           // 1行14文字目に表示
        LCD_hex(num++);            // 数値を表示し、+1する
        __delay_ms(1000);          // 1000msec
    }
}

//-------- i2cで1byteデータを送信する -----------------------
//  以下の引数が必要
//  addr : Slaveのアドレス
//  cont : Slaveへ制御コード
//  data : 送信するデータ
//  NACKやBus衝突などの対応は行っていない
// -----------------------------------------------------------
void i2cByteWrite(char addr, char cont, char data){
    SEN = 1;                       // Start condition 開始
    while(SEN);                    // Start condition 確認
    i2cTxData(addr);               // アドレス送信
    i2cTxData(cont);               // 制御コード送信
    i2cTxData(data);               // データ送信
    SSP1IF = 0;                    // 終了フラグクリア
    PEN = 1;                       // Stop condition 開始
    while(PEN);                    // Stop condition 確認
}

//-------- SSPBUFに1文字保存し送信終了を待つ -----------------
void i2cTxData(char data){
    SSP1IF = 0;                    // 終了フラグクリア
    SSPBUF = data;                 // データセット
    while(!SSP1IF);                // 送信終了待ち
}

//-------- 1文字表示 --------------------------------------
void LCD_dat(char chr){
    i2cByteWrite(0xA0, 0x80, chr);
    __delay_us(60);                // 60μsec
}
//-------- コマンド出力 --------------------------------------
void LCD_cmd(char cmd){
    i2cByteWrite(0xA0, 0x00, cmd);
    if(cmd & 0xFC)                 // 上位6ビットに1がある命令
        __delay_us(60);            // 60usec
    else
        __delay_ms(3);             // 3msec 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;  // 1行目
        case 1: pcode=0xC0;break;  // 2行目
        case 2: pcode=0x94;break;  // 3行目
        case 3: pcode=0xD4;break;  // 4行目
    }
    LCD_cmd(pcode += xpos);        // 横位置を加える
}
//-------- 文字列出力 -----------------------------------------
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
}
//-------- 16進文字変換表示 --------------------------------
void LCD_hex(char c){
    const char hexch[] ="0123456789ABCDEF";
    LCD_dat(hexch[c >> 4]);        //上位4bit表示
    LCD_dat(hexch[c & 0xF]);       //下位4bit表示
}

//-------- 初期化 --------------------------------------
void LCD_int(void){
    __delay_ms(100);               // 電源安定するまでの時間
    LCD_cmd(0x38);                 // 8bit 2行 表示命令モード
    LCD_cmd(0x0C);                 // Display on Cursor=0 Blink=0
    LCD_cmd(0x06);                 // Entry Inc/Dec=1 Shift=0
    LCD_cmd(0x01);                 // Clear Display
}