【記錄貼】STM32 I2C 控制 OLED 卡死?根源在 SR1 與 SR2 的讀取操作

問題描述

最近在復用以前STM32F407控制OLED的代碼,移植到STM32F103 上,使用硬件 I2C 通信方式。按照常規流程,先發送 OLED 的從機地址,OLED 有正常應答,但當發送第一個控制命令(0xAE)前的控制字節(0x00)時,程序卡在了while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE))這一行,始終等待不到 TXE 標志置位。

更讓人疑惑的是,同樣的 OLED 模塊,用 ESP32 通過 U8G2 庫控制時完全正常,說明 OLED 硬件本身沒問題,問題大概率出在 STM32 的 I2C 配置或通信邏輯上。

解決過程

嘗試解決

一開始,我以為是控制字節發送錯誤,反復確認后發現發送的是正確的 0x00(命令控制字節),排除了這個可能。

接著懷疑是 I2C 地址錯誤,用示波器抓取波形,確認從機地址發送正確且 OLED 有應答,這一步也沒問題。

然后檢查 I2C 初始化配置,時鐘頻率、ACK 使能等參數都設置正確,GPIO 也配置成了復用開漏輸出模式,硬件使用 ESP32說明也沒問題。

最后把目光聚焦在 I2C 狀態標志的處理上。代碼流程大概是這樣的:

static void iic1_send_byte(uint8_t addr, uint8_t data)
{while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));// 起始信號I2C_GenerateSTART(I2C1, ENABLE);while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_SB));// 發送從機地址sI2C_Send7bitAddress(I2C1, 0x78, I2C_Direction_Transmitter);while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR));// 發送模式I2C_SendData(I2C1, addr);while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE));I2C_SendData(I2C1, data); while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE));// 發送停止信號I2C_GenerateSTOP(I2C1, ENABLE);
}

正確的解決方法

在反復查閱 STM32 參考手冊并嘗試多種方法后,發現問題出在ADDR標志的清除方式上。STM32 的 I2C 硬件設計規定,ADDR標志必須通過先讀取 SR1 寄存器,再讀取 SR2 寄存器的方式才能清除。

修改后的代碼如下:

static void iic1_send_byte(uint8_t addr, uint8_t data)
{while(I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY));// 起始信號I2C_GenerateSTART(I2C1, ENABLE);while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_SB));// 發送從機地址sI2C_Send7bitAddress(I2C1, 0x78, I2C_Direction_Transmitter);while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR));//! 清除I2C_FLAG_ADDR標志// ----------------------------------------------I2C_ReadRegister(I2C1, I2C_Register_SR1);I2C_ReadRegister(I2C1, I2C_Register_SR2);// ----------------------------------------------// 發送模式I2C_SendData(I2C1, addr);while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE));I2C_SendData(I2C1, data); while(!I2C_GetFlagStatus(I2C1, I2C_FLAG_TXE));// 發送停止信號I2C_GenerateSTOP(I2C1, ENABLE);
}

增加讀取 SR2 寄存器的操作后,程序不再卡死,TXE 標志能正常置位,控制命令也順利發送給了 OLED,問題終于解決。

思考:為什么不這么做可以

解決問題后,我心中產生了一個疑問:為什么網上很多 STM32 控制 OLED 的教程代碼里,都沒有顯式地同時讀取 SR1 和 SR2 寄存器,代碼卻能正常工作,經過分析,主要有以下幾個原因:

1. 使用 HAL 庫封裝了底層操作

現在很多教程采用 HAL 庫進行開發,HAL 庫的 I2C 相關函數(如HAL_I2C_Master_Transmit)內部已經封裝了ADDR標志的清除邏輯,包括先讀 SR1 再讀 SR2 的操作。用戶在調用這些庫函數時,不需要關心底層寄存器的操作,所以教程代碼里看不到相關讀取操作,但實際上底層已經處理了。

2. 采用軟件 I2C 方式

其實在CSDN中大部分教程也是軟件I2C,為了簡化操作,采用軟件模擬 I2C 時序的方式控制 OLED。軟件 I2C 通過直接操作 GPIO 引腳來模擬 I2C 通信,不涉及 STM32 的 I2C 硬件外設,自然不需要處理 SR1 和 SR2 寄存器。

3. 不規范代碼的偶然工作

極少數情況下,一些不規范的代碼(比如只讀取 SR1 寄存器,甚至不讀取任何寄存器)可能在特定條件下偶然工作。這可能是因為 I2C 總線速率極低,或者使用的 STM32 型號存在硬件特性,使得ADDR標志在未正確清除的情況下,狀態機也能進入數據發送階段。但這種情況很不穩定,換個環境或芯片型號可能就會出現問題。

總的來說,直接操作 STM32 I2C 硬件外設時,嚴格按照參考手冊的要求,通過先讀 SR1 再讀 SR2 的方式清除ADDR標志,才是規范且可靠的做法。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/93034.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/93034.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/93034.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【AI驅動的語義通信:突破比特傳輸的下一代通信范式】

文章目錄1 語義通信簡介1.1 基本概念:什么是語義通信?語義通信的核心目標1.2 基本結構:語義通信系統結構語義通信系統的通用結構組成語義通信系統的結構關鍵模塊1.3 基于大模型的語義通信關鍵技術🧠語義通信系統中AI大模型的設計建…

網絡原理-HTTP

應用層自定義協議自定義協議是指根據特定需求設計的通信規則,用于設備或系統間的數據交換。其核心在于定義數據結構、傳輸方式及處理邏輯。協議結構示例典型的自定義協議包含以下部分:頭部(Header):標識協議版本、數據…

ROS配置debug指南

一. 安裝插件 下面的這一個插件過期了需要用下面的這一個插件來替換:二. 設置CMakeLists.txt的編譯模式 set(CMAKE_BUILD_TYPE "Debug") set(CMAKE_CXX_FLAGS_DEBUG "$ENV{CXXFLAGS} -O0 -Wall -g -ggdb") set(CMAKE_CXX_FLAGS_RELEASE "$ENV{CXXFLAG…

微軟正式將GPT-5接入Microsoft Copilot Studio(國際版)

微軟宣布正式在Microsoft Copilot Studio(國際版)中集成GPT-5,推動智能體構建能力實現突破性升級。此次更新不僅為企業用戶帶來更高效的響應速度、更精準的語境理解能力,還通過增強的邏輯推理功能,顯著提升了AI交互的深…

微算法科技(NASDAQ:MLGO)通過蟻群算法求解資源分配的全局最優解,實現低能耗的區塊鏈資源分配

隨著區塊鏈網絡規模的不斷擴大和業務需求的日益復雜,資源分配問題逐漸成為制約其發展的關鍵因素之一。傳統的區塊鏈資源分配方法往往存在效率低下、能耗過高、難以達到全局最優解等問題。高能耗不僅增加了運營成本,還對環境造成了較大的壓力。因此&#…

深入淺出JVM:Java虛擬機的探秘之旅

深入淺出JVM:Java虛擬機的探秘之旅一、JVM 初相識:揭開神秘面紗 在 Java 的世界里,JVM(Java Virtual Machine,Java 虛擬機)就像是一個神秘的幕后大 boss,掌控著 Java 程序運行的方方面面。你可以…

Nginx學習筆記(八)—— Nginx緩存集成

🗄🗄 Nginx緩存集成 📌📌 一、緩存核心價值 #mermaid-svg-CNji1KUDOsF8MwoY {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-CNji1KUDOsF8MwoY .error-icon{fill:#5522…

httpx 設置速率控制 limit 時需要注意 timeout 包含 pool 中等待時間

假設通過 httpx.Client 設置 limit 速率控制后,同時發起多個請求訪問 youtube。并且由于科學原因一直連接不上 假設一共 4 個連接,max_connection2,timeout5s。 默認會發生的情況不是前兩個連接 tcp 握手 timeout,后兩個連接再發起…

【網絡】TCP/UDP總結復盤

1.UDP的格式2.TCP的格式3.TCP是來解決什么問題的?答:解決IP層的不可靠傳輸問題,可能數據包丟失、損壞、重復等為上層應用層提高可靠有序的數據傳輸服務通過校驗和、確認應答機制、序列號來解決不可靠傳輸和無序性問題通過流量控制--->>…

Nginx 配置中,root 和 alias 區別

在 Nginx 配置中,root 和 alias 都用于定義文件路徑,但它們的行為有重要區別,特別是 路徑拼接方式 和 末尾斜杠 (/) 的影響。1. root 和 alias 的區別 (1) root 指令 作用:root 會將 location 的 URI 拼接到 root 路徑后面&#x…

基于vue.js的無縫滾動

方法一&#xff1a;基于requestAnimationFrame demo <template><h-page-container class"hoem-page"><h1>無縫滾動</h1><h2>垂直方向</h2><div class"container1"><AutoScroll :data"list" :item-…

【Linux學習|黑馬筆記|Day4】IP地址、主機名、網絡請求、下載、端口、進程管理、主機狀態監控、環境變量、文件的上傳和下載、壓縮和解壓

【DAY4】 今天看的是Linux第四章剩余部分 至此Linux暫時學到這&#xff0c;第五章還包含很多軟件的安裝&#xff0c;但是等我要用的時候再裝吧 我現在只裝了MySQL8.0&#xff0c;具體教程請看筆記安裝教程 內容包含更換鏡像源和安裝配置步驟 文章目錄【DAY4】6&#xff09;IP地…

【合新通信】射頻光纖傳輸模塊詳解

射頻光纖傳輸模塊是一種將射頻(RF)信號通過光纖進行傳輸的關鍵設備&#xff0c;廣泛應用于通信、軍事、廣播電視等領域。以下是關于射頻光纖傳輸模塊的全面介紹&#xff1a;基本原理與組成射頻光纖傳輸模塊主要由以下幾部分組成&#xff1a;電光轉換單元&#xff1a;將輸入的射…

【信息收集】從GET到POST:破解登錄表單的全流程

目標&#xff1a;將瀏覽器數據代理至BP的proxy模塊。將個人PHP的留言板項目首頁登錄數據包代理至BP&#xff0c;并轉發至intrder模塊&#xff0c;進行暴力破解。免責聲明&#xff1a;本文章內容僅用于個人網絡安全知識學習與研究&#xff0c;嚴禁用于任何未經授權的攻擊或非法活…

【辦公自動化】如何使用Python操作PPT和自動化生成PPT?

在現代商業和教育環境中&#xff0c;PowerPoint演示文稿是信息傳遞的重要工具。通過Python自動化PPT創建和編輯過程&#xff0c;可以大幅提高工作效率&#xff0c;特別是在需要批量生成或更新演示文稿的場景下。本文將介紹如何使用python-pptx庫實現PPT自動化&#xff0c;并提供…

18 ABP Framework 模塊管理

ABP Framework 模塊管理 概述 該頁面詳細介紹了在 ABP Framework 解決方案中使用 ABP CLI 及相關工具添加、更新和管理模塊的方法。模塊管理是 ABP 模塊化架構的核心&#xff0c;支持可重用業務和基礎設施功能的集成。模塊通常以 NuGet 和/或 NPM 包的形式分發&#xff0c;有時…

外觀模式C++

外觀模式&#xff08;Facade Pattern&#xff09;是一種結構型設計模式&#xff0c;它為復雜系統提供一個簡化的接口&#xff0c;隱藏系統內部的復雜性&#xff0c;使客戶端能夠更輕松地使用系統。這種模式通過創建一個外觀類&#xff0c;封裝系統內部的交互邏輯&#xff0c;客…

Go 微服務限流與熔斷最佳實踐:滑動窗口、令牌桶與自適應閾值

&#x1f31f; Hello&#xff0c;我是蔣星熠Jaxonic&#xff01; &#x1f308; 在浩瀚無垠的技術宇宙中&#xff0c;我是一名執著的星際旅人&#xff0c;用代碼繪制探索的軌跡。 &#x1f680; 每一個算法都是我點燃的推進器&#xff0c;每一行代碼都是我航行的星圖。 &#x…

Java面試寶典:JVM性能優化

一、運行時優化 Java虛擬機(JVM)的運行時優化是提升Java應用性能的核心環節。JIT(Just-In-Time)編譯器在程序運行過程中,通過分析熱點代碼的執行模式,動態地進行一系列高級優化。這些優化技術對開發者透明,但了解其原理能幫助我們編寫出更易于優化的代碼,從而顯著提升…

Day55--圖論--107. 尋找存在的路徑(卡碼網)

Day55–圖論–107. 尋找存在的路徑&#xff08;卡碼網&#xff09; 今天學習并查集。先過一遍并查集理論基礎。再做下面這一道模板題&#xff0c;就可以結束了。體量不多&#xff0c;但是理解并查集&#xff0c;并使用好&#xff0c;不容易。 后續再找相關的題目來做&#xff0…