<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <author>
    <name>John Doe</name>
  </author>
  <generator uri="https://hexo.io/">Hexo</generator>
  <id>https://blog.j182010.top/</id>
  <link href="https://blog.j182010.top/" rel="alternate"/>
  <link href="https://blog.j182010.top/atom.xml" rel="self"/>
  <rights>All rights reserved 2026, John Doe</rights>
  <title>Hexo</title>
  <updated>2026-09-04T15:43:07.879Z</updated>
  <entry>
    <author>
      <name>John Doe</name>
    </author>
    <category term="学习" scheme="https://blog.j182010.top/categories/%E5%AD%A6%E4%B9%A0/"/>
    <category term="RTOS" scheme="https://blog.j182010.top/tags/RTOS/"/>
    <id>https://blog.j182010.top/2026/06/28/%E4%BB%BB%E5%8A%A1%E6%9C%BA%E5%88%B6%EF%BC%88%E5%AD%A6%E4%B9%A0%E5%9F%B9%E8%AE%AD%EF%BC%89/</id>
    <link href="https://blog.j182010.top/2026/06/28/%E4%BB%BB%E5%8A%A1%E6%9C%BA%E5%88%B6%EF%BC%88%E5%AD%A6%E4%B9%A0%E5%9F%B9%E8%AE%AD%EF%BC%89/"/>
    <published>2026-06-27T16:00:00.000Z</published>
    <title>任务机制（学习培训）</title>
    <updated>2026-09-04T15:43:07.879Z</updated>
  </entry>
  <entry>
    <author>
      <name>John Doe</name>
    </author>
    <category term="调试" scheme="https://blog.j182010.top/categories/%E8%B0%83%E8%AF%95/"/>
    <category term="J-Link" scheme="https://blog.j182010.top/tags/J-Link/"/>
    <content>
      <![CDATA[<div class="toc"><!-- toc --><ul><li><a href="#itm-%E4%B8%8E-segger-rtt-viewer-%E5%8C%BA%E5%88%AB">ITM 与 SEGGER RTT Viewer 区别</a><ul><li><a href="#%E7%A1%AC%E4%BB%B6%E5%BC%95%E8%84%9A">硬件引脚</a><ul><li><a href="#itmswo">ITM(SWO)</a></li><li><a href="#rtt-viewer">RTT Viewer</a></li></ul></li><li><a href="#%E5%B7%A5%E4%BD%9C%E5%8E%9F%E7%90%86">工作原理</a><ul><li><a href="#itmswo">ITM‑SWO</a></li><li><a href="#rtt">RTT</a></li></ul></li><li><a href="#%E5%85%B3%E9%94%AE%E6%80%A7%E8%83%BD%E5%AF%B9%E6%AF%94">关键性能对比</a></li><li><a href="#%E5%AE%9E%E9%99%85%E5%BC%80%E5%8F%91%E7%97%9B%E7%82%B9">实际开发痛点</a></li><li><a href="#cubemx%E5%AF%B9%E5%BA%94%E5%85%B3%E7%B3%BB%E5%9B%9E%E9%A1%BE">CubeMX对应关系回顾</a></li><li><a href="#%E9%80%89%E5%9E%8B%E5%BB%BA%E8%AE%AE">选型建议</a><ul><li><a href="#%E8%A1%A5%E5%85%85%E5%B0%8F%E6%8F%90%E7%A4%BA">补充小提示</a></li></ul></li></ul></li></ul><!-- tocstop --></div><h1><span id="itm-与-segger-rtt-viewer-区别">ITM 与 SEGGER RTT Viewer 区别</span></h1><blockquote><p>ITM：ARM Cortex‑M 内核自带的 <strong>Instrumentation Trace Macrocell</strong>，对应你前面看到的 <code>Trace Asynchronous Sw</code>（SWO 异步跟踪）。<br>RTT：SEGGER J‑Link 私有技术，不依赖内核 Trace 外设，靠内存环形缓冲区交互。</p></blockquote><h2><span id="硬件引脚">硬件引脚</span></h2><h3><span id="itmswo">ITM(SWO)</span></h3><ul><li>需要：<code>SWDIO</code>、<code>SWCLK</code> + <strong>SWO 跟踪引脚</strong>（单独一根物理引脚）</li><li>STM32：PA13(SWDIO), PA14(SWCLK), <strong>PB3&#x3D;SWO</strong></li><li>必须硬件引出SWO引脚；很多最小系统板没有引出PB3，直接用不了ITM。</li><li>信号是<strong>单向输出</strong>：MCU → 调试器，MCU只能发，不能接收主机下发字符。</li></ul><h3><span id="rtt-viewer">RTT Viewer</span></h3><ul><li>只需要标准SWD两根线：<code>SWDIO + SWCLK</code>，<strong>不需要SWO引脚</strong>。</li><li>完全复用下载调试的SWD接口，不用额外接线。</li><li><strong>双向通信</strong>：MCU输出打印；PC端可以发字符串&#x2F;命令给单片机。</li></ul><h2><span id="工作原理">工作原理</span></h2><h3><span id="itmswo">ITM‑SWO</span></h3><ol><li>Cortex‑M内核ITM外设把printf字符打包成trace数据包</li><li>通过SWO引脚串行输出</li><li>J‑Link&#x2F;ST‑Link捕获SWO引脚电平，解析字节流输出日志</li><li>属于<strong>硬件跟踪外设</strong>，内核硬件完成数据输出；CPU要开销驱动ITM寄存器。<blockquote><p>CubeMX里选项：<code>Trace Asynchronous Sw</code> 就是开启ITM‑SWO。</p></blockquote></li></ol><h3><span id="rtt">RTT</span></h3><ol><li>MCU内存开辟<strong>环形缓冲区（up‑buffer：MCU发PC；down‑buffer：PC发MCU）</strong></li><li>J‑Link调试器<strong>不停通过SWD读MCU内存</strong>，轮询读取缓冲区；写缓冲区实现PC下发数据。</li><li><strong>不使用内核Trace硬件，纯内存+调试器读写</strong>。</li><li>代码层面需要SEGGER_RTT库，把printf重定向到RTT。</li></ol><h2><span id="关键性能对比">关键性能对比</span></h2><table><thead><tr><th>项目</th><th>ITM‑SWO</th><th>SEGGER RTT</th></tr></thead><tbody><tr><td>额外引脚</td><td>需要SWO(PB3)</td><td>仅标准SWD，无需额外引脚</td></tr><tr><td>双向通信</td><td>❌只能MCU输出打印</td><td>✅双向收发，可下发命令</td></tr><tr><td>中断里输出</td><td>高速中断慎用；波特率有限</td><td>✅支持中断输出（注意缓冲区溢出）</td></tr><tr><td>速度</td><td>受SWO波特率限制，一般几Mbit</td><td>速度很高，不受外部引脚波特率限制；受SWD读写速度限制</td></tr><tr><td>ST‑Link支持</td><td>✅ST‑Link支持SWO</td><td>❌<strong>ST‑Link不支持RTT！只能J‑Link</strong></td></tr><tr><td>低功耗场景</td><td>SWO引脚持续输出，会影响休眠</td><td>MCU休眠时调试器读内存会唤醒MCU，低功耗测试要注意</td></tr><tr><td>代码依赖</td><td>内核自带，几乎不用额外代码</td><td>必须导入SEGGER_RTT源文件</td></tr><tr><td>缓冲区溢出</td><td>丢数据，直接截断</td><td>缓冲区满会丢字符，可以配置阻塞模式</td></tr></tbody></table><h2><span id="实际开发痛点">实际开发痛点</span></h2><ol><li><strong>ST‑Link用户：只能用ITM‑SWO，不能用RTT</strong>，RTT是SEGGER私有，ST‑Link硬件不支持。</li><li>RTT最大优势：不需要SWO引脚；支持双向交互；但是<strong>必须J‑Link仿真器</strong>。</li><li>ITM‑SWO：很多板子PB3被LED占用，或者没有引出，硬件直接废掉ITM打印。</li><li>ITM在高波特率下，如果CPU进入Sleep，SWO输出会乱码；RTT如果MCU休眠，调试器读内存会唤醒芯片，测STOP待机电流会不准。</li></ol><h2><span id="cubemx对应关系回顾">CubeMX对应关系回顾</span></h2><ul><li><code>Serial Wire</code>：普通SWD下载调试，只下载+断点调试，<strong>没有打印输出功能</strong>。</li><li><code>Trace Asynchronous Sw</code>：SWD+开启ITM异步跟踪，开启SWO打印输出。</li></ul><h2><span id="选型建议">选型建议</span></h2><ol><li>手上是 <strong>J‑Link仿真器 → 优先RTT Viewer</strong>，不用折腾SWO引脚，支持双向命令交互，工程最舒服。</li><li>手上是 <strong>ST‑Link</strong>：只能 ITM‑SWO(SWO引脚必须引出)，或者普通串口printf。</li><li>做低功耗休眠电流测试：两者都有副作用，建议改用硬件UART打印。</li></ol><h3><span id="补充小提示">补充小提示</span></h3><ul><li>ITM printf重定向：重定向<code>ITM_SendChar()</code></li><li>RTT：把<code>SEGGER_RTT_printf()</code>包装成printf，或者retarget重定向stdout。</li></ul><p>如果你需要，我可以贴极简的ITM打印重定向代码，以及RTT最小工程示例。</p>]]>
    </content>
    <id>https://blog.j182010.top/2026/06/19/ITM/</id>
    <link href="https://blog.j182010.top/2026/06/19/ITM/"/>
    <published>2026-06-19T01:00:00.000Z</published>
    <summary>
      <![CDATA[<div class="toc">

<!-- toc -->

<ul>
<li><a href="#itm-%E4%B8%8E-segger-rtt-viewer-%E5%8C%BA%E5%88%AB">ITM 与 SEGGER RTT Viewer 区别</a><ul>
<]]>
    </summary>
    <title>ITM</title>
    <updated>2026-08-20T15:08:47.317Z</updated>
  </entry>
  <entry>
    <author>
      <name>John Doe</name>
    </author>
    <category term="调试" scheme="https://blog.j182010.top/categories/%E8%B0%83%E8%AF%95/"/>
    <category term="J-Link" scheme="https://blog.j182010.top/tags/J-Link/"/>
    <content>
      <![CDATA[<div class="toc"><!-- toc --><ul><li><a href="#%E4%B8%80-%E8%83%8C%E6%99%AF%E4%B8%B2%E5%8F%A3%E6%97%A5%E5%BF%97%E7%9A%84%E7%97%9B%E7%82%B9">一、背景：串口日志的痛点</a></li><li><a href="#%E4%BA%8C-j-link-rtt-viewer-%E6%98%AF%E4%BB%80%E4%B9%88">二、J-Link RTT Viewer 是什么</a></li><li><a href="#%E4%B8%89-%E6%A0%B8%E5%BF%83%E5%8E%9F%E7%90%86%E4%B8%BA%E4%BB%80%E4%B9%88%E5%AE%83%E4%B8%8D%E5%8D%A0-mcu-%E8%B5%84%E6%BA%90">三、核心原理：为什么它”不占 MCU 资源”</a><ul><li><a href="#31-%E6%95%B4%E4%BD%93%E6%9E%B6%E6%9E%84">3.1 整体架构</a></li><li><a href="#32-%E6%97%A0%E9%94%81%E8%AE%BE%E8%AE%A1%E8%AF%BB%E5%86%99%E6%8C%87%E9%92%88%E7%9A%84%E5%88%86%E5%B7%A5">3.2 无锁设计：读写指针的分工</a></li><li><a href="#33-j-link-%E5%A6%82%E4%BD%95%E5%AE%9A%E4%BD%8D%E6%8E%A7%E5%88%B6%E5%9D%97">3.3 J-Link 如何定位控制块</a></li><li><a href="#34-%E9%98%BB%E5%A1%9E-vs-%E9%9D%9E%E9%98%BB%E5%A1%9E%E6%A8%A1%E5%BC%8F">3.4 阻塞 vs 非阻塞模式</a></li></ul></li><li><a href="#%E5%9B%9B-%E7%9B%B8%E8%BE%83-uart-%E4%B8%B2%E5%8F%A3%E6%89%93%E5%8D%B0%E7%9A%84%E4%BC%98%E5%8A%BF">四、相较 UART 串口打印的优势</a></li><li><a href="#%E4%BA%94-%E5%B7%A5%E7%A8%8B%E7%A7%BB%E6%A4%8Dkeil">五、工程移植（Keil）</a><ul><li><a href="#51-%E8%8E%B7%E5%8F%96%E6%BA%90%E7%A0%81">5.1 获取源码</a></li><li><a href="#52-%E5%8A%A0%E5%85%A5%E5%B7%A5%E7%A8%8B">5.2 加入工程</a></li><li><a href="#53-%E5%88%9D%E5%A7%8B%E5%8C%96%E4%B8%8E%E6%89%93%E5%8D%B0">5.3 初始化与打印</a></li><li><a href="#54-%E4%B8%B2%E5%8F%A3%E9%87%8D%E6%98%A0%E5%B0%84printf-%E9%87%8D%E5%AE%9A%E5%90%91">5.4 串口重映射（printf 重定向）</a></li></ul></li><li><a href="#%E5%85%AD-%E8%BF%9B%E9%98%B6%E5%AF%BC%E5%85%A5-ulog-%E7%BB%84%E4%BB%B6%E5%AE%9E%E7%8E%B0%E5%B8%A6%E9%A2%9C%E8%89%B2-%E7%AD%89%E7%BA%A7%E7%9A%84%E6%97%A5%E5%BF%97">六、进阶：导入 uLog 组件，实现带颜色、等级的日志</a><ul><li><a href="#61-%E9%85%8D%E7%BD%AErtconfigh-%E7%A4%BA%E4%BE%8B">6.1 配置（<code>rtconfig.h</code> 示例）</a></li></ul></li><li><a href="#%E4%B8%83-rtt-server-xshell%E8%BF%9C%E7%A8%8B%E6%97%A5%E5%BF%97%E4%BA%A4%E4%BA%92">七、RTT Server + Xshell：远程日志交互</a><ul><li><a href="#71-%E5%8E%9F%E7%90%86">7.1 原理</a></li><li><a href="#72-xshell-%E9%85%8D%E7%BD%AE">7.2 Xshell 配置</a></li><li><a href="#73-%E6%97%A5%E5%BF%97%E8%AE%B0%E5%BD%95">7.3 日志记录</a></li></ul></li><li><a href="#%E5%85%AB-%E5%B7%A5%E7%A8%8B%E8%90%BD%E5%9C%B0%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9%E8%B8%A9%E5%9D%91%E6%80%BB%E7%BB%93">八、工程落地注意事项（踩坑总结）</a></li><li><a href="#%E4%B9%9D-%E5%BF%AB%E9%80%9F-checklist">九、快速 Checklist</a></li><li><a href="#%E5%8D%81-%E9%80%82%E7%94%A8%E5%9C%BA%E6%99%AF%E6%80%BB%E7%BB%93">十、适用场景总结</a><ul><li><a href="#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99">📎 参考资料</a></li></ul></li></ul><!-- tocstop --></div><h2><span id="一-背景串口日志的痛点">一、背景：串口日志的痛点</span></h2><p>串口打印是嵌入式开发中最常见的调试手段，但在实际工程中越来越力不从心。</p><p><img src="/images/J-Link%20RTT%20Viewer%20日志系统/0.png" style="width: 800px;"><br></p><ol><li><p><strong>实时性杀手</strong>：在调试中断处理程序、电机控制、无线通讯等对时序极为敏感的场景时，UART <code>printf</code> 通过轮询或中断发送一个字节往往要耗时数微秒到数毫秒。轻则导致通信丢帧，重则系统直接崩溃。<strong>RTT 的写入操作本质上只是一次内存拷贝，延迟在纳秒级，甚至可以在中断服务函数（ISR）中直接安全调用。</strong></p></li><li><p><strong>硬件资源占用</strong>：UART 外设 + TX&#x2F;RX 引脚，在多引脚复用的低成本 MCU 上是奢侈资源。以<strong>燃气表、水表、烟感、BLE 信标</strong>这类产品为例，量产阶段 UART 引脚通常不引出、不预留——传统串口日志在部署后等于”失明”，现场出问题时无从排查。</p></li><li><p><strong>单向为主，交互成本高</strong>：传统串口即使做双向通信，也要额外处理回显、命令解析、中断抢占，且通常占用更多软件资源。而 RTT 天然支持全双工双向，相当于在调试口上”免费”开了一个交互式终端。</p></li></ol><blockquote><p>💡 <strong>一句话总结</strong>：串口日志在低成本、高实时、引脚紧张的场景下，要么用不起，要么不敢用。RTT 正是为解决这个问题而生——<strong>复用调试口，零额外硬件，双向高速通信</strong>。</p></blockquote><hr><h2><span id="二-j-link-rtt-viewer-是什么">二、J-Link RTT Viewer 是什么</span></h2><p><strong>RTT（Real Time Transfer，实时传输）</strong> 是 SEGGER 专为 J-Link 仿真器开发的<strong>基于内存共享的高速双向实时通信机制</strong>；它把 SWO 高速输出和半主机双向交互的优点以极高的性能结合起来。</p><p><strong>J-Link RTT Viewer</strong> 是 SEGGER 配套提供的 GUI 上位机工具，属于 J-Link 软件安装包自带程序（Windows &#x2F; macOS &#x2F; Linux 均支持）。</p><!-- 缩小图片尺寸 --><img src="/images/J-Link%20RTT%20Viewer%20日志系统/4.png" style="width: 600px;"><!--居中显示图片<img src="/images/J-Link%20RTT%20Viewer%20日志系统/J-Link%20RTT%20Viewer%20日志系统-4.png" width="600" style="display:block; margin:0 auto;">--><hr><h2><span id="三-核心原理为什么它不占-mcu-资源">三、核心原理：为什么它”不占 MCU 资源”</span></h2><h3><span id="31-整体架构">3.1 整体架构</span></h3><p>MCU 工程移植 SEGGER RTT 源码后，会在芯片 RAM 中创建 <strong>RTT 控制块（RTT Control Block）</strong> 与若干 <strong>环形缓冲区（Ring Buffer）</strong>：</p><ol><li>设备固件将日志、数据写入<strong>上行缓冲区（Up-channel，Target → PC）</strong>；</li><li>J-Link 通过已有的 SWD&#x2F;JTAG 调试接口，<strong>后台直接读取</strong> MCU 内存中的缓冲区数据，全程<strong>目标 CPU 不被 halt</strong>；</li><li>PC 端工具（RTT Viewer &#x2F; RTT Client &#x2F; Telnet 客户端）接收数据并展示；</li><li>同时支持反向写入<strong>下行缓冲区（Down-channel，PC → Target）</strong>，实现指令下发、双向交互。<br><img src="/images/J-Link%20RTT%20Viewer%20%E6%97%A5%E5%BF%97%E7%B3%BB%E7%BB%9F/5.png"></li></ol><h3><span id="32-无锁设计读写指针的分工">3.2 无锁设计：读写指针的分工</span></h3><p>这是 RTT 能在中断中安全调用的<strong>核心秘密</strong>——环形缓冲区的读写指针由不同角色独占修改：</p><table><thead><tr><th>缓冲区</th><th>写指针由谁修改</th><th>读指针由谁修改</th></tr></thead><tbody><tr><td><strong>上行缓冲区</strong>（MCU → PC）</td><td><strong>仅 MCU 端</strong>写入</td><td><strong>仅 J-Link</strong>（Host）读取后更新</td></tr><tr><td><strong>下行缓冲区</strong>（PC → MCU）</td><td><strong>仅 J-Link</strong>（Host）写入</td><td><strong>仅 MCU 端</strong>读取后更新</td></tr></tbody></table><p>双方各写各的指针，永远不冲突，<strong>无需任何锁、无需关中断、无需临界区保护</strong>。这就是为什么 RTT 可以在 ISR 中直接调用的根本原因。</p><h3><span id="33-j-link-如何定位控制块">3.3 J-Link 如何定位控制块</span></h3><p>J-Link 上电后会在目标 RAM 的已知范围内<strong>自动扫描</strong>带有特定标识符（<code>&quot;SEGGER RTT&quot;</code>）的控制块结构。一旦找到，后续通信就直接按地址读写环形缓冲区，不再需要 CPU 参与数据传输。这就是为什么 RTT Viewer 连接时通常只需选对芯片型号、勾选 Auto Detection 即可。</p><blockquote><p>如果自动扫描失败（常见于 RAM 布局特殊或优化级别过高），可通过 map 文件定位 <code>_SEGGER_RTT</code> 符号地址，在 RTT Viewer 的 Address 栏手动填写。</p></blockquote><h3><span id="34-阻塞-vs-非阻塞模式">3.4 阻塞 vs 非阻塞模式</span></h3><p>每个通道可独立配置写入策略：</p><ul><li><strong>阻塞模式</strong>（<code>SEGGER_RTT_MODE_BLOCK_IF_FIFO_FULL</code>）：缓冲区满时应用等待，直到 J-Link 读走数据腾出空间——保证日志不丢，但可能阻塞当前任务</li><li><strong>非阻塞模式</strong>（<code>SEGGER_RTT_MODE_NO_BLOCK_SKIP</code>）：缓冲区满时直接丢弃新数据，程序继续执行——<strong>即使调试器没连，也不影响系统实时性</strong>，代码可原样保留到 Release 版本</li></ul><blockquote><p>⚠️ 严谨说法：RTT 不是”零开销”，目标侧仍需把数据 memcpy 到 RAM 缓冲区；但它的巧妙之处在于<strong>数据传输由 J-Link 通过调试接口后台异步完成</strong>，不占用 UART 外设、不产生阻塞等待、不抢占 ISR。</p></blockquote><hr><h2><span id="四-相较-uart-串口打印的优势">四、相较 UART 串口打印的优势</span></h2><table><thead><tr><th>维度</th><th>RTT</th><th>UART 串口</th></tr></thead><tbody><tr><td><strong>额外硬件</strong></td><td>无，复用调试接口</td><td>需要 UART 收发器 + USB-TTL 转接板</td></tr><tr><td><strong>占用引脚</strong></td><td>0（复用 SWD）</td><td>至少 TX&#x2F;RX 2 个引脚</td></tr><tr><td><strong>通信方向</strong></td><td>全双工双向</td><td>硬件全双工，但日志场景多为 TX-only</td></tr><tr><td><strong>传输速度</strong></td><td>极高，可达 <strong>1 MB&#x2F;s 以上</strong></td><td>受波特率限制，通常 ≤ 1 Mbps</td></tr><tr><td><strong>CPU 开销</strong></td><td>极低（仅内存拷贝）</td><td>较高（字节处理 + 中断）</td></tr><tr><td><strong>实时性影响</strong></td><td>几乎无影响</td><td>轮询发送会阻塞；中断发送占用 ISR 时间</td></tr><tr><td><strong>多路输出</strong></td><td>原生支持多通道 + 多虚拟终端</td><td>需要多个 UART 外设</td></tr><tr><td><strong>ISR 安全性</strong></td><td>✅ 可在中断中直接调用</td><td>❌ 中断中调用易引发重入问题</td></tr><tr><td><strong>量产保留</strong></td><td>可保留代码，无硬件成本</td><td>引脚未引出即失效</td></tr></tbody></table><hr><h2><span id="五-工程移植keil">五、工程移植（Keil）</span></h2><h3><span id="51-获取源码">5.1 获取源码</span></h3><p>官方仓库：<a href="https://github.com/SEGGERMicro/RTT">https://github.com/SEGGERMicro/RTT</a></p><h3><span id="52-加入工程">5.2 加入工程</span></h3><p>将 GitHub 下载的软件包加入工程，需要关注的文件结构：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">RTT/</span><br><span class="line">├── SEGGER_RTT.c              ← 核心引擎（必加）</span><br><span class="line">├── SEGGER_RTT.h              ← 调用接口</span><br><span class="line">├── SEGGER_RTT_ASM_ARMv7M.S   ← ARMv7M/ARMv8M 汇编优化（可选）</span><br><span class="line">├── SEGGER_RTT_Printf.c       ← 简化版 printf 实现（不支持 %f 浮点数）</span><br><span class="line">└── Syscalls/</span><br><span class="line">    └── SEGGER_RTT_Syscalls_*.c  ← 各工具链 printf 重定向</span><br><span class="line">Config/</span><br><span class="line">└── SEGGER_RTT_Conf.h         ← 配置文件（建议复制到工程配置目录）</span><br></pre></td></tr></table></figure><p><img src="/images/J-Link%20RTT%20Viewer%20%E6%97%A5%E5%BF%97%E7%B3%BB%E7%BB%9F/6.png"></p><h3><span id="53-初始化与打印">5.3 初始化与打印</span></h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;SEGGER_RTT.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="title function_">main</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">    <span class="comment">// ... HAL_Init()、SystemClock_Config() 之后</span></span><br><span class="line">    SEGGER_RTT_Init();</span><br><span class="line">    SEGGER_RTT_printf(<span class="number">0</span>, <span class="string">&quot;hello..\r\n&quot;</span>);   <span class="comment">// 通道 0 = 默认终端</span></span><br><span class="line">    <span class="keyword">while</span> (<span class="number">1</span>) &#123;</span><br><span class="line">        <span class="comment">// ...</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>⚠️ <code>SEGGER_RTT_printf</code> 是简化实现，<strong>不支持 <code>%f</code> 浮点格式</strong>。如果只需裸文本日志，它够用且体积小、速度快。</p><p>✅ <strong>需要打印浮点数时，推荐用 §5.4 的 <code>fputc</code> 重映射方案</strong>——重映射后标准 <code>printf</code> 走的是编译器 C 库，<strong>原生支持 <code>%f / %e / %g</code></strong>，示例见下。ISR 内为保实时性，仍建议用 <code>SEGGER_RTT_Write</code> 写原始数据，浮点格式化放到主循环做。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// 方案 A：重映射后，标准 printf 直接支持 %f（推荐用于应用层代码）</span></span><br><span class="line"><span class="type">float</span> temperature = <span class="number">36.6f</span>;</span><br><span class="line"><span class="type">double</span> voltage   = <span class="number">3.1415926</span>;</span><br><span class="line"><span class="built_in">printf</span>(<span class="string">&quot;temp=%.2f C, v=%.4f V\r\n&quot;</span>, temperature, voltage);</span><br><span class="line"></span><br><span class="line"><span class="comment">// 方案 B：不想引入完整 printf，可先用 sprintf 格式化到栈缓冲，再交给 RTT 输出</span></span><br><span class="line"><span class="type">char</span> buf[<span class="number">64</span>];</span><br><span class="line"><span class="built_in">sprintf</span>(buf, <span class="string">&quot;temp=%.2f\r\n&quot;</span>, temperature);</span><br><span class="line">SEGGER_RTT_WriteString(<span class="number">0</span>, buf);</span><br></pre></td></tr></table></figure><h3><span id="54-串口重映射printf-重定向">5.4 串口重映射（printf 重定向）</span></h3><p>为了让标准 <code>printf</code> 直接走 RTT，需要做半主机禁用 + <code>fputc</code> 重映射。</p><blockquote><p><strong>重映射后的 <code>printf</code> 支持 <code>%f</code> 浮点数打印</strong></p><p>这里要特别注意一个常见误区：很多人以为”RTT 不支持浮点打印”，其实<strong>要看用哪个接口</strong>：</p><ul><li><p><code>SEGGER_RTT_printf()</code> 是 SEGGER 自带的<strong>简化版实现</strong>，<strong>不支持 <code>%f</code></strong>，遇到浮点格式会原样输出格式串或乱码；</p></li><li><p>而通过本节 <code>fputc</code> 重映射走的是<strong>编译器标准库里的 <code>printf</code></strong>（无论是 MicroLIB 还是标准 C 库），<strong>完整支持所有格式符，包括 <code>%f</code>、<code>%e</code>、<code>%g</code> 浮点数打印</strong>。</p></li></ul><p>换句话说，<strong>只要做了 <code>fputc</code> 重定向，业务代码里直接写 <code>printf(&quot;temp=%.2f\r\n&quot;, 36.6);</code> 就能正常输出浮点</strong>——代价是标准 <code>printf</code> 的代码体积比 <code>SEGGER_RTT_printf</code> 大一些，实时性要求极高的 ISR 内仍建议用 <code>SEGGER_RTT_Write</code> 写原始数据。</p></blockquote><blockquote><p><strong>为什么要禁用半主机（Semihosting）？</strong></p><p>Keil 不使用 MicroLIB 时，标准 <code>printf</code> 默认走<strong>半主机模式</strong>——通过调试器陷入（breakpoint trap）让 CPU 暂停，由调试器代为处理 I&#x2F;O。这会<strong>直接 halt 目标 MCU</strong>，在实时系统中是灾难性的。必须禁用半主机，并重新实现 <code>fputc</code> 将其重定向到 RTT。</p></blockquote><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">ifdef</span> __MICROLIB</span></span><br><span class="line">    <span class="comment">// 使用 MicroLIB 时，printf 直接通过 fputc 输出，无需额外处理</span></span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">    <span class="comment">// 不使用 MicroLIB 时，必须禁用半主机模式</span></span><br><span class="line">    <span class="meta">#<span class="keyword">if</span> defined (__CC_ARM) <span class="comment">// Arm Compiler 5</span></span></span><br><span class="line">        <span class="meta">#<span class="keyword">pragma</span> import(__use_no_semihosting)</span></span><br><span class="line">        <span class="class"><span class="keyword">struct</span> __<span class="title">FILE</span> &#123;</span> <span class="type">int</span> handle; &#125;;</span><br><span class="line">        FILE __stdout;</span><br><span class="line">        <span class="type">void</span> _sys_exit(<span class="type">int</span> x) &#123; x = x; &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">#<span class="keyword">elif</span> defined (__ARMCC_VERSION) &amp;&amp; (__ARMCC_VERSION &gt;= 6010050) <span class="comment">// Arm Compiler 6</span></span></span><br><span class="line">        __asm(<span class="string">&quot;.global __use_no_semihosting\n\t&quot;</span>);</span><br><span class="line">        FILE __stdout;</span><br><span class="line">        <span class="type">void</span> _sys_exit(<span class="type">int</span> x) &#123; x = x; &#125;</span><br><span class="line">    <span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// 无论 MicroLIB 还是标准库，最终都会调用这个 fputc</span></span><br><span class="line"><span class="type">int</span> <span class="title function_">fputc</span><span class="params">(<span class="type">int</span> ch, FILE *f)</span></span><br><span class="line">&#123;</span><br><span class="line">    SEGGER_RTT_PutChar(<span class="number">0</span>, (<span class="type">char</span>)ch);  <span class="comment">// 通道 0 = 默认终端</span></span><br><span class="line">    <span class="keyword">return</span> ch;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p>📌 AC6 用 <code>__asm</code> 内嵌全局符号 <code>.global __use_no_semihosting</code> 来禁用半主机，否则链接时会报 <code>_write</code>、<code>_read</code> 等符号未定义。</p></blockquote><hr><h2><span id="六-进阶导入-ulog-组件实现带颜色-等级的日志">六、进阶：导入 uLog 组件，实现带颜色、等级的日志</span></h2><p>单纯 <code>SEGGER_RTT_printf</code> 只能打裸文本。引入 <strong>uLog</strong>（RT-Thread 的微型日志组件，μ &#x3D; 微）可以实现：</p><ul><li>✅ <strong>5 级日志</strong>：<code>ASSERT / ERROR / WARNING / INFO / DEBUG</code></li><li>✅ <strong>ANSI 颜色输出</strong>：不同级别自动上色（红&#x2F;黄&#x2F;绿&#x2F;青），RTT Viewer 原生解释</li><li>✅ <strong>标签 + 时间戳</strong>：每行列明来源模块和时间</li><li>✅ <strong>运行时过滤</strong>：可按级别、标签、关键字动态过滤</li><li>✅ <strong>异步输出</strong>：专门线程负责刷日志，主业务零阻塞</li></ul><h3><span id="61-配置rtconfigh-示例">6.1 配置（<code>rtconfig.h</code> 示例）</span></h3><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/* Utilities */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> RT_USING_ULOG</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ULOG_OUTPUT_LVL_D</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ULOG_OUTPUT_LVL        7</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ULOG_ASSERT_ENABLE</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ULOG_LINE_BUF_SIZE     128</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* log format */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ULOG_USING_COLOR           <span class="comment">// 颜色</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ULOG_OUTPUT_TIME           <span class="comment">// 时间</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ULOG_OUTPUT_LEVEL          <span class="comment">// 级别</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ULOG_OUTPUT_TAG            <span class="comment">// 标签</span></span></span><br><span class="line"><span class="comment">/* end of log format */</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ULOG_BACKEND_USING_CONSOLE <span class="comment">// 控制台后端</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ULOG_USING_FILTER          <span class="comment">// 运行时过滤</span></span></span><br><span class="line"><span class="comment">/* end of Utilities */</span></span><br></pre></td></tr></table></figure><p>uLog 内部用 <code>CSI_START</code> &#x2F; <code>CSI_END</code> 包裹 ANSI 颜色码（如 <code>\033[31m</code> 红色、<code>\033[32m</code> 绿色），RTT Viewer 直接渲染成彩色行，日志可读性质实现飞跃。</p><p><em>图：uLog 输出的彩色分级日志，RTT Viewer 原生渲染 ANSI 颜色码。</em></p><p><img src="/images/J-Link%20RTT%20Viewer%20%E6%97%A5%E5%BF%97%E7%B3%BB%E7%BB%9F/7.png"></p><hr><h2><span id="七-rtt-server-xshell远程日志交互">七、RTT Server + Xshell：远程日志交互</span></h2><h3><span id="71-原理">7.1 原理</span></h3><p>J-Link 软件在本地启动一个 <strong>Telnet 服务</strong>（默认 <code>127.0.0.1:19021</code>），任何第三方 Telnet 客户端都能接入读取 RTT 数据。该通道是”类 Telnet”的——纯可打印字符完全兼容，原始字节按裸字节解释。</p><blockquote><p><strong>触发条件</strong>：只要 <strong>J-Link 处于激活工作状态</strong>，该 Telnet 服务就会自动启动——例如 Keil&#x2F;IAR 进入调试模式，或 J-Link RTT Viewer 已成功连接目标芯片。</p></blockquote><p><em>图：RTT Telnet 路径。</em></p><p><img src="/images/J-Link%20RTT%20Viewer%20%E6%97%A5%E5%BF%97%E7%B3%BB%E7%BB%9F/2.png"></p><h3><span id="72-xshell-配置">7.2 Xshell 配置</span></h3><p>新建会话 → 协议选 <strong>TELNET</strong> → 主机 <code>127.0.0.1</code> → 端口 <code>19021</code> → 建议勾选”连接异常关闭时自动重新连接”。</p><img src="/images/J-Link%20RTT%20Viewer%20日志系统/J-Link%20RTT%20Viewer%20日志系统-3.png" style="width: 800px;"><h3><span id="73-日志记录">7.3 日志记录</span></h3><p>Xshell 左侧菜单”日志记录” → 设置保存文件路径与时间戳格式 → 重新连接即可把全部 RTT 输出落盘，方便事后追溯。</p><blockquote><p>💡 这个方案对<strong>燃气表、烟感等现场调试</strong>特别实用：设备只留 SWD 口，笔记本接 J-Link + Xshell，既能实时看彩色日志，又能存档，还能键盘下发测试命令，一套顶 UART 的三套活。</p></blockquote><blockquote><p>⚠️ <strong>多客户端互斥</strong>：RTT Telnet 通道同一时刻只能被一个客户端占用。如果 RTT Viewer 已经连着，Xshell 可能连不上；反之亦然。需要断开一个再连另一个。</p><p>⚠️ <strong>ANSI 转义码清洗</strong>：Xshell 的日志记录会把所有 ANSI 颜色码也写入文件。后续用文本工具分析时，可先清洗：<code>sed -r &#39;s/\x1B\[[0-9;]*m//g&#39; log.txt &gt; clean.txt</code></p></blockquote><p><em>图：Xshell 连接 RTT Telnet 通道后的日志输出效果。</em></p><p><img src="/images/J-Link%20RTT%20Viewer%20%E6%97%A5%E5%BF%97%E7%B3%BB%E7%BB%9F/1.png"></p><hr><h2><span id="八-工程落地注意事项踩坑总结">八、工程落地注意事项（踩坑总结）</span></h2><ol><li><p><strong>初始化顺序</strong>：<code>SEGGER_RTT_Init()</code> 必须在 <code>HAL_Init()</code>、<code>SystemClock_Config()</code> 之后、任何 RTT 调用之前。极端做法是用 <code>__attribute__((constructor))</code> 让它在 <code>main()</code> 之前自动执行。</p></li><li><p><strong>控制块找不到时</strong>：通过 map 文件定位 <code>_SEGGER_RTT</code> 符号地址，在 RTT Viewer 的 Address 栏手动填写；或者检查是否被链接器优化掉了（可在 <code>SEGGER_RTT_Conf.h</code> 中确认缓冲区不被优化）。</p></li><li><p><strong>ISR 里慎用 <code>printf</code></strong>：格式化函数内部可能有等待逻辑；正确做法是 ISR 里只调用 <code>SEGGER_RTT_Write</code> 写入原始数据，主循环里统一格式化输出。</p></li><li><p><strong>缓冲区大小按场景调</strong>：高频日志把 <code>BUFFER_SIZE_UP</code> 设 2048~4096；低功耗小 RAM 设备可降到 256；多任务日志启用多缓冲区分级。</p></li><li><p><strong>非阻塞模式会丢数据</strong>：高频循环写入时 1KB 默认缓冲很快填满，要心中有数——非阻塞模式下丢数据是无声的，不会报错。</p></li><li><p><strong>AC6 编译</strong>：必须用 <code>__asm(&quot;.global __use_no_semihosting\n\t&quot;)</code> 禁用半主机，否则链接失败。</p></li><li><p><strong>多虚拟终端</strong>：通道 0 可在 RTT Viewer 里虚拟成 Terminal 0~15 多标签页，用 <code>SEGGER_RTT_SetTerminal(n)</code> 切换，实现 stdout &#x2F; stderr &#x2F; debug 分流；不同 Terminal 可用 ANSI 颜色码区分。</p></li><li><p><strong>目标必须在运行态</strong>：RTT Viewer 连接前 MCU 不能处于 halt&#x2F;断点状态，否则会显示空白或报错。勾选 <strong>Force Go on Connect</strong> 可让 J-Link 连上后自动恢复运行。</p></li></ol><hr><h2><span id="九-快速-checklist">九、快速 Checklist</span></h2><p>读者照着做时最容易忘的步骤，部署前逐项核对：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">☐ J-Link 驱动已安装（≥ V6.30，RTT 需要较新版本）</span><br><span class="line">☐ SEGGER_RTT.c 和 SEGGER_RTT_Conf.h 已加入工程</span><br><span class="line">☐ 头文件路径已添加（RTT/ 和 Config/ 两个目录）</span><br><span class="line">☐ SEGGER_RTT_Init() 在 main 早期调用</span><br><span class="line">☐ Keil 未使用 MicroLIB 时，已禁用半主机 + 重定义 fputc</span><br><span class="line">☐ RTT Viewer 连接时目标 MCU 在运行态（非断点 halt）</span><br><span class="line">☐ 缓冲区大小按日志频率调整（默认 1KB 可能不够）</span><br><span class="line">☐ 非阻塞模式下确认可接受的丢数据场景</span><br><span class="line">☐ 需要浮点打印时改用 sprintf + SEGGER_RTT_Write</span><br><span class="line">☐ Xshell 连不上时确认没有其他客户端占用 19021 端口</span><br></pre></td></tr></table></figure><hr><h2><span id="十-适用场景总结">十、适用场景总结</span></h2><p>RTT 特别适合：</p><ul><li>🔋 <strong>低成本设备</strong>（燃气表、水表、烟感）：引脚紧张，不预留 UART，SWD 口是唯一调试通道</li><li>🚀 <strong>高频日志</strong>：传感器数据流、性能剖析、事件追踪，1 MB&#x2F;s 吞吐轻松应对</li><li>💬 <strong>交互式调试</strong>：需要键盘输入下发命令（替代串口 shell）</li><li>🔒 <strong>量产现场</strong>：SWD 口保留即可，无需额外硬件，日志代码可常驻</li><li>📊 <strong>多路分流</strong>：日志、追踪、命令走不同通道互不干扰</li><li>⚡ <strong>实时性敏感</strong>：中断处理、电机控制、无线通信中安全调用，不阻塞业务</li></ul><blockquote><p>只要能用 J-Link 下载程序，就能用 RTT 输出调试信息——这是它对小型开发板最友好的地方。从原型验证到量产部署，一条调试链打通到底。</p></blockquote><hr><h3><span id="参考资料">📎 参考资料</span></h3><ul><li>SEGGER 官方 RTT 页面：<a href="https://www.segger.com/products/debug-probes/j-link/technology/about-real-time-transfer/">https://www.segger.com/products/debug-probes/j-link/technology/about-real-time-transfer/</a></li><li>SEGGER RTT Wiki：<a href="https://kb.segger.com/RTT">https://kb.segger.com/RTT</a></li><li>RTT TELNET 通道说明：<a href="https://kb.segger.com/J-Link_RTT_TELNET_Channel">https://kb.segger.com/J-Link_RTT_TELNET_Channel</a></li><li>GitHub 源码：<a href="https://github.com/SEGGERMicro/RTT">https://github.com/SEGGERMicro/RTT</a></li><li>uLog 组件文档：<a href="https://rt-thread.github.io/rt-thread/page_component_ulog.html">https://rt-thread.github.io/rt-thread/page_component_ulog.html</a></li></ul>]]>
    </content>
    <id>https://blog.j182010.top/2026/06/19/J-Link%20RTT%20Viewer%20%E6%97%A5%E5%BF%97%E7%B3%BB%E7%BB%9F/</id>
    <link href="https://blog.j182010.top/2026/06/19/J-Link%20RTT%20Viewer%20%E6%97%A5%E5%BF%97%E7%B3%BB%E7%BB%9F/"/>
    <published>2026-06-18T16:00:00.000Z</published>
    <summary>
      <![CDATA[<div class="toc">

<!-- toc -->

<ul>
<li><a href="#%E4%B8%80-%E8%83%8C%E6%99%AF%E4%B8%B2%E5%8F%A3%E6%97%A5%E5%BF%97%E7%9A%84%E7%97%9B%E7%82]]>
    </summary>
    <title>J-Link RTT Viewer 日志系统</title>
    <updated>2026-09-05T05:08:17.387Z</updated>
  </entry>
  <entry>
    <author>
      <name>John Doe</name>
    </author>
    <category term="工具" scheme="https://blog.j182010.top/categories/%E5%B7%A5%E5%85%B7/"/>
    <category term="Tools" scheme="https://blog.j182010.top/tags/Tools/"/>
    <content>
      <![CDATA[<!-- ## 即开即用 --><ul class="doc-links">  <li>    <a class="doc-card" href="/downloads/doc/PCP协议工具.html" target="_blank">      <span class="doc-icon">P</span>      <span class="doc-info">        <span class="doc-title">PCP协议工具</span>        <span class="doc-desc">电信AEP升级平台</span>      </span>    </a>  </li>  <li>    <a class="doc-card" href="/downloads/doc/随机二进制固件生成器.html" target="_blank">      <span class="doc-icon">S</span>      <span class="doc-info">        <span class="doc-title">随机二进制固件生成器</span>        <span class="doc-desc">模拟固件生成</span>      </span>    </a>  </li>  <li>    <a class="doc-card" href="/downloads/doc/emoji.html" target="_blank">      <span class="doc-icon">🏰</span>      <span class="doc-info">        <span class="doc-title">Unicode Emoji 表情符号</span>        <span class="doc-desc">常见符号，点击复制</span>      </span>    </a>  </li>  <li>    <a class="doc-card" href="/downloads/doc/ASCII表.jpg" target="_blank">      <span class="doc-icon">⌨</span>      <span class="doc-info">        <span class="doc-title">ASCII 码表</span>        <span class="doc-desc">0-127 完整对照表，点击查看大图</span>      </span>    </a>  </li>  <li>    <a class="doc-card" href="/downloads/doc/三线圈电机换向原理动画.html" target="_blank">      <span class="doc-icon">🧲</span>      <span class="doc-info">        <span class="doc-title">三线圈电机换向原理</span>        <span class="doc-desc">有刷电机换向示意动画</span>      </span>    </a>  </li>  <li>    <a class="doc-card" href="/downloads/doc/字节格式转换.html" target="_blank">      <span class="doc-icon">0x</span>      <span class="doc-info">        <span class="doc-title">字节格式转换</span>        <span class="doc-desc">HEX 无空格/空格/0x 三种格式互转</span>      </span>    </a>  </li>  <!-- 下面是新增的外部链接 ↓↓↓ -->  <!-- <li>    <a class="doc-card" href="https://test.j182010.top/" target="_blank" rel="noopener noreferrer">      <span class="doc-icon">S</span>      <span class="doc-info">        <span class="doc-title">事件驱动状态机</span>        <span class="doc-desc">基于燃气表 OTA 升级模块的架构实践/span>      </span>    </a>  </li> --></ul>]]>
    </content>
    <id>https://blog.j182010.top/2026/06/19/%E5%9C%A8%E7%BA%BF%E5%B7%A5%E5%85%B7/</id>
    <link href="https://blog.j182010.top/2026/06/19/%E5%9C%A8%E7%BA%BF%E5%B7%A5%E5%85%B7/"/>
    <published>2026-06-18T16:00:00.000Z</published>
    <summary>
      <![CDATA[<!-- ## 即开即用 -->

<ul class="doc-links">
  <li>
    <a class="doc-card" href="/downloads/doc/PCP协议工具.html" target="_blank">
      <span clas]]>
    </summary>
    <title>在线工具</title>
    <updated>2026-09-10T10:53:50.756Z</updated>
  </entry>
  <entry>
    <author>
      <name>John Doe</name>
    </author>
    <category term="工具" scheme="https://blog.j182010.top/categories/%E5%B7%A5%E5%85%B7/"/>
    <category term="UART" scheme="https://blog.j182010.top/tags/UART/"/>
    <category term="FT4232" scheme="https://blog.j182010.top/tags/FT4232/"/>
    <content>
      <![CDATA[<div class="toc"><!-- toc --><ul><li><a href="#%E4%B8%80-%E5%BC%80%E5%8F%91%E7%9A%84%E6%A1%8C%E9%9D%A2%E4%B8%BA%E4%BB%80%E4%B9%88%E6%80%BB%E6%98%AF%E8%BF%99%E4%B9%88%E4%B9%B1">一、开发的桌面为什么总是这么乱</a></li><li><a href="#%E4%BA%8C-%E8%87%AA%E5%88%B6ft4232h-%E5%9B%9B%E8%B7%AF%E4%B8%B2%E5%8F%A3%E4%BC%98%E5%8A%BF">二、自制FT4232H 四路串口优势</a><ul><li><a href="#%E9%9B%86%E6%88%90%E7%BA%BF%E4%B8%8E%E7%9B%91%E5%90%AC%E4%B8%80%E4%B8%AA%E7%AA%97%E5%8F%A3%E7%9C%8B%E5%8F%8C%E5%90%91%E6%8A%A5%E6%96%87">🌟 集成线与监听（一个窗口看双向报文）</a></li><li><a href="#31-%E4%BC%A0%E7%BB%9F%E5%81%9A%E6%B3%95%E7%9A%84%E9%BA%BB%E7%83%A6">3.1 传统做法的麻烦</a></li><li><a href="#32-%E6%9C%AC%E5%B7%A5%E5%85%B7%E7%9A%84%E7%9B%91%E5%90%AC%E5%8E%9F%E7%90%86">3.2 本工具的监听原理</a></li></ul></li><li><a href="#%E5%9B%9B-%E7%A1%AC%E4%BB%B6%E7%AE%80%E4%BB%8B">四、硬件简介</a></li><li><a href="#%E4%BA%94-%E5%AE%9E%E7%89%A9%E6%95%88%E6%9E%9C">五、实物效果</a></li></ul><!-- tocstop --></div><h2><span id="一-开发的桌面为什么总是这么乱">一、开发的桌面为什么总是这么乱</span></h2><p>做嵌入式开发，尤其是经常跟通信模组（4G Cat.1、WiFi、蓝牙、GPS）打交道的同学，桌面上永远是这一幕：</p><ul><li>一个串口接模组 <strong>AT 指令口</strong></li><li>一个接 <strong>MCU 日志口</strong></li><li>一个接 <strong>传感器 &#x2F; 调试口</strong></li><li>……</li></ul><p><img src="/images/自制%20FT4232H%20四路串口调试器/0.jpg" style="width:500px;"><br><br><strong>USB 口被一堆 CH340、CP2102 小板占满，线缠成一团，还动不动掉盘、插拔一次 COM 号就变。</strong></p><h2><span id="二-自制ft4232h-四路串口优势">二、自制FT4232H 四路串口优势</span></h2><ul><li>一根 Type-C 手机充电线&#x2F;USB鼠标线 搞定</li><li>全贴片（SMT），底板平整无焊盘，避免管脚误触发</li><li>配 EEPROM + Serial Number，端口顺序永久固定</li><li>集成两路二极管线与，一个助手同时看 TX+RX</li></ul><h3><span id="集成线与监听一个窗口看双向报文">🌟 集成线与监听（一个窗口看双向报文）</span></h3><p>调试通信模组（MCU ↔ 模组）时，想同时看 TX 和 RX 报文，要么开两个串口助手手动拼时序，要么搬出逻辑分析仪 —— 都太重了。</p><h3><span id="31-传统做法的麻烦">3.1 传统做法的麻烦</span></h3><p>调试 MCU ↔ 通信模组时，链路是：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">MCU:TX ──── 模组:RX</span><br><span class="line">MCU:RX ──── 模组:TX</span><br></pre></td></tr></table></figure><p>想完整分析一帧协议（MCU 发了什么、模组回了什么），传统方案：</p><ul><li><strong>方案 A</strong>：用两个串口分别抓 MCU 和模组 → 两个串口助手<strong>时间戳难对齐</strong>，还得手动拼</li><li><strong>方案 B</strong>：搬逻辑分析仪 → 太重，还得额外软件</li></ul><h3><span id="32-本工具的监听原理">3.2 本工具的监听原理</span></h3><h2><span id="带2路-3pin-监听接口用两个二极管把-mcu模组-和-模组mcu-两条线合并成一个-rx">带2路 <strong>3Pin 监听接口</strong>，用<strong>两个二极管把 MCU→模组 和 模组→MCU 两条线”合并”成一个 RX</strong>：<br><img src="/images/自制%20FT4232H%20四路串口调试器/1.png" style="width:300px;"><br></span></h2><h2><span id="四-硬件简介">四、硬件简介</span></h2><p><img src="/images/自制%20FT4232H%20四路串口调试器/SCH.png" style="width:1000px;"><br></p><p><strong>主要特性速览：</strong></p><ul><li>✅ 4 路独立 UART（A&#x2F;B&#x2F;C&#x2F;D），每路引出 <strong>VOUT &#x2F; TX &#x2F; RX &#x2F; GND</strong></li><li>✅ 每路<strong>电平转换</strong>，兼容  3.3 &#x2F; 5V 目标板</li><li>✅ 每路<strong>流量 LED 指示</strong>（74HC595 驱动）</li><li>✅ 带2路 <strong>3Pin 通信模组收发监听接口</strong>（二极管线与）</li><li>✅ USB Type-C 母座 + PH2.0 鼠笼线（兼容鼠标线）两种连接方式</li><li>✅ <strong>全贴片、单面布局，底板无焊盘</strong></li></ul><p><strong>关键元件表：</strong></p><table><thead><tr><th>位号</th><th>型号</th><th>作用</th></tr></thead><tbody><tr><td>U1</td><td>FT4232HL-Reel (LQFP-64)</td><td>主芯片，出 4 个 COM</td></tr><tr><td>U2</td><td>TXS0108E</td><td>8 位双向电平转换</td></tr><tr><td>U4</td><td>AMS1117-3.3 兼容</td><td>3.3V LDO</td></tr><tr><td>U5</td><td>93LC56B</td><td>配置 EEPROM（固定端口名）</td></tr><tr><td>U6</td><td>74HC595D</td><td>LED 流量灯驱动</td></tr><tr><td>X1</td><td>12MHz 3225</td><td>主时钟</td></tr><tr><td>D1&#x2F;D2…</td><td>SOT-23 开关二极管</td><td>监听”线与”</td></tr></tbody></table><hr><h2><span id="五-实物效果">五、实物效果</span></h2><p><img src="/images/自制%20FT4232H%20四路串口调试器/2.png" style="width:600px;"><br></p><p><img src="/images/自制%20FT4232H%20四路串口调试器/3.png" style="width:600px;"><br></p><p><img src="/images/自制%20FT4232H%20四路串口调试器/4.png" style="width:600px;"><br></p>]]>
    </content>
    <id>https://blog.j182010.top/2026/06/19/%E8%87%AA%E5%88%B6%20FT4232H%20%E5%9B%9B%E8%B7%AF%E4%B8%B2%E5%8F%A3%E8%B0%83%E8%AF%95%E5%99%A8/</id>
    <link href="https://blog.j182010.top/2026/06/19/%E8%87%AA%E5%88%B6%20FT4232H%20%E5%9B%9B%E8%B7%AF%E4%B8%B2%E5%8F%A3%E8%B0%83%E8%AF%95%E5%99%A8/"/>
    <published>2026-06-18T16:00:00.000Z</published>
    <summary>
      <![CDATA[<div class="toc">

<!-- toc -->

<ul>
<li><a href="#%E4%B8%80-%E5%BC%80%E5%8F%91%E7%9A%84%E6%A1%8C%E9%9D%A2%E4%B8%BA%E4%BB%80%E4%B9%88%E6%80]]>
    </summary>
    <title>自制 FT4232H 四路串口调试器</title>
    <updated>2026-09-10T12:16:56.189Z</updated>
  </entry>
  <entry>
    <author>
      <name>John Doe</name>
    </author>
    <content>
      <![CDATA[<div class="toc"><!-- toc --><ul><li><a href="#%E4%B8%80-%E5%89%8D%E8%A8%80">一、前言</a><ul><li><a href="#1-%E7%97%9B%E7%82%B9%E8%AF%B4%E6%98%8E">1. 痛点说明</a></li><li><a href="#2-%E6%96%B9%E6%A1%88%E4%BD%9C%E7%94%A8">2. 方案作用</a></li><li><a href="#3-%E7%BC%96%E8%AF%91%E5%99%A8%E9%80%82%E9%85%8D%E8%8C%83%E5%9B%B4">3. 编译器适配范围</a></li><li><a href="#4-%E4%BD%BF%E7%94%A8%E5%89%8D%E6%8F%90">4. 使用前提</a></li></ul></li><li><a href="#%E4%BA%8C-%E5%AE%8C%E6%95%B4%E5%8F%AF%E7%9B%B4%E6%8E%A5%E5%B7%A5%E7%A8%8B%E4%BB%A3%E7%A0%81">二、完整可直接工程代码</a></li><li><a href="#%E4%B8%89-%E4%BB%A3%E7%A0%81%E5%88%86%E5%B1%82%E9%80%BB%E8%BE%91%E8%AF%B4%E6%98%8E">三、代码分层逻辑说明</a><ul><li><a href="#1-%E6%B1%87%E7%BC%96%E5%B1%82%E6%A1%88%E5%8F%91%E7%8E%B0%E5%9C%BA%E4%BF%9D%E6%8A%A4hardfault_handler">1. 汇编层：案发现场保护（HardFault_Handler）</a></li><li><a href="#2-c%E8%AF%AD%E8%A8%80%E5%B1%82%E6%A1%88%E5%8F%91%E7%8E%B0%E5%9C%BA%E8%A7%A3%E6%9E%90hard_fault_handler_c">2. C语言层：案发现场解析（hard_fault_handler_c）</a></li></ul></li><li><a href="#%E5%9B%9B-%E6%A0%B8%E5%BF%83%E5%BA%95%E5%B1%82%E5%8E%9F%E7%90%86%E5%BF%85%E6%87%82%E7%9F%A5%E8%AF%86%E7%82%B9">四、核心底层原理（必懂知识点）</a><ul><li><a href="#1-tst-lr-4-%E6%B1%87%E7%BC%96%E6%8C%87%E4%BB%A4%E5%8E%9F%E7%90%86">1. TST LR, #4 汇编指令原理</a></li><li><a href="#2-r0%E5%AF%84%E5%AD%98%E5%99%A8%E4%BC%A0%E5%8F%82%E8%A7%84%E5%88%99arm-atpcs%E8%B0%83%E7%94%A8%E8%A7%84%E8%8C%83">2. R0寄存器传参规则（ARM ATPCS调用规范）</a></li><li><a href="#3-%E6%A0%88%E5%B8%A7%E5%AF%84%E5%AD%98%E5%99%A8%E5%81%8F%E7%A7%BB%E8%A7%84%E5%88%99">3. 栈帧寄存器偏移规则</a></li></ul></li><li><a href="#%E4%BA%94-%E6%A0%B9%E6%8D%AEpc%E5%9C%B0%E5%9D%80%E5%AE%9A%E4%BD%8D%E5%B4%A9%E6%BA%83%E4%BB%A3%E7%A0%81%E4%B8%A4%E7%A7%8D%E6%96%B9%E6%B3%95">五、根据PC地址定位崩溃代码（两种方法）</a><ul><li><a href="#%E6%96%B9%E6%B3%951keil-mdk-%E5%9C%A8%E7%BA%BF%E4%BB%BF%E7%9C%9F%E5%AE%9A%E4%BD%8D%E6%9C%80%E7%9B%B4%E8%A7%82">方法1：Keil MDK 在线仿真定位（最直观）</a></li><li><a href="#%E6%96%B9%E6%B3%952gcc-addr2line-%E8%84%B1%E6%9C%BA%E5%AE%9A%E4%BD%8D%E6%97%A0%E4%BB%BF%E7%9C%9F%E5%99%A8%E4%B9%9F%E8%83%BD%E7%94%A8">方法2：GCC addr2line 脱机定位（无仿真器也能用）</a></li></ul></li><li><a href="#%E5%85%AD-%E8%80%81%E6%97%A7ac5%E7%BC%96%E8%AF%91%E5%99%A8%E9%80%82%E9%85%8D%E8%AF%B4%E6%98%8E">六、老旧AC5编译器适配说明</a></li><li><a href="#%E4%B8%83-%E5%B8%B8%E8%A7%81hardfault%E6%95%85%E9%9A%9C%E6%A0%B9%E6%BA%90%E6%B1%87%E6%80%BB">七、常见HardFault故障根源汇总</a></li><li><a href="#%E5%85%AB-%E4%BD%BF%E7%94%A8%E6%B3%A8%E6%84%8F%E4%BA%8B%E9%A1%B9">八、使用注意事项</a></li></ul><!-- tocstop --></div><h2><span id="一-前言">一、前言</span></h2><h3><span id="1-痛点说明">1. 痛点说明</span></h3><p>STM32 嵌入式开发中，空指针访问、数组越界、内存踩踏、非法地址访问等问题，都会触发<strong>HardFault硬件硬故障</strong>。</p><p>工程启动文件 <code>startup_stm32xxx.s</code> 默认自带空的 HardFault_Handler 死循环，故障发生后程序直接卡死，无任何报错信息，无法定位崩溃代码行，排查难度极大。</p><h3><span id="2-方案作用">2. 方案作用</span></h3><p>重写 HardFault 中断服务函数，自动抓取故障发生时刻CPU寄存器、栈帧、崩溃指令地址，通过串口打印完整故障现场，<strong>无需在线仿真，脱机也能精准定位死机代码行</strong>。</p><h3><span id="3-编译器适配范围">3. 编译器适配范围</span></h3><ul><li><p><strong>完全兼容</strong>：ARM GCC、Keil MDK AC6、STM32CubeIDE（主流编译器，本文代码直接复用）</p></li><li><p><strong>兼容修改</strong>：老旧Keil MDK AC5，汇编函数语法需要微调</p></li></ul><h3><span id="4-使用前提">4. 使用前提</span></h3><p>工程已完成<strong>printf串口重定向</strong>，保证串口可以正常输出日志。</p><hr><h2><span id="二-完整可直接工程代码">二、完整可直接工程代码</span></h2><p>可放置于 <code>main.c</code> 文件末尾，或单独新建 <code>debug_fault.c</code> 文件添加至工程。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdio.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;stdint.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief       HardFault故障C层处理函数</span></span><br><span class="line"><span class="comment"> * @param       fault_args: 栈指针地址，保存故障发生时8个内核寄存器</span></span><br><span class="line"><span class="comment"> * @retval      无</span></span><br><span class="line"><span class="comment"> * @note        栈内寄存器固定顺序：R0、R1、R2、R3、R12、LR、PC、xPSR</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">hard_fault_handler_c</span><span class="params">(<span class="type">uint32_t</span> *fault_args)</span> &#123;</span><br><span class="line">    <span class="comment">// 打印完整HardFault故障现场</span></span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;\r\n==================== HardFault 致命错误报告 ====================\r\n&quot;</span>);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;R0  = 0x%08lX\r\n&quot;</span>, fault_args[<span class="number">0</span>]);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;R1  = 0x%08lX\r\n&quot;</span>, fault_args[<span class="number">1</span>]);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;R2  = 0x%08lX\r\n&quot;</span>, fault_args[<span class="number">2</span>]);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;R3  = 0x%08lX\r\n&quot;</span>, fault_args[<span class="number">3</span>]);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;R12 = 0x%08lX\r\n&quot;</span>, fault_args[<span class="number">4</span>]);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;LR  = 0x%08lX (异常发生前函数返回地址)\r\n&quot;</span>, fault_args[<span class="number">5</span>]);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;PC  = 0x%08lX (【核心】崩溃指令所在代码地址)\r\n&quot;</span>, fault_args[<span class="number">6</span>]);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;PSR = 0x%08lX (程序状态寄存器)\r\n&quot;</span>, fault_args[<span class="number">7</span>]);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;================================================================\r\n&quot;</span>);</span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;故障排查提示：使用PC地址可直接定位死机代码行\r\n\r\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">// 死循环锁定故障现场，防止程序继续跑飞</span></span><br><span class="line">    <span class="keyword">while</span> (<span class="number">1</span>)</span><br><span class="line">    &#123;</span><br><span class="line">        <span class="comment">// 可拓展：添加LED闪烁，硬件直观提示设备发生硬故障</span></span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief       HardFault中断服务函数（纯汇编）</span></span><br><span class="line"><span class="comment"> * @note        __attribute__((naked))：编译器不自动生成栈保护、返回指令，纯手写汇编</span></span><br><span class="line"><span class="comment"> *              自动识别当前使用堆栈：主栈MSP / 进程栈PSP</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">__attribute__((naked)) <span class="type">void</span> <span class="title function_">HardFault_Handler</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">    __asm <span class="title function_">volatile</span> <span class="params">(</span></span><br><span class="line"><span class="params">        <span class="string">&quot;TST LR, #4 \n&quot;</span>         <span class="comment">// 检测EXC_RETURN寄存器Bit2位</span></span></span><br><span class="line"><span class="params">        <span class="string">&quot;ITE EQ \n&quot;</span>             <span class="comment">// 条件判断：相等/不相等分支</span></span></span><br><span class="line"><span class="params">        <span class="string">&quot;MRSEQ R0, MSP \n&quot;</span>      <span class="comment">// Bit2=0：故障前使用主堆栈MSP，读取MSP存入R0</span></span></span><br><span class="line"><span class="params">        <span class="string">&quot;MRSNE R0, PSP \n&quot;</span>      <span class="comment">// Bit2=1：故障前使用进程堆栈PSP，读取PSP存入R0</span></span></span><br><span class="line"><span class="params">        <span class="string">&quot;B hard_fault_handler_c \n&quot;</span> <span class="comment">// 跳转到C故障处理函数，R0作为函数入参</span></span></span><br><span class="line"><span class="params">    )</span>;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure><hr><h2><span id="三-代码分层逻辑说明">三、代码分层逻辑说明</span></h2><h3><span id="1-汇编层案发现场保护hardfault_handler">1. 汇编层：案发现场保护（HardFault_Handler）</span></h3><p>异常进入瞬间，CPU会自动压栈8个内核寄存器，第一步核心任务：<strong>判断故障发生时CPU使用的堆栈类型，取出栈顶地址</strong>。</p><h3><span id="2-c语言层案发现场解析hard_fault_handler_c">2. C语言层：案发现场解析（hard_fault_handler_c）</span></h3><p>接收汇编传递的栈指针，按照固定偏移读取栈内保存的寄存器数值，串口打印全部现场信息，其中<strong>PC寄存器地址为定位BUG的核心关键</strong>。</p><hr><h2><span id="四-核心底层原理必懂知识点">四、核心底层原理（必懂知识点）</span></h2><h3><span id="1-tst-lr-4-汇编指令原理">1. TST LR, #4 汇编指令原理</span></h3><ul><li><p>HardFault异常触发后，LR寄存器会被赋值为<strong>EXC_RETURN特殊返回值</strong></p></li><li><p><code>#4</code> 二进制：<code>0100</code>，对应寄存器<strong>Bit2位</strong></p></li><li><p>判断规则：</p><ul><li><p>Bit2 &#x3D; 0：异常发生前，CPU使用<strong>主堆栈 MSP</strong>（内核中断默认堆栈）</p></li><li><p>Bit2 &#x3D; 1：异常发生前，CPU使用<strong>进程堆栈 PSP</strong>（RTOS任务运行时堆栈）</p></li></ul></li></ul><h3><span id="2-r0寄存器传参规则arm-atpcs调用规范">2. R0寄存器传参规则（ARM ATPCS调用规范）</span></h3><p>ARM Cortex-M内核函数调用约定：<strong>函数第一个形参，固定通过R0寄存器传递</strong>。</p><p>汇编中将MSP&#x2F;PSP栈指针存入R0，直接跳转C函数后，<code>uint32_t *fault_args</code> 指针直接接管栈顶地址，无需额外传参。</p><h3><span id="3-栈帧寄存器偏移规则">3. 栈帧寄存器偏移规则</span></h3><p>Cortex-M内核进入异常时，自动向下压栈8个寄存器，数组下标一一对应，固定不变：</p><table><thead><tr><th>数组下标</th><th>寄存器</th><th>作用说明</th></tr></thead><tbody><tr><td>fault_args[0]</td><td>R0</td><td>通用寄存器</td></tr><tr><td>fault_args[1]</td><td>R1</td><td>通用寄存器</td></tr><tr><td>fault_args[2]</td><td>R2</td><td>通用寄存器</td></tr><tr><td>fault_args[3]</td><td>R3</td><td>通用寄存器</td></tr><tr><td>fault_args[4]</td><td>R12</td><td>过程调用临时寄存器</td></tr><tr><td>fault_args[5]</td><td>LR</td><td>异常前函数返回地址</td></tr><tr><td>fault_args[6]</td><td><strong>PC</strong></td><td><strong>崩溃代码指令地址（核心）</strong></td></tr><tr><td>fault_args[7]</td><td>xPSR</td><td>程序状态字寄存器</td></tr></tbody></table><hr><h2><span id="五-根据pc地址定位崩溃代码两种方法">五、根据PC地址定位崩溃代码（两种方法）</span></h2><p>假设串口打印崩溃地址：<code>PC = 0x08001A4C</code></p><h3><span id="方法1keil-mdk-在线仿真定位最直观">方法1：Keil MDK 在线仿真定位（最直观）</span></h3><ol><li><p>进入Keil调试模式</p></li><li><p>顶部菜单栏：<code>View → Disassembly Window</code> 打开反汇编窗口</p></li><li><p>反汇编窗口右键，勾选 <code>Show Code</code> 显示对应C代码</p></li><li><p>地址栏输入串口打印的PC地址，回车，光标直接跳转至崩溃代码行</p></li></ol><h3><span id="方法2gcc-addr2line-脱机定位无仿真器也能用">方法2：GCC addr2line 脱机定位（无仿真器也能用）</span></h3><p>适用场景：STM32CubeIDE、GCC编译器，无仿真器、量产设备死机排查</p><ol><li><p>找到工程编译生成的 <code>.elf</code> 可执行文件</p></li><li><p>打开CMD终端，输入以下命令：</p></li></ol><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">arm-none-eabi-addr2line -e 你的工程文件.elf 0x08001A4C</span><br><span class="line"></span><br></pre></td></tr></table></figure><p>终端直接输出结果：<code>main.c:142</code>，精准告知崩溃文件与代码行数。</p><hr><h2><span id="六-老旧ac5编译器适配说明">六、老旧AC5编译器适配说明</span></h2><p>当前主流开发基本淘汰AC5编译器，若必须使用Keil AC5，汇编中断函数需要修改函数声明，其余代码无需改动：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// AC5 专用写法</span></span><br><span class="line">__asm <span class="type">void</span> <span class="title function_">HardFault_Handler</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">    TST LR, #<span class="number">4</span></span><br><span class="line">    ITE EQ</span><br><span class="line">    MRSEQ R0, MSP</span><br><span class="line">    MRSNE R0, PSP</span><br><span class="line">    B hard_fault_handler_c</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><hr><h2><span id="七-常见hardfault故障根源汇总">七、常见HardFault故障根源汇总</span></h2><ul><li><p>野指针：指针未初始化直接解引用</p></li><li><p>数组越界：访问数组下标超出定义范围</p></li><li><p>栈溢出：局部变量过大、递归死循环导致栈空间耗尽</p></li><li><p>非法地址访问：操作外设未开启时钟、访问保留内存地址</p></li><li><p>RTOS场景：任务堆栈过小，任务运行时栈溢出</p></li></ul><hr><h2><span id="八-使用注意事项">八、使用注意事项</span></h2><ol><li><p>该函数会<strong>覆盖启动文件默认的HardFault中断</strong>，无需修改.s启动文件</p></li><li><p>必须保证printf串口重定向正常，否则无法打印故障日志</p></li><li><p>故障发生后程序进入死循环，上电复位即可恢复</p></li><li><p>可在while死循环内添加LED指示灯，硬件直观提示故障</p></li></ol><blockquote><p>（注：部分内容可能由 AI 生成）</p></blockquote>]]>
    </content>
    <id>https://blog.j182010.top/2026/06/18/%E6%8A%93%E9%AC%BC%E4%BB%A3%E7%A0%81%EF%BC%88%E6%A0%88%E5%9B%9E%E6%BA%AF%EF%BC%89/</id>
    <link href="https://blog.j182010.top/2026/06/18/%E6%8A%93%E9%AC%BC%E4%BB%A3%E7%A0%81%EF%BC%88%E6%A0%88%E5%9B%9E%E6%BA%AF%EF%BC%89/"/>
    <published>2026-06-18T03:12:01.000Z</published>
    <summary>
      <![CDATA[<div class="toc">

<!-- toc -->

<ul>
<li><a href="#%E4%B8%80-%E5%89%8D%E8%A8%80">一、前言</a><ul>
<li><a href="#1-%E7%97%9B%E7%82%B9%E8%AF%B4%E]]>
    </summary>
    <title>抓鬼代码（栈回溯）</title>
    <updated>2026-09-05T07:38:56.993Z</updated>
  </entry>
  <entry>
    <author>
      <name>John Doe</name>
    </author>
    <category term="学习" scheme="https://blog.j182010.top/categories/%E5%AD%A6%E4%B9%A0/"/>
    <category term="OTA" scheme="https://blog.j182010.top/tags/OTA/"/>
    <category term="RTOS" scheme="https://blog.j182010.top/tags/RTOS/"/>
    <id>https://blog.j182010.top/2026/06/04/%E4%BA%8B%E4%BB%B6%E9%A9%B1%E5%8A%A8%E7%8A%B6%E6%80%81%E6%9C%BA%EF%BC%88%E5%AD%A6%E4%B9%A0%E5%9F%B9%E8%AE%AD%EF%BC%89/</id>
    <link href="https://blog.j182010.top/2026/06/04/%E4%BA%8B%E4%BB%B6%E9%A9%B1%E5%8A%A8%E7%8A%B6%E6%80%81%E6%9C%BA%EF%BC%88%E5%AD%A6%E4%B9%A0%E5%9F%B9%E8%AE%AD%EF%BC%89/"/>
    <published>2026-06-03T16:00:00.000Z</published>
    <title>事件驱动状态机（学习培训）</title>
    <updated>2026-09-11T14:15:52.147Z</updated>
  </entry>
  <entry>
    <author>
      <name>John Doe</name>
    </author>
    <category term="说明" scheme="https://blog.j182010.top/categories/%E8%AF%B4%E6%98%8E/"/>
    <category term="modbus" scheme="https://blog.j182010.top/tags/modbus/"/>
    <category term="Tools" scheme="https://blog.j182010.top/tags/Tools/"/>
    <content>
      <![CDATA[<blockquote><p>文档版本：V0.2</p></blockquote><div class="pdf-toolbar" style="display:flex;gap:10px;align-items:center;margin-bottom:14px;flex-wrap:wrap;">  <a href="/downloads/doc/modbus%20tool%20%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E%20V0.2.pdf" target="_blank" rel="noopener" style="display:inline-flex;align-items:center;gap:6px;padding:8px 16px;border-radius:8px;background:#f0f7ff;color:#2563eb !important;text-decoration:none;font-size:13.5px;font-weight:500;transition:all .15s ease;" onmouseover="this.style.background='#dbeafe';this.style.transform='translateY(-1px)'" onmouseout="this.style.background='#f0f7ff';this.style.transform='translateY(0)'">    <i class="icon icon-fullscreen"></i> 新标签页全屏查看  </a>  <!-- <a href="/downloads/doc/modbus%20tool%20%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E%20V0.2.pdf" download     style="display:inline-flex;align-items:center;gap:6px;padding:8px 16px;border-radius:8px;background:#fff;color:#334155 !important;text-decoration:none;font-size:13.5px;font-weight:500;border:1px solid #e2e8f0;transition:all .15s ease;"     onmouseover="this.style.background='#f8fafc';this.style.borderColor='#cbd5e1'"     onmouseout="this.style.background='#fff';this.style.borderColor='#e2e8f0'">    <i class="icon icon-download"></i> 下载 PDF  </a> --></div><div class="pdf-viewer" style="border:1px solid #e2e8f0;border-radius:12px;overflow:hidden;background:#fff;box-shadow:0 1px 3px rgba(16,24,40,0.06);">  <embed src="/downloads/doc/modbus%20tool%20%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E%20V0.2.pdf#toolbar=1&navpanes=0" type="application/pdf" width="100%" height="820px" style="display:block;width:100%;height:820px;border:0;"></div><noscript>  <div class="alert alert-warning" role="alert" style="margin-top:14px;">    您的浏览器未启用 JavaScript 或不支持内嵌 PDF 预览，    <a href="/downloads/doc/modbus%20tool%20%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E%20V0.2.pdf">点此直接打开 PDF</a>。  </div></noscript>]]>
    </content>
    <id>https://blog.j182010.top/2024/10/24/modbus%20tool%20%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E%E4%B9%A6/</id>
    <link href="https://blog.j182010.top/2024/10/24/modbus%20tool%20%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E%E4%B9%A6/"/>
    <published>2024-10-23T16:00:00.000Z</published>
    <summary>
      <![CDATA[<blockquote>
<p>文档版本：V0.2</p>
</blockquote>
<div class="pdf-toolbar" style="display:flex;gap:10px;align-items:center;margin-bottom:14px;flex]]>
    </summary>
    <title>modbus tool 使用说明书</title>
    <updated>2026-09-05T07:21:35.388Z</updated>
  </entry>
  <entry>
    <author>
      <name>John Doe</name>
    </author>
    <category term="技巧" scheme="https://blog.j182010.top/categories/%E6%8A%80%E5%B7%A7/"/>
    <category term="Tools" scheme="https://blog.j182010.top/tags/Tools/"/>
    <category term="UI" scheme="https://blog.j182010.top/tags/UI/"/>
    <category term="MasterGo" scheme="https://blog.j182010.top/tags/MasterGo/"/>
    <content>
      <![CDATA[<p>官网：<a href="https://mastergo.com/">https://mastergo.com</a></p><p>MasterGo（莫高设计）是国产云端 UI&#x2F;UX 设计 + 产设研协同平台，常被当作 Figma 国内替代；除了画界面，也很适合画<strong>流程图、状态图、交互原型</strong>等嵌入式开发配套插图。<br>相较于传统绘图工具，MasterGo 支持矢量绘制、组件复用、自动布局与研发标注，可高效完成充电桩、工控设备等嵌入式项目的状态机、UI 交互流程图绘制，支持团队在线协同评审，是 Figma 本土化替代优选。</p><!-- ![充电桩UI流程图](/downloads/images/STD01_V1.1.webp) --><p><em>以下为实际项目中的充电桩 UI 状态流程图：</em><br><img src="/downloads/images/STD01_V1.1.webp" alt="充电桩UI流程图" style="max-width:100%; border-radius:6px;"><br><br><br><br><img src="/downloads/images/A5115-EVH001 V1.0.webp" alt="充电桩UI流程图" style="max-width:100%; border-radius:6px;"></p>]]>
    </content>
    <id>https://blog.j182010.top/2024/05/10/%E7%94%A8%20MasterGo%20%E7%BB%98%E5%88%B6%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91%E6%B5%81%E7%A8%8B%E5%9B%BE%E5%92%8C%E7%8A%B6%E6%80%81%E5%9B%BE/</id>
    <link href="https://blog.j182010.top/2024/05/10/%E7%94%A8%20MasterGo%20%E7%BB%98%E5%88%B6%E5%B5%8C%E5%85%A5%E5%BC%8F%E5%BC%80%E5%8F%91%E6%B5%81%E7%A8%8B%E5%9B%BE%E5%92%8C%E7%8A%B6%E6%80%81%E5%9B%BE/"/>
    <published>2024-05-09T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>官网：<a href="https://mastergo.com/">https://mastergo.com</a></p>
<p>MasterGo（莫高设计）是国产云端 UI&#x2F;UX 设计 + 产设研协同平台，常被当作 Figma 国内替代；除了画界面，也很适合]]>
    </summary>
    <title>用 MasterGo 绘制嵌入式开发流程图/状态图</title>
    <updated>2026-09-08T15:23:10.289Z</updated>
  </entry>
  <entry>
    <author>
      <name>John Doe</name>
    </author>
    <category term="加密" scheme="https://blog.j182010.top/categories/%E5%8A%A0%E5%AF%86/"/>
    <category term="算法" scheme="https://blog.j182010.top/tags/%E7%AE%97%E6%B3%95/"/>
    <content>
      <![CDATA[<div class="toc"><!-- toc --><ul><li><a href="#span-classcolor-title-inline%E4%B8%80-aes-%E6%98%AF%E4%BB%80%E4%B9%88span"><span class="color-title-inline">一、AES 是什么</span></a></li><li><a href="#span-classcolor-title-inline%E4%BA%8C-%E5%8A%A0%E5%AF%86%E6%96%B9%E5%BC%8Fspan"><span class="color-title-inline">二、加密方式</span></a></li><li><a href="#span-classcolor-title-inline%E4%B8%89-ecb-%E6%A8%A1%E5%BC%8F%E7%94%B5%E5%AD%90%E5%AF%86%E7%A0%81%E6%9C%ACspan"><span class="color-title-inline">三、ECB 模式（电子密码本）</span></a></li><li><a href="#%E5%9B%9B-cbc-%E6%A8%A1%E5%BC%8F%E5%AF%86%E7%A0%81%E5%88%86%E7%BB%84%E9%93%BE%E6%8E%A5">四、CBC 模式（密码分组链接）</a></li></ul><!-- tocstop --></div><h2><span id="一-aes-是什么"><span class="color-title-inline">一、AES 是什么</span></span></h2><!-- ## <span class="color-title-inline" style="--title-color: #E05656;">一、AES 是什么 指定颜色</span> --><p><strong>AES（Advanced Encryption Standard）</strong> 是目前应用最广泛的对称分组加密标准，由 NIST 于 2001 年发布，替代 DES。</p><ul><li><strong>分组长度</strong>：固定 128 bit（16 字节）</li><li><strong>密钥长度</strong>：AES-128 &#x2F; AES-192 &#x2F; AES-256（16 &#x2F; 24 &#x2F; 32 字节）</li><li><strong>对称加密</strong>：加密和解密使用同一把密钥</li><li><strong>轮数</strong>：10 &#x2F; 12 &#x2F; 14 轮（对应 128 &#x2F; 192 &#x2F; 256 位密钥）</li></ul><h2><span id="二-加密方式"><span class="color-title-inline">二、加密方式</span></span></h2><p><strong>加密方式分为五种：</strong></p><ul><li>电码本模式（Electronic Codebook Book (ECB)）</li><li>密码分组链接模式（Cipher Block Chaining (CBC)）</li><li>计算器模式（Counter (CTR)）</li><li>密码反馈模式（Cipher FeedBack (CFB)）</li><li>输出反馈模式（Output FeedBack (OFB)）</li></ul><p><strong>实际应用比较多的是ECB和CBC。</strong></p><h2><span id="三-ecb-模式电子密码本"><span class="color-title-inline">三、ECB 模式（电子密码本）</span></span></h2><p>将明文按16字节分组，每组分别加密后拼接。</p><p>ECB 分组加密流程：</p><p><img src="/downloads/doc/ECB.svg" style="width: 600px;"><br></p><blockquote><p>⚠️ ECB 致命缺陷：</p><ul><li>相同明文块 → 相同密文块</li><li>明文结构直接反映到密文</li><li>加密图片可看出轮廓</li><li>无法抵抗重放 &#x2F; 模式分析</li></ul></blockquote><h2><span id="四-cbc-模式密码分组链接">四、CBC 模式（密码分组链接）</span></h2><p>ECB缺点是明文内相同的明文块，最终的密文也是相同的，<br>为了更好的隐藏明文信息，针对这个问题就有了CBC模式。<br>每一小段明文先与初始块向量或者上一段的密文段进行异或运算后，再与密钥进行加密。<br>必须提供随机 IV，IV 不保密但不可重复。</p>]]>
    </content>
    <id>https://blog.j182010.top/2023/07/22/AES%20%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95/</id>
    <link href="https://blog.j182010.top/2023/07/22/AES%20%E5%8A%A0%E5%AF%86%E7%AE%97%E6%B3%95/"/>
    <published>2023-07-21T16:00:00.000Z</published>
    <summary>
      <![CDATA[<div class="toc">

<!-- toc -->

<ul>
<li><a href="#span-classcolor-title-inline%E4%B8%80-aes-%E6%98%AF%E4%BB%80%E4%B9%88span"><span class="]]>
    </summary>
    <title>AES 加密算法</title>
    <updated>2026-09-08T15:43:47.657Z</updated>
  </entry>
  <entry>
    <author>
      <name>John Doe</name>
    </author>
    <category term="硬件" scheme="https://blog.j182010.top/categories/%E7%A1%AC%E4%BB%B6/"/>
    <category term="电路" scheme="https://blog.j182010.top/tags/%E7%94%B5%E8%B7%AF/"/>
    <content>
      <![CDATA[<p><strong>图腾柱驱动电路：</strong></p><p><img src="/images/PWM驱动电路/0.png" style="width: 600px;"><br><br><strong>工作说明：</strong><br>1、PWM为高电平，Q4导通，Q3截止，U8的寄生电容Cgs通过Q2与R6放电，U8关闭；<br>2、PWM为低电平，Q4截止，Q2截止，12V电压通过Q3给U8的寄生电容Cgs充电，U8导通；<br>3、R3为限流电阻，避免Cgs的充放电电流过大产生浪涌电流；<br>4、R6的作用：Cgs放电时，通过Q2与放电，只能放到0.7V左右，加上R6，就可以放到0V，确保关闭MOS；<br>5、此电路可以用于有刷直流电机的PWM调速；<br>6、推挽电路作用：电压跟随，电流放大（弱信号变强）</p><hr><p>增加Ugs电压，避免工作在“米勒平台”电压附近，另外尽可能增加Ugs的输出电流。<br>这里使用三极管组成“推挽电路”，推挽电路的作用是将b极小电流转化为输出大电流，同时电压实现跟随。<br>即保证输入输出电压相等，并将输入电流放大。保证了接近于12V对MOS管进行充电，接近于0V对MOS管进行放电。<br>使得N-MOS能够快速导通，快速关断，并且不会存在某个时刻两个三极管同时导通的情况。</p><p>MOS管串接20欧电阻为了限流，因为MOS管存在Cgs杂散电容，如果没有此限流电阻，上电瞬间会直接给Cgs充电，造成浪涌电流，损坏MOS管。<br>MOS管下拉的10K电阻作用是给Cgs杂散电容一个通路，并且当MOS管G极发生雷击或静电，有一个释放的通路。</p>]]>
    </content>
    <id>https://blog.j182010.top/2023/06/02/PWM%E9%A9%B1%E5%8A%A8%E7%94%B5%E8%B7%AF/</id>
    <link href="https://blog.j182010.top/2023/06/02/PWM%E9%A9%B1%E5%8A%A8%E7%94%B5%E8%B7%AF/"/>
    <published>2023-06-01T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p><strong>图腾柱驱动电路：</strong></p>
<p><img src="/images/PWM驱动电路/0.png" style="width: 600px;"><br><br><strong>工作说明：</strong><br>1、PWM为高电平，Q4导通，]]>
    </summary>
    <title>PWM驱动电路</title>
    <updated>2026-09-05T08:22:30.519Z</updated>
  </entry>
  <entry>
    <author>
      <name>John Doe</name>
    </author>
    <category term="硬件" scheme="https://blog.j182010.top/categories/%E7%A1%AC%E4%BB%B6/"/>
    <category term="电路" scheme="https://blog.j182010.top/tags/%E7%94%B5%E8%B7%AF/"/>
    <content>
      <![CDATA[<p>在做一款消费电子产品时，需要采集电池电压（3.3V-4.2V），希望休眠时尽量减小待机电流。<br>电池电压采集电路为两个1%的300K电阻进行分压，由该电路引起的待机电流为 4.2&#x2F;（300+300）mA&#x3D;7uA。此时比较合理（整机的待机电流要求30uA以内）。<br>初始设计电路如下:</p><p><img src="/images/ADC输入阻抗/0.png" style="width: 330px;"><br><br>在编程采集数据时发现测试电压与实际电压有偏差，测试值总比实际值偏小一点。在软件上做补偿，把值修正了。<br>但是换一个板子测试的时候发现测试的电压又不准了，此时知道通过软件补偿这种方法行不通，那么只能从硬件找原因。、</p><p>查找datasheet发现AD的输入阻抗最大只有50KΩ。</p><p><img src="/images/ADC输入阻抗/1.png" style="width: 700px;"><br><br>RAIN：外部输入阻抗，STM32芯片中这个值最大为50KΩ;<br>RADC：采样开关电阻，最大值为1KΩ;<br>CADC：内部采样和保持电容，最大值为8pF。</p><p>在ADC数据采集的时候需要有电流流入，那么RAIN会产生一个压降。阻容网络中的RADC和CADC上，对电容的充电由RADC控制。<br>随着源电阻(RADC)的增加，对保持电容的充电时间也相应增加。</p><p>对CADC的充电由RAIN+RADC控制，因此充电时间常数为tc &#x3D; (RADC + RAIN)×CADC。如果时间过短，ADC转换的数值会小于实际值。<br>通过以上数据知道，采集精度跟采集时间和输入阻抗有关。但是通过计算得知，如果输入阻抗为300KΩ，那么充电时间约为2.4uS。</p><p>在软件上把采样周期调到最大（ADC_SampleTime_239_5Cycles，频率为12M，时间19.9uS）,还是存在误差。说明此时跟周期不是主要原因。<br>问题出在输入阻抗大于IC里ADC允许的最大阻抗。充电时电流分两路，一路经过R1到R2到地，还有一路经过R1流入MCU的AD接口。<br>（不知是不是IO口会有一定的漏电流到地）此时相当于在R2旁边并了一个电阻到地，检测点的电压不是标准的1&#x2F;2Vbat。</p><p>那么为了更准确地检测电池电压，只好把电阻改小。</p><p><img src="/images/ADC输入阻抗/2.png" style="width: 330px;"><br><br>原来接地的地方改接到一个IO口，在需要检测的时候输出低电平，不需要的时候输出高电平。<br>然后分压电阻使用两个30K的问题得到解决，电压检测误差小于0.02V，待机电流比原来的还小了几个微安。</p>]]>
    </content>
    <id>https://blog.j182010.top/2023/05/01/ADC%E8%BE%93%E5%85%A5%E9%98%BB%E6%8A%97/</id>
    <link href="https://blog.j182010.top/2023/05/01/ADC%E8%BE%93%E5%85%A5%E9%98%BB%E6%8A%97/"/>
    <published>2023-04-30T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>在做一款消费电子产品时，需要采集电池电压（3.3V-4.2V），希望休眠时尽量减小待机电流。<br>电池电压采集电路为两个1%的300K电阻进行分压，由该电路引起的待机电流为 4.2&#x2F;（300+300）mA&#x3D;7uA。此时比较合理（整机的待机电流要求30u]]>
    </summary>
    <title>ADC输入阻抗</title>
    <updated>2026-09-05T08:09:07.296Z</updated>
  </entry>
  <entry>
    <author>
      <name>John Doe</name>
    </author>
    <category term="硬件" scheme="https://blog.j182010.top/categories/%E7%A1%AC%E4%BB%B6/"/>
    <category term="电路" scheme="https://blog.j182010.top/tags/%E7%94%B5%E8%B7%AF/"/>
    <content>
      <![CDATA[<div class="toc"><!-- toc --><ul><li><a href="#%E6%96%B9%E6%A1%88%E4%B8%80">方案一</a></li><li><a href="#%E6%96%B9%E6%A1%88%E4%BA%8C">方案二</a></li><li><a href="#usb%E4%B8%8E%E9%94%82%E7%94%B5%E6%B1%A0%E4%BE%9B%E7%94%B5%E5%88%87%E6%8D%A2%E7%94%B5%E8%B7%AF">USB与锂电池供电切换电路：</a></li></ul><!-- tocstop --></div><h2><span id="方案一">方案一</span></h2><p><img src="/images/双电源电路/1.png" style="width: 600px;"><br></p><blockquote><p>❗缺点：二极管存在压降</p></blockquote><h2><span id="方案二">方案二</span></h2><p><img src="/images/双电源电路/2.png" style="width: 700px;"><br></p><ul><li>当外部充电电源VBUS(5V)插入时Q5导通，Q4打开，Q3关闭，负载由外部电源供电。</li><li>当外部电源拔掉的时候，Q3打开，Q4关闭，电池有备用电池Pbatter供电。</li></ul><blockquote><p><strong>💡提示</strong><br>其中有个D7稳压管的作用必不可少，如果VBUS直接连接R39而没有D7的话，当外部电源拔掉时，由于电源是缓慢下降，当VBUS下降到Q4还未关闭完全，Q3 MOS管由于<strong>体二极管</strong>的存在大于VBUS电压时会形成一个闭环，即Q4无法关闭，Q3无法完全打开，处在一个非正常的工作模式，加了D7稳压管可以避免当VBUS在降压过程中，出现以上现象。<br>注：Pbatter电压-D7压降（加上电阻分压）&lt;0.7V（三极管导通压降）即可。</p></blockquote><h2><span id="usb与锂电池供电切换电路">USB与锂电池供电切换电路：</span></h2><p><img src="/images/双电源电路/3.png" style="width: 300px;"><br></p>]]>
    </content>
    <id>https://blog.j182010.top/2023/03/20/%E5%8F%8C%E7%94%B5%E6%BA%90%E7%94%B5%E8%B7%AF/</id>
    <link href="https://blog.j182010.top/2023/03/20/%E5%8F%8C%E7%94%B5%E6%BA%90%E7%94%B5%E8%B7%AF/"/>
    <published>2023-03-19T16:00:00.000Z</published>
    <summary>
      <![CDATA[<div class="toc">

<!-- toc -->

<ul>
<li><a href="#%E6%96%B9%E6%A1%88%E4%B8%80">方案一</a></li>
<li><a href="#%E6%96%B9%E6%A1%88%E4%BA%8C">方案二]]>
    </summary>
    <title>双电源电路</title>
    <updated>2026-09-08T15:32:18.394Z</updated>
  </entry>
  <entry>
    <author>
      <name>John Doe</name>
    </author>
    <category term="硬件" scheme="https://blog.j182010.top/categories/%E7%A1%AC%E4%BB%B6/"/>
    <category term="电路" scheme="https://blog.j182010.top/tags/%E7%94%B5%E8%B7%AF/"/>
    <content>
      <![CDATA[<p><img src="/images/防反接电路/1.png" style="width: 500px;"><br><br><strong>POMS 设计说明：</strong><br>1、巧妙利用内部寄生二极管。上电时，通过内部寄生二极管，Vgs电压大于开启电压，PMOS管完全导通；<br>2、R29，R31：电阻分压，调整Vgs电压，Vgs电压尽量大，这样，Ron越小，压降越小，损耗越低；<br>3、D5、稳压二极管，防止Vgs电压超过极限电压。</p><hr><p><img src="/images/防反接电路/2.png" style="width: 500px;"><br><br><strong>NMOS 设计说明：</strong><br>1、巧妙利用内部寄生二极管。上电时，通过内部寄生二极管，Vgs电压大于Vth电压，NMOS管完全导通；<br>2、R87，R88：电阻分压，调整Vgs电压，Vgs电压尽量大，这样，Ron越小，压降越小，损耗越低；<br>3、D25、稳压二极管，防止Vgs电压超过极限电压。</p>]]>
    </content>
    <id>https://blog.j182010.top/2023/03/15/%E9%98%B2%E5%8F%8D%E6%8E%A5%E7%94%B5%E8%B7%AF/</id>
    <link href="https://blog.j182010.top/2023/03/15/%E9%98%B2%E5%8F%8D%E6%8E%A5%E7%94%B5%E8%B7%AF/"/>
    <published>2023-03-14T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p><img src="/images/防反接电路/1.png" style="width: 500px;"><br><br><strong>POMS 设计说明：</strong><br>1、巧妙利用内部寄生二极管。上电时，通过内部寄生二极管，Vgs电压大于开启电压，PMOS管]]>
    </summary>
    <title>防反接电路</title>
    <updated>2026-09-05T04:49:32.075Z</updated>
  </entry>
  <entry>
    <author>
      <name>John Doe</name>
    </author>
    <category term="硬件" scheme="https://blog.j182010.top/categories/%E7%A1%AC%E4%BB%B6/"/>
    <category term="电路" scheme="https://blog.j182010.top/tags/%E7%94%B5%E8%B7%AF/"/>
    <content>
      <![CDATA[<div class="toc"><!-- toc --><ul><li><a href="#%E6%AD%A3%E5%B8%B8%E6%95%B0%E7%A0%81%E7%AE%A1">正常数码管：</a></li><li><a href="#3%E4%BD%8D6%E8%84%9A%E6%95%B0%E7%A0%81%E7%AE%A1">3位6脚数码管：</a></li><li><a href="#%E6%9F%A5%E7%90%86%E5%A4%8D%E7%94%A8%E7%AE%97%E6%B3%95charlieplexing">查理复用算法（Charlieplexing）：</a></li></ul><!-- tocstop --></div><h2><span id="正常数码管">正常数码管：</span></h2><p><img src="/images/3位6脚数码管（查理复用算法）/1.png" style="width: 500px;"><br></p><h2><span id="3位6脚数码管">3位6脚数码管：</span></h2><p><img src="/images/3位6脚数码管（查理复用算法）/2.png" style="width: 700px;"><br></p><h2><span id="查理复用算法charlieplexing">查理复用算法（Charlieplexing）：</span></h2><p>单片机GPIO的三个状态：高电平、低电平、高阻态。<br><img src="/images/3位6脚数码管（查理复用算法）/3.png" style="width: 700px;"><br><br>2路端口可以控制2个LED<br>3路端口可以控制6个LED<br>4路端口可以控制12个LED<br>x    y<br>2    2<br>3    6<br>4    12<br>5    20<br>6    30<br>y&#x3D;x*(x-1)</p><p><img src="/images/3位6脚数码管（查理复用算法）/4.png" style="width: 700px;"><br></p><p>利用IO口的三态进行控制，Z为高阻态。<br>例如要点亮 LED1，可以令 P1&#x3D;1，P2&#x3D;0，P3&#x3D;Z。<br>另外一个通路LED6和LED4因为被LED1钳位为2.2V，电压太低不足以点亮2个灯。<br><img src="/images/3位6脚数码管（查理复用算法）/5.png" style="width: 700px;"><br></p><p>使用4个GPIO时：<br><img src="/images/3位6脚数码管（查理复用算法）/6.png" style="width: 700px;"><br><br>LED亮起时完全由单片机的GPIO输出电流，所以对于GPIO的电流驱动能力有一定的要求。</p><p>如果要同时亮起两个以上的LED，只要交替切换点亮的速度够快，由于人眼的视觉暂留效应，看起来就是同时亮起的。</p>]]>
    </content>
    <id>https://blog.j182010.top/2023/03/10/3%E4%BD%8D6%E8%84%9A%E6%95%B0%E7%A0%81%E7%AE%A1%EF%BC%88%E6%9F%A5%E7%90%86%E5%A4%8D%E7%94%A8%E7%AE%97%E6%B3%95%EF%BC%89/</id>
    <link href="https://blog.j182010.top/2023/03/10/3%E4%BD%8D6%E8%84%9A%E6%95%B0%E7%A0%81%E7%AE%A1%EF%BC%88%E6%9F%A5%E7%90%86%E5%A4%8D%E7%94%A8%E7%AE%97%E6%B3%95%EF%BC%89/"/>
    <published>2023-03-09T16:00:00.000Z</published>
    <summary>
      <![CDATA[<div class="toc">

<!-- toc -->

<ul>
<li><a href="#%E6%AD%A3%E5%B8%B8%E6%95%B0%E7%A0%81%E7%AE%A1">正常数码管：</a></li>
<li><a href="#3%E4%BD%8D6]]>
    </summary>
    <title>3位6脚数码管（查理复用算法）</title>
    <updated>2026-09-08T15:33:24.264Z</updated>
  </entry>
  <entry>
    <author>
      <name>John Doe</name>
    </author>
    <category term="硬件" scheme="https://blog.j182010.top/categories/%E7%A1%AC%E4%BB%B6/"/>
    <category term="电路" scheme="https://blog.j182010.top/tags/%E7%94%B5%E8%B7%AF/"/>
    <content>
      <![CDATA[<p>图中使用的是HCNR201光耦，一个输入端，两个输出端；<br>两个输出端的特性高度一致，即输入端有电流流过时，在两个输出端产生的输出电流也一样。<br>利用这个特性，<strong>将一路输出用于反馈给输入端，一路输出到隔离端，可以实现模拟信号的隔离。</strong></p><h2><span id><img src="/images/模拟信号隔离/0.png" style="width: 700px;"><br></span></h2><p>高线性光耦&#x2F;LTV-W201S&#x2F;光宝<br><img src="/images/模拟信号隔离/1.png" style="width: 800px;"><br><br>当ui输入变大，LM2904运放输出电压变大，光耦发光二极管电流变大，输出端(3到4脚)电流也变大，R62电流变大，运放负端输入电压升高，使得运放输出变小（因为运放正负输入端差值减小），所以是负反馈。</p><hr><p><img src="/images/模拟信号隔离/2.png" style="width: 500px;"><br><br>电流方向：<br>IF: 2-&gt;1<br>IPD1: 3-&gt;4<br>IPD2: 6-&gt;5</p><p><img src="/images/模拟信号隔离/3.png" style="width: 500px;"><br>Vin输入变大（运放输入差值变大） -&gt; 运放输出电压减小（Vin由运放负端口输入），IF电流变大 -&gt; 光照使IP1，IP2电流也变大</p><p>-&gt; IP1分流导致Vin电压减小，形成负反馈。</p>]]>
    </content>
    <id>https://blog.j182010.top/2023/02/08/%E6%A8%A1%E6%8B%9F%E4%BF%A1%E5%8F%B7%E9%9A%94%E7%A6%BB/</id>
    <link href="https://blog.j182010.top/2023/02/08/%E6%A8%A1%E6%8B%9F%E4%BF%A1%E5%8F%B7%E9%9A%94%E7%A6%BB/"/>
    <published>2023-02-07T16:00:00.000Z</published>
    <summary>
      <![CDATA[<p>图中使用的是HCNR201光耦，一个输入端，两个输出端；<br>两个输出端的特性高度一致，即输入端有电流流过时，在两个输出端产生的输出电流也一样。<br>利用这个特性，<strong>将一路输出用于反馈给输入端，一路输出到隔离端，可以实现模拟信号的隔离。</strong><]]>
    </summary>
    <title>模拟信号隔离</title>
    <updated>2026-09-05T08:50:10.140Z</updated>
  </entry>
  <entry>
    <author>
      <name>John Doe</name>
    </author>
    <category term="硬件" scheme="https://blog.j182010.top/categories/%E7%A1%AC%E4%BB%B6/"/>
    <category term="电路" scheme="https://blog.j182010.top/tags/%E7%94%B5%E8%B7%AF/"/>
    <content>
      <![CDATA[<div class="toc"><!-- toc --><ul><li><a href="#%E6%A6%82%E8%BF%B0">概述</a></li><li><a href="#1-%E5%8F%8D%E7%9B%B8%E6%AF%94%E4%BE%8B%E8%BF%90%E7%AE%97%E7%94%B5%E8%B7%AF">1、反相比例运算电路</a></li><li><a href="#2-%E5%90%8C%E7%9B%B8%E6%AF%94%E4%BE%8B%E8%BF%90%E7%AE%97%E7%94%B5%E8%B7%AF">2、同相比例运算电路</a><ul><li><a href="#%E7%94%B5%E5%8E%8B%E8%B7%9F%E9%9A%8F%E5%99%A8rf0">电压跟随器:RF&#x3D;0</a></li></ul></li><li><a href="#3-%E5%87%8F%E6%B3%95%E8%BF%90%E7%AE%97%E7%94%B5%E8%B7%AF%E5%B7%AE%E5%8A%A8%E6%94%BE%E5%A4%A7%E7%94%B5%E8%B7%AF">3、减法运算电路(差动放大电路)</a><ul><li><a href="#%E5%B0%8F%E4%BF%A1%E5%8F%B7%E5%A4%84%E7%90%86%E7%94%B5%E8%B7%AF">小信号处理电路</a></li></ul></li><li><a href="#4-%E5%90%8C%E7%9B%B8%E5%B7%AE%E5%88%86%E8%BE%93%E5%85%A5%E6%94%BE%E5%A4%A7%E7%94%B5%E8%B7%AF%E4%BB%AA%E8%A1%A8%E6%94%BE%E5%A4%A7%E7%94%B5%E8%B7%AF">4、同相差分输入放大电路(仪表放大电路)</a></li></ul><!-- tocstop --></div><h1><span id="概述">概述</span></h1><p>运算放大器内部由三个层级组成：输入级、放大级、输出级。</p><ul><li><strong>输入级：</strong> 差分电路。抑制共模信号，放大差模信号。</li><li><strong>放大级：</strong> 共射电路。优点：放大能力很强。缺点：内阻大，输出电流弱。</li><li><strong>输出级：</strong> 推挽电路。电压不变，放大电流。</li></ul><p>常用低速双运放LM358，低速四运放LM324，高速单运放LM721（价格较高）<br>（LM2904其实和LM358是一样的，只不过是工作温度范围不一样）<br>常用比较器LM239。</p><p>offset电压：输出0V时输入端的电压差；输出电压不会超过电源电压。</p><h1><span id="1-反相比例运算电路">1、反相比例运算电路</span></h1><p><img src="/images/运放电路/0.png" style="width: 300px;"><br></p><ol><li>ui输入增加（+），运放正负端输入（负）差值变大；</li><li>（负）差值变大，运放输出端电压减小（-）；</li><li>输出端减小的电压通过RF分流将输入的ui同时拉低，导致运放正负端输入（负）差值减小，运放输出端电压降低减小，形成负反馈。</li></ol><ul><li><p>RP称为平衡电阻，通常取： $$R_P &#x3D; R_1 \parallel R_F$$保证输入端电阻平衡，提高差动电路对称性。</p></li><li><p>闭环电压放大倍数：$$A_{uf} &#x3D; -\frac{R_F}{R_1}$$</p></li><li><p><strong>输入阻抗低</strong></p></li><li><p>反相器：RF&#x3D;R1</p></li></ul><blockquote><p>💡运放负反馈电阻RF越大引入的背景噪声（毛刺）越大。</p></blockquote><h1><span id="2-同相比例运算电路">2、同相比例运算电路</span></h1><p><img src="/images/运放电路/1.png" style="width: 300px;"><br></p><ol><li>ui输入增加（+），运放正负端输入（正）差值变大；</li><li>（正）差值变大，运放输出端电压增加（+）；</li><li>输出端增加的电压通过RF将运放的负输入端电压拉高，导致运放正负端输入差值减小，运放输出端电压增加减小，形成负反馈。</li></ol><ul><li>平衡电阻：$$R_P &#x3D; R_1 \parallel R_F$$</li><li>闭环电压放大倍数：$$A_{uf} &#x3D; 1 + \frac{R_F}{R_1}$$</li><li><strong>输入阻抗高</strong></li></ul><br><h2><span id="电压跟随器rfx3d0">电压跟随器:RF&#x3D;0</span></h2><p><img src="/images/运放电路/2.png" style="width: 230px;"><br><br>uo &#x3D; u- &#x3D; u+ &#x3D; ui<br>电压并联负反馈，输入电阻大，输出电阻小。</p><h1><span id="3-减法运算电路差动放大电路">3、减法运算电路(差动放大电路)</span></h1><p><img src="/images/运放电路/3.png" style="width: 260px;"><br></p><p>$$<br>u_0 &#x3D; \frac{R_2}{R_1}\cdot(u_{i2}-u_{i1})<br>$$</p><hr><p>$$<br>\frac{u_{i2}\cdot \frac{R_2}{R_1+R_2}-u_{i1}}{R_1} &#x3D; \frac{u_0-u_{i1}}{R_1+R_2}<br>$$</p><p>$$<br>\frac{u_{i2}\cdot R_2 - u_{i1}\cdot(R_1+R_2)}{R_1} &#x3D; u_0 - u_{i1}<br>$$</p><p>$$<br>u_0 &#x3D; \frac{u_{i2}\cdot R_2 - u_{i1}R_1 - u_{i1}R_2 + u_{i1}R_1}{R_1} &#x3D; \frac{R_2}{R_1}\cdot(u_{i2}-u_{i1})<br>$$</p><h2><span id="小信号处理电路">小信号处理电路</span></h2><p><img src="/images/运放电路/4.png" style="width: 550px;"><br></p><h1><span id="4-同相差分输入放大电路仪表放大电路">4、同相差分输入放大电路(仪表放大电路)</span></h1><p><img src="/images/运放电路/5.png" style="width: 550px;"><br><br>电路由两级放大组成，第一级由运放A1、A2组成同相输入，输入电阻很高，电路结构对称，可抑制零点漂移。</p><p>全局法（根据虚短虚断）：</p><p>$$<br>\frac{u_{i1}-u_{i2}}{R_1} &#x3D; \frac{u_{o1}-u_{o2}}{R_1+2R_2}<br>$$</p><p>$$<br>u_{o1}-u_{o2} &#x3D; \left(1+\frac{2R_2}{R_1}\right)(u_{i1}-u_{i2})<br>$$<br>第二级由运放A3构成差动放大电路，所以：</p><p>$$<br>u_o &#x3D; \frac{R_4}{R_3}(u_{o2}-u_{o1}) &#x3D; -\frac{R_4}{R_3}\left(1+\frac{2R_2}{R_1}\right)(u_{i1}-u_{i2})<br>$$</p><blockquote><p>💡同相放大输入阻抗高，反相放大输入阻抗低</p></blockquote>]]>
    </content>
    <id>https://blog.j182010.top/2022/04/20/%E8%BF%90%E6%94%BE%E7%94%B5%E8%B7%AF/</id>
    <link href="https://blog.j182010.top/2022/04/20/%E8%BF%90%E6%94%BE%E7%94%B5%E8%B7%AF/"/>
    <published>2022-04-19T16:00:00.000Z</published>
    <summary>
      <![CDATA[<div class="toc">

<!-- toc -->

<ul>
<li><a href="#%E6%A6%82%E8%BF%B0">概述</a></li>
<li><a href="#1-%E5%8F%8D%E7%9B%B8%E6%AF%94%E4%BE%8B%E8%]]>
    </summary>
    <title>运放电路</title>
    <updated>2026-09-08T15:34:37.943Z</updated>
  </entry>
  <entry>
    <author>
      <name>John Doe</name>
    </author>
    <category term="硬件" scheme="https://blog.j182010.top/categories/%E7%A1%AC%E4%BB%B6/"/>
    <category term="电路" scheme="https://blog.j182010.top/tags/%E7%94%B5%E8%B7%AF/"/>
    <content>
      <![CDATA[<div class="toc"><!-- toc --><ul><li><a href="#div-classsection-title%E4%BD%95%E8%B0%93%E7%83%AD%E7%94%B5%E5%81%B6div"><div class="section-title">何谓热电偶</div></a><ul><li><a href="#div-classsection-title%E7%83%AD%E7%94%B5%E5%81%B6%E7%9A%84%E5%8E%9F%E7%90%86div"><div class="section-title">热电偶的原理</div></a></li><li><a href="#div-classsection-title%E7%B1%BB%E5%9E%8Bdiv"><div class="section-title">类型</div></a></li></ul></li><li><a href="#div-classsection-title%E9%87%87%E9%9B%86%E6%96%B9%E5%BC%8Fdiv"><div class="section-title">采集方式</div></a></li><li><a href="#div-classsection-title%E7%83%AD%E7%94%B5%E5%81%B6%E7%9A%84%E6%84%9F%E6%B8%A9%E9%83%A8%E4%BD%8D%E4%BD%8D%E4%BA%8E%E4%BD%95%E5%A4%84div"><div class="section-title">热电偶的感温部位位于何处？</div></a></li><li><a href="#div-classsection-title%E5%AE%9E%E9%99%85%E5%BA%94%E7%94%A8div"><div class="section-title">实际应用</div></a></li></ul><!-- tocstop --></div><!-- <div style="border-left:4px solid #2196F3; padding:6px 14px; margin:18px 0; border-bottom:2px solid #2196F3;">  <span style="font-size:20px; font-weight:bold; color:#1A1A1A;">何谓热电偶</span></div> --><h1><span id="何谓热电偶"><div class="section-title">何谓热电偶</div></span></h1><p>所谓热电偶，是指由两种不同材质的金属导体构成的温度传感器。<br>与其他温度计（水银温度计、热敏电阻等）相比较，主要用于工业行业的热电偶具有如下特点。</p><blockquote><ol><li>响应速度快。</li><li>可进行-200℃到+1700℃之间大范围的温度采集。</li><li>可对特定点和小空间进行温度采集。</li><li>由于温度信息可检测为电信号（热电动势），信息的处理和分析非常便利。</li><li>价格低廉，易购买。</li></ol></blockquote><h2><span id="热电偶的原理"><div class="section-title">热电偶的原理</div></span></h2><p>1821年德国科学家塞贝克（T. J. Seebeck）发现：当连接两种不同金属，并对两端的接点施加不同温度时，金属之间会产生电压并有电流通过。<br>这一现象以发现者的名字命名为“塞贝克效应”。该电路中生成电流的电力被称为热电动势（Thermoelectromotive force），其极性和大小仅由两种导体的材质和两端之间的温度差决定。</p><p><img src="/images/热电偶/0.gif" style="width: 400px;"><br><br><strong>利用前面所说的塞贝克效应，热电偶凭借两种不同金属的接合处（测温接点）T1与采集仪接点（基准接点）T0之间的温度差T，从而产生电压。</strong><br><strong>使用热电偶采集温度时，采集仪会采集该电压。</strong></p><h2><span id="类型"><div class="section-title">类型</div></span></h2><p><img src="/images/热电偶/1.png" style="width: 1000px;"><br></p><h1><span id="采集方式"><div class="section-title">采集方式</div></span></h1><p><img src="/images/热电偶/2.gif" style="width: 400px;"><br></p><ol><li>将基准接点设为0°C（冷接点补偿）直接读取温度的方法</li><li>采集基准接点的气温（基准接点补偿）计入温度差ΔT的方法</li></ol><blockquote><p>采集时，将冷接点维持在0℃非常困难。通过采集端子周围的温度，将其与以0℃为基准的热电动势相加，可以获得测温接点的温度。我们称之为基准接点补偿。</p></blockquote><h1><span id="热电偶的感温部位位于何处"><div class="section-title">热电偶的感温部位位于何处？</div></span></h1><p><img src="/images/热电偶/3.gif" style="width: 400px;"><br></p><p>图为将热电偶插入装有热液体的杯中的示意图。<br>假设液体内温度为均匀100°C（无温度梯度）。<br>此时，<strong>液体内的热电偶部分不会产生热电动势</strong>。热电动势只产生于存在温度梯度的部分。<br>由于热电偶的感温部位会产生热电动势，因此该温度梯度部位即为热电偶的感温部位。</p><h1><span id="实际应用"><div class="section-title">实际应用</div></span></h1><p>热电偶测温时，需要参考（冷端）的温度，因为热电偶测量的是热电偶两端（热端和冷端）的温度差。<br>在实际应用中，冷端的温度并不恒定，也可能不容易直接测量。如果不对这个冷端温度进行补偿，就可能导致测量误差。<br>MAX6675内置了一个冷端补偿电路。通过一个内部的温度传感器直接测量出MAX6675芯片的温度，然后将这个温度作为冷端温度。<br>再根据这个温度计算出应该对热电偶电压进行多大的补偿，以消除冷端温度变化带来的测量误差。<br><br><img src="/images/热电偶/4.png" style="width: 1000px;"><br></p>]]>
    </content>
    <id>https://blog.j182010.top/2022/04/10/%E7%83%AD%E7%94%B5%E5%81%B6/</id>
    <link href="https://blog.j182010.top/2022/04/10/%E7%83%AD%E7%94%B5%E5%81%B6/"/>
    <published>2022-04-09T16:00:00.000Z</published>
    <summary>
      <![CDATA[<div class="toc">

<!-- toc -->

<ul>
<li><a href="#div-classsection-title%E4%BD%95%E8%B0%93%E7%83%AD%E7%94%B5%E5%81%B6div"><div class="sect]]>
    </summary>
    <title>热电偶</title>
    <updated>2026-09-08T15:36:05.072Z</updated>
  </entry>
  <entry>
    <author>
      <name>John Doe</name>
    </author>
    <category term="硬件" scheme="https://blog.j182010.top/categories/%E7%A1%AC%E4%BB%B6/"/>
    <category term="电路" scheme="https://blog.j182010.top/tags/%E7%94%B5%E8%B7%AF/"/>
    <content>
      <![CDATA[<h1><span id="i2c电平转换">I2C电平转换：</span></h1><p><img src="/images/双向电平转换/0.png" style="width: 1000px;"><br></p><p><strong>双向传输原理，分四种情况：</strong><br>1、当SDA1输出高电平时：MOS管Q1的Vgs &#x3D; 0，MOS管关闭，SDA2被电阻R3上拉到5V。<br>2、当SDA1输出低电平时：MOS管Q1的Vgs &#x3D; 3.3V，大于导通电压，MOS管导通，SDA2通过MOS管被拉到低电平。<br>3、当SDA2输出高电平时：MOS管Q1的Vgs不变，MOS维持关闭状态，SDA1被电阻R2上拉到3.3V。<br>4、当SDA2输出低电平时：MOS管不导通，但内部体二极管导通（压降0.2V左右）把SDA1拉低到低电平，此时Vgs约等于3.3V，MOS管导通，进一步拉低了SDA1的电压。</p><blockquote><p>注：<br>1、mos管的gs上拉电阻（R1、R2）需接电压阈较小的一端（3.3V），如果接电压阈高的一端（5V）,高压阈会通过体二极管对低压阈构成回路！即低端电压一定要低于等于高端电压。<br>2、关于速率，如果太快信号也会失真，一般100K以内问题都不大，超出了就要实际观察下波形失真情况了，看下能否接受。</p></blockquote><p>优点：<br>1、适用于低频信号电平转换，价格低廉。<br>2、导通后，压降比三极管小。<br>3、正反向双向导通，相当于机械开关。<br>4、电压型驱动，当然也需要一定的驱动电流，而且有的应用也许比三极管大。</p><p><strong>其他事项：</strong><br>1、3.3V、2.5V、1.8V等电压值的两两之间，需要注意MOS管的Vgs开启导通电压。实际使用时为保证完全开启、完全导通，设计上要多预留余量，<br>比如实际电路中Vgs起码给到1.8V。因为1.8V的设计参数接近数据手册标注的1V临界值，尤其注意用实验验证，确保万无一失。</p><p><img src="/images/双向电平转换/1.png" style="width: 800px;"><br><br>2、给MOS管过高的Vgs会导致MOS管烧坏！<br><img src="/images/双向电平转换/2.png" style="width: 800px;"><br></p>]]>
    </content>
    <id>https://blog.j182010.top/2022/03/10/%E5%8F%8C%E5%90%91%E7%94%B5%E5%B9%B3%E8%BD%AC%E6%8D%A2/</id>
    <link href="https://blog.j182010.top/2022/03/10/%E5%8F%8C%E5%90%91%E7%94%B5%E5%B9%B3%E8%BD%AC%E6%8D%A2/"/>
    <published>2022-03-09T16:00:00.000Z</published>
    <summary>
      <![CDATA[<h1><span id="i2c电平转换">I2C电平转换：</span></h1><p><img src="/images/双向电平转换/0.png" style="width: 1000px;"><br></p>
<p><strong>双向传输原理，分四种情况：</stro]]>
    </summary>
    <title>双向电平转换</title>
    <updated>2026-09-05T13:36:12.040Z</updated>
  </entry>
</feed>
