I2C簡介
I2C總線是由Philips公司開發的一種簡單、雙向二線制同步串行總線。它只需要兩根線即可在連接于總線上的器件之間傳送信息。
主器件用于啟動總線傳送數據,并產生時鐘以開放傳送的器件,此時任何被尋址的器件均被認為是從器件.在總線上主和從、發和收的關系不是恒定的,而取決于此時數據傳送方向。如果主機要發送數據給從器件,則主機首先尋址從器件,然后主動發送數據至從器件,最后由主機終止數據傳送;如果主機要接收從器件的數據,首先由主器件尋址從器件.然后主機接收從器件發送的數據,最后由主機終止接收過程。在這種情況下.主機負責產生定時時鐘和終止數據傳送。
I2C:就好像上下級對話。一個領導面對一個或者多個員工。只有領導主動說話的份兒,下面的員工不能主動說話。只有領導問了,員工才能答。
I2C通信只需要兩個引腳 一個數據線,一個時鐘線。 數據線顧名思義就是用來傳遞數據的。時鐘線是來決定數據傳輸的速度。當時鐘線為高電平時,數據線上的數據才會被認為是有效的。數據線的 數據有四種狀態 : 高電平,低電平,下降沿(高電平變低電平),上升沿(低電平變高電平)。當時鐘線為高電平時候這四種狀態分別代表:1,0,起始位,停止位。
I2C的從模式與主模式的區別
宏觀上來講,主模式:就是主CPU作為主機,向從機(掛載器件)發送接收數據。
從模式:就是主CPU作為從機,接收和發送主機(掛載器件)數據。而主從機的分別其實是一個觸發的作用,主機主動觸發,從機只能被動響應觸發。
I2C(Inter-Integrated Circuit)總線是由PHILIPS公司開發的兩線式串行總線,用于連接微控制器及其外圍設備。是微電子通信控制領域廣泛采用的一種總線標準。它是同步通信的一種特殊形式,具有接口線少,控制方式簡單,器件封裝形式小,通信速率較高等優點。
I2C 總線支持任何IC 生產過程(CMOS、雙極性)。通過串行數據(SDA)線和串行時鐘 (SCL)線在連接到總線的器件間傳遞信息。每個器件都有一個唯一的地址識別(無論是微控制器——MCU、LCD 驅動器、存儲器或鍵盤接口),而且都可以作為一個發送器或接收器(由器件的功能決定)。LCD 驅動器只能作為接收器,而存儲器則既可以接收又可以發送數據。除了發送器和接收器外,器件在執行數據傳輸時也可以被看作是主機或從機。主機是初始化總線的數據傳輸并產生允許傳輸的時鐘信號的器件。此時,任何被尋址的器件都被認為是從機。
PIC單片機之I2C(從模式)
介紹完了我們就來看看PIC單片機使用MSSP模塊實現I2C從模式。
模式單片機的數據。
下面為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;
}
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;
}
}
}
評論
查看更多