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?

PIC16F1827 I2C slaveサイド 2バイト受信

Last updated at Posted at 2024-07-24

24.11.16 訂正:slave割込みのフラグチェックを追加。

masterサイドで、コントローラの16bits押下データを取得。2バイトデータとして、slaveサイドにI2Cを通じて送信。送信側、受信側ともにおなじLEDを点灯させています。

microchipのforumに、MSSP I2C Slaveの情報があります。
題名:I2C Slave problem
https://forum.microchip.com/s/topic/a5C3l000000Mf1lEAC/t387764

もっとわかりやすいコード。
note:ESP32とPICをI2Cで繋いでみる(その2)PICにデータを転送
https://note.com/khe00716/n/nb5486d214d9b#wcQk4

以下の設定で、スレーブとして動作しています。

・スレーブアドレス:0x32
・2バイトを受信。受信データから16ビットデータを再構成。
・割り込み処理関数の中でスレーブ受信対応処理。
・LEDの点滅は、受信処理が終わってから、フラグで、mainループ内処理。

※MSSPモジュールI2Cとして機能させるため、SCL,SDAピンを入力に設定すること。

Masterサイドのコード

スレーブアドレス(0x32)に、ボタン押下状況をしめす2バイトデータを送信します。

I2C_MSSP1.c

// PIC16F1827 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1
//#pragma config FOSC = HS      // Oscillator Selection (HS Oscillator, High-speed crystal/resonator connected between OSC1 and OSC2 pins)
#pragma config FOSC = INTOSC    // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON        // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = ON       // PLL Enable (4x PLL enabled)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP =ON      // Low-Voltage Programming Enable (Low-voltage programming enabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>
#include <stdlib.h>
#include <stdio.h>
#include "Interrupt.h"
#include "Peripheral.h"
#include "I2C_MSSP1.h"
#include "LCDdriver.h"
#include "famicon.h"

#define _XTAL_FREQ  16000000

void Oscillator_Init(void);
void Port_Init(void);

void main(void)
{    
    uint8_t cnt=0;
    uint8_t i,j,temp;
    uint16_t buttonState;
    uint8_t  direction;
    
    //Basic Hard Initialize
    Oscillator_Init();
    Port_Init(); 
    //Peripheral 
    Timer0_INIT();
    Timer2_INIT();
    USART_INIT();
    ADC_INIT();
    I2C1_Reg_Init();
    LCD_Init(LcdDeviceAdd);
    SSP1ADD=0x09;  //Fosc=16MHz Fclock=400kHz
    LCD_Printf(LcdDeviceAdd, "HostSide",8,0x80);
    
    famiconInit();
    //割り込み許可
    Interrupt_START();
    direction=false;
    while(1)
    {
        //USART interrupt processing
        if(usart.rxCompleted)
        {
            usart.rxCompleted=false;
            printf("%s\n",usart.rxBuf);
            usart.length=0;
            PIE1bits.RCIE=1;
        }
        
        //Timer0 interrupt processing
        if(tm0.up)
        {
            tm0.up=false;
            //LATBbits.LATB0=~LATBbits.LATB0;
            //printf("%d\n",cnt++);
            if(ADC.Completed)
            {
                ADC.Completed=false;
                //printf("%d\n", ADC.data[0]);
                PIE1bits.ADIE=1;
                PIE1bits.TMR2IE=1;
            }
            INTCONbits.TMR0IE=1;
        }
        
        buttonState = getButton();
        //buttonState = (uint16_t)strtol(usart.rxBuf,NULL,16);
        if((buttonState&0x0200)==0x0)//Left
        {
            printf("%02X\n",buttonState);            
            I2C1_b2Write(0x32,0xFD,0xF0);
            __delay_ms(50);
            LATBbits.LATB0=1;
        }
        
        if((buttonState&0x0100)==0x0)//Right
        {
            printf("%02X\n",buttonState);                
            I2C1_b2Write(0x32,0xFE,0xF0);
            __delay_ms(50);
            LATBbits.LATB3=1;
        }
        
        if((buttonState&0x8000)==0x0)
        {
            //printf("B ");
            I2C1_b2Write(0x32,0x7F,0xF0);
            LATBbits.LATB7=1;
            __delay_ms(50);
        }

        if((buttonState&0x4000)==0x0)
        {
            //printf("Y ");
            I2C1_b2Write(0x32,0xBF,0xF0);
            LATBbits.LATB6=1;
            __delay_ms(50);
        }
        
        if((buttonState&0x0080)==0x0)
        {
            //printf("A ");
            I2C1_b2Write(0x32,0xFF,0x70);
            LATBbits.LATB3=1;
            __delay_ms(50);
        }

        if((buttonState&0x0040)==0x0)
        {
            //printf("X ");
            I2C1_b2Write(0x32,0xFF,0xB0);
            LATBbits.LATB0=1;
            __delay_ms(50);
        }
        if(buttonState==0xFFF0)
        {
            I2C1_b2Write(0x32,0xFF,0xF0);
            __delay_ms(50);
            LATBbits.LATB0=0;
            LATBbits.LATB3=0; 
            LATBbits.LATB6=0;
            LATBbits.LATB7=0;  
        }
    }
    return;
}

void Oscillator_Init(void)
{
    OSCCONbits.SPLLEN=0;
    OSCCONbits.IRCF=0b1111;//16Mhz
    OSCCONbits.SCS=0b10;//InternalOscillator
}

void Port_Init(void)
{
    TRISA=0x00;
    ANSELA=0x00;
    TRISB=0x04;     //RX:RB2
    ANSELB=0x00;
    PORTA=0x00;
    PORTB=0x00;  
    //Altanative Pin Selective
    APFCON0bits.RXDTSEL=1;  //RX:RB2
    APFCON1bits.TXCKSEL=1;  //TX:RB5
    //I2C1
    TRISBbits.TRISB1=1;//SDA:RB1
    TRISBbits.TRISB4=1;//SCL:RB4
}

void delay_ms(uint16_t time)
{
    uint16_t t;
    for(t=0; t<time; t++)
        __delay_ms(1);
}

Slaveサイドのコード

MSSPの割り込みイベントで処理していきます。
受信終了、ストップコードが発行されたら、main内で、LED点灯処理を行っています。

I2C_MSSP1_SLAVE_H

#ifndef I2C_MSSP1_SLAVE_H
#define	I2C_MSSP1_SLAVE_H

#ifdef	__cplusplus
extern "C" {
#endif

typedef struct
{
    uint8_t index;
    uint8_t rxData[10];
    uint8_t txData[10];
    uint8_t cnt1;
    uint8_t cnt2;
    bool    flag;
}_i2cStruct;

extern _i2cStruct i2cInfo;

void I2C1_Reg_Init_Slave(void);
void I2C1_Slave_Interrupt(void);


#ifdef	__cplusplus
}
#endif

#endif	/* I2C_MSSP1_SLAVE_H */
I2C_MSSP1_SLAVE.c
#include "Peripheral.h"
#include "I2C_MSSP1_Slave.h"

_i2cStruct i2cInfo;

///I2C MSSPモジュール初期化 スレーブモード
void I2C1_Reg_Init_Slave(void)
{
    uint8_t val;
    SSP1STAT=0xC0;
    SSP1CON1=0x36;          //slave mode , 7bit address
    //SSP1CON1=0x3E;        //slave mode , 7bit address with interrupts
    SSP1CON2bits.SEN=1;     //0:Clock stretching is disable
    SSP1CON3bits.PCIE=0;
    SSP1CON3bits.SCIE=0;
    SSP1CON3bits.AHEN=0;
    SSP1CON3bits.DHEN=0;
    SSP1ADD=0x32;
    val=SSP1BUF;
    PIE1bits.SSP1IE=1;
   
}


///MSSPモジュール I2Cスレーブモード割込み処理
void I2C1_Slave_Intterrupt(void)
{
    uint8_t I2c1stat,i,buf;
    //---------MSSP1 ステータス読み出し---------
        PIR1bits.SSP1IF=0;
        I2c1stat=SSP1STAT & 0b00111101;
        
        /*1.--------I2c Writeモード 
                 スタートコンディション検出&スレーブアドレス読み出し--------- */
        if(I2c1stat==0b00001001)
        {
            i2cInfo.index=0;
            for(i=0; i<=3; i++) i2cInfo.rxData[i]=0;
            i2cInfo.rxData[i2cInfo.index++]=SSP1BUF;    
            if(SSP1CON2bits.SEN==1)
                    SSP1CON1bits.CKP=1;
        }
        /*2.--------I2c Writeモード 受信データバイト読み出し---------*/
        if(I2c1stat==0b00101001)
        {
            i2cInfo.rxData[i2cInfo.index++]=SSP1BUF;
            if(i2cInfo.index==3)
            {
               i2cInfo.flag=true;//mainループで処理。
            }
            if(SSP1CON2bits.SEN==1)
                SSP1CON1bits.CKP=1;
        }
        /*3.--------I2c Readモード スタートコンディション検出&
                            データバイトバッファ出力 送信(アドレス部)--------- */
        if(I2c1stat==0b00001101)
        {
           
        }
        /*4.--------I2c Readモード データバイトバッファ出力 送信(データ部)---------*/
        if(I2c1stat==0b00101100)
        {
           
        }
        /*5-1.--------I2c Writeモードストップビット検知---------*/
        if(I2c1stat==0b00110000)
        {
            
            if(SSP1CON2bits.SEN==1)
            {
                SSP1CON1bits.CKP=1;
            }
        }
        /*5-2.---------I2c Readモードストップビット検知---------*/
        if(I2c1stat==0b00110100)
        {
             if(SSP1CON2bits.SEN==1)
                SSP1CON1bits.CKP=1;               
        }
}
interrupt.c
#include <pic16f1827.h>
#include "Peripheral.h"
#include "Interrupt.h"
#include "I2C_MSSP1_Slave.h"

void __interrupt()isr()
{
    uint8_t ch;
    
    //USART受信割り込み処理
    if(PIE1bits.RCIE==1 &&  PIR1bits.RCIF)
    {
        PIR1bits.RCIF=0;
        ch = getch();
        usart.rxBuf[usart.length++]=ch;
        if(usart.length>=rxLength)
        {
            usart.length=0;
        }
        if(ch==0x0A)
        {//CR,LF受信
            usart.rxCompleted=true;
            usart.rxBuf[usart.length-2]=0x00;
            PIE1bits.RCIE=0;
        }
    }
    
    //Timer0割り込み処理
    if(INTCONbits.TMR0IE==1 && INTCONbits.TMR0IF )
    {
        INTCONbits.TMR0IF=0;
        tm0.cnt++;
        if(tm0.cnt==20)
        {
            tm0.cnt=0;
            INTCONbits.TMR0IE=0;
            tm0.up=true;
        }
        TMR0=0x63;
    }
 
    //Timer2割り込み処理 A/D変換トリガー
    if(PIE1bits.TMR2IE == 1 && PIR1bits.TMR2IF)
    {
        PIR1bits.TMR2IF=0;
        ADCON0bits.ADGO=1;
       // while(ADCON0bits.ADGO);
    }
    
    //AD変換割り込み処理
    if(PIE1bits.ADIE==1 && PIR1bits.ADIF)
    {
        PIR1bits.ADIF = 0;
        ADC.data[0]=ADRESH;
        ADC.data[0]<<=8;
        ADC.data[0]|=ADRESL;
        PIE1bits.ADIE = 0;
        PIE1bits.TMR2IE=0;
        ADC.Completed = true;
    }

    if(PIR1bits.SSP1IF)//修正24.11.17
    I2C1_Slave_Interrupt();
}

main.c

// PIC16F1827 Configuration Bit Settings

// 'C' source line config statements

// CONFIG1
//#pragma config FOSC = HS      // Oscillator Selection (HS Oscillator, High-speed crystal/resonator connected between OSC1 and OSC2 pins)
#pragma config FOSC = INTOSC    // Oscillator Selection (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON        // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PLLEN = ON       // PLL Enable (4x PLL enabled)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LVP =ON      // Low-Voltage Programming Enable (Low-voltage programming enabled)

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

#include <xc.h>
#include <stdlib.h>
#include <stdio.h>
#include "Interrupt.h"
#include "Peripheral.h"
#include "I2C_MSSP1_Slave.h"
#include "famicon.h"


#define _XTAL_FREQ  16000000

void Oscillator_Init(void);
void Port_Init(void);

void main(void)
{    
    uint8_t cnt=0;
    uint8_t i,j,temp;
    uint16_t buttonState;
    uint8_t  direction;
    
    //Basic Hard Initialize
    Oscillator_Init();
    Port_Init(); 
    //Peripheral 
    //Timer0_INIT();
    Timer2_INIT();
    USART_INIT();
    //ADC_INIT();
    I2C1_Reg_Init_Slave();
    
    //famiconInit();
    //割り込み許可
    Interrupt_START();
    direction=false;
    while(1)
    {
        //USART interrupt processing
        if(usart.rxCompleted)
        {
            usart.rxCompleted=false;
            printf("%s\n",usart.rxBuf);
            usart.length=0;
            PIE1bits.RCIE=1;
        }
        
        if(i2cInfo.flag)
        {
            i2cInfo.flag=false;
            //buttonState = getButton();
            //buttonState = (uint16_t)strtol(usart.rxBuf,NULL,16);
            buttonState = i2cInfo.rxData[1];
            buttonState <<=8;
            buttonState |= i2cInfo.rxData[2];
            //printf("rcvData: %X %X\n",rcvdata[1],rcvdata[2]);
            //printf("RES:%02X\n",buttonState);
             if((buttonState&0x0200)==0x0)//Left
            {               
                LATBbits.LATB0=1;
            }

            if((buttonState&0x0100)==0x0)//Right
            {               
                LATBbits.LATB3=1;
            }

            if((buttonState&0x8000)==0x0)
            {    
                //printf("B ");
                LATBbits.LATB7=1;               
            }

            if((buttonState&0x4000)==0x0)
            {      
                //printf("Y ");
                LATBbits.LATB6=1;                
            }

            if((buttonState&0x0080)==0x0)
            {            
                //printf("A ");
                LATBbits.LATB3=1;
            }

            if((buttonState&0x0040)==0x0)
            {
                //printf("X ");
                LATBbits.LATB0=1;
            }
            
            if(buttonState==0xFFF0)
            {
                LATBbits.LATB0=0;
                LATBbits.LATB3=0; 
                LATBbits.LATB6=0;
                LATBbits.LATB7=0;  
            }
        }
    }
    return;
}

void Oscillator_Init(void)
{
    OSCCONbits.SPLLEN=0;
    OSCCONbits.IRCF=0b1111;//16Mhz
    OSCCONbits.SCS=0b10;//InternalOscillator
}

void Port_Init(void)
{
    TRISA=0x00;
    ANSELA=0x00;
    TRISB=0x04;     //RX:RB2
    ANSELB=0x00;
    PORTA=0x00;
    PORTB=0x00;  
    //Altanative Pin Selective
    APFCON0bits.RXDTSEL=1;  //RX:RB2
    APFCON1bits.TXCKSEL=1;  //TX:RB5
    //I2Cinitialize
    TRISBbits.TRISB1=1;     //RB1
    TRISBbits.TRISB4=1;     //RB4
}


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?