news 2026/9/8 12:34:08

1-Wire单总线协议深度解析:从物理层到时序与ROM搜索

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
1-Wire单总线协议深度解析:从物理层到时序与ROM搜索

做嵌入式这么多年,凡是搞过温度采集、电池管理或者传感器网络的人,基本都绕不开Dallas Semiconductor(现在归了Maxim)推出的1-Wire单总线协议。特别是一提到DS18B20,几乎成了单总线代名词。这东西的厉害之处在于:一根数据线,既能传数据,还能给设备供电,而且一条总线上能挂几十个器件,每个器件有全球唯一的64位ID。听起来很美好,可真要自己做主机时序、读ROM、搜索设备,里面的坑一点不少——上拉电阻选错、时序余量不够、寄生供电失效,任何一个都能让你调一整天。

这篇文章我打算把单总线协议从物理层到ROM寻址完整拆开讲一遍,重点是讲清楚工程中必须知道的那部分:为什么开漏输出加一个上拉电阻就能实现双向通信、复位和读写时隙的时间参数到底怎么卡、64位ROM里每个字节是什么含义、搜索ROM算法究竟怎么把一条总线上的所有设备一个一个找出来。适合刚接触1-Wire的新手,也适合之前用过但只停留在“照着例程抄”阶段的人。

1. 物理层设计:一根线如何既传数据又供电

1.1 为什么单总线可以“单线”通信

单总线协议的物理连接很朴素:主机的某个GPIO接一根数据线(DQ),所有从设备挂在这根线上,再加上公共地线就完事。某些寄生供电模式甚至可以让从设备只靠数据线供电,地线都省不了,但通信线确实只有一根。

它能在一根线上完成双向数据传输,靠的不是什么高深调制,而是“开漏输出 + 上拉电阻”这种电气结构。主机和所有从设备的数据引脚都是开漏结构,也就是说引脚内部只有拉低能力,没有主动拉高的能力。总线空闲时,全靠主机端的一个上拉电阻把总线拉到高电平。任何一端要发数据,就把总线拉低;要释放,就把内部晶体管关断,让上拉电阻把电平拉回去。

这种结构有一个天然好处:任何设备都能安全地把总线拉低,只要保证上拉电阻和器件驱动能力匹配,就不会出现两个设备同时输出高低电平打架烧口的问题。这也是为什么单总线可以做成一主多从,多设备挂同一条线不怕冲突。

另外还要强调一点,总线从高电平到低电平其实是“主动拉低 + 上拉恢复”两个动作完成的。低电平的边沿速度主要取决于从设备拉低能力,高电平的恢复速度取决于上拉电阻和总线等效电容共同构成的RC充电时间。这直接影响了你的通信速率上限,也解释了为什么总线长了、设备多了之后,波形会变得歪歪扭扭。

1.2 上拉电阻、寄生电容与总线负载的配合

上拉电阻的选择是整个物理层设计里最容易被忽视、也最容易埋雷的地方。电阻太小,总线充电快,但低电平时器件拉低电流太大,可能拉不到规定的低电平;电阻太大,总线充电慢,上升沿变缓,高速时序下采样点出错。

工程上常用4.7kΩ,这是Dallas官方文档里的典型值。如果你的总线就一个设备,线又很短,5V供电时选4.7k基本不会出问题。但在长线缆、强干扰环境,或者3.3V低压系统里,这个值未必最优。

选上拉电阻可以从两个方向估算。一个是低电平电流限制,保证器件拉低时总线上电压低于规定的最大低电平电压。假设上拉电压是5V,器件最大输出低电平电流是4mA,最大低电平电压是0.4V,那么:

[ R_{min} = \frac{V_{pullup} - V_{OLmax}}{I_{OLmax}} = \frac{5 - 0.4}{0.004} = 1150\Omega ]

也就是说上拉电阻最小不能小于1.15k左右。另一个是高电平恢复速度,总线等效电容假设在几百pF到几nF之间,RC时间常数要小于时隙间隔的1/10才行。比如标准速率下最小时隙是60μs,那么RC常数要小于6μs。如果C=1nF,R=4.7k,RC=4.7μs,留的余量已经不大,所以有些要求高的设计会用2.2k甚至1k。

实际项目中我的经验是:短距离(几十厘米)、单设备、3.3V系统,4.7k放心用;超过2米线缆或挂多个设备,优先考虑2.2k;如果还伴随强电磁干扰,就得配合屏蔽和更小的上拉。注意不要为了追求沿速度无脑减小上拉,等效电阻太小,寄生供电模式下从设备可能拉不出足够低的电平,也会出问题。

1.3 寄生供电与强上拉的工程意义

单总线最吸引人的特性之一就是寄生供电。原理很直接:总线为高电平时,从设备内部的电容充电,把能量存起来;总线为低电平时,就靠电容里存的电继续维持工作。所以从设备其实一直在“偷电”,偷多少取决于高电平的占空比和持续时间。

听上去很完美,但实际操作里有个大坑:某些场景设备耗电猛增,比如DS18B20做温度转换时,转换过程需要1mA级别的工作电流,光靠平时那些高电平窗口充进去的电根本不够。如果供电不足,转换结果会出错,甚至读回来全是0xFF或CRC错误。

这时候就需要主机开启“强上拉”。所谓强上拉,就是主机在温度转换期间把上拉电阻短路到电源,直接给从设备供电。很多国产的DS18B20模块没有做强上拉,只是简单接个4.7k电阻,你如果直接用寄生供电模式去读转换结果,大概率失败。解决思路有两种:一是把DS18B20的VDD引脚接真实电源,放弃寄生供电,这是最稳妥的;二是用GPIO模拟强上拉,在转换期间把数据线直接拉高到供电电压,转换结束再恢复。

我自己在项目里一般直接用外部供电,省心。真要用寄生供电,务必量一下转换期间数据线上的电压波形,确认没有掉到2.5V以下,不然一切时序优化都是白费。

2. 时序基石:复位、存在脉冲与读写时隙

2.1 初始化时序:主机复位与从设备存在脉冲

1-Wire通信的每次交互,不管是读ROM还是读温度,第一步都是复位时序。主机先把总线拉低至少480μs,然后释放,由1-Wire从设备在检测到这个低电平后,再主动拉低60至240μs作为存在脉冲。主机在这段时间内去读总线,如果读到低电平,就说明总线上有设备响应。

这里有个非常容易被误会的点:检测存在脉冲的窗口不是从主机释放总线那一刻算起。主机释放总线后,从设备内部会有个延时,典型值是60μs左右,最长可以到差不多120μs才开始拉低。所以主机释放总线之后不能马上读,得等到从设备的存在窗口真正出现后再采样。数据手册上写的窗口是“释放总线后15至60μs”开始读?不对,准确说,从设备在检测到复位脉冲后准备存在脉冲,主机应该在释放总线后的60至240μs窗口内进行采样。很多初始化失败,就是主控GPIO释放之后立即去读取,读到的是未拉低的高电平,误判总线上没有设备。

初始化时序的关键参数我用一张表梳理出来,方便对照:

参数最小值典型值最大值说明
主机复位低电平时间480μs480μs必须足够长,让所有从设备都能检测到
主机释放后到采样窗口15μs60μs60μs建议至少在释放后60μs再开始采样
从设备存在脉冲低电平60μs120μs240μs主机在此窗口内读取低电平
复位周期总时长960μs含复位与存在脉冲,之后才能发ROM命令

很多人的时序代码是从数据手册抄的,但抄的时候只抄了“拉低480μs然后释放”,没有仔细控制后面的采样点。我在实际调试中遇到过一次,主机在释放后10μs就去读,100次里有七八次说“设备不存在”,而用示波器看波形却明明存在脉冲很标准。后来把采样点推后到释放后大于60μs,问题立刻消失。

2.2 写时隙与读时隙:时间窗口里的离散信号

复位之后,主机开始发送ROM命令,接着是功能命令和数据。单总线的数据位传输不是靠电平高低表示的,而是靠“低电平持续多长”和“何时释放”来区分。每个bit占用一个时隙,时隙长度最小60μs,位与位之间至少要有1μs的恢复时间。

写1和写0的区别在数据手册里写得很清楚:

  • 写0:主机把总线拉低,并持续整个时隙,直到时隙结束再释放,典型拉低60至120μs。
  • 写1:主机把总线拉低一小段时间(1至15μs),然后释放,让上拉电阻把总线拉回高电平,剩余时间保持高。
  • 读时隙:主机先把总线拉低至少1μs,然后释放,在释放后15μs内对总线进行采样。如果从设备此时将总线拉低,读到的就是0;如果从设备不动作,上拉电阻把总线拉高,读到的就是1。

说白了,这本质上是一种“脉宽调制”式的编码,只是它把离散bit映射到了时隙内不同的低电平持续时长上。主机发送任何数据位时,都必须主动产生一个时隙起始的低电平脉冲;从设备利用这个脉冲的低电平边沿来同步自己的内部时钟。这也是为什么1-Wire从设备不需要外部时钟,它能靠主机产生的一个个时隙起始沿自行对齐采样时刻。

读时序比写时序更容易踩坑。因为读时序中,主机必须自己在每个bit开始时拉低一次总线,然后马上释放并采样。如果GPIO没有在拉低和读取之间正确切换方向,或者释放后没有延时足够时间再采样,很容易把从设备刚准备拉低的信号漏掉。比如从设备响应读1时,它根本不拉低总线,你采样稍晚一点问题不大;但响应读0时,从设备只会在主机释放后把总线拉低一小段时间,采样晚于15μs就可能错过低电平。

用软件GPIO模拟1-Wire时,尤其要注意中断干扰。读时隙中从主机释放总线到采样窗口结束,前后不过几十微秒,任何一次中断嵌套都可能破坏窗口。我习惯在读写字节期间关闭中断,或者用DMA配合定时器来生成精确时序,否则时序抖动会导致偶发的通信错误,极难排查。

2.3 时序容差与时钟精度的现实约束

看1-Wire时序参数会发现,很多时间范围给得挺宽,比如复位低电平只要大于480μs,写1低电平允许1至15μs。宽泛的范围给了软件模拟很大的容错空间。但如果主机用的单片机时钟不稳定,或者定时器配置不准,积累误差也会暴露出来。

一个特别容易被忽略的点是时隙间恢复时间。标准速率的时隙是60μs,但很多实现把时隙拉得很长,比如自己定成100μs,这在单设备场景下没问题,因为从设备对时隙长度的上限容忍度很高。真正的风险在于你对每个bit的“启动沿”控制是否精确。从设备是以启动沿作为参考点的,它内部对每个bit的采样时刻也是相对启动沿来算的。只要启动沿准确,时隙拉长一点影响不大。

在120kHz的高速模式(overdrive speed)下,时序参数会缩到标准模式的1/10左右,这时候软件GPIO模拟基本没有容错空间了。大多数应用跑标准速率就行,但如果你在项目里开了高速模式,建议用硬件定时器介入或者干脆上带硬件1-Wire外设的主控,否则调试过程会非常痛苦。

3. ROM寻址:64位身份码与设备搜索算法

3.1 64位ROM的构成与字节序陷阱

每条1-Wire总线上挂着的每个从设备,出厂时都烧录了一个唯一的64位ROM ID。这64位不是随便排的,它的结构是固定的:最低8位是家族码,表示设备类型;中间48位是序列号,每个设备唯一;最高8位是CRC校验码,由前56位计算得到,用于校验ROM读取是否正确。

以DS18B20为例,它的家族码是0x28。如果你读回某个设备的64位ROM后发现低字节不是0x28,要么是读取时序出错,要么就是挂的不是DS18B20而是其他1-Wire器件。家族码在总线仲裁和多设备混挂场景下非常有用,你可以根据家族码判断设备类型,再决定发送哪套功能命令。

字节序是新手最容易搞乱的地方。1-Wire协议规定ROM的每一位发送顺序是从最低位开始,也就是先发送家族码的最低位,再依次向高位推进。但很多人在代码里把ROM当普通整数数组按从高位到低位顺序发送,结果设备完全不响应。正确做法是:从ROM数组的第0个字节开始发送,发送每个字节时也是从LSB到MSB逐位发送。换句话说,你在代码里看到的ROM数组顺序和总线上的位顺序是完全一致的,都是“低字节优先、低位优先”。

举个例子,假设某颗DS18B20的ROM是0x28 0xA1 0x2B 0x4C 0x00 0x00 0x00 0xE3,那么总线上最先发出去的是0x28这个字节的最低位(bit0=0),最后发出去的是0xE3这个字节的最高位(bit7=1)。如果你用移位发送数据的函数时没注意方向,把MSB先发出去了,一切就全乱了。

3.2 ROM命令集:读、匹配、跳过、搜索

ROM命令是主机与总线上的设备“打招呼”的指令,在复位时序之后发送。常用命令有:

命令名命令码作用
读ROM0x33总线上只有1个设备时,直接读出它的64位ROM
匹配ROM0x55后跟64位ROM ID,只与ID匹配的设备响应
跳过ROM0xCC不指定设备,所有设备都响应后续功能命令
搜索ROM0xF0逐位搜索总线上所有设备的ROM ID
条件搜索0xECDS18B20特有,只搜索满足报警条件的设备

读ROM命令有两个严格限制:读之前必须确认总线上只有一个从设备。如果一条总线上挂了多个设备,你发0x33后所有设备都会同时响应,数据引脚上会重叠出各种乱波形,读回来的ROM ID大概率是错的。所以多设备场景必须先搜索,再通过匹配或者直接对单个地址操作,别偷懒。

跳过ROM命令则是“不挑食”的代表。它后面不跟任何地址数据,直接接功能命令。单设备总线实现最简温度读取流程就是发送复位,发0xCC,再发0x44启动转换,延时等转换完成,再发复位,发0xCC,最后发0xBE读暂存器。整套流程完全不需要知道设备的ROM ID。

3.3 搜索ROM算法:如何用二分法找出总线上的所有设备

搜索ROM是整个1-Wire协议中最巧妙的部分。表面看是个寻址过程,本质是个位级二分搜索——从ROM的最高位开始,逐个bit地让所有设备参与仲裁,每一轮都通过两次读时隙把某个bit的真值和反值都读出来,最终确定这个bit是0、是1,还是有多台设备冲突。

算法流程是这样的:

  1. 主机发送复位时序,然后发送搜索ROM命令0xF0。
  2. 从ROM的第63位(最高位)开始,先执行一次读时隙,读取当前位在总线上的值(所有设备该位的逻辑或值);再执行一次读时隙,读取当前位的反值。
  3. 根据两次读值判断:
    • 第一次读到0,第二次读到1:当前位为0,无冲突;
    • 第一次读到1,第二次读到0:当前位为1,无冲突;
    • 两次都读到0:说明该位上有的设备是0、有的设备是1,出现冲突;
    • 两次都读到1:说明总线上没有设备或设备出错。
  4. 如果冲突,需要选择走哪条分支。经典的算法可以选择“先走0路径,并把该位的状态记录到一个路径栈中”,之后回溯时再走1路径。
  5. 选定了当前位的值后,发送一个与选定值对应的写时隙,把所有该位不等于选定值的设备屏蔽掉。
  6. 继续下一位,一直到64位全部处理完,就找到了一台设备的完整ROM ID。然后回溯上一个冲突位,选择另一个分支继续,直到所有设备都被枚举出来。

整个搜索过程是典型的深度优先遍历。工程实现上,最常见的做法是维护一个路径栈记录哪些位发生过冲突、哪些冲突位已经选了0、哪些选了1。我用数组加递归就能实现,也可以用非递归的栈方式。

这里我给出一个可以实际跑通的搜索ROM核心代码片段,用位操作实现:

uint8_t ow_search_rom(uint64_t *rom_id) { uint8_t bit_index, byte_idx, byte_mask; uint8_t last_conflict = -1; uint8_t send_bit; int id_bit, cmp_id_bit; uint64_t current_rom = 0; uint8_t found = 0; for (bit_index = 0; bit_index < 64; bit_index++) { id_bit = ow_read_bit(); cmp_id_bit = ow_read_bit(); if (id_bit == 1 && cmp_id_bit == 1) { return 0; // 总线上没有设备 } else if (id_bit == 0 && cmp_id_bit == 0) { // 冲突位:需要决定走0还是走1 if (bit_index == last_conflict) { send_bit = 1; // 说明上一次已经走过0分支,这次走1 last_conflict = -1; // 重置,方便下一次回溯 } else if (bit_index > last_conflict) { send_bit = 0; // 优先走0分支,并记录冲突位 last_conflict = bit_index; } else { send_bit = (current_rom >> bit_index) & 0x01; } } else { send_bit = id_bit; // 非冲突位,按读取值写回 } if (send_bit) { current_rom |= ((uint64_t)1 << bit_index); } ow_write_bit(send_bit); } *rom_id = current_rom; return 1; }

这段代码的核心是last_conflict变量,它记录了上一次搜索时遇到的最后一个冲突位。第一次搜索时,所有冲突位都优先走0;再次调用搜索时,如果当前bit_index正好等于last_conflict,说明上一次已经在这条分支上走通过了0,这次改为走1。这样不断调用,就能把所有ROM全都枚举出来,直到返回0表示搜索结束。

实际调试中,搜索算法的冲突判断很容易被时序抖动干扰。如果读时隙采样不准,冲突位会判断错误,搜索结果会漏设备或者出现重复ID。因此搜索之前务必先用复位时序和读ROM确认总线设备数量,再用稳定的读写时隙跑搜索。

3.4 CRC校验:64位ROM的完整性保障

64位ROM中最高8位是CRC,这8位不是数据,而是前56位的校验结果。每次成功读取一个ROM后,都建议把低56位输入CRC计算函数,比对结果是否等于最高字节。如果不等,说明读取有误,应该丢弃这次读取结果。

1-Wire协议用的CRC是CRC-8,生成多项式为 (x^8 + x^5 + x^4 + 1),在数值上等价于0x31(正向)或0x8C(反向,用于右移算法)。嵌入式里常见实现是查表法,但位运算版本更省空间,适用大多数场景:

uint8_t ow_crc8(uint8_t crc, uint8_t byte) { uint8_t i; for (i = 0; i < 8; i++) { uint8_t mix = (crc ^ byte) & 0x01; crc >>= 1; if (mix) { crc ^= 0x8C; } byte >>= 1; } return crc; }

使用方式很简单:遍历ROM数组的前7个字节,逐个喂给CRC函数,初始crc设为0,最终结果应与第8字节相等。DS18B20读暂存器数据时,9字节数据中的第9字节同样是CRC,也可以用同一个函数逐字节计算校验。

CRC校验不是可选项。我在实际项目中遇到过偶发的“温度跳变到85℃”问题,罪魁祸首就是读暂存器时最后两个字节出了位错误,而旧代码没做CRC校验,直接把坏数据当有效值用了。加了CRC校验并增加重读逻辑后,问题彻底解决。

4. 实测排障与工具链:波形、参数和常见问题速查

4.1 示波器实测:单总线波形怎么判读

调试1-Wire协议,示波器绝对是最直观的工具。把探头接在数据线上,地线接GND,触发方式设置成下降沿,就能捕捉到完整的通信过程。

一个正常的复位周期应该是这样的:先看到一段长度约480μs的低电平,随后总线回到高电平,过几十微秒后出现一个宽度约120μs的低脉冲,这就是从设备的存在脉冲。整个复位周期结束后,总线保持高电平。如果示波器上复位低电平之后紧跟着看不到存在脉冲,基本就是从设备没响应,检查供电、接线和上拉电阻。

读写时隙的波形判读则要看细节。写0时,总线被拉低并保持整个时隙;写1时,总线只会出现一个很窄的低脉冲,然后立即回到高。连续发送数据时,波形里会交替出现这两种形态,很容易辨认。读时隙则更微妙,主机产生一个约1μs的低脉冲,然后释放,之后如果在15μs内看到总线被拉低,说明从设备回的是0,如果始终是高电平,回的就是1。

很多新手抓波形时会犯一个错误:把探头接在从设备端而不是主机端。如果线缆较长,主机端和从设备端的波形相位会有差异,靠从设备端波形去判断主机时序容易产生误导。我建议主机端和从设备端各接一个探头,同时观察,先确认主机发送的时序满足手册要求,再确认从设备的响应波形正常。两头对照,排障效率能提升不少。

4.2 常见问题速查表与工程建议

现象可能原因排查与解决
复位后读不到存在脉冲上拉电阻过大/未接、供电异常、线缆过长用示波器测复位波形,确认存在脉冲是否被电容拉平;尝试换2.2k电阻
读ROM按字节与手册不符字节序或位序处理错误确认ROM低位优先、MSB最后发送;用已知ROM做比对
温度转换结果偶发错误寄生供电不足、时序受中断干扰改用外部VDD供电;转换期间开强上拉;关闭中断或改为硬件时序
搜索ROM漏设备搜索算法冲突位回溯逻辑错误检查last_conflict状态管理;先确认单设备读ROM能读到正确ID
长线缆下通信不稳定总线电容过大、上升沿过缓减小上拉电阻、缩短线缆、使用屏蔽双绞线
多个设备互相干扰总线没有真正的开漏结构,或设备地址冲突用示波器看波形是否有强驱动产生;检查所有设备零位响应是否正常

长线缆场景还有一个容易被忽略的点:从设备数量越多,总线等效电容越大,RC上升时间越长。挂20个DS18B20时,理论上总线和地之间可能有接近1nF甚至更多电容,再加上信号反射,波形质量会显著下降。工程上如果必须在长线缆上挂大量设备,可以考虑加个总线驱动器芯片,或者用集线器分路,别一根线硬拖到底。

4.3 强上拉、GPIO模式切换与高速模式的实践心得

如果坚持要用寄生供电,强上拉的设计就很重要。在主机端,强上拉通常是让GPIO在转换期间切换到输出模式并直接输出高电平。但这里有个隐患:切换GPIO模式时,如果时序没控制好,可能在总线上产生意外的低脉冲,破坏通信。建议做法是,用一个专用的MOS管电路,由MCU控制MOS管栅极,在需要强上拉时把数据线直接连到电源,不影响通信线上的正常状态机。

GPIO模拟1-Wire时,主机的GPIO模式切换频率非常高。每个读时隙都要从输出模式切换成输入模式,再在采样后切回输出模式。频繁切换会带来额外的指令周期开销,如果单片机主频不高,会导致时隙参数偏移。所以我在软件实现里一般会把同一个GPIO的输入输出配置合并到端口寄存器操作里,减少函数调用和位操作开销。

最后说高速模式。overdrive模式的时序大约是标准模式的十分之一左右,对GPIO模拟来说非常苛刻。除非你对时序特别有把握,或者用的主控跑在几十MHz以上且代码执行时间完全可控,否则不建议在高速模式下用软件模拟。很多带硬件1-Wire外设的MCU也会对overdrive支持不全,设计之初最好确认清楚。

5. 学习路径与后续扩展

如果看完这部分,你准备在项目里自己动手写单总线驱动,我的建议是:先拿一个DS18B20单设备练手,实现“复位+跳过ROM+温度转换+读暂存器”的最小闭环;再换多设备场景,自己实现搜索ROM,把所有设备的ID打印出来;最后再加入CRC校验和异常重试,把驱动做成稳定可复用的模块。

具体顺序可以这样排:

  1. 硬件准备:一块带一个GPIO的开发板、一个DS18B20、一个4.7kΩ电阻、一根短杜邦线。先把硬件按标准电路接好,VDD接3.3V或5V,DQ接GPIO,上拉电阻从DQ接到VCC。
  2. 软件实现最小时序:写复位函数、写一个bit的函数、读一个bit的函数。先用示波器对照手册确认每个时间点都落在线内。
  3. 实现跳过ROM读取温度:按“复位 + 0xCC + 0x44 + 延时750ms + 复位 + 0xCC + 0xBE”的流程,把9字节数据读出来并解析温度。
  4. 实现搜索ROM:把总线上挂两个或更多DS18B20,用上面的搜索代码逐个枚举设备ID,再通过匹配ROM分别读取每个设备的温度。
  5. 增加健壮性:对每次读取做CRC校验,校验失败重试三次以上;加入超时机制,避免总线上无设备时卡死主循环。

过了这几个阶段,单总线协议的核心就算吃透了。后续如果再遇到DS2431、DS2482或者其他基于1-Wire的器件,你会发现它们的时序和控制方式大同小异,只是功能命令和数据格式不同,基本能快速上手。

我再分享一个自己常用的调试技巧:准备一颗已知ROM ID的单总线设备,专门用于验证主机时序是否正常。每次写完底层驱动后,先用这颗设备读出ROM,比对ID是否一致。如果ID完全一致,说明主机时序基本可靠;如果ID随机或者CRC经常不过,就应该回头查底层读写时序,而不是继续向上排查应用层逻辑。这一招能省下大量排查时间。

单总线协议之所以能沿用这么多年,靠的就是物理层简单、协议层次清晰、寻址机制巧妙这三点。对于嵌入式开发者来说,理解它的核心逻辑不仅能让你在DS18B20相关项目里少走弯路,更能举一反三地看懂依赖类似单线机制的芯片手册,比如一些温湿度传感器、EEPROM、电池管理芯片。把这根线玩明白,你慢慢会体会到一种“用最小硬件代价解决复杂工程问题”的设计美感。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/8 12:32:41

磁力链接聚合搜索:基于DHT网络的多源去重排序实践

简介&#xff1a;这是一份磁力链接聚合搜索的前端工程源码包&#xff0c;面向需要搭建聚合检索工具或学习前端项目结构的开发者。在传统多源检索场景中&#xff0c;信息分散、结果重叠&#xff0c;这套源码围绕关键词提交、结果聚合展示和配置管理核心流程&#xff0c;提供了完…

作者头像 李华
网站建设 2026/9/8 12:32:37

STM32F429移植STemWin+FreeRTOS:用GUI Builder实现LED图形控制

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/8 12:32:25

AI副业实战指南:从工具选型到内容去AI味的完整流程

1. 起步第一步不是选工具&#xff0c;而是把你的副业拆成一张"需求清单" 1.1 副业的热门方向只有三大类&#xff0c;AI只是其中的加速器 最近总有人来问我&#xff1a;"我想搞AI副业&#xff0c;帮我推荐几个AI工具呗。" 这种问题一问出来&#xff0c;我就…

作者头像 李华
网站建设 2026/9/8 12:32:05

EC20 4G模块TCP透传配置详解:从AT指令到稳定链路搭建

简介&#xff1a;面向STM32F4嵌入式开发者的EC20 4G模块TCP透传通信完整工程资源&#xff0c;采用MDK/KEIL工程结构&#xff0c;重点解决在Cortex-M4平台上通过AT指令配置EC20、完成串口对接并建立Socket数据通道的实际问题。无论刚开始接触4G透传开发&#xff0c;还是需要在现…

作者头像 李华
网站建设 2026/9/8 12:31:39

用大模型给商品资料包做自动化“体检”,一次查出27个问题

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/8 12:31:24

Claude Code装精不装多:9款实战验证的高效插件清单

Claude Code 这工具&#xff0c;2026 年已经不止是"终端里跑个 AI 自动改代码"那么简单了。GitHub 上搜 claude code plugins&#xff0c;几万个星标仓库砸过来&#xff0c;插件生态热闹得跟当年 VSCode 商店爆发一样。但丰富也意味着鱼龙混杂——有包装几行 curl 就…

作者头像 李华