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

2019-08-09来源: eefocus关键字:PIC单片机  I2C通信  从模式

网上有许多讲解单片机 实现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;
#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;
            }
    }


}


关键字:PIC单片机  I2C通信  从模式 编辑:什么鱼 引用地址:http://news.eeworld.com.cn/mcu/ic470558.html 本网站转载的所有的文章、图片、音频视频文件等资料的版权归版权所有人所有,本站采用的非本站原创文章及图片等内容无法一一联系确认版权者。如果本网所选内容的文章作者及编辑认为其作品不宜公开自由传播,或不应无偿使用,请及时通过电子邮件或电话通知我们,以迅速采取适当措施,避免给双方造成不必要的经济损失。

上一篇:PIC单片机实现二进制码与压缩BCD码的相互转换
下一篇:PIC系列单片机简介

关注eeworld公众号 快捷获取更多信息
关注eeworld公众号
快捷获取更多信息
关注eeworld服务号 享受更多官方福利
关注eeworld服务号
享受更多官方福利

推荐阅读

PIC单片机调试心得
我是一位初学者,pic初学者,但是在单片机行当已经混迹多年了。说句实话,c开发环境都大同小异,只不过烧写和在线仿真大同小异。钻研了两天,收到了很多回应和启发。下面应soso的请求,把最近的调试心得和大家分享1、 先说说我要做的东西说来惭愧,这是临时的一个小任务,做一个采集和现实的部分,用两路ad采集模拟量,通过开关进行切换,简单的说就是开关打开,显示一路模拟量;开关关闭,显示另一路模拟量。主电路及其简单,我就直接说了,不附图了。电源通过一个负载(滑动变阻器就可以)回到电源负极,在回路中接入一个电流传感器,实时采集电流信号(如果条件不允许,也可以用康铜丝或者一个大瓦数小数值的采样电阻采集电流信号。然后通过放大,隔离后送入单片机
发表于 2019-11-16
PIC单片机调试心得
PIC单片机USART的应用
//★★★★★★★★★PIC单片机USART的应用(串口通信)★★★★★★★★★★★\//单征机型号:PIC16F877A//功能描述:PIC单片机USART的应用,串口调试助手发送数据给877,877收到后再转发回串口助手//通过“串口调试助手”协助工作#include<pic.h>              //包含单片机内部资源预定义__CONFIG(0xf73a);        //芯片配置字,看门狗关,上电延时开,掉电检测关,低压编程关,加密,4M
发表于 2019-11-16
0802LCD 4位显示程序 PIC单片机C语言程序
#include <xc.h>#include<pic.h>//#include"head.h"#define uchar unsigned char #define uint unsigned int #pragma config FOSC = XT        // Oscillator Selection bits (XT oscillator)#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled
发表于 2019-11-16
pic16f887单片机用AD590高精度测温的电路和程序
一、 前言AD590 为Analog Devices 公司出品的一种双端温度转换电流源的单晶IC。图为AD590内部的线路结构,及其二种常用的包装。二、原理与暂存器设定说明原理:AD 590是一个良好的温度-电流转换的感测元件,具有良好的线性关系,其转换率为1μA/°K。&#1048708;图(左边)所示为AD 590转换电路,其输出转换率有100mV/°C(Vo15)输出。由于AD 590之转换率为1μA/°K。因运算放大器具有极高的输入阻抗,极小的输入电流的特性,使得AD 590电流完全流过R2与R3,故U1 的输出电压为1μA/°K.(R2+R3),当调整R2使得R2+R3=10KΩ时,U1 的输出电压为10mV/°K
发表于 2019-11-15
pic16f887单片机用AD590高精度测温的电路和程序
PIC单片机上实时时钟PCF8563测试程序
;WDTE_OFF&MCLRE_OFF);  //PIC配置位设置void init_fosc()    //PIC内部晶振设置{OSCCON=0x61;}...................在PCF8563.h头文件里定义的结构体.....................struct Time{uchar second;uchar minute;uchar hour;uchar day;uchar week;uchar month;uchar year
发表于 2019-11-15
PIC18f4520单片机驱动H1632的C语言程序
#include<p18f4520.h>#include <delays.h>//#pragma config OSC = HS //配置内部振荡器Fosc/4 RA7,IO口RA7//#pragma config PWRT =OFF//#pragma config BOREN = OFF//#pragma config WDT = OFF//#pragma config MCLRE = ON//#pragma config PBADEN = OFF//#pragma config LVP = OFF#define CLK PORTCbits.RC3 #define DAT PORTCbits.RC
发表于 2019-11-15
PIC18f4520单片机驱动H1632的C语言程序
小广播
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号 电信业务审批[2006]字第258号函 京公海网安备110108001534 Copyright © 2005-2019 EEWORLD.com.cn, Inc. All rights reserved