01、概述
在之前的文章中《STM32IIC詳解》中詳細講解了IIC協議,並且使用是NXP的官方手冊,demo示例使用IIC讀取RTC晶片,執行正常,沒有任何問題。並且更新了《IIC踩過的坑》,講述了在使用IIC讀取RTC晶片時遇到的問題,併成功解決。
我以為我已經完全學會了IIC,但現實卻打了臉,我在使用《STM32IIC詳解》文中的IIC驅動,去驅動MPU6050時,總是讀取失敗。這個驅動明明是驗證過的,為什麼會有問題。讓我一度很是鬱悶。
02、問題所在
不賣關子,直接說問題,是我之前的IIC驅動有問題。
問題1:
錯誤將CLK訊號GPIO設定為推輓輸出。應該設定為開漏輸出。
問題2:
讀取函式有bug。1處應該先左移再讀取SDA的資料,然後刪除2處的資料。
問題2:這個就是純粹的bug了,大家應該看出來了。在RTC的驅動沒有觸發bug的原因是:在RTC的IIC接收資料中,實際應用中最高位為0,觸發不了這個bug。而在MPU6050的IIC接收資料中就觸發了這個bug。我也在感慨,有時候不是程式沒有bug,而是可能沒有觸發。
問題1:這個問題,其實很簡單,IIC協議中也提到過,很多大神也知道需要將MCU的IIC引腳設定為開漏輸出。這一方面我也瞭解,但是沒有在意,因為一直讀取RTC一直“沒有bug”。接下來我將細細和大家分享一下IIC為什麼需要開漏輸出,開漏輸出和推輓輸出有什麼區別。精通的大佬可以出門左轉了,想了解一下的同學歡迎繼續往下看。
03、開漏輸出
STM32F207的GPIO框圖如下
普通輸入模式下,上拉和下拉電阻(微弱)的存在。主要是由於P-MOS和N-MOS的存在分為下列兩種模式
-
開漏模式:輸出暫存器是 0 時,啟用 N-MOS, 而輸出暫存器是 1 時,埠保持高阻態(P-MOS 不會被使能)
-
推輓輸出: 輸出暫存器是 0 時,啟用 N-MOS, 而輸出暫存器是 1 時,啟用 P-MOS。
上面是我的在文章《STM32 GPIO詳解》中的說明,GPIO的其他模式請看文章《STM32 GPIO詳解》。上文說到開漏模式輸出1時,埠保持高阻態,這個時候如果埠外上拉電阻,就可以輸出電平1。
開漏輸出的作用:
1:防止短路,在一些應用中,兩個GPIO連結在一起(中間沒有串電阻),或者在匯流排應用中,需要將MCU的多個GPIO連線在一起。如果都設定成推輓輸出,當一個GPIO輸出1,另一個輸出0,那麼就短路了,直接涼涼。如下圖
如果換成開漏輸出,GPIO的高電平是靠上拉電阻的,也就是VCC和GND之間會有個電阻,不會出現短路的問題。這樣的電路就安全一些,所以部分匯流排採用開路輸出。
2:線與:開漏輸出還能實現線與,減少一個與門,簡化電路。這個問題下文講到。
04、開漏輸出在IIC的應用
IIC為什麼需要開漏輸出,除了上文說的到的防止短路,還有一個重要的因素就是線與。
首先我們先說一下線與功能:
線與邏輯,即兩個輸出端(包括兩個以上)直接互連就可以實現“AND”的邏輯功能。在匯流排傳輸等實際應用中需要多個門的輸出端並聯連線使用,而一般TTL門輸出端並不能直接並接使用,否則這些門的輸出管之間由於低阻抗形成很大的短路電流(灌電流),而燒壞器件。
在硬體上,可用集電極開路門(OC門)或三態門(TS門)來實現。用OC門實現線與,應同時在輸出埠加一個上拉電阻。
上面是數電知識,我的個人簡單理解是:就是a,b兩條線,兩端接一塊做輸出,另兩端做輸入。如果輸入都是高電平,那輸出就是高電平,否則輸出就是低電平。
那麼線與在IIC中的應用是什麼呢?
答案是:多主裝置搶佔匯流排的仲裁。
在之前IIC讀取RTC或IIC讀取MPU6050的情況,都是一個主機,一個從機。但IIC設計中可以支援多主機模式,那麼就面臨一個問題,當多個主機同時啟動匯流排時,如果仲裁的問題。線與邏輯就起到了作用。
假設主裝置A需要啟動IIC,它需要在SCL高電平時,將SDA由高電平轉換為低電平作為啟動訊號。主裝置A在把SDA拉高後,它需要再檢查一下SDA的電平。
-
SDA是高電平,說明主裝置A可以佔用匯流排,然後主裝置A將SDA拉低,開始通訊。
-
SDA是低電平, 說明有人已經捷足先登了,主裝置A不能佔用匯流排, 結束通訊。
如果主裝置A拉高SDA時,已經有其他主裝置將SDA拉低了。由於1 & 0 = 0 那麼主裝置A在檢查SDA電平時,會發現不是高電平,而是低電平,說明其他主裝置搶佔匯流排的時間比它早,裝置A只能放棄佔用匯流排。如果是高電平, 則可以佔用。
這就是IIC通訊開漏輸出的原因。上拉電阻的原因就是由於開漏輸出的特性,需要上拉電阻在輸出1時,提高驅動力。
05、最後補充
最後說一下為什麼之前使用推輓輸出的IIC讀取RTC沒有問題,這個因為上拉電阻的阻值不同,RTC的上拉電阻即使推輓輸出也可以正常拉高拉低電平。這個根據上文講述的,可以查MCU的datasheet,確認IO的PMOS和NMOS的阻抗,計算一下電壓。
還有一個簡單粗暴的辦法,直接使用示波器看波形也可以發現問題。
點選檢視本文所在的專輯,開發工具