PIC单片机之I2C(从模式)实例讲解

来源:网络

点击:1759

A+ A-

所属频道:新闻中心

关键词: PIC单片机,I2C

      网上有许多讲解单片机实现I2C主模式,但是从模式的很少。我现在就来讲讲PIC单片机使用MSSP模块实现I2C从模式。

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

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

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

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

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

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

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

    PIC单片机之I2C(从模式)实例讲解

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

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

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

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

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

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

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

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

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

    PIC单片机之I2C(从模式)实例讲解

      我们以写字节数据为例:

      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 ;

      #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;

      }

      }

      }
     

    (审核编辑: 智汇李)

    声明:除特别说明之外,新闻内容及图片均来自网络及各大主流媒体。版权归原作者所有。如认为内容侵权,请联系我们删除。