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