中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

聊城冠縣網(wǎng)站建設(shè)班級(jí)優(yōu)化大師怎么用

聊城冠縣網(wǎng)站建設(shè),班級(jí)優(yōu)化大師怎么用,網(wǎng)站開發(fā)應(yīng)注意什么,青島的網(wǎng)站建設(shè)單片機(jī)學(xué)習(xí)! 目錄 前言 一、軟件I2C讀寫代碼框架 二、I2C初始化 三、六個(gè)時(shí)序基本單元 3.1 引腳操作的封裝和改名 3.2 起始條件執(zhí)行邏輯 3.3 終止條件執(zhí)行邏輯 3.4 發(fā)送一個(gè)字節(jié) 3.5 接收一個(gè)字節(jié) 3.5 發(fā)送應(yīng)答&接收應(yīng)答 3.5.1 發(fā)送應(yīng)答 3.5.2 接…
單片機(jī)學(xué)習(xí)!

目錄

前言

一、軟件I2C讀寫代碼框架

二、I2C初始化

三、六個(gè)時(shí)序基本單元

3.1 引腳操作的封裝和改名? ?

3.2 起始條件執(zhí)行邏輯

3.3 終止條件執(zhí)行邏輯

3.4 發(fā)送一個(gè)字節(jié)

3.5 接收一個(gè)字節(jié)

3.5 發(fā)送應(yīng)答&接收應(yīng)答

3.5.1 發(fā)送應(yīng)答

3.5.2 接收應(yīng)答

總結(jié)


前言

????????本文介紹了軟件I2C讀寫代碼,I2C協(xié)議層重點(diǎn)關(guān)注的是使用的兩個(gè)引腳、I2C配置、時(shí)序的高低電平等協(xié)議相關(guān)的內(nèi)容。


一、軟件I2C讀寫代碼框架

????????代碼整體框架:首先建立I2C通信層的.c和.h模塊,在通信層里寫好I2C底層的GPIO初始化和6個(gè)時(shí)序基本單元,也就是起始、終止、發(fā)送一個(gè)字節(jié)、接收一個(gè)字節(jié)、發(fā)送應(yīng)答和接收應(yīng)答。

????????由于本代碼使用軟件I2C,所以I2C的庫函數(shù)暫時(shí)不用看,軟件I2C只需要用GPIO的讀寫函數(shù)就行了。

軟件I2C初始化要做兩個(gè)任務(wù):

  • 第一個(gè)任務(wù),把SCL和SDA都初始化為開漏輸出模式;
  • 第二個(gè)任務(wù),把SCL和SDA置高電平。

?? ?

二、I2C初始化

????????當(dāng)前接線SCL是PB10,SDA是PB11。所以要開啟GPIOB,PB10和PB11都要配置成開漏輸出的模式。雖然開漏輸出名字上帶了個(gè)輸出,但并不代表它只能輸出,開漏輸出模式仍然可以輸入。輸入時(shí)先輸出1再直接讀取輸入數(shù)據(jù)寄存器就行了。這個(gè)過程在之前博文講I2C硬件規(guī)定時(shí)介紹過。

代碼示例:

void MyI2C_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//開啟時(shí)鐘GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Mode= GPIO_Mode_Out_OD;GPIO_InitStruct.GPIO_Pin= GPIO_Pin_10 | GPIO_Pin_11;GPIO_InitStruct.GPIO_Speed= GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStruct);GPIO_SetBits(GPIOB,GPIO_Pin_10 | GPIO_Pin_11);//把GPIOB的PB10和PB11都置高電平}

????????調(diào)用MyI2C_Init函數(shù),PB10和PB11兩個(gè)端口就被初始化為開漏輸出模式,然后釋放總線。SCL和SDA處于高電平,此時(shí)I2C總線處于空閑狀態(tài)。

三、六個(gè)時(shí)序基本單元

3.1 引腳操作的封裝和改名? ?

????????第一個(gè)基本單元,起始條件。根據(jù)波形圖,首先把SCL和SDA都確保釋放。然后先拉低SDA,再拉低SCL,這樣就能產(chǎn)生起始條件了。

????????在這里可以不斷地調(diào)用SetBits和ResetBit函數(shù),來手動(dòng)翻轉(zhuǎn)高低電平。但是這樣做會(huì)在后面的程序中出現(xiàn)非常多的地方來指定這個(gè)GPIO端口號(hào)。一方面,這樣做語義不是很明顯;另一方面,如果之后需要換一個(gè)端口那就需要改動(dòng)非常多的地方。所以這時(shí)就需要在上面做個(gè)定義,把端口號(hào)統(tǒng)一替換一個(gè)名字,這樣無論是語義還是端口的修改都會(huì)非常方便。

????????給端口號(hào)換一個(gè)名字有很多方法都能實(shí)現(xiàn)功能,一種簡(jiǎn)單的替換方法就是宏定義,
?

#define SCL_PORT ? ? ? GPIOB ? ?
#define SCL_PIN ? ? ? ?GPIO_Pin_10

????????之后如果想釋放SCL,就調(diào)用SetBits函數(shù)將GPIOB替換為SCL_PORT;將GPIO_Pin_10替換為SCL_PIN。

GPIO_SetBits(GPIOB,GPIO_Pin_10);
GPIO_SetBits(SCL_PORT,SCL_PIN);

????????這樣語義比較明確,而且修改引腳的時(shí)候直接在上面修改一下宏定義,下面所有引用宏定義的地方都會(huì)自動(dòng)更改。但是這樣宏定義的方法如果換到一個(gè)主頻很高的單片機(jī)中,需要對(duì)軟件時(shí)序進(jìn)行延時(shí)操作的時(shí)候,也不太方便進(jìn)一步修改。所以這里也可以直接一點(diǎn),定義函數(shù)對(duì)操作端口的庫函數(shù)進(jìn)行封裝,這樣既容易理解,又方便加軟件延時(shí)。

定義函數(shù)對(duì)操作端口的庫函數(shù)進(jìn)行封裝代碼示例:

void MyI2C_W_SCL(uint8_t BitValue)
{GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)BitValue);
}

????????MyI2C_W_SCL這個(gè)W代表寫的意思,函數(shù)里調(diào)用GPIO_WriteBit函數(shù),第三個(gè)參數(shù)給BitValue強(qiáng)轉(zhuǎn)為BitAction類型。

????????這樣套一個(gè)函數(shù)替換之后,后面再調(diào)用MyI2C_W_SCL函數(shù),參數(shù)給1或0,就可以釋放或拉低SCL了。


????????如果要把這個(gè)程序移植到別的單片機(jī),就可以把這個(gè)函數(shù)里的操作替換為其他單片機(jī)對(duì)應(yīng)的操作。

比如SCL是51單片機(jī)的P10口,就可以把

GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)BitValue);

上面這句替換為下面這句

P10=BitValue; 

????????另外如果單片機(jī)主頻比較快,函數(shù)里也非常方便加一些延時(shí),比如這里要求每次操作引腳之后都要延時(shí)10us,就可以在引腳操作之后調(diào)用延時(shí)函數(shù)進(jìn)行引腳延時(shí)操作了。I2C可以慢一些,多慢都行,但是快的話還是要看一下手冊(cè)里對(duì)時(shí)序時(shí)間的要求。

void MyI2C_W_SCL(uint8_t BitValue)
{GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)BitValue);Delay_us(10);
}

同理封裝一下SDA:

//SDA封裝
void MyI2C_W_SDA(uint8_t BitValue) 
{GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction)BitValue);Delay_us(10);
}

????????另外還要再來個(gè)讀SDA的函數(shù),因?yàn)镾TM32庫函數(shù)中,讀和寫不是同一個(gè)寄存器

uint8_t MyI2C_R_SDA(void)
{uint8_t BitValue;BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);Delay_us(10);return BitValue;
}

? ? ? ? 函數(shù)MyI2C_R_SDA中R代表讀的意思,讀出SDA之后也延時(shí)10us,返回讀到SDA線的電平。


? ? ? ? 有了以上三個(gè)函數(shù)的封裝就實(shí)現(xiàn)了函數(shù)名稱、端口號(hào)的替換。同時(shí)也可以很方便地修改時(shí)序的延時(shí)。當(dāng)需要替換端口時(shí),或者把這個(gè)程序移植到別的單片機(jī)中時(shí)就只需要對(duì)這前4個(gè)函數(shù)里的操作對(duì)應(yīng)更改,后面的函數(shù)都調(diào)用這里封裝的新名稱進(jìn)行操作,這樣在移植的時(shí)候后面的部分就不需要再進(jìn)行修改了。

? ? ? ? 以上關(guān)于引腳操作的封裝和改名就完成了。


3.2 起始條件執(zhí)行邏輯

????????在起始條件里需要先把SCL和SDA都釋放,也就是都輸出1.然后先拉低SDA,再拉低SCL。

代碼示例:

void MyI2C_Start(void)
{MyI2C_W_SDA(1);MyI2C_W_SCL(1);MyI2C_W_SDA(0);MyI2C_W_SCL(0);
}

????????代碼中需注意,最好將釋放SDA的放在最前面,這樣更符合起始條件的波形,這樣保險(xiǎn)一些。

????????如果起始條件之前的SCL和SDA已經(jīng)是高電平了,那不管先釋放哪一個(gè)都是一樣的效果。但是看下圖中Sr這里,Start還要兼容這里的重復(fù)起始條件Sr,Sr最開始SCL是低電平,SDA電平不敢確定。所以保險(xiǎn)起見,趁著SCL是低電平,先釋放SDA;再釋放SCL。這時(shí)SDA和SCL都是高電平。

????????然后再拉低SDA,拉低SCL。這樣Start就可以兼容起始條件和重復(fù)起始條件了。


?

3.3 終止條件執(zhí)行邏輯

? ? ? ? 當(dāng)Stop開始,如果SDA和SCL都已經(jīng)是低電平了,那就先釋放SCL,再釋放SDA就行了。但是在時(shí)序單元開始時(shí),SDA并不一定是低電平。所以為了確保之后釋放SDA能產(chǎn)生上升沿,要在時(shí)序單元開始時(shí),先拉低SDA,然后再釋放SCL、釋放SDA。

????????所以在程序里Stop的執(zhí)行邏輯是:先拉低SDA,再釋放SCL,再釋放SDA。

void MyI2C_Stop(void)
{MyI2C_W_SDA(0);MyI2C_W_SCL(1);MyI2C_W_SDA(1);
}

? ? ? ? 終止條件后,SCL和SDA都回歸到高電平。

3.4 發(fā)送一個(gè)字節(jié)

? ? ? ? 函數(shù)的參數(shù)是要發(fā)送的一個(gè)字節(jié)。發(fā)送一個(gè)字節(jié)時(shí)序開始時(shí),SCL是低電平。實(shí)際上除了終止條件,SCL以高電平結(jié)束,所有的單元都會(huì)保證SCL以低電平結(jié)束,這樣方便各個(gè)單元的拼接。

????????

????????上圖所示,SCL低電平,變換數(shù)據(jù);SCL高電平,保持?jǐn)?shù)據(jù)穩(wěn)定。由于是高位先行,所以變換數(shù)據(jù)的時(shí)候按照先放最高位,再放次高位,最后最低位,這樣的順序依次把一個(gè)字節(jié)的每一位放在SDA線上。每放完一位后,執(zhí)行釋放SCL,拉低SCL的操作,驅(qū)動(dòng)時(shí)鐘運(yùn)轉(zhuǎn)。

????????在程序中的操作就是,首先趁SCL低電平,先把Byte的最高位放在SDA線上,寫SDA,寫1還是寫0取決于Byte的最高位。這里需要取出Byte的最高位,可以用 (Byte & 0x80) ,這是一個(gè)單片機(jī)中非常常見的操作。就是用按位與的方式取出數(shù)據(jù)的某一位或某幾位。

按位與取出數(shù)據(jù)某一位的運(yùn)行邏輯:

  • Byte可以是任意的數(shù)據(jù)? ?xxxx xxxx
  • 0x80就是? ? ? ? ? ? ? ? ? ? ? ?1000 0000
  • Byte與0x80按位與結(jié)果? x000 0000

低7位因?yàn)楹?相與,所以結(jié)果不受Byte數(shù)據(jù)的影響,始終是0;

最高位和1相與,所以結(jié)果取決于Byte的最高位。

  • 如果Byte的最高位是1,結(jié)果就是1000 0000,也就是0x80;
  • 如果Byte最高位是0,結(jié)果就是0000 0000,也就是0x00.

這就相當(dāng)于把Byte的最高位取出來了。但是注意,Byte & 0x80 這個(gè)式子計(jì)算結(jié)果是0x80或0x00,而不是1或0.不過上文函數(shù)將參數(shù)BitValue強(qiáng)轉(zhuǎn)為BitAction類型,就是非0即1,所以即使傳入0x80也相當(dāng)于傳入了1,代碼中可以直接寫 (Byte & 0x80)。

????????上面方法步驟將最高位數(shù)據(jù)放好后,再釋放SCL,再拉低SCL,驅(qū)動(dòng)時(shí)鐘走一個(gè)脈沖。

	MyI2C_W_SDA(Byte & 0x80);MyI2C_W_SCL(1);MyI2C_W_SCL(0);

????????當(dāng)釋放SCL之后,從機(jī)就會(huì)立刻把放好在SDA的數(shù)據(jù)讀走,再拉低SCL,然后就可以放下一個(gè)數(shù)據(jù)了,下一位是次高位。

?? ?MyI2C_W_SDA(Byte & 0x40);MyI2C_W_SCL(1);MyI2C_W_SCL(0);?? ?

????????寫SDA,數(shù)據(jù)與0x40,取出次高位,再驅(qū)動(dòng)SCL,來一個(gè)時(shí)鐘。

????????之后繼續(xù),寫SDA,數(shù)據(jù)與0x20,取出再下一位,再驅(qū)動(dòng)SCL,來一個(gè)時(shí)鐘。

?? ?MyI2C_W_SDA(Byte & 0x20);MyI2C_W_SCL(1);MyI2C_W_SCL(0);??

? ? ? ? 這樣來8次這個(gè)操作,就可以寫入一個(gè)字節(jié)。不過可以套個(gè)for循環(huán),循環(huán)8次減少代碼量。

void MyI2C_SendByte(uint8_t Byte);
{uint8_t i;for(i=0;i<8;i++){MyI2C_W_SDA(Byte & (0x80 >>i));MyI2C_W_SCL(1);MyI2C_W_SCL(0);}
}

定義一個(gè)迭代變量i,循環(huán)八次,然后把上述重復(fù)的操作單元放在里面。

第一次循環(huán) i=0,需要 (Byte & 0x80)?

第二次循環(huán) i=1,需要 (Byte & 0x40)?

第三次循環(huán) i=2,需要 (Byte & 0x20)?

...

所以這里的通式就是(Byte & (0x80 >>i)) 注意要加個(gè)括號(hào),確保優(yōu)先級(jí)。

3.5 接收一個(gè)字節(jié)

? ? ? ? 接收一個(gè)字節(jié)時(shí)序開始時(shí),SCL低電平,此時(shí)從機(jī)需要把數(shù)據(jù)放到SDA上,為了防止主機(jī)干擾從機(jī)寫入數(shù)據(jù),主機(jī)需要先釋放SDA,釋放SDA也相當(dāng)于切換為輸入模式。那在SCL低電平時(shí),從機(jī)會(huì)把數(shù)據(jù)放到SDA。

  • 如果從機(jī)想發(fā)1,就釋放SDA;
  • 如果從機(jī)想發(fā)0,就拉低SDA;

????????然后主機(jī)釋放SCL,在SCL高電平期間,讀取SDA,再拉低SCL。SCL低電平期間從機(jī)就會(huì)把下一位數(shù)據(jù)放到SDA上。這樣重復(fù)八次主機(jī)就能得到一個(gè)字節(jié)了。

????????在這里可以發(fā)現(xiàn),SCL低電平變換數(shù)據(jù),高電平讀取數(shù)據(jù)。實(shí)際上就是一種讀寫分離的設(shè)計(jì):

  • 低電平時(shí)間定義為寫的時(shí)間;
  • 高電平時(shí)間定義為讀的時(shí)間。

????????那在SCL高電平期間,如果非要?jiǎng)覵DA來破壞讀寫規(guī)則的話,那這個(gè)信號(hào)就是起始條件和終止條件。SCL高電平時(shí),SDA下降沿為起始條件,SDA上升沿為終止條件。這個(gè)設(shè)計(jì)也保證了起始條件和終止條件的特異性,能夠在連續(xù)不斷的波形中快速地定位起始和終止。因?yàn)槠鹗冀K止與數(shù)據(jù)傳輸?shù)牟ㄐ斡斜举|(zhì)區(qū)別:

  • 數(shù)據(jù)傳輸SCL高電平不許動(dòng)SDA;
  • 起始終止SCL高電平必須動(dòng)SDA。

這就是這個(gè)設(shè)計(jì)的巧妙之處。

進(jìn)接收一個(gè)字節(jié)的時(shí)序之后,SCL是低電平,主機(jī)釋放SDA。從機(jī)把數(shù)據(jù)放到SDA時(shí),主機(jī)釋放SCL,SCL高電平時(shí),主機(jī)就能讀取數(shù)據(jù)了。

uint8_t MyI2C_ReceiveByte(void)
{uint8_t Byte = 0x00;MyI2C_W_SDA(1);MyI2C_W_SCL(1);if(MyI2C_R_SDA() == 1){Byte |= 0x80;}MyI2C_W_SCL(0);}

????????讀取數(shù)據(jù)用MyI2C_R_SDA函數(shù),套個(gè)if,如果讀SDA為1,if成立,就知道接收這一位為1了。先定義一個(gè)數(shù)據(jù)Byte,給初始值0x00.

  • 如果第一次讀SDA為1,就Byte |= 0x80; 把Byte最高位置1;
  • 如果第一次讀SDA為0,if條件不成立,Byte默認(rèn)為0x00,就相當(dāng)于寫如0了。

????????讀取一位之后,再把SCL拉低。這時(shí)從機(jī)就會(huì)把下一位數(shù)據(jù)放到SDA上。再執(zhí)行下方代碼相同的流程8次就能接收一個(gè)字節(jié)了。

	MyI2C_W_SCL(1);if(MyI2C_R_SDA() == 1){Byte |= 0x80;}MyI2C_W_SCL(0);

????????可以用個(gè)for循環(huán),把上方代碼放進(jìn)去,循環(huán)8次,依次從高位到低位進(jìn)行判斷。所以在寫個(gè)和發(fā)送一個(gè)字節(jié)一樣的移位操作。就可以接收一個(gè)字節(jié)了。最后return Byte; 把接收的Byte返回去。

3.5 發(fā)送應(yīng)答&接收應(yīng)答

????????發(fā)送應(yīng)答和接收應(yīng)答其實(shí)就是發(fā)送一個(gè)字節(jié)和接收一個(gè)字節(jié)的簡(jiǎn)化版:

  • 發(fā)送一個(gè)字節(jié)是發(fā)8位,發(fā)送應(yīng)答是發(fā)1位;
  • 接收一個(gè)字節(jié)是收8位,接收應(yīng)答是收1位。

所以程序這里可以參照發(fā)送一個(gè)字節(jié)和接收一個(gè)字節(jié)來修改。

3.5.1 發(fā)送應(yīng)答

? ? ? ??將發(fā)送一個(gè)字節(jié)的代碼中的for循環(huán)去掉,修改一下。

void MyI2C_SendAck(uint8_t AckBit)
{MyI2C_W_SDA(AckBit);MyI2C_W_SCL(1);MyI2C_W_SCL(0);
}

? ? ? ? 現(xiàn)在的邏輯是:函數(shù)進(jìn)來時(shí),SCL低電平。

  • 主機(jī)把AckBit放到SDA上。
  • SCL高電平,從機(jī)讀取應(yīng)答。
  • SCL低電平,進(jìn)入下一個(gè)時(shí)序單元。

3.5.2 接收應(yīng)答

????????將接收一個(gè)字節(jié)的代碼中的for循環(huán)去掉,修改一下。讀SDA時(shí),直接把讀到的值,賦值給AckBit就行了。最后返回讀AckBit。

uint8_t MyI2C_ReceiveAck(void)
{uint8_t AckBit;MyI2C_W_SDA(1);MyI2C_W_SCL(1);AckBit = MyI2C_R_SDA();MyI2C_W_SCL(0);return AckBit;
}

????????現(xiàn)在的邏輯是:函數(shù)進(jìn)來時(shí),SCL低電平。

  • 主機(jī)釋放SDA,防止干擾從機(jī),同時(shí)從機(jī)把應(yīng)答位放在SDA上。
  • SCL高電平,主機(jī)讀取應(yīng)答位。
  • SCL低電平,進(jìn)入下一個(gè)時(shí)序單元。


代碼疑問:

? ? ? ? 1.程序里主機(jī)先把SDA置1了,然后再讀取SDA,應(yīng)答位就肯定是1嗎?

可以從兩點(diǎn)分析:

  • 第一,I2C的引腳都是開漏輸出+弱上拉的配置,主機(jī)輸出1并不是強(qiáng)置SDA為高電平,而是釋放SDA。
  • 第二,I2C是在進(jìn)行通信,主機(jī)釋放了SDA,那從機(jī)如果在的話,從機(jī)是有義務(wù)把SDA再拉低的。

所以即使主機(jī)在前面把SDA置1了,之后再讀取SDA,讀到的值也可能是0.

  • 讀到0代表從機(jī)給了應(yīng)答。
  • 讀到1代表從機(jī)沒給應(yīng)答。

? ? ? ? 2.接收一個(gè)字節(jié)的代碼里不斷讀取SDA,但是for循環(huán)中又沒寫過SDA,那SDA讀出來應(yīng)該始終是一個(gè)值嗎?

? ? ? ? I2C進(jìn)行通信是有從機(jī)的,當(dāng)主機(jī)不斷驅(qū)動(dòng)SCL時(shí)鐘時(shí),從機(jī)就有義務(wù)去改變SDA的電平。所以主機(jī)每次循環(huán)讀取SDA的時(shí)候,這個(gè)讀取到的數(shù)據(jù)是從機(jī)控制的,這個(gè)讀取到的數(shù)據(jù)也正是從機(jī)想要給我們發(fā)送的數(shù)據(jù)。這也就是這個(gè)時(shí)序叫做接收一個(gè)字節(jié)。

? ? ? ? 通信是有時(shí)序的,有些引腳的電平之前讀和之后讀,讀的值就是不一樣的。


四、總代碼示例

.c代碼示例:

#include "stm32f10x.h"                  // Device header
#include "Delay.h" //CL封裝
void MyI2C_W_SCL(uint8_t BitValue) 
{GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)BitValue);Delay_us(10);
}//SDA封裝
void MyI2C_W_SDA(uint8_t BitValue) 
{GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction)BitValue);Delay_us(10);
}//讀SDA的函數(shù)
uint8_t MyI2C_R_SDA(void)
{uint8_t BitValue;BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);Delay_us(10);return BitValue;
}void MyI2C_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//開啟時(shí)鐘GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Mode= GPIO_Mode_Out_OD;GPIO_InitStruct.GPIO_Pin= GPIO_Pin_10 | GPIO_Pin_11;GPIO_InitStruct.GPIO_Speed= GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStruct);GPIO_SetBits(GPIOB,GPIO_Pin_10 | GPIO_Pin_11);//把GPIOB的PB10和PB11都置高電平}//六個(gè)時(shí)序基本單元//起始條件	
void MyI2C_Start(void)
{MyI2C_W_SDA(1);MyI2C_W_SCL(1);MyI2C_W_SDA(0);MyI2C_W_SCL(0);
}//終止條件
void MyI2C_Stop(void)
{MyI2C_W_SDA(0);MyI2C_W_SCL(1);MyI2C_W_SDA(1);
}//發(fā)送一個(gè)字節(jié)
void MyI2C_SendByte(uint8_t Byte)
{uint8_t i;for(i=0;i<8;i++){MyI2C_W_SDA(Byte & (0x80 >>i));MyI2C_W_SCL(1);MyI2C_W_SCL(0);}
}//接收一個(gè)字節(jié)
uint8_t MyI2C_ReceiveByte(void)
{uint8_t i, Byte = 0x00;MyI2C_W_SDA(1);for(i = 0 ; i < 8 ; i++){MyI2C_W_SCL(1);if(MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);}MyI2C_W_SCL(0);}return Byte;
}//發(fā)送應(yīng)答
void MyI2C_SendAck(uint8_t AckBit)
{MyI2C_W_SDA(AckBit);MyI2C_W_SCL(1);MyI2C_W_SCL(0);
}//接收應(yīng)答
uint8_t MyI2C_ReceiveAck(void)
{uint8_t AckBit;MyI2C_W_SDA(1);MyI2C_W_SCL(1);AckBit = MyI2C_R_SDA();MyI2C_W_SCL(0);return AckBit;
}

.h代碼示例:

#ifndef __MYI2C_H__
#define __MYI2C_H__void MyI2C_Init(void);//起始條件	
void MyI2C_Start(void);//終止條件
void MyI2C_Stop(void);//發(fā)送一個(gè)字節(jié)
void MyI2C_SendByte(uint8_t Byte);//接收一個(gè)字節(jié)
uint8_t MyI2C_ReceiveByte(void);//發(fā)送應(yīng)答
void MyI2C_SendAck(uint8_t AckBit);//接收應(yīng)答
uint8_t MyI2C_ReceiveAck(void);#endif


總結(jié)

????????以上就是今天要講的內(nèi)容,本文僅僅簡(jiǎn)單介紹了軟件I2C讀寫代碼。其中有使用的兩個(gè)引腳、I2C配置、時(shí)序的高低電平等協(xié)議相關(guān)內(nèi)容的代碼配置細(xì)節(jié)。

http://www.risenshineclean.com/news/30235.html

相關(guān)文章:

  • 做網(wǎng)站開發(fā)的集團(tuán)品牌策劃案例
  • 網(wǎng)站建設(shè)證書網(wǎng)站建設(shè)流程步驟
  • 學(xué)校網(wǎng)站建設(shè)電話代刷網(wǎng)站推廣鏈接免費(fèi)
  • 網(wǎng)絡(luò)運(yùn)營(yíng)和網(wǎng)絡(luò)營(yíng)銷的區(qū)別合肥seo網(wǎng)絡(luò)優(yōu)化公司
  • 上海網(wǎng)站建設(shè)哪家品牌推廣軟文案例
  • 提供秦皇島網(wǎng)站建設(shè)江西省seo
  • 沒有網(wǎng)站可以做seo最新軍事頭條
  • 做網(wǎng)站公司職務(wù)免費(fèi)找精準(zhǔn)客戶軟件
  • 北京網(wǎng)站推廣seo優(yōu)化頁面設(shè)計(jì)
  • 西安門戶網(wǎng)站建設(shè)公司哪家好軟文廣告經(jīng)典案例600
  • 怎么在word里做網(wǎng)站百度競(jìng)價(jià)代運(yùn)營(yíng)公司
  • 綜合社區(qū)網(wǎng)站開發(fā)費(fèi)用公司網(wǎng)站建設(shè)費(fèi)
  • 電銷防封號(hào)系統(tǒng)seo入門到精通
  • 娛樂公司網(wǎng)站建設(shè)價(jià)格電腦培訓(xùn)學(xué)校排名
  • 成都企業(yè)網(wǎng)站建站大數(shù)據(jù)精準(zhǔn)營(yíng)銷的策略
  • 新疆建設(shè)管理局網(wǎng)站seo基礎(chǔ)教程使用
  • 網(wǎng)絡(luò)營(yíng)銷推廣的優(yōu)劣勢(shì)深圳短視頻seo教程
  • 怎么增加網(wǎng)站的外鏈?zhǔn)謾C(jī)系統(tǒng)優(yōu)化
  • 煙臺(tái)網(wǎng)站建設(shè)公司鏈接推廣平臺(tái)
  • 鹽城網(wǎng)站開發(fā)招代理最火的網(wǎng)絡(luò)推廣平臺(tái)
  • dede網(wǎng)站模版百度app優(yōu)化
  • 國外優(yōu)秀設(shè)計(jì)網(wǎng)站推薦seo關(guān)鍵字排名優(yōu)化
  • 中國公司排行榜前十名seo怎么發(fā)布外鏈
  • wordpress網(wǎng)站添加背景音樂自助建站系統(tǒng)個(gè)人網(wǎng)站
  • 網(wǎng)站建設(shè)功能是什么意思萬詞優(yōu)化
  • web模板免費(fèi)下載網(wǎng)站常見的推廣平臺(tái)有哪些
  • 臨海網(wǎng)站制作費(fèi)用如何記賬網(wǎng)站優(yōu)化 福州
  • 網(wǎng)頁設(shè)計(jì)與制作06386自考真題windows優(yōu)化大師官方下載
  • 免費(fèi)com域名注冊(cè)網(wǎng)站上海seo推廣整站
  • 天津平臺(tái)網(wǎng)站建設(shè)哪家好如何免費(fèi)建立一個(gè)網(wǎng)站