首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

嵌入式開發:使用 GPIO 模擬 I2C 總線時序驅動 SHT11 溫濕度傳感器

     編輯:關於C語言

為什麼要軟件模擬 I2C?

  • 部分 MCU 缺乏硬件 I2C 控制器,或引腳已被佔用
  • 某些傳感器(如 SHT11)使用非標準 I2C 時序(啟動信號不同),硬件 I2C 無法兼容
  • 低速通信(≤100 kHz)下,GPIO 翻轉時序易於控制,調試靈活

SHT11 非標準啟動時序

標準 I2C:SCL 高電平時 SDA 由高→低產生 START。
SHT11:SDA 先拉低,SCL 產生一個時鐘脈沖(高→低→高),SDA 再拉高。這要求精確控制 GPIO 時序。

GPIO 宏定義(以 PIC 單片機為例)

#define IIC_SCL       RC0
#define IIC_SDA       RC1
#define IIC_SCL_DIR   TRISC0
#define IIC_SDA_DIR   TRISC1
#define INPUT  1
#define OUTPUT 0

#define SCL_HIGH()  IIC_SCL_DIR = INPUT   // 釋放總線,上拉電阻拉高
#define SCL_LOW()   do { IIC_SCL_DIR = OUTPUT; IIC_SCL = 0; } while(0)
#define SDA_HIGH()  IIC_SDA_DIR = INPUT
#define SDA_LOW()   do { IIC_SDA_DIR = OUTPUT; IIC_SDA = 0; } while(0)

關鍵技巧:利用三態輸出特性,輸入模式時由外部上拉電阻拉高(邏輯 1),輸出模式驅動低電平(邏輯 0),實現開漏輸出效果。

核心時序函數實現

1. 啟動信號

void SHT_Start(void) {
    SCL_HIGH(); SDA_HIGH(); delay_us(5);
    SDA_LOW();  delay_us(5);
    SCL_LOW();  delay_us(5);
    SCL_HIGH(); delay_us(5); // SHT11 要求的額外時鐘脈沖
    SDA_HIGH(); delay_us(5);
    SCL_LOW();
}

2. 發送一字節(含應答檢測)

void SHT_WriteByte(unsigned char dat) {
    for (int i = 0; i < 8; i++) {
        if (dat & 0x80) SDA_HIGH(); else SDA_LOW();
        dat <<= 1;
        SCL_LOW();  delay_us(5);
        SCL_HIGH(); delay_us(5); // 上升沿發送數據
    }
    SCL_LOW();
    SDA_HIGH(); delay_us(5); // 釋放總線準備讀取 ACK
    SCL_HIGH(); delay_us(5); // 主機產生第 9 個時鐘讀取 ACK
    // 可在此檢測 IIC_SDA 是否為 0(從機應答)
    SCL_LOW();
    SDA_HIGH();
}

3. 讀取一字節(發送 ACK/NACK)

unsigned char SHT_ReadByte(unsigned char ack) {
    unsigned char dat = 0;
    SDA_HIGH(); // 釋放總線
    for (int i = 0; i < 8; i++) {
        dat <<= 1;
        SCL_HIGH(); delay_us(5);
        if (IIC_SDA) dat |= 1; // 上升沿讀取數據
        SCL_LOW(); delay_us(5);
    }
    // 發送應答
    if (ack) SDA_LOW(); else SDA_HIGH();
    SCL_LOW(); delay_us(5);
    SCL_HIGH(); delay_us(5);
    SCL_LOW();
    SDA_HIGH();
    return dat;
}

4. 停止信號

void SHT_Stop(void) {
    SDA_LOW();  delay_us(5);
    SCL_HIGH(); delay_us(5);
    SDA_HIGH(); delay_us(5); // SCL 高時 SDA 低→高
    SCL_LOW();
}

工程實踐建議

  • 時序裕度:delay_us(5) 滿足 SHT11 最小 4.7μs 時鐘週期,實際應根據 MCU 主頻校準
  • 中斷保護:關鍵時序段關閉中斷(cli()/sei()),防止時序被打亂
  • 總線恢復:通信異常時發送 9 個時鐘脈沖並發送 STOP,強制從機釋放總線
  • 移植性:將 GPIO 操作封裝為宏/內聯函數,便於移植到 STM32、ESP32 等平台

總結

GPIO 模擬 I2C 是嵌入式工程師必備技能。通過精確控制 SCL/SDA 時序,可驅動任何兼容 I2C 協議的設備,甚至適配非標準時序器件。關鍵在於理解開漏輸出機制、掌握時序圖參數、合理設置延時與中斷保護。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved