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

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

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

*注意*
SCL SDAの2ピンはオープンドレインの回路にする必要があるため、TRISレジスタで入力モードに設定しておく必要があります。
SCL SDAの2ピンの配置は、PIC16F1455とPIC16F1459で異なります。注意が必要です。

SCL SDA
PIC16F1455 RC0
pin10
RC1
pin9
PIC16F1459 RB6
pin11
RB4
pin13
レジスタ 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
TRISB TRISB7 TRISB6 TRISB5 TRISB4
レジスタ 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 SSPEN 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に表示する。
//    秋月(AQM0802A)I2C 8x2 LCD表示器への書き込み
//    「LCD Test」と液晶表示する。
//     1)Define I/O PORT
//           SDA  :    PORTB(4) pin13
//           SCL  :    PORTB(6) pin11
//     2)OSC
//         4MHz (内部クロック)
//
//    Language: MPLABX XC8
//    Target: PIC16F1459
// Copyright (c) 2015 iwamoto All Rights Reserved
//*********************************************************
#include <xc.h>
#include <stdio.h>
#define _XTAL_FREQ 4000000

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

//************* 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_posyx(char,char);              // カーソル位置指定

// **************** printf Routen *****************************
// LCD で printf関数が使用できるようにするため putch を設定する
void putch(char data) {
        LCD_dat(data);      // LCD への一文字表示関数
}

//////////// Main //////////////////////////////////
void main(void){
    char msgStart[] ="LCD Test";
    unsigned char num = 0;
    OSCCON = 0b00110110;           // 内部クロック4Mhz
    ANSELA = 0;                    // PortAをデジタルI/Oにする
    TRISA4 = 1;                    // PortA4をデジタルInputにする
    ANSELB = 0;                    // PortBをデジタルI/Oにする
    TRISB  = 0b11111111;           // PortBを入力I/Oにする
    nWPUEN = 0;                    // 弱プルアップをONにする

    SSPCON1 = 0x28;                // I2Cマスターモード指定
    SSPSTAT = 0x00;
    SSPADD  = 0x09;                // I2Cクロック周波数100KHz for 4MHz
    LCD_int();                     // LCD初期化
    num=0;
    printf("LCD Test");            // 上行に表示
    while(1){
        LCD_posyx(1,3);            // 下行4文字目から
        printf("%02X",num++);      // 16進で2文字表示
        __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);                // 送信終了待ち
}
//********************************************************************
// 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;  // 1行目
        case 1: pcode=0xC0;break;  // 2行目
    }
    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
}