尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

DS1821单总线温度传感器在XMC嵌入式项目中的选型与驱动实现

DS1821单总线温度传感器在XMC嵌入式项目中的选型与驱动实现 1. 从项目需求到器件选型为什么是DS1821最近在做一个基于英飞凌XMC系列MCU的嵌入式项目其中一个核心功能是环境温度监测。在选型温度传感器时我几乎没怎么犹豫就圈定了DS1821。可能有人会问市面上温度传感器那么多从模拟输出的热敏电阻、PT100到数字输出的各种IC为什么偏偏是它尤其是在ESP32这类自带温度传感功能的MCU大行其道的今天为一个专门的MCU外接一个温度传感器是不是有点“多此一举”我的回答是这完全取决于你的应用场景和精度要求。ESP32的内部温度传感器其主要设计目的是监测芯片本身的结温用于过热保护或性能调节其测量环境温度的精度和稳定性通常难以满足工业或高可靠性场合的需求。而像PT100这类高精度模拟传感器虽然性能优异但需要额外的信号调理电路如恒流源、高精度运放和复杂的校准过程对于很多中小型项目来说成本和复杂度都偏高。DS1821恰好卡在了一个非常舒服的位置上。它是一款单总线数字温度传感器这意味着你只需要一根数据线加上电源和地就能与MCU通信极大地简化了布线。其测温范围是-55°C到125°C分辨率为0.5°C对于绝大多数工业控制、环境监测、设备状态监控等应用来说这个精度已经绰绰有余。更重要的是它内部集成了温度传感、A/D转换和单总线接口MCU只需要通过简单的数字协议就能读取温度值省去了模拟电路设计和抗干扰处理的麻烦。在XMC这种资源丰富、外设强大的MCU上实现单总线通信更是小菜一碟。所以当你的项目需要在有限的IO口、简单的电路下实现一个可靠、够用的温度监测功能时DS1821是一个非常务实且经典的选择。它没有DS18B20那么高的分辨率DS18B20可达0.0625°C但协议更简单在某些对时序要求不那么严苛或资源受限的系统中反而更容易稳定驱动。2. 硬件连接与电路设计要点确定了DS1821接下来就是把它和XMC MCU连接起来。硬件连接看似简单但有几个细节不注意很容易导致通信失败或数据不稳。2.1 经典的单总线电路DS1821遵循Dallas单总线协议。最基本的连接方式如下VDD引脚接3.3V或5V电源。DS1821的工作电压范围是3.0V至5.5VXMC的IO口通常是3.3V电平因此推荐使用3.3V供电这样可以避免电平转换的问题。GND引脚接系统地。DQ引脚数据线接XMC的任意一个GPIO引脚。这个引脚需要配置为开漏输出模式并且必须连接一个4.7kΩ的上拉电阻到VDD。这是单总线协议的强制要求用于在总线空闲时将其拉至高电平并为器件提供通信所需的强上拉。注意很多初学者会忘记这个上拉电阻或者随意用一个10kΩ的电阻代替。4.7kΩ是经过验证的推荐值它能保证在总线电容和传输距离下上升时间满足协议要求。电阻过大可能导致上升沿太慢通信失败电阻过小则会增加功耗。2.2 电源模式的选择与寄生供电DS1821支持两种供电模式外部供电和寄生供电。上面描述的是标准的外部供电模式。寄生供电模式则更为“极致”只需要将VDD引脚接地DQ引脚通过上拉电阻提供电源和通信。这种方式可以节省一根电源线适用于传感器分布很远的场合。但是我强烈不建议在初次使用或对可靠性要求高的项目中使用寄生供电。原因在于当DS1821进行温度转换或执行EEPROM写入操作时瞬时电流需求会比较大最高可达1.5mA仅靠单总线上的弱上拉可能无法满足会导致芯片复位或操作失败。虽然协议里提供了“强上拉”的时序在发起温度转换命令后由MCU将DQ线强制拉至高电平一段时间但这增加了软件时序的复杂性且对总线长度和负载更敏感。对于XMC项目我们通常有充足的电源和IO因此优先采用外部供电模式。这样电路最简单通信也最稳定。如果你的应用场景必须使用寄生供电那么务必仔细阅读数据手册中关于强上拉时序的部分并在代码中严格实现。2.3 布局与抗干扰考虑虽然DS1821是数字器件但良好的PCB布局依然重要去耦电容在DS1821的VDD和GND引脚之间尽可能靠近芯片放置一个0.1μF的陶瓷去耦电容。这有助于滤除电源噪声尤其是在有其他数字或模拟电路共存的板子上。走线长度单总线对走线长度比较敏感。理论上在标准速度下可靠通信距离可达几十米。但在实际PCB上如果传感器离MCU较远比如超过30厘米建议适当减小上拉电阻值例如用3.3kΩ并检查走线是否靠近噪声源如电机驱动线、开关电源。ESD保护如果传感器需要通过线缆连接到外部环境在DQ线上串联一个小的电阻如100Ω并在对地接一个TVS管可以有效防止静电损坏。3. XMC端单总线驱动代码实现硬件搭好了接下来就是让XMC的“大脑”学会和DS1821“说话”。单总线协议是一种严格的基于时序的通信方式核心在于MCU要能精确地产生特定的高低电平脉冲并检测DS1821的响应。3.1 底层时序函数精确的“微操作”单总线协议的所有命令和数据交换都建立在三种基本时序之上复位脉冲、写时序写0写1和读时序。由于协议对时间要求非常严格微秒级我们通常需要用精确的延时函数来实现。在XMC上有几种方法空循环延时最简单但精度受编译器优化和CPU频率影响大不推荐用于产品。SysTick定时器延时利用ARM Cortex-M内核的SysTick定时器可以产生高精度的微秒级延时。这是最通用和可靠的方法。通用定时器延时使用XMC的CCU4或CCU8定时器模块精度最高但配置稍复杂。这里以SysTick为例展示如何实现一个微秒延时函数并在此基础上构建最底层的时序操作// 假设系统主频为120MHz #define CPU_FREQ_MHZ 120 // 初始化SysTick用于微秒延时 void BSP_Delay_Init(void) { SysTick-LOAD (CPU_FREQ_MHZ) - 1; // 设置重装载值每计数一次为1/CPU_FREQ_MHZ 微秒 SysTick-VAL 0; // 清空当前值 SysTick-CTRL SysTick_CTRL_CLKSOURCE_Msk | SysTick_CTRL_ENABLE_Msk; // 使用处理器时钟使能 } // 微秒级延时函数 void delay_us(uint32_t us) { uint32_t start_tick SysTick-VAL; uint32_t ticks_needed us * CPU_FREQ_MHZ; uint32_t elapsed_ticks; if (ticks_needed SysTick-LOAD) { // 如果需要延时的ticks超过重装载值需要特殊处理此处简化 // 实际应用中可能需要循环 } do { elapsed_ticks (start_tick - SysTick-VAL) SysTick-LOAD; } while (elapsed_ticks ticks_needed); } // 定义DQ引脚例如P1.0 #define DS1821_DQ_PORT XMC_GPIO_PORT1 #define DS1821_DQ_PIN 0 // 将DQ引脚配置为开漏输出初始高电平 void DS1821_DQ_Init_Output(void) { XMC_GPIO_SetMode(DS1821_DQ_PORT, DS1821_DQ_PIN, XMC_GPIO_MODE_OUTPUT_OPEN_DRAIN); XMC_GPIO_SetOutputHigh(DS1821_DQ_PORT, DS1821_DQ_PIN); } // 将DQ引脚配置为输入带上拉 void DS1821_DQ_Init_Input(void) { XMC_GPIO_SetMode(DS1821_DQ_PORT, DS1821_DQ_PIN, XMC_GPIO_MODE_INPUT_PULL_UP); } // 产生复位脉冲480us的低电平并检测存在脉冲60-240us的低电平 uint8_t DS1821_Reset(void) { uint8_t presence 0; DS1821_DQ_Init_Output(); XMC_GPIO_SetOutputLow(DS1821_DQ_PORT, DS1821_DQ_PIN); // 主机拉低DQ delay_us(480); // 保持低电平至少480us XMC_GPIO_SetOutputHigh(DS1821_DQ_PORT, DS1821_DQ_PIN); // 释放总线变高 DS1821_DQ_Init_Input(); // 切换为输入模式准备检测 delay_us(60); // 等待15-60us后采样 if (!XMC_GPIO_GetInput(DS1821_DQ_PORT, DS1821_DQ_PIN)) { presence 1; // 检测到低电平表示有器件响应 } delay_us(420); // 等待存在脉冲结束 return presence; // 返回1表示有器件在线 } // 向DS1821写一位数据 void DS1821_WriteBit(uint8_t bit) { DS1821_DQ_Init_Output(); XMC_GPIO_SetOutputLow(DS1821_DQ_PORT, DS1821_DQ_PIN); // 主机拉低启动写时序 delay_us(1); // 保持低电平至少1us if (bit) { XMC_GPIO_SetOutputHigh(DS1821_DQ_PORT, DS1821_DQ_PIN); // 如果是写1则在1us后释放总线 } // 如果是写0则继续保持低电平 delay_us(60); // 整个写时序至少持续60us XMC_GPIO_SetOutputHigh(DS1821_DQ_PORT, DS1821_DQ_PIN); // 释放总线 // 写时序后需要至少1us的恢复时间 } // 向DS1821写一个字节调用8次WriteBit void DS1821_WriteByte(uint8_t byte) { uint8_t i; for (i 0; i 8; i) { DS1821_WriteBit(byte 0x01); byte 1; } } // 从DS1821读一位数据 uint8_t DS1821_ReadBit(void) { uint8_t bit 0; DS1821_DQ_Init_Output(); XMC_GPIO_SetOutputLow(DS1821_DQ_PORT, DS1821_DQ_PIN); // 主机拉低启动读时序 delay_us(1); // 保持低电平至少1us XMC_GPIO_SetOutputHigh(DS1821_DQ_PORT, DS1821_DQ_PIN); // 释放总线 DS1821_DQ_Init_Input(); // 切换为输入模式 delay_us(10); // 等待10-15us后采样 if (XMC_GPIO_GetInput(DS1821_DQ_PORT, DS1821_DQ_PIN)) { bit 1; } delay_us(50); // 完成读时序 return bit; } // 从DS1821读一个字节调用8次ReadBit uint8_t DS1821_ReadByte(void) { uint8_t i, byte 0; for (i 0; i 8; i) { byte 1; if (DS1821_ReadBit()) { byte | 0x80; } } return byte; }3.2 高层命令封装让通信更直观有了底层的位读写和复位函数我们就可以根据DS1821的命令集来封装更易用的函数了。DS1821的常用命令不多核心流程是复位 - 发送命令 - 读写数据。// DS1821命令定义 #define DS1821_CMD_CONVERT_T 0x44 // 开始温度转换 #define DS1821_CMD_READ_SCRATCHPAD 0xBE // 读取暂存器包含温度值 #define DS1821_CMD_WRITE_SCRATCHPAD 0x4E // 写入暂存器配置TH, TL #define DS1821_CMD_COPY_SCRATCHPAD 0x48 // 将暂存器内容拷贝到EEPROM #define DS1821_CMD_RECALL_EEPROM 0xB8 // 将EEPROM内容召回至暂存器 #define DS1821_CMD_READ_POWER_SUPPLY 0xB4 // 读电源模式 // 启动一次温度转换 void DS1821_StartConversion(void) { if (DS1821_Reset()) { DS1821_WriteByte(DS1821_CMD_CONVERT_T); // 对于外部供电此后MCU可以去做其他事情稍后再来读结果 // 对于寄生供电此处可能需要立即提供强上拉 } } // 读取温度值原始数据需转换 int16_t DS1821_ReadTemperatureRaw(void) { uint8_t temp_lsb, temp_msb; int16_t raw_temp 0; if (DS1821_Reset()) { DS1821_WriteByte(DS1821_CMD_READ_SCRATCHPAD); temp_lsb DS1821_ReadByte(); // 温度低字节 temp_msb DS1821_ReadByte(); // 温度高字节符号位 // 可以继续读其他字节TH, TL, 配置等但这里我们只关心温度 raw_temp (temp_msb 8) | temp_lsb; } return raw_temp; // 返回16位有符号整数 } // 将原始温度值转换为摄氏度浮点数 float DS1821_RawToCelsius(int16_t raw_temp) { // DS1821温度数据格式高字节为符号位和整数部分低字节高4位为小数部分0.5°C分辨率 // 例如0x00A2 162 * 0.5 81.0°C; 0xFF5E -162 * 0.5 -81.0°C float temperature (float)raw_temp * 0.5f; return temperature; }3.3 主程序中的调用逻辑在实际应用中我们通常不会连续不停地读取温度。一个典型的流程是周期性采样。这里展示一个在XMC主循环或定时器中断中实现的简单逻辑// 全局变量存储温度 float current_temperature 0.0f; uint32_t last_conversion_time 0; #define CONVERSION_INTERVAL_MS 1000 // 每1秒转换一次 void App_TemperatureTask(void) { uint32_t current_time GetSystemTick(); // 获取系统滴答时钟 if ((current_time - last_conversion_time) CONVERSION_INTERVAL_MS) { // 步骤1启动转换 DS1821_StartConversion(); last_conversion_time current_time; // 注意DS1821的转换需要时间典型值为1秒。 // 这里我们启动转换后立即返回下次任务执行时再读取。 // 更精细的做法是设置一个“转换完成”标志位在转换时间到后再读取。 } // 假设我们知道转换需要1秒可以在启动转换后延迟读取 // 这里简化处理在启动转换的下一个周期读取 static uint8_t read_flag 0; if (read_flag) { int16_t raw_temp DS1821_ReadTemperatureRaw(); if (raw_temp ! 0xFFFF) { // 简单的错误检查复位失败会返回0xFFFF需根据实际情况调整 current_temperature DS1821_RawToCelsius(raw_temp); // 在这里可以使用温度值例如通过串口打印或进行控制逻辑判断 printf(Current Temperature: %.1f C\r\n, current_temperature); } read_flag 0; } else { // 启动转换后置位标志下一个周期读取 if ((current_time - last_conversion_time) 100) { // 转换启动后100ms再置位确保转换已开始 read_flag 1; } } }4. 精度校准、常见问题与进阶应用代码跑通了能读到温度了但这只是第一步。要想让DS1821在实际项目中稳定可靠地工作还需要考虑精度校准和排查一些常见问题。4.1 精度校准与补偿DS1821的标称精度在0°C到70°C范围内为±2°C。对于很多应用这个精度足够了。但如果需要更高的准确性可以进行一点校准。单点校准找一个你认为最准的温度计或恒温源在某个温度点比如25°C室温下同时读取DS1821的值和参考温度计的值计算出一个偏移量Offset。后续所有读数都加上这个偏移量。T_calibrated T_DS1821 Offset两点校准在高温和低温两个点例如0°C冰水混合物和50°C恒温箱分别测量可以计算出一个斜率和偏移量进行线性补偿。这能更好地修正传感器在整个量程内的非线性误差。公式类似于T_calibrated A * T_DS1821 B其中A和B通过两点标定计算得出。校准系数可以存储在XMC的Flash中或者如果DS1821连接了多个可以为每个传感器存储独立的校准值。4.2 通信失败排查指南当你发现DS1821_Reset()总是返回0无器件响应或者读回来的数据全是0xFF或0x00时可以按照以下步骤排查检查硬件连接这是最常出问题的地方。用万用表确认VDD、GND、DQ三根线是否连接正确且牢固。重点检查4.7kΩ上拉电阻是否接在DQ和VDD之间以及是否焊接良好。检查电源测量DS1821的VDD引脚电压确保在3.0V-5.5V之间。如果使用寄生供电在通信期间用示波器观察DQ线上的电压看是否能被拉高到足够的电平。检查时序用逻辑分析仪或示波器抓取DQ线上的波形这是最直接的调试手段。对照DS1821数据手册的时序图检查复位脉冲的低电平时间是否大于480us从主机释放总线拉高到采样存在脉冲的时间是否在15-60us之间写0/写1时序的低电平时间是否符合要求读时序中主机拉低的时间是否足够短1-15us采样点是否在15us之后检查代码延时确认你的delay_us函数是准确的。可以在GPIO上产生一个已知脉宽的信号并用示波器测量来校准延时函数。SysTick的延时精度很高但要确保CPU_FREQ_MHZ宏定义正确。检查GPIO配置确认XMC的GPIO已正确初始化为开漏输出模式并且初始状态为高。在切换输入输出模式时时序是否正确。总线负载过重如果总线上挂了多个单总线器件虽然DS1821通常单用但协议兼容电容会增大可能导致上升沿变缓。可以尝试减小上拉电阻如用2.2kΩ或者降低通信速率但DS1821不支持可变速率。4.3 多传感器管理与CRC校验虽然本项目标题是单个DS1821的应用但单总线协议本身支持一线挂多器件的。每个DS1821都有一个唯一的64位激光ROM码。通过“搜索ROM”命令可以枚举总线上的所有器件然后通过“匹配ROM”命令对特定器件进行操作。这对于需要多点测温的场景非常有用。此外DS1821的暂存器数据包含一个8位的CRC校验码。在读取多字节数据如温度值、TH、TL等后可以计算CRC并与读取的CRC字节比较以确保数据传输的正确性。在长距离或干扰较大的环境中启用CRC校验能极大提高通信可靠性。XMC的CRC硬件外设CRC单元可以很方便地用来计算单总线CRC减轻CPU负担。4.4 低功耗设计考虑如果项目是电池供电需要关注功耗。DS1821在待机状态下功耗极低典型值750nA。主要的耗电来自温度转换期间。因此低功耗策略可以是降低采样频率根据应用需要将温度采样间隔从1秒延长到10秒、1分钟甚至更长。间歇供电如果不使用寄生供电可以用一个XMC的GPIO口控制一个MOSFET来给DS1821的VDD供电。仅在需要测温时打开电源测完后立即关闭。这样可以完全消除传感器待机功耗。利用XMC的低功耗模式在两次采样间隔让XMC进入睡眠Sleep或深度睡眠Deep Sleep模式通过RTC或看门狗定时器唤醒从而大幅降低系统整体功耗。5. 从DS1821到其他温度传感器的思考成功集成DS1821后你可能会遇到新的需求需要更高的分辨率如0.1°C、更快的转换速度、更小的封装或者I2C/SPI接口。这时了解DS1821的优缺点能帮助你更好地选型。需要更高分辨率可以升级到DS18B20。它是DS1821的“升级版”分辨率可配置9-12位最高0.0625°C同样使用单总线命令集高度相似代码移植成本低。但时序要求更严格一些。需要更快的转换速度DS1821的典型转换时间是1秒DS18B20在12位分辨率下也需要750ms。如果需要每秒多次采样可以考虑MCP9808I2C接口典型转换时间30ms或TMP117I2C高精度转换时间可选。嫌弃单总线时序麻烦如果项目IO口不紧张希望用更标准、更易驱动的接口I2C或SPI接口的温度传感器是更好的选择如LM75I2C、MAX31865SPI用于PT100铂电阻。XMC的I2C和SPI外设非常强大配合DMA使用可以极大减轻CPU负担。需要模拟输出如果你的XMC板载了高精度ADC并且温度传感器离MCU很近模拟信号传输距离短那么使用热敏电阻或热电偶配合信号调理电路和ADC可能是成本更低的选择。但这需要你处理模拟电路的噪声、非线性校准等问题。选择哪种传感器没有绝对的好坏只有是否适合。DS1821以其极简的连接、数字化的输出和足够的精度在那些对成本敏感、布线受限、精度要求不极致的场合依然有着强大的生命力。通过这个项目你不仅掌握了一款具体传感器的用法更重要的是理解了如何根据需求选择外设如何阅读数据手册如何调试底层通信协议这些经验在接触任何新的传感器时都是通用的。
返回列表