當(dāng)前位置:首頁 > 單片機(jī) > 單片機(jī)
[導(dǎo)讀]主模式:我們今天來講I2C通信。那I2C通信的特點(diǎn)是什么能。我們一般使用的串口 (半雙工異步串行通信)與I2C 有什么區(qū)別呢。 串口(半雙工異步串行通信):就是好像朋友在對話。我可以主動和你講話,你也可以主動和我

主模式:

我們今天來講I2C通信。那I2C通信的特點(diǎn)是什么能。我們一般使用的串口 (半雙工異步串行通信)與I2C 有什么區(qū)別呢。

串口(半雙工異步串行通信):就是好像朋友在對話。我可以主動和你講話,你也可以主動和我講話。

I2C:就好像上下級對話。一個領(lǐng)導(dǎo)面對一個或者多個員工。只有領(lǐng)導(dǎo)主動說話的份兒,下面的員工不能主動說話。只有領(lǐng)導(dǎo)問了,員工才能答。

I2C通信

I2C通信只需要兩個引腳 一個數(shù)據(jù)線,一個時鐘線。 數(shù)據(jù)線顧名思義就是用來傳遞數(shù)據(jù)的。時鐘線是來決定數(shù)據(jù)傳輸?shù)乃俣?。?dāng)時鐘線為高電平時,數(shù)據(jù)線上的數(shù)據(jù)才會被認(rèn)為是有效的。

數(shù)據(jù)線的 數(shù)據(jù)有四種狀態(tài) : 高電平,低電平,下降沿(高電平變低電平),上升沿(低電平變高電平)。

當(dāng)時鐘線為高電平時候這四種狀態(tài)分別代表:1,0,起始位,停止位。

如果我們發(fā)送的數(shù)據(jù)為十六進(jìn)制的0x88即是二進(jìn)制為10001000的數(shù)據(jù)是怎么發(fā)送的呢?我們就以此為例一步步講解。

1,常態(tài)

在不發(fā)送任何數(shù)據(jù)的時候數(shù)據(jù)線和時鐘線都為高電平。所以I2C通信在硬件設(shè)計,需要在數(shù)據(jù)線和時鐘線上分別加上兩個上拉電阻。

2,起始

當(dāng)開始發(fā)送數(shù)據(jù)的時候 時鐘線為高同時數(shù)據(jù)線從 高電平變低電平,代表開始發(fā)送數(shù)據(jù)。

3,發(fā)送數(shù)據(jù)

發(fā)送完起始位后時鐘線變?yōu)榈碗娖?,在發(fā)送每一位的數(shù)據(jù)之前時鐘線有一段低電平,主要的作用是給數(shù)據(jù)線做電平變化用的。

我們現(xiàn)在要發(fā)送的第一個位是 1。

1、時鐘線為低,同時數(shù)據(jù)線從低電平變成高電平。

2、接著時鐘線變?yōu)楦唠娖?,此時接收方得知時鐘線為高,便查看數(shù)據(jù)線為高電平 說明數(shù)據(jù)為 “1”。

3、我們要發(fā)送的下一個位為0。時鐘線再變?yōu)榈停瑫r數(shù)據(jù)線從高電平變成低電平。

4、接著時鐘線再變?yōu)楦唠娖?,此時接收方得知時鐘線為高,便查看數(shù)據(jù)線為低電平 說明數(shù)據(jù)為"0"。

5、再下一個為還為0。時鐘線再變?yōu)榈停瑫r數(shù)據(jù)線一直保持低電平不變。

6、接著時鐘線再變?yōu)楦唠娖剑藭r接收方得知時鐘線為高,便查看數(shù)據(jù)線為低電平 說明數(shù)據(jù)為”0“。

以此類推 直到發(fā)送完所有的位。

4,應(yīng)答(ACK)

當(dāng)接收方接收完一個字節(jié)的數(shù)據(jù)就要告訴對方我收到了。接收方如果接收到數(shù)據(jù)則控制數(shù)據(jù)線輸出低電平。否則為高電平。

5,停止

沒有下一個字節(jié)要發(fā)送,最后時鐘線變?yōu)楦唠娖胶?,?shù)據(jù)線從低電平變?yōu)楦唠娖?。代表?shù)據(jù)發(fā)送停止。

實(shí)例講解:使用單片機(jī)使用 RSM2257 電子音量控制芯片來控制音量。一個按鍵按下,聲音變大,一個按鍵按下,聲音變小。在加上一個按鍵,控制一個LED亮滅的程序。而且音量掉電保存。

介紹RSM2257.

子地址

在I2C通信中每一個從設(shè)備都有個子地址,因?yàn)镮2C支持一主多從,也就是說有一個主機(jī)可以連接多個從機(jī)。每個從機(jī),都有個地址。就好像每個人的名字一樣來區(qū)分不同的設(shè)備。下面是RSM2257接口協(xié)議,首先先發(fā)送RSM2257 設(shè)備地址 10001000.然后再發(fā)送數(shù)據(jù)。

數(shù)據(jù)

RSM2257的數(shù)據(jù)是用來表示音量大小的。我們控制兩個音頻通道,以10dB為單位降低或增加音量。從功能設(shè)置位表格中可知數(shù)據(jù)為 11100B2B1B0.

B2B1B0的數(shù)值決定了音量。請?jiān)斠?衰減設(shè)置位。

單片機(jī)I2C通信初始化設(shè)置

1、設(shè)置端口為輸入

TRISC0 = input;
TRISC1 = input;

2、設(shè)置模式

我們設(shè)置ssp1控制寄存器的 SSP1M<3:0>.我們需要的是I2C主模式。設(shè)置如下

SSP1CON1bits.SSPM0 = 0;
SSP1CON1bits.SSPM1 = 0;
SSP1CON1bits.SSPM2 = 0;
SSP1CON1bits.SSPM3 = 1;// I2C Master mode ,clock=Fosc/(4*(SSPxADD+1))

3、設(shè)置時鐘線頻率RSM2257最大為100KHZ,我選擇設(shè)置為50KHZ.

使用計算公式clock=Fosc/(4*(SSPxADD+1)) 計算出SSP1ADD的值為0x9F;

SSP1ADD=0x9F;

4、開啟I2C通信

SSP1CON1bits.SSPEN = 1;

單片機(jī)I2C發(fā)送程序

1、發(fā)送起始位

SSP1CON2bits.SEN = 1;//Start condition
while(SSP1CON2bits.SEN == 1);//waiting for Start condition completed.

2、發(fā)送地址
PIR1bits.SSP1IF = 0;
SSP1BUF = 0x88;//Device Address
while(PIR1bits.SSP1IF == 0);
PIR1bits.SSP1IF = 0;
// ~ACK 我們不理會接收方有沒有應(yīng)答。
3、發(fā)送 10db音量控制的數(shù)據(jù)
SSP1BUF = tx_data;//Data 10db level
while(PIR1bits.SSP1IF == 0);
PIR1bits.SSP1IF = 0;
4、發(fā)送1db音量控制的數(shù)據(jù)
// ~ACK
SSP1BUF = 0xD0;//Data 1db level
while(PIR1bits.SSP1IF == 0);
PIR1bits.SSP1IF = 0;

5,發(fā)送停止位
// ~ACK
SSP1CON2bits.PEN = 1;//Stop condition

關(guān)于I2C通信協(xié)議,RSM2257,PIC MSSP 模塊設(shè)置成I2C,更詳細(xì)的內(nèi)容就必須去看數(shù)據(jù)手冊了。

實(shí)例程序:程序分為main.c 和 define.h兩個文件 芯片PIC16LF1823,開發(fā)環(huán)境MPLAB X IDE.

define.h文件

/**********RA*********/
//B'1111,1000'H F8
#define LED_SW RA5//IN
#define UP_SW RA4//IN
#define DOWN_SW RA3//IN
#define LED RA2//OUT
//RA1
//RA0
/**********RC***********/
//H FF
//RC0 SCL
//RC1 SDA
#define input 1
#define LED_VALUE 1
#define UP_VALUE 2
#define DOWN_VALUE 3
#define key_delay 300

main.c文件

#include
#include"define.h"
__CONFIG(FOSC_INTOSC&WDTE_OFF&PWRTE_ON&MCLRE_OFF&CP_ON&CPD_OFF&BOREN_ON

&CLKOUTEN_OFF&IESO_ON&FCMEN_ON);
__CONFIG(PLLEN_OFF&LVP_OFF) ;
void tx_pro(unsigned char tx_db);
unsigned char DB_VALUE;
void init_fosc(void)
{
OSCCON = 0xF0;//32MHZ
}
void init_gpio(void)
{
PORTA=0;
LATA =0;
ANSELA=0x00;
TRISA =0xF8;


PORTC=0;
LATC=0;
ANSELC = 0x00;
TRISC =0xFF;
}
void init_i2c_master()
{
TRISC0 = input;
TRISC1 = input;
SSP1CON1bits.SSPM0 = 0;
SSP1CON1bits.SSPM1 = 0;
SSP1CON1bits.SSPM2 = 0;
SSP1CON1bits.SSPM3 = 1;// I2C Master mode ,clock=Fosc/(4*(SSPxADD+1))
SSP1STATbits.SMP = 1;
SSP1ADD = 0x9F;//SCL CLOCK Frequency 50KHZ
SSP1CON1bits.SSPEN = 1;
}
void i2c_master_tx(unsigned char tx_data)
{
SSP1CON2bits.SEN = 1;//Start condition
while(SSP1CON2bits.SEN == 1);//waiting for Start condition completed.


PIR1bits.SSP1IF = 0;
SSP1BUF = 0x88;//Device Address
while(PIR1bits.SSP1IF == 0);
PIR1bits.SSP1IF = 0;
// ~ACK

SSP1BUF = tx_data;//Data 10db level
while(PIR1bits.SSP1IF == 0);
PIR1bits.SSP1IF = 0;

// ~ACK
SSP1BUF = 0xD0;//Data 1db level
while(PIR1bits.SSP1IF == 0);
PIR1bits.SSP1IF = 0;
// ~ACK
SSP1CON2bits.PEN = 1;//Stop condition
}
void delay(unsigned int n)
{
while(n--);
}
unsigned char key_board(void)
{
if(LED_SW==1)
{
delay(key_delay);
if(LED_SW==1)
{
while(LED_SW==1);
return LED_VALUE;
}
}
if(UP_SW==1)
{
delay(key_delay);
if(UP_SW==1)
{
while(UP_SW==1);
return UP_VALUE;
}
}
if(DOWN_SW==1)
{
delay(key_delay);
if(DOWN_SW==1)
{
while(DOWN_SW==1);
return DOWN_VALUE;
}


}
return 0;


}
void DB_INC(void)
{
if(DB_VALUE < 7)
{
DB_VALUE++;
eeprom_write(0x00, DB_VALUE);//將音量值保存到EEPROM這樣掉電后數(shù)據(jù)也不會丟失。
tx_pro(DB_VALUE);
}




}
void DB_DEC(void)
{
if(DB_VALUE > 0)
{
DB_VALUE --;
eeprom_write(0x00, DB_VALUE);
tx_pro(DB_VALUE);
}
}
void tx_pro(unsigned char tx_db)
{
tx_db |= 0xE0; //將高三位設(shè)置為1。表示兩個音頻通道,以10dB為單位降低或增加音量
i2c_master_tx(tx_db);//I2C發(fā)送數(shù)據(jù)程序
}
/*
*
*/
int main(int argc, char** argv) {
unsigned char keyvalue;
init_fosc();
init_gpio();
init_i2c_master();
LED=0;
DB_VALUE= eeprom_read(0x00);//讀eeprom 中保存的音量值
if(DB_VALUE > 7)//如果之前沒有設(shè)置過則音量不衰減
{
DB_VALUE = 0;
}
tx_pro(DB_VALUE);//用I2C通信設(shè)置RSM2257的音量
while(1)
{
keyvalue=key_board();//判斷按鍵程序,
switch(keyvalue)
{
case LED_VALUE://LED按鍵按下
{
LED = ~LED;
};break;
case UP_VALUE://音量加
{
DB_INC();
};break;
case DOWN_VALUE://音量減
{
DB_DEC();
};break;
}
}
}

從模式:

網(wǎng)上有許多講解單片機(jī) 實(shí)現(xiàn)I2C主模式,但是從模式的很少。我現(xiàn)在就來講講PIC單片機(jī)使用MSSP模塊實(shí)現(xiàn)I2C從模式。

有關(guān)I2C協(xié)議的具體介紹可以看 《PIC單片機(jī)之I2C(主模式)》,我們這里直接講解實(shí)例

實(shí)例講解:我們模仿 AT24C02 EEPROM 的協(xié)議。讓一個主模式的單片機(jī),來讀取從模式單片機(jī)的數(shù)據(jù)。

下面為AT24C02的隨機(jī)地址讀取的協(xié)議。

第一個字節(jié) :輸入7位地址和一位的寫狀態(tài)位,

第二個字節(jié):然后寫入EEPROM數(shù)據(jù)地址,

第三個字節(jié):輸入7位地址和一位的讀狀態(tài)位,

第四~N個字節(jié):讀出的EEPROM的數(shù)據(jù)。

我們來講解下程序的基本思路:我們使能了MSSP中斷,即是I2C接收中斷,當(dāng)PIC單片機(jī)接收到一個數(shù)據(jù)后就會產(chǎn)生中斷。那是接收到設(shè)備地址,還是接收到數(shù)據(jù),由SSP1STAT寄存器的狀態(tài)位來判斷。

需要判斷的狀態(tài)位分別是 :

數(shù)據(jù)和地址: 用來判斷接收到是地址還是數(shù)據(jù)

啟動位: 用來判斷是否接收到啟動位

讀寫: 用來判斷是寫狀態(tài)還是讀狀態(tài)。

緩存滿: 用來判斷緩沖區(qū)是否滿

我們以隨機(jī)地址讀取為例:講講程序執(zhí)行的過程

1,從單片機(jī)接收到啟示位和設(shè)備地址中斷:我們判斷SSP1STAT的狀態(tài)位為(寫狀態(tài),地址,緩存滿,接收到啟示位) 然后讀取緩存中的設(shè)備地址, 接著在讀取 需要讀/寫的數(shù)據(jù)地址。

2,單片機(jī)再次接收到設(shè)備地址:我們判斷是SSP1STAT的狀態(tài)為(讀狀態(tài))然后從設(shè)備就輸出數(shù)據(jù)

我們以寫字節(jié)數(shù)據(jù)為例:

1,從單片機(jī)接收到啟示位和設(shè)備地址中斷:我們判斷SSP1STAT的狀態(tài)位為(寫狀態(tài),地址,緩存滿,接收到啟示位) 然后讀取緩存中的設(shè)備地址, 接著在讀取 需要讀/寫的數(shù)據(jù)地址。

2,單片機(jī)判斷SSP1STAT的狀態(tài)位為(寫狀態(tài),數(shù)據(jù),緩存滿)那么單片機(jī)就接收輸入的數(shù)據(jù)。

初始化設(shè)置:

1,設(shè)置I2C通信的兩引腳為CLK SCL為輸入,

TRISB6 = input;
TRISB4 = input;

2,將MSSP設(shè)置為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,設(shè)置從設(shè)備地址為 0xA0

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

5,開啟I2C

SSP1CONbits.SSPEN=1;//enable I2c

6,清楚狀態(tài)標(biāo)志
SSPSTAT=0;
7,使能I2C中斷
PIE1bits.SSP1IE = 1;//Enabe interrupt MSSP
INTCONbits.PEIE = 1;
INTCONbits.GIE = 1;

如果你要使用PIC單片機(jī)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;
}

}

將初始化函數(shù)init_i2c_slave();放到主函數(shù)中

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


}

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點(diǎn),本站亦不保證或承諾內(nèi)容真實(shí)性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫?dú)角獸公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運(yùn)行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點(diǎn): 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實(shí)提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅(jiān)持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運(yùn)營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉