STM32的IIC应用详解2
IIC簡(jiǎn)單介紹
小編能力有限,寫(xiě)的不對(duì)處還望諸位大俠指正哈!
?? ? ?平時(shí)所說(shuō)的IIC通信指的是用單片機(jī)的兩個(gè)I/O端口模擬出來(lái)的IIC,正真的IIC實(shí)際上是一塊硬件電路,那是飛利浦公司的專利,要想用那就拿錢來(lái)買。有大牛既想用又不想花錢,就用兩個(gè)端口模擬出了IIC通信協(xié)議,因?yàn)榉奖?#xff08;51上的IIC改一下端口配置就可以在STM32F103上使用)所以被廣泛使用。啰嗦了這么多,下面進(jìn)入正題,嘿嘿。
?? ? ?首先IIC通信由兩根線組成:?
?? ? ? ? ?? ? ? 時(shí)鐘線SCL:在通信過(guò)程起到控制作用。?
?? ? ? ? ?? ? ? 數(shù)據(jù)線SDA:用來(lái)一位一位的傳送數(shù)據(jù)。?
?? ? ?其次IIC通信過(guò)程由開(kāi)始、結(jié)束、發(fā)送、接收四個(gè)函數(shù)構(gòu)成,接下來(lái)小編通過(guò)介紹這四個(gè)函數(shù)來(lái)介紹IIC通信協(xié)議。
?? ? ?先記住兩個(gè)概念,很重要:?
?? ? ? ? ?? ? ??1、(在發(fā)送、接收數(shù)據(jù)的時(shí)候)當(dāng)SCL為高電平時(shí),SDA線不允許變化;當(dāng)SCL線為低電平時(shí),SDA線可以任意0、1變化。?
?? ? ? ? ?? ? ??2、(在任意時(shí)候)只有當(dāng)SCL為高電平時(shí),IIC電路才對(duì)SDA線上的電平(0或者1)進(jìn)行記錄(這個(gè)記錄小編把它叫做采樣),當(dāng)SCL線為低電平時(shí),無(wú)論SDA是高還是低,IIC電路都不對(duì)SDA進(jìn)行采樣。
- ?
開(kāi)始信號(hào)
?? ? ?IIC協(xié)議規(guī)定:當(dāng)SCL為高電平時(shí),SDA由高電平變成低電平,認(rèn)為這是IIC通信的開(kāi)始信號(hào)。具體代碼實(shí)現(xiàn)如下:
void MPU_IIC_Start(void) {MPU_SDA_OUT(); //sda線輸出MPU_IIC_SDA=1; MPU_IIC_SCL=1;MPU_IIC_Delay();MPU_IIC_SDA=0;//SDA線由高變低MPU_IIC_Delay();MPU_IIC_SCL=0; }?? ? ?如上述代碼所示,起始狀態(tài)SCL和SDA均為高點(diǎn)平,延時(shí)下(一般4.7us左右),之后拉低SDA,這樣起始信號(hào)就產(chǎn)生了,外設(shè)的IIC接口一收到這種電平變化就認(rèn)為 哦哦,要開(kāi)始IIC通信了。最后一句拉低SCL的操作小編認(rèn)為是一是為了允許SDA線0、1變化;二是為了防止外設(shè)的IIC對(duì)SDA線進(jìn)行采樣。
結(jié)束信號(hào)
?? ? ?IIC協(xié)議規(guī)定:當(dāng)SCL為高電平時(shí),SDA由低電平變成高電平,認(rèn)為這是IIC通信的結(jié)束信號(hào)。具體代碼實(shí)現(xiàn)如下:
void IIC_Stop(void) {SDA_OUT();//sda線輸出IIC_SCL=0;IIC_SDA=0;delay_us(4); IIC_SCL=1;delay_us(4); IIC_SDA=1;//發(fā)送I2C總線結(jié)束信號(hào) }?? ? ?如上述代碼所示,先把SCL拉低允許SDA變化,再把SDA拉低(為拉高做準(zhǔn)備,哈哈)延時(shí),再把SCL拉高,(讓外設(shè)的IIC電路采集SDA線上的電平0)再延時(shí)(外設(shè)采樣需要花時(shí)間)之后拉高SDA(因?yàn)镾CL已經(jīng)為高了,所以外設(shè)直接就采樣了)。這樣結(jié)束信號(hào)就產(chǎn)生了,外設(shè)IIC接收到這種電平變換意識(shí)到 哦哦 IIC通信結(jié)束了。
應(yīng)答信號(hào)
?? ? ?IIC協(xié)議規(guī)定,當(dāng)接受到一個(gè)字節(jié)(8bit)后,數(shù)據(jù)接收方必須向數(shù)據(jù)發(fā)送方返回一個(gè)低電平信號(hào),此信號(hào)稱作應(yīng)答信號(hào)(表示上一個(gè)數(shù)據(jù)成功接受可以繼續(xù)接受)。若未返回應(yīng)答信號(hào),則認(rèn)為數(shù)據(jù)接收方出現(xiàn)故障。由于單片的這端是IIC程序,而外設(shè)那端是IIC電路,所以當(dāng)單片機(jī)發(fā)送數(shù)據(jù)時(shí),外設(shè)的IIC電路會(huì)自動(dòng)返回應(yīng)答信號(hào)(前提外設(shè)沒(méi)故障,嘿嘿)。當(dāng)單片機(jī)接收數(shù)據(jù)的時(shí)候,應(yīng)答信號(hào)就得我們自己寫(xiě)了。?
?? ? ?//應(yīng)答信號(hào)具體實(shí)現(xiàn)如下:
?? ? ?如上代碼所示,先把時(shí)鐘線拉低,再把數(shù)據(jù)線拉低,最后把始終先拉高,這樣就告訴外設(shè)趕緊把數(shù)據(jù)線上的低電平才進(jìn)去,應(yīng)答信號(hào)就這樣反回了,是不是很簡(jiǎn)單呢。非應(yīng)答信號(hào)的代碼如下,也很近單,小編就不啰嗦了。
void IIC_NAck(void) {IIC_SCL=0;SDA_OUT();IIC_SDA=1;delay_us(2);IIC_SCL=1;delay_us(2);IIC_SCL=0; }發(fā)送函數(shù)
?? ? ?發(fā)送數(shù)據(jù)就是把字節(jié)一位一位的發(fā)送出去,具體實(shí)現(xiàn)如下:
void IIC_Send_Byte(u8 txd) { u8 t; SDA_OUT(); IIC_SCL=0;for(t=0;t<8;t++){ IIC_SDA=(txd&0x80)>>7;//把要發(fā)送的數(shù)據(jù)的最高位放到數(shù)據(jù)線上txd<<=1;//次高位變最高位(為下次發(fā)送做準(zhǔn)備) delay_us(2); //必須延時(shí)IIC_SCL=1;//拉高時(shí)鐘線,告訴外設(shè)可以采樣了delay_us(2); IIC_SCL=0;//拉低時(shí)鐘線,允許數(shù)據(jù)線發(fā)生變化delay_us(2);} }?? ? ?對(duì)了單片機(jī)發(fā)送完一個(gè)字節(jié)后面必須跟一個(gè)等外應(yīng)答函數(shù),萬(wàn)一外設(shè)掛了呢,單片機(jī)還在傻傻的發(fā)送,好可憐呢?具體實(shí)現(xiàn)如下:
u8 IIC_Wait_Ack(void) {u8 Time=0;SDA_IN(); IIC_SDA=1;delay_us(1); IIC_SCL=1;delay_us(1); while(IIC_SDA){Time++;if(Time>250){IIC_Stop();return 1;}}IIC_SCL=0; return 0; }?? ? ?這段代碼很簡(jiǎn)單,就是先讓SDA=1,再判斷在一定時(shí)間內(nèi)SDA是否變?yōu)?,從而識(shí)別出外設(shè)有沒(méi)有發(fā)送應(yīng)答信號(hào)。這里就不贅述了。
接受函數(shù)
?? ? ?跟發(fā)送一樣,只是把數(shù)據(jù)一位一位接受進(jìn)來(lái),記得要返回應(yīng)答信號(hào)喲。具體實(shí)現(xiàn)如下:
u8 IIC_Read_Byte(unsigned char ack) {unsigned char i,receive=0;SDA_IN();for(i=0;i<8;i++ ){IIC_SCL=0; delay_us(2);IIC_SCL=1;receive<<=1;if(IIC_SDA)receive++; delay_us(1); } if (!ack)IIC_NAck();//非應(yīng)答elseIIC_Ack(); //應(yīng)答 return receive; }- ?
?? ? ?首先我們要確定這個(gè)字節(jié)接收完畢后還需不需要繼續(xù)接受字節(jié),繼續(xù)ACK=1,不繼續(xù)ACK=0。循環(huán)中,時(shí)鐘線拉低,先允許外設(shè)把數(shù)據(jù)線0、1變換,在時(shí)鐘線拉高,禁止數(shù)據(jù)線變化(把外設(shè)送到數(shù)據(jù)線上的電平固定住)。 當(dāng)i=0時(shí),receive<<=1;不起任何作用,但是以后就有用了,有大用處。再判斷下數(shù)據(jù)線上電平是高還是低,假設(shè)IIC_SDA=1,則receive++就是把外設(shè)輸出的1方到receive的最低位上去,這樣一位數(shù)據(jù)就接受進(jìn)來(lái)了。循環(huán)第二次,此時(shí)i=1,仍舊數(shù)據(jù)線拉低,再拉高,先允許變化再固定,receive<<=1起作用了,把剛才接受到的1移到次低位上去,給即將要接收的電平騰個(gè)地,之后的在判斷什么什么的就都一樣了哈,讀者自己分析。八次循環(huán)以后,一個(gè)字節(jié)就接受到了。別忘了應(yīng)答信號(hào)喲。最后把接受到了的數(shù)據(jù)返回,則一個(gè)字節(jié)就真正接收到了。是不是很簡(jiǎn)單呢??
?? ? ?上述幾個(gè)函數(shù)是IIC通信協(xié)議,具體怎么使用得看不同外設(shè)的通信方式是怎么規(guī)定的。這些就只能見(jiàn)招拆招了,嘿嘿,至此,小編啰嗦完畢!
總結(jié)
以上是生活随笔為你收集整理的STM32的IIC应用详解2的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: STM32的IIC应用详解1
- 下一篇: 已解决:IAR编译时出现duplicat