本课对应《DNESP32S3 使用指南(IDF 版)》第 29 章。配套完整工程:examples/24-ds18b20。
环境与验收边界: DNESP32S3 V1.2,ESP-IDF v5.5.5;本机 macOS 构建通过。Ubuntu 26、外设接线、屏幕效果和实际测量仍待实板验收。下文输出均为预期格式,不能当作已采集的硬件日志。
本课完成后能做什么
- 连接正确时周期输出温度,轻触探头温度变化。
- 断开探头得到 NOT_FOUND 或 CRC/响应错误,不能稳定显示假 0°C。
- 解释为什么 750 ms 用任务延时,而 6 μs 时隙不用 vTaskDelay。
硬件连接与资源
| 信号或资源 | 对应关系 |
|---|---|
| 总线 | GPIO0,P5 IO0↔1WIRE_DQ |
| 供电 | 3.3V、GND,使用三线供电而非寄生供电 |
| 上拉 | 板载 4.7 kΩ |
| 器件 | 单个 DS18B20;与 DHT11/BOOT 共用信号,禁止同时操作 |
以下为正点原子 DNESP32S3 V1.2 原理图的相关页,保留原厂标识;表格用于快速定位,遇到板卡版本差异以实际原理图为准。点击图片可查看引脚与网络名。


一根数据线如何实现双向通信
单总线的数据脚用开漏模式。主机输出 0 表示主动拉低,输出 1 表示释放,总线依靠 4.7 kΩ 上拉变高;传感器需要回传 0 时也可以拉低。若主机用推挽持续输出高,就会与传感器争用总线。
本课默认总线上只有一个 DS18B20,使用 Skip ROM 0xCC。若接入多个器件,需要枚举并使用 Match ROM,不能让所有器件同时应答。使用外部 3.3V 供电,不支持寄生供电所需的强上拉。
对照 U4 插座丝印和传感器具体封装引脚,不能只按“平面朝前”猜线序。V1.2 的 U4 第 1 脚为 3.3V、第 2 脚为 DQ,第 3、4 脚均连地(第 3 脚对 DHT11 标为 NC)。标准 TO-92 DS18B20 的第 1 脚 GND 接 U4 第 3 脚、第 2 脚 DQ 接 U4 第 2 脚、第 3 脚 VDD 接 U4 第 1 脚;带线封装仍应按其厂商引脚表确认,不能凭线色猜测。

P5 连接 IO0 与 1WIRE_DQ 后,不要再按 BOOT,启动时也不要让总线被拉低。
从复位到温度要经过哪些步骤
主机拉低约 480 μs,再释放,约 70 μs 后采样 Presence。确认器件存在后发送 0xCC、0x44 开始转换;12 位转换最长等待 750 ms,这段长等待让出 CPU,不应放在临界区。
转换完成后再次复位,发送 0xCC、0xBE,读出 9 字节 scratchpad。前两个字节为有符号温度,默认 12 位分辨率下除以 16 得到摄氏度。例如原始 0x0191 对应 25.0625°C;处理负温度时,要先转成 int16_t,避免将其按无符号数解释成很大的正值。
CRC 与超时是读数的一部分
最后一个字节是前 8 字节的 CRC-8。代码还检查保留字节和合理温度范围,排除断线或被拉死后出现的全零假数据。失败时不更新调用者温度。
本课采用 GPIO 位操作,仅用于帮助理解时序;每个时隙由短暂的临界区保护,750 ms 转换期间绝不关闭中断。Wi-Fi、缓存和长临界区可能影响软件时序,复杂产品可改用 RMT 单总线驱动,本课的实板验证仍不可省略。
工程如何组织
驱动放在 components/BSP/,应用放在 main/main.c。本工程包含 ONEWIRE 模块。ESP-IDF 会自动发现项目根目录下的 components/BSP。main 通过 PRIV_REQUIRES BSP 声明组件依赖,INCLUDE_DIRS 则导出编译时使用的头文件搜索路径,不涉及运行时文件查找。
固定引脚通过 CONFIG_LESSON_* 常量定义在本工程的 Kconfig.projbuild 中,构建后可在 sdkconfig 中核对。这些默认值对应本板连线,仅修改配置数字并不能改变硬件连接。
应用代码:入口与处理流程
下面代码直接取自配套工程的 main/main.c,头文件和 BSP 实现在仓库中一并提供。初学时先看 app_main(),再追踪它调用的模块。
1#include <stdio.h>
2#include <stdint.h>
3#include <stdbool.h>
4#include <string.h>
5#include <stdlib.h>
6#include <assert.h>
7#include "esp_err.h"
8#include "esp_log.h"
9#include "esp_timer.h"
10#include "freertos/FreeRTOS.h"
11#include "freertos/task.h"
12#include "onewire.h"
13void app_main(void)
14{
15 ESP_ERROR_CHECK(ds_init());
16 while(1) {
17 float temperature;
18 esp_err_t err=ds_read(&temperature);
19 if(err==ESP_OK) ESP_LOGI("ds18b20","temperature=%.4f C",temperature);
20 else ESP_LOGW("ds18b20","%s",esp_err_to_name(err));
21 vTaskDelay(pdMS_TO_TICKS(1000));
22 }
23}
BSP 关键实现:ONEWIRE
以下是本课对应驱动的完整源文件。对外声明见 onewire.h。
1#include "sdkconfig.h"
2#include "onewire.h"
3#include "driver/gpio.h"
4#include "esp_rom_sys.h"
5#include "freertos/FreeRTOS.h"
6#include "freertos/task.h"
7#define DQ CONFIG_LESSON_ONEWIRE
8static portMUX_TYPE s_lock=portMUX_INITIALIZER_UNLOCKED;
9esp_err_t ds_init(void)
10{
11 gpio_config_t c={.pin_bit_mask=1ULL<<DQ,.mode=GPIO_MODE_INPUT_OUTPUT_OD,.pull_up_en=true};
12 esp_err_t err=gpio_config(&c);
13 gpio_set_level(DQ,1); // 开漏输出 1 表示释放,靠外部 4.7k 拉高。
14 return err;
15}
16static bool reset(void)
17{
18 gpio_set_level(DQ,0); esp_rom_delay_us(480);
19 portENTER_CRITICAL(&s_lock);
20 gpio_set_level(DQ,1); esp_rom_delay_us(70);
21 bool present=!gpio_get_level(DQ);
22 portEXIT_CRITICAL(&s_lock);
23 esp_rom_delay_us(410);
24 return present && gpio_get_level(DQ); // 排除总线一直短路到地。
25}
26static void write_byte(uint8_t value)
27{
28 for(int bit=0;bit<8;bit++) {
29 portENTER_CRITICAL(&s_lock);
30 gpio_set_level(DQ,0);
31 esp_rom_delay_us(value&1 ? 6 : 60);
32 gpio_set_level(DQ,1);
33 esp_rom_delay_us(value&1 ? 64 : 10);
34 portEXIT_CRITICAL(&s_lock);
35 value>>=1;
36 }
37}
38static uint8_t read_byte(void)
39{
40 uint8_t value=0;
41 for(int bit=0;bit<8;bit++) {
42 portENTER_CRITICAL(&s_lock);
43 gpio_set_level(DQ,0); esp_rom_delay_us(3);
44 gpio_set_level(DQ,1); esp_rom_delay_us(10);
45 if(gpio_get_level(DQ)) value|=1U<<bit;
46 esp_rom_delay_us(57);
47 portEXIT_CRITICAL(&s_lock);
48 }
49 return value;
50}
51uint8_t ds_crc(const uint8_t *bytes,int n)
52{
53 uint8_t crc=0;
54 while(n--) {
55 uint8_t value=*bytes++;
56 for(int i=0;i<8;i++) {
57 uint8_t mix=(crc^value)&1;
58 crc>>=1;
59 if(mix) crc^=0x8c; // Dallas/Maxim CRC-8,低位优先。
60 value>>=1;
61 }
62 }
63 return crc;
64}
65esp_err_t ds_read(float *celsius)
66{
67 if(!reset()) return ESP_ERR_NOT_FOUND;
68 write_byte(0xcc); write_byte(0x44); // 单个器件:Skip ROM,再开始转换。
69 vTaskDelay(pdMS_TO_TICKS(750)); // 12 位转换最大等待时间;此时不关闭中断。
70 if(!reset()) return ESP_ERR_NOT_FOUND;
71 write_byte(0xcc); write_byte(0xbe);
72 uint8_t b[9];
73 for(int i=0;i<9;i++) b[i]=read_byte();
74 if(ds_crc(b,8)!=b[8]) return ESP_ERR_INVALID_CRC;
75 // DS18B20 的保留字节应为 0xff、0x0c、0x10,排除全 0 假数据。
76 if(b[5]!=0xff || b[6]!=0x0c || b[7]!=0x10) return ESP_ERR_INVALID_RESPONSE;
77 float next=(int16_t)((b[1]<<8)|b[0])/16.0f;
78 if(next< -55 || next>125) return ESP_ERR_INVALID_RESPONSE;
79 *celsius=next;
80 return ESP_OK;
81}
CMake 与中文注释
1# 私有依赖只供本组件源码使用。
2idf_component_register(SRCS "main.c" INCLUDE_DIRS "."
3 PRIV_REQUIRES esp_timer BSP )
每个工程有自己的 project() 名称和 sdkconfig.defaults。VS Code 已关闭普通 CMake 自动配置,C/C++ 语言服务从 build/compile_commands.json 读取编译信息。首次构建前,这个文件还不存在,需要先激活 IDF 并完成构建,无需手工拼接头文件路径。
编译、烧录与观察
1# 激活 EIM 安装的 IDF;每个新终端都需要激活。
2source ~/.espressif/tools/activate_idf_v5.5.5.sh
3# 进入单个示例根目录,不是在 examples 总目录运行。
4cd ~/mycode/esp32-blog/examples/24-ds18b20
5# 首次配置目标;已有正确配置时不用每次重复 set-target。
6idf.py set-target esp32s3
7# 编译会生成 build/compile_commands.json,供 VS Code 使用。
8idf.py build
9# 把这个值换成实际连接开发板的端口;macOS 通常为 /dev/cu.*。
10PORT=/dev/ttyUSB0
11idf.py -p "$PORT" flash monitor
12# 串口监视退出:Ctrl+]。
预期输出或屏幕内容(示意;数值、日志前缀和启动时间依现场而变):
1ds18b20: temperature=25.0625 C
2# 断线时应得到明确错误,例如:
3ds18b20: ESP_ERR_NOT_FOUND
故障定位与逐项验收
先确认目标为 esp32s3,再检查实际端口、供电,并按本文引脚表核对跳线。编译成功只能说明源码与工具链兼容,模块型号、物理线路和时序仍需实板确认。
- 连接正确时周期输出温度,轻触探头温度变化。
- 断开探头得到 NOT_FOUND 或 CRC/响应错误,不能稳定显示假 0°C。
- 解释为什么 750 ms 用任务延时,而 6 μs 时隙不用 vTaskDelay。
遇到通信错误,先检查错误码和对应模块,不要用“错误时返回 0”掩盖异常。文中的预期日志只供阅读程序时参考;实板验收时,应记录实际现象,保存日志和接线照片。
与教材和官方实现对照
对照教材第 29 章正文:保留单总线时序,加入九字节 CRC、保留字节检查与错误传播;明确单器件、外部供电和 GPIO0 复用约束。
本地验证记录与参考
- 2026-10-24:ESP-IDF v5.5.5、目标 ESP32-S3,本机 macOS
idf.py build通过。 - Hugo 草稿页面、文内本地图片和课程入口已检查;
draft: true保留,实板验收后再考虑发布。 - 未执行本课硬件烧录、波形测量或外设现象验收,以上待办不提前勾选。
- ESP-IDF v5.5.5 官方接口文档。
- 教材第 29 章;DNESP32S3 V1.2 原理图第 1、2、4 页。