从脉冲到数据:51单片机IIC时序模拟与GXHT3L连续模式驱动实现

# 从脉冲到数据:51单片机IIC时序模拟与GXHT3L连续模式驱动实现


IIC协议是嵌入式开发中连接传感器、存储芯片的核心串行协议,然而51单片机多数型号不集成硬件IIC控制器。软件模拟时序成为开发者必须跨越的门槛。本文以温湿度传感器GXHT3L为载体,从起始信号、应答机制、字节传输的底层脉冲出发,完整呈现IIC时序的软件模拟方法,并解析GXHT3L连续转换模式下的数据读取与CRC校验。


---


## 一、IIC总线时序的软件模拟


IIC总线由SCL(时钟线)与SDA(数据线)构成,**所有时序信号均通过两根I/O口的电平变化组合产生**。


**起始信号**:SCL高电平期间,SDA由高电平切换至低电平。

```c

sbit sda = P0^1;

sbit scl = P0^2;


void i2c_start() {

    scl = 1;

    sda = 1;

    delay10us();  // 建立时间 >4.7μs

    sda = 0;      // 下降沿,产生起始条件

    delay10us();  // 保持时间 >4μs

    scl = 0;      // 拉低SCL,准备传输数据

}

```


**停止信号**:SCL高电平期间,SDA由低电平切换至高电平。

```c

void i2c_stop() {

    sda = 0;

    scl = 1;

    delay10us();  // 停止信号建立时间

    sda = 1;      // 上升沿,产生停止条件

    delay10us();  // 总线空闲时间

}

```


**字节写入**:高位先行,每1位数据在SCL低电平时设置SDA,SCL高电平时被从机读取。

```c

void i2c_write_byte(unsigned char dat) {

    unsigned char i;

    for(i = 0; i < 8; i++) {

        scl = 0;

        if(dat & 0x80) sda = 1;

        else sda = 0;

        dat <<= 1;

        scl = 1;          // 从机在SCL高电平期间读取SDA

        delay10us();

    }

    scl = 0;

}

```


**应答检测**:第9个时钟周期,主机释放SDA(置1),检测从机是否将SDA拉低。

```c

unsigned char i2c_wait_ack() {

    unsigned char ack;

    sda = 1;          // 释放总线

    scl = 1;

    delay10us();

    ack = sda;        // 0表示应答,1表示非应答

    scl = 0;

    return ack;

}

```

<"b8.a8k1.org.cn"><"x0.a8k1.org.cn"><"r4.a8k1.org.cn">

**字节读取**:主机释放SDA,每个SCL高电平周期读取一位。

```c

unsigned char i2c_read_byte() {

    unsigned char i, val = 0;

    sda = 1;          // 释放总线

    for(i = 0; i < 8; i++) {

        val <<= 1;

        scl = 1;

        if(sda) val |= 0x01;

        scl = 0;

    }

    return val;

}

```


> 延时时长直接影响IIC通信速率。10μs延时对应约50kHz速率,若需400kHz快速模式,延时需压缩至1.25μs以内。**时钟频率应严格匹配从机规格**,GXHT3L最高支持1MHz。


---


## 二、GXHT3L传感器驱动实现


GXHT3L是中科银河芯开发的单芯片温湿度传感器,集成16位ADC,**I2C地址由ADDR引脚电平决定**:接低电平时地址0x44,接高电平时地址0x45。


### 2.1 连续转换模式启动


连续转换模式下,传感器以2.5ms周期自主测量,主机可直接读取最新数据。启动命令为`0x2C10`:


```c

void GXHT3L_start_continuous() {

    i2c_start();

    i2c_write_byte(0x44 << 1 | 0);  // 地址+写位

    i2c_wait_ack();

    i2c_write_byte(0x2C);           // 命令高字节

    i2c_wait_ack();

    i2c_write_byte(0x10);           // 命令低字节(高重复性)

    i2c_wait_ack();

    i2c_stop();

}

```


### 2.2 温湿度数据读取


连续模式下读取数据无需再次发送测量命令,直接发起读事务即可。**数据格式为“温度高8位+温度低8位+CRC+湿度高8位+湿度低8位+CRC”**。


```c

void GXHT3L_read_data(float *temp, float *hum) {

    unsigned char buf[6];

    unsigned int rawT, rawH;

    

    i2c_start();

    i2c_write_byte(0x44 << 1 | 1);  // 地址+读位

    if(i2c_wait_ack() == 0) {       // 从机应答

        buf[0] = i2c_read_byte(1);  // 温度高8位,发送ACK

        buf[1] = i2c_read_byte(1);  // 温度低8位

        buf[2] = i2c_read_byte(1);  // 温度CRC

        buf[3] = i2c_read_byte(1);  // 湿度高8位

        buf[4] = i2c_read_byte(1);  // 湿度低8位

        buf[5] = i2c_read_byte(0);  // 湿度CRC,发送NACK

    }

    i2c_stop();

    

    // CRC校验(实现略,多项式0x31)

    if(!check_crc(buf, 2, buf[2])) return;

    if(!check_crc(buf+3, 2, buf[5])) return;

    <"k6.a8k1.org.cn"><"p3.a8k1.org.cn"><"m7.a8k1.org.cn">

    rawT = (buf[0] << 8) | buf[1];

    rawH = (buf[3] << 8) | buf[4];

    

    *temp = (175.0 * (float)rawT / 65535.0) - 45.0;  // 温度转换

    *hum  = 100.0 * (float)rawH / 65535.0;           // 湿度转换

}

```


**数据转换公式**源于传感器手册:温度范围-45℃至+130℃,对应数字量0~65535;湿度范围0~100%RH,线性映射。


### 2.3 CRC校验的必要性


GXHT3L为每个16位数据附加8位CRC校验码,多项式为`x^8 + x^5 + x^4 + 1`(0x31)。**在强干扰工业环境中,跳过CRC校验可能导致数十摄氏度的异常跳变**。校验算法可复用SHT3x系列的标准实现。


---


## 三、连续模式与单次模式的选择


| 模式         | 启动方式                     | 数据获取延迟 | 功耗   | 适用场景                     |

|--------------|------------------------------|--------------|--------|------------------------------|

| 单次转换模式 | 每次测量需发0x2C10命令      | ≥15ms        | 较低   | 电池供电、低频采集           |

| 连续转换模式 | 启动后自主测量,直接读数据   | <3ms         | 较高   | 实时监控、动态响应           |


**连续模式下,读取频率不应高于传感器内部更新速率(约2.5ms/次)**,否则可能读到同一笔未更新的数据。


---


## 四、常见问题与调试要点


1. **总线死锁**:从机异常时可能持续拉低SDA。模拟时序需设计**总线恢复机制**——发送9个以上SCL时钟迫使从机释放总线。


2. **延时精度**:51单片机`nop()`约1μs(12MHz晶振),可用`_nop_()`函数构建微秒级延时,避免使用`delay10ms()`这类毫秒级函数降低通信速率。


3. **地址左移混淆**:传感器手册地址0x44是**7位器件地址**,IIC通信字节需左移1位,最低位补R/W。初学者易直接发送0x44导致寻址失败。


4. **ACK/NACK时机**:读取最后一字节后**必须发送NACK**,否则从机认为主机仍需更多数据,持续占用总线。


---


软件模拟IIC的实质,是将协议规范转化为**精确的电平序列**。理解起始、停止、应答、字节读写的脉冲关系后,任何IIC从机的驱动都只是命令序列的排列组合。GXHT3L的连续模式读取,正是这一方法论的典型实践——以稳定的底层时序为基,逐字节组装出完整的数据通路。


请使用浏览器的分享功能分享到微信等