PICでI2Cを試す(マスター編)

PICでI2Cのマスター側のテスト。
この前作ったスレーブ側のデータ・ダンプ・デバイスに適当なデータを送ってみる。

PIC16F1938でI2Cのマスター

PIC16F1938でI2Cのマスター

アドレス:0x20
データ:0x00, 0x88の2バイト

ソースコードは後閑さんのサイトを参考に書きました。
一度、0x20に0x00, 0x88を送り、その際の割り込みのSSPSTATのログを録り、そのログを0x20に送ることで、マスター側の割り込みのSSPSTATを見ることができる。

/* 
 * File:   main.c
 * Author: sakai
 *
 * Created on 2015/05/16, 23:04
 */

#include <stdio.h>
#include <stdlib.h>
#include <xc.h>

#define _XTAL_FREQ  32000000

#pragma config FOSC = INTOSC  // INTOSCIO
#pragma config CLKOUTEN = OFF
#pragma config FCMEN = OFF
#pragma config IESO = OFF
#pragma config MCLRE = ON
#pragma config BOREN = ON   // Brown Out Detect
#pragma config WDTE = OFF
#pragma config CPD = OFF    // Data Code Protection bit
#pragma config CP = OFF
#pragma config PWRTE = ON
#pragma config PLLEN = OFF
#pragma config STVREN = ON
#pragma config WRT = OFF
#pragma config BORV = HI
#pragma config LVP = OFF

#define I2C_DEBUGGER_ADDRESS    (0x20)

#define I2C_IDLE_PORT   (PORTBbits.RB0)

#define MAX_BUFF    (32)

typedef unsigned char byte;

byte logging = 0;
byte data[MAX_BUFF];
byte dindex = 0;

static void interrupt intr(void) {
    // 割り込み
    if (SSPIF == 1) {
        if (logging) {
            data[dindex] = SSPSTAT;
            dindex++;
        }
        PORTAbits.RA5 = 1;
        SSPIF = 0; // クリア
    }
}

void i2c_idle() {
    while (SSPCON2bits.SEN || SSPCON2bits.RSEN || SSPCON2bits.PEN ||
           SSPCON2bits.RCEN || SSPCON2bits.ACKEN || SSPSTATbits.R_nW) {
        I2C_IDLE_PORT = 0;
    }
    I2C_IDLE_PORT = 1;
}

/*
 * 
 */
int main(int argc, char** argv) {
    OSCCON = 0b11110000;
    // A, Bポートの設定
    ANSELA = 0;
    ANSELB = 0;
    TRISA = 0b00000000;
    TRISB = 0b00000000;
    PORTA = 0b00000000;
    PORTB = 0b00000000;

    // I2Cマスターの設定
    SSPSTAT = 0b00000000;
    SSPCON1 = 0b00101000;   // SSPEN=1, SSPM<3:0>=FOSC/4*(SSPADD+1) SSPADD=19
    SSPCON2 = 0b00000000;
    SSPCON3 = 0b00000000;
    SSPADD  = 19;           // 400kHz

    // 割り込み
    PIE1    = 0b00001000;   // SSPIE=1
    PIE2    = 0b00001000;   // BCLIE=1
    PIE3    = 0b00000000;
    INTCON  = 0b11000000;   // GIE, PEIE

    PORTBbits.RB0 = 1;
    PORTBbits.RB1 = 1;
    PORTBbits.RB2 = 1;
    PORTBbits.RB3 = 1;
    PORTBbits.RB4 = 1;
    PORTBbits.RB5 = 1;
    PORTAbits.RA7 = 1;

    byte count = 0;
    logging = 1;

    i2c_idle();
    SSPCON2bits.SEN = 1;    // スタートコンディション
    while (SSPCON2bits.SEN) ;
    SSPBUF = I2C_DEBUGGER_ADDRESS<<1;
    while (SSPSTATbits.BF) ;
    while (SSPCON2bits.ACKSTAT) PORTAbits.RA7 = 1;
    PORTAbits.RA7 = 0;
    i2c_idle();
    SSPBUF = 0x00;
    while (SSPSTATbits.BF) ;
    while (SSPCON2bits.ACKSTAT) PORTAbits.RA7 = 1;
    PORTAbits.RA7 = 0;
    i2c_idle();
    SSPBUF = 0x88;
    while (SSPSTATbits.BF) ;
    while (SSPCON2bits.ACKSTAT) PORTAbits.RA7 = 1;
    PORTAbits.RA7 = 0;
    i2c_idle();
    SSPCON2bits.PEN = 1;    // ストップコンディション
    while (SSPCON2bits.PEN) ;

    logging = 0;
    for (count = 0; count < 45; count++) {  // 45秒待ち
        __delay_ms(1000);
    }

    i2c_idle();
    SSPCON2bits.SEN = 1;    // スタートコンディション
    while (SSPCON2bits.SEN) ;
    SSPBUF = I2C_DEBUGGER_ADDRESS<<1;
    while (SSPSTATbits.BF) ;
    while (SSPCON2bits.ACKSTAT) PORTAbits.RA7 = 1;
    PORTAbits.RA7 = 0;
    count = 0;
    while (count < dindex) {
        i2c_idle();
        SSPBUF = data[count];
        while (SSPSTATbits.BF) ;
        while (SSPCON2bits.ACKSTAT) PORTAbits.RA7 = 1;
        PORTAbits.RA7 = 0;
        count++;
    }
    i2c_idle();
    SSPCON2bits.PEN = 1;    // ストップコンディション
    while (SSPCON2bits.PEN) ;

    while (1) {
        PORTAbits.RA0 = 1;
        __delay_ms(50);
        PORTAbits.RA0 = 0;
        __delay_ms(50);
    }

    return (EXIT_SUCCESS);
}

最初の0x20デバイスの表示は
0x08, 0x28, 0x09, 0x40, 0x29, 0x00, 0x29, 0x88, 0x30

その後は、
0x0E, 0x28, 0x09, 0x40, 0x29, 0x08, 0x29, 0x08, 0x29, 0x08, 0x29, 0x08, 0x29, 0x10, 0x30

マスター側でのログとしては、
0x08, 0x08, 0x08, 0x08, 0x10

これはスタートコンディションがあった(×4)、ストップコンディションがあった(×1)という単純なもの。

アドレスを間違えると…
最初、うまく動かなくて原因を調べてみたら、アドレスを間違えて0x28を指定していた。
すると、アドレスを送って、その次のデータ0x00を送信した後の
while (SSPCON2bits.ACKSTAT) PORTAbits.RA7 = 1;
の行で無限ループしていた。
アドレス送信時のACKは誰が返しているのか?と思った。

カテゴリー: PIC, 作ったモノ, 作業 タグ: , パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

CAPTCHA