0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

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

Posted at

MSSPモジュール I2C通信作成資料

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

データシートDS41391Bから、自分なりに読み込んだタイミングチャート。
I2Cタイミングチャート.jpg

上記チャートをフローに起こしてみました。
MSSP1_1byteSend_フローチャート.jpg

PIC16F1827データシート DS41391B

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

データシートP.268 29.6.6.4 Typical Transmit Sequence

1.スタートコンディションの発行 SSP1CON2レジスタのSENビットをセット
2.SSP1IFビットがセットされる。 スタートが完了したら、SSP1IFビットがセットされる。
3.SSP1IFビットをユーザーがクリアする。
4.MSSPモジュールは、他の制御が起きる前に、スタートに必要な経過時間待つ。
5.ユーザーは、SSP1BUFにスレーブアドレスを書きこむ
6.SDAピンから、1ビットずつシフトしながら、スレーブアドレス8ビットがすべて出力される。
7.MSSPモジュールは、スレーブからのACKを受信し、その値を、SSP1CON2のACKSTATビットに格納する。
8.9クロック目の終わりに、MSSPモジュールは割込みを発生させる。 このとき、SSP1IFビットはセットされる。
9.ユーザーは、データバイトをSSP1BUFに格納する(次に出力するデータ)
10.8ビットすべてが送信されるまで、SDAピンからデータが1ビットずつ出力される。
11.MSSPモジュールは、スレーブからのACKを受信し、その値を、SSP1CON2のACKSTATビットに格納する。
12.すべてのデータを転送するまで、8から11の動作をくりかえす。
13.ユーザーは、SSP1CON2のPENビットまたは、RSENビットをセットすることで、ストップ、リスタートを生成することができます。ストップ、リスタートが生成されたら、割り込みが起こります。

MSSPモジュール I2Cマスター 送受信コード

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 */
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 1バイト受信
//_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:送信データ
//戻り値:2バイトデータ
//----------------------------------------------------
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;
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?