您的位置:首页 > 其它

PIC单片机之I2C通信(从模式)

2016-06-16 14:14 295 查看
网上有许多讲解单片机 实现I2C主模式,但是从模式的很少。我现在就来讲讲PIC单片机使用MSSP模块实现I2C从模式。

    有关I2C协议的具体介绍可以看 《PIC单片机之I2C(主模式)》,我们这里直接讲解实例

    实例讲解:我们模仿 AT24C02 EEPROM 的协议。让一个主模式的单片机,来读取从模式单片机的数据。 

      下面为AT24C02的随机地址读取的协议。

           第一个字节 :输入7位地址和一位的写状态位,

           第二个字节:然后写入EEPROM数据地址,

           第三个字节:输入7位地址和一位的读状态位,

           第四~N个字节:读出的EEPROM的数据。

     


       我们来讲解下程序的基本思路:我们使能了MSSP中断,即是I2C接收中断,当PIC单片机接收到一个数据后就会产生中断。那是接收到设备地址,还是接收到数据,由SSP1STAT寄存器的状态位来判断。

需要判断的状态位分别是 :

       数据和地址:  用来判断接收到是地址还是数据

       启动位:         用来判断是否接收到启动位

       读写:             用来判断是写状态还是读状态。

       缓存满:        用来判断缓冲区是否满

    我们以随机地址读取为例:讲讲程序执行的过程

     1,从单片机接收到启示位和设备地址中断:我们判断SSP1STAT的状态位为(写状态,地址,缓存满,接收到启示位) 然后读取缓存中的设备地址, 接着在读取 需要读/写的数据地址。

     2,单片机再次接收到设备地址:我们判断是SSP1STAT的状态为(读状态)然后从设备就输出数据



   我们以写字节数据为例:

1,从单片机接收到启示位和设备地址中断:我们判断SSP1STAT的状态位为(写状态,地址,缓存满,接收到启示位) 然后读取缓存中的设备地址, 接着在读取 需要读/写的数据地址。

  2,单片机判断SSP1STAT的状态位为(写状态,数据,缓存满)那么单片机就接收输入的数据。

     初始化设置:

     1,设置I2C通信的两引脚为CLK SCL为输入,

          TRISB6 = input;

          TRISB4 = input;

     2,将MSSP设置为I2C从模式,七位从地址

           SSP1CONbits.SSPM0 = 0;

           SSP1CONbits.SSPM1 = 1;

           SSP1CONbits.SSPM2 = 1;

           SSP1CONbits.SSPM3 = 0;// I2C slave mode ,7bit address

      3,使能CLK时钟

        SSP1CONbits.CKP = 1; // enable clock

      4,设置从设备地址为 0xA0

      SSP1ADD =0xA0;       //slave address is 0xa0

      5,开启I2C

      SSP1CONbits.SSPEN=1;//enable I2c

      6,清楚状态标志

      SSPSTAT=0;

     7,使能I2C中断

     PIE1bits.SSP1IE = 1;//Enabe interrupt MSSP

     INTCONbits.PEIE = 1;

     INTCONbits.GIE =  1;

      

    如果你要使用PIC单片机I2C从模式只要使用下面的代码:

  将void i2c_salve_interrupt_tx();void i2c_salve_interrupt_rx();放到中断程序中,如下:

void interrupt isr(void)

{

      if(SSP1IE && SSP1IF)

   {

        i2c_salve_interrupt_tx();

        i2c_salve_interrupt_rx();

        SSP1IF=0;

   }

}

 将初始化函数init_i2c_slave();放到主函数中

void main()

{

  init_i2c_slave();

}

头文件 :i2c_salve.h

#ifndef _I2C_SALVE_H

#define _I2C_SALVE_H

void init_i2c_slave();

void i2c_salve_interrupt_tx();

void i2c_salve_interrupt_rx();

#endif

代码:i2c_salve.c

   #include<pic.h>;

#define input  1

#define  RX_BUF_LEN  29

#define  while_delay 6000

unsigned char i2c_address,word_address,Register[29];

unsigned  char RANDOM_READ,i2c_counter;

extern unsigned char A_readflag;

/*I2C SALVE */

void init_i2c_slave()

{

    TRISB6 = input;

    TRISB4 = input;

    SSP1CONbits.SSPM0 = 0;

    SSP1CONbits.SSPM1 = 1;

    SSP1CONbits.SSPM2 = 1;

    SSP1CONbits.SSPM3 = 0;// I2C slave mode ,7bit address

    SSP1CONbits.CKP = 1; // enable clock

    SSP1ADD =0xA0;       //slave address is 0xa0

    SSP1CONbits.SSPEN=1;//enable I2c

    SSPSTAT=0;

    PIE1bits.SSP1IE = 1;//Enabe interrupt MSSP

    INTCONbits.PEIE = 1;

    INTCONbits.GIE =  1;

}

/*I2C salve mode interrupt */

void i2c_salve_interrupt_tx()//master read

{

    unsigned char Temp;

    unsigned int  timercounter;

    Temp=SSP1STAT;

    Temp &= 0x2D;

    if(SSP1STATbits.R_nW ==1)//Read operation.

    {

                A_readflag=0;

              SSP1IF = 0;

              i2c_address =  SSP1BUF;

              i2c_counter = word_address;

             while(i2c_counter < RX_BUF_LEN)

             {

               SSP1BUF=Register[i2c_counter];//send data

               SSP1CONbits.CKP=1;// enable colck

               timercounter=while_delay;

             while(PIR1bits.SSP1IF == 0)

               {

                 timercounter--;

                 if(timercounter==0)

                 {

                     return;

                 }

                }//waiting for ~ACK

               SSP1IF = 0;

             if(SSP1CON2bits.ACKSTAT == 1)

              {

                return ; //NOACK

               }

               else

              {

              i2c_counter++;//ACK

            

               }

             }

            SSP1IF = 0;

    }

 }

 

void i2c_salve_interrupt_rx()//master writer

{

    unsigned char rx_status;

    unsigned char Temp;

    unsigned int  timercounter;

    rx_status=false;

    Temp=SSP1STAT;

    Temp &= 0x2D;

    if(Temp==0x09)//Write operation,last byte was an address,buffer is full

    {

         SSP1IF = 0;

         i2c_address =  SSP1BUF;

         timercounter=while_delay;

          while(PIR1bits.SSP1IF == 0)

          {

              timercounter--;

              if(timercounter==0)

               {

                     return ;

               }

          }//waiting for send ~ACK

          SSP1IF = 0;

          word_address = SSP1BUF;

          return ;

    }

    if(Temp==0x29)//Write operation,last byte was data,buffer is full

    {

        

        SSP1IF=0;

        Register[word_address]=SSP1BUF;

        word_address++;

        if(word_address>=RX_BUF_LEN)

            {

                word_address=0;

            }

    }

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: