新闻详情

新闻详情

首页 / 资讯中心 / 详情

从MY18E20看单总线协议:MicroPython手写温度传感器驱动实战

发布时间:2026/9/8 18:07:43来源:尧图网络
从MY18E20看单总线协议:MicroPython手写温度传感器驱动实战
搞嵌入式的人基本都遇过这种场面明明买的时候冲着 DS18B20 去的撕开标签一看丝印却是 MY18E20。我第一次遇到这芯片时也愣了一下查完资料发现它其实是 DS18B20 的兼容替代品单总线协议、寄存器结构、命令字基本照搬。这几年我在 MicroPython 项目里写了不少温度采集驱动绕了一圈之后反而觉得拿 MY18E20 来“练手”拆解单总线协议特别合适芯片便宜、时序窗口宽容、逻辑清晰踩坑成本也低。这篇文章我会从芯片身份、单总线底层时序、ROM 寻址机制、温度读取链路一直讲到手写一个可用的 MicroPython 驱动最后再复盘我实际调试中踩过的坑。适合两类人看一是想把单总线协议弄明白、不想只会调现成库的嵌入式初学者二是准备在 MicroPython 平台上自己写驱动做多点温度采集的项目开发者。1. 从芯片身份开始MY18E20 与 DS18B20 家族的亲缘关系1.1 命名与引脚先把这颗芯片认清楚MY18E20 的命名其实已经暴露了它的出处。“18”开头的是 Dallas/Maxim 定义的一类高精度数字温度传感器产品线DS18B20 是这个产品线里最出名的一颗MY18E20 里的“MY”一般理解为封装厂或品牌前缀“E20”对应的就是“B20”这颗核心功能。换句话说它就是一颗兼容 DS18B20 的国产替代芯片厂商在 ROM 家族码、暂存器布局、命令集上都做了兼容为的就是让老项目可以直接替换。引脚上 MY18E20 也是三脚封装为主常见 SOP8、TO-92、贴片几种形态。无论哪种封装三个关键引脚永远是GND电源地DQ数据线也是单总线通信的唯一通道VDD外部供电正极有一点我得提前说MY18E20 和 DS18B20 都支持“寄生供电”模式也就是 DQ 和数据线复用不需要 VDD 接电源也能工作。但实际项目中我会更推荐外部供电原因后面讲供电方式时展开。1.2 两种供电方式寄生供电与外接供电的取舍寄生供电的原理很有意思芯片内部有一颗电容数据线为高电平时通过 DQ 给这颗电容充电之后靠电容存储的电荷维持芯片工作。温度转换时电流会突然拉高数据线上必须提供“强上拉”——主机在发出转换命令后把数据线持续拉高至少 10ms否则转换过程中电容电量不够芯片会复位。外接供电就简单得多VDD 接 3.3V 或 5VDQ 只负责通信。这样温度转换期间不需要额外强上拉也更稳定。我的建议是只要布线条件允许一律选外接供电。寄生供电这个功能看起来省一根线实际调试时常常因为供电不足导致温度读数偶发为 85 摄氏度这是非常典型的一个坑。上拉电阻的选择也要多说一句。DQ 是开漏输出必须外接上拉电阻才能输出高电平经典值是 4.7kΩ。如果总线上挂的传感器数量多、线缆长上拉电阻可能需要降到 2.2kΩ 甚至 1kΩ。判断标准是测 DQ 低电平时的电压能否低于 0.8V 左右如果因为上拉太小导致低电平抬不起来通信就会出现随机错误。2. 单总线底层时序把它当成“开漏 时间窗”协议来理解2.1 为什么单总线能靠一根线既供电又通信单总线协议的物理基础是开漏结构这一点和 I2C 很像。设备端 DQ 内部只有一颗 MOS 管拉低时把总线拉到地释放时总线被外部上拉电阻拉回高电平。通信双方通过在特定时间窗口内拉低总线、观察总线电平变化来传递数据。这根线本身没有时钟线所有节奏都由主机控制。每个 bit 的传输都是一个严格的时间窗口读和写的窗口宽度都在 60~120 微秒之间。所以单总线本质上是“时间窗 电平采样”的组合理解了这个基础后面所有时序代码都不难懂。2.2 初始化时序复位脉冲与存在脉冲主机要和 MY18E20 通信第一步永远是复位。复位信号由主机拉低总线 480μs 以上然后释放总线。芯片检测到这个足够长的低电平脉冲后会等待一段时间再主动把总线拉低 60~240μs这就是存在脉冲相当于告诉主机“我在线”。我把常见的时序参数整理了一下方便对照参数最小典型最大单位主机复位脉冲拉低时间480500960μs主机释放后等待存在脉冲156060μs存在脉冲拉低时间60120240μs写 0 时隙拉低时间6075120μs写 1 时隙释放时间11515μs读采样时间点81515μs芯片的这个响应过程不受主机控制主机只能在特定时间点去采样总线电平。如果总线上没有设备主机会读到持续高电平那就说明通信链路有问题。2.3 读写时隙每一位都要卡在时间窗口里写完复位之后所有数据交换都通过“时隙”完成。写一个 bit 时主机要先拉低总线然后根据要写的是 0 还是 1 决定释放时机写 0 就继续保持低电平到 60μs 以上再释放写 1 就拉低一小段后立刻释放让上拉电阻把总线拉高。芯片会在主机拉低后的 15~60μs 窗口内采样总线电平采到低就是 0采到高就是 1。读一个 bit 稍微反直觉同样是主机拉低总线但拉低后必须迅速释放然后把总线交给芯片。芯片如果想让主机读到 0就会在随后的时间里主动把总线拉低如果想让主机读到 1就什么都不做让总线保持高电平。主机需要在拉低后大约 15μs 处采样一次再往后等 60μs 以上的恢复时间。这里有个现实中很容易误解的点单总线时序看起来全是微秒级窗口很多人以为要用微控制器的高级定时器才能实现。实际上因为芯片的采样窗口有容差即使主机端的延迟有几微秒偏差通信依然可靠。真正要命的是某个延时延时函数带来几十上百微秒的误差那才会导致通信失败。3. ROM 寻址和多点布局一条 GPIO 上挂十个传感器也不打架3.1 64 位 ROM 的结构与家族码每一颗 MY18E20 在出厂时都有一个唯一的 64 位序列号写入芯片内部的 ROM 区。这个 ROM 不是存温度数据的暂存器而是设备身份码结构如下8 位家族码MY18E20 是 0x2848 位序列号出厂唯一8 位 CRC 校验对前 56 位做循环冗余校验多点采集的时候主机可以利用 ROM 命令区分不同设备。如果总线上只有一颗传感器可以用“跳过 ROM”命令避免发送这 64 位地址直接进入功能命令如果有多个设备就必须先做寻址。3.2 常用 ROM 命令Skip ROM、Read ROM、Match ROM单总线 ROM 层的几个命令非常固定0xCC Skip ROM跳过地址直接进入功能命令适合单设备场景0x33 Read ROM读取设备 ROM 内容只能在总线上仅有一个设备时使用0x55 Match ROM后面必须跟 64 位地址只和地址匹配的设备响应0xF0 Search ROM主机通过搜索算法找出总线上所有设备的 ROM匹配 ROM 的使用很容易理解主机先广播 0x55然后按字节发送目标设备的 64 位 ROM。所有设备都知道这个地址不是自己的话就保持沉默只有被点名的设备会继续响应功能命令。3.3 ROM 搜索算法树状搜索的核心思路如果总线上挂了多颗传感器又不知道各自的 ROM 地址那就得用搜索算法。搜索 ROM 命令 0xF0 发出后主机逐个 bit 向设备“询问”ROM 内容每个 bit 位置主机先读一位再读一位取反位。如果总线上所有设备在该 bit 上的值相同两次读回的结果就是一个是 0 一个是 1如果出现分歧两个读回结果都是 0如果两次都读到 1说明总线出错。所以搜索过程本质是在一个 64 位二叉树上做深度优先遍历。每次遇到分歧位主机先选一个方向继续并记录分歧位置遍历完一个分支后回到分歧点走另一个分支。最终的输出就是总线上所有设备的 ROM 列表。不过在真实项目里我并不建议在 MicroPython 里频繁做全量搜索。总线上的传感器数量通常不多几个到十几个完全可以在部署时用上位机或调试脚本扫描一遍把设备 ROM 烧写进配置表。长期运行的程序直接按配置表匹配寻址这样既省时间又省代码量。4. 一次完整温度读取的链路从转换命令到摄氏度换算4.1 暂存器布局9 个字节里藏着什么MY18E20 的温度数据存在一个 9 字节的暂存器里结构非常固定字节内容说明0温度 LSB温度低字节1温度 MSB温度高字节2高温报警触发值用户可写3低温报警触发值用户可写4配置寄存器控制分辨率5保留固定为 0xFF6保留固定为 0x0C7保留固定为 0x108CRC前 8 字节的校验值上电后默认分辨率是 12 位对应 0.0625℃ 的温度精度。4.4 节会详细说怎么从 12 位二进制换算成实际温度。4.2 标准读取流程两次复位 两次写命令一次完整的温度读取要经历两组“复位 ROM 命令 功能命令”复位发 0xCC跳过 ROM发转换命令 0x44启动温度转换等待转换完成12 位分辨率下典型等待 750ms再次复位发 0xCC跳过 ROM发读暂存器命令 0xBE连续读 9 个字节对前 8 个字节做 CRC 校验第一次发转换命令后等待时间由分辨率决定。9 位分辨率对应 93.75ms10 位对应 187.5ms11 位对应 375ms12 位对应 750ms。代码里一般直接 sleep 750ms省心但不高效。如果项目对功耗敏感可以先发转换命令然后轮询读一位状态位转换完成后芯片会自动拉高总线这样能省下几百毫秒的空转时间。4.3 温度换算补码与 0.0625 的分度值读取回来的前两个字节是温度原始值一个 16 位有符号数低字节在前。组合方式很简单raw (data[1] 8) | data[0]12 位数据有效位是低 12 位但数据寄存器里高 4 位是符号扩展位。如果raw 0x8000不为 0说明是负温度需要先取补码再计算if raw 0x8000: raw -((~raw 1) 0xFFFF) temp raw * 0.0625这里有个新手容易算错的地方(~raw 1) 0xFFFF这个操作不能丢因为 Python 里整型没有位数上限不把结果限制在 16 位内负数运算结果会很奇怪。换算到实际案例读回 LSB0xD0MSB0xFC合并后是 0xFCD0补码转换后是 -816乘 0.0625 得到 -51℃这是一个非常典型的负温度值。5. 手写一个 MicroPython 驱动从选型、时序实现到完整代码5.1 为什么不直接用现成库还要自己写MicroPython 固件里自带onewire和ds18x20模块用起来两行代码就能读到温度。但自带库有几个局限第一它默认按 DS18B20 的默认时序工作对 MY18E20 这类兼容芯片的容错和超时控制是黑盒第二想加 CRC 校验、多点匹配、状态查询这些功能时扩展反而比重写更麻烦第三自带库依赖底层 C 实现的 onewire 模块在某些精简固件或非标准板子上不一定可用。自己写驱动的过程本质上是把协议吃透的过程。我强烈建议即使最终用自带库也先自己实现一遍。把代码压到最小时你会发现 MicroPython 的层次结构其实非常适合这类 bit-banging 应用。5.2 驱动核心代码复位、读写位、读写字节先给出完整核心类。我用的是machine.Pin的OPEN_DRAIN模式如果是 ESP8266 等不支持该模式的平台可以用普通输出口加外部上拉电阻替代代码里只需改动初始化部分。import time from machine import Pin class MY18E20: def __init__(self, pin): self.pin Pin(pin, Pin.OPEN_DRAIN, Pin.PULL_UP) self.pin.value(1) def _reset(self) - bool: self.pin.value(0) time.sleep_us(500) self.pin.value(1) time.sleep_us(70) presence self.pin.value() time.sleep_us(410) return presence 0 def _write_bit(self, bit: int): self.pin.value(0) if bit: time.sleep_us(6) self.pin.value(1) time.sleep_us(64) else: time.sleep_us(90) self.pin.value(1) time.sleep_us(6) def _read_bit(self) - int: self.pin.value(0) time.sleep_us(2) self.pin.value(1) time.sleep_us(8) val self.pin.value() time.sleep_us(60) return val def _write_byte(self, byte: int): for i in range(8): self._write_bit((byte i) 0x01) def _read_byte(self) - int: val 0 for i in range(8): val | self._read_bit() i return val有几点要说明_reset()里我在采样存在脉冲前先睡了 70μs这是芯片手册给出的等待时间。采样完成后继续等足 410μs是为了保证整个复位时序完整避免紧接着的读写操作“跑进”上一条命令的尾巴里。_write_bit里写 1 时只拉低 6μs 就释放这个 6μs 不是一个严格参数不同兼容芯片对“写 1 时隙里的低电平时间”容忍范围很大6μs 是我在不同平台上测试都比较安全的经验值。_read_bit里的采样点选在拉低后大约 10μs 处对应 8~15μs 的典型窗口加上 MicroPython 执行self.pin.value()本身还有几微秒开销实际采样点会落在正确区间内。5.3 读取温度单设备与多设备两种路径单设备模式下直接用 Skip ROM 命令省掉 64 位地址传输staticmethod def _crc8(data) - int: crc 0 for byte in data: for _ in range(8): mix (crc ^ byte) 0x01 crc 1 if mix: crc ^ 0x8C byte 1 return crc def read_temp(self, rom: bytes None): if not self._reset(): return None if rom: self._write_byte(0x55) for b in rom: self._write_byte(b) else: self._write_byte(0xCC) self._write_byte(0x44) time.sleep_ms(750) if not self._reset(): return None if rom: self._write_byte(0x55) for b in rom: self._write_byte(b) else: self._write_byte(0xCC) self._write_byte(0xBE) data bytes([self._read_byte() for _ in range(9)]) if self._crc8(data) ! 0: return None raw (data[1] 8) | data[0] if raw 0x8000: raw -((~raw 1) 0xFFFF) return raw * 0.0625CRC 校验用的是 Maxim 1-Wire 的标准多项式LSB-first 形式下掩码是0x8C。如果 CRC 结果不为 0说明这 9 个字节传输有误直接丢弃这次读数。温度在很多项目里是慢变量返回None让上层重试比返回一个脏数据要安全得多。多设备场景下的调用方式是把已知设备的 64 位 ROM 以字节序列传入devices [ b\x28\xaa\xbb\xcc\xdd\xee\xff\x01, b\x28\xaa\xbb\xcc\xdd\xee\xff\x02, ] for rom in devices: t sensor.read_temp(romrom) if t is not None: print(temp:, t, rom:, rom.hex())注意 ROM 字节顺序是低位在前也就是先发家族码 0x28再发序列号和 CRC。如果你用自带ds18x20库扫描过设备它会返回 8 字节的 ROM直接塞进来就能用。5.4 时序精度的优化与 MicroPython 的延迟陷阱MicroPython 的time.sleep_us实际上不是一个精密的微秒定时器。它在不同固件上的实现差异很大有的平台用 SysTick 驱动最小粒度是 1μs但加上 Python 字节码解释开销后实际延迟可能比参数多出几微秒有的平台则直接用忙等待循环误差相对可控。好消息是 MY18E20 的时序容差足够大几微秒的偏移并不会致命。真正致命的是在读写时序中间发生中断、垃圾回收或线程调度导致延迟突然拉长几十微秒。所以在写驱动时我会有意识地把时序关键代码放在较短的函数里减少中间调用层级如果并发任务多可以在关键读写前暂时禁用中断from machine import disable_irq, enable_irq irq_state disable_irq() # 这里执行一次完整的 bit 读写 enable_irq(irq_state)但注意disable_irq的粒度很粗千万不要在禁用中断的状态里做sleep_ms(750)那会把整个系统的时钟、定时器都卡死。正确做法是只在单个 bit 的读写函数内部短暂禁用中断也就是把_write_bit和_read_bit包一层。我自己在 ESP32 和 RP2040 上都跑过这个驱动不额外禁用中断也能稳定工作但如果你的环境里有 Wi-Fi 协议栈频繁抢占 CPU加一层保护会更安心。5.5 和自带 ds18x20 模块的对比跑完自写驱动再把结果和自带库对比一下更有意思。我实测的差异如下对比项自带 ds18x20手写驱动代码量少多CRC 校验模块内部处理自己实现可控制多点寻址支持但封装 API 固定灵活可按项目需求调整调试可控性低高对非标兼容芯片的容差一般可根据实测调整时序占用 Flash少略多如果你的项目追求快速交付直接用自带库完全没问题。但如果你想在特殊板卡上移植、或者要适配一批参数不太标准的兼容芯片手写驱动的价值就体现出来了。6. 现场调试实录驱动写完后我踩过的那些坑与规避方法6.1 读回数值一直都是 85℃别急着怀疑代码这个现象太经典了。85℃ 是 MY18E20/DS18B20 上电后暂存器里的默认温度值它一般不代表真实环境温度而是芯片在上电初始化时温度寄存器里的一个固定初值。如果你的程序不断读到 85℃ 而不是有效温度多半是温度转换命令没有成功执行或者转换过程中芯片掉电复位。我遇到过一次特别隐蔽的情况为了省电转换命令发出后立刻把主机的 DQ 引脚配置成输入并关闭上拉然后 sleep 750ms。结果寄生供电的传感器在转换期间彻底失电芯片自动复位。解决方法是要么用外部供电要么在转换期间保持总线上拉和高电平输出。如果你用外接供电还读到 85℃再检查代码里是否真的发了 0xCC 和 0x44或者用示波器看 DQ 上转换期间有没有被异常拉低。6.2 长线传输时偶发读空上拉和线材是最大变量传感器和主板之间的线一长问题就开始出现。两米以内通常没事超过 5 米或者和电机线、电源线并行走线单总线的时序会被分布电容和干扰拖垮。我的排查思路是这样的先看复位时序是否正常如果复位后存在脉冲采样时好时坏大概率是上拉电阻太大导致上升沿太慢。这时把 4.7kΩ 换成 2.2kΩ 或者 1kΩ 试试。如果上拉换了还不行就要检查是不是数据线旁边有强干扰源把 DQ 改成双绞线或者屏蔽线能明显改善。另一个常被忽略的是地线。单总线靠的是 DQ 对地电平差来通信如果传感器板和主板之间的地线太长地电位不一致所有时序都会失真。长线采集时我至少会拉一根独立的地线过去而不是依赖电源负极那根走线。6.3 MicroPython 固件差异导致的时序不稳定同样的驱动代码在 ESP32 官方固件上跑得好好的换到某些精简固件或者国产开发板定制的固件上就可能时不时读不到存在脉冲。这类问题的根源基本都在time.sleep_us的实现差异上。排查方法很简单在_reset函数里用逻辑分析仪抓 DQ 电平测量从拉低到释放的时间是否真的是 500μs。如果实际时间明显偏离或者抖动大优先尝试把import time换成import utime在某些固件上 utime 才是较稳定的实现反过来也一样再不行就手动调整_reset里的睡眠参数把 500μs 改成 600μs。MY18E20 对复位脉冲的容差是 480μs 到 960μs给足余量并不会伤到通信。我在 RP2040 上实测时发现MicroPython 的time.sleep_us在小数值区间表现还可以但一旦在大量字节读写循环里反复调用整体耗时比理想值多出明显一截。所以长时间连续读取场景下我会在两次读取之间主动加一点点延时避免芯片还没准备好主机就开始下一次复位。6.4 按 ROM 匹配多设备时地址写反这个坑纯粹是字节序问题。单总线协议以 LSB-first 顺序发送 ROM也就是说编程时经常看到的 ROM 十六进制打印值28 ff 12 34 56 78 90 ab发送时第一个字节就是0x28家族码。但有些人从模块自带库拿到地址后习惯性地把它当成“大端整数”再倒序发送结果匹配 ROM 命令后永远没有设备响应。我的建议是把 ROM 一律当bytes对象处理发送时按列表顺序for b in rom: self._write_byte(b)打印时用.hex()显示这样字节序从头到尾一致不容易错。如果你在代码里用整数变量存 ROM那一定要搞清每个字节的发送顺序否则改起来非常痛苦。6.5 为什么说 CRC 校验必须有MY18E20 这类芯片工作在工业现场时数据线很容易被干扰。短距离时温度数据偶发一个 bit 错误换算出来可能差好几度如果恰好是符号位错了温度甚至能从正变负。CRC 校验是最后一道防线它不保证数据一定正确但能保证错误数据不会被上层当成有效值使用。手写驱动的另一个好处是CRC 校验函数完全可以复用去校验其他 1-Wire 设备的数据。我代码里那个_crc8函数比较简洁逐 bit 计算速度在 MicroPython 下稍慢但对 9 字节的暂存器读取完全够用。如果你在意速度可以改成查表法用 256 字节的表换时间但在 ESP32 这类主频上百兆的平台上逐 bit 计算开销其实微不足道。7. 把驱动接进真实项目的几点补充写完驱动只是第一步真正部署时还有几件事值得注意。一是读取频率不要太高。MY18E20 完成一次 12 位转换需要 750ms即使你只读 9 位分辨率转换时间也要 93.75ms。所以设置成 1 秒读一次已经是比较激进的了连续高频读取除了浪费功耗还会让芯片内部持续处于转换状态反而增加数据不稳定的概率。二是异常处理要放在最外层。read_temp返回None时上层循环要做得优雅一点。我的习惯是连续失败 3 次才真正报错单次失败可能只是干扰多试一次往往就恢复了。如果连续多次失败则丢弃这条数据并打日志而不是在业务逻辑里频繁重试。三是不同批次的 MY18E20 时序容差可能略有差异。做正式项目时我建议批量采购后先抽样测一遍把驱动里的几个关键时序参数复位脉冲长度、采样等待时间做成常量方便在全局统一调整。这样即使后续换了批次只需要微调参数不用改业务代码。四是和自带ds18x20库的共存问题。如果一个工程里既有自写驱动又有自带库两个驱动会共用同一套 GPIO 和上拉配置但各自维护自己的时序逻辑。混用不是不行但调试时容易分不清是哪个驱动在读总线。我倾向于一整个项目只保留一套底层读取实现避免隐性冲突。说实话我最初写这个驱动只是为了把一颗国产兼容芯片跑通但拆开协议之后收获比预期大得多。单总线的“一根线跑天下”思路、开漏结构与上拉电阻的配合、ROM 搜索算法的树形思想这些概念在 I2C、SPI 和 CAN 里都能找到影子。掌握了 MY18E20 的驱动编写再去看其他单总线设备比如 EEPROM、湿度传感器、甚至某些加密防伪芯片基本上半天就能上手。如果这篇文章能帮你少走几个我走过的弯路那就很值了。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

AI写作实用指南:高效创作技巧与应用场景解析 2026/9/8 18:52:49

AI写作实用指南:高效创作技巧与应用场景解析

搞科研的朋友都懂,找英文文献永远是科研路上第一道耗时又磨人的坎。 尤其是 2026 年的当下,顶刊新成果迭代速度翻倍,学校图书馆权限永远覆盖不全,关键词检索翻几十页都找不到匹配研究方向的核心论文;免费 OA 平台要么…

阅读更多 →
科研idea高效挖掘与落地实操指南 2026/9/8 18:52:49

科研idea高效挖掘与落地实操指南

搞科研的朋友都懂,找英文文献永远是科研路上第一道耗时又磨人的坎。 尤其是 2026 年的当下,顶刊新成果迭代速度翻倍,学校图书馆权限永远覆盖不全,关键词检索翻几十页都找不到匹配研究方向的核心论文;免费 OA 平台要么…

阅读更多 →
FPGA三段式状态机设计实战:从按键消抖到序列检测器 2026/9/8 18:52:49

FPGA三段式状态机设计实战:从按键消抖到序列检测器

最近好几个读者几乎同时问我同一个问题:按键消抖代码明明照着例程写的,为什么按十次有五次失灵?我把代码拿过来一看,问题不在消抖算法,而在逻辑设计的基本功上——状态机虽然写了,但状态跳转和输出全糊在同…

阅读更多 →
AI学术应用的发展现状与实践价值探析 2026/9/8 18:52:49

AI学术应用的发展现状与实践价值探析

搞科研的朋友都懂,找英文文献永远是科研路上第一道耗时又磨人的坎。 尤其是 2026 年的当下,顶刊新成果迭代速度翻倍,学校图书馆权限永远覆盖不全,关键词检索翻几十页都找不到匹配研究方向的核心论文;免费 OA 平台要么…

阅读更多 →
从GPU训练到RK3566部署:机器人强化学习落地全流程解析 2026/9/8 18:52:49

从GPU训练到RK3566部署:机器人强化学习落地全流程解析

把训练好的机器人策略从英伟达 GPU 搬到一块 RK3566 上,听着好像只是装环境、拷模型的事,但真做起来,坑多到你得把 GitHub 仓库从头到尾再翻几遍。这块 25 厘米级的 Microduck 桌面小机器人,是典型的“训练重、部署轻”的强化学习…

阅读更多 →
OpenCV Color Correction 色彩校正系列:线性化变换(Linearization Transformation)原理、公式与源码实现解析 2026/9/8 18:49:48

OpenCV Color Correction 色彩校正系列:线性化变换(Linearization Transformation)原理、公式与源码实现解析

OpenCV Color Correction 色彩校正系列:线性化变换(Linearization Transformation)原理、公式与源码实现解析 【免费下载链接】opencv Open Source Computer Vision Library 项目地址: https://gitcode.com/GitHub_Trending/opencv31/openc…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞