发新帖本帖赏金 50.00元(功能说明)我要提问
返回列表
打印
[APM32F4]

APM32F402 & HC-SR04超声测距应用场景:温湿度补偿

[复制链接]
218|2
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主

1. 背景:真的准了吗

在之前的文章里,我们介绍了在APM32F402 EVB平台如何使用 HC-SR04 测量距离,并通过卡尔曼滤波等手段让数据变得平稳。然而别忘了,声速并不是“恒速奔跑”,它会随着环境温度、湿度的变化而有所波动。

  • 温度越高,空气分子运动就越激烈,声速就越快;
  • 湿度增加,声速也会稍微提高,因为水蒸气分子质量比空气分子更小;
  • 压强的影响则相对有限,可以在大多数情况下忽略。

也就是说,如果你只是在室温环境下随便测测,可能还好;但如果追求更高精度,或者实地环境温湿度较为极端,就要正儿八经地考虑温湿度补偿了!


2. 温湿度对声音的影响:别让声波了迷路

参考https://www.buildenvi.com/zhuanti/abc/sygs/141111c2#,声音在理想气体中的传播速度可由公式 : v = √(k·R·T)  来估算。其中 k 为气体绝热指数,R 为气体常数,T 为绝对温度(K)。虽说公式挺复杂,但我们大可以用现成的“声音在不同温湿度情况下的速度对照表”:

image1.png

那么,这些公式或表格有什么实战意义?举个例子:本来在 20°C、湿度 60% 时声音速度可能是 343 m/s,但若环境升温到 30°C,又是一个潮湿闷热的地方,声速可能就到了 350 m/s。别看这区区几 m/s,相当于测 2 米时就能带来好几厘米的误差呢!


3. 成本王者 DHT11:小巧又实惠

要想搞定温湿度测量,就得有传感器。DHT11 行业内非常吃香:便宜、易上手、占空间小。精度虽不算“炸裂”,但足以应付日常需求。更何况它有点“萌萌哒”外形,一看就让人有安全感。

image2.png

图片来源:https://images.theengineeringprojects.com/image/webp/2019/02/dht11.jpg.webp?ssl=1

下面是 DHT11 的部分驱动代码,核心逻辑就是通过单总线协议与 MCU 通信,一收一发间便获取到温度与湿度:

static void DHT11_IO_OUT(void)
{
    GPIO_Config_T GPIO_ConfigStruct;
    /* Enable GPIO and AFIO clock */
    RCM_EnableAPB2PeriphClock(DHT11_GPIO_CLK);

    /* Configure DHT11 pin as push-pull output */
    GPIO_ConfigStruct.pin = DHT11_PIN;
    GPIO_ConfigStruct.mode = GPIO_MODE_OUT_PP;
    GPIO_ConfigStruct.speed = GPIO_SPEED_50MHz;
    GPIO_Config(DHT11_GPIO_PORT, &GPIO_ConfigStruct);
}

static void DHT11_IO_IN(void)
{
    GPIO_Config_T GPIO_ConfigStruct;
    /* Enable GPIO and AFIO clock */
    RCM_EnableAPB2PeriphClock(DHT11_GPIO_CLK);

    /* Configure DHT11 pin as floating input */
    GPIO_ConfigStruct.pin = DHT11_PIN;
    GPIO_ConfigStruct.mode = GPIO_MODE_IN_FLOATING;
    GPIO_ConfigStruct.speed = GPIO_SPEED_50MHz;  // For input mode, speed usually has no real effect
    GPIO_Config(DHT11_GPIO_PORT, &GPIO_ConfigStruct);
}

uint8_t DHT11_Read_Data(uint8_t *temp, uint8_t *humi)
{
    uint8_t buf[5];
    uint8_t i;

    /* Reset signal */
    DHT11_Rst();

    /* Check if DHT11 responds */
    if (DHT11_Check() == 0)
    {
        for (i = 0; i < 5; i++)
        {
            buf[i] = DHT11_Read_Byte();
        }
        /* Verify checksum */
        if ((buf[0] + buf[1] + buf[2] + buf[3]) == buf[4])
        {
            *humi = buf[0];
            *temp = buf[2];
        }
        else
        {
            return 1; // Checksum error
        }
    }
    else
    {
        return 1; // Not responding
    }
    return 0; // Success
}

uint8_t DHT11_Init(void)
{
    /* Send reset signal */
    DHT11_Rst();
    /* Check if DHT11 is ready */
    return DHT11_Check();  // 0 => success; 1 => fail
}

就这么几段,你已经能搞定 DHT11 的温湿度测量。理论很简单:拉低、等待、检测响应、读出数据,然后校验和即可。


4. 温湿度补偿:查表法 or 公式?

接下来是超声测距的“终极大招”——温湿度补偿。大致流程是:

  1. 用 DHT11 读出实时温湿度;
  2. 根据温湿度找到对应的声速;
  3. 将 echo 回波时间乘以该声速即可得到实际距离。

4.1 为什么选择“查表法”?

  1. 速度快:大部分MCU 做大规模浮点运算效率较低,不如直接索引查表再做微小插值来得痛快。
  2. 稳定性好:在一定范围内,表格能给出稳定输出,不会因为浮点误差惊扰软件。
  3. 简单可控:如果后续对更多温湿度点有需求,也可以继续扩展表格。

当然,APM32F402 内置 FPU(Floating Point Unit),也能飙浮点运算,用公式也行,但查表依旧是个常用、简洁的方案。以下为示例代码:

/* 在 ultrasonic_th_compensation.c 中 */

// Temperature array (°C)
static const float tempPoints[7] = {0.0f, 5.0f, 10.0f, 15.0f, 20.0f, 25.0f, 30.0f};
// Humidity array (%)
static const float humPoints[9]  = {10.0f, 20.0f, 30.0f, 40.0f, 50.0f,
                                    60.0f, 70.0f, 80.0f, 90.0f};

/* speedTable[row for temp][column for humidity] => mm/us (one-way) */
static const float speedTable[7][9] =
{
    /* T=0   */ {0.16575f, 0.16575f, 0.16575f, 0.16580f, 0.16580f, 0.16580f, 0.16585f, 0.16585f, 0.16585f},
    /* T=5   */ {0.16725f, 0.16730f, 0.16730f, 0.16735f, 0.16735f, 0.16735f, 0.16740f, 0.16740f, 0.16745f},
    /* T=10  */ {0.16875f, 0.16880f, 0.16885f, 0.16885f, 0.16890f, 0.16895f, 0.16895f, 0.16900f, 0.16900f},
    /* T=15  */ {0.17025f, 0.17030f, 0.17035f, 0.17040f, 0.17045f, 0.17050f, 0.17055f, 0.17060f, 0.17060f},
    /* T=20  */ {0.17175f, 0.17180f, 0.17185f, 0.17195f, 0.17200f, 0.17205f, 0.17210f, 0.17220f, 0.17225f},
    /* T=25  */ {0.17320f, 0.17330f, 0.17340f, 0.17350f, 0.17355f, 0.17365f, 0.17375f, 0.17380f, 0.17390f},
    /* T=30  */ {0.17470f, 0.17480f, 0.17495f, 0.17505f, 0.17515f, 0.17525f, 0.17540f, 0.17550f, 0.17560f}
};

static int getNearestIndex(const float* arr, int arrSize, float value)
{
    if(value <= arr[0]) return 0;
    if(value >= arr[arrSize - 1]) return arrSize - 1;

    int nearestIdx = 0;
    float minDiff = fabsf(value - arr[0]);
    for(int i = 1; i < arrSize; i++)
    {
        float diff = fabsf(value - arr[i]);
        if(diff < minDiff)
        {
            minDiff = diff;
            nearestIdx = i;
        }
    }
    return nearestIdx;
}

float CalcDistanceWithTHCompensation(uint32_t echoWidth_us, float temperature, float humidity)
{
    // 1) 索引
    int tempIndex = getNearestIndex(tempPoints, 7, temperature);
    int humIndex  = getNearestIndex(humPoints, 9, humidity);

    // 2) 查表得到单程声速因子(mm/us)
    float speedFactor = speedTable[tempIndex][humIndex];

    // 3) 计算距离(回波时间 × speedFactor)
    float distance_mm = echoWidth_us * speedFactor;

    // 4) 超过4m做无效处理
    if (distance_mm > 4000.0f)
    {
        distance_mm = 0.0f;
    }

    return distance_mm;
}

实际对比:

image3.png


5. 结语

声速听起来神秘,却又真实地影响着我们的超声测距结果。大部分室内测量可以忽略温湿度差异,但在极寒、高温、高湿或极干环境中,差异不容小觑。

本文给大家简单介绍了如何把 DHT11 测得的温湿度值与 HC-SR04 的回波时间配合使用upload 附件:APM32F402_403_SDK_V1.0.1_HC_SR04_DHT11.zip。文中使用了查表法补偿。当然,你也可以直接使用浮点公式来计算,一样能得到不错的效果——凡事任何时候都要权衡精度、速度和可维护性。

使用特权

评论回复

打赏榜单

21小跑堂 打赏了 50.00 元 2025-06-30
理由:恭喜通过原创审核!期待您更多的原创作品~~

评论
21小跑堂 2025-6-30 16:55 回复TA
通过温湿度补偿,提高HC-SR04超声波测距模块的精准度。 
沙发
kai迪皮|  楼主 | 2025-6-29 17:11 | 只看该作者

使用特权

评论回复
发新帖 本帖赏金 50.00元(功能说明)我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

36

主题

237

帖子

11

粉丝