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

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

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

*注意*
SCL(RA1)ピンは、ICSP と共通使用しています。PICkitは内部でこの端子をプルダウンしているため、PICkit を接続したままでは、I2C機能が働きません。プログラムの動作確認をするときには、必ずPICkitを取り外します。

I2C クロック PIC クロック
4M 16M 32M
400 kHz - 0x09 0x13
100 kHz 0x09 0x27 0x4F

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

レジスタ bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0
INTCON GIE PEIE TMR0IE INTE IOCIE TMR0IF INTF IOCIF
PIE1 TMR1GIE ADIE RCIE TXIE SSP1IE CCP1IE TMR2IE TMR1IE
PIR1 TMR1GIF ADIF RCIF TXIF SSP1IF CCP1IF TMR2IF TMR1IF
SSP1CON1 WCOL SSPOV SSPEN CKP SSPM<3:0>
SSP1CON2 GCEN ACKSTAT ACKDT ACKEN RCEN PEN RSEN SEN
SSP1STAT SMP CKE D/nA P S R/nW UA BF
SSP1ADD baud レートクロック分周値
SSP1BUF 同期シリアルポート受信バッファ/ 送信レジス
レジスタ BIT 説明 1 0
INTCON 7 GIE 全インタラプトの使用許可 許可
6 PEIE 周辺機能インタラプトの使用許可 許可
PIE1 3 SSP1IE SSP1 インタラプトを使用許可 許可
PIR1 3 SSP1IF SSP1 フラグ 発生 未発生
SSP1CON1 7 WCOL 書き込みコリジョン検出 発生 未発生
6 SSPOV 受信オーバーフロー 発生 未発生
5 SSPEN SSP イネーブルビット 有効 無効
4 CKP クロック ストレッチ制御 Open LOW
3 SSPM3 1000 = I2C マスタモード、
クロック = FOSC / (4 * (SSP1ADD+1))(4)
2 SSPM2
1 SSPM1
0 SSPM0
SSP1CON2 7 GCEN ジェネラルコール アドレス 有効 無効
6 ACKSTAT 肯定応答(ACK)信号を受信 YESS NO
5 ACKDT マスタ受信モード肯定応答(ACK) シーケンス 開始 アイドル
4 ACKEN 受信イネーブルビット (I2C マスタモードのみ) 有効 無効
3 PEN ストップ条件 (I2C マスタモードのみ) 開始 アイドル
2 RSEN 反復スタート条件 (I2C マスタモードのみ) 開始 アイドル
0 SEN スタート条件 (I2C マスタモードのみ) 開始 アイドル
SSP1STAT 7 SMP スルーレート制御 (400 kHzは有効「0」にする) 無効 有効
6 CKE SMBus 仕様 有効 無効
0 BF SSP1BUFバッファフル ステータス フル

MSSPのプログラム例

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

<プログラム>

/*********************************************************************
 *  データをLCDに表示する。
 *    秋月(ACM1602NI)I2C LCD表示器を使用
 *          4MHz (内部クロック)
 *
 *     1 VDD         8 VSS
 *     2 RA5         7 RA0
 *     3 RA4         6 RA1 SCL
 *     4 MCLR        5 RA2 SDA
 *
 * PIC12F1822  MPLAB X IDE with XC8 Ver1.32
 * Copyright (c) 2014 iwamoto All Rights Reserved
 * *******************************************************************/
#define _XTAL_FREQ 4000000

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

#include <xc.h>

//******************* コンフィグレーション ****************************
#pragma config FOSC = INTOSC, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, CP = OFF
#pragma config CPD = OFF, BOREN = ON, CLKOUTEN = OFF, IESO = OFF, FCMEN = OFF
#pragma config WRT = OFF, PLLEN = OFF, STVREN = ON, BORV = LO, LVP = 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";

    OSCCON = 0b01101010;       // 内部クロック4Mhz
    PORTA = 0x00;
    TRISA = 0xFF;              // Port すべて入力
    ANSELA = 0x00;             // すべてデジタル
    WPUA   = 0xFF;             // 弱プルアップ ON
    nWPUEN = 0;
    // 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
}