PIC16F　MSSPモジュール　I2Cマスター　送信　資料

# MSSPモジュール I2C通信作成資料
以前作成した、MSSPモジュール　I2Cマスターの基本動作を組み込んだ時の資料をまとめました。

データシートDS41391Bから、自分なりに読み込んだタイミングチャート。
![I2Cタイミングチャート.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/4675e4b1-4452-b6f8-6177-6df603ef73dd.jpeg)

上記チャートをフローに起こしてみました。
![MSSP1_1byteSend_フローチャート.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3693934/37b9c80a-8cf0-b899-7393-22937760d336.jpeg)


## PIC16F1827データシート　DS41391B
このデータシートをそのままC言語に翻訳する作業を淡々と行いました。
各々の状態遷移を複数の関数を作成することで、実行します。

:::note info 

# データシートP.268　29.6.6.4　Typical Transmit Sequence 
**１．スタートコンディションの発行**　SSP1CON2レジスタの`SENビット`をセット
**２．`SSP1IFビット`がセットされる。** スタートが完了したら、`SSP1IFビット`がセットされる。
**３．`SSP1IFビット`をユーザーがクリアする。**
**４．MSSPモジュールは、他の制御が起きる前に、スタートに必要な経過時間待つ。**
**５．ユーザーは、`SSP1BUF`にスレーブアドレスを書きこむ**
**６．SDAピンから、1ビットずつシフトしながら、スレーブアドレス8ビットがすべて出力される。**
**７．MSSPモジュールは、スレーブからのACKを受信し、その値を、`SSP1CON2のACKSTATビット`に格納する。**
**８．9クロック目の終わりに、MSSPモジュールは割込みを発生させる。** このとき、SSP1IFビットはセットされる。
**９．ユーザーは、データバイトを`SSP1BUF`に格納する**(次に出力するデータ)
**１０．8ビットすべてが送信されるまで、SDAピンからデータが1ビットずつ出力される。**
**１１．MSSPモジュールは、スレーブからのACKを受信し、その値を、`SSP1CON2のACKSTATビット`に格納する。**
**１２．すべてのデータを転送するまで、８から１１の動作をくりかえす。**
**１３．ユーザーは、`SSP1CON2のPENビットまたは、RSENビット`をセットすることで、ストップ、リスタートを生成することができます。ストップ、リスタートが生成されたら、割り込みが起こります。**
:::

# MSSPモジュール　I2Cマスター　送受信コード
```C:I2C_MSSP1.h
#ifndef I2C_MSSP1_H
#define	I2C_MSSP1_H
#include <xc.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>

#define _XTAL_FREQ  16000000

#ifdef	__cplusplus
extern "C" {
#endif
//-----------------------------------------------
#define I2C1_Ack   0//SSP1CON2.ACKDT master:receive mode
#define I2C1_NoAck 1//SSP1CON2.ACKDT master:receive mode
extern void I2C1_Reg_Init(void);
extern bool I2C1_Start(void);
extern bool I2C1_ReStart(void);
extern bool I2C1_Stop(void);
extern bool I2C1_Tx_Buffer_Write(uint8_t _byte_data);
extern uint8_t I2C1_Rx_Buffer_Read(void);
extern bool I2C1_Wait_Ack(void);
extern bool I2C1_Send_Ack(uint8_t _Ack_Nack);
extern bool I2C1_CheckIdle(void);
extern bool I2C1_ClearSSPxIF(void);
//------------------------------------------------
//-----------------------------------------------
extern bool I2C1_b1Write(uint8_t _device_add, uint8_t _data);
extern uint8_t I2C1_b2Write(uint8_t _device_add, uint8_t _data1, uint8_t _data2);
extern uint8_t I2C1_DataBuffer[10];
extern bool I2C1_bnWrite(uint8_t _device_add, uint8_t *_data, uint8_t _len);
extern uint8_t I2C1_b1Read(uint8_t _device, uint8_t _data1);
extern uint16_t I2C1_b2Read(uint8_t _device_add, uint8_t _data1);
extern bool I2C1_bnRead(uint8_t _device_add, uint8_t _data1,uint8_t _len);
//-----------------------------------------------
#ifdef	__cplusplus
}
#endif

#endif	/* I2C_MSSP1_H */
```

```C:I2C_MSSP1.c
#include "I2C_MSSP1.h"


uint8_t I2C1_DataBuffer[10];//読取りバッファ

//--------------------------------------------
//I2C1 MSSP1初期化
//--------------------------------------------
void I2C1_Reg_Init(void)
{
    SSP1STAT=0xC0;
    SSP1CON1=0x38;
    SSP1CON3=0x00;
    //SSP1ADD=0x50;//Fosc=16Mhz Fclock=50kHz
    SSP1ADD=0x27;//Fosc=16MHz Fclock=100kHz
    //SSP1ADD=0x09;//Fosc=16MHz Fclock=400kHz
    PIE1bits.SSP1IE=0;
}

//--------------------------------------------
//I2C1 MSSP1スタートコンディション発令
//--------------------------------------------
bool I2C1_Start(void)
{
    if(!I2C1_CheckIdle()) return false;
    SSP1CON2bits.SEN=1;
    if(!I2C1_ClearSSPxIF())return false;
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    return true;
}

//--------------------------------------------
//I2C1 MSSP1リスタートコンディション発令
//--------------------------------------------
bool I2C1_ReStart(void)
{
     //restart
    if(!I2C1_CheckIdle()) return false;
    SSP1CON2bits.RSEN=1;
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    return true;
    
}

//--------------------------------------------
//I2C1 MSSP1ストップコンディション発令
//--------------------------------------------
bool I2C1_Stop(void)
{
     if(!I2C1_CheckIdle()) return false;
    SSP1CON2bits.PEN=1;
    if(!I2C1_ClearSSPxIF())return false;
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    return true;
}

//--------------------------------------------
//I2C1 MSSP1　送信バッファ書込み
//--------------------------------------------
bool I2C1_Tx_Buffer_Write(uint8_t _byte_data)
{
    if(!I2C1_CheckIdle()) return false;
    SSP1BUF=_byte_data;
    if(!I2C1_ClearSSPxIF())return false;
    NOP();
    NOP();
    NOP();
    NOP();
    NOP();
    return true;
}

//--------------------------------------------
//I2C1 MSSP1 受信バッファ読み出し
//--------------------------------------------
uint8_t I2C1_Rx_Buffer_Read(void)
{
    uint8_t ret, cnt;
    ret=0xFF;
    cnt=0;
    if(!I2C1_CheckIdle()) return false;
    SSP1CON2bits.RCEN=1;
    while(!SSP1STATbits.BF){
        __delay_us(3);
        cnt++;
        if(cnt==100)return false;
    }
    if(!I2C1_CheckIdle()) return false;
    ret = SSP1BUF;
    if(!I2C1_ClearSSPxIF())return false;
    return ret;
}

//--------------------------------------------
//I2C1 MSSP1　ACK確認
//--------------------------------------------
bool I2C1_Wait_Ack(void)
{
    //while(SSP1CON2bits.ACKSTAT);
    if(SSP1CON2bits.ACKSTAT)
    {
        return false;//error
        
    }else
    {
        return true;//success
    }
}

//--------------------------------------------
//I2C1 MSSP1　ACK送信
//--------------------------------------------
bool I2C1_Send_Ack(uint8_t _Ack_Nack)
{
    if(!I2C1_CheckIdle()) return false;
    SSP1CON2bits.ACKDT=_Ack_Nack;
    SSP1CON2bits.ACKEN=1;   
    if(!I2C1_ClearSSPxIF())return false;
    return true;
}

//--------------------------------------------
//I2C1 MSSP1　アイドリングチェック
//--------------------------------------------
bool I2C1_CheckIdle(void)
{
    uint8_t cnt=0;
    while(SSP1STATbits.R_nW || SSP1CON2 & 0x1F)
    {
    /*    __delay_us(2);
        cnt++;
        if(cnt==100) 
            return false;*/
    };//MSSP1 is idle mode
    return true;
}

//--------------------------------------------
//I2C1 MSSP1 SSP1IFフラグクリア
//--------------------------------------------
bool I2C1_ClearSSPxIF(void)
{
    uint8_t cnt=0;
    while(!PIR1bits.SSP1IF)
    {
    /*    __delay_us(2);
        cnt++;
        if(cnt==100)
            return false;*/
    };
    PIR1bits.SSP1IF=0;
    return true;
}


//-----------------------------------------------------------------


//----------------------------------------------------
//  I2C1 MSSP1 1バイト送信
//_device_add:I2Cスレーブアドレス
//_data:送信データ
//----------------------------------------------------
bool I2C1_b1Write(uint8_t _device_add, uint8_t _data)
{  
    //start condition
    I2C1_Start();
    //send device address
    I2C1_Tx_Buffer_Write(_device_add);
    if(!I2C1_Wait_Ack())
        return false;
    //send data
    I2C1_Tx_Buffer_Write(_data);
    if(!I2C1_Wait_Ack())
        return false;
    //Stop condition
    I2C1_Stop();
    return true;
}

//----------------------------------------------------
//  I2C1 MSSP1 2バイト送信
//_device_add:I2Cスレーブアドレス
//_data1:送信データ
//_data2:送信データ
//----------------------------------------------------
uint8_t I2C1_b2Write(uint8_t _device_add, uint8_t _data1, uint8_t _data2)
{
    //start condition
    I2C1_Start();
    //send device address
    I2C1_Tx_Buffer_Write(_device_add);
    if(!I2C1_Wait_Ack())
    {
        return 0xF1;
        //return false;
    }
    //send data
    I2C1_Tx_Buffer_Write(_data1);
    if(!I2C1_Wait_Ack())
    {    
        return 0xF2;
        //return false;
    }
        //send data
    I2C1_Tx_Buffer_Write(_data2);
    if(!I2C1_Wait_Ack())
    {
        return 0xF3;
        //return false;
    }
    //Stop condition
    I2C1_Stop();
    return true;
}

//----------------------------------------------------
//  I2C1 MSSP1 nバイト送信
//_device_add:I2Cスレーブアドレス
//_data:送信データ先頭アドレス
//_len:送信長
//----------------------------------------------------
bool I2C1_bnWrite(uint8_t _device_add, uint8_t *_data, uint8_t _len)
{
    //start condition
    I2C1_Start();
    //send device address
    I2C1_Tx_Buffer_Write(_device_add);
     if(!I2C1_Wait_Ack())
        return false;
    //send data
    do{
        I2C1_Tx_Buffer_Write(*_data);
        if(!I2C1_Wait_Ack())
        return false;
        _data++;
    }while(--_len);
    //Stop condition
    I2C1_Stop();
    return true;
}

//----------------------------------------------------
//  I2C1 MSSP1 １バイト受信
//_device_add:I2Cスレーブアドレス
//_data1:送信データ
//戻り値：受信バイトデータ
//----------------------------------------------------
uint8_t I2C1_b1Read(uint8_t _device_add, uint8_t _data1)
{
    uint8_t ret;
    //Start Condition
    I2C1_Start();
     //send device address
    I2C1_Tx_Buffer_Write(_device_add);
     if(!I2C1_Wait_Ack())
        return false;
    //send data
    I2C1_Tx_Buffer_Write(_data1);
     if(!I2C1_Wait_Ack())
        return false;
    //restart
    I2C1_ReStart();
      //send device address
    I2C1_Tx_Buffer_Write(_device_add|0x01);
     if(!I2C1_Wait_Ack())
        return false;
    //recieve data
    ret=I2C1_Rx_Buffer_Read();
    //send Nack
    I2C1_Send_Ack(I2C1_NoAck);
    //Stop Condition
    I2C1_Stop();
    return ret;
}

//----------------------------------------------------
//  I2C1 MSSP1 2バイト受信
//_device_add:I2Cスレーブアドレス
//_data1:送信データ
//戻り値：２バイトデータ
//----------------------------------------------------
uint16_t I2C1_b2Read(uint8_t _device_add, uint8_t _data1)
{
    uint16_t ret;
    //Start Condition
    I2C1_Start();
     //send device address
    I2C1_Tx_Buffer_Write(_device_add);
     if(!I2C1_Wait_Ack())
        return false;
    //send data
    I2C1_Tx_Buffer_Write(_data1);
     if(!I2C1_Wait_Ack())
        return false;
    //restart
    I2C1_ReStart();
    //send device address
    I2C1_Tx_Buffer_Write(_device_add|0x01);
     if(!I2C1_Wait_Ack())
        return false;
    //recieve data
    ret=I2C1_Rx_Buffer_Read();
    ret<<=8;
    //send Ack
    I2C1_Send_Ack(I2C1_Ack);
    //recieve data
    ret|=I2C1_Rx_Buffer_Read();
    //send Nack
    I2C1_Send_Ack(I2C1_NoAck);
    //Stop Condition
    I2C1_Stop();
    return ret;
}

//----------------------------------------------------
//  I2C1 MSSP1 nバイト受信
//_device_add:I2Cスレーブアドレス
//_data1:送信データ
//_len:受信長
//戻り値：受信の成否
//----------------------------------------------------
bool I2C1_bnRead(uint8_t _device_add, uint8_t _data1,uint8_t _len)
{
    uint8_t index=0;
    
    //Start Condition
    I2C1_Start();
     //send device address
    I2C1_Tx_Buffer_Write(_device_add);
     if(!I2C1_Wait_Ack())
        return false;
    //send data
    I2C1_Tx_Buffer_Write(_data1);
     if(!I2C1_Wait_Ack())
        return false;
    //restart
    I2C1_ReStart();
      //send device address
    I2C1_Tx_Buffer_Write(_device_add|0x01);
     if(!I2C1_Wait_Ack())
        return false;
    //recieve data
    do{
        I2C1_DataBuffer[index++]=I2C1_Rx_Buffer_Read();
        if(_len!=1)
        {
            I2C1_Send_Ack(I2C1_Ack);
        }
        _len--;
    }while(_len!=0);
    //send Nack
    I2C1_Send_Ack(I2C1_NoAck);
    //Stop Condition
    I2C1_Stop();
    return true;
}
```