51单片机DS18B20温度报警器:汇编驱动与单总线时序实现详解
简介面向51单片机与DS18B20温度传感器学习者的完整工程资料以C语言与汇编两种实现方式呈现温度报警器从通信、采集到报警触发的全流程。代码中可看到单线通信协议的初始化序列、时序延迟控制和温度寄存器解析过程附带原理图、Keil工程文件及中文数据手册方便对照硬件连接理解底层驱动与报警阈值判断逻辑。资源压缩包共51个文件涵盖asm/c源文件、hex烧录文件、uvproj工程配置、备份文件及png原理图等整体约1.91MB结构简洁适合课程设计、毕业设计或入门实践参考。已有1453人学习既有代码分步注释也保留了工程生成过程文件便于排查编译与下载问题能帮助快速复现并扩展为温控风扇、过温保护等应用。1. 51单片机DS18B20温度报警器为什么还在用汇编写驱动冷库、机房、粮仓里最常见的设备就是温度报警器核心需求其实只有三句话把温度读准、跟阈值比较、超限就响。DS18B20是单总线传感器所有命令、数据和应答都在一根线上按位传输时序精度到微秒级。51单片机主频低、指令周期固定天然适合用汇编写这套底层驱动。C语言不是不能写而是编译器生成的代码抖动大碰上时序边界参数容易偶发读错。下面这份工程整理按完整链路的顺序拆解先讲单总线时序的汇编实现再讲温度读取和解析然后落到报警比较、阈值设定和掉电保存最后给Proteus仿真和实机排错的具体技巧。正在做51单片机课程设计的人可以直接照着搭想彻底弄懂DS18B20单总线时序的工程师也能从这里抠到细节。2. 单总线时序的汇编实现DS18B20复位、读写位与微秒延时2.1 单总线协议到底在传输什么命令流和应答流DS18B20 的通信结构分三层复位、ROM 命令、功能命令。每次读写一字节位与位之间靠时间片time slot区分。主机必须先把总线拉低产生复位脉冲从机回一个存在脉冲之后主机发 ROM 命令确定跟谁通信再发功能命令执行温度转换或读暂存器等操作。因为只有一根数据线读写方向靠主机控制时序参数一旦越界从机要么不应答要么把 0 当 1 读。51 单片机上使用任意一个 IO 口模拟单总线常见做法是接 P2.0 或者 P3.7外部加上拉电阻。DS18B20 的数据口是开漏输出必须靠 4.7kΩ 上拉电阻维持高电平否则总线浮空读回来的数据全是乱码。以下是一张典型的引脚连接表报警输出部分也一并列出来方便后面章节直接对照功能引脚说明DQ 数据线P2.0接 DS18B20 的 DQ4.7kΩ 上拉到 VCC蜂鸣器输出P1.0通过 NPN 三极管驱动有源蜂鸣器高温指示灯P1.1超上限时点亮低温指示灯P1.2低于下限时点亮SET 按键P3.2进入阈值设置状态INC/DEC 按键P3.3 / P3.4设置状态下调整阈值晶振11.0592MHz决定机器周期和延时参数2.2 11.0592MHz晶振下的延时估算与汇编延时子程序51 单片机标准 12T 模式下一个机器周期等于 12 个时钟周期。用 11.0592MHz 晶振计算一个机器周期约 1.085μs。这个数值是整套延时函数的基准。DJNZ 指令消耗两个机器周期约 2.17μs所以延时子程序里循环次数乘上 2.17μs再加上 MOV 和调用指令的开销就是实际延时时间。复位脉冲要求主机拉低总线 480μs 以上存在脉冲窗口是 60~240μs。写 0 时隙需要保持低电平 60~120μs写 1 时隙允许拉低 1~15μs 然后释放。读时隙主机拉低至少 1μs 后释放再在 15μs 内完成采样。以下是复位和写时序的延时核心代码直接按整段延时估算不拆单个 NOP 也能用;---------------------------------------------- ; 复位延时约500us ; 11.0592MHzDJNZ循环约2.17us/次 ;---------------------------------------------- RST_DLY: MOV R6, #230 ; 230 * 2.17us ≈ 500us RST_DLY_LOOP: DJNZ R6, RST_DLY_LOOP RET参数说明R6 赋值 230 是拿总延时除以 2.17 之后取整得到的。如果换用 12MHz 晶振机器周期刚好 1μsDJNZ 两机器周期就是 2μs那么 480μs 需要的循环次数是 240直接改 MOV R6, #240 即可。需要注意子程序调用本身还有 ACALL 和 RET 各占两个机器周期在要求严格的读采样点附近不要用子程序延时改用内联 NOP 更稳。2.3 复位、写位、读位的核心汇编代码复位函数的关键是采样存在脉冲的时机。主机释放总线后从机等待 15~60μs 才会把总线拉低采样点不能太早也不能太晚。以下代码在释放总线后插入 6 个 NOP 再采样大约在第 6.5μs 处实际调试时可以根据示波器波形微调 NOP 数量。DQ BIT P2.0 ;---------------------------------------------- ; DS18B20复位函数 ; 返回CY1表示传感器在线CY0表示无设备 ;---------------------------------------------- DS18B20_RESET: CLR DQ ; 拉低总线 MOV R6, #230 ; 约500us复位脉冲 RST_WAIT: DJNZ R6, RST_WAIT SETB DQ ; 释放总线 NOP NOP NOP NOP NOP NOP ; 约6.5us后采样 MOV C, DQ ; CY0说明从机拉低了总线 MOV R6, #110 ; 补齐剩余存在脉冲时间 RST_WAIT2: DJNZ R6, RST_WAIT2 RET逻辑说明复位子程序把 CY 当作传感器在线标志调用方通过 JC 跳转判断继续执行还是走异常分支。存在脉冲是 DS18B20 把总线拉低 60~240μs主机在这个窗口内任意时刻采样都能读到低电平所以 6 个 NOP 之后采样已经足够可靠。写字节要特别注意数据位顺序。DS18B20 是 LSB 优先传输即先发最低位。使用 RRC A 指令把 A 的最低位移入 CY然后判断 CY 决定当前时隙是写 0 还是写 1;---------------------------------------------- ; DS18B20写一字节LSB在前A为待写数据 ;---------------------------------------------- DS18B20_WRITE_BYTE: MOV R6, #8 ; 8个数据位 WR_BIT: CLR DQ ; 启动写时隙 RRC A ; 最低位移入CY JNC WR_ZERO ; 写1只拉低约4us就释放 NOP NOP NOP NOP SETB DQ MOV R7, #50 ; 保持剩余时隙 WR_DLY1: DJNZ R7, WR_DLY1 SJMP WR_NEXT WR_ZERO: ; 写0持续拉低整个时隙 MOV R7, #55 ; 约120us WR_DLY0: DJNZ R7, WR_DLY0 SETB DQ WR_NEXT: DJNZ R6, WR_BIT RET写 1 分支里 4 个 NOP 加上 CLR DQ 和 JNC 的执行周期低电平时间被限制在 4μs 左右符合“最晚 15μs 内释放”的要求。写 0 分支的 55 次 DJNZ 大约给出 119μs落进 60~120μs 的窗口。RRC A 每轮右移一次正好按 LSB 到 MSB 的顺序把数据送出去。读字节时序的采样点比写时序更敏感。主机拉低后必须尽快释放然后等从机驱动总线采样太早读到的是主机自己释放后的高电平采样太晚可能错过数据窗口;---------------------------------------------- ; DS18B20读一字节LSB在前返回值在A ;---------------------------------------------- DS18B20_READ_BYTE: MOV R6, #8 RD_BIT: CLR DQ ; 启动读时隙 NOP NOP SETB DQ ; 释放总线 NOP NOP NOP NOP ; 约5~8us处采样 MOV C, DQ RLC A ; CY移入A最低位 MOV R7, #50 RD_DLY: DJNZ R7, RD_DLY DJNZ R6, RD_BIT RET逻辑说明读数据同样遵循 LSB 优先。RLC A 把 CY 的值移入 A 的第 0 位同时把 A 原先内容左移所以第一个读到的位是 bit0第二个读到的位变成 bit1顺序和数据手册保持一致。这里的 NOP 数量决定了采样点在 5~8μs 之间是读时序的黄金采样区间。2.4 时序参数边界与C语言方案的对比DS18B20 官方手册给出的参数有一个范围例如写 0 时隙是 60~120μs读采样建议在 15μs 内完成。实际工程中不需要把每个参数都卡到中间值只要落在范围内即可。汇编比 C 语言的优势体现在两个地方一是每条指令的机器周期可数二是可以在采样点前临时关中断防止定时器中断把采样时序拉长。C 语言写这类底层驱动要靠嵌汇编或者对编译器生成的代码逐条核对开发效率反而低。DS18B20 复位、读写位这套代码是整个报警器的地基后面所有功能都建立在它的正确性之上。3. 温度读取与解析ROM命令、暂存器与BCD码转换3.1 DS18B20的ROM命令表和单温/多温总线选择每片 DS18B20 出厂时都有一个 64 位激光序列号主机通过 ROM 命令决定跟总线上哪一片通信。单温度报警器通常只挂一个传感器直接发跳过 ROM 命令即可省去读取序列号的过程。如果一条总线上要挂多个传感器就必须先执行读 ROM 命令拿到每片序列号再通过匹配 ROM 选通。温度报警搜索命令比较特殊它会自动找出总线上温度越限的设备适合巡检电路。常用命令码如下表命令名命令码功能跳过 ROM0xCC不匹配序列号单设备总线必须用读 ROM0x33读取 64 位序列号多设备枚举用匹配 ROM0x55后跟 64 位序列号选中指定设备报警搜索0xEC返回温度越限的设备序列号启动温度转换0x44执行一次温度测量结果存内部寄存器读暂存器0xBE从字节 0 开始连续读 9 字节写暂存器0x4E写入报警阈值 TH 和 TL后跟 3 字节写暂存器这条命令在调试报警阈值时有用可以通过程序直接修改 DS18B20 内部报警寄存器而不必每次都在数据手册里换算原始码。3.2 读取温度的汇编主流程跳过ROM、启动转换、读暂存器完整读温度流程分三段复位后发 0xCC 跳过 ROM再发 0x44 启动温度转换等待转换完成后再复位发 0xBE 读暂存器低字节和高字节分别存入 R4、R5。12 位分辨率下最大转换时间是 750ms等待期间可以让单片机顺便刷新数码管或者扫描按键。;---------------------------------------------- ; 读取温度原始值 ; 返回R4温度低字节R5温度高字节 ; 传感器不在线时返回0xFFFF ;---------------------------------------------- READ_TEMP: ACALL DS18B20_RESET JC RT_SKIP MOV R5, #0FFH ; 复位失败返回无效值 MOV R4, #0FFH RET RT_SKIP: MOV A, #0CCH ; 跳过ROM ACALL DS18B20_WRITE_BYTE MOV A, #44H ; 启动温度转换 ACALL DS18B20_WRITE_BYTE MOV R6, #250 ; 等待约750ms RT_WAIT: ACALL DELAY_1MS DJNZ R6, RT_WAIT ACALL DS18B20_RESET JC RT_READ MOV R5, #0FFH MOV R4, #0FFH RET RT_READ: MOV A, #0CCH ; 再次跳过ROM ACALL DS18B20_WRITE_BYTE MOV A, #0BEH ; 读暂存器 ACALL DS18B20_WRITE_BYTE ACALL DS18B20_READ_BYTE MOV R4, A ; 温度低字节 ACALL DS18B20_READ_BYTE MOV R5, A ; 温度高字节 RET参数说明DELAY_1MS 是 1ms 延时子程序R6 赋 250 得到 250ms但 12 位转换最大需要 750ms这里的 250 只是示意值实际工程要循环调用三次或者直接用 3 个嵌套循环凑 750ms。转换等待时间宁长勿短否则读到的是上一次的旧数据。读暂存器时总线上会连续返回 9 个字节前两个是温度值报警代码只取前两个字节剩余 CRC 字节直接丢弃。3.3 16位原始值转带符号整数补码处理与BCD码转换温度原始值的高 5 位是符号扩展位正数时为 0负数时为 1。以 12 位分辨率为例25°C 对应的原始码是 0x0190-25°C 对应 0xFE70。把原始值转成整数需要先判断符号负数取补码后再提取整数部分。温度分辨率是 0.0625°C低 4 位是小数部分报警器如果只显示整数把高 12 位中的高 8 位取出来即可。TEMP_INT EQU 30H ; 整数温度存放位置 TEMP_NEG_FLAG BIT 00H ; 负温标志位 ;---------------------------------------------- ; 16位原始值转整数 ; 输入R5:R4输出TEMP_INTTEMP_NEG_FLAG1为负温 ;---------------------------------------------- TEMP_TO_INT: MOV A, R5 ANL A, #80H ; 只检测符号位 JZ T_POS ; 负数转补码绝对值 MOV A, R4 CPL A ADD A, #1 MOV R4, A MOV A, R5 CPL A ADDC A, #0 MOV R5, A SETB TEMP_NEG_FLAG SJMP T_CALC T_POS: CLR TEMP_NEG_FLAG T_CALC: MOV A, R5 ANL A, #07H ; 12位数据中整数高3位 SWAP A ; 移到结果高4位 MOV TEMP_INT, A MOV A, R4 ANL A, #0F0H ; 整数低4位 SWAP A ; 移到结果低4位 ORL A, TEMP_INT MOV TEMP_INT, A RET补码转换是这段代码最需要注意的地方。0xFE70 取反加一得到 0x0190再提取整数部分得到 25符号标志位由 F0 或自定义位保存后续显示负号就靠它。如果温度是 -0.5°C原始码 0xFFF8 取补后整数部分是 0小数丢弃显示 0°C 会丢失负号信息做温度监控时可以接受。显示到数码管还需要把整数转成 BCD 码。常见的除法拆位法最直接;---------------------------------------------- ; 整数温度转BCDTEMP_INT为0~125 ; 返回R1百位R2十位R0个位 ;---------------------------------------------- HEX_TO_BCD: MOV A, TEMP_INT MOV B, #100 DIV AB MOV R1, A ; 百位 MOV A, B MOV B, #10 DIV AB MOV R2, A ; 十位 MOV R0, B ; 个位 RETDIV AB 执行后 A 存商B 存余数。先除以 100 得到百位再对余数除以 10 得到十位和个位。这套流程每组装一次显示缓冲区调用一次成本很低主循环每秒刷新几十次都没问题。3.4 用原始码直接比较0.0625°C精度不丢失的做法报警判断如果只用整数温度25.3°C 和 25.9°C 都会被当成 25°C阈值设定误差很大。更准确的做法是拿 16 位原始码直接比较阈值也换算成原始码。30°C 的原始码是 30×160x01E0下限 10°C 对应 0x00A0以 0.0625°C 为步进整个 16 位比较过程能保留小数精度。下一章会写一套用原始码做上下限判断的汇编逻辑。4. 温度报警逻辑上下限比较、蜂鸣器与LED输出控制4.1 报警器阈值比较的两种思路整数比较与原始码比较课程设计里常见的报警器写法是先把温度转成整数再用 CJNE 和 JC/JNC 组合做区间判断。这种做法逻辑简单但阈值只能设定到整数摄氏度DS18B20 的 12 位精度几乎浪费掉。另一种思路是把阈值预计算成 16 位原始码程序里直接比较 R5:R4 和 TH_H:TH_L。原始码比较天然保留小数精度而且汇编里用 SUBB 指令一次就能完成 16 位无符号减法代码量反而更少。需要留意的是温度原始码的正负问题。0°C 以下的原始码按补码表示符号位为 1用无符号比较时负温度数值远大于正温度。所以要区分两种情况当前温度非负时直接和 0x0000 精度的阈值比较温度是负数时阈值也要用负值原始码。实际做报警器时可以在校验阈值设定阶段就把上下限限制在 0°C 以上简化逻辑。4.2 用SUBB指令做无符号16位比较的汇编片段以下比较代码使用无符号减法通过检测借位来判断温度是否落在上下限区间内。为便于理解阈值设为上限 30°C、下限 10°C对应原始码 0x01E0 和 0x00A0。TH_H EQU 31H ; 上限高字节 TH_L EQU 30H ; 上限低字节 TL_H EQU 33H ; 下限高字节 TL_L EQU 32H ; 下限低字节 BUZZER BIT P1.0 LED_H BIT P1.1 LED_L BIT P1.2 ;---------------------------------------------- ; 报警判断R5:R4为当前温度原始码 ;---------------------------------------------- CHECK_ALARM: ; 先判断温度是否大于等于上限 MOV A, R4 CLR C SUBB A, TH_L MOV A, R5 SUBB A, TH_H JNC ALARM_HIGH ; CY0说明温度上限 ; 再判断温度是否低于下限 MOV A, R4 CLR C SUBB A, TL_L MOV A, R5 SUBB A, TL_H JC ALARM_LOW ; CY1说明温度下限 ; 正常温度区间 CLR BUZZER CLR LED_H CLR LED_L SJMP ALARM_END ALARM_HIGH: SETB BUZZER SETB LED_H CLR LED_L SJMP ALARM_END ALARM_LOW: SETB BUZZER CLR LED_H SETB LED_L ALARM_END: RET逻辑说明16 位减法需要分两次做。第一次先减低字节第二次用 ADDC 借位方式减高字节。JNC 跳转表示减法结果没有借位也就是被减数不小于减数所以温度大于等于上限阈值时进入高温报警分支。JC 跳转则相反温度小于下限阈值时进入低温报警分支。两种跳转之间是正常区间程序把所有输出口清零。阈值赋值要在主程序初始化阶段完成。例如设上限 30°C 可以这样写MOV TH_H, #01H ; 0x01E0 30 * 16 MOV TH_L, #0E0H MOV TL_H, #00H ; 0x00A0 10 * 16 MOV TL_L, #0A0H换算方法很简单设定温度乘以 16 就是原始码。比如 35.5°C 对应 35.5×16568换算成十六进制是 0x0238。做阈值设定功能时直接把按键输入的整数乘 16 存入 TH 和 TL比查表更通用。4.3 引脚分配表与继电器驱动的实用细节上一章引脚表里定了蜂鸣器在 P1.0LED 在 P1.1 和 P1.2。51 单片机 IO 口的驱动能力有限标准模式下拉电流只有几百微安不能直接驱动蜂鸣器和继电器。常见做法是输出引脚接一个 NPN 三极管基极串联 1kΩ 限流电阻集电极接蜂鸣器负极发射极接地。继电器线圈并联一个续流二极管方向是阴极接正极阳极接集电极防止关断瞬间的反向电动势击穿三极管。输出设备驱动方式对应引脚有源蜂鸣器NPN 三极管开关P1.0高温红色 LED直接串联 330Ω 电阻P1.1低温蓝色 LED直接串联 330Ω 电阻P1.2继电器NPN 三极管 续流二极管预留 P1.3如果报警器要控制加热器或制冷压缩机建议把 P1.3 留作继电器控制脚并且用光耦隔离。继电器动作瞬间会在电源线上产生较大干扰严重时会导致 DS18B20 通信失败实际布线时控制线远离 DQ 信号线。汇编层面可以在继电器动作前后加一个 10ms 延时再读温度避开切换瞬间的噪声窗口。5. 阈值设置与掉电保存按键消抖、EEPROM写入和Keil5工程搭建5.1 三个按键怎么组织状态机正常态、设上限态、设下限态报警器的阈值不能永远写死在程序里运行时要能调节。用三个按键就能完成全部交互SET 进入设置状态INC 加阈值DEC 减阈值。程序内部用一个状态寄存器保存当前模式0 表示正常运行1 表示调整上限2 表示调整下限。按键正常运行态设置上限态设置下限态SET进入设置上限切换到设置下限保存阈值退出设置INC无动作上限加0.5°C下限加0.5°CDEC无动作上限减0.5°C下限减0.5°C按键扫描必须做消抖机械按键按下瞬间会产生 5~10ms 的抖动直接读取电平会一次触发多次。消抖的做法是先检测到低电平延时 10ms 再读一次确认还是低电平才认为按键有效。KEY_SET BIT P3.2 KEY_INC BIT P3.3 KEY_DEC BIT P3.4 WORK_MODE EQU 40H ; 0正常 1设上限 2设下限 ;---------------------------------------------- ; 按键消抖和状态切换 ;---------------------------------------------- KEY_SCAN: JB KEY_SET, K_SCAN_INC ; SET没按下 ACALL DELAY_10MS JB KEY_SET, K_SCAN_INC ; 10ms后还是高-抖动 ; 确认SET按下 MOV A, WORK_MODE INC A CJNE A, #03H, K_SET_MODE MOV A, #00H ; 返回正常态 K_SET_MODE: MOV WORK_MODE, A ; 等待按键释放 K_SET_WAIT: JNB KEY_SET, K_SET_WAIT RET K_SCAN_INC: JB KEY_INC, K_SCAN_DEC ACALL DELAY_10MS JB KEY_INC, K_SCAN_DEC AJMP K_INC_HANDLE K_SCAN_DEC: JB KEY_DEC, K_SCAN_END ACALL DELAY_10MS JB KEY_DEC, K_SCAN_END AJMP K_DEC_HANDLE K_SCAN_END: RET逻辑说明状态机的核心是 WORK_MODE 累加循环。SET 按下一次从正常态跳到设上限态再按一次跳到设下限态第三次按回正常态并保存阈值。INC 和 DEC 的处理函数里要判断当前 WORK_MODE 的值只在设置状态才修改对应阈值。设置时还要限制上下限不能交叉否则会出现温度永远处于报警区间或永远不报警的死区。5.2 阈值写进STC内部EEPROM的IAP调用方式STC 系列单片机的掉电保存通常用内置 EEPROM 完成不需要外挂存储芯片。不同型号的 IAP 寄存器地址有差异但流程一致先写命令再写地址然后触发命令最后查询忙标志。以下代码以 STC89C52RC 为参考关键寄存器建议和自己的数据手册核对。;---------------------------------------------- ; STC EEPROM写字节骨架代码 ; 入口A数据DPTR目标地址 ; 寄存器地址仅作参考以实际芯片手册为准 ;---------------------------------------------- IAP_WRITE_BYTE: CLR EA ; 写EEPROM期间关中断 MOV IAP_DATA, A ; 数据寄存器 MOV IAP_ADDRH, DPH ; 地址高字节 MOV IAP_ADDRL, DPL ; 地址低字节 MOV IAP_CMD, #02H ; 字节写命令 MOV IAP_CONTR, #80H ; 使能IAP MOV IAP_TRIG, #5AH ; 触发顺序固定 MOV IAP_TRIG, #0A5H ; 第二次触发 NOP MOV A, IAP_CONTR ; 查询忙标志 JB ACC.0, $ ; 等待写完成 MOV IAP_CONTR, #00H ; 关闭IAP SETB EA RET注意事项IAP_TRIG 必须先写 0x5A 再写 0xA5顺序反了命令不会生效。写 EEPROM 期间不能响应中断所以子程序开头要关 EA结束恢复。掉电保存的最佳时机是 SET 键退出设置状态时把 TH 和 TL 各写两个字节。上电初始化再从对应地址读回来主程序不手动赋值阈值而是从内存变量加载这样每次开机都沿用上次设定的报警值。5.3 Keil5中汇编源文件的工程组织与烧录注意事项Keil5 的 C51 版支持纯汇编工程。常见做法是新建工程后添加一个 STARTUP.A51 和一个 USER.A51汇编源文件里用CSEG AT 0000H定义复位入口然后 LJMP 跳到主程序。STARTUP.A51 负责初始化堆栈指针和清零内部数据段如果不用可编程初始化它会在跳转到 main 之前完成基本环境准备。USER.A51 内部结构建议按模块划分延时子程序段、DS18B20 驱动段、按键扫描段、报警判断段、EEPROM 读写段。每个段用CSEG显式定义代码段变量用DSEG定义避免编译器自动分配和实际物理地址冲突。烧录时注意 STC 单片机需要选择正确的内部晶振频率选项例如使用 11.0592MHz 外部晶振时烧录软件里晶振频率要选 11.0592M否则串口下载时间计算会出错。6. Proteus仿真验证与汇编时序排错技巧Proteus 里搭仿真电路时单片机选 AT89C51 或 AT89C52DS18B20 组件自带模型不需要额外加载动态库。先把晶振频率设为 11.0592MHz再把 DS18B20 的 DQ 脚接到 P2.0上拉电阻用 4.7kΩ。仿真运行后如果温度显示 85°C这是 DS18B20 上电后的默认寄存器值说明复位或者转换命令没执行成功优先检查复位子程序的采样点。如果显示 -0.5°C 之类的乱码基本是写时序的时隙长度不对把写 0 分支的 DJNZ 次数减少到 45 左右再试。Proteus 仿真的 DS18B20 模型对时序的容忍度比实物高仿真能跑通不等于实物能跑通。调实物时最好的工具是逻辑分析仪或示波器把探头夹在 DQ 脚上看复位波形和写时序。正常波形里能清楚看到约 500μs 低电平的复位脉冲后面跟着一个约 120μs 的存在脉冲。如果看不到存在脉冲先确认上拉电阻和接线再用万用表量 DQ 对地电压空闲状态应该是 3V 以上。另一个实用技巧是给主循环加一个运行计数器。数码管正常刷新表示主程序在跑如果数码管停住而蜂鸣器乱响多半是 EEPROM 写入时触发了看门狗或者关中断时间过长。EEPROM 写操作前后各加一条 NOP 延时能明显降低总线干扰对单总线时序的影响。汇编时序调试时把延时参数单独抽出来做一个延时表表中记录每个延时函数在不同晶振频率下的循环次数。换晶振时只改一张表不用逐行翻代码。以下是一张常用的速查表延时用途11.0592MHz循环次数12MHz循环次数复位低电平 500μs230250写 0 时隙 120μs5560写 1 释放前 5μs4 个 NOP5 个 NOP读采样前 8μs8 个 NOP8 个 NOP最后提一个工程里容易忽略的点每次读完温度后把 DQ 拉高并且在主循环末尾加一个 10ms 空闲延时。单总线协议要求两次通信之间至少间隔 1μs但留出足够余量能让传感器电源稳定也能避免和按键扫描共用中断时产生偶发时序冲突。本文还有配套的精品资源点击获取
上一篇/下一篇内容由系统自动关联
返回资讯列表 →