<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>UinIO.com 电子技术实验室</title>
  
  <subtitle>UinIO.com 电子技术实验室</subtitle>
  <link href="http://www.uinio.com/atom.xml" rel="self"/>
  
  <link href="http://www.uinio.com/"/>
  <updated>2026-02-09T14:53:45.621Z</updated>
  <id>http://www.uinio.com/</id>
  
  <author>
    <name>Hank</name>
    
  </author>
  
  <generator uri="https://hexo.io/">Hexo</generator>
  
  <entry>
    <title>运算放大器 Op-Amp 基本应用与参数选型</title>
    <link href="http://www.uinio.com/Electronics/Amplifier/"/>
    <id>http://www.uinio.com/Electronics/Amplifier/</id>
    <published>2026-02-02T16:00:00.000Z</published>
    <updated>2026-02-09T14:53:45.621Z</updated>
    
    <content type="html"><![CDATA[<p><strong>运算放大器</strong>（Op-Amp，OperationalAmplifier）是一种对信号具有放大功能的电路，实际使用时通常会与<strong>反馈网络</strong>配合起来使用。它能够对输入信号进行<code>加</code>、<code>减</code>、<code>微分</code>、<code>积分</code>等数学运算之后再进行输出，因而被广泛应用于信号处理、仪器仪表等领域。美国<strong>仙童</strong>（Fairchild）公司于1965 年先后推出了运算放大器芯片 <strong>μA702</strong> 和<strong>μA709</strong>，标志着运算放大电路进入了集成电路时代。该公司后于1968 年再次推出了极为经典的 <strong>μA741</strong>运算放大器芯片，至今仍然在被广泛应用。</p><p><img src="/Electronics/Amplifier/logo.png"></p><p>伴随近些年运算放大器电路设计与制造技术的不断进步，各种类型的运放芯片百花齐放。例如：<strong>差动运放</strong>（放大两个输入信号的差值，并且抑制共模信号）、<strong>全差分运放</strong>（输入和输出都是差分信号）、<strong>仪表放大器</strong>（具有极高的共模抑制比与输入阻抗）、<strong>可变增益放大器VGA</strong>（增益由外部电压进行控制）、<strong>可编程增益放大器PGA</strong>（通过数字信号控制运放增益）、<strong>隔离放大器</strong>（输入端与输出端之间存在<code>电容</code>、<code>电感</code>、<code>光电</code>等方式的电气隔离）、<strong>轨到轨运放</strong>（输入和输出电压可以接近电源电压的范围）、<strong>电流检测放大器</strong>（通过检测采样电阻两端的微小电压差实现，并且能够工作在远高于自身电源幅值的共模电压场景）、<strong>跨导放大器</strong>（用于将电压输入转换为电流输出）、<strong>跨阻放大器</strong>（用于将电流输入转换为电压输出）、<strong>精密运算放大器</strong>(输入失调电压<span class="math inline">\(V_{OS}&lt;1mV\)</span>)。</p><span id="more"></span><h2 id="输入比较器">输入比较器</h2><p>标准<strong>运算放大器</strong>（<strong>Op Amp</strong>，OperationalAmplifier）是一个<strong>双输入单输出</strong>的集成电路元器件，其电路原理图符号标记正号 <code>+</code> 的是<strong>同相输入端</strong><span class="math inline">\(V_P\)</span>（输入信号与输出信号相位相同），而标记负号<code>-</code> 的是<strong>反相输入端</strong> <span class="math inline">\(V_N\)</span>（输入信号与输出信号相位相反），<strong>输出端</strong>则使用<span class="math inline">\(V_O\)</span> 进行表示：</p><p><img src="/Electronics/Amplifier/1.png"></p><p>运算放大器的<strong>开环增益</strong>（Open-LoopGain）是指在没有接入任何反馈环路的情况下，输入端信号 <span class="math inline">\(V_N\)</span> 和 <span class="math inline">\(V_P\)</span> 与输出端信号 <span class="math inline">\(V_O\)</span>之间的增益关系，它们之间遵循着如下的计算关系：</p><p><span class="math display">\[(同相输入端 V_P - 反相输入端 V_N) \times 开环增益 = 输出端 V_O\]</span></p><p>标准运算放大器需要单独的<strong>电源</strong>进行供电，主要划分<strong>双电源</strong>和<strong>单电源</strong>两种供电形式，对于双电源供电运放，其输出可以在<strong>零电压两侧</strong>进行变化。而采用单电源供电的运放，其输出只会在<strong>电源正极与地</strong>之间的某个范围内进行变化。运算放大器电源电压范围的上下限也被称作<strong>电源轨</strong>（Rail），由于运放的输出电压在接近电源轨时会发生<strong>饱和</strong>现象，所以该参数决定着运放输出电压幅值的上下限，具体关系可以参照下面的列表：</p><ul><li>当 <strong>同相输入端</strong> <span class="math inline">\(V_P\)</span> 减去 <strong>反相输入端</strong><span class="math inline">\(V_N\)</span>为<strong>正值</strong>，那么其<strong>输出端</strong> <span class="math inline">\(V_O\)</span>约等于电源轨电压的<strong>上限值</strong>；</li><li>当 <strong>同相输入端</strong> <span class="math inline">\(V_P\)</span> 减去 <strong>反相输入端</strong><span class="math inline">\(V_N\)</span>为<strong>负值</strong>，那么其<strong>输出端</strong> <span class="math inline">\(V_O\)</span>约等于电源轨电压的<strong>下限值</strong>；</li></ul><blockquote><p><strong>注意</strong>：换而言之，虽然标准运算放大器的<strong>开环增益</strong>非常大，但是其输出的上下限值依然受到当前电源轨的约束。</p></blockquote><p>例如，当 <strong>同相输入端</strong> <span class="math inline">\(V_P= 1.8V\)</span>，<strong>反相输入端</strong> <span class="math inline">\(V_N =1.5V\)</span>，则运放的<strong>输出端</strong> <span class="math inline">\(V_O = 12V\)</span>：</p><p><img src="/Electronics/Amplifier/2.png"></p><p>反之，如果 <strong>同相输入端</strong> <span class="math inline">\(V_P = 1.5V\)</span>，<strong>反相输入端</strong><span class="math inline">\(V_N = 1.8V\)</span>的时候，那么运算放大器的输出端电压 <span class="math inline">\(V_O =0V\)</span>：</p><p><img src="/Electronics/Amplifier/3.png"></p><p>运算放大器这种开环的使用方式，相当于是在对两个输入端的电压进行比较，因而被称作<strong>输入比较器</strong>。</p><h2 id="电压跟随器">电压跟随器</h2><p>如果直接把运算放大器的<strong>输出端</strong> <span class="math inline">\(V_O\)</span> 与<strong>反相输入端</strong> <span class="math inline">\(V_N\)</span>连接在一起，实时的将输出结果反馈至反相输入端，进而形成动态的<strong>负反馈</strong>（NegativeFeedback）网络：</p><p><img src="/Electronics/Amplifier/4.png"></p><p>如果这种反馈速度非常迅速（也就是形成了<strong>深度负反馈</strong>），最终就会使得<strong>输出端</strong><span class="math inline">\(V_O\)</span>无限接近于<strong>同相输入端</strong> <span class="math inline">\(V_P\)</span> 的值，形成类似 <span class="math inline">\(V_N = V_P = V_O\)</span>的关系，这种带有负反馈的运算放大器接法被称作<strong>电压跟随器</strong>。当运算放大器加入负反馈机制之后，随之会引入<strong>虚短</strong>和<strong>虚断</strong>两个非常重要的概念：</p><ul><li><strong>虚断</strong>：运算放大器输入端的输入阻抗被设计成了无穷大，导致几乎不会有电流进入到输入端（仅仅只感测电压），类似于<strong>电流</strong>通路被<strong>断开。</strong></li></ul><p><img src="/Electronics/Amplifier/5.png"></p><ul><li><strong>虚短</strong>：在形成深度负反馈之后，<strong>同相输入端</strong><span class="math inline">\(V_P\)</span> 与<strong>反相输入端</strong><span class="math inline">\(V_N\)</span>两端的电压相等，类似于两端<strong>电压</strong>是被<strong>短路</strong>在一起的。</li></ul><p><img src="/Electronics/Amplifier/6.png"></p><h2 id="同相反相放大器">同相/反相放大器</h2><p>同相和反相放大器属于运算放大器比较基本的配置方式，两者主要区别在于输入端的连接方式，以及输入信号与输出信号之间的相位关系：</p><ol type="1"><li><strong>同相放大器</strong>：增益为<strong>正</strong><code>+</code>，输出信号与输入信号同相，其<strong>输入信号</strong>连接到运算放大器的同相输入端，<strong>反馈网络</strong>连接到反相输入端；</li><li><strong>反相放大器</strong>：增益为<strong>负</strong><code>-</code>，输出信号与输入信号反相（存在 <code>180°</code>相位差），其<strong>输入信号</strong>和<strong>反馈网络</strong>都连接到运算放大器的反相输入端，而同相输入端直接连接到地。</li></ol><h3 id="同相放大器">同相放大器</h3><p>接下来，讨论下面这个<strong>同相放大器</strong>的连接方法，其最显著的特点是<strong>反相输入端</strong>与<strong>输出端</strong>通过电阻网络（电阻<span class="math inline">\(R_2\)</span>通常被称作<strong>反馈[Feedback]电阻</strong> <span class="math inline">\(R_F\)</span>，而 <span class="math inline">\(R_1\)</span>则被称作<strong>增益[Gain]电阻</strong> <span class="math inline">\(R_G\)</span>）连接在一起，从而形成了<strong>深度负反馈</strong>：</p><p><img src="/Electronics/Amplifier/7.png"></p><p>由于运算放大器<strong>虚短</strong>的存在，其<strong>同相输入端</strong><span class="math inline">\(V_P\)</span> 与<strong>反相输入端</strong><span class="math inline">\(V_N\)</span>两端的电压相等，作用效果类似于这两端直接被连接在一起：</p><p><img src="/Electronics/Amplifier/8.png"></p><p>同时又由于<strong>虚断</strong>的存在，其反相输入端的输入阻抗无穷大，效果类似于连接断开，因此可以将运算放大器的<strong>输出端</strong><span class="math inline">\(V_O\)</span> 与<strong>电阻</strong> <span class="math inline">\(R_1\)</span> 和 <span class="math inline">\(R_2\)</span> 等效为一个串联回路：</p><p><img src="/Electronics/Amplifier/9.png"></p><p>综合上述分析，基于<strong>欧姆定律</strong> <span class="math inline">\(I = \frac{U}{R}\)</span>以及<strong>串联电阻</strong> <span class="math inline">\(R_1\)</span>与 <span class="math inline">\(R_2\)</span>上通过的电流相等，可以得到下面的数学推导过程：</p><p><span class="math display">\[I = \frac{U}{R}\implies\frac{V_{I} - 0}{R_1} = \frac{V_{O} - 0}{R_1}\impliesV_O = V_I \times (1 + \frac{R_2}{R_1})\]</span></p><p>根据上面的推导结果，如果<strong>电阻</strong> <span class="math inline">\(R_1\)</span> 和 <span class="math inline">\(R_2\)</span> 的阻值均为<code>1kΩ</code>，那么<strong>输出电压</strong> <span class="math inline">\(V_O\)</span> 将会是<strong>输入电压</strong> <span class="math inline">\(V_I\)</span> 的两倍关系：</p><p><span class="math display">\[V_O = V_I \times (1 + \frac{1kΩ}{1kΩ})= V_I \times 2\]</span></p><p>由此可见，通过反馈回路上串联的两颗电阻值，就可以调节运算放大器的增益（但是依然会受到电源轨上下限值的约束）。</p><h3 id="反相放大器">反相放大器</h3><p>接下来，继续讨论下图所示<strong>反相放大器</strong>的连接配置方法，以及输入端和输出端之间的数学关系：</p><p><img src="/Electronics/Amplifier/10.png"></p><p>同样基于运算放大器的<strong>虚短</strong>和<strong>虚断</strong>现象，以及<strong>欧姆定律</strong><span class="math inline">\(I = \frac{U}{R}\)</span>和<strong>串联电阻</strong> <span class="math inline">\(R_1\)</span> 和<span class="math inline">\(R_2\)</span>上经过的电流相同等条件，就可以得到如下的推导过程：</p><p><span class="math display">\[I = \frac{U}{R}\implies\frac{0-V_I}{R_1} = \frac{V_O - 0}{R_2}\impliesV_O = V_I \times - \frac{R_2}{R_1}\]</span></p><p>根据上述推导关系，如果<strong>电阻</strong> <span class="math inline">\(R_1\)</span> 和 <span class="math inline">\(R_2\)</span> 的阻值均等于<code>1kΩ</code>，那么<strong>输出电压</strong> <span class="math inline">\(V_O\)</span> 将会与<strong>输入电压</strong> <span class="math inline">\(V_I\)</span> 呈现出反相的关系：</p><p><span class="math display">\[V_O = V_I \times (- \frac{1kΩ}{1kΩ})= V_I \times -1\]</span></p><blockquote><p><strong>注意</strong>：反相放大器的<strong>电源轨</strong>分别接入的是<strong>正电源</strong>和<strong>负电源</strong>，这是因为其输出信号反相，信号的幅值就会低于<code>0V</code>。</p></blockquote><h2 id="静态选型参数">静态选型参数</h2><table><colgroup><col style="width: 12%"><col style="width: 7%"><col style="width: 80%"></colgroup><thead><tr><th>静态参数</th><th>英文名称</th><th>功能描述</th></tr></thead><tbody><tr><td><strong>输入失调电压</strong> <span class="math inline">\(V_{OS}\)</span></td><td>Offset Voltage</td><td>该参数是由于运放内部晶体管在生产制造时的不对称性，导致开环使用时能够使其输出端呈现为<code>0V</code>，因而需要施加在两个输入端之间的差分补偿电压。</td></tr><tr><td><strong>输入失调电压漂移</strong> <span class="math inline">\(dV_{OS}/dT\)</span></td><td>Offset Voltage Drift</td><td>用于表征环境温度每变化<code>1°C</code>，运算放大器的<strong>输入失调电压</strong> <span class="math inline">\(V_{OS}\)</span> 对应的变化量，即 <span class="math inline">\(V_{OS}\)</span> 随环境温度进行变化的特性，通常使用<code>µV/°C</code> 或 <code>mV/°C</code> 作为计量单位。</td></tr><tr><td><strong>输入偏置电流</strong> <span class="math inline">\(I_B\)</span></td><td>Input Bias Current</td><td>运算放大器正常工作时，其输入端<strong>流入</strong>或者<strong>流出</strong>的电流。（该参数源于运放内部的晶体管，需要维持一定电流才能确保其处于合适的工作点）。</td></tr><tr><td><strong>输入失调电流</strong> <span class="math inline">\(I_{OS}\)</span></td><td>Input Offset Current</td><td>用于描述运算放大器正常工作时，两个输入端的<strong>输入偏置电流</strong><span class="math inline">\(Ib\)</span> 之间产生的差值。</td></tr><tr><td><strong>输入电压范围</strong></td><td>Input Voltage Range</td><td>确保运算放大器正常工作，且满足数据手册性能指标的前提下，其最大的输入电压范围。该参数通常被更为具象的<strong>共模输入电压范围</strong>（两个输入端电压的平均值）和<strong>差模输入电压范围</strong>（两个输入端电压的差值）两个参数来进行表征。</td></tr><tr><td><strong>输出电压范围</strong></td><td>Output Voltage Swing</td><td>运算放大器能够输出的最大和最小电压范围值，通常采用其与正负<strong>电源轨</strong>的<strong>压差</strong>来进行表示（<strong>轨到轨运放</strong>的输出电压接近电源轨，<strong>非轨到轨运放</strong>的输出电压与电源轨存在明显压降）。</td></tr></tbody></table><h2 id="动态选型参数">动态选型参数</h2><table><colgroup><col style="width: 6%"><col style="width: 8%"><col style="width: 85%"></colgroup><thead><tr><th>动态参数</th><th>英文名称</th><th>功能描述</th></tr></thead><tbody><tr><td><strong>开环增益</strong> <span class="math inline">\(A_{OL}\)</span></td><td>Open Loop Gain</td><td>用于描述运算放大器没有反馈网络的情况下，对于两个输入端之间的<strong>电压差</strong>进行放大和增益的能力，通常以具体的<strong>增益倍数</strong>或者<strong>分贝</strong><code>dB</code> 进行表示。</td></tr><tr><td><strong>共模抑制比</strong> <span class="math inline">\(CMRR\)</span></td><td>Common Mode Rejection Ratio</td><td>用于表征运算放大器抑制<strong>共模信号</strong>干扰的能力，单位为<code>dB</code><strong>分贝</strong>。理想情况下运放只会放大<strong>差模信号</strong>（即两个输入端之间的压差），但由于内部电路的非理想特性，导致一些共模信号也随之被放大。该参数等于<strong>差模电压增益</strong>（差模输入信号与输出的关系）与<strong>共模电压增益</strong>（共模输入信号与输出的关系）的比值<span class="math inline">\(20\log(\frac{A_d}{A_c})\)</span>。</td></tr><tr><td><strong>电源电压抑制比</strong> <span class="math inline">\(PSRR\)</span></td><td>Power Supply Rejection Ratio</td><td>用于表征运放抵制电源电压波动被耦合到输出的能力，即抑制电源电压波动或者纹波的能力，其值等于<span class="math inline">\(\frac{电源电压变化量 \Delta V_S}{\Delta电源电压变化引发的输入失调电压变化量V_{io}}\)</span>，该参数值越大抗干扰能力就越强。</td></tr><tr><td><strong>压摆率</strong> <span class="math inline">\(SR\)</span></td><td>Slew Rate</td><td>用于表征运放输出电压能够达到的最大变化速率，即运放相对于时间的最大瞬时变化率<span class="math inline">\(\vert \frac{输出电压 dV_{out}}{时间 dt}\vert_{max}\)</span>，该参数通常使用 <code>V/µs</code> 或者<code>V/ms</code> 作为单位。</td></tr><tr><td><strong>建立时间</strong> <span class="math inline">\(t_S\)</span></td><td>Settling Time</td><td>表达的是将运放配置为指定增益（通常为<code>1</code>），从开始输入阶跃信号到输出进入指定误差范围（例如<code>±0.1%</code>、<code>±0.01%</code>、<code>±0.001%</code>）所需要的总时间。</td></tr><tr><td><strong>相位裕度</strong> <span class="math inline">\(\varphi_m\)</span></td><td>Phase Margin</td><td>开环增益下降到 <code>1</code> 或者 <code>0dB</code>时，开环相移值减去 <code>-180°</code> 得到的差值，即开环增益为<code>1</code> 的时候，运放还能够容忍多大的相移而不会发生自激振荡。</td></tr><tr><td><strong>增益裕度</strong> <span class="math inline">\(GM\)</span></td><td>Gain Margin</td><td>表示运算放大器在开环相移达到 <code>-180°</code>的时候，距离自激振荡（开环增益为 <code>1</code> 或者<code>0dB</code>）还存在多少增益余量。</td></tr><tr><td><strong>总谐波失真+噪声</strong> <span class="math inline">\(THD+N\)</span></td><td>Total Harmonic Distortion + Noise</td><td>衡量运算放大器输出信号纯净度的综合指标，给运放输入一个精确的固定频率正弦波，输出当中除了输入频率的<strong>基波</strong>之外，还会产生n次<strong>谐波分量</strong>，这些<strong>谐波分量的功率总和</strong>的有效值和与<strong>基波功率</strong>的比值<span class="math inline">\(\frac{\sqrt{V_{2次谐波}^2 + V_{3次谐波}^3 +... + V_{n次谐波}^2 + V_{噪声}^2}}{V_{基波}}\)</span>就是总谐波失真，通常使用百分数 <code>%</code> 或者 <code>dB</code>作为单位进行表示。</td></tr><tr><td><strong>热阻</strong> <span class="math inline">\(R_{\thetaJA}\)</span></td><td>Thermal Resistance</td><td>用于衡量运算放大器的散热能力，运放每消耗 <code>1W</code>功率，内部<strong>结温</strong> <span class="math inline">\(T_J\)</span>相对于环境温度 <span class="math inline">\(T_A\)</span> 升高的值（单位为<code>°C/W</code>），即 <span class="math inline">\(结温 T_J = 环境温度T_A + 运放消耗的功率 P_D \times 热阻 R_{\thetaJA}\)</span>，该参数值越小，运放的散热就会越好。</td></tr><tr><td></td><td></td><td></td></tr></tbody></table><h2 id="动态带宽参数">动态带宽参数</h2><table><colgroup><col style="width: 9%"><col style="width: 10%"><col style="width: 80%"></colgroup><thead><tr><th>动态带宽参数</th><th>英文名称</th><th>功能描述</th></tr></thead><tbody><tr><td><strong>单位增益带宽</strong> <span class="math inline">\(UGBW\)</span></td><td>Unity Gain Bandwidth</td><td>当输入信号的频率<strong>高于</strong>该参数时，运算放大器的<strong>开环增益</strong>将会小于<code>1</code>，即此时不再具备放大能力。</td></tr><tr><td><strong>增益带宽积</strong> <span class="math inline">\(GBW\)</span></td><td>Gain Bandwidth Product</td><td>运算放大器的<strong>开环增益</strong> <span class="math inline">\(A_{OL}\)</span>（即放大倍数）与其<strong>频率</strong><span class="math inline">\(f\)</span>的乘积，在某个特定频率范围之内会近似为一个<strong>常数</strong>（例如频率提高<code>10</code> 倍，开环增益降低 <code>0.1</code>倍，其乘积就是一个常数），该常数就是增益带宽积。</td></tr><tr><td><strong>闭环 -3dB 带宽</strong></td><td>Closed-Loop -3dB Bandwidth</td><td>指运算放大器<strong>增益下降到</strong> <code>-3dB</code><strong>时刻</strong>（半功率点）的带宽，该参数决定了运放电路能够处理的最大频率范围，超出该范围的信号将会发生衰减。</td></tr><tr><td><strong>满功率带宽</strong> <span class="math inline">\(FPBW\)</span></td><td>Full Power Bandwidth</td><td>运放在该参数频率范围之内，能够实现满幅度输出（即输出不会发生衰减），因而也被称作<strong>满幅带宽</strong>，其值等于<span class="math inline">\(\frac{压摆率 SR}{2 \pi \cdot 峰值输出电压V_{max}}\)</span>，单位为赫兹 <code>Hz</code>。</td></tr></tbody></table>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;strong&gt;运算放大器&lt;/strong&gt;（Op-Amp，Operational
Amplifier）是一种对信号具有放大功能的电路，实际使用时通常会与&lt;strong&gt;反馈网络&lt;/strong&gt;配合起来使用。它能够对输入信号进行
&lt;code&gt;加&lt;/code&gt;、&lt;code&gt;减&lt;/code&gt;、&lt;code&gt;微分&lt;/code&gt;、&lt;code&gt;积分&lt;/code&gt;
等数学运算之后再进行输出，因而被广泛应用于信号处理、仪器仪表等领域。美国&lt;strong&gt;仙童&lt;/strong&gt;（Fairchild）公司于
1965 年先后推出了运算放大器芯片 &lt;strong&gt;μA702&lt;/strong&gt; 和
&lt;strong&gt;μA709&lt;/strong&gt;，标志着运算放大电路进入了集成电路时代。该公司后于
1968 年再次推出了极为经典的 &lt;strong&gt;μA741&lt;/strong&gt;
运算放大器芯片，至今仍然在被广泛应用。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/Electronics/Amplifier/logo.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;伴随近些年运算放大器电路设计与制造技术的不断进步，各种类型的运放芯片百花齐放。例如：&lt;strong&gt;差动运放&lt;/strong&gt;（放大两个输入信号的差值，并且抑制共模信号）、&lt;strong&gt;全差分运放&lt;/strong&gt;（输入和输出都是差分信号）、&lt;strong&gt;仪表放大器&lt;/strong&gt;（具有极高的共模抑制比与输入阻抗）、&lt;strong&gt;可变增益放大器
VGA&lt;/strong&gt;（增益由外部电压进行控制）、&lt;strong&gt;可编程增益放大器
PGA&lt;/strong&gt;（通过数字信号控制运放增益）、&lt;strong&gt;隔离放大器&lt;/strong&gt;（输入端与输出端之间存在
&lt;code&gt;电容&lt;/code&gt;、&lt;code&gt;电感&lt;/code&gt;、&lt;code&gt;光电&lt;/code&gt;
等方式的电气隔离）、&lt;strong&gt;轨到轨运放&lt;/strong&gt;（输入和输出电压可以接近电源电压的范围）、&lt;strong&gt;电流检测放大器&lt;/strong&gt;（通过检测采样电阻两端的微小电压差实现，并且能够工作在远高于自身电源幅值的共模电压场景）、&lt;strong&gt;跨导放大器&lt;/strong&gt;（用于将电压输入转换为电流输出）、&lt;strong&gt;跨阻放大器&lt;/strong&gt;（用于将电流输入转换为电压输出）、&lt;strong&gt;精密运算放大器&lt;/strong&gt;
(输入失调电压&lt;span class=&quot;math inline&quot;&gt;&#92;(V_{OS}&amp;lt;1mV&#92;)&lt;/span&gt;)。&lt;/p&gt;</summary>
    
    
    
    <category term="硬件电子技术" scheme="http://www.uinio.com/categories/%E7%A1%AC%E4%BB%B6%E7%94%B5%E5%AD%90%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="芯片" scheme="http://www.uinio.com/tags/%E8%8A%AF%E7%89%87/"/>
    
  </entry>
  
  <entry>
    <title>电子学单位分贝 dB 数学推导与速查表</title>
    <link href="http://www.uinio.com/Math/Decible/"/>
    <id>http://www.uinio.com/Math/Decible/</id>
    <published>2026-01-17T16:00:00.000Z</published>
    <updated>2026-02-10T17:47:51.451Z</updated>
    
    <content type="html"><![CDATA[<p><strong>分贝</strong>（<code>dB</code>，Decibel[ˈdesɪbel]）是一个用于衡量声压等级、信号功率强度的对数无量纲单位，该单位来源于美国的电话发明家<strong>贝尔</strong><code>Alexander Graham Bell</code>的名字，是从<strong>贝尔</strong>（<strong>B</strong>，Bel）这个单位衍生而来（<strong>一贝尔等于十分贝</strong><span class="math inline">\(1Bel =10dB\)</span>），其最初被用于贝尔实验室长途电话线路损耗的计量，从而解决线性度量单位无法描述超过<span class="math inline">\(10^{14}\)</span>数量级的信号强度问题，而后成为<strong>声学</strong>、<strong>电子</strong>、<strong>通信</strong>等领域的通用计量单位。</p><p><img src="/Math/Decible/logo.png"></p><p>分贝并不是一个线性的绝对数值单位，其反映的是两个相同单位物理量的比值，在取对数之后分别再乘以<code>10</code>（<strong>功率类参数</strong>，例如<code>声音功率</code>、<code>电功率</code>）或者<code>20</code>（<strong>场量类参数</strong>，<code>声压</code>、<code>电压</code>、<code>电流</code>、<code>场强</code>），其<strong>反映的是一个相对的数量级，而非一个绝对的数值</strong>。总而言之，由于分贝采用了<strong>对数</strong><span class="math inline">\(y = \log_a x\)</span>来作为单位的标度，因为而能够极大的压缩数值范围并且简化计算，同时也更加适配人类听觉以及信号传输的<strong>非线性感知特性</strong>。</p><span id="more"></span><h2 id="声学当中的分贝">声学当中的分贝</h2><p>最常见的以分贝 <code>dB</code>作为单位的声学参数是<strong>声压级</strong>（<strong>SPL</strong>，SoundPressureLevel），该参数能够压缩人耳所能感知的巨大动态范围，并且匹配人耳对声音强度的非线性感知特性，其计算公式如下面所示：</p><p><span class="math display">\[SPL_{dB} = 20 \cdot \log_{10} \left(\frac{P_{实际声压}}{P_{人类听觉下限参考声压}} \right)\]</span></p><blockquote><p><strong>注意</strong>：人类听觉下限的参考声压通常为<code>20 μPa</code>，即健康人耳在 <code>1 kHz</code>频率声音下的听觉阈值。</p></blockquote><h2 id="功率比分贝公式">功率比分贝公式</h2><p>使用 <strong>分贝</strong> <code>dB</code>作为单位，可以将两个相同物理量的比值，转换为一个<strong>对数</strong>尺度上的值（通过压缩数值表达的动态范围，从而便于表达和计算），电子学当中可以使用该单位来表达<code>功率</code>、<code>电压</code>、<code>电流</code>、<code>增益</code>、<code>衰减</code>等参数，但是其原始定义主要是以<strong>功率比值</strong>来作为基准：</p><p><span class="math display">\[\text{dB} = 10 \cdot \log_{10} \left( \frac{功率值 P_2}{功率值 P_1}\right)\]</span></p><blockquote><p><strong>注意</strong>：上述方程当中的功率值 <span class="math inline">\(P_2\)</span>称为<strong>被测物理量</strong>，而功率值 <span class="math inline">\(P_1\)</span>则被称作<strong>参考基准值</strong>。</p></blockquote><h2 id="复习对数函数的知识">复习对数函数的知识</h2><p>在进一步介绍分贝单位的知识之前，先来温习一些初等代数的知识。初中课本当中将<strong>指数函数</strong>定义为如下的公式（其中<span class="math inline">\(x\)</span> 是<strong>自变量</strong>，<span class="math inline">\(a\)</span> 是<strong>底数</strong>），该函数的<strong>定义域</strong> <span class="math inline">\(x \in R\)</span>，而<strong>值域</strong> <span class="math inline">\(y &gt;0\)</span>：</p><p><span class="math display">\[y = a^x \quad (a &gt; 0, \, a \neq 1)\]</span></p><p>上述这个指数函数，可以在转换形式之后，被定义为<strong>对数函数</strong>的形式，也就是<strong>数</strong><span class="math inline">\(y\)</span> 被称作是以 <span class="math inline">\(a\)</span> 作为<strong>底</strong>的 <span class="math inline">\(x\)</span>的<strong>对数</strong>。此时，这个对数函数的 <strong>定义域</strong><span class="math inline">\(x &gt; 0\)</span>，而 <strong>值域</strong><span class="math inline">\(y \in R\)</span>：</p><p><span class="math display">\[a^y = x（a&gt;0, a\neq 1)\impliesy = \log_a x\]</span></p><p>上述的指数函数和对数函数互为<strong>反函数</strong>，它们在平面直角坐标系的图像关于<strong>直线</strong><span class="math inline">\(y = x\)</span> 对称。换而言之，当 <span class="math inline">\(a&gt;0, a\neq 1\)</span>的时候，<strong>指数函数和对数函数可以相互进行转化</strong>：</p><p><span class="math display">\[a^y = x \Longleftrightarrow y = \log_a x\]</span></p><p><strong>常用对数</strong>（CommonLogarithm）是以<strong>数字</strong> <code>10</code> 作为底的对数 <span class="math inline">\(\log_{10} x\)</span>，可以简写为 <span class="math inline">\(\lg x\)</span>：</p><p><span class="math display">\[\log_{10} x\implies\lg x\]</span></p><p><strong>自然对数</strong>（NaturalLogarithm）则是以<strong>自然常数</strong> <span class="math inline">\(e≈2.718281828\)</span> 作为底数的对数：</p><p><span class="math display">\[\log_e x\implies\ln x\]</span></p><h2 id="建立功率与电压和电流的关系">建立功率与电压和电流的关系</h2><p>根据<strong>欧姆定律</strong> <span class="math inline">\(I =\frac{V}{R}\)</span> 以及<strong>功率计算公式</strong> <span class="math inline">\(P = I \cdotV\)</span>，可以分别得到<strong>功率</strong> <span class="math inline">\(P\)</span> 分别与<strong>电压</strong> <span class="math inline">\(V\)</span> 以及<strong>电流</strong> <span class="math inline">\(I\)</span> 之间的换算关系：</p><p><span class="math display">\[\begin{cases}I = \frac{V}{R} \\P = I \cdot V\end{cases}\implies\begin{align}&amp; P = \frac{V^2}{R} \\&amp; P = I^2 R\end{align}\]</span></p><h2 id="推导电压分贝公式">推导电压分贝公式</h2><p>假设当前存在两个不同的<strong>电压</strong> <span class="math inline">\(V_2\)</span> 和 <span class="math inline">\(V_1\)</span>分别作用在相同的<strong>负载电阻</strong> <span class="math inline">\(R\)</span> 上面，则可以推导出：</p><ul><li>当<strong>负载电阻</strong> <span class="math inline">\(R\)</span>相同，并且<strong>电压</strong>等于 <span class="math inline">\(V_1\)</span> 时，此时<strong>功率</strong>的值等于<span class="math inline">\(P_1 = \frac{V_1^2}{R}\)</span>；</li><li>当<strong>负载电阻</strong> <span class="math inline">\(R\)</span>相同，并且<strong>电压</strong>等于 <span class="math inline">\(V_2\)</span> 时，此时<strong>功率</strong>的值等于<span class="math inline">\(P_2 = \frac{V_2^2}{R}\)</span>；</li></ul><p>根据上述关系，进而就可以计算出 <span class="math inline">\(P_2\)</span> 和 <span class="math inline">\(P_1\)</span> 两个功率的比值：</p><p><span class="math display">\[\frac{P_2}{P_1} = \frac{\frac{V_2^2}{R}}{\frac{V_1^2}{R}} =\frac{V_2^2}{R} \times \frac{R}{V_1^2} = \frac{V_2^2}{V_1^2} = \left(\frac{V_2}{V_1} \right)^2\]</span></p><p>可以发现公式当中的<strong>负载电阻</strong> <span class="math inline">\(R\)</span>被省略，说明<strong>只要两个电路的负载电阻相等，它们功率的比值就等于电压比值的平方</strong>。接下来，将这个功率的比值<span class="math inline">\(\frac{P_2}{P_1} =(\frac{V_2}{V_1})^2\)</span>，代入到上述功率分贝的定义 <span class="math inline">\(10 \log_{10}(\frac{P_2}{P_1})\)</span> 当中：</p><p><span class="math display">\[\text{dB} = 10 \log*{10} \left( \frac{P_2}{P_1} \right) = 10 \log*{10}\left( \left( \frac{V_2}{V_1} \right)^2 \right)\]</span></p><p>使用对数的运算法则 <span class="math inline">\(\log_b (x^y) = y\log_b (x)\)</span>进行化简，就可以推导出<strong>电压增益分贝</strong>的计算公式：</p><p><span class="math display">\[\text{dB} = 10 \times \left[ \log_{10} \left( \left( \frac{V_2}{V_1}\right)^2 \right) \right] = 10 \times \left[ 2 \times \log_{10} \left(\frac{V_2}{V_1} \right) \right]  = 20 \log_{10} \left( \frac{V_2}{V_1}\right)\]</span></p><h2 id="推导电流分贝公式">推导电流分贝公式</h2><p>类似于前面电压增益分贝公式的推导过程，假设当前存在两个不同的<strong>电流</strong><span class="math inline">\(I_2\)</span> 和 <span class="math inline">\(I_1\)</span>分别通过相同的<strong>负载电阻</strong> <span class="math inline">\(R\)</span> 可以推导出：</p><ul><li>当电流 <span class="math inline">\(I_1\)</span>通过相同的<strong>负载电阻</strong> <span class="math inline">\(R\)</span> 时，<strong>功率</strong>的值等于 <span class="math inline">\(P_1 = I_1^2 R\)</span>；</li><li>当电流 <span class="math inline">\(I_2\)</span>通过相同的<strong>负载电阻</strong> <span class="math inline">\(R\)</span> 时，<strong>功率</strong>的值等于 <span class="math inline">\(P_2 = I_2^2 R\)</span>；</li></ul><p>根据上述关系，进而就可以计算出 <span class="math inline">\(P_2\)</span> 和 <span class="math inline">\(P_1\)</span> 两个功率的比值：</p><p><span class="math display">\[\frac{P_2}{P_1} = \frac{I_2^2 R}{I_1^2 R} = \frac{I_2^2}{I_1^2} = \left(\frac{I_2}{I_1} \right)^2\]</span></p><p>同样可以发现公式当中的<strong>负载电阻</strong> <span class="math inline">\(R\)</span>被略去，说明<strong>只要两个电路的负载电阻相等，它们功率的比值就等于电流比值的平方</strong>。接下来，依然将这个功率的比值<span class="math inline">\(\frac{P_2}{P_1} =(\frac{I_2}{I_1})^2\)</span>，代入到上述功率分贝的定义 <span class="math inline">\(10 \log_{10}(\frac{P_2}{P_1})\)</span> 当中：</p><p><span class="math display">\[\text{dB} = 10 \log*{10} \left( \frac{P_2}{P_1} \right) = 10 \log*{10}\left( \left( \frac{I_2}{I_1} \right)^2 \right)\]</span></p><p>使用对数的运算法则 <span class="math inline">\(\log_b (x^y) = y\log_b (x)\)</span>进行化简，就可以推导出<strong>电流增益分贝</strong>的计算公式：</p><p><span class="math display">\[\text{dB} = 10 \times \left[ \log_{10} \left( \left( \frac{I_2}{I_1}\right)^2 \right) \right] = 10 \times \left[ 2 \times \log_{10} \left(\frac{I_2}{I_1} \right) \right]  = 20 \log_{10} \left( \frac{I_2}{I_1}\right)\]</span></p><h2 id="电子学分贝单位的总结">电子学分贝单位的总结</h2><p>综上所诉，<strong>功率类</strong>的比值全部使用 <span class="math inline">\(10 \cdot log_{10}()\)</span>作为<strong>对数分贝公式</strong>，而在相同<strong>负载电阻</strong><span class="math inline">\(R\)</span> 的前提下，涉及 <code>电压</code>与 <code>电流</code> 等<strong>幅值类</strong>参数的平方关系比值，则使用<span class="math inline">\(20 \cdot log_{10}()\)</span>作为<strong>对数分贝公式</strong>：</p><table><thead><tr><th style="text-align: left;">物理量</th><th style="text-align: left;">关系公式</th><th style="text-align: left;">分贝公式</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>功率</strong> <span class="math inline">\(P\)</span></td><td style="text-align: left;"><span class="math inline">\(P =VI\)</span></td><td style="text-align: left;"><span class="math inline">\(10\log_{10}(\frac{P_2}{P_1})\)</span></td></tr><tr><td style="text-align: left;"><strong>电压</strong> <span class="math inline">\(V\)</span></td><td style="text-align: left;"><span class="math inline">\(P = V^2 /R\)</span></td><td style="text-align: left;"><span class="math inline">\(20\log_{10}(\frac{V_2}{V_1})\)</span></td></tr><tr><td style="text-align: left;"><strong>电流</strong> <span class="math inline">\(I\)</span></td><td style="text-align: left;"><span class="math inline">\(P = I^2R\)</span></td><td style="text-align: left;"><span class="math inline">\(20\log_{10}(\frac{I_2}{I_1})\)</span></td></tr></tbody></table><h2 id="常用分贝值速查表">常用分贝值速查表</h2><p>本节内容的表格总结了 <code>0 ~ ±100dB</code>常用分贝值之间的换算关系。</p><h3 id="正分贝值-0-100db-速查表">正分贝值 <code>0 ~ +100dB</code>速查表</h3><table style="width:100%;"><colgroup><col style="width: 8%"><col style="width: 12%"><col style="width: 12%"><col style="width: 7%"><col style="width: 12%"><col style="width: 12%"><col style="width: 8%"><col style="width: 12%"><col style="width: 12%"></colgroup><thead><tr><th>分贝 dB</th><th>功率类</th><th>幅值类</th><th>分贝 dB</th><th>功率类</th><th>幅值类</th><th>分贝 dB</th><th>功率类</th><th>幅值类</th></tr></thead><tbody><tr><td><strong>+0</strong></td><td>1</td><td>1</td><td><strong>+21</strong></td><td>125.8925412</td><td>11.22018454</td><td><strong>+61</strong></td><td>1258925.412</td><td>1122.018454</td></tr><tr><td><strong>+0.1</strong></td><td>1.023292992</td><td>1.011579454</td><td><strong>+22</strong></td><td>158.4893192</td><td>12.58925412</td><td><strong>+62</strong></td><td>1584893.192</td><td>1258.925412</td></tr><tr><td><strong>+0.2</strong></td><td>1.047128548</td><td>1.023292992</td><td><strong>+23</strong></td><td>199.5262315</td><td>14.12537545</td><td><strong>+63</strong></td><td>1995262.315</td><td>1412.537545</td></tr><tr><td><strong>+0.3</strong></td><td>1.071519305</td><td>1.035142167</td><td><strong>+24</strong></td><td>251.1886432</td><td>15.84893192</td><td><strong>+64</strong></td><td>2511886.432</td><td>1584.893192</td></tr><tr><td><strong>+0.4</strong></td><td>1.046478196</td><td>1.047128548</td><td><strong>+25</strong></td><td>316.227766</td><td>17.7827941</td><td><strong>+65</strong></td><td>3162277.66</td><td>1778.27941</td></tr><tr><td><strong>+0.5</strong></td><td>1.122018454</td><td>1.059253725</td><td><strong>+26</strong></td><td>398.1071706</td><td>19.95262315</td><td><strong>+66</strong></td><td>3981071.706</td><td>1995.262315</td></tr><tr><td><strong>+0.6</strong></td><td>1.148153621</td><td>1.071519305</td><td><strong>+27</strong></td><td>501.1872336</td><td>22.38721139</td><td><strong>+67</strong></td><td>5011872.336</td><td>2238.721139</td></tr><tr><td><strong>+0.7</strong></td><td>1.174897555</td><td>1.803926914</td><td><strong>+28</strong></td><td>630.9573445</td><td>25.11886432</td><td><strong>+68</strong></td><td>6309573.445</td><td>2511.886432</td></tr><tr><td><strong>+0.8</strong></td><td>1.202264435</td><td>1.096478196</td><td><strong>+29</strong></td><td>794.3282347</td><td>28.18382931</td><td><strong>+69</strong></td><td>7943282.347</td><td>2818.382931</td></tr><tr><td><strong>+0.9</strong></td><td>1.230268771</td><td>1.109174815</td><td><strong>+30</strong></td><td>1000</td><td>31.6227766</td><td><strong>+70</strong></td><td>10000000</td><td>3162.27766</td></tr><tr><td><strong>+1</strong></td><td>1.258925412</td><td>1.122018454</td><td><strong>+31</strong></td><td>1258.925412</td><td>35.48133892</td><td><strong>+71</strong></td><td>12589254.12</td><td>3548.133892</td></tr><tr><td><strong>+1.5</strong></td><td>1.412537545</td><td>1.188502227</td><td><strong>+32</strong></td><td>1584.893192</td><td>39.81071706</td><td><strong>+72</strong></td><td>15848931.92</td><td>3981.071706</td></tr><tr><td><strong>+2</strong></td><td>1.584893192</td><td>1.258925412</td><td><strong>+33</strong></td><td>1995.262315</td><td>44.66835922</td><td><strong>+73</strong></td><td>19952623.15</td><td>4466.835922</td></tr><tr><td><strong>+2.5</strong></td><td>1.77827941</td><td>1.333521432</td><td><strong>+34</strong></td><td>2511.886432</td><td>50.11872336</td><td><strong>+74</strong></td><td>25118864.32</td><td>5011.872336</td></tr><tr><td><strong>+3</strong></td><td>1.995262315</td><td>1.412537545</td><td><strong>+35</strong></td><td>3162.27766</td><td>56.23413252</td><td><strong>+75</strong></td><td>31622776.6</td><td>5623.413252</td></tr><tr><td><strong>+3.5</strong></td><td>2.238721139</td><td>1.496235656</td><td><strong>+36</strong></td><td>3981.071706</td><td>63.09573445</td><td><strong>+76</strong></td><td>39810717.06</td><td>6309.573445</td></tr><tr><td><strong>+4</strong></td><td>2.511886432</td><td>1.584893192</td><td><strong>+37</strong></td><td>5011.872336</td><td>70.79457844</td><td><strong>+77</strong></td><td>50118723.36</td><td>7079.457844</td></tr><tr><td><strong>+4.5</strong></td><td>2.819838293</td><td>1.678804018</td><td><strong>+38</strong></td><td>6309.573445</td><td>79.43282347</td><td><strong>+78</strong></td><td>63095734.45</td><td>7943.282347</td></tr><tr><td><strong>+5</strong></td><td>3.16227766</td><td>1.77827941</td><td><strong>+39</strong></td><td>7943.282347</td><td>89.12509381</td><td><strong>+79</strong></td><td>79432823.47</td><td>8912.509381</td></tr><tr><td><strong>+5.5</strong></td><td>3.548133829</td><td>1.883649089</td><td><strong>+40</strong></td><td>10000</td><td>100</td><td><strong>+80</strong></td><td>100000000</td><td>10000</td></tr><tr><td><strong>+6</strong></td><td>3.981071706</td><td>1.995262315</td><td><strong>+41</strong></td><td>12589.25412</td><td>112.2018454</td><td><strong>+81</strong></td><td>125892541.2</td><td>11220.18454</td></tr><tr><td><strong>+6.5</strong></td><td>4.466835922</td><td>2.11348904</td><td><strong>+42</strong></td><td>15848.93192</td><td>125.8925412</td><td><strong>+82</strong></td><td>158489319.2</td><td>12589.25412</td></tr><tr><td><strong>+7</strong></td><td>5.011872336</td><td>2.238721139</td><td><strong>+43</strong></td><td>19952.62315</td><td>141.2537545</td><td><strong>+83</strong></td><td>199526231.5</td><td>14125.37545</td></tr><tr><td><strong>+7.5</strong></td><td>5.623413252</td><td>2.371373706</td><td><strong>+44</strong></td><td>25118.86432</td><td>158.4893192</td><td><strong>+84</strong></td><td>251188643.2</td><td>15848.93192</td></tr><tr><td><strong>+8</strong></td><td>6.309573445</td><td>2.511886432</td><td><strong>+45</strong></td><td>31622.7766</td><td>177.827941</td><td><strong>+85</strong></td><td>316227766</td><td>17782.7941</td></tr><tr><td><strong>+8.5</strong></td><td>7.079497844</td><td>2.66072506</td><td><strong>+46</strong></td><td>39810.71706</td><td>199.5262315</td><td><strong>+86</strong></td><td>398107170.6</td><td>19952.62315</td></tr><tr><td><strong>+9</strong></td><td>7.943282347</td><td>2.818382931</td><td><strong>+47</strong></td><td>50118.72336</td><td>223.8721139</td><td><strong>+87</strong></td><td>501187233.6</td><td>22387.21139</td></tr><tr><td><strong>+9.5</strong></td><td>8.912509381</td><td>2.985382619</td><td><strong>+48</strong></td><td>63095.73445</td><td>251.1886432</td><td><strong>+88</strong></td><td>630957344.5</td><td>25118.86432</td></tr><tr><td><strong>+10</strong></td><td>10</td><td>3.16227766</td><td><strong>+49</strong></td><td>79432.82347</td><td>281.8382931</td><td><strong>+89</strong></td><td>794328234.7</td><td>28183.82931</td></tr><tr><td><strong>+11</strong></td><td>12.58925412</td><td>3.548133892</td><td><strong>+50</strong></td><td>100000</td><td>316.227766</td><td><strong>+90</strong></td><td>1000000000</td><td>31622.7766</td></tr><tr><td><strong>+12</strong></td><td>15.84893192</td><td>3.981071706</td><td><strong>+51</strong></td><td>125892.5412</td><td>354.8133892</td><td><strong>+91</strong></td><td>1258925412</td><td>35481.33892</td></tr><tr><td><strong>+13</strong></td><td>19.95262315</td><td>4.466835922</td><td><strong>+52</strong></td><td>158489.3192</td><td>398.1071706</td><td><strong>+92</strong></td><td>1584893192</td><td>39810.71706</td></tr><tr><td><strong>+14</strong></td><td>25.11886432</td><td>5.011872336</td><td><strong>+53</strong></td><td>199526.2315</td><td>446.6835922</td><td><strong>+93</strong></td><td>1995262315</td><td>44668.35922</td></tr><tr><td><strong>+15</strong></td><td>31.6227766</td><td>5.623413252</td><td><strong>+54</strong></td><td>251188.6432</td><td>501.1872336</td><td><strong>+94</strong></td><td>2511886432</td><td>50118.72336</td></tr><tr><td><strong>+16</strong></td><td>39.81071706</td><td>6.309573445</td><td><strong>+55</strong></td><td>316227.766</td><td>562.3413252</td><td><strong>+95</strong></td><td>3162277660</td><td>56234.13252</td></tr><tr><td><strong>+17</strong></td><td>50.11872336</td><td>7.079457844</td><td><strong>+56</strong></td><td>398107.1706</td><td>630.9573445</td><td><strong>+96</strong></td><td>3981071706</td><td>63095.73445</td></tr><tr><td><strong>+18</strong></td><td>63.09573445</td><td>7.943282347</td><td><strong>+57</strong></td><td>501187.2336</td><td>707.9457844</td><td><strong>+97</strong></td><td>5011872336</td><td>70794.57844</td></tr><tr><td><strong>+19</strong></td><td>79.43282347</td><td>8.912509381</td><td><strong>+58</strong></td><td>630957.3445</td><td>794.3282347</td><td><strong>+98</strong></td><td>6309573445</td><td>79432.82347</td></tr><tr><td><strong>+20</strong></td><td>100</td><td>10</td><td><strong>+59</strong></td><td>794328.2347</td><td>891.2509381</td><td><strong>+99</strong></td><td>7943282347</td><td>89125.09381</td></tr><tr><td>-</td><td>-</td><td>-</td><td><strong>+60</strong></td><td>1000000</td><td>1000</td><td><strong>+100</strong></td><td>10000000000</td><td>100000</td></tr></tbody></table><h3 id="负分贝值-0--100db-速查表">负分贝值 <code>0 ~ -100dB</code>速查表</h3><table style="width:100%;"><colgroup><col style="width: 8%"><col style="width: 12%"><col style="width: 12%"><col style="width: 7%"><col style="width: 12%"><col style="width: 12%"><col style="width: 8%"><col style="width: 12%"><col style="width: 12%"></colgroup><thead><tr><th>分贝 dB</th><th>功率类</th><th>幅值类</th><th>分贝 dB</th><th>功率类</th><th>幅值类</th><th>分贝 dB</th><th>功率类</th><th>幅值类</th></tr></thead><tbody><tr><td><strong>0 </strong></td><td>1</td><td>1</td><td><strong>-21</strong></td><td>0.007943282</td><td>0.089125094</td><td><strong>-61</strong></td><td>7.94328E-07</td><td>0.000891251</td></tr><tr><td><strong>-0.1</strong></td><td>0.977237221</td><td>0.988553095</td><td><strong>-22</strong></td><td>0.006309573</td><td>0.079432823</td><td><strong>-62</strong></td><td>6.30957E-07</td><td>0.000794328</td></tr><tr><td><strong>-0.2</strong></td><td>0.954992586</td><td>0.977237221</td><td><strong>-23</strong></td><td>0.005011872</td><td>0.070794578</td><td><strong>-63</strong></td><td>5.01187E-07</td><td>0.000707946</td></tr><tr><td><strong>-0.3</strong></td><td>0.933254301</td><td>0.966050879</td><td><strong>-24</strong></td><td>0.003981072</td><td>0.063095734</td><td><strong>-64</strong></td><td>3.98107E-07</td><td>0.000630957</td></tr><tr><td><strong>-0.4</strong></td><td>0.912010839</td><td>0.954992586</td><td><strong>-25</strong></td><td>0.003162278</td><td>0.056234133</td><td><strong>-65</strong></td><td>3.16228E-07</td><td>0.000562341</td></tr><tr><td><strong>-0.5</strong></td><td>0.891250938</td><td>0.944060876</td><td><strong>-26</strong></td><td>0.002511886</td><td>0.050118723</td><td><strong>-66</strong></td><td>2.51189E-07</td><td>0.000501187</td></tr><tr><td><strong>-0.6</strong></td><td>0.87096359</td><td>0.933254301</td><td><strong>-27</strong></td><td>0.001995262</td><td>0.044668359</td><td><strong>-67</strong></td><td>1.99526E-07</td><td>0.000446684</td></tr><tr><td><strong>-0.7</strong></td><td>0.851138038</td><td>0.922571427</td><td><strong>-28</strong></td><td>0.001584893</td><td>0.039810717</td><td><strong>-68</strong></td><td>1.58489E-07</td><td>0.000398107</td></tr><tr><td><strong>-0.8</strong></td><td>0.831763771</td><td>0.912010839</td><td><strong>-29</strong></td><td>0.001258925</td><td>0.035481339</td><td><strong>-69</strong></td><td>1.25893E-07</td><td>0.000354813</td></tr><tr><td><strong>-0.9</strong></td><td>0.812830516</td><td>0.901571138</td><td><strong>-30</strong></td><td>0.001</td><td>0.031622777</td><td><strong>-70</strong></td><td>0.0000001</td><td>0.000316228</td></tr><tr><td><strong>-1</strong></td><td>0.794328235</td><td>0.891250938</td><td><strong>-31</strong></td><td>0.000794328</td><td>0.028183829</td><td><strong>-71</strong></td><td>7.94328E-08</td><td>0.000281838</td></tr><tr><td><strong>-1.5</strong></td><td>0.707945784</td><td>0.841385142</td><td><strong>-32</strong></td><td>0.000630957</td><td>0.025118864</td><td><strong>-72</strong></td><td>6.30957E-08</td><td>0.000251189</td></tr><tr><td><strong>-2</strong></td><td>0.630957344</td><td>0.794328235</td><td><strong>-33</strong></td><td>0.000501187</td><td>0.022387211</td><td><strong>-73</strong></td><td>5.01187E-08</td><td>0.000223872</td></tr><tr><td><strong>-2.5</strong></td><td>0.562341325</td><td>0.749894209</td><td><strong>-34</strong></td><td>0.000398107</td><td>0.019952623</td><td><strong>-74</strong></td><td>3.98107E-08</td><td>0.000199526</td></tr><tr><td><strong>-3</strong></td><td>0.501187234</td><td>0.707945784</td><td><strong>-35</strong></td><td>0.000316228</td><td>0.017782794</td><td><strong>-75</strong></td><td>3.16228E-08</td><td>0.000177828</td></tr><tr><td><strong>-3.5</strong></td><td>0.446683592</td><td>0.668343918</td><td><strong>-36</strong></td><td>0.000251189</td><td>0.015848932</td><td><strong>-76</strong></td><td>2.51189E-08</td><td>0.000158489</td></tr><tr><td><strong>-4</strong></td><td>0.398107171</td><td>0.630957344</td><td><strong>-37</strong></td><td>0.000199526</td><td>0.014125375</td><td><strong>-77</strong></td><td>1.99526E-08</td><td>0.000141254</td></tr><tr><td><strong>-4.5</strong></td><td>0.354813389</td><td>0.595662144</td><td><strong>-38</strong></td><td>0.000158489</td><td>0.012589254</td><td><strong>-78</strong></td><td>1.58489E-08</td><td>0.000125893</td></tr><tr><td><strong>-5</strong></td><td>0.316227766</td><td>0.562341325</td><td><strong>-39</strong></td><td>0.000125893</td><td>0.011220185</td><td><strong>-79</strong></td><td>1.25893E-08</td><td>0.000112202</td></tr><tr><td><strong>-5.5</strong></td><td>0.281838293</td><td>0.530884444</td><td><strong>-40</strong></td><td>0.0001</td><td>0.01</td><td><strong>-80</strong></td><td>0.00000001</td><td>0.0001</td></tr><tr><td><strong>-6</strong></td><td>0.251188643</td><td>0.501187234</td><td><strong>-41</strong></td><td>7.94328E-05</td><td>0.008912509</td><td><strong>-81</strong></td><td>7.94328E-09</td><td>8.91251E-05</td></tr><tr><td><strong>-6.5</strong></td><td>0.223872114</td><td>0.473151259</td><td><strong>-42</strong></td><td>6.30957E-05</td><td>0.007943282</td><td><strong>-82</strong></td><td>6.30957E-09</td><td>7.94328E-05</td></tr><tr><td><strong>-7</strong></td><td>0.199526231</td><td>0.446683592</td><td><strong>-43</strong></td><td>5.01187E-05</td><td>0.007079458</td><td><strong>-83</strong></td><td>5.01187E-09</td><td>7.07946E-05</td></tr><tr><td><strong>-7.5</strong></td><td>0.177827941</td><td>0.421696503</td><td><strong>-44</strong></td><td>3.98107E-05</td><td>0.006309573</td><td><strong>-84</strong></td><td>3.98107E-09</td><td>6.30957E-05</td></tr><tr><td><strong>-8</strong></td><td>0.158489319</td><td>0.398107171</td><td><strong>-45</strong></td><td>3.16228E-05</td><td>0.005623413</td><td><strong>-85</strong></td><td>3.16228E-09</td><td>5.62341E-05</td></tr><tr><td><strong>-8.5</strong></td><td>0.141253754</td><td>0.375837404</td><td><strong>-46</strong></td><td>2.51189E-05</td><td>0.005011872</td><td><strong>-86</strong></td><td>2.51189E-09</td><td>5.01187E-05</td></tr><tr><td><strong>-9</strong></td><td>0.125892541</td><td>0.354813389</td><td><strong>-47</strong></td><td>1.99526E-05</td><td>0.004466836</td><td><strong>-87</strong></td><td>1.99526E-09</td><td>4.46684E-05</td></tr><tr><td><strong>-9.5</strong></td><td>0.112201845</td><td>0.334965439</td><td><strong>-48</strong></td><td>1.58489E-05</td><td>0.003981072</td><td><strong>-88</strong></td><td>1.58489E-09</td><td>3.98107E-05</td></tr><tr><td><strong>-10</strong></td><td>0.1</td><td>0.316227766</td><td><strong>-49</strong></td><td>1.25893E-05</td><td>0.003548134</td><td><strong>-89</strong></td><td>1.25893E-09</td><td>3.54813E-05</td></tr><tr><td><strong>-11</strong></td><td>0.079432823</td><td>0.281838293</td><td><strong>-50</strong></td><td>0.00001</td><td>0.003162278</td><td><strong>-90</strong></td><td>0.000000001</td><td>3.16228E-05</td></tr><tr><td><strong>-12</strong></td><td>0.063095734</td><td>0.251188643</td><td><strong>-51</strong></td><td>7.94328E-06</td><td>0.002818383</td><td><strong>-91</strong></td><td>7.94328E-10</td><td>2.81838E-05</td></tr><tr><td><strong>-13</strong></td><td>0.050118723</td><td>0.223872114</td><td><strong>-52</strong></td><td>6.30957E-06</td><td>0.002511886</td><td><strong>-92</strong></td><td>6.30957E-10</td><td>2.51189E-05</td></tr><tr><td><strong>-14</strong></td><td>0.039810717</td><td>0.199526231</td><td><strong>-53</strong></td><td>5.01187E-06</td><td>0.002238721</td><td><strong>-93</strong></td><td>5.01187E-10</td><td>2.23872E-05</td></tr><tr><td><strong>-15</strong></td><td>0.031622777</td><td>0.177827941</td><td><strong>-54</strong></td><td>3.98107E-06</td><td>0.001995262</td><td><strong>-94</strong></td><td>3.98107E-10</td><td>1.99526E-05</td></tr><tr><td><strong>-16</strong></td><td>0.025118864</td><td>0.158489319</td><td><strong>-55</strong></td><td>3.16228E-06</td><td>0.001778279</td><td><strong>-95</strong></td><td>3.16228E-10</td><td>1.77828E-05</td></tr><tr><td><strong>-17</strong></td><td>0.019952623</td><td>0.141253754</td><td><strong>-56</strong></td><td>2.51189E-06</td><td>0.001584893</td><td><strong>-96</strong></td><td>2.51189E-10</td><td>1.58489E-05</td></tr><tr><td><strong>-18</strong></td><td>0.015848932</td><td>0.125892541</td><td><strong>-57</strong></td><td>1.99526E-06</td><td>0.001412538</td><td><strong>-97</strong></td><td>1.99526E-10</td><td>1.41254E-05</td></tr><tr><td><strong>-19</strong></td><td>0.012589254</td><td>0.112201845</td><td><strong>-58</strong></td><td>1.58489E-06</td><td>0.001258925</td><td><strong>-98</strong></td><td>1.58489E-10</td><td>1.25893E-05</td></tr><tr><td><strong>-20</strong></td><td>0.01</td><td>0.1</td><td><strong>-59</strong></td><td>1.25893E-06</td><td>0.001122018</td><td><strong>-99</strong></td><td>1.25893E-10</td><td>1.12202E-05</td></tr><tr><td>-</td><td>-</td><td>-</td><td><strong>-60</strong></td><td>0.000001</td><td>0.001</td><td><strong>-100</strong></td><td>1E-10</td><td>0.00001</td></tr></tbody></table><h2 id="分贝衍生的单位">分贝衍生的单位</h2><p>除此之外，电子学当中还会经常使用到<code>dBm</code>、<code>dBW</code>、<code>dBu</code>、<code>dBV</code>等<strong>绝对分贝</strong>单位（固定的参考基准值），它们都是<strong>对数分贝</strong>的衍生单位，核心区别在于<strong>参考基准</strong>不同，其中<code>dBm</code> 和 <code>dBW</code> 用于表征<strong>功率</strong>，而<code>dBu</code> 和 <code>dBV</code>用于表征<strong>电压</strong>，具体请参考下面两个表格：</p><table><colgroup><col style="width: 8%"><col style="width: 11%"><col style="width: 21%"><col style="width: 58%"></colgroup><thead><tr><th>功率绝对分贝单位</th><th>表征对象</th><th>参考基准值</th><th>核心公式</th></tr></thead><tbody><tr><td><code>dBm</code></td><td><strong>功率</strong>（<code>分贝毫瓦</code>）</td><td>使用 <span class="math inline">\(P_{ref}=1\ \text{mW}\)</span>作为功率基准</td><td><span class="math inline">\(P(\text{dBm}) =10\log\left(\frac{P(\text{mW})}{P_{ref}}\right) =10\log\left(\frac{P(\text{mW})}{1}\right)\)</span></td></tr><tr><td><code>dBW</code></td><td><strong>功率</strong>（<code>分贝瓦</code>）</td><td>使用 <span class="math inline">\(P_{ref}=1\ \text{W}\)</span>作为功率基准</td><td><span class="math inline">\(P(\text{dBW}) =10\log\left(\frac{P(\text{W})}{P_{ref}}\right) =10\log\left(\frac{P(\text{W})}{1}\right)\)</span></td></tr></tbody></table><table><colgroup><col style="width: 8%"><col style="width: 10%"><col style="width: 22%"><col style="width: 58%"></colgroup><thead><tr><th>电压绝对分贝单位</th><th>表征对象</th><th>参考基准值</th><th>核心公式</th></tr></thead><tbody><tr><td><code>dBu</code></td><td><strong>电压</strong>（<code>分贝伏</code>）</td><td>使用 <span class="math inline">\(U_{ref}=0.775\ \text{V}\)</span>作为电压基准</td><td><span class="math inline">\(U(\text{dBu}) =20\log\left(\frac{U(\text{V})}{U_{ref}}\right) =20\log\left(\frac{U(\text{V})}{0.775}\right)\)</span></td></tr><tr><td><code>dBV</code></td><td><strong>电压</strong>（<code>分贝伏</code>）</td><td>使用 <span class="math inline">\(U_{ref}=1\ \text{V}\)</span>作为电压基准</td><td><span class="math inline">\(U(\text{dBV}) =20\log\left(\frac{U(\text{V})}{U_{ref}}\right) =20\log\left(\frac{U(\text{V})}{1}\right)\)</span></td></tr></tbody></table><h2 id="功率单位-dbmw-转换速查表">功率单位 dBm/W 转换速查表</h2><p>下面的表格展示了常用<strong>分贝毫瓦</strong> <code>dBm</code>值及其<strong>瓦</strong>/<strong>毫瓦</strong> <code>mW/W</code>单位的对照关系：</p><table><colgroup><col style="width: 17%"><col style="width: 10%"><col style="width: 17%"><col style="width: 5%"><col style="width: 17%"><col style="width: 7%"><col style="width: 17%"><col style="width: 5%"></colgroup><thead><tr><th>分贝毫瓦 dBm</th><th>毫瓦 mW</th><th>分贝毫瓦 dBm</th><th>瓦 W</th><th>分贝毫瓦 dBm</th><th>瓦 W</th><th>分贝毫瓦 dBm</th><th>瓦 W</th></tr></thead><tbody><tr><td><strong>-20</strong></td><td>0.010</td><td><strong>+1</strong></td><td>1.25</td><td><strong>+21</strong></td><td>0.120</td><td><strong>+41</strong></td><td>12.6</td></tr><tr><td><strong>-19</strong></td><td>0.012</td><td><strong>+2</strong></td><td>1.58</td><td><strong>+22</strong></td><td>0.159</td><td><strong>+42</strong></td><td>15.8</td></tr><tr><td><strong>-18</strong></td><td>0.016</td><td><strong>+3</strong></td><td>2.00</td><td><strong>+23</strong></td><td>0.200</td><td><strong>+43</strong></td><td>20.0</td></tr><tr><td><strong>-17</strong></td><td>0.020</td><td><strong>+4</strong></td><td>2.51</td><td><strong>+24</strong></td><td>0.251</td><td><strong>+44</strong></td><td>25.1</td></tr><tr><td><strong>-16</strong></td><td>0.025</td><td><strong>+5</strong></td><td>3.16</td><td><strong>+25</strong></td><td>0.316</td><td><strong>+45</strong></td><td>31.6</td></tr><tr><td><strong>-15</strong></td><td>0.032</td><td><strong>+6</strong></td><td>3.98</td><td><strong>+26</strong></td><td>0.398</td><td><strong>+46</strong></td><td>39.8</td></tr><tr><td><strong>-14</strong></td><td>0.040</td><td><strong>+7</strong></td><td>5.01</td><td><strong>+27</strong></td><td>0.501</td><td><strong>+47</strong></td><td>50.1</td></tr><tr><td><strong>-13</strong></td><td>0.050</td><td><strong>+8</strong></td><td>6.30</td><td><strong>+28</strong></td><td>0.631</td><td><strong>+48</strong></td><td>68.1</td></tr><tr><td><strong>-12</strong></td><td>0.063</td><td><strong>+9</strong></td><td>7.94</td><td><strong>+29</strong></td><td>0.794</td><td><strong>+49</strong></td><td>79.4</td></tr><tr><td><strong>-11</strong></td><td>0.079</td><td><strong>+10</strong></td><td>10.0</td><td><strong>+30</strong></td><td>1.00</td><td><strong>+50</strong></td><td>100</td></tr><tr><td><strong>-10</strong></td><td>0.100</td><td><strong>+11</strong></td><td>12.6</td><td><strong>+31</strong></td><td>1.26</td><td><strong>+51</strong></td><td>126</td></tr><tr><td><strong>-9</strong></td><td>0.130</td><td><strong>+12</strong></td><td>15.8</td><td><strong>+32</strong></td><td>1.59</td><td><strong>+52</strong></td><td>158</td></tr><tr><td><strong>-8</strong></td><td>0.160</td><td><strong>+13</strong></td><td>19.9</td><td><strong>+33</strong></td><td>2.00</td><td><strong>+53</strong></td><td>200</td></tr><tr><td><strong>-7</strong></td><td>0.200</td><td><strong>+14</strong></td><td>25.1</td><td><strong>+34</strong></td><td>2.55</td><td><strong>+54</strong></td><td>251</td></tr><tr><td><strong>-6</strong></td><td>0.250</td><td><strong>+15</strong></td><td>31.6</td><td><strong>+35</strong></td><td>3.16</td><td><strong>+55</strong></td><td>316</td></tr><tr><td><strong>-5</strong></td><td>0.316</td><td><strong>+16</strong></td><td>39.8</td><td><strong>+36</strong></td><td>3.98</td><td><strong>+56</strong></td><td>398</td></tr><tr><td><strong>-4</strong></td><td>0.398</td><td><strong>+17</strong></td><td>50.1</td><td><strong>+37</strong></td><td>5.01</td><td><strong>+57</strong></td><td>501</td></tr><tr><td><strong>-3</strong></td><td>0.501</td><td><strong>+18</strong></td><td>63.1</td><td><strong>+38</strong></td><td>6.31</td><td><strong>+58</strong></td><td>631</td></tr><tr><td><strong>-2</strong></td><td>0.630</td><td><strong>+19</strong></td><td>79.4</td><td><strong>+39</strong></td><td>7.94</td><td><strong>+59</strong></td><td>794</td></tr><tr><td><strong>-1</strong></td><td>0.794</td><td><strong>+20</strong></td><td>100</td><td><strong>+40</strong></td><td>10.0</td><td><strong>+60</strong></td><td>1000</td></tr><tr><td><strong>0</strong></td><td>1.00</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td><td>-</td></tr></tbody></table>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;strong&gt;分贝&lt;/strong&gt;（&lt;code&gt;dB&lt;/code&gt;，Decibel
[ˈdesɪbel]）是一个用于衡量声压等级、信号功率强度的对数无量纲单位，该单位来源于美国的电话发明家&lt;strong&gt;贝尔&lt;/strong&gt;
&lt;code&gt;Alexander Graham Bell&lt;/code&gt;
的名字，是从&lt;strong&gt;贝尔&lt;/strong&gt;（&lt;strong&gt;B&lt;/strong&gt;，Bel）这个单位衍生而来（&lt;strong&gt;一贝尔等于十分贝&lt;/strong&gt;
&lt;span class=&quot;math inline&quot;&gt;&#92;(1Bel =
10dB&#92;)&lt;/span&gt;），其最初被用于贝尔实验室长途电话线路损耗的计量，从而解决线性度量单位无法描述超过
&lt;span class=&quot;math inline&quot;&gt;&#92;(10^{14}&#92;)&lt;/span&gt;
数量级的信号强度问题，而后成为
&lt;strong&gt;声学&lt;/strong&gt;、&lt;strong&gt;电子&lt;/strong&gt;、&lt;strong&gt;通信&lt;/strong&gt;
等领域的通用计量单位。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/Math/Decible/logo.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;分贝并不是一个线性的绝对数值单位，其反映的是两个相同单位物理量的比值，在取对数之后分别再乘以
&lt;code&gt;10&lt;/code&gt;（&lt;strong&gt;功率类参数&lt;/strong&gt;，例如
&lt;code&gt;声音功率&lt;/code&gt;、&lt;code&gt;电功率&lt;/code&gt;）或者
&lt;code&gt;20&lt;/code&gt;（&lt;strong&gt;场量类参数&lt;/strong&gt;，&lt;code&gt;声压&lt;/code&gt;、&lt;code&gt;电压&lt;/code&gt;、&lt;code&gt;电流&lt;/code&gt;、&lt;code&gt;场强&lt;/code&gt;），其&lt;strong&gt;反映的是一个相对的数量级，而非一个绝对的数值&lt;/strong&gt;。总而言之，由于分贝采用了&lt;strong&gt;对数&lt;/strong&gt;
&lt;span class=&quot;math inline&quot;&gt;&#92;(y = &#92;log_a x&#92;)&lt;/span&gt;
来作为单位的标度，因为而能够极大的压缩数值范围并且简化计算，同时也更加适配人类听觉以及信号传输的&lt;strong&gt;非线性感知特性&lt;/strong&gt;。&lt;/p&gt;</summary>
    
    
    
    <category term="硬件电子技术" scheme="http://www.uinio.com/categories/%E7%A1%AC%E4%BB%B6%E7%94%B5%E5%AD%90%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="芯片" scheme="http://www.uinio.com/tags/%E8%8A%AF%E7%89%87/"/>
    
  </entry>
  
  <entry>
    <title>IEEE1394 FireWire 火线接口物理层硬件设计</title>
    <link href="http://www.uinio.com/Electronics/IEEE1394/"/>
    <id>http://www.uinio.com/Electronics/IEEE1394/</id>
    <published>2025-11-21T16:00:00.000Z</published>
    <updated>2026-02-26T14:23:15.317Z</updated>
    
    <content type="html"><![CDATA[<p><strong>IEEE1394</strong>是一种高速实时串行通信总线标准。最早由美国苹果公司推出，被称作<strong>火线</strong>（FireWire）接口，相关专利主要由<strong>美国</strong>的苹果（Apple）、德州仪器（TI）和<strong>日本</strong>的索尼（SONY）、松下（Panasonic）、东芝（Toshiba）、日立（HITACHI）、佳能（Canon），<strong>韩国</strong>的乐金（LG）以及<strong>欧洲</strong>的飞利浦（Philips）、意法半导体（ST）等商业公司持有。但是进入到2011 年之后，苹果公司开始引入更加快速的 <strong>Thunderbolt</strong>接口来取代 <strong>FireWire</strong> 标准，并于 2015年之后逐渐过度到符合 <strong>USB 3.1</strong> 规范的 <strong>USBType-C</strong> 接口，目前在消费类电子领域已经比较少使用该接口标准。</p><p><img src="/Electronics/IEEE1394/logo.png"></p><p>然而得益于 <strong>IEEE1394b</strong>简单的线束结构，该协议的应用也从消费类电子领域，扩展到航空航天领域。<strong>美国汽车工程师协会</strong>（<strong>SAE</strong>，Societyof Automotive Engineers）基于 <strong>IEEE1394b</strong>规范，增加了通信的<strong>确定性</strong>（包括网络拓扑预分配、强制根节点、带宽预分配、帧开始数据包同步、异步流数据包、静态分配通道号）和<strong>可靠性</strong>（纵向奇偶校验、健康状态字、心跳字、控制计算机分支状态字）相关的约束，进一步制定出了适用于<a href="https://www.daptechnology.com/mil1394#panel-88535-1">航空航天领域</a>的《<strong>SAEAS5643B-2016</strong>》标准。</p><span id="more"></span><h2 id="ieee1394-标准演进历史">IEEE1394 标准演进历史</h2><p>相比较于同时期的 <strong>USB1.1</strong>接口标准，<strong>IEEE1394a</strong>标准在数据传输速率上占据着绝对优势，但是当 <strong>USB2.0</strong>标准推出之后，<strong>IEEE1394a</strong>接口在传输速度上的优势就不再明显；而后续传输速率高达 <code>5Gbps</code>以上的 <strong>USB3.0</strong> 接口标准的出现，使得<strong>IEEE1394</strong>规范的后续版本在速度和成本上处于劣势，因而逐渐在消费级市场处于被边缘化的地位：</p><p><img src="/Electronics/IEEE1394/Layer.png"></p><ol type="1"><li><strong>IEEE 1394-1995</strong>（<strong>FireWire400</strong>）：采用半双工传输，在不同的传输模式<code>S100/200/400</code> 下面，其理想传输速率分别可以达到<code>100/200/400 Mbit/s</code>。传输线缆最长可以达到 4.5 米，并使用<strong>6 针</strong> 阿尔法（<strong>Alpha</strong>）连接器。</li><li><strong>IEEE 1394a-2000</strong>（<strong>改进 FireWire400</strong>）：澄清和改进了原始规范，增加了异步流、更快的总线重配置、数据包串接、省电暂停模式。最大优点在于其允许总线加速仲裁周期提高效率，并且支持仲裁短总线复位（ArbitratedShort BusReset），可以在添加或者移除节点时降低传输速率。同时该标准还吸纳了日本索尼（SONY）公司定义的<strong>i.LINK</strong> 四芯连接器（不包含电源连接）。</li><li><strong>IEEE 1394b-2002</strong>（<strong>FireWire800</strong>）：引入了全新的 <code>8b/10b</code> 编码方案，允许设备以<code>800 Mbit/s</code>速率全双工运行，并采用了九芯的贝塔（<strong>Beta</strong>）连接器（无法向下兼容）。</li><li><strong>IEEE 1394c-2006</strong>（<strong>FireWireS800T</strong>）：允许通过以太网 RJ45 连接器提供高达<code>800 Mbit/s</code> 的传输速率。</li><li><strong>IEEE 1394c-2008</strong>（<strong>FireWireS1600/S3200</strong>）：该标准可以让九芯贝塔（<strong>Beta</strong>）连接器的传输速率达到<code>1.6/3.2 Gbit/s</code>，但是后续的应用普及非常缓慢。</li></ol><h2 id="连接器-线缆">连接器 &amp; 线缆</h2><p>下图从左至右分别展示了简化掉电源引脚的 4 Pin 引脚的 Mini<strong>IEEE1394a</strong> 连接器、6 Pin 引脚的标准<strong>IEEE1394a</strong> 连接器，以及 9 Pin 引脚的<strong>IEEE1394b</strong> 标准连接器。</p><p><img src="/Electronics/IEEE1394/Connector.png"></p><p>以 <strong>IEEE1394a</strong> 标准为例，6 Pin 引脚的连接器使用的是 6芯传输线缆，其外层为<strong>屏蔽层</strong>，内置有两对双绞线（分别用于传送数据和时钟信号），以及一对电源线（电压范围<code>8V ~ 40V</code>，额定电流<code>1.5A</code>），线缆的剖面如下图所示：</p><p><img src="/Electronics/IEEE1394/Wire.png"></p><p>截止到本文撰写时的 <strong>2026</strong>年，市面上比较通用，且出货量比较大的是 <a href="https://www.aiitw.com.tw/"><strong>台湾雅安科技Accurate</strong></a> 推出的 <code>6Pin</code> 规格<strong>IENF-061N</strong> 型（下图左）以及 <code>9Pin</code> 规格<strong>IENF-092N</strong> 型（下图右），这两款<strong>IEEE1394</strong> 标准连接器：</p><p><img src="/Electronics/IEEE1394/Accurate.png"></p><h2 id="ieee1394-连接器线序定义">IEEE1394 连接器线序定义</h2><p>下面的表格，展示了常用的<code>4Pin</code>、<code>6Pin</code>、<code>9Pin</code> 规格 IEEE1394连接器的线序与引脚功能定义：</p><p><img src="/Electronics/IEEE1394/Order.png"></p><table style="width:100%;"><colgroup><col style="width: 16%"><col style="width: 16%"><col style="width: 16%"><col style="width: 11%"><col style="width: 24%"><col style="width: 15%"></colgroup><thead><tr><th style="text-align: center;">4Pin 引脚编号</th><th style="text-align: center;">6Pin 引脚编号</th><th style="text-align: center;">9Pin 引脚编号</th><th style="text-align: left;">引脚名称</th><th style="text-align: left;">功能描述</th><th style="text-align: left;">线束颜色参考</th></tr></thead><tbody><tr><td style="text-align: center;">-</td><td style="text-align: center;"><code>1</code></td><td style="text-align: center;"><code>8</code></td><td style="text-align: left;"><strong>Power</strong></td><td style="text-align: left;">电源正极</td><td style="text-align: left;">白色</td></tr><tr><td style="text-align: center;">-</td><td style="text-align: center;"><code>2</code></td><td style="text-align: center;"><code>6</code></td><td style="text-align: left;"><strong>GND</strong></td><td style="text-align: left;">电源地和屏蔽地</td><td style="text-align: left;">黑色</td></tr><tr><td style="text-align: center;"><code>1</code></td><td style="text-align: center;"><code>3</code></td><td style="text-align: center;"><code>1</code></td><td style="text-align: left;"><strong>TPB-</strong></td><td style="text-align: left;">双绞线 B 差分信号负</td><td style="text-align: left;">橙色</td></tr><tr><td style="text-align: center;"><code>2</code></td><td style="text-align: center;"><code>4</code></td><td style="text-align: center;"><code>2</code></td><td style="text-align: left;"><strong>TPB+</strong></td><td style="text-align: left;">双绞线 B 差分信号正</td><td style="text-align: left;">蓝色</td></tr><tr><td style="text-align: center;"><code>3</code></td><td style="text-align: center;"><code>5</code></td><td style="text-align: center;"><code>3</code></td><td style="text-align: left;"><strong>TPA-</strong></td><td style="text-align: left;">双绞线 A 差分信号负</td><td style="text-align: left;">红色</td></tr><tr><td style="text-align: center;"><code>4</code></td><td style="text-align: center;"><code>6</code></td><td style="text-align: center;"><code>4</code></td><td style="text-align: left;"><strong>TPA+</strong></td><td style="text-align: left;">双绞线 A 差分信号正</td><td style="text-align: left;">绿色</td></tr><tr><td style="text-align: center;">-</td><td style="text-align: center;">-</td><td style="text-align: center;"><code>5</code></td><td style="text-align: left;">屏蔽 A</td><td style="text-align: left;">-</td><td style="text-align: left;">-</td></tr><tr><td style="text-align: center;">-</td><td style="text-align: center;">-</td><td style="text-align: center;"><code>7</code></td><td style="text-align: left;">-</td><td style="text-align: left;">-</td><td style="text-align: left;">-</td></tr><tr><td style="text-align: center;">-</td><td style="text-align: center;">-</td><td style="text-align: center;"><code>9</code></td><td style="text-align: left;">屏蔽 B</td><td style="text-align: left;">-</td><td style="text-align: left;">-</td></tr><tr><td style="text-align: center;">外壳</td><td style="text-align: center;">外壳</td><td style="text-align: center;">线束屏蔽层</td><td style="text-align: left;">-</td><td style="text-align: left;">-</td><td style="text-align: left;">-</td></tr></tbody></table><blockquote><p>注意：上述表格中的<strong>引脚编号</strong>对应着示意图里的<strong>引脚序号</strong>。</p></blockquote><h2 id="usb2.0-ieee1394-性能比较">USB2.0 &amp; IEEE1394 性能比较</h2><table><thead><tr><th style="text-align: left;">参数</th><th style="text-align: left;">标准 IEEE 1394</th><th style="text-align: left;">USB 2.0 接口</th></tr></thead><tbody><tr><td style="text-align: left;">标准传输速率</td><td style="text-align: left;"><code>400 Mbps</code></td><td style="text-align: left;"><code>480 Mbps</code></td></tr><tr><td style="text-align: left;">持续<strong>读</strong>速度</td><td style="text-align: left;"><code>38 MB/s</code></td><td style="text-align: left;"><code>33 MB/s</code></td></tr><tr><td style="text-align: left;">持续<strong>写</strong>速度</td><td style="text-align: left;"><code>35 MB/s</code></td><td style="text-align: left;"><code>27 MB/s</code></td></tr><tr><td style="text-align: left;">连接器循环寿命</td><td style="text-align: left;">4 引脚 <code>1000</code> 次，6 引脚<code>1500</code> 次</td><td style="text-align: left;"><code>1500</code> 次</td></tr><tr><td style="text-align: left;">通信架构</td><td style="text-align: left;">点对点结构</td><td style="text-align: left;">主从结构</td></tr></tbody></table><h2 id="总线基本结构">总线基本结构</h2><p>1394 总线以节点 Node 作为单位来组成通信网络，一个基本的 1394总线系统由<strong>控制计算机节点</strong>（CC，ControlComputer）、<strong>远程节点</strong>（RN，RemoteNode）、<strong>总线监控节点</strong>（BM，Bus Monitor）以及 IEEE1394线缆与连接器共同组成，下图展示了 IEEE1394 总线的基本网络拓扑：</p><ol type="1"><li><strong>控制计算机节点CC</strong>：作为总线控制器，周期性发送<strong>帧起始</strong>（STOF，StartofFrame）信号，通知总线上所有节点开始发送新的数据帧，并借此实现总线数据同步；</li><li><strong>远程节点RN</strong>：作为远程终端，根据总线通道预分配，将不同的节点 ID和通道号进行绑定；RN 节点接收到 <code>STOF</code>帧起始信号之后，就会确认新的数据帧开始，并且按照预先分配的偏移时间，在时间窗口到来时发送数据。</li><li><strong>总线监控节点BM</strong>：作为叶子节点挂载在总线上，能够监控总线上其它节点发出的<code>网络管理</code> 与 <code>普通数据</code>消息，从而实现对于网络数据的分析；</li></ol><p>总线上各个节点之间通过 1394 线缆连接，1394总线线缆是一种物理通信媒介，是网络信号传输的载体。1394线缆通过连接器与模块进行连接，通过连接器实现不同子系统的中转接口。当节点之间距离过长时，会导致传输信号衰减过大，由此需要通过1394 总线中继器来完成信号的增强。</p><h2 id="物理层-phy-芯片">物理层 PHY 芯片</h2><p>下图展示的是一款同时支持 <strong>IEEE1394-1995</strong>、<strong>IEEE 1394a-2000</strong>、<strong>IEEE1394b-2002</strong> 协议标准的 PHY 物理层芯片的引脚定义图：</p><p><img src="/Electronics/IEEE1394/PHY-1.png"></p><p>接下来的示意图，则展示了上面这片 PHY物理层芯片内部的基本功能框图：</p><p><img src="/Electronics/IEEE1394/PHY-2.png"></p><p><strong>物理层</strong>（PHY，PhysicalLayer）芯片通常需要与<strong>链接层控制器</strong> (LLC，Link LayerController) 搭配起来使用，两者各司其职。下面的表格对上述 PHY芯片的引脚定义进行了详细的说明：</p><table><colgroup><col style="width: 8%"><col style="width: 2%"><col style="width: 6%"><col style="width: 2%"><col style="width: 80%"></colgroup><thead><tr><th>名称</th><th>类型</th><th>编号</th><th>I/O</th><th>功能描述</th></tr></thead><tbody><tr><td><strong>AGND</strong></td><td>电源</td><td><code>21/40/43/50/61/62</code></td><td>-</td><td>模拟接地引脚。</td></tr><tr><td><strong>AVDD</strong></td><td>电源</td><td><code>24/39/44/51/57/63</code></td><td>-</td><td>模拟电源引脚，建议并联 <code>0.1uF</code> 和 <code>0.001 uF</code>高频去耦电容，以及 <code>10uF</code> 低频去耦电容。</td></tr><tr><td><strong>BMODE</strong></td><td>CMOS</td><td><code>74</code></td><td>输入</td><td><strong>Beta</strong> 模式输入，用于决定<code>PHY&lt;-&gt;Link</code> 接口的连接协议（高电平为<code>IEEE1394b-2002</code>，低电平为 <code>IEEE1394a-2000</code>）</td></tr><tr><td><strong>CPS</strong></td><td>CMOS</td><td><code>34</code></td><td>输入</td><td><strong>线缆电源状态</strong>（CPS，Cable powerstatus）输入引脚，通常使用 <code>400KΩ</code>电阻连接到线缆上的电源，然后通过内部比较器检测线缆电源是否存在（没有检测到电源，就会向LLC 生成中断）。</td></tr><tr><td><strong>CTL0/1</strong></td><td>CMOS</td><td><code>9/10</code></td><td>输入</td><td>控制 IO 引脚，用于控制 PHY 与 LLC 之间的双向控制通信。</td></tr><tr><td><strong>D0 ~ D7</strong></td><td>CMOS</td><td><code>11/12/13/15/16/17/19/20</code></td><td>输入</td><td>数据 IO 引脚，用于控制 PHY 与 LLC 之间的双向数据通信。</td></tr><tr><td><strong>DGND</strong></td><td>电源</td><td><code>4/14/38/64/72/76</code></td><td>-</td><td>数字接地引脚。</td></tr><tr><td><strong>DVDD-CORE</strong></td><td>电源</td><td><code>8/37/65/71</code></td><td>-</td><td>数字核心电源，建议并联<code>0.001 uF</code>、<code>0.1uF</code>、<code>1uF</code>去耦电容。</td></tr><tr><td><strong>DVDD-3.3</strong></td><td>电源</td><td><code>6/18/69/70</code></td><td>-</td><td>数字 3.3V 电源，建议并联<code>0.001 uF</code>、<code>0.1uF</code>、<code>10uF</code>去耦电容。</td></tr><tr><td><strong>LCLK_PMC</strong></td><td>CMOS</td><td><code>7</code></td><td>输入</td><td>Link 时钟与复位电源管理控制输入引脚，<code>LINK-&gt;PHY</code> 提供<code>98.304MHz</code>的时钟信号用于同步数据传输，硬件重置时，该引脚的采样决定了<strong>电源管理控制</strong>（PMC，PowerManagement Control）的模式。</td></tr><tr><td><strong>LPS</strong></td><td>CMOS</td><td><code>80</code></td><td>输入</td><td>Link 电源状态（LPS，Link Power Status）输入引脚，用于监视 LLC控制器的活动状态，并且控制 <code>PHY&lt;-&gt;Link</code>接口的状态。</td></tr><tr><td><strong>LREQ</strong></td><td>CMOS</td><td><code>3</code></td><td>输入</td><td>LLC 请求（Request）输入引脚，链接层控制器 LLC 使用该引脚向 PHY发起服务请求。</td></tr><tr><td><strong>PCLK</strong></td><td>CMOS</td><td><code>5</code></td><td>输出</td><td>PHY 时钟输出引脚，当 <code>PHY-&gt;LINK</code> 处于<code>IEEE1394b-2002</code> 模式时，提供 <code>98.304MHz</code>的时钟信号用于同步数据传输。如果处于 <code>IEEE1394a-2000</code>模式，则只提供 <code>49.152MHz</code> 的时钟信号。</td></tr><tr><td><strong>PD</strong></td><td>CMOS</td><td><code>77</code></td><td>输入</td><td>下电输入，高电平时关闭全部内部电路，同时激活 RESET引脚的内部下拉，从而强制重置内部控制逻辑。</td></tr><tr><td><strong>PINT</strong></td><td>CMOS</td><td><code>1</code></td><td>输出</td><td>PHY 中断，当 <code>PHY&lt;-&gt;Link</code> 接口处于 1394b工作模式时，用于输出串行传输状态给 Link 层控制器。</td></tr><tr><td><strong>PLLGND</strong></td><td>电源</td><td><code>25/28</code></td><td>-</td><td>PLL 锁相环电路接地。</td></tr><tr><td><strong>PLLVDD-CORE</strong></td><td>电源</td><td><code>29/30</code></td><td>-</td><td>PLL 锁相环核心电路电源，建议并联<code>0.001 uF</code>、<code>0.1uF</code>、<code>1uF</code>去耦电容，该引脚必须与 <code>DVDD-CORE</code> 分开独立供电。</td></tr><tr><td><strong>PLLVDD-3.3</strong></td><td>电源</td><td><code>31</code></td><td>-</td><td>PLL 锁相环的 3.3V 电源引脚，建议并联<code>0.001 uF</code>、<code>0.1uF</code>、<code>10uF</code>去耦电容。</td></tr><tr><td><strong>RESET</strong></td><td>CMOS</td><td><code>75</code></td><td>输入</td><td>重置输入引脚，低电平时重置内部逻辑，其内部包含有一个连接到 VDD的上电阻，所以执行上拉时外部只需要一个延迟电容</td></tr><tr><td><strong>R0</strong>/<strong>R1</strong></td><td>偏置</td><td><code>22/23</code></td><td>-</td><td>电流配置电阻引脚，用于配置内部操作电流以及电缆驱动器的输出电流，为了满足IEEE1394-1995 的输出电压要求，建议使用一枚精度为 <code>±1%</code> 的<code>6.34 kΩ</code> 电阻器。</td></tr><tr><td><strong>SE</strong></td><td>CMOS</td><td><code>35</code></td><td>输入</td><td>测试控制输入引脚，用于生产制造测试，常规使用时必须通过<code>1kΩ</code> 电阻下拉至 GND 或者直接连接到 GND。</td></tr><tr><td><strong>SLPEN</strong></td><td>CMOS</td><td><code>79</code></td><td>输入</td><td>自动休眠模式使能引脚，用于开启自动休眠模式，低电平时保持常规的 1394b功能。</td></tr><tr><td><strong>SM</strong></td><td>CMOS</td><td><code>36</code></td><td>输入</td><td>测试控制输入引脚，用于生产制造测试，常规使用时必须通过<code>1kΩ</code> 电阻下拉至 GND 或者直接连接到 GND。</td></tr><tr><td><strong>S2_PC0</strong>/<strong>S1_PC1</strong>/<strong>S0_PC2</strong></td><td>CMOS</td><td><code>66/67/68</code></td><td>输入</td><td>端口休眠和模式选择引脚 0、1、2（通过 <code>1kΩ</code>上下拉电阻来实现）。</td></tr><tr><td><strong>S3</strong>/<strong>S4</strong></td><td>CMOS</td><td><code>33/32</code></td><td>输入</td><td>端口休眠和模式选择引脚 3 和 4（通过 <code>1kΩ</code>上下拉电阻来实现）。</td></tr><tr><td><strong>S5_LKON</strong></td><td>CMOS</td><td><code>2</code></td><td>输入/输出</td><td>端口休眠和模式选择引脚 5；除此之外，该引脚还可以作为<code>Link-on</code> 输出，通过 <code>1kΩ</code> 电阻连接到 LLC 控制器的<code>Link-on</code> 输入引脚。</td></tr><tr><td><strong>TESTM</strong></td><td>CMOS</td><td><code>78</code></td><td>输入</td><td>测试控制输入引脚，用于生产制造测试，常规使用时必须通过连接到<code>VDD</code> 的 <code>1kΩ</code> 电阻进行上拉。</td></tr><tr><td><strong>TPA0−/+</strong>、<strong>TPB0−/+</strong></td><td>线缆</td><td><code>45/46/41/42</code></td><td>输入/输出</td><td>差分双绞线 0 端口。</td></tr><tr><td><strong>TPA1−/+</strong>、<strong>TPB1−/+</strong></td><td>线缆</td><td><code>52/53/48/49</code></td><td>输入/输出</td><td>差分双绞线 1 端口。</td></tr><tr><td><strong>TPA2−/+</strong>、<strong>TPB2−/+</strong></td><td>线缆</td><td><code>58/59/55/56</code></td><td>输入/输出</td><td>差分双绞线 2 端口。</td></tr><tr><td><strong>TPBIAS0/1/2_SD0/1/2</strong></td><td>线缆接入</td><td><code>47/54/60</code></td><td>输入</td><td>双绞线偏置输出和信号检测输入，用于为双绞线驱动接收器提供<code>1.86V</code> 偏置电压，并且表明在 <code>IEEE1394a-2000</code>模式下存在活动的线缆连接，使用时该引脚必须使用 <code>1uF</code> 电容与GND 解耦，未使用可以不连接。如果 PHY 芯片被配置为 <code>Beta</code>模式，则该端口转变为输入引脚，此时必须在可用信号到来之时被上拉为<strong>高电平</strong>。</td></tr><tr><td><strong>VREG_PD</strong></td><td>CMOS</td><td><code>73</code></td><td>输入</td><td>稳压器电源下拉输入，高电平时关闭芯片内部的 <code>3.3V</code> 转<code>1.8V</code> 稳压器，对于仅有 <code>3.3V</code>的操作，则该引脚必须连接到 GND。</td></tr><tr><td><strong>XI</strong>/<strong>XO</strong></td><td>晶振</td><td><code>26/27</code></td><td>输入/输出</td><td>晶体振荡器输入，连接到 <code>49.152 MHz</code>晶体振荡器，<code>XI</code> 是一个 <code>1.8V</code> CMOS 输入。</td></tr></tbody></table><h2 id="ieee1394-接口保护电路">IEEE1394 接口保护电路</h2><p><strong>IEEE1394</strong> 使用介于 <code>1.2V ~ 2.0V</code>范围的差分信号传输数据，最大数据传输速率为 <strong>IEEE1394a</strong> 的<code>400 Mbps</code> 到 <strong>IEEE1394b</strong> 的<code>1600 Mbps</code>，因此在该速率范围之内，<code>TPA+/-</code>、<code>TPB+/-</code>两组四条信号线上，需要尽可能的选择<strong>寄生电容</strong>较低的<strong>静电释放</strong>（ESD，ElectroStatic Discharge）元器件。除此之外，也需要防止 <code>30V</code> 直流电源ESD 以及<strong>过电流</strong>危害。</p><p><img src="/Electronics/IEEE1394/ESD.png"></p><ul><li><code>SMD1812-110 33V</code>自恢复保险丝：用于总线电源的过电流保护。</li><li><code>MVR1206-420</code> 防浪涌压敏电阻：用于连接器总线电源的 ESD静电释放。</li><li><code>PGB-ESD0603S</code>双向瞬态电压抑制二极管：用于连接器信号线路的 ESD 静电释放。</li></ul><blockquote><p><strong>注意</strong>：总而言之，<strong>IEEE1394</strong>连接器的接口电路设计，遵循着<strong>串联器件用于电流防护，并联器件用于电压防护</strong>的基本设计原则。</p></blockquote>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;strong&gt;IEEE1394&lt;/strong&gt;
是一种高速实时串行通信总线标准。最早由美国苹果公司推出，被称作&lt;strong&gt;火线&lt;/strong&gt;（FireWire）接口，相关专利主要由&lt;strong&gt;美国&lt;/strong&gt;的苹果（Apple）、德州仪器（TI）和&lt;strong&gt;日本&lt;/strong&gt;的索尼（SONY）、松下（Panasonic）、东芝（Toshiba）、日立（HITACHI）、佳能（Canon），&lt;strong&gt;韩国&lt;/strong&gt;的乐金（LG）以及&lt;strong&gt;欧洲&lt;/strong&gt;的飞利浦（Philips）、意法半导体（ST）等商业公司持有。但是进入到
2011 年之后，苹果公司开始引入更加快速的 &lt;strong&gt;Thunderbolt&lt;/strong&gt;
接口来取代 &lt;strong&gt;FireWire&lt;/strong&gt; 标准，并于 2015
年之后逐渐过度到符合 &lt;strong&gt;USB 3.1&lt;/strong&gt; 规范的 &lt;strong&gt;USB
Type-C&lt;/strong&gt; 接口，目前在消费类电子领域已经比较少使用该接口标准。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/Electronics/IEEE1394/logo.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;然而得益于 &lt;strong&gt;IEEE1394b&lt;/strong&gt;
简单的线束结构，该协议的应用也从消费类电子领域，扩展到航空航天领域。&lt;strong&gt;美国汽车工程师协会&lt;/strong&gt;（&lt;strong&gt;SAE&lt;/strong&gt;，Society
of Automotive Engineers）基于 &lt;strong&gt;IEEE1394b&lt;/strong&gt;
规范，增加了通信的&lt;strong&gt;确定性&lt;/strong&gt;（包括网络拓扑预分配、强制根节点、带宽预分配、帧开始数据包同步、异步流数据包、静态分配通道号）和&lt;strong&gt;可靠性&lt;/strong&gt;（纵向奇偶校验、健康状态字、心跳字、控制计算机
分支状态字）相关的约束，进一步制定出了适用于&lt;a href=&quot;https://www.daptechnology.com/mil1394#panel-88535-1&quot;&gt;航空航天领域&lt;/a&gt;的《&lt;strong&gt;SAE
AS5643B-2016&lt;/strong&gt;》标准。&lt;/p&gt;</summary>
    
    
    
    <category term="硬件电子技术" scheme="http://www.uinio.com/categories/%E7%A1%AC%E4%BB%B6%E7%94%B5%E5%AD%90%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="通信总线" scheme="http://www.uinio.com/tags/%E9%80%9A%E4%BF%A1%E6%80%BB%E7%BA%BF/"/>
    
  </entry>
  
  <entry>
    <title>Cadence SPB OrCAD/Allegro 设计技巧合集</title>
    <link href="http://www.uinio.com/Electronics/Cadence-Skill/"/>
    <id>http://www.uinio.com/Electronics/Cadence-Skill/</id>
    <published>2025-09-27T16:00:00.000Z</published>
    <updated>2026-01-19T17:46:24.643Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://www.cadence.com/zh_CN/home/company.html"><strong>楷登电子</strong></a>推出的 <strong>Cadence SPB</strong>（<strong>SPB</strong> 是<code>Silicon</code>、<code>Package</code>、<code>Board</code>三个英文字母的缩写）整合了原理图绘制工具 <strong>OrCAD</strong> 和 PCB版图设计工具 <strong>Allegro</strong> 以及电路仿真工具<strong>PSpice</strong>，已经成为了业界领先的<strong>电子设计自动化</strong>（EDA，ElectronicDesignAutomation）工具链。伴随电子系统复杂度的日益提升，如何运用工具当中提供的各种功能来应对设计挑战，业已成为了广大电子硬件工程师们亟需掌握的技能。</p><p><img src="/Electronics/Cadence-Skill/logo.png"></p><p>关于 <strong>OrCAD</strong> 和 <strong>Allegro</strong>的基础操作，已经在五年之前所撰写的《<a href="http://uinio.com/Electronics/Cadence/"><strong>写给有经验 PCB工程师的 Cadence SPB 17.4极速上手指南</strong></a>》这篇文章当中进行过图文并茂的阐述，而本文则主要聚焦于实际应用中的<strong>高频痛点</strong>，提炼出经过验证的<code>操作技巧</code> 和<code>配置方法</code>。希冀能够帮助广大的电子硬件工程师，更加合理与熟练的使用<strong>Cadence SPB</strong> 工具套件进行原理图和 PCB版图的绘制，从而有效的提高研发工作效率，进而得心应手的面对各类纷繁复杂的设计挑战。</p><span id="more"></span><h2 id="orcadallegro-的正确打开方式">OrCAD/Allegro 的正确打开方式</h2><ol type="1"><li>鼠标依次点击 <strong>OrCAD</strong> 菜单栏上的<code>File -&gt; Change Product...</code>，然后选择【OrCAD CaptureCIS】；</li><li>鼠标依次点击 <strong>Allegro</strong> 菜单栏上的<code>File -&gt; Change Editor...</code>，然后选择【Allegro PCBDesigner】，并且勾选所需的功能项，例如<code>High-Speed</code>、<code>PCB Team Design</code>、<code>Analog/RF</code>；</li></ol><h2 id="cadence-spb-工程文件常用后缀">Cadence SPB 工程文件常用后缀</h2><table><colgroup><col style="width: 18%"><col style="width: 10%"><col style="width: 21%"><col style="width: 10%"><col style="width: 27%"><col style="width: 10%"></colgroup><thead><tr><th>文件类型</th><th>后缀名称</th><th>文件类型</th><th>后缀名称</th><th>文件类型</th><th>后缀名称</th></tr></thead><tbody><tr><td>Cadence 工程</td><td><code>.opj</code></td><td>PCB 封装</td><td><code>.psm</code></td><td>原理图库</td><td><code>.olb</code></td></tr><tr><td>Logo 图形</td><td><code>.osm</code></td><td>PCB 封装源文件</td><td><code>.dra</code></td><td>无电气特性的机械零件</td><td><code>.bsm</code></td></tr><tr><td>PCB 版图</td><td><code>.brd</code></td><td>原理图文件</td><td><code>.dsn</code></td><td>负片通孔连接方式</td><td><code>.fsm</code></td></tr><tr><td>Cadence 网表</td><td><code>.dat</code></td><td>自定义焊盘图形</td><td><code>.ssm</code></td><td>Allegro 操作记录</td><td><code>.jrl</code></td></tr><tr><td>第三方网表</td><td><code>.net</code></td><td>焊盘</td><td><code>.pad</code></td><td>日志</td><td><code>.log</code></td></tr><tr><td>操作记录脚本</td><td><code>.scr</code></td><td>可重复的模块定义</td><td><code>.mdd</code></td><td>PCB 规则钻孔</td><td><code>.drl</code></td></tr><tr><td>PCB 不规则钻孔</td><td><code>.rou</code></td><td>光绘文件</td><td><code>.art</code></td><td>-</td><td>-</td></tr></tbody></table><h2 id="原理图符号和-pcb-封装的默认位置">原理图符号和 PCB封装的默认位置</h2><ul><li><strong>OrCAD默认原理图符号库</strong>：<code>C:\Cadence\SPB_17.4\tools\capture\library</code>；</li><li><strong>Allegro 默认 PCB封装库</strong>：<code>C:\Cadence\SPB_17.4\share\pcb\pcb_lib\symbols</code>；</li></ul><p>其中在 <strong>OrCAD</strong>自带的原理图符号库当中，比较常用的有如下三种：</p><ul><li><code>Discrete.olb</code> 原理图符号库：用于存放分立式元件；</li><li><code>Transistor.olb</code>原理图符号库：用于存放有各类晶体管；</li><li><code>Connector.olb</code> 原理图符号库：用于存放有各种连接器；</li></ul><h2 id="orcadallegro-关闭-start-page-页面">OrCAD/Allegro 关闭 Start Page页面</h2><p>关闭 <strong>OrCAD</strong> 启动时自动显示【StartPage】页面的方法：</p><ol type="1"><li>鼠标依次点击 <strong>OrCAD</strong> 菜单栏上的<code>View -&gt; Toolbar -&gt; Command Window</code>；</li><li>在底部的命令行窗口执行 <code>SetOptionBool EnableStartPage 0</code>之后，再按下回车键；</li><li>重新启动 OrCAD 之后，就不会再弹出 <strong>Start Page</strong>页面；</li></ol><p>除此之外，更为有效的办法是直接对<code>C:\Cadence\Spb_data\cdssetup\OrCAD_Capture\17.4.0\Capture.ini</code>文件进行修改：</p><figure class="highlight js"><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></pre></td><td class="code"><pre><span class="line">[<span class="title class_">Preferences</span>]</span><br><span class="line">... ... ...</span><br><span class="line"><span class="title class_">EnableStartPage</span> = <span class="title class_">False</span>;</span><br><span class="line">... ... ...</span><br></pre></td></tr></table></figure><blockquote><p><strong>注意</strong>：上述操作必须在完全关闭 <strong>CadenceSPB</strong>之后进行，避免修改好的配置被覆盖丢失。除此之外，上述方法可能已经在<strong>Cadence SPB 17.4</strong> 的 <strong>S039</strong>版本失效，请用户酌情使用。</p></blockquote><p>关闭 <strong>Allegro</strong> 启动时自动显示【StartPage】页面的方法：</p><ol type="1"><li>鼠标依次点击 <strong>Allegro</strong> 菜单栏上的<code>Setup -&gt; User Preferences...</code>；</li><li>鼠标选中弹出【User PreferencesEditor】界面上的【Display】选项；</li><li>通过在界面底部的搜索框查找 <code>start</code>关键字，勾选查找结果列表中的 <code>allegro_no_startpage</code>项即可；</li></ol><h2 id="orcad-原理图快捷操作">【OrCAD 原理图快捷操作】</h2><table><thead><tr><th style="text-align: center;">OrCAD 快捷键</th><th style="text-align: left;">功能说明</th><th style="text-align: left;">应用环境</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>鼠标滚轮</strong></td><td style="text-align: left;">上下移动图纸</td><td style="text-align: left;">【原理图】编辑器</td></tr><tr><td style="text-align: center;"><strong>Shift + 鼠标滚轮</strong></td><td style="text-align: left;">左右移动图纸</td><td style="text-align: left;">【原理图】编辑器</td></tr><tr><td style="text-align: center;"><strong>Ctrl + 鼠标滚轮</strong></td><td style="text-align: left;">缩放图纸</td><td style="text-align: left;">【原理图】编辑器</td></tr><tr><td style="text-align: center;"><strong>B</strong></td><td style="text-align: left;">放置总线</td><td style="text-align: left;">【原理图】编辑器</td></tr><tr><td style="text-align: center;"><strong>E</strong></td><td style="text-align: left;">放置总线分支入口</td><td style="text-align: left;">【原理图】编辑器</td></tr><tr><td style="text-align: center;"><strong>F</strong></td><td style="text-align: left;">放置电源符号</td><td style="text-align: left;">【原理图】编辑器</td></tr><tr><td style="text-align: center;"><strong>G</strong></td><td style="text-align: left;">放置 <code>GND</code> 符号</td><td style="text-align: left;">【原理图】编辑器</td></tr><tr><td style="text-align: center;"><strong>J</strong></td><td style="text-align: left;">放置连接点</td><td style="text-align: left;">【原理图】编辑器</td></tr><tr><td style="text-align: center;"><strong>N</strong></td><td style="text-align: left;">放置网络别名</td><td style="text-align: left;">【原理图】编辑器</td></tr><tr><td style="text-align: center;"><strong>P</strong></td><td style="text-align: left;">放置元器件</td><td style="text-align: left;">【原理图】编辑器</td></tr><tr><td style="text-align: center;"><strong>T</strong></td><td style="text-align: left;">放置文本</td><td style="text-align: left;">【原理图】编辑器</td></tr><tr><td style="text-align: center;"><strong>W</strong></td><td style="text-align: left;">放置电气连线</td><td style="text-align: left;">【原理图】编辑器</td></tr><tr><td style="text-align: center;"><strong>Y</strong></td><td style="text-align: left;">放置图形连线</td><td style="text-align: left;">【原理图】编辑器</td></tr><tr><td style="text-align: center;"><strong>X</strong></td><td style="text-align: left;">放置无连接符号</td><td style="text-align: left;">【原理图】编辑器</td></tr><tr><td style="text-align: center;"><strong>Ctrl + B</strong></td><td style="text-align: left;">跳转到前一个 <code>Part</code></td><td style="text-align: left;">【原理图符号】编辑器</td></tr><tr><td style="text-align: center;"><strong>Ctrl + N</strong></td><td style="text-align: left;">跳转到后一个 <code>Part</code></td><td style="text-align: left;">【原理图符号】编辑器</td></tr><tr><td style="text-align: center;"><strong>Ctrl + E</strong></td><td style="text-align: left;">编辑属性</td><td style="text-align: left;">【原理图 &amp; 符号】编辑器</td></tr><tr><td style="text-align: center;"><strong>Ctrl + F</strong></td><td style="text-align: left;">查找</td><td style="text-align: left;">【原理图 &amp; 符号】编辑器</td></tr><tr><td style="text-align: center;"><strong>Ctrl + T</strong></td><td style="text-align: left;">吸附到栅格点</td><td style="text-align: left;">【原理图 &amp; 符号】编辑器</td></tr><tr><td style="text-align: center;"><strong>Ctrl + Y</strong></td><td style="text-align: left;">重做</td><td style="text-align: left;">【原理图 &amp; 符号】编辑器</td></tr><tr><td style="text-align: center;"><strong>Ctrl + Z</strong></td><td style="text-align: left;">撤销</td><td style="text-align: left;">【原理图 &amp; 符号】编辑器</td></tr><tr><td style="text-align: center;"><strong>F4</strong></td><td style="text-align: left;">重复操作</td><td style="text-align: left;">【原理图 &amp; 符号】编辑器</td></tr><tr><td style="text-align: center;"><strong>C</strong></td><td style="text-align: left;">以鼠标指针为中心</td><td style="text-align: left;">【原理图 &amp; 符号】编辑器</td></tr><tr><td style="text-align: center;"><strong>I</strong></td><td style="text-align: left;">放大</td><td style="text-align: left;">【原理图 &amp; 符号】编辑器</td></tr><tr><td style="text-align: center;"><strong>O</strong></td><td style="text-align: left;">缩小</td><td style="text-align: left;">【原理图 &amp; 符号】编辑器</td></tr><tr><td style="text-align: center;"><strong>R</strong></td><td style="text-align: left;">旋转</td><td style="text-align: left;">【原理图 &amp; 符号】编辑器</td></tr><tr><td style="text-align: center;"><strong>H</strong></td><td style="text-align: left;">水平镜像</td><td style="text-align: left;">【原理图 &amp; 符号】编辑器</td></tr><tr><td style="text-align: center;"><strong>V</strong></td><td style="text-align: left;">垂直镜像</td><td style="text-align: left;">【原理图 &amp; 符号】编辑器</td></tr><tr><td style="text-align: center;"><strong>E</strong></td><td style="text-align: left;">结束连线</td><td style="text-align: left;">【原理图 &amp; 符号】编辑器</td></tr></tbody></table><h2 id="预览-orcad-原理图符号的封装">预览 OrCAD 原理图符号的封装</h2><p>打开 <strong>OrCAD</strong> 的时候，界面底部的【SessionLog】会打印出，当前所使用的 INI 配置文件的路径：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">INI File Location: C:\Cadence\Spb_data\cdssetup\OrCAD_Capture\17.4.0\Capture.ini</span><br></pre></td></tr></table></figure><p>在 <code>Capture.ini</code> 配置文件当中检索<code>[Allegro Footprints]</code>，并将其修改为下面的形式，就可以通过<strong>OrCAD</strong> 鼠标右键菜单当中的【ShowFootprint】，预览原理图符号所对应的 PCB 封装：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[Allegro Footprints]</span><br><span class="line">Dir0=C:\Cadence\SPB_17.4\share\pcb\pcb_lib\symbols\</span><br><span class="line">Dir1=D:\Workspace\UINIO-Cadence-Libraries\Footprint\</span><br></pre></td></tr></table></figure><h2 id="orcad-与-allegro-交互式选择">OrCAD 与 Allegro 交互式选择</h2><p>首先，鼠标点击 <strong>OrCAD</strong> 顶部的<code>Options -&gt; Preference</code>；然后，切换【Preference】对话框至<code>Miscellaneous</code> 选项卡；最后，勾选界面当中的如下选项：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Intertool Commumicatiom -&gt; Enable Intertool Commmication</span><br></pre></td></tr></table></figure><h2 id="orcad-的选择过滤器">OrCAD 的选择过滤器</h2><ol type="1"><li>打开 <strong>OrCAD</strong>在原理图上展开鼠标右键菜单，选中【Selection Filter】或者按下快捷键【Ctrl+ I】打开<strong>选择过滤器</strong>对话框。</li><li>取消 <code>Graphical Object</code>项的勾选，就可以避免在框选原理图符号时，图形线框被错误的选中。</li></ol><h2 id="批量修改-orcad-原理图符号属性">批量修改 OrCAD原理图符号属性</h2><ol type="1"><li>首先，在 <strong>OrCAD</strong> 的原理图绘制界面按下快捷键【Ctrl +I】，在打开的 <strong>Selection Filter</strong> 对话框中只勾选<code>Parts</code> 项。</li><li>然后，在 <strong>OrCAD</strong>原理图绘制界面，使用鼠标<strong>框选</strong>需要批量修改属性的元件，点击鼠标右键菜单上面的<code>Edit Properties...</code>选项，或者也可以直接按下<strong>快捷键</strong>【Ctrl + E】。</li><li>最后，在随后打开的 <strong>Property Editor</strong>界面，鼠标选中<strong>整行</strong>或者<strong>整列</strong>的属性值，通过右键菜单中的<code>Edit</code> 或者<code>Display</code>，就可以对原理图符号的各项属性值（包括参数可见性、PCB封装信息等）进行批量调整。</li></ol><h2 id="为原理图添加-intersheet-references">为原理图添加 IntersheetReferences</h2><p>在分页原理图的<strong>跨页连接符</strong>前面加上引用的原理图页码，鼠标选中当前所要操作的<strong>OrCAD</strong>原理图工程，展开右键菜单选择【Annotate...】项，在弹出的<strong>Annotate</strong> 原理图注释对话框，鼠标点击<code>Add Intersheet References</code>，并进行下图所示的设置：</p><p><img src="/Electronics/Cadence-Skill/Intersheet/1.png"></p><p>点击确定按钮之后，在弹出的【IntersheetReferences】对话框里执行如下的通用设置：</p><p><img src="/Electronics/Cadence-Skill/Intersheet/2.png"></p><p>在上面【IntersheetReferences】对话框当中，各个设置项的具体意义如下所示：</p><hr><ul><li><code>Place On OffPage Connectors</code>：是否在跨页连接符放置<strong>引用页码</strong>（通常选择该项）；</li><li><code>Position -&gt; Offset Relative to Port</code>：以跨页连接符作为偏移基准；</li><li><code>Position -&gt; Offset Relative to Port Name</code>：以跨页连接符的<strong>名称</strong>作为偏移基准（通常选择该项）；</li></ul><hr><ul><li><code>Reset Positions -&gt; X Offset</code>：X轴偏移量（不能为负值），通常设置为 <code>10</code>；</li><li><code>Reset Positions -&gt; Y Offset</code>：Y轴偏移量（不能为负值），通常设置为 <code>0</code>；</li></ul><hr><ul><li><code>Format -&gt; Standard[1,2,3]</code>：页码格式为数字形式（通常选择该项）；</li><li><code>Format -&gt; Abbreviated[1..3]</code>：页码格式为缩写形式；</li><li><code>Format -&gt; Grid[1A5[Zone][Num]]</code>：页码格式为<code>行号 + 列号 + 页码</code> 的格式；</li></ul><hr><ul><li><code>Format -&gt; Prefix</code>：原理图页码的<strong>前缀</strong>，可以设置为<code>[]</code>、<code>&#123;&#125;</code>、<code>()</code>，通常设置为<code>[]</code>；</li><li><code>Format -&gt; Suffix</code>：原理图页码的<strong>后缀</strong>，可以设置为<code>[]</code>、<code>&#123;&#125;</code>、<code>()</code>，通常设置为<code>[]</code>；</li></ul><hr><h2 id="网络别名端口跨页连接符的区别">网络别名、端口、跨页连接符的区别</h2><p>使用 OrCAD 绘制原理图的时候，经常使用到下图从左至右展示的<strong>网络别名</strong>、<strong>端口</strong>、<strong>跨页连接符</strong>三个符号，虽然它们都用于表示相同属性名称之间的连接关系，但是各自的作用范围并不相同：</p><p><img src="/Electronics/Cadence-Skill/Alias-Port-Off-Page.png"></p><ol type="1"><li><strong>网络别名</strong>【NetAlias】：无独立符号，需要放置到导线上面，作用范围仅仅局限于当前原理图；</li><li><strong>端口</strong>【Port】：通常用于<strong>层次原理图</strong>设计，用于建立具有相同属性的端口之间的连接关系；</li><li><strong>跨页连接符</strong>【Off-PageConnector】：作用于多张原理图之间，但是不能在一张原理图里多次放置；</li></ol><h2 id="orcad-批量指定字体和图形的颜色">OrCAD批量指定字体和图形的颜色</h2><ol type="1"><li>首先，依次点击 OrCAD 菜单栏上的<code>View -&gt; Toolbar -&gt; Command Window</code>；</li><li>然后，使用鼠标框选当前需要指定颜色的 <strong>文字</strong> 和<strong>图形</strong>；</li><li>最后，在【Command Window】窗口输入<code>SetColor 颜色代码</code>；</li></ol><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></pre></td><td class="code"><pre><span class="line">SetColor 0    // 设置为黄色</span><br><span class="line">SetColor 4    // 设置为浅蓝色</span><br><span class="line">SetColor 6    // 设置为粉色</span><br></pre></td></tr></table></figure><div style="font-weight:bold;background-color: rgba(255, 204, 0, 1)">    0 黄色</div><div style="font-weight:bold;background-color: rgba(46, 209, 91, 1)">    3 深绿色</div><div style="font-weight:bold;background-color: rgba(0, 255, 255, 1)">    4 浅蓝色</div><div style="font-weight:bold;background-color: rgba(51, 102, 255, 1)">    5 蓝色</div><div style="font-weight:bold;background-color: rgba(255, 153, 204, 1)">    6 粉色</div><div style="font-weight:bold;background-color: rgba(255, 0, 0, 1)">    8 红色</div><div style="font-weight:bold;background-color: rgba(255, 255, 0, 1)">    9 浅黄色</div><div style="font-weight:bold;background-color: rgba(104, 243, 11, 1)">    10 浅绿色</div><div style="font-weight:bold;background-color: rgba(255, 0, 255, 1)">    15 亮粉色</div><h2 id="常见-orcap-原理图错误处理">常见 ORCAP 原理图错误处理</h2><h3 id="orcap-1589-多个网络别名">ORCAP-1589 多个网络别名</h3><p><code>ORCAP-1589</code>错误是指该网络存在多个<strong>网络别名</strong>，可能会造成短路。</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">WARNING(ORCAP-1589): Net has two or more aliases - possible short ?</span><br></pre></td></tr></table></figure><p>在 <strong>OrCAD</strong> 当中，属性为 <code>POWER</code>的引脚，引脚符号的名称，必须同时为对应网络的名称，否则就会报出该错误，该问题可以通过下面几种方式解决：</p><ol type="1"><li>属性为 <code>POWER</code>的引脚符号名称，保持其与对应网络的名称相同。</li><li>将 <code>POWER</code> 属性修改为<code>Passive</code>，就可以避免引脚名称与网络名称相同的问题。</li><li>取消【DRC】当中的 <code>Physical Rules</code> 检查，即在【DesignRules Check】对话框【Rules Setup】界面当中，取消<code>Check power ground short</code> 在 <code>Batch</code>项下面的勾选。</li></ol><h3 id="orcap-1376-多个网络别名">ORCAP-1376 多个网络别名</h3><p><strong>Heterogeneous</strong> [ˌhetərəˈdʒiːniəs]类型的元件由多个部分组成，如果 <strong>OrCAD</strong>原理图当中，放置了多个 <strong>Heterogeneous</strong>元件，那么在分配位号的时候，<strong>OrCAD</strong> 的 <strong>SessionLog</strong> 窗口就会报出 <code>ORCAP-1376</code> 错误信息：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ERROR(ORCAP-1376): Cannot package part <span class="string">&#x27;SFP?A(Value M42F-08P-020-P002G_0) at location (121.92, 139.70) on page 09-ETH-SFP-[0-6]&#x27;</span>, with multiple schematic symbols representing different <span class="built_in">functions</span>. Ensure package has similar parts.</span><br></pre></td></tr></table></figure><p>导致该错误的原因是 <strong>OrCAD</strong>无法分辨哪几些部分属于同一个 <strong>Heterogeneous</strong>元件，解决该问题可以遵循如下步骤：</p><ol type="1"><li>为 <strong>Heterogeneous</strong>元件的每一个组成部分，都添加一个自定义的 <code>Package</code>属性；</li><li>确保每一个 <strong>Heterogeneous</strong> 元件的各个组成部分<code>Package</code> 属性都相同；</li><li>分配位号的时候，在【Annotate】窗口的<code>Combined property string</code> 输入框内容的尾部添加<code>&#123;Package&#125;</code>；</li></ol><p><img src="/Electronics/Cadence-Skill/ORCAP/ORCAP-1376.png"></p><h2 id="orcadallegro-交互式网表的导入导出">OrCAD/Allegro交互式网表的导入导出</h2><h3 id="orcad-里设置交互功能">OrCAD 里设置交互功能</h3><p>鼠标点击 <strong>OrCAD</strong> 菜单栏上的<code>Options -&gt; Preferences...</code>，切换至【Preferences】对话框的【Miscellaneous】选项卡，勾选该选项卡下的<code>Intertool Communication</code>，开启 <strong>OrCAD</strong>的工具交互功能：</p><p><img src="/Electronics/Cadence-Skill/Netlist/1.png"></p><h3 id="orcad-导出网表">OrCAD 导出网表</h3><p>鼠标点击 <strong>OrCAD</strong> 菜单栏上的<code>Tools -&gt; Create Netlist...</code>或者直接点击工具栏上的图标，打开【Create Netlist】对话框：</p><p><img src="/Electronics/Cadence-Skill/Netlist/2.png"></p><p>紧接着在【Create Netlist】对话框里指定 <code>.dat</code><strong>网表文件</strong>导出的路径:</p><p><img src="/Electronics/Cadence-Skill/Netlist/3.png"></p><p><strong>OrCAD</strong> 导出的网表文件主要由<code>pstchip.dat</code>、<code>pstxprt.dat</code>、<code>pstxnet.dat</code>三个文件组成，它们各自的功能和用途请参考下面的表格：</p><table><thead><tr><th style="text-align: left;">网表文件名称</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>pstchip.dat</code></td><td style="text-align: left;">描述原理图当中元器件的引脚信息；</td></tr><tr><td style="text-align: left;"><code>pstxprt.dat</code></td><td style="text-align: left;">描述原理图当中元器件的封装信息；</td></tr><tr><td style="text-align: left;"><code>pstxnet.dat</code></td><td style="text-align: left;">描述原理图当中各个元器件之间的网络连接关系；</td></tr></tbody></table><h3 id="allegro-导入网表">Allegro 导入网表</h3><p>鼠标点击 <strong>Allegro</strong> 菜单栏上的<code>File -&gt; Import -&gt; Logic/Netlist...</code>，打开【Logic/Netlist...】对话框：</p><p><img src="/Electronics/Cadence-Skill/Netlist/4.png"></p><p>接下来在打开的【Logic/Netlist...】对话框中进行如下的设置（注意指定<strong>OrCAD</strong> 网表文件的所在目录）：</p><p><img src="/Electronics/Cadence-Skill/Netlist/5.png"></p><h2 id="allegro-自定义快捷键">【Allegro 自定义快捷键】</h2><p>合理配置 <strong>Allegro</strong> 的快捷键，可以大大提升 PCB设计效率。特别是对于从 <strong>Altium Designer</strong> 或者<strong>PADS</strong>迁移过来的工程师而言，可以最大化的保留自己的操作习惯：</p><figure class="highlight bash"><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><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br><span class="line">121</span><br><span class="line">122</span><br><span class="line">123</span><br><span class="line">124</span><br><span class="line">125</span><br><span class="line">126</span><br><span class="line">127</span><br><span class="line">128</span><br><span class="line">129</span><br><span class="line">130</span><br><span class="line">131</span><br><span class="line">132</span><br><span class="line">133</span><br><span class="line">134</span><br><span class="line">135</span><br><span class="line">136</span><br><span class="line">137</span><br><span class="line">138</span><br><span class="line">139</span><br><span class="line">140</span><br><span class="line">141</span><br><span class="line">142</span><br><span class="line">143</span><br><span class="line">144</span><br><span class="line">145</span><br><span class="line">146</span><br><span class="line">147</span><br><span class="line">148</span><br><span class="line">149</span><br><span class="line">150</span><br><span class="line">151</span><br><span class="line">152</span><br><span class="line">153</span><br><span class="line">154</span><br><span class="line">155</span><br><span class="line">156</span><br><span class="line">157</span><br><span class="line">158</span><br><span class="line">159</span><br><span class="line">160</span><br><span class="line">161</span><br><span class="line">162</span><br><span class="line">163</span><br><span class="line">164</span><br><span class="line">165</span><br><span class="line">166</span><br><span class="line">167</span><br><span class="line">168</span><br><span class="line">169</span><br><span class="line">170</span><br><span class="line">171</span><br><span class="line">172</span><br><span class="line">173</span><br><span class="line">174</span><br><span class="line">175</span><br><span class="line">176</span><br><span class="line">177</span><br><span class="line">178</span><br><span class="line">179</span><br><span class="line">180</span><br><span class="line">181</span><br><span class="line">182</span><br><span class="line">183</span><br><span class="line">184</span><br><span class="line">185</span><br><span class="line">186</span><br><span class="line">187</span><br><span class="line">188</span><br><span class="line">189</span><br><span class="line">190</span><br><span class="line">191</span><br><span class="line">192</span><br><span class="line">193</span><br><span class="line">194</span><br><span class="line">195</span><br><span class="line">196</span><br><span class="line">197</span><br><span class="line">198</span><br><span class="line">199</span><br><span class="line">200</span><br><span class="line">201</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">source</span> <span class="variable">$TELENV</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ====================== Funckey 快捷键（字母/数字键） ====================== #</span></span><br><span class="line"></span><br><span class="line">funckey m  <span class="string">&quot;move&quot;</span>                  <span class="comment">#移动元素</span></span><br><span class="line">funckey d  <span class="string">&quot;slide&quot;</span>                 <span class="comment">#调整走线与过孔</span></span><br><span class="line">funckey e  <span class="string">&quot;change&quot;</span>                <span class="comment">#改变元素属性</span></span><br><span class="line">funckey f  <span class="string">&quot;mirror&quot;</span>                <span class="comment">#元素换层</span></span><br><span class="line">funckey o  <span class="string">&quot;oops&quot;</span>                  <span class="comment">#撤回操作</span></span><br><span class="line">funckey n  <span class="string">&quot;cancel&quot;</span>                <span class="comment">#取消操作</span></span><br><span class="line">funckey M  <span class="string">&quot;pop mirror&quot;</span>            <span class="comment">#移动并且换层</span></span><br><span class="line">funckey r  <span class="string">&quot;iangle 90&quot;</span>             <span class="comment">#元素旋转90度</span></span><br><span class="line">funckey R  <span class="string">&quot;iangle 45&quot;</span>             <span class="comment">#元素旋转45度</span></span><br><span class="line">funckey b  <span class="string">&quot;hilight&quot;</span>               <span class="comment">#高亮元素</span></span><br><span class="line">funckey g  <span class="string">&quot;define grid&quot;</span>           <span class="comment">#栅格定义</span></span><br><span class="line">funckey w  <span class="string">&quot;add connect&quot;</span>           <span class="comment">#添加走线</span></span><br><span class="line">funckey v  <span class="string">&quot;toggle&quot;</span>                <span class="comment">#切换45°出线方向</span></span><br><span class="line">funckey y  <span class="string">&quot;flipdesign&quot;</span>            <span class="comment">#翻转设计</span></span><br><span class="line">funckey z  <span class="string">&quot;delay tune&quot;</span>            <span class="comment">#时延等长走线（单端）</span></span><br><span class="line">funckey q  <span class="string">&quot;phase tune&quot;</span>            <span class="comment">#相位等长走线（差分）</span></span><br><span class="line">funckey X  <span class="string">&quot;settoggle pcb_cursor infinite cross;redraw&quot;</span> <span class="comment">#全屏十字光标</span></span><br><span class="line"></span><br><span class="line">funckey -  <span class="string">&quot;cmgr&quot;</span>                  <span class="comment">#约束管理器</span></span><br><span class="line">funckey =  <span class="string">&quot;xsection&quot;</span>              <span class="comment">#叠层管理器</span></span><br><span class="line">funckey \  <span class="string">&quot;color192&quot;</span>              <span class="comment">#颜色管理器</span></span><br><span class="line">funckey o  <span class="string">&quot;artwork&quot;</span>               <span class="comment">#光绘控制表格</span></span><br><span class="line">funckey u  <span class="string">&quot;enved&quot;</span>                 <span class="comment">#用户偏好编辑器</span></span><br><span class="line"></span><br><span class="line">funckey ]  <span class="string">&quot;zoom in&quot;</span>               <span class="comment">#放大视图</span></span><br><span class="line">funckey [  <span class="string">&quot;zoom out&quot;</span>              <span class="comment">#缩小视图</span></span><br><span class="line"></span><br><span class="line">funckey ta <span class="string">&quot;add text&quot;</span>              <span class="comment">#添加文本</span></span><br><span class="line">funckey te <span class="string">&quot;text edit&quot;</span>             <span class="comment">#编辑文本</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#扇出</span></span><br><span class="line">funckey cf <span class="string">&quot;create fanout&quot;</span></span><br><span class="line"><span class="comment">#平滑走线</span></span><br><span class="line">funckey cs <span class="string">&quot;custom smooth&quot;</span></span><br><span class="line"></span><br><span class="line">funckey ,  <span class="string">&quot;rats net&quot;</span>              <span class="comment">#显示指定网络的飞线</span></span><br><span class="line">funckey .  <span class="string">&quot;unrats net&quot;</span>            <span class="comment">#隐藏指定网络的飞线</span></span><br><span class="line">funckey /  <span class="string">&quot;rats toggle &quot;</span>          <span class="comment">#切换飞线的显示与隐藏</span></span><br><span class="line">funckey i  <span class="string">&quot;grid toggle&quot;</span>           <span class="comment">#切换网格的显示与隐藏</span></span><br><span class="line"></span><br><span class="line">funckey ac  <span class="string">&quot;align components&quot;</span>      <span class="comment">#元素对齐</span></span><br><span class="line">funckey ar  <span class="string">&quot;assign color&quot;</span>          <span class="comment">#分配颜色</span></span><br><span class="line">funckey ad  <span class="string">&quot;deassign color&quot;</span>        <span class="comment">#取消颜色分配</span></span><br><span class="line">funckey ag  <span class="string">&quot;gloss param&quot;</span>           <span class="comment">#Gloss控制器</span></span><br><span class="line">funckey at  <span class="string">&quot;artwork&quot;</span>               <span class="comment">#光绘控制表格</span></span><br><span class="line">funckey ap  <span class="string">&quot;prmed&quot;</span>                 <span class="comment">#设计参数编辑器</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#指定过孔所属网络</span></span><br><span class="line">funckey vn  <span class="string">&quot;via assign net&quot;</span></span><br><span class="line"><span class="comment">#指定区域所属网络</span></span><br><span class="line">funckey sn  <span class="string">&quot;shape assign net&quot;</span></span><br><span class="line"></span><br><span class="line">funckey st  <span class="string">&quot;status&quot;</span>                <span class="comment">#查看元素状态</span></span><br><span class="line">funckey se  <span class="string">&quot;show element&quot;</span>          <span class="comment">#显示元素参数</span></span><br><span class="line">funckey sm  <span class="string">&quot;show measure&quot;</span>          <span class="comment">#显示测量数据</span></span><br><span class="line">funckey sc  <span class="string">&quot;swap components&quot;</span>       <span class="comment">#交换元素位置</span></span><br><span class="line">funckey sz  <span class="string">&quot;zcopy shape&quot;</span>           <span class="comment">#将形状拷贝到指定Class</span></span><br><span class="line">funckey sw  <span class="string">&quot;cns show&quot;</span>              <span class="comment">#展示所选元素的约束设置</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#添加多边形区域</span></span><br><span class="line">funckey sa  <span class="string">&quot;shape add&quot;</span></span><br><span class="line"><span class="comment">#删除孤岛区域</span></span><br><span class="line">funckey sd  <span class="string">&quot;island_delete&quot;</span></span><br><span class="line"><span class="comment">#添加矩形区域</span></span><br><span class="line">funckey sr  <span class="string">&quot;shape add rect&quot;</span></span><br><span class="line"><span class="comment">#选择区域</span></span><br><span class="line">funckey ss  <span class="string">&quot;shape select&quot;</span></span><br><span class="line"><span class="comment">#选择并且修改区域边界</span></span><br><span class="line">funckey sb  <span class="string">&quot;shape select;shape edit boundary&quot;</span></span><br><span class="line"><span class="comment">#禁止铺铜区域</span></span><br><span class="line">funckey sk  <span class="string">&quot;shape keepout&quot;</span></span><br><span class="line"><span class="comment">#铺铜区域显示方式切换</span></span><br><span class="line">funckey sf  <span class="string">&quot;settoggle no_shape_fill;redraw&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#自动捕捉</span></span><br><span class="line">funckey sp1  <span class="string">&quot;prepopup; pop dyn_option_select &#x27;Snap pick to@:@Segment Vertex&#x27;&quot;</span>     <span class="comment">#捕捉线段顶点</span></span><br><span class="line">funckey sp2  <span class="string">&quot;prepopup; pop dyn_option_select &#x27;Snap pick to@:@Segment Midpoint&#x27;&quot;</span>   <span class="comment">#捕捉线段中点</span></span><br><span class="line">funckey sp3  <span class="string">&quot;prepopup; pop dyn_option_select &#x27;Snap pick to@:@Segment&#x27;&quot;</span>            <span class="comment">#捕捉鼠标所在线段位置</span></span><br><span class="line">funckey sp4  <span class="string">&quot;prepopup; pop dyn_option_select &#x27;Snap pick to@:@Intersection&#x27;&quot;</span>       <span class="comment">#捕捉交点</span></span><br><span class="line">funckey sp5  <span class="string">&quot;prepopup; pop dyn_option_select &#x27;Snap pick to@:@Shape Center&#x27;&quot;</span>       <span class="comment">#捕捉铺铜区域的几何中心</span></span><br><span class="line">funckey sp6  <span class="string">&quot;prepopup; pop dyn_option_select &#x27;Snap pick to@:@Arc/Circle Center&#x27;&quot;</span>  <span class="comment">#捕捉圆/圆弧的圆心</span></span><br><span class="line">funckey sp7  <span class="string">&quot;prepopup; pop dyn_option_select &#x27;Snap pick to@:@Symbol Origin&#x27;&quot;</span>      <span class="comment">#捕捉元件的原点</span></span><br><span class="line">funckey sp8  <span class="string">&quot;prepopup; pop dyn_option_select &#x27;Snap pick to@:@Symbol Center&#x27;&quot;</span>      <span class="comment">#捕捉元件的中心</span></span><br><span class="line">funckey sp9  <span class="string">&quot;prepopup; pop dyn_option_select &#x27;Snap pick to@:@Pin&#x27;&quot;</span>                <span class="comment">#捕捉焊盘的中心</span></span><br><span class="line">funckey sp10 <span class="string">&quot;prepopup; pop dyn_option_select &#x27;Snap pick to@:@Via&#x27;&quot;</span>                <span class="comment">#捕捉过孔的中心</span></span><br><span class="line">funckey sp11 <span class="string">&quot;prepopup; pop dyn_option_select &#x27;Snap pick to@:@Figure&#x27;&quot;</span>             <span class="comment">#捕捉标记符号的中心</span></span><br><span class="line">funckey sp12 <span class="string">&quot;prepopup; pop dyn_option_select &#x27;Snap pick to@:@Pad Edge Vertex&#x27;&quot;</span>    <span class="comment">#捕捉焊盘顶点</span></span><br><span class="line">funckey sp13 <span class="string">&quot;prepopup; pop dyn_option_select &#x27;Snap pick to@:@Pad Edge Midpoint&#x27;&quot;</span>  <span class="comment">#捕捉焊盘中点</span></span><br><span class="line">funckey sp14 <span class="string">&quot;prepopup; pop dyn_option_select &#x27;Snap pick to@:@Pad Edge&#x27;&quot;</span>           <span class="comment">#捕捉焊盘边缘</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#切换到指定层</span></span><br><span class="line">funckey p  <span class="string">&quot;Jun_LayerEtch&quot;</span></span><br><span class="line"><span class="comment">#切换到丝印顶层</span></span><br><span class="line">funckey h  <span class="string">&quot;Jun_LayerTool st t&quot;</span></span><br><span class="line"><span class="comment">#切换到丝印底层</span></span><br><span class="line">funckey l  <span class="string">&quot;Jun_LayerTool sb t&quot;</span></span><br><span class="line"><span class="comment">#切换到下一层</span></span><br><span class="line">funckey k  <span class="string">&quot;Jun_LayerEtch Down&quot;</span></span><br><span class="line"><span class="comment">#切换到上一层</span></span><br><span class="line">funckey j  <span class="string">&quot;Jun_LayerEtch UP&quot;</span></span><br><span class="line"><span class="comment">#中心对齐焊盘 &amp; 过孔</span></span><br><span class="line">funckey .  <span class="string">&quot;Jun_SymbolTool&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#走线时切换线宽（单位 mil）</span></span><br><span class="line">funckey W5   <span class="string">&quot;options acon_line_width 5&quot;</span></span><br><span class="line">funckey W8   <span class="string">&quot;options acon_line_width 8&quot;</span></span><br><span class="line">funckey W10  <span class="string">&quot;options acon_line_width 10&quot;</span></span><br><span class="line">funckey W12  <span class="string">&quot;options acon_line_width 12&quot;</span></span><br><span class="line">funckey W16  <span class="string">&quot;options acon_line_width 16&quot;</span></span><br><span class="line">funckey W18  <span class="string">&quot;options acon_line_width 18&quot;</span></span><br><span class="line">funckey W20  <span class="string">&quot;options acon_line_width 20&quot;</span></span><br><span class="line">funckey W24  <span class="string">&quot;options acon_line_width 24&quot;</span></span><br><span class="line">funckey W28  <span class="string">&quot;options acon_line_width 28&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#预定义栅格尺寸</span></span><br><span class="line"><span class="built_in">alias</span> 0 <span class="string">&#x27;define grid;setwindow form.grid;FORM grid non_etch non_etch_x_grids 0.1;FORM grid non_etch non_etch_y_grids 0.1;FORM grid all_etch all_etch_x_grids 0.1;FORM grid all_etch all_etch_y_grids 0.1;FORM grid done;&#x27;</span>  <span class="comment">#0.1mil</span></span><br><span class="line"><span class="built_in">alias</span> 1 <span class="string">&#x27;define grid;setwindow form.grid;FORM grid non_etch non_etch_x_grids 1;FORM grid non_etch non_etch_y_grids 1;FORM grid all_etch all_etch_x_grids 1;FORM grid all_etch all_etch_y_grids 1;FORM grid done;&#x27;</span>          <span class="comment">#1mil</span></span><br><span class="line"><span class="built_in">alias</span> 2 <span class="string">&#x27;define grid;setwindow form.grid;FORM grid non_etch non_etch_x_grids 5;FORM grid non_etch non_etch_y_grids 5;FORM grid all_etch all_etch_x_grids 5;FORM grid all_etch all_etch_y_grids 5;FORM grid done;&#x27;</span>          <span class="comment">#5mil</span></span><br><span class="line"><span class="built_in">alias</span> 3 <span class="string">&#x27;define grid;setwindow form.grid;FORM grid non_etch non_etch_x_grids 10;FORM grid non_etch non_etch_y_grids 10;FORM grid all_etch all_etch_x_grids 10;FORM grid all_etch all_etch_y_grids 10;FORM grid done;&#x27;</span>      <span class="comment">#10mil</span></span><br><span class="line"><span class="built_in">alias</span> 4 <span class="string">&#x27;define grid;setwindow form.grid;FORM grid non_etch non_etch_x_grids 25;FORM grid non_etch non_etch_y_grids 25;FORM grid all_etch all_etch_x_grids 25;FORM grid all_etch all_etch_y_grids 25;FORM grid done;&#x27;</span>      <span class="comment">#25mil</span></span><br><span class="line"><span class="built_in">alias</span> 5 <span class="string">&#x27;define grid;setwindow form.grid;FORM grid non_etch non_etch_x_grids 50;FORM grid non_etch non_etch_y_grids 50;FORM grid all_etch all_etch_x_grids 50;FORM grid all_etch all_etch_y_grids 50;FORM grid done;&#x27;</span>      <span class="comment">#50mil</span></span><br><span class="line"><span class="built_in">alias</span> 6 <span class="string">&#x27;define grid;setwindow form.grid;FORM grid non_etch non_etch_x_grids 100;FORM grid non_etch non_etch_y_grids 100;FORM grid all_etch all_etch_x_grids 100;FORM grid all_etch all_etch_y_grids 100;FORM grid done;&#x27;</span>  <span class="comment">#100mil</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ====================== Alias 快捷键（功能键 + 字母/数字键） ====================== #</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">alias</span> ~3     <span class="string">&quot;3D&quot;</span>                    <span class="comment">#3D预览</span></span><br><span class="line"><span class="built_in">alias</span> ~C     <span class="string">&quot;copy&quot;</span>                  <span class="comment">#拷贝元素</span></span><br><span class="line"><span class="built_in">alias</span> ~V     <span class="string">&quot;paste&quot;</span>                 <span class="comment">#粘贴元素</span></span><br><span class="line"><span class="built_in">alias</span> ~D     <span class="string">&quot;drc update&quot;</span>            <span class="comment">#刷新DRC检查</span></span><br><span class="line"><span class="built_in">alias</span> ~P     <span class="string">&quot;placementedit&quot;</span>         <span class="comment">#切换到位置编辑模式</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">alias</span> Del    <span class="string">&quot;delete&quot;</span>                <span class="comment">#删除元素</span></span><br><span class="line"><span class="built_in">alias</span> Esc    <span class="string">&quot;done&quot;</span>                  <span class="comment">#完成操作</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#方向键移动元素（基于栅格尺寸）</span></span><br><span class="line"><span class="built_in">alias</span> Up     <span class="string">&quot;move;ipick_to_gridunit 0 +1&quot;</span></span><br><span class="line"><span class="built_in">alias</span> Down   <span class="string">&quot;move;ipick_to_gridunit 0 -1&quot;</span></span><br><span class="line"><span class="built_in">alias</span> Left   <span class="string">&quot;move;ipick_to_gridunit -1&quot;</span></span><br><span class="line"><span class="built_in">alias</span> Right  <span class="string">&quot;move;ipick_to_gridunit +1&quot;</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ====================== 自定义用户设置 ====================== #</span></span><br><span class="line"></span><br><span class="line"><span class="comment">#取消保存覆盖提示</span></span><br><span class="line"><span class="built_in">set</span> noconfirm_savedb</span><br><span class="line"><span class="comment">#指定光绘文件的输出目录</span></span><br><span class="line"><span class="built_in">set</span> ads_sdart = Gerbers</span><br><span class="line"><span class="comment">#取消模块复用之后，元件被锁定</span></span><br><span class="line"><span class="built_in">set</span> disable_module_auto_lock</span><br><span class="line"><span class="comment">#取消模块复用之后，铺铜从动态自动转换为静态</span></span><br><span class="line"><span class="built_in">set</span> disable_module_shape_convert</span><br><span class="line"><span class="comment">#取消线宽记忆，使用约束管理器默认值</span></span><br><span class="line"><span class="built_in">set</span> acon_no_width_override_retain</span><br><span class="line"><span class="comment">#设置撤回操作占用的最大 MB 值</span></span><br><span class="line"><span class="built_in">set</span> max_undo_memory = 500</span><br><span class="line"><span class="comment">#设置撤回次数（取值范围 0~50 次）</span></span><br><span class="line"><span class="built_in">set</span> undo_depth = 50</span><br><span class="line"><span class="comment">#显示等长绕线时进度条</span></span><br><span class="line"><span class="built_in">set</span> allegro_dynam_timing = on</span><br><span class="line"><span class="comment">#等长绕线进度条被固定在窗口右上角显示</span></span><br><span class="line"><span class="built_in">set</span> allegro_dynam_timing_fixedpos</span><br><span class="line"><span class="comment">#实时显示走线长度</span></span><br><span class="line"><span class="built_in">set</span> allegro_etch_length_on</span><br><span class="line"><span class="comment">#走线时相同网络的元素高亮</span></span><br><span class="line"><span class="built_in">set</span> acon_oldhlt = all</span><br><span class="line"><span class="comment">#铺铜避让走线的形状为圆形</span></span><br><span class="line"><span class="built_in">set</span> av_endcapstyle = round</span><br><span class="line"><span class="comment">#显示实心的 DRC 标志</span></span><br><span class="line"><span class="built_in">set</span> display_drcfill</span><br><span class="line"><span class="comment">#展示mm、mil两种单位的测量结果</span></span><br><span class="line"><span class="built_in">set</span> showmeasure_altunits = mm</span><br><span class="line"><span class="comment">#分配区域网络时，高亮相同网络全部元素</span></span><br><span class="line"><span class="built_in">set</span> highlight_shape_net</span><br><span class="line"><span class="comment">#自动存档（取值范围 10~300 分钟）</span></span><br><span class="line"><span class="built_in">set</span> autosave</span><br><span class="line"><span class="built_in">set</span> autosave_time = 10</span><br><span class="line"><span class="comment">#允许使用反斜杠 \ 作用网络名称</span></span><br><span class="line"><span class="built_in">set</span> legacy_character_set</span><br><span class="line"><span class="comment">#区域是否轮廓显示</span></span><br><span class="line"><span class="built_in">unset</span> no_shape_fill</span><br><span class="line"><span class="comment">#设置鼠标滚轮缩放系数</span></span><br><span class="line"><span class="built_in">set</span> buttonfactor = 0.5</span><br><span class="line"><span class="comment">#3D预览时不弹出过滤器对话框</span></span><br><span class="line"><span class="built_in">set</span> hide_unified_filter_dialog</span><br><span class="line"><span class="comment">#设置手动修改与创建网络功能</span></span><br><span class="line"><span class="built_in">set</span> logic_edit_enabled</span><br><span class="line"></span><br><span class="line"><span class="comment">### User Preferences section</span></span><br><span class="line"><span class="comment">### This section is computer generated.</span></span><br><span class="line"><span class="comment">### Please do not modify to the end of the file.</span></span><br><span class="line"><span class="comment">### Place your hand edits above this section.</span></span><br><span class="line"><span class="comment">###</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># ====================== Allegro 焊盘 &amp; 封装配置 ====================== #</span></span><br><span class="line"></span><br><span class="line"><span class="built_in">set</span> devpath = <span class="variable">$psmpath</span> D:/Workspace/UINIO-Cadence-Libraries/Footprint/Cadence D:/Workspace/UINIO-Cadence-Libraries/Footprint/Via</span><br><span class="line"><span class="built_in">set</span> padpath = <span class="variable">$padpath</span> D:/Workspace/UINIO-Cadence-Libraries/Footprint/Cadence D:/Workspace/UINIO-Cadence-Libraries/Footprint/Via</span><br><span class="line"><span class="built_in">set</span> psmpath = <span class="variable">$devpath</span> D:/Workspace/UINIO-Cadence-Libraries/Footprint/Cadence D:/Workspace/UINIO-Cadence-Libraries/Footprint/Via</span><br></pre></td></tr></table></figure><p>在 <strong>Allegro</strong>的【Command】窗口当中，输入如下的命令可以打印出当前所使用的用户环境变量路径：</p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">echo</span> <span class="variable">$localenv</span></span><br></pre></td></tr></table></figure><p>通过修改该环境变量路径下的 <code>env</code> 文件，就可以使用<code>alias</code> 和 <code>funckey</code>命令进行自定义快捷键。根据当前 <strong>Cadence</strong>安装环境的不同，打印出的用户环境变量路径会存在如下两种情况（按需修改即可）：</p><ul><li><code>C:\Cadence\SPB_Data\pcbenv</code></li><li><code>C:\Cadence\SPB_17.4\share\pcb\text</code></li></ul><p>如果 <code>env</code> 文件位于<code>C:\Cadence\SPB_Data\pcbenv</code> 目录下，自定义的配置信息需要放到<code>env</code> 文件的如下位置，以避免被其它配置项覆盖：</p><p><img src="/Electronics/Cadence-Skill/Allegro-Shortkey/1.png"></p><blockquote><p><strong>注意</strong>： <code>C:\Cadence\SPB_Data\pcbenv</code>目录下的 <code>env</code> 文件顶部必须保留 <code>source $TELENV</code>字段，否则会导致 <strong>Allegro</strong> 启动错误。</p></blockquote><p>如果 <code>env</code> 文件位于<code>C:\Cadence\SPB_17.4\share\pcb\text\env</code>目录下，自定义配置信息则建议放置到 <code>env</code> 文件的如下位置：</p><p><img src="/Electronics/Cadence-Skill/Allegro-Shortkey/2.png"></p><p><code>alias</code> 命令用于对 <strong>Allegro</strong>命令取别名，使用时需要同时按下 <code>特殊功能键</code> 或者<code>特殊功能键 + 字母/数字</code>组合，并不能定义单独的字母快捷键：</p><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"><span class="built_in">alias</span> &lt;<span class="built_in">alias</span>&gt; &lt;<span class="built_in">command</span> to run&gt;</span><br><span class="line"><span class="built_in">alias</span> &lt;<span class="built_in">alias</span>&gt; “&lt;command1; command2&gt;”</span><br></pre></td></tr></table></figure><ul><li><code>alias F2  Add Connect</code>：这里 <code>F2</code>是指键盘上的<strong>特殊功能键</strong>【F2】；</li><li><code>alias ~W  Add Connect</code>：符号 <code>~</code> 用于表示<code>Ctrl</code> 按键，表示的是同时按下【Ctrl + W】；</li><li><code>alias CF2 Add Connect</code>：字母 <code>C</code> 等同于<code>Ctrl</code> 按键，表示的是同时按下【Ctrl + F2】；</li></ul><blockquote><p><strong>注意</strong>：<code>alias</code> 命令里的 <code>C</code>代表按键【Ctrl】，<code>S</code> 代表按键【Shift】。</p></blockquote><p><code>funckey</code>命令用于定义单独的<strong>字母</strong>快捷键，在 PCB版图上按下该字母，或者在<strong>Allegro</strong>的【Command】窗口输入该命令，就可以执行相应的功能：</p><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">funckey &lt;user-defined key or name&gt; &lt;<span class="built_in">command</span> to run&gt;</span><br><span class="line">funckey &lt;user-defined key or name&gt; “&lt;command1; command2&gt;”</span><br></pre></td></tr></table></figure><ul><li><code>funckey r iangle 90</code>：小写字母 <code>r</code>用于宣传正在移动的 PCB 封装 90° 度；</li><li><code>funckey R iangle 45</code>：大写字母 <code>R</code>用于宣传正在移动的 PCB 封装 45° 度；</li></ul><p>鼠标依次点击 <strong>Allegro</strong> 菜单栏上的【Tools -&gt;Utilities -&gt; KeyboardCommands】，就可以打开<strong>命令浏览器</strong>【CommandBrowser】窗口，浏览当前 Cadence 可以被执行和定义的命令：</p><p><img src="/Electronics/Cadence-Skill/Allegro-Shortkey/3.png"></p><blockquote><p><strong>注意</strong>：<strong>命令浏览器</strong>当中的【Execute】用于执行列表中的命令，【Help】用于单击查看列表当中命令的帮助文档。</p></blockquote><h2 id="关闭-allegro-手动保存提示">关闭 Allegro 手动保存提示</h2><ol type="1"><li>首先，鼠标依次点击 <strong>Allegro</strong> 菜单栏上的<code>Setup -&gt; User Preferences...</code>；</li><li>然后，在弹出界面【User Preferences Editor】左下角的<code>Search for preference</code> 输出框里输入 <code>save</code>关键字，然后按下【Search】按钮或者回车键。</li><li>最后，勾选 <code>noconfirm_savedb</code>的【Value】和【Favorite】即可关闭 <strong>Allegro</strong>的保存提示功能。</li></ol><h2 id="指定-allegro-的-pcb-封装库路径">指定 Allegro 的 PCB封装库路径</h2><ol type="1"><li>首先，鼠标依次点击 <strong>Allegro</strong> 菜单栏上的<code>Setup -&gt; User Preferences...</code>；</li><li>然后，打开【User Preferences Editor】对话框左侧树形菜单中的<code>Paths -&gt; Library</code>；</li></ol><p>勾选打开界面当中<code>devpath</code>、<code>padpath</code>、<code>psmpath</code>后的【Favorite】选项，并且指定其【Value】项对应的资源路径：</p><ol type="1"><li><code>devpath</code>指定<strong>第三方网表文件</strong>的保存路径（如果当时导入的是 OrCAD生成的网表，则保持默认即可）；</li><li><code>padpath</code> 用于指定 PCB封装<strong>焊盘</strong>的存放路径。</li><li><code>psmpath</code> 用于指定 PCB<strong>封装</strong>的存放路径。</li></ol><h2 id="预览-allegro-里导入的-pcb-封装">预览 Allegro 里导入的 PCB封装</h2><ol type="1"><li>当 <strong>Allegro</strong> 新建或者打开 <code>.brd</code>文件之后，鼠标点击 <strong>Allegro</strong> 菜单栏上的<code>Place -&gt; Manually</code>；</li><li>在弹出的【Placement】对话框中选择【AdvancedSettings】选项卡，然后勾选界面上的 <code>Library</code> 选项；</li><li>将选项卡切换回【Placement】对话框当中的【PlacementList】选项卡；</li><li>切换至下拉列表里的【Package symbols】，就可以浏览到当前引用的 PCB封装（可以通过右侧的【Selection filters】查询和过滤）：</li></ol><h2 id="allegro-的-move-命令选项">Allegro 的 Move 命令选项</h2><p>在 <strong>Allegro</strong> 当中执行元素移动命令 Move时，需要注意【Option】窗口中的如下参数选项：</p><ul><li><code>Ripup etch</code>：移动对象时，<strong>去除</strong>所有的<code>走线</code> 与 <code>过孔</code>；</li><li><code>Slide etch</code>：移动对象时，保留 <code>走线</code> 和<code>过孔</code>，但走线伴随对象<strong>平滑</strong>移动；</li><li><code>Stretch etch</code>：移动对象时，保留 <code>走线</code> 和<code>过孔</code>，但走线伴随对象<strong>任意角度</strong>移动；</li><li><code>上述三项都不勾选</code>：表示只移动对象，完全<strong>不影响</strong><code>走线</code> 和 <code>过孔</code>；</li></ul><p><img src="/Electronics/Cadence-Skill/Move.png"></p><p><strong>Point</strong>属性用于设置元素旋转时的<strong>基准点</strong>，<strong>Allegro</strong>提供了如下几种方式：</p><ul><li><code>Sym Origin</code>：以元件<strong>封装的原点</strong>作为基准点；</li><li><code>Body Center</code>：以元件的 <code>place_bound</code>几何中心作为基准，常用于<strong>各个元件的就地旋转</strong>；</li><li><code>User Pick</code>：以用户鼠标单击的<strong>选择点</strong>作为基准，常用于<strong>多个元件的整体旋转</strong>；</li><li><code>Sym Pin#</code>：以指定的<strong>元件引脚编号</strong>作为基准点，常用于元件结构相关的定位；</li></ul><blockquote><p><strong>注意</strong>：上述参数中的 <code>Sym Origin</code> 和<code>Body Center</code> 与 PCB 封装绘制得是否规范密切相关。</p></blockquote><h2 id="allegro-的-room-模块化布局">Allegro 的 ROOM 模块化布局</h2><ol type="1"><li>添加 <code>ROOM</code> 属性：<strong>OrCAD</strong>当中为元件添加自定义的 <code>ROOM</code>属性（相同的模块，属性值相同）。</li><li>绘制 <code>ROOM</code> 框：鼠标依次点击 <strong>Allegro</strong>菜单栏的<code>Setup -&gt; Outlines -&gt; ROOM Outline</code>，打开【ROOMOutline】对话框之后，直接在 <strong>Allegro</strong>的绘制区域点击拖动，就可以为具有相同 <code>ROOM</code>属性值的元件绘制出一个放置区域。</li><li>根据 <code>ROOM</code> 属性放置元件：鼠标依次点击<strong>Allegro</strong> 菜单栏的【Place -&gt;Quickplace】，勾选对话框里【Placement filter】下的<code>Place by room</code>，并且在后面的下拉列表当中，指定当前需要放置的<code>ROOM</code>属性元件，最后点击对话框上的【Place】按钮，即可将具有相同<code>ROOM</code> 属性值的元件摆放到指定的 <code>Outline</code>区域当中。</li></ol><h2 id="开启-allegro-的移动对齐辅助线">开启 Allegro的移动对齐辅助线</h2><ol type="1"><li>在 <strong>Allegro</strong>当中，选择移动命令，然后按下鼠标右键；</li><li>依次选择弹出菜单中的<code>Options -&gt; Dynamic Aligment -&gt; Enable</code>，就可以开启<strong>移动对齐辅助线</strong>；</li></ol><h2 id="从-allegro-工程导出-pcb-封装">从 Allegro 工程导出 PCB 封装</h2><h3 id="从-allegro-导出-.dra-封装库源文件">从 Allegro 导出 .dra封装库源文件</h3><p>使用 Allegro 打开已有的 PCB 版图文件 <code>.brd</code>之后，可以导出当前 PCB 版图所涉及的各种封装文件：</p><p><img src="/Electronics/Cadence-Skill/Export/Libraries.png"></p><ol type="1"><li>鼠标依次点击 Allegro 菜单栏上的<code>File -&gt; Export -&gt; Libraries...</code>;</li><li>在弹出的【Export Libraries】对话框当中，勾选<code>No library dependencies</code>，并在<code>Export to directory</code> 填写 PCB 封装的导出路径；</li><li><strong>Allegro</strong> 就会自动将 PCB 封装源文件<code>.dra</code>、PCB 封装文件 <code>.psm</code>、PCB 封装描述文件<code>.txt</code> 导出到指定的目录当中。</li></ol><h3 id="从封装库源文件导出-.pad-焊盘文件">从封装库源文件导出 .pad焊盘文件</h3><p>基于已有的 PCB 封装源文件 <code>.dra</code>，可以进一步导出指定的<code>.pad</code> 焊盘文件：</p><p><img src="/Electronics/Cadence-Skill/Export/Pad.png"></p><ol type="1"><li>依次点击 <strong>Allegro</strong> 菜单栏上的<code>Tools -&gt; Padstack -&gt; Modify Design Padstack...</code></li><li>在 <strong>Allegro</strong> 当中打开 <code>.dra</code>文件，并且选中一个焊盘；</li><li>然后展开鼠标右键，选择【Edit】对该焊盘进行编辑，此时会弹出【PadstackEditor】窗口；</li><li>鼠标依次选择弹出界面当中的【File -&gt; Save As...】，就可以将<code>.pad</code> 焊盘文件导出到指定目录；</li></ol><h3 id="从封装库源文件导出-.txt-封装信息">从封装库源文件导出 .txt封装信息</h3><p>基于已有的 PCB 封装源文件 <code>.dra</code>，还可以导出以<code>.txt</code> 作为后缀的 PCB 封装信息文件：</p><p><img src="/Electronics/Cadence-Skill/Export/Info.png"></p><ol type="1"><li>鼠标依次点击 <strong>Allegro</strong> 菜单栏上的<code>File -&gt; Create Device...</code>；</li><li>在弹出的【Create DeviceFile】窗口选择当前所要导出的<strong>元件类型</strong><code>Device Type</code>（默认包含<code>IC</code>、<code>IO</code>、<code>DISCRETE</code>三个选项）；</li><li>按下【OK】按钮之后，就会自动将 <code>.txt</code>封装信息文件导出至当前 <code>.dra</code> 文件所在的目录；</li></ol><h3 id="从封装库源文件导出-.psm-封装文件">从封装库源文件导出 .psm封装文件</h3><p>基于已有的 PCB 封装源文件 <code>.dra</code>，可以进一步导出<strong>Allegro</strong> 实际使用的 PCB 封装文件 <code>.psm</code>：</p><p><img src="/Electronics/Cadence-Skill/Export/Footprint.png"></p><ol type="1"><li>鼠标依次点击 <strong>Allegro</strong> 菜单栏上的<code>File -&gt; Create Symbol...</code>;</li><li>在弹出的【Create Symbol】对话框当中，选择 <code>.psm</code>封装文件的保存位置；</li><li><strong>Allegro</strong> 就会自动将 <code>.psm</code>封装文件导出到指定的目录；</li></ol><h2 id="修改-.dra-封装源文件的-pin-number">修改 .dra 封装源文件的 PinNumber</h2><ol type="1"><li>使用 <strong>Allegro</strong> 打开 <code>.dra</code>封装源文件；</li><li>切换 <strong>Allegro</strong> 界面右侧【Options】选项卡里的<strong>Active Class</strong> 为<code>Package Geometry</code>，<strong>Subclass</strong> 为<code>Pin_Number</code>；</li><li>鼠标点击 <strong>Allegro</strong> 菜单栏上的<code>Edit -&gt; Text</code>；</li><li>鼠标选中 <strong>Allegro</strong> 工作区的封装焊盘，即可以实现对<code>Pin Number</code> 的修改。</li></ol><p><img src="/Electronics/Cadence-Skill/Pin-Number.png"></p><h2 id="allegro-导出-.dra-中的-.pad-焊盘文件">Allegro 导出 .dra 中的.pad 焊盘文件</h2><p>使用 <strong>Allegro</strong> 打开需要处理的 <code>.dra</code>封装源文件，鼠标点击【Tools -&gt; Padstack -&gt; Modify DesignPadstack】</p><p><img src="/Electronics/Cadence-Skill/DRA-PAD/1.png"></p><p>鼠标双击 <strong>Allegro</strong>右侧工作面板【Option】选项卡上面，当前需要导出的焊盘名称：</p><p><img src="/Electronics/Cadence-Skill/DRA-PAD/2.png"></p><p>在弹出的【Padstack Designer】窗口，鼠标依次点击<code>File -&gt; Save As...</code>，即可将 <code>.pad</code>焊盘文件保存到其所属 <code>.dra</code> 封装源文件所在的目录：</p><p><img src="/Electronics/Cadence-Skill/DRA-PAD/3.png"></p><h2 id="cross-section-叠层的定义与添加">Cross Section叠层的定义与添加</h2><p>官方建议在 <strong>Allegro</strong>当中，信号层采用<strong>正片层</strong>方式处理，电源层和接地线层采用<strong>负片层</strong>方式处理，这样可以减少工程文件的数据量，并且提升EDA 软件的运行效率：</p><ul><li><strong>Conductor</strong>：<strong>正片层</strong>，即用于正常走线的<strong>信号层</strong>；</li><li><strong>Plane</strong>：<strong>负片层</strong>，被默认铺铜填充（走线被视为分割线）的<strong>电源层</strong>或者<strong>接地层</strong>，也被称为<strong>内电层</strong>；</li></ul><blockquote><p><strong>注意</strong>：<strong>内电层</strong>在<strong>Allegro</strong> 的 <code>Anti Etch</code> 层，使用大于或者等于<code>15mil</code> 的分隔线进行分割。然后使用鼠标右键菜单的<code>Assign Net</code> 分配网络。</p></blockquote><p>鼠标点击 <strong>Allegro</strong> 菜单栏上的<code>Setup -&gt; Cross Section</code>项，或者直接点击菜单栏上的【Xsection】按钮，就可以进入 PCB叠层管理器【Cross-section Editor】进行相关参数的设置：</p><p><img src="/Electronics/Cadence-Skill/Cross-Section/1.png"></p><p>鼠标点击【Cross-section Editor】窗口当中表格的 <code>Name</code>列，选择右键菜单上的【Add Layer】项，就可以添加新的 PCB 叠层：</p><p><img src="/Electronics/Cadence-Skill/Cross-Section/2.png"></p><blockquote><p><strong>注意</strong>：<strong>Dielectric</strong> [ˌdaɪɪˈlektrɪk]n.电介质，绝缘体。</p></blockquote><p>鼠标双击 <code>Name</code> 列还可以修改叠层的名称，命名方式推荐使用<code>层名称缩写 + 层顺序编号</code>格式，例如：<code>TOP</code>、<code>GND2、SIN3</code>、<code>SIN4</code>、<code>PWR5</code>、<code>BOTTOM</code>等：</p><p><img src="/Electronics/Cadence-Skill/Cross-Section/3.png"></p><blockquote><p><strong>注意</strong>：除此之外还可以根据 PCB生产企业提供的工艺制造参数（例如《<a href="https://tools.jlc.com/jlcTools/#/impedanceDefaultTemplate"><strong>嘉立创层压结构</strong></a>》），选择相应的PCB 叠层<code>厚度</code>（Thickness）、<code>材质</code>（Material）、<code>电导率</code>（Conductivity）、<code>介电常数</code>（DielectricConstant）等参数。</p></blockquote><p>值得注意的是，PCB 的<strong>负片层</strong>也是在【Cross-sectionEditor】窗口当中进行设置的：</p><p><img src="/Electronics/Cadence-Skill/Negative-Artwork.png"></p><h2 id="切换-allegro-单位为-mil-或者-mm">切换 Allegro 单位为 mil 或者mm</h2><p>鼠标依次选择 <strong>Allegro</strong> 菜单栏上的<code>Setup -&gt; Design Parameters...</code>，在弹出的<strong>设计参数编辑器</strong>【DesignParameters Editor】窗口，修改【Design】选项卡下面的<code>User units</code> 下拉菜单：</p><p><img src="/Electronics/Cadence-Skill/Unit.png"></p><h2 id="设置-allegro-工作区栅格大小">设置 Allegro 工作区栅格大小</h2><p>鼠标依次选择 <strong>Allegro</strong> 菜单栏上的<code>Setup -&gt; Grids...</code>，在弹出的<strong>栅格定义窗口</strong>【DefineGrid】，就可以分别设置各个<strong>叠层</strong>的栅格大小（设置为<code>5mil</code> <code>0.127mm</code> 更加方便元器件对齐）：</p><p><img src="/Electronics/Cadence-Skill/Grid.png"></p><blockquote><p><strong>注意</strong>：为了方便元件对齐与摆放，推荐布局时使用<code>5mil/0.127mm</code> 的栅格。</p></blockquote><h2 id="allegro-的-class-与-subclass-概念">Allegro 的 Class 与 Subclass概念</h2><p><strong>Allegro</strong> 当中的<strong>类型</strong><code>Class</code> 与 <strong>子类型</strong> <code>Subclass</code>是这款设计工具当中的基本概念，当前绘制在 PCB 版图当中的所有对象都会以<strong>Class</strong> 和 <strong>Subclass</strong>进行管理。就像每一名学生都归属为某个年级与某个班级，这里年级与班级就可以分别被理解为<code>Class</code> 与 <code>Subclass</code>，下图展示了<strong>Allegro</strong> 当中一些默认的 <strong>Class</strong>：</p><p><img src="/Electronics/Cadence-Skill/Class-Subclass/1.png"></p><blockquote><p><strong>注意</strong>：在一些特定的系统 <code>Class</code>下面，可以创建自定义的 <code>Subclass</code>。</p></blockquote><p>例如<strong>电气层</strong> <code>Etch</code> 这个<strong>Class</strong> 下面，对应着 <code>Top</code> 和<code>Bottom</code> 两个 <strong>SubClass</strong>：</p><p><img src="/Electronics/Cadence-Skill/Class-Subclass/2.png"></p><p>例如 PCB版图相关的<strong>几何形状层</strong>（板框、丝印、尺寸标注等）都被放置在<code>Board Geometry</code> 这个 <strong>Class</strong>下面，对应着下图当中的各个 <strong>SubClass</strong>：</p><p><img src="/Electronics/Cadence-Skill/Class-Subclass/3.png"></p><p><strong>Allegro</strong> 当中 <code>Class</code> 和<code>Subclass</code> 的名称本身没有任何意义，关键在于当把 PCB版图上的对象放置到 <code>Class</code> 或者 <code>Subclass</code>的时候，<strong>Allegro</strong> 如何去使用和处理这些对象。例如<strong>Allegro</strong> 导入 PCB 封装的时候，PCB封装当中的各个对象就会自动被放置在相应的 <code>Class</code>当中进行管理，因为这些对象在 PCB 封装创建的时候就已经被指定了相应的<code>Class</code>。</p><blockquote><p><strong>注意</strong>：<strong>Allegro</strong> 导入<code>.dxf</code> 板框时，默认会自动新建一个 PCB 文件覆盖当前的 PCB工程，如果想将 <code>.dxf</code> 板框导入到当前的 PCB文件，则必须勾选【DXF In】对话框当中的<code>Incremental addition</code>。</p></blockquote><p><strong>电气布局走线</strong>相关的常用 <strong>Class</strong> 与<strong>Subclass</strong> 如下面表格所示：</p><table><colgroup><col style="width: 29%"><col style="width: 8%"><col style="width: 12%"><col style="width: 13%"><col style="width: 8%"><col style="width: 27%"></colgroup><thead><tr><th style="text-align: left;">Class  SubClass</th><th style="text-align: center;"><code>top</code></th><th style="text-align: center;"><code>inner</code></th><th style="text-align: center;"><code>bottom</code></th><th style="text-align: center;"><code>all</code></th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>anti etch</code></td><td style="text-align: center;">✔</td><td style="text-align: center;">✔</td><td style="text-align: center;">✔</td><td style="text-align: center;">✔</td><td style="text-align: left;">用于切割覆铜</td></tr><tr><td style="text-align: left;"><code>etch</code></td><td style="text-align: center;">✔</td><td style="text-align: center;">✔</td><td style="text-align: center;">✔</td><td style="text-align: center;">-</td><td style="text-align: left;">用于电气连接</td></tr><tr><td style="text-align: left;"><code>package keepin</code></td><td style="text-align: center;">-</td><td style="text-align: center;">-</td><td style="text-align: center;">-</td><td style="text-align: center;">✔</td><td style="text-align: left;">允许放置元件区域</td></tr><tr><td style="text-align: left;"><code>package keepout</code></td><td style="text-align: center;">✔</td><td style="text-align: center;">-</td><td style="text-align: center;">✔</td><td style="text-align: center;">✔</td><td style="text-align: left;">禁止放置元件区域</td></tr><tr><td style="text-align: left;"><code>route keepin</code></td><td style="text-align: center;">-</td><td style="text-align: center;">-</td><td style="text-align: center;">-</td><td style="text-align: center;">✔</td><td style="text-align: left;">允许布线区</td></tr><tr><td style="text-align: left;"><code>route keepout</code></td><td style="text-align: center;">✔</td><td style="text-align: center;">✔</td><td style="text-align: center;">✔</td><td style="text-align: center;">✔</td><td style="text-align: left;">禁止布线区</td></tr><tr><td style="text-align: left;"><code>via keepout</code></td><td style="text-align: center;">✔</td><td style="text-align: center;">✔</td><td style="text-align: center;">✔</td><td style="text-align: center;">✔</td><td style="text-align: left;">禁止过孔区</td></tr></tbody></table><p><strong>工艺装配标注</strong> 相关的常用 <strong>Class</strong> 与<strong>Subclass</strong> 如下面表格所示：</p><table style="width:100%;"><colgroup><col style="width: 24%"><col style="width: 19%"><col style="width: 22%"><col style="width: 11%"><col style="width: 22%"></colgroup><thead><tr><th style="text-align: left;">Class  SubClass</th><th style="text-align: center;"><code>board geometry</code></th><th style="text-align: center;"><code>package geometry</code></th><th style="text-align: center;"><code>ref des</code></th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>soldermask_top</code></td><td style="text-align: center;">✔</td><td style="text-align: center;">✔</td><td style="text-align: center;">-</td><td style="text-align: left;">顶层阻焊层</td></tr><tr><td style="text-align: left;"><code>soldermask bottom</code></td><td style="text-align: center;">✔</td><td style="text-align: center;">✔</td><td style="text-align: center;">-</td><td style="text-align: left;">底层阻焊层</td></tr><tr><td style="text-align: left;"><code>silkscreen top</code></td><td style="text-align: center;">✔</td><td style="text-align: center;">✔</td><td style="text-align: center;">✔</td><td style="text-align: left;">顶层丝印层</td></tr><tr><td style="text-align: left;"><code>silkscreen_bottom</code></td><td style="text-align: center;">✔</td><td style="text-align: center;">✔</td><td style="text-align: center;">✔</td><td style="text-align: left;">底层丝印层</td></tr><tr><td style="text-align: left;"><code>pastemask top</code></td><td style="text-align: center;">-</td><td style="text-align: center;">✔</td><td style="text-align: center;">-</td><td style="text-align: left;">顶层助焊（钢网）层</td></tr><tr><td style="text-align: left;"><code>pastemask_bottom</code></td><td style="text-align: center;">-</td><td style="text-align: center;">✔</td><td style="text-align: center;">-</td><td style="text-align: left;">底层助焊（钢网）层</td></tr><tr><td style="text-align: left;"><code>place_bound_top</code></td><td style="text-align: center;">-</td><td style="text-align: center;">✔</td><td style="text-align: center;">-</td><td style="text-align: left;">顶层元件封装边界</td></tr><tr><td style="text-align: left;"><code>place_bound_bottom</code></td><td style="text-align: center;">-</td><td style="text-align: center;">✔</td><td style="text-align: center;">-</td><td style="text-align: left;">底层元件封装边界</td></tr><tr><td style="text-align: left;"><code>outline</code></td><td style="text-align: center;">✔</td><td style="text-align: center;">-</td><td style="text-align: center;">-</td><td style="text-align: left;">PCB 板框</td></tr><tr><td style="text-align: left;"><code>assembly_top</code></td><td style="text-align: center;">-</td><td style="text-align: center;">✔</td><td style="text-align: center;">✔</td><td style="text-align: left;">顶层装配层</td></tr><tr><td style="text-align: left;"><code>assembly_bottom</code></td><td style="text-align: center;">-</td><td style="text-align: center;">✔</td><td style="text-align: center;">✔</td><td style="text-align: left;">底层装配层</td></tr></tbody></table><blockquote><p><strong>注意</strong>：<code>board geometry</code> 是指 PCB<strong>板级</strong>的几何形状，<code>package geometry</code> 是指 PCB<strong>封装级</strong>的几何形状。</p></blockquote><h2 id="allegro-颜色编辑器">Allegro 颜色编辑器</h2><p>鼠标点击 <strong>Allegro</strong> 菜单栏上的<code>Display -&gt; Color/Visbility...</code>或者直接按下<strong>快捷键</strong>【Ctrl + F5】，就可以打开【ColorDialog】对话框，使用 Allegro 进行 PCB版图布局布线的时候，只需要开启如下的 <strong>Class</strong> 与<strong>Subclass</strong> 的显示即可：</p><ul><li><strong>元件封装丝印</strong>：将<code>Geometry -&gt; Package Geometry -&gt; Silkscreen_Top/Silkscreen_Bottom</code>显示为白色；</li><li><strong>元件封装位号</strong>：将<strong>丝印层</strong><code>Component -&gt; Ref des -&gt; Silkscreen_Top/Silkscreen_Bottom</code>显示为白色，将<strong>装配层</strong><code>Component -&gt; Ref des -&gt; Assembly_Top/Assembly_Bottom</code>显示为蓝色；</li><li><strong>元件焊盘阻焊</strong>：将<code>Stack-Up -&gt; Pin -&gt; Soldermask_Top/Soldermask_Bottom</code>显示为紫色；</li><li><strong>PCB 板框</strong>：将<code>Geometry -&gt; Border Geometry -&gt; Outline/Design_Outline</code>显示为亮黄色；</li><li><strong>PCB 板级丝印</strong>：打开<code>Geometry -&gt; Board Geometry</code> 下的<strong>丝印层</strong><code>Silkscreen_Top/Silkscreen_Bottom</code>以及<strong>阻焊层</strong><code>Soldermask_Top/Soldermask_Bottom</code> 的显示；</li></ul><p><img src="/Electronics/Cadence-Skill/Color.png"></p><h2 id="导入-pcb-板框-允许布线区域">导入 PCB 板框 &amp;允许布线区域</h2><p>导入的板框放置在 <code>Board geometry</code> 这个<strong>Class</strong> 的 <code>Design Outline</code>（兼容 17.x之后的版本）和 <code>Outline</code>（虽然兼容 16.x之前的版本，但是会导致 <code>17.4</code> 无法正常渲染 3D 模型）两个<strong>SubClass</strong> 下面。放置板框的时候，在<strong>Allegro</strong> 底部的【Command】输入框里键入<code>x 0 0</code>，就可以让板框的左上角位置成为<strong>坐标原点</strong>。</p><ol type="1"><li>PCB 镂空区域：将需要板框图层 <strong>Z-Copy</strong> 到<code>Board geometry -&gt; Design Outline</code>（生成 3D预览可见的板框）；</li><li>PCB 镂空区域：将需要挖空处理的图层 <strong>Z-Copy</strong> 到<code>Board geometry -&gt; Cutout</code>（镂空板框当中的开孔区域）；</li><li>PCB 允许布线区域：将允许布线的图层 <strong>Z-Copy</strong> 到<code>Route Keepin -&gt; All</code>（防止布线到板框区域之外），再鼠标点击右侧【Option】选项卡下的<code>Contract</code>，然后将图层的<strong>缩进</strong><code>Offset</code> 设置为<code>10mil/0.254mm</code>（防止铺铜之后，板框边沿的铜层割手）；</li><li>PCB 禁止布线区域：将需要镂空的图层 <strong>Z-Copy</strong> 到<code>Route Keepout -&gt; All</code>（防止铺铜之后，铜层覆盖镂空区域），再鼠标点击右侧【Option】选项卡下的<code>Expand</code>，然后将图层的<strong>外扩</strong><code>Offset</code> 设置为<code>10mil/0.254mm</code>（防止铺铜之后，镂空的边沿即是板框边沿）；</li></ol><blockquote><p><strong>注意</strong>：如果系统提示板框超出绘制区域<code>SPMHA2-54: Cannot place outside of the drawing extends</code>，则需要进入下面介绍的<strong>设计参数编辑器</strong>【DesignParametersEditor】，通过修改【Extends】选项卡下的相关参数，来调整绘制区域的大小。</p></blockquote><h2 id="修改-allegro-绘制区域尺寸">修改 Allegro 绘制区域尺寸</h2><p>鼠标点击 <strong>Allegro</strong> 顶部菜单栏上的<code>Setup -&gt; Design Parameters...</code>，切换到【Design ParametersEditor】对话框下的【Design】选项卡，通过调整 <code>Extends</code>下的各项参数，就可以修改<strong>绘制区域</strong>的大小尺寸：调整绘制区域的尺寸。</p><p><img src="/Electronics/Cadence-Skill/Drawing-Area-Size.png"></p><ul><li><code>LeftX</code> 和<code>LeftY</code>：表示<strong>绘制区域</strong>左下角起始的<code>横坐标</code> 与 <code>纵坐标</code> 的值；</li><li><code>Width</code> 和<code>Heigth</code>：表示<strong>绘制区域</strong>的 <code>宽度</code>与 <code>高度</code>；</li><li><code>Move orign</code>: 通过修改其 <code>X</code> 和 <code>Y</code>取值，就可以调整当前<strong>绘制区域</strong>中<strong>原点</strong>的位置；</li></ul><h2 id="进行-3d-canvas-预览时的操作">进行 3D Canvas 预览时的操作</h2><p>按下 <strong>鼠标中键</strong> 并且拖动，就可以移动预览 PCB，按下<strong>Shirt + 鼠标中键</strong> 则可以用于旋转 PCB 版图的 3D预览效果。</p><blockquote><p><strong>注意</strong>：3D预览当中的丝印颜色显示，需要在<strong>颜色管理器</strong>指定<code>Board Geometry/Silkscreen_Top</code> 和<code>Board Geometry/Silkscreen_Bottom</code> 的颜色与可见性。</p></blockquote><h2 id="焊盘进入约束-enhanced-padentry">焊盘进入约束 EnhancedPadEntry</h2><p><strong>Allegro</strong> 走线的时候，展开鼠标右键菜单取消【EnhancedPadEntry】项的选择，可以避免走线必须从<strong>焊盘居中</strong>的位置进入<strong>焊盘中心</strong>。</p><h2 id="元素按坐标精确移动">元素按坐标精确移动</h2><p>首先，在 <strong>Allegro</strong> 当中执行 <code>move</code>命令，在右侧的【options】选项卡当中选择 <code>User Pick</code>：</p><p><img src="/Electronics/Cadence-Skill/User%20Pick.png"></p><ol type="1"><li><code>Sym Origin</code>：封装原点作为基准点（默认项）;</li><li><code>Body Center</code>：以封装的 <code>Place Bound</code>几何中心作为基准，通常用于<strong>单个元件</strong>的原地旋转；</li><li><code>User Pick</code>：以用户鼠标单击的点作为基准，通常用于<strong>多个元件</strong>的整体旋转；</li><li><code>Sym Pin</code>：以元件的<strong>引脚编号</strong>作为基准，通常用于<strong>元件结构</strong>定位；</li></ol><p>然后，在 <strong>Allegro</strong>底部的【Command】窗口输入执行下面的命令，就可以让指定的元素按照坐标进行移动：</p><ul><li><strong>绝对定位</strong><code>x a b</code>：基于右侧【0ption】选项卡当中选择的参考点，将元素移动到坐标<code>a</code> 和 <code>b</code>；</li><li><strong>相对定位</strong> <code>ix a</code>：将元素沿着<code>x</code> 轴的方向移动 <code>a</code>个单位，相对移动命令不需要在【Option】选择参考点；</li><li><strong>相对定位</strong> <code>iy a</code>：将元素沿着<code>y</code> 轴的方向移动 <code>a</code> 个单位，如果当前单位为<code>mm</code>，那么输入 <code>iy -2</code> 就可以将元素向下移动<code>2mm</code>；</li><li><strong>相对定位</strong> <code>ix a iy b</code> ：将元素沿着<code>x</code> 轴的方向移动 <code>a</code> 个单位，沿着 <code>y</code>轴的方向移动 <code>b</code> 个单位；</li></ul><h2 id="设置-pcb-版图原点的可见性和颜色">设置 PCB版图原点的可见性和颜色</h2><p><img src="/Electronics/Cadence-Skill/Origin/1.png"></p><p><img src="/Electronics/Cadence-Skill/Origin/2.png"></p><h2 id="倒圆角与斜角">倒圆角与斜角</h2><ol type="1"><li>首先，需要将 <code>Shape</code> 转换为 <code>Line</code>，鼠标点击<strong>Allegro</strong> 顶部菜单栏上的<code>Shape -&gt; Decompose Shape</code>，然后框选目标元素执行操作；</li><li>然后，再选择 <strong>Allegro</strong>菜单栏上的<code>Manufacture -&gt; Drafting</code>，进行<code>Fillet</code>（倒圆角）或者<code>Chamfer</code>（倒斜角），此时可以在右侧【Options】窗口填写倒角的<strong>半径</strong>、<strong>长度</strong>以及<strong>角度</strong>；</li><li>最后，选择相邻的两条 <code>Line</code>，即可执行倒角操作；</li></ol><h2 id="解决嘉立创板框外形层缺失问题">解决嘉立创板框/外形层缺失问题</h2><p>导出 <strong>Gerber</strong> 光绘文件给<strong>嘉立创</strong>进行PCB 打样的时候，为了避免出现 <code>板框/外形层</code>缺失的问题，需要鼠标点击 <strong>Allegro</strong> 顶部菜单栏上的<code>Manufacture -&gt; Artwork</code>，将弹出窗口中的<code>Undefined Line Width</code> 项修改为 <code>0.2</code>：</p><p><img src="/Electronics/Cadence-Skill/Undefined-Line-Width.png"></p><h2 id="在-allegro-当中显示过孔形状">在 Allegro 当中显示过孔形状</h2><p>鼠标点击 <strong>Allegro</strong> 菜单栏上的<code>Setup -&gt; Design Parameter Editor</code>，勾选【Display】选项卡下的<code>Plated holes</code> 复选框（同时会自动勾选<code>Padless holes</code>）：</p><p><img src="/Electronics/Cadence-Skill/Via-Display.png"></p><h2 id="使用-advanced-mirror-高级镜像">使用 Advanced Mirror高级镜像</h2><p>首先，鼠标点击 <strong>Allegro</strong> 顶部菜单栏上的<code>File -&gt; Change Editor...</code>，勾选<code>Allegro Productivity Toolbox</code> 项：</p><p><img src="/Electronics/Cadence-Skill/Allegro-Productivity-Toolbox/1.png"></p><p>然后，重新启动 <strong>Allegro</strong> 之后，再点击顶部菜单栏上的<code>Edit -&gt; Advanced Mirror...</code>，此时可以在右侧的【Option】窗口看到相关的设置项：</p><p><img src="/Electronics/Cadence-Skill/Allegro-Productivity-Toolbox/2.png"></p><p>最后，鼠标框选当前工作区需要进行高级镜像处理的元素，并移动到空白处单击鼠标，即可执行相应的镜像操作。</p><h2 id="镜像已经添加了的丝印文字">镜像已经添加了的丝印文字</h2><p>如果丝印文字在 PCB顶层或者底层的显示出现<strong>镜像</strong>，那么可以通过如下所述的方式进行调整：</p><ol type="1"><li>首先，勾选【Allegro PCB Designer Product Choices】当中的<strong>Allegro Productivity Toolbox</strong> 选项，并且重新启动<strong>Allegro</strong>；</li><li>然后，鼠标选择 <strong>Allegro</strong> 菜单上的<code>Edit -&gt; Advanced Mirror...</code>；</li><li>接着，勾选 <strong>Find</strong> 窗口当中的 <code>Text</code>选项；</li><li>接下来，勾选 <strong>Options</strong> 窗口当中的<code>Mirror type -&gt; Geometry only -&gt; Mirror text</code>选项；</li><li>最后，鼠标选择需要镜像的丝印文字即可；</li></ol><h2 id="丝印字符推荐参数">丝印字符推荐参数</h2><p><strong>Allegro</strong> 丝印字符的<code>Width</code>、<code>Height</code>、<code>Line Space</code>三个参数，推荐采用下面的 <strong>换算公式</strong> 进行计算：</p><p><span class="math display">\[\begin{cases}Width \\Height = Width + 5/10 \\LineSpace = Height + 10\end{cases}\]</span></p><p><code>Photo Width</code> 和 <code>Char Space</code> 按照如下<strong>表格</strong> 的顺序加 <code>1</code> 递增即可：</p><table><colgroup><col style="width: 15%"><col style="width: 11%"><col style="width: 13%"><col style="width: 20%"><col style="width: 19%"><col style="width: 20%"></colgroup><thead><tr><th style="text-align: center;">编号 Text Blk</th><th style="text-align: left;">宽度 Width</th><th style="text-align: left;">高度 Height</th><th style="text-align: left;">行间距 Line Space</th><th style="text-align: left;">线宽 Photo Width</th><th style="text-align: left;">字间距 Char Space</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>1</strong></td><td style="text-align: left;"><code>20 mil</code></td><td style="text-align: left;"><code>25 mil</code></td><td style="text-align: left;"><code>35 mil</code></td><td style="text-align: left;"><code>4 mil</code></td><td style="text-align: left;"><code>4 mil</code></td></tr><tr><td style="text-align: center;"><strong>2</strong></td><td style="text-align: left;"><code>30 mil</code></td><td style="text-align: left;"><code>35 mil</code></td><td style="text-align: left;"><code>45 mil</code></td><td style="text-align: left;"><code>5 mil</code></td><td style="text-align: left;"><code>5 mil</code></td></tr><tr><td style="text-align: center;"><strong>3</strong></td><td style="text-align: left;"><code>35 mil</code></td><td style="text-align: left;"><code>45 mil</code></td><td style="text-align: left;"><code>55 mil</code></td><td style="text-align: left;"><code>6 mil</code></td><td style="text-align: left;"><code>6 mil</code></td></tr><tr><td style="text-align: center;"><strong>4</strong></td><td style="text-align: left;"><code>45 mil</code></td><td style="text-align: left;"><code>50 mil</code></td><td style="text-align: left;"><code>60 mil</code></td><td style="text-align: left;"><code>7 mil</code></td><td style="text-align: left;"><code>7 mil</code></td></tr><tr><td style="text-align: center;"><strong>5</strong></td><td style="text-align: left;"><code>50 mil</code></td><td style="text-align: left;"><code>55 mil</code></td><td style="text-align: left;"><code>65 mil</code></td><td style="text-align: left;"><code>8 mil</code></td><td style="text-align: left;"><code>8 mil</code></td></tr></tbody></table><h2 id="切换单位动态铺铜无法自动避让">切换单位动态铺铜无法自动避让</h2><p>当 <strong>Allegro</strong> 切换设计单位（<code>Mils</code> 或<code>Millimeter</code>）之后，就会出现<strong>动态铺铜</strong>无法自动避让的问题。这是由于<strong>Allegro</strong> 切换单位之后，动态铺铜变为<code>disabled</code> 模式，此时需要鼠标点击 <strong>Allegro</strong>顶部菜单栏上的<code>Shape -&gt; Global Dynamic Params...</code>，在打开的【<strong>GlobalDynamic Shape Parameters</strong>】话框当中，重新勾选具有自动避让功能的<code>smooth</code> 模式：</p><p><img src="/Electronics/Cadence-Skill/Smooth.png"></p><h2 id="解除原理图与-pcb-的交互式布局">解除原理图与 PCB的交互式布局</h2><p>为了解决 <strong>Allegro</strong> 与 <strong>OrCAD</strong>交互式布局时引发的运行缓慢问题，可以鼠标点击 <strong>Allegro</strong>顶部菜单栏上的 <code>Setup</code>，取消 <code>Enable Crossprobing</code>菜单项的勾选，从而<strong>临时</strong>解除原理图与 PCB的交互式布局关系：</p><p><img src="/Electronics/Cadence-Skill/Enable-Crossprobing.png"></p><h2 id="负片层的切割与网络指定">负片层的切割与网络指定</h2><ol type="1"><li>确认 PCB 板框的 <code>Design Outline</code> 和<code>Route Keepin</code> 区域是否绘制正确（两者相距至少<code>0.5mm/20mil</code>）</li><li>在 <strong>Allegro</strong> 叠层管理器中设置好负片层；</li><li>执行 <strong>Allegro</strong> 菜单栏上的 <code>Add -&gt; Line</code>命令，并且选择【Options】面板中的 <code>Class</code> 和<code>Subclass</code> 分别为 <code>Anti Etch</code>和相应的负片层；</li><li>接下来在【Options】面板里的 <code>Line width</code>参数项当中，设置平面切割的宽度（即<strong>铺铜间距</strong>，通常设置为<code>0.5mm/20mil</code> 或者 <code>1mm/40mil</code>）；</li><li>根据负片层功能区域划分绘制好<strong>分隔线</strong>之后，点击<strong>Allegro</strong> 菜单栏上的<code>Edit -&gt; Split Plane -&gt; Parameters…</code>，勾选填充风格为<code>Solid</code> <strong>实心填充</strong>；</li><li>接着鼠标选择 <strong>Allegro</strong> 菜单栏上的<code>Edit -&gt; Split Plane -&gt; Create</code>，选择需要进行切割处理的负片层，并且指定其属于<strong>动态</strong><code>Dynamic</code> 还是<strong>静态</strong> <code>Static</code>类型的铺铜；</li><li>按下【Create】按钮之后，窗口会自动聚焦到当前需要铺铜填充的区域，同时弹出【Selectanet】对话框要求选择该区域所属的网络，选择并且确定之后，又会自动聚焦到下一个需要填充的区域；</li></ol><h2 id="过孔焊盘的创建步骤">过孔焊盘的创建步骤</h2><ol type="1"><li>【Drill】：钻孔参数设置（<strong>Finished diameter</strong>表示钻孔直径）</li><li>【Drill Symbol】选项卡：设置显示在 Allegro 的 PCB版图中的钻孔符号（即 <code>Characters</code> 项设置的 3个字母参数）。</li><li>【Design Layer】：<strong>规则焊盘</strong> <code>Regular Pad</code>用于正片层、<strong>恒温焊盘</strong> <code>Thermal Relief</code>用于正片和负片层、<strong>负焊盘</strong> <code>Anti Pad</code>用于负片层（其中的 <code>Diameter</code> 参数表示的是过孔直径）；</li><li>【Mask Layer】：主要设置 <strong>阻焊层</strong><code>SOLDERMASK_TOP/BOTTOM</code>，从而达到<strong>过孔盖油</strong>的目的；</li></ol><h2 id="批量修改过孔类型">批量修改过孔类型</h2><ol type="1"><li>在 <strong>Allegro</strong> 绘制区展开鼠标右键菜单，切换<code>Application Mode -&gt; General Edit</code>；</li><li><strong>Allegro</strong> 侧边栏的【Find】工作区里只勾选<code>Vias</code> 选项，然后选中需要执行修改的目标过孔；</li><li>在 <strong>Allegro</strong> 绘制区展开鼠标右键菜单，选择<code>Replace padstack</code> 下的选项即可完成相应功能（其中<code>Filter Instances</code> 可以用于指替换过孔）；</li></ol><h2 id="加载外部-skill-脚本">加载外部 Skill 脚本</h2><p>把需要加载的 Skill 脚本放置在任意目录下面，然后在下面的路径列表里找到<code>allegro.ilinit</code> 文件，在其中加入<code>load("Skill文件名称")</code> 代码即可：</p><ol type="1"><li><code>C:\Cadence\Spb_data\pcbenv\allegro.ilinit</code></li><li><code>C:\Cadence\SPB_17.4\share\pcb\etc\allegro.ilinit</code></li></ol><h2 id="点对点相对等长布线">点对点相对等长布线</h2><ol type="1"><li>打开 <strong>Allegro</strong> 约束管理器当中的【Electrical -&gt; Net-&gt; Relative Propagation Delay】界面。</li><li>对需要进行等长布线的网络，在约束管理器当中建立<code>Net Group...</code> 或者 <code>Class...</code>；</li><li>鼠标依次选择约束管理器顶部菜单栏上的【Analyze -&gt; AnalysisMode】或者直接按下快捷键【Ctrl + F9】;</li><li>分别勾选弹出对话框当中的 <code>Relative propagation delay</code>为【On】选项，以及界面底部的【Pin Delay】选项；</li><li>分别设置该等长组的 <code>Delta/Tolerance</code> 为<code>0mil/5mil</code> 或者其它值，并且指定 <code>Target</code>网络；</li></ol><p><img src="/Electronics/Cadence-Skill/Analysis-Modes.png"></p><blockquote><p><strong>注意</strong>：<code>Delta</code> ：表示相对于<code>Target</code>长度的固定延迟。<code>Tolerance</code>：表示走线长度所允许的正负公差值。</p></blockquote><h2 id="pin-pair-引脚对等长">Pin Pair 引脚对等长</h2><ol type="1"><li>打开 <strong>Allegro</strong> 约束管理器的【Electrical -&gt; Net-&gt; Relative PropagationDelay】界面，将需要进行等长处理的网络，添加到相同的<strong>Class</strong> 或者 <strong>Net Group</strong>；</li><li>鼠标右键该 Class 或者 Net Group 下的每一个网络，然后依次点击<code>Create -&gt; Pin Pair...</code> 创建 Pin Pair 的网络起始引脚<code>First Pins</code> 和终点引脚 <code>Second Pins</code>；</li><li>然后鼠标全选上述步骤创建的所有 Pin Pair，然后右键依次点击<code>Create -&gt; Match Group...</code> 创建等长组；</li><li>分别设置该等长组的 <code>Delta/Tolerance</code> 并且指定<code>Target</code> 网络；</li></ol><h2 id="差分信号的对内相位等长">差分信号的对内相位等长</h2><ol type="1"><li><strong>静态相位控制</strong>（StaticPhase）：用于控制差分对线之间的总长度偏差，但是在布线过程当中进行检查。</li><li><strong>动态相位控制</strong>（DynamicPhase）：由于静态相位控制只能确定两条差分对线之间的总相位差，无法在布线过程中实时展示偏差情况，此时就需要使用到动态相位控制（也就是所谓的<strong>实时等长</strong>）。</li></ol><p>通常情况下，差分信号对内等长需要小于或者等于<code>5mil</code>，因而需要进行静态相位控制：</p><p><img src="/Electronics/Cadence-Skill/Phase-Tune/Static.png"></p><ol type="1"><li>进入 <strong>Allegro</strong> 约束管理器的<code>Electrical -&gt; Net -&gt; Routing -&gt; Differential Pair</code>界面；</li><li>设置表格当中的 <code>Static Phase -&gt; Tolerance</code>列参数；</li><li>返回 <strong>Allegro</strong> 的 PCB绘制界面，并在【Find】面板上勾选<code>Nets</code>，然后鼠标选择需要进行静态相位控制的差分网络，展开右键菜单勾选<code>Single Trace Mode</code>；</li><li>最后依次勾选 <strong>Allegro</strong> 顶部菜单栏上的<code>Route -&gt; Phase Tune</code>，拖动目标差分线即可；</li></ol><p>对于 <code>5Gbit/s</code>以上速率的高速差分串行总线，需要考虑进行实时等长控制，即当走线偏差大于<code>25mil</code> 时，必须在 <code>600mil</code>的总布线长度之内进行补偿（使用反向拐角或者基于 3W规则进行小波浪绕线来补偿）：</p><ol type="1"><li>进入 <strong>Allegro</strong> 约束管理器的<code>Electrical -&gt; Net -&gt; Routing -&gt; Differential Pair</code>界面；</li><li>设置表格当中的 <code>Dynamic Phase -&gt; Tolerance</code>列参数；</li></ol><p><img src="/Electronics/Cadence-Skill/Phase-Tune/Dynamic.png"></p><h2 id="基于-ghostscript-导出-pdf">基于 Ghostscript 导出 PDF</h2><p>基于 <code>File -&gt; Print...</code> 方式导出的 PDF原理图，存在无法对带有下划线的关键字进行搜索的问题，这里介绍一种使用开源PDF 处理工具 <strong>Ghostscript</strong> 进行导出的办法：</p><p><img src="/Electronics/Cadence-Skill/PDF.png"></p><ol type="1"><li>前往 <a href="https://www.ghostscript.com/releases/gsdnld.html">Ghostscript</a>官网下载<code>Ghostscript 10.06.0 for Windows (64 bit)</code>，并双击安装其到指定目录；</li><li>OrCAD 里选择当前需要导出的 <code>.dsn</code>原理图工程，然后鼠标依次点击<code>File -&gt; Export -&gt; PDF</code>；</li><li>在弹出的【PDF Export】窗口，<strong>Postscript Driver</strong>项填写为 <code>Microsoft Print to PDF</code>；</li><li>除此之外，还需要分别设置 <code>Converter</code> 项为<code>Ghostscript 64 bit / equivalent</code>，同时将<code>Converter Path</code> 项指定为 <strong>Ghostscript</strong>安装目录下的 <code>gswin64.exe</code> 文件；</li><li>最后按下【OK】即可开始转换过程，稍等片刻即可在桌面或者指定路径获取到<code>.pdf</code> 格式的原理图文件；</li></ol>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;a href=&quot;https://www.cadence.com/zh_CN/home/company.html&quot;&gt;&lt;strong&gt;楷登电子&lt;/strong&gt;&lt;/a&gt;
推出的 &lt;strong&gt;Cadence SPB&lt;/strong&gt;（&lt;strong&gt;SPB&lt;/strong&gt; 是
&lt;code&gt;Silicon&lt;/code&gt;、&lt;code&gt;Package&lt;/code&gt;、&lt;code&gt;Board&lt;/code&gt;
三个英文字母的缩写）整合了原理图绘制工具 &lt;strong&gt;OrCAD&lt;/strong&gt; 和 PCB
版图设计工具 &lt;strong&gt;Allegro&lt;/strong&gt; 以及电路仿真工具
&lt;strong&gt;PSpice&lt;/strong&gt;，已经成为了业界领先的&lt;strong&gt;电子设计自动化&lt;/strong&gt;（EDA，Electronic
Design
Automation）工具链。伴随电子系统复杂度的日益提升，如何运用工具当中提供的各种功能来应对设计挑战，业已成为了广大电子硬件工程师们亟需掌握的技能。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/Electronics/Cadence-Skill/logo.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;关于 &lt;strong&gt;OrCAD&lt;/strong&gt; 和 &lt;strong&gt;Allegro&lt;/strong&gt;
的基础操作，已经在五年之前所撰写的《&lt;a href=&quot;http://uinio.com/Electronics/Cadence/&quot;&gt;&lt;strong&gt;写给有经验 PCB
工程师的 Cadence SPB 17.4
极速上手指南&lt;/strong&gt;&lt;/a&gt;》这篇文章当中进行过图文并茂的阐述，而本文则主要聚焦于实际应用中的&lt;strong&gt;高频痛点&lt;/strong&gt;，提炼出经过验证的
&lt;code&gt;操作技巧&lt;/code&gt; 和
&lt;code&gt;配置方法&lt;/code&gt;。希冀能够帮助广大的电子硬件工程师，更加合理与熟练的使用
&lt;strong&gt;Cadence SPB&lt;/strong&gt; 工具套件进行原理图和 PCB
版图的绘制，从而有效的提高研发工作效率，进而得心应手的面对各类纷繁复杂的设计挑战。&lt;/p&gt;</summary>
    
    
    
    <category term="硬件电子技术" scheme="http://www.uinio.com/categories/%E7%A1%AC%E4%BB%B6%E7%94%B5%E5%AD%90%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="EDA" scheme="http://www.uinio.com/tags/EDA/"/>
    
  </entry>
  
  <entry>
    <title>内置集成电路总线协议 I²C 简明指南</title>
    <link href="http://www.uinio.com/Electronics/I2C/"/>
    <id>http://www.uinio.com/Electronics/I2C/</id>
    <published>2025-09-05T16:00:00.000Z</published>
    <updated>2025-09-28T16:16:30.234Z</updated>
    
    <content type="html"><![CDATA[<p><strong>内置集成电路总线</strong>（Inter-IntegratedCircuit）是一种串行通信协议，其英文缩写为<strong>I²C</strong>，因为中间存在 2 个英文字母<code>I</code>，所以被读作 <code>I Square C</code>，中文读作<code>I 平方 C</code> 或者 <code>I 方 C</code>总线。本文后续内容为了书写方便，会将 <strong>I²C</strong> 简写为<strong>I2C</strong>。该总线协议需要<strong>串行数据线</strong>（SDA，SerialData）和<strong>串行时钟线</strong>（SCL，SerialClock）两条信号线，接线方式较为简单，通常用于连接微控制器、存储器、传感器等低速元器件。</p><p><img src="/Electronics/I2C/logo.png"></p><p>在 <strong>I²C</strong>总线通信协议当中，规定总线上可以存在一个<strong>主设备</strong>以及多个<strong>从设备</strong>。<strong>主设备</strong>掌控着整个通信过程，负责发起、控制、停止通信。而<strong>从设备</strong>则需要等待主设备请求、接收、发送数据。主设备与从设备之间的数据交换采用特定的<strong>数据帧</strong>格式，每个数据帧包含有<code>地址</code>、<code>数据</code>、<code>控制</code>信息。<strong>主设备</strong>会根据<strong>从设备</strong>的 I2C地址来选择总线上需要进行通信的外设，从设备则根据控制信息返回相应的响应。</p><span id="more"></span><h2 id="演进历程">演进历程</h2><p><strong>1982</strong>年<strong>荷兰飞利浦</strong>（Philips）公司为自家的芯片产品制订了 I²C总线技术规范，原始规范只能提供 <code>100kHz</code> 的通信速率，以及 7位的地址空间（由于存在有保留地址，总线上设备数量被限制为 112个）。后续在 <strong>1992</strong> 年发布了第一个公共规范，增加了<code>400kHz</code> 快速模式，以及扩展的 10位地址空间。经过多年的发展，目前 I2C协议规范已经能够提供下面表格当中的五种工作速率模式：</p><table><thead><tr><th>I2C 总线模式</th><th>英文名称</th><th>典型传输速率</th></tr></thead><tbody><tr><td><strong>标准模式</strong></td><td>Standard Mode</td><td><code>100 KHz</code></td></tr><tr><td><strong>快速模式</strong></td><td>Fast Mode</td><td><code>400 KHz</code></td></tr><tr><td><strong>增强快速模式</strong></td><td>Fast Mode Plus</td><td><code>1 MHz</code></td></tr><tr><td><strong>高速模式</strong></td><td>High-Speed Mode</td><td><code>3.4 MHz</code></td></tr><tr><td><strong>极速模式</strong></td><td>Ultra-Fast Mode</td><td><code>5 MHz</code></td></tr></tbody></table><blockquote><p><strong>注意</strong>：<strong>英特尔</strong>（Intel）公司于 1995年推出的<strong>系统管理总线</strong>（<strong>SMBus</strong>，SystemManagement Bus）是一种基于 I2C总线演变而来的变体，其提供了更加严格的控制模式，传输速率被限制在<code>10kHz ~ 100kHz</code>范围之间，并且支持时钟超时、固定逻辑电平（I2C的逻辑电平由总线上拉电阻连接的 <code>VCC</code> 决定）等特性。</p></blockquote><h2 id="漏极开路设计">漏极开路设计</h2><p>芯片内置的 I2C总线驱动器，通常采用<strong>漏极开路</strong>设计（不同于 UART 和 SPI总线），这意味着其可以将总线信号线拉低，但不能将总线信号驱动为高电平。从而在一个设备试图将I2C总线驱动为高电平，而另外一个设备又试图将总线电平拉低的时候，不会出现争抢总线资源的情况，从而避免损坏芯片内部的I2C 总线驱动器，以及随之带来的功耗过大问题。正是因为如此，I2C总线的信号线上都会存在一个上拉电阻 ，用于协助总线恢复到高电平状态。</p><p><img src="/Electronics/I2C/Open-Drain.png"></p><blockquote><p><strong>注意</strong>：I2C上拉电阻的选型需要根据总线上的主从设备进行选型（后续的内容会给出理论指导），但一个好的经验法则是从<code>4.7kΩ</code> 电阻开始，然后逐步向下进行调整。</p></blockquote><h2 id="探究上拉电阻的取值">探究上拉电阻的取值</h2><h3 id="上拉电阻的推导">上拉电阻的推导</h3><p><strong>I2C</strong>总线是一种采用了<strong>漏极开路</strong>（Open-Drain）或者<strong>集电极开路</strong>（Open-Collector）的通信标准，因而可以支持具有不同工作电压的芯片和传感器相互通信。如下图所示，当总线没有被芯片引脚内部的漏极开路下拉为低电平时，I2C总线的上拉电阻就会将总线电平进行拉高：</p><p><img src="/Electronics/I2C/Resistor-1.png"></p><p>芯片 I2C引脚内部的输入缓冲器，所能够读取的<strong>最小有效低电平</strong> <span class="math inline">\(V_{OL}\)</span>决定了<strong>上拉电阻最小值</strong> <span class="math inline">\(R_{P_{min}}\)</span>：</p><p><span class="math display">\[R_{P_{min}}  = \frac{V_{CC} - V_{OL_{max}}}{I_{OL}}\]</span></p><p><strong>上拉电阻最大值</strong> $R_{P_{min}} $ 受限于 I2C总线的<strong>等效电容</strong> <span class="math inline">\(C_B\)</span>，I2C总线规范当中定义了信号的<strong>上升时间</strong>（RiseTime），如果上拉电阻的取值过大，可能会导致 I2C总线在被下拉之前，没有足够的时间上升到有效的<strong>逻辑高电平</strong>。从时间<span class="math inline">\(t=0\)</span> 开始，RC 电路对振幅为 VCC的电压阶跃响应，可以使用 <strong>RC 时间常数</strong>进行表示，因此 I2C总线上的电压波形可以表达为下面的方程：</p><p><span class="math display">\[V(t) = V_{CC} \times \bigg( 1 - e^{\frac{-t}{R_P \times C_B}} \bigg)\]</span></p><blockquote><p><strong>注意</strong>：<strong>RC 时间常数</strong> <span class="math inline">\(\tau\)</span> 是指电阻值 <span class="math inline">\(R\)</span> 与电容值 <span class="math inline">\(C\)</span>的乘积，其单位为<strong>秒</strong>，表达的是电容器通过电阻器进行<strong>充电</strong>与<strong>放电</strong>的时间特性。</p></blockquote><p>通常情况下，I2C 总线上的<strong>输入高电平电压</strong>（Input HighVoltage）<span class="math inline">\(V_{IH}\)</span>、<strong>输入低电平电压</strong>（InputLow Voltage）<span class="math inline">\(V_{IL}\)</span>与<strong>上拉参考电压</strong> <span class="math inline">\(V_{CC}\)</span>之间的关系可以表达为如下的方程组：</p><p><span class="math display">\[\begin{cases}V_{IH} = 0.7 \times V_{CC} = V_{CC} \times \big(1 - e^{\frac{-t_1}{R_P\times C_B}} \big) \\V_{IL} = 0.3 \times V_{CC} = V_{CC} \times \big(1 - e^{\frac{-t_2}{R_P\times C_B}} \big)\end{cases}\]</span></p><p>基于上述方程组，可以将 I2C 总线信号的<strong>上升时间</strong> <span class="math inline">\(t_R\)</span> 描述为下面的公式：</p><p><span class="math display">\[t_R = t_2 - t_1 = 0.8473 \times R_P \times C_B\]</span></p><p>由此，就可以推导出<strong>上拉电阻最大值</strong> <span class="math inline">\(R_{P_{max}}\)</span> 与<strong>上升时间</strong><span class="math inline">\(t_R\)</span> 之间的函数关系：</p><p><span class="math display">\[R_{P_{max}} = \frac{t_R}{0.8473 \times C_B}\]</span></p><p>推导出上拉电阻的最小值 <span class="math inline">\(R_{P_{min}}\)</span> 与最大值 <span class="math inline">\(R_{P_{max}}\)</span>之后，就可以根据预定的传输速率和功率进行恰当的取值，较小的阻值可以带来更快的响应速度，较大的阻值则会带来更少的功率耗散。</p><h3 id="i2c-总线规范参数">I2C 总线规范参数</h3><p>I2C 总线协议规范当中，对于前面内容提到的 <span class="math inline">\(t_R\)</span>、<span class="math inline">\(C_B\)</span>、<span class="math inline">\(V_{OL}\)</span> 参数作出了如下定义：</p><table><colgroup><col style="width: 7%"><col style="width: 44%"><col style="width: 12%"><col style="width: 17%"><col style="width: 17%"></colgroup><thead><tr><th style="text-align: center;">参数名称</th><th>描述</th><th>标准模式(最大)</th><th>快速模式(最大)</th><th>增强快速模式(最大)</th></tr></thead><tbody><tr><td style="text-align: center;"><span class="math inline">\(t_R\)</span></td><td>SDA 和 SCL 信号的上升时间</td><td><code>1000 ns</code></td><td><code>300 ns</code></td><td><code>120 ns</code></td></tr><tr><td style="text-align: center;"><span class="math inline">\(C_B\)</span></td><td>I2C 传输线等效电容</td><td><code>400 pF</code></td><td><code>400 pF</code></td><td><code>550 pF</code></td></tr><tr><td style="text-align: center;"><span class="math inline">\(V_{OL}\)</span></td><td>低电平输出电压（<code>3mA</code> 电流源，<span class="math inline">\(V_{CC} &gt; 2V\)</span>）</td><td><code>0.4 V</code></td><td><code>0.4 V</code></td><td><code>0.4 V</code></td></tr><tr><td style="text-align: center;"> </td><td>低电平输出电压（<code>2mA</code> 电流源，<span class="math inline">\(V_{CC} \leq 2V\)</span>）</td><td>-</td><td><span class="math inline">\(0.2 \times V_{CC}\)</span></td><td><span class="math inline">\(0.2 \times V_{CC}\)</span></td></tr></tbody></table><p>下面图像表达了 I2C总线在标准模式和快速模式下，<strong>上拉电阻最小值</strong> <span class="math inline">\(R_{P_{min}}\)</span>与<strong>上拉参考电压</strong> <span class="math inline">\(V_{CC}\)</span> 之间的关系：</p><p><img src="/Electronics/I2C/Resistor-2.png"></p><p>下面图像表达了 I2C总线在标准模式和快速模式下，<strong>上拉电阻最大值</strong> <span class="math inline">\(R_{P_{max}}\)</span>与<strong>上拉参考电压</strong> <span class="math inline">\(V_{CC}\)</span> 之间的关系：</p><p><img src="/Electronics/I2C/Resistor-3.png"></p><h3 id="上拉电阻计算实例">上拉电阻计算实例</h3><p>当一个 I2C总线处于快速模式下的时候，已知<strong>传输线等效电容</strong> <span class="math inline">\(C_B =200pF\)</span>，<strong>总线参考电压</strong> <span class="math inline">\(V_{CC} = 3.3V\)</span>参数，通过如下步骤就可以计算出上拉电阻的阻值：</p><p><span class="math display">\[\begin{cases}R_{P_{max}} = \frac{t_R}{0.8473 \times C_B} = \frac{300 \times10^{-9}}{0.8473 \times 200 \times 10^{-12}} = 1.77 kΩ \\R_{P_{min}} = \frac{V_{CC} - V_{OL_{max}}}{I_{OL}} = \frac{3.3 - 0.4}{3\times 10^{-3}} = 966.667 Ω\end{cases}\]</span></p><blockquote><p><strong>注意</strong>：上述计算步骤采用了前面 I2C总线规范参数表格当中的数据，</p></blockquote><p>经过上述的计算步骤，就可以基于当前的<strong>速率</strong>与<strong>功耗</strong>需求，选择<code>966.667Ω ~ 1.77kΩ</code> 范围之间的任意上拉电阻值。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;strong&gt;内置集成电路总线&lt;/strong&gt;（Inter-Integrated
Circuit）是一种串行通信协议，其英文缩写为
&lt;strong&gt;I²C&lt;/strong&gt;，因为中间存在 2 个英文字母
&lt;code&gt;I&lt;/code&gt;，所以被读作 &lt;code&gt;I Square C&lt;/code&gt;，中文读作
&lt;code&gt;I 平方 C&lt;/code&gt; 或者 &lt;code&gt;I 方 C&lt;/code&gt;
总线。本文后续内容为了书写方便，会将 &lt;strong&gt;I²C&lt;/strong&gt; 简写为
&lt;strong&gt;I2C&lt;/strong&gt;。该总线协议需要&lt;strong&gt;串行数据线&lt;/strong&gt;（SDA，Serial
Data）和&lt;strong&gt;串行时钟线&lt;/strong&gt;（SCL，Serial
Clock）两条信号线，接线方式较为简单，通常用于连接微控制器、存储器、传感器等低速元器件。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/Electronics/I2C/logo.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;在 &lt;strong&gt;I²C&lt;/strong&gt;
总线通信协议当中，规定总线上可以存在一个&lt;strong&gt;主设备&lt;/strong&gt;以及多个&lt;strong&gt;从设备&lt;/strong&gt;。&lt;strong&gt;主设备&lt;/strong&gt;掌控着整个通信过程，负责发起、控制、停止通信。而&lt;strong&gt;从设备&lt;/strong&gt;则需要等待主设备请求、接收、发送数据。主设备与从设备之间的数据交换采用特定的&lt;strong&gt;数据帧&lt;/strong&gt;格式，每个数据帧包含有
&lt;code&gt;地址&lt;/code&gt;、&lt;code&gt;数据&lt;/code&gt;、&lt;code&gt;控制&lt;/code&gt;
信息。&lt;strong&gt;主设备&lt;/strong&gt;会根据&lt;strong&gt;从设备&lt;/strong&gt;的 I2C
地址来选择总线上需要进行通信的外设，从设备则根据控制信息返回相应的响应。&lt;/p&gt;</summary>
    
    
    
    <category term="硬件电子技术" scheme="http://www.uinio.com/categories/%E7%A1%AC%E4%BB%B6%E7%94%B5%E5%AD%90%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="通信总线" scheme="http://www.uinio.com/tags/%E9%80%9A%E4%BF%A1%E6%80%BB%E7%BA%BF/"/>
    
  </entry>
  
  <entry>
    <title>硬件工程师必知必会的 Xilinx FPGA 知识</title>
    <link href="http://www.uinio.com/Electronics/FPGA/"/>
    <id>http://www.uinio.com/Electronics/FPGA/</id>
    <published>2025-07-01T16:00:00.000Z</published>
    <updated>2025-10-27T15:10:46.975Z</updated>
    
    <content type="html"><![CDATA[<p><strong>现场可编程门阵列</strong>（FPGA，Field Programmable GateArray）是一种<code>高性能</code>、<code>低延时</code>、<code>可重构</code>，拥有<code>高速并行运算</code>能力，并<code>可定制性能与功耗</code>的可编程数字逻辑芯片，最早由<strong>1984</strong>年创立的<strong>赛灵思</strong>（Xilinx）公司推出，该公司由<code>Ross H. Freeman</code> 和 <code>Bernard V. Vonderschmitt</code>共同创办。不同于<strong>专用集成电路</strong>（ASIC，ApplicationSpecific Integrated Circuit）固定的内部电路连接和逻辑功能。FPGA的内部电路连接和逻辑功能，都可以通过编程来灵活的定义。</p><p><img src="/Electronics/FPGA/logo.png"></p><p>目前全球 FPGA的市场份额主要集中在<strong>赛灵思</strong>（Xilinx，2020 年被 AMD收购）和<strong>阿尔特拉</strong>（Altera，2015 年被 Intel收购）两家美国企业手中，余下的市场份额同样由美国的<strong>莱迪思</strong>（Lattice）和<strong>美高森美</strong>（Microsemi）两家公司占据。国产FPGA 芯片产业起步较晚，产品性能与专利积累较为薄弱，目前主要有 <a href="https://www.pangomicro.com/index.html">深圳紫光同创</a>、<a href="https://www.anlogic.com/">上海安路科技</a>、<a href="https://www.gowinsemi.com.cn/">广东高云半导体</a>、<a href="https://www.fmsh.com/">上海复旦微电子</a>、<a href="https://www.isilicontech.com/">西安智多晶</a>、<a href="https://www.elitestek.com/index.html">深圳易灵思</a>、<a href="https://www.hercules-micro.com/">北京京微齐力</a>、<a href="http://www.csmsc.com/">成都华微电子</a> 等芯片研发厂商。</p><span id="more"></span><h2 id="amdxilinx-产品线介绍">AMD/Xilinx 产品线介绍</h2><p><strong>AMD/Xilinx</strong> 公司的<strong>现场可编程门阵列</strong>（FPGA，Field Programmable GateArray）产品线，主要可以划分为 <strong>7系列</strong>、<strong>UltraScale 系列</strong>、<strong>UltraScale+系列</strong> 三个大系列：</p><ol type="1"><li><strong>7 系列</strong>：采用 <code>28nm</code> 制程工艺，包含<code>Spartan-7</code>、<code>Artix-7</code>、<code>Kintex-7</code>、<code>Virtex-7</code>四个子系列；</li><li><strong>UltraScale 系列</strong>：采用 <code>20nm</code>制程工艺，包含<code>Kintex UltraScale</code>、<code>Virtex UltraScale</code>两个子系列；</li><li><strong>UltraScale+ 系列</strong>：采用 <code>16nm</code>制程工艺，包含<code>Spartan UltraScale+</code>、<code>Artix UltraScale+</code>、<code>Kintex UltraScale+</code>、<code>Virtex UltraScale+</code>子系列；</li></ol><p>在上述三个大系列的基础之上，面向不同的应用场景，上述每一个系列会被进一步划分为<strong>Spartan</strong>、<strong>Artix</strong>、<strong>Kintex</strong>、<strong>Virtex</strong>四个子系列：</p><ol type="1"><li><strong>Spartan</strong>系列：低成本低功耗，面向消费电子和基础应用；</li><li><strong>Artix</strong>系列：平衡成本与性能，适用于低功耗中等算力场景；</li><li><strong>Kintex</strong>系列：高性能计算与通信，同时兼顾性价比；</li><li><strong>Virtex</strong> 系列：旗舰级高性能，用于最苛刻的应用；</li></ol><p><strong>AMD/Xilinx</strong> 公司也推出了同时集成有 Soc 和 FPGA的四种<strong>自适应 Soc</strong>（Adaptive SoCs）产品线：</p><ul><li><strong>7000 SoC</strong>：采用 <strong>28nm</strong>制程工艺，集成有单/双核 <code>ARM Cortex-A9</code>，拥有<code>12.5G</code> 速率的收发器；</li><li><strong>UltraScale+™ MPSoC</strong>：采用 16nm制程工艺，集成有双/四核 <code>ARM Cortex-A53</code>、双核<code>ARM Cortex-R5F</code>、<code>ARM Mali-400MP2</code> 和 H.264/H.265视频编解码器。</li><li><strong>UltraScale+ RFSoC</strong>：采用 16nm 制程工艺，集成有四核<code>ARM Cortex-A53</code>、双核 <code>ARM Cortex-R5F</code> 和数字<code>RF-ADC</code>、<code>RF-DAC</code>、<code>SD-FEC</code>，广泛应用于5G 通信、雷达、卫星通信等领域。</li><li><strong>AMD Versal Adaptive SoC</strong>：采用 7nm制程工艺，集成有双核 <code>ARM Cortex-A72</code>、双核<code>ARM Cortex-R5F</code>，以及 DSP 和 AI引擎与可编程片上网络，主要应运用于人工智能场景。</li></ul><p><strong>AMD/Xilinx</strong> 公司目前力推的<strong>UltraScale+</strong> 系列<strong>多处理器片上系统</strong>（MPSoC，Multi-Processor System onChip）产品，属于集成有多种异构处理核心的高性能片上系统，主要内置有如下的片上计算资源：</p><ul><li><strong>应用处理器 APU</strong>：多核 64 位<code>ARM Cortex-A53</code>，可运行 Linux 操作系统，负责通用计算；</li><li><strong>实时处理器 RPU</strong>：双核<code>ARM Cortex-R5F</code>，用于处理实时任务；</li><li><strong>图形处理器 GPU</strong>：<code>ARM Mali-400MP2</code>用于处理显示输出任务；</li><li><strong>可编程逻辑PL</strong>：<code>UltraScale+ FPGA</code>，用于实现硬件加速；</li><li><strong>视频编解码</strong>：用于支持 <code>H.264/H.265</code>视频编解码；</li></ul><p>而 <strong>UltraScale+ MPSoC</strong> 主要涵盖了<strong>CG</strong>、<strong>EG</strong>、<strong>EV</strong>、<strong>RF</strong>如下四个子系列：</p><ul><li><strong>CG 子系列</strong>：入门级器件，主要集成有<code>双核 1.3 GHz ARM Cortex-A53</code> 和<code>双核 ARM Cortex-R5F</code>，系统逻辑单元数量在<code>81K ~ 600K</code> 范围；</li><li><strong>EG 子系列</strong>：资源较为丰富，主要集成有<code>四核 1.5 GHz ARM Cortex-A53</code>、<code>双核 600 MHz ARM Cortex-R5F</code>、<code>ARM Mali-400MP2</code>，系统逻辑单元数量在<code>81K ~ 1143K</code> 范围；</li><li><strong>EV 子系列</strong>：内置视频编解码器，主要集成有<code>四核 1.5 GHz ARM Cortex-A53</code>、<code>双核 600 MHz ARM Cortex-R5F</code>、<code>ARM Mali-400MP2</code>、<code>H.264/H.265 视频编解码器</code>，系统逻辑单元数量在<code>192K ~ 504K</code> 范围；</li></ul><h2 id="mpsoc-命名规则">MPSoC 命名规则</h2><p><strong>UltraScale+ MPSoC</strong> 系列产品的命名由<code>设备名称 + 设备属性 + 封装信息</code> 构成，例如对于命名为<code>XCZU7EV-2FFV C1156I</code> 的 MPSoC 芯片:</p><p><img src="/Electronics/FPGA/Naming-Rule.png"></p><p><strong>设备名称</strong> 部分是 <code>XCZU7EV</code>：</p><ul><li><strong>商品级别</strong>：<strong>XC</strong> 表示 XilinxCommercial 公司；</li><li><strong>产品系列</strong>：<strong>ZU</strong> 表示<code>Zynq UltraScale+</code> 系列；</li><li><strong>价值索引</strong>：该数值越大，片上资源就越丰富，价格也就越高；</li><li><strong>处理器系统标识符</strong>：<strong>C</strong> 代表双核 APU和双核 RPU，<strong>E</strong> 代表四核 APU、双核 RPU、单个 GPU；</li><li><strong>引擎类型</strong>： <strong>G</strong>表示通用，<strong>V</strong> 表示带有视频解码器；</li></ul><p><strong>制造工艺</strong> 部分是 <code>-2FFV</code>：</p><ul><li><strong>速度等级</strong>：<code>-1/2/3</code>表示最慢/中等/最快，<code>-L1/L2</code> 表示低功耗；</li><li><strong>倒装封装</strong>：<strong>F</strong> 表示球距<code>1.0 mm</code> 的 Flip-chip 封装，<strong>S</strong> 表示球距<code>0.8 mm</code> 的 Flip-chip 封装，<strong>U</strong> 表示球距<code>0.5 mm</code> 的 InFO 封装；</li><li><strong>封装技术</strong>：<strong>F</strong> 表示 <code>Lid</code>封装技术，<strong>B</strong> 表示 <code>Lidless</code> 封装技术；</li><li><strong>电气标准</strong>：<strong>V</strong> 表示符合<strong>RoHS</strong> 六项检测；</li></ul><p><strong>封装信息</strong> 部分是 <code>C1156I</code>：</p><ul><li><strong>封装标识符</strong>：例如 <code>A</code> 或者 <code>C</code>等；</li><li><strong>封装引脚数量</strong>：例如 <code>1156</code> 等；</li><li><strong>温度等级</strong>：<strong>E</strong> 表示工作在<code>0°C ~ +100°C</code>，<strong>I</strong> 表示工作在<code>–40°C ~ +100°C</code>；</li></ul><h2 id="处理系统-ps-可编程逻辑-pl">处理系统 PS / 可编程逻辑 PL</h2><p><strong>AMD/Xilinx</strong> 的 <strong>MPSoC</strong> 系列 FPGA芯片主要由 <strong>处理系统</strong>（PS，Processing System）和<strong>可编程逻辑</strong>（PL，ProgrammableLogic）两个核心部分组成（两者可以分别独立供电与断电），下图展示了<strong>XCZU7EV</strong> 的系统架构图：</p><p><img src="/Electronics/FPGA/UltraScale+EG.jpg"></p><ul><li><strong>处理系统</strong>（PS，Processing System）：基于 ARM Cortex架构，类似于传统的 CPU 中央处理器，可以直接运行嵌入式 Linux操作系统；</li><li><strong>可编程逻辑</strong>（PL，Programmable Logic）：传统的 FPGA可编程逻辑资源，支持硬件并行处理，可通过 <strong>Verilog</strong> 或者<strong>VHDL</strong> 进行编程；</li></ul><blockquote><p><strong>注意</strong>：<strong>PS</strong> 和 <strong>PL</strong>之间通过 FPGA 片内的<strong>高级可扩展接口</strong>（AXI，AdvancedeXtensible Interface）总线进行高速数据传输。</p></blockquote><h2 id="可编程逻辑-pl">可编程逻辑 PL</h2><p>简化的 FPGA 基本结构分别由<code>可编程输入/输出单元</code>、<code>基本可编程逻辑单元</code>、<code>嵌入式块 RAM</code>、<code>布线资源</code>、<code>底层嵌入功能单元</code>、<code>内嵌专用硬核</code>六个部分组成：</p><p>FPGA的输入/输出单元被设计为可编程模式，可以通过开发工具灵活的进行配置，从而适配不同的电气标准与I/O 物理特性（可以调整匹配阻抗特性、上下拉电阻、驱动电流的大小等）。</p><h2 id="处理系统-ps">处理系统 PS</h2><h2 id="串行解串器-serdes">串行解串器 SerDes</h2><p>FPGA内置的<strong>串行解串器</strong>（<strong>SerDes</strong>，Serializer/Deserializer）用于进行串行数据与并行数据的相互转换：</p><ol type="1"><li>当 FPGA 作为<strong>接收端</strong>的时候，用于将串行数据，转换为FPGA 内部能够处理的并行数据。</li><li>当 FPGA 作为<strong>发送端</strong>的时候，用于将 FPGA内部的并行数据，转换为便于传输的串行数据。</li></ol><blockquote><p><strong>注意</strong>：现代 FPGA 通常集成了专用的<strong>SerDes</strong> 外设，例如 <strong>AMD/Xilinx</strong> 的<code>GTX/GTH/GTY</code> 收发器，以及 <strong>Intel/Altera</strong> 的<code>Transceiver</code> 收发器。</p></blockquote><h2 id="查找表-lut">查找表 LUT</h2><p><strong>查找表</strong>（LUT，Look-Up Table）是现场可编程门阵列 FPGA当中的基本逻辑单元，用于实现组合逻辑功能。</p><p>简单的来说，就是将某个简单逻辑功能的全部可能结果写到一个存储单元中，并根据输入的变化直接查找结果并输出。</p><h2 id="mioemio-多路复用-io">MIO/EMIO 多路复用 IO</h2><p>AMD/Xilinx FPGA 提供了<strong>多路复用</strong>（MIO，MultiplexedIO）和<strong>扩展多路复用</strong>（EMIO，Extended Multiplexed IO）两种I/O 管理机制：</p><ul><li><strong>MIO</strong>：由处理系统 PS 直接管理的物理引脚，无需经过 PL可编程逻辑单元，可以控制 PS 的各种外设；</li><li><strong>EMIO</strong>：由处理系统 PS 通过 PL 可编程逻辑扩展的 I/O接口，当 PS 的 MIO 数量不足时，可通过 PL 路由出更多的EMIO（会引入额外延迟）；</li></ul><h2 id="io-bank">I/O Bank</h2><p>FPGA 的器件管脚按照 Bank 进行划分，通过为每个 Bank独立供电（通过接口电压 <code>VCCO</code>进行配置），适配不同的信号电平标准，从而增强 I/O 设计的灵活性。每组用户Bank 可以包括 <code>52</code> 个 <strong>HP</strong> 或者<strong>HR</strong> 的 I/O 引脚，或者 <code>24</code> 组<strong>HD</strong> 的 I/O 引脚（由 48 个差分引脚和 4个单端引脚组成）：</p><ul><li><strong>高性能</strong>（<strong>HP</strong>，HighPerformance）：应用于高速场景，工作电压通常在 <code>1.0V ~ 1.8V</code>范围（电平的电压越低，通信速率就会越快）；</li><li><strong>宽范围</strong>（<strong>HR</strong>，HighRange）：应用于宽范围电压场景，可以支持 <code>1.2V ~ 3.3V</code>的宽范围工作电压；</li><li><strong>高密度</strong>（<strong>HD</strong>，High Density）：每个Bank 通常由 24 个 I/O 构成，可以支持 <code>1.2V ~ 3.3V</code>；</li></ul><h2 id="串行解串器-serdes-1">串行解串器 SerDes</h2><p>FPGA内置的<strong>串行解串器</strong>（<strong>SerDes</strong>，Serializer/Deserializer）用于进行串行数据与并行数据的相互转换：</p><ol type="1"><li>当 FPGA 作为<strong>接收端</strong>的时候，用于将串行数据，转换为FPGA 内部能够处理的并行数据。</li><li>当 FPGA 作为<strong>发送端</strong>的时候，用于将 FPGA内部的并行数据，转换为便于传输的串行数据。</li></ol><blockquote><p><strong>注意</strong>：现代 FPGA 通常集成了专用的<strong>SerDes</strong> 外设，例如 <strong>AMD/Xilinx</strong> 的<code>GTx</code> 收发器，以及 <strong>Intel/Altera</strong> 的<code>Transceiver</code> 收发器。</p></blockquote><h2 id="吉比特收发器-gtx">吉比特收发器 GTx</h2><p><strong>AMD/Xilinx</strong> 的 FPGA 产品当中集成的 SerDes外设被称作<strong>吉比特收发器</strong>（GT，GigabyteTransceiver），基于不同的数据传输速率及其所具备的高级特性，规格书当中会分别以<code>GTx</code> 格式进行命名，例如<code>GTP</code>、<code>GTX</code>、<code>GTH</code>、<code>GTZ</code>、<code>GTY</code>。对应于<strong>AMD/Xilinx</strong> 的不同产品系列，<code>GTx</code>的传输速率也会有所不同：</p><table><thead><tr><th style="text-align: left;">7 系列</th><th style="text-align: left;">UltraScale 系列</th><th style="text-align: left;">UltraScale+ 系列</th></tr></thead><tbody><tr><td style="text-align: left;"><code>GTP = 6.6 Gb/s</code></td><td style="text-align: left;"><code>GTH = 16.3Gb/s</code></td><td style="text-align: left;"><code>GTH = 16.3Gb/s</code></td></tr><tr><td style="text-align: left;"><code>GTX = 12.5 Gb/s</code></td><td style="text-align: left;"><code>GTY = 30.5Gb/s</code></td><td style="text-align: left;"><code>GTY = 32.75Gb/s</code></td></tr><tr><td style="text-align: left;"><code>GTH = 13.1 Gb/s</code></td><td style="text-align: left;">-</td><td style="text-align: left;">-</td></tr><tr><td style="text-align: left;"><code>GTZ = 28.05 Gb/s</code></td><td style="text-align: left;">-</td><td style="text-align: left;">-</td></tr></tbody></table><h2 id="赛灵思-fpga-最小系统">赛灵思 FPGA 最小系统</h2><p><strong>插入损耗</strong>（IL，InsertionLoss）是指由于元器件插入传输线路之前与之后，信号传输功率损耗的差值，通常使用单位<strong>分贝</strong><code>dB</code> 来进行表示。</p><p>下面的图片展示了 XCZU5EG 的系统架构框图：</p><h2 id="基本的数字逻辑门">基本的数字逻辑门</h2><p><strong>门电路</strong>是数字集成电路当中，最为基本的逻辑单元，用于实现<strong>基本逻辑运算</strong><code>与</code>、<code>或</code>、<code>非</code>，以及<strong>复合逻辑运算</strong><code>与非</code>、<code>或非</code>、<code>异或</code>、<code>同或</code>，对应的逻辑运算门电路有<code>与门</code>、<code>或门</code>、<code>非门</code>、<code>与非门</code>、<code>或非门</code>、<code>异或门</code>、<code>同或门</code>，其电路符号如下图所示：</p><p><img src="/Electronics/FPGA/Logic.png"></p><h2 id="广濑-fx10-高速堆叠连接器">广濑 FX10 高速堆叠连接器</h2><p><strong>FX10</strong> 是日本广濑推出的一款 <code>0.5mm</code>间距高速堆叠连接器，其最高传输速率可以达到 <code>15+ Gbps</code>：</p><p><img src="/Electronics/FPGA/FX10.png"></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;strong&gt;现场可编程门阵列&lt;/strong&gt;（FPGA，Field Programmable Gate
Array）是一种&lt;code&gt;高性能&lt;/code&gt;、&lt;code&gt;低延时&lt;/code&gt;、&lt;code&gt;可重构&lt;/code&gt;，拥有&lt;code&gt;高速并行运算&lt;/code&gt;能力，并&lt;code&gt;可定制性能与功耗&lt;/code&gt;的可编程数字逻辑芯片，最早由
&lt;strong&gt;1984&lt;/strong&gt;
年创立的&lt;strong&gt;赛灵思&lt;/strong&gt;（Xilinx）公司推出，该公司由
&lt;code&gt;Ross H. Freeman&lt;/code&gt; 和 &lt;code&gt;Bernard V. Vonderschmitt&lt;/code&gt;
共同创办。不同于&lt;strong&gt;专用集成电路&lt;/strong&gt;（ASIC，Application
Specific Integrated Circuit）固定的内部电路连接和逻辑功能。FPGA
的内部电路连接和逻辑功能，都可以通过编程来灵活的定义。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/Electronics/FPGA/logo.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;目前全球 FPGA
的市场份额主要集中在&lt;strong&gt;赛灵思&lt;/strong&gt;（Xilinx，2020 年被 AMD
收购）和&lt;strong&gt;阿尔特拉&lt;/strong&gt;（Altera，2015 年被 Intel
收购）两家美国企业手中，余下的市场份额同样由美国的&lt;strong&gt;莱迪思&lt;/strong&gt;（Lattice）和&lt;strong&gt;美高森美&lt;/strong&gt;（Microsemi）两家公司占据。国产
FPGA 芯片产业起步较晚，产品性能与专利积累较为薄弱，目前主要有 &lt;a href=&quot;https://www.pangomicro.com/index.html&quot;&gt;深圳紫光同创&lt;/a&gt;、&lt;a href=&quot;https://www.anlogic.com/&quot;&gt;上海安路科技&lt;/a&gt;、&lt;a href=&quot;https://www.gowinsemi.com.cn/&quot;&gt;广东高云半导体&lt;/a&gt;、&lt;a href=&quot;https://www.fmsh.com/&quot;&gt;上海复旦微电子&lt;/a&gt;、&lt;a href=&quot;https://www.isilicontech.com/&quot;&gt;西安智多晶&lt;/a&gt;、&lt;a href=&quot;https://www.elitestek.com/index.html&quot;&gt;深圳易灵思&lt;/a&gt;、&lt;a href=&quot;https://www.hercules-micro.com/&quot;&gt;北京京微齐力&lt;/a&gt;、&lt;a href=&quot;http://www.csmsc.com/&quot;&gt;成都华微电子&lt;/a&gt; 等芯片研发厂商。&lt;/p&gt;</summary>
    
    
    
    <category term="硬件电子技术" scheme="http://www.uinio.com/categories/%E7%A1%AC%E4%BB%B6%E7%94%B5%E5%AD%90%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="芯片" scheme="http://www.uinio.com/tags/%E8%8A%AF%E7%89%87/"/>
    
  </entry>
  
  <entry>
    <title>一份面面俱到的 Ethernet 以太网技术摘要</title>
    <link href="http://www.uinio.com/Electronics/Ethernet/"/>
    <id>http://www.uinio.com/Electronics/Ethernet/</id>
    <published>2025-06-04T16:00:00.000Z</published>
    <updated>2025-11-23T17:10:09.858Z</updated>
    
    <content type="html"><![CDATA[<p>早在 <strong>1972</strong> 年，就职于<a href="https://www.xerox.com/en-us">美国施乐 <strong>Xerox</strong>公司</a>的 <strong>RobertMetcalfe</strong>（被称作以太网之父）与另外两位学者，协作发表了一篇名为《<strong>以太网：区域计算机网络的分布式包交换技术</strong>》的文章，并在不久之后获得了《具有冲突检测的多点数据通信系统》专利，<strong>以太网</strong>（Ethernet）技术的雏形就此诞生。至此以太网相关的标准不断演进，诞生了<strong>标准以太网</strong>(<code>10 Mbit/s</code>)、<strong>快速以太网</strong>(<code>100 Mbit/s</code>)、<strong>千兆以太网</strong>(<code>1000 Mbit/s</code>)、<strong>万兆以太网</strong>(<code>10000 Mbit/s</code>)等一系列标准。</p><p><img src="/Electronics/Ethernet/logo.png"></p><p><strong>以太网</strong>的底层工作机制基于<strong>载波侦听多路访问/碰撞检测</strong>（<strong>CSMA/CD</strong>，CarrierSense Multiple Access with CollisionDetection）协议，从而确保多个设备在相同的物理介质上通信。当其中一个设备有数据需要发送时，会先监听线路上是否存在其它信号，线路空闲就开始传输数据，线路繁忙则等待直至线路可用为止。如果在传输过程当中发生了碰撞（即两个设备同时发送数据导致信号叠加），设备就会检测到这种情况并且发送阻塞信号，然后等待随机时间之后再进行重试。</p><span id="more"></span><h2 id="以太网发展历程">以太网发展历程</h2><p>自从 1972年<strong>以太网</strong>诞生之后，其标准经过数十年的演进，陆续由<strong>电气电子工程师学会</strong>（IEEE，Institute of Electrical andElectronics Engineers）制订了 <code>10 Mbit/s</code><strong>标准以太网</strong>、<code>100 Mbit/s</code><strong>快速以太网</strong>、<code>1000 Mbit/s</code><strong>千兆以太网</strong>、<code>10 Gbit/s</code><strong>万兆以太网</strong> 等一系列规范：</p><p><img src="/Electronics/Ethernet/History.png"></p><table><thead><tr><th style="text-align: left;">以太网类型</th><th style="text-align: left;">传输速率</th><th style="text-align: left;">IEEE 标准</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>标准以太网</strong></td><td style="text-align: left;"><code>10 Mbit/s</code></td><td style="text-align: left;"><strong>IEEE 802.3</strong></td></tr><tr><td style="text-align: left;"><strong>快速以太网</strong></td><td style="text-align: left;"><code>100 Mbit/s</code></td><td style="text-align: left;"><strong>IEEE 802.3u</strong></td></tr><tr><td style="text-align: left;"><strong>千兆以太网</strong></td><td style="text-align: left;"><code>1000 Mbit/s</code></td><td style="text-align: left;"><strong>IEEE 802.3ab</strong> 和<strong>IEEE 802.3z</strong></td></tr><tr><td style="text-align: left;"><strong>万兆以太网</strong></td><td style="text-align: left;"><code>10 Gbit/s</code></td><td style="text-align: left;"><strong>IEEE 802.3ae</strong></td></tr></tbody></table><p>由 <strong>IEEE</strong> 制订的<strong>以太网</strong> Ethernet相关的协议规范及其基本特性，请参考下面的表格所示：</p><table><colgroup><col style="width: 20%"><col style="width: 28%"><col style="width: 20%"><col style="width: 30%"></colgroup><thead><tr><th style="text-align: left;">IEEE 标准</th><th style="text-align: left;">传输速率</th><th style="text-align: left;">物理介质</th><th style="text-align: left;">最大传输距离</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>IEEE 802.3</strong></td><td style="text-align: left;"><code>10 Mbit/s</code></td><td style="text-align: left;">同轴电缆、双绞线</td><td style="text-align: left;">500 米（同轴线缆）</td></tr><tr><td style="text-align: left;"><strong>IEEE 802.3u</strong></td><td style="text-align: left;"><code>100 Mbit/s</code></td><td style="text-align: left;">双绞线、光纤</td><td style="text-align: left;">100 米</td></tr><tr><td style="text-align: left;"><strong>IEEE 802.3z</strong></td><td style="text-align: left;"><code>1 Gbit/s</code></td><td style="text-align: left;">光纤</td><td style="text-align: left;">550 米 (SX)，5 公里 (LX)</td></tr><tr><td style="text-align: left;"><strong>IEEE 802.3ab</strong></td><td style="text-align: left;"><code>1 Gbit/s</code></td><td style="text-align: left;">双绞线</td><td style="text-align: left;">100 米</td></tr><tr><td style="text-align: left;"><strong>IEEE 802.3ae</strong></td><td style="text-align: left;"><code>10 Gbit/s</code></td><td style="text-align: left;">光纤</td><td style="text-align: left;">400 米 ~ 40 公里</td></tr><tr><td style="text-align: left;"><strong>IEEE 802.3an</strong></td><td style="text-align: left;"><code>10 Gbit/s</code></td><td style="text-align: left;">双绞线</td><td style="text-align: left;">100 米</td></tr><tr><td style="text-align: left;"><strong>IEEE 802.3ba</strong></td><td style="text-align: left;"><code>40/100 Gbit/s</code></td><td style="text-align: left;">光纤</td><td style="text-align: left;">100 米 ~ 10 公里</td></tr><tr><td style="text-align: left;"><strong>IEEE 802.3by</strong></td><td style="text-align: left;"><code>25 Gbit/s</code></td><td style="text-align: left;">光纤、双轴线缆</td><td style="text-align: left;">100 米</td></tr><tr><td style="text-align: left;"><strong>IEEE 802.3bs</strong></td><td style="text-align: left;"><code>200/400 Gbit/s</code></td><td style="text-align: left;">光纤</td><td style="text-align: left;">500 米 ~ 10 公里</td></tr><tr><td style="text-align: left;"><strong>IEEE 802.3bt</strong></td><td style="text-align: left;"><code>10 Mbit/s ~ 1 Gbit/s</code></td><td style="text-align: left;">双绞线（POE）</td><td style="text-align: left;">100 米</td></tr></tbody></table><h2 id="以太网基本拓扑">以太网基本拓扑</h2><p><strong>总线型拓扑</strong>：所有设备都连接到同一条传输介质，所需要的线缆数量较少，长度也较短，易于布线和维护；并且多个结点共用一条传输信道，信道利用率也更高。</p><p><img src="/Electronics/Ethernet/Topology-1.png"></p><p><strong>星型拓扑</strong>：一种单中心多节点的结构，管理维护相对容易，并且扩展性较强。缺点在于一旦中心发生故障，整个网络就会瘫痪，而且整体的信道利用率也不高。</p><p><img src="/Electronics/Ethernet/Topology-2.png"></p><p><strong>环形拓扑</strong>：由节点形成的一个闭合环路，组网成本比较低。但是单个节点的故障，会导致整个网络都出现问题。</p><p><img src="/Electronics/Ethernet/Topology-3.png"></p><blockquote><p><strong>注意</strong>：这种节点之间直接通过线缆进行串连的连接方式也被称作<strong>菊花链拓扑</strong>（无论是否首尾相连）。</p></blockquote><p><strong>树形拓扑</strong>：由总线型拓扑演变而来，顶部的根结点接收各个子结点发送的数据，然后再广播到整个拓扑网络。</p><p><img src="/Electronics/Ethernet/Topology-4.png"></p><p><strong>网状拓扑</strong>：这种拓扑结构应用最为广泛，优点在于不易出现连接故障，而缺点在于组网过于复杂，不利于排查问题，且后期的运营维护成本会比较高。</p><p><img src="/Electronics/Ethernet/Topology-5.png"></p><blockquote><p><strong>注意</strong>：<strong>以太网的拓扑结构</strong>表达的是网络当中，各个设备结点之间的物理连接方式。</p></blockquote><h2 id="以太网通信动画演示">以太网通信动画演示</h2><p>本节内容主要是通过一系列动画来演示以太网的基本通信过程，帮助大家建立起直观的概念。第一个动画演示的是一个基于<strong>同轴线缆</strong>连接的<strong>菊花链</strong>结构以太网，在节点2 向节点 4发送消息之前，需要监听当前网络的占用状态。如果当前网络处于空闲状态，节点2 就会开始数据传输（黄色屏幕闪烁），每个数据包都包含有<code>目的地址</code>、<code>发送者地址</code>、<code>待传输的数据</code>。线缆上传输的数据包将会被每一个节点接收到，但是由于其<code>目的地址</code> 是指向 4号节点，所以其它节点会忽略该数据包。然后节点 4在接收到数据包之后，会向节点 2号响应一个用于接收确认的数据包（紫色屏幕闪烁）：</p><p><img src="/Electronics/Ethernet/Animation-1.gif"></p><p>接下来的动画，演示了节点 2 和节点 5同时发送数据包的情景，此时两个数据包会在传输线缆上发生<strong>碰撞</strong>，导致各个节点在指定的时间周期内监听不到信号。此时节点2会在延迟一段时间之后，继续重新发出数据包（对于菊花链拓扑方式，如果当前接入的节点过多，大量数据包有可能会同时发生碰撞，这会降低网络的响应速度，甚至瘫痪整个网络，所以菊花链拓扑当中不宜接入过多的节点）：</p><p><img src="/Electronics/Ethernet/Animation-2.gif"></p><p>而下面的动画当中，则是将以太网的拓扑结构从菊花链，转变为了基于<strong>集线器</strong>的<strong>星型</strong>连接。此时节点1 向节点 4发送数据包，这些数据包都会先经过集线器之后再到达其它节点。虽然集线器无法解决数据包碰撞的问题，但是其集中布线的特点，能够自动绕开故障节点（目前集线器已经较少使用，取而代之的是<strong>交换机</strong>）：</p><p><img src="/Electronics/Ethernet/Animation-3.gif"></p><p>在接下来的动画里，则是把以太网<strong>星型</strong>拓扑结构中的<strong>集线器</strong>更换为了<strong>交换机</strong>，此时交换机会解析出数据包当中的<code>目标地址</code>，然后将其转发给拥有该地址的节点。这样就可以避免向整个网络上的所有节点广播该数据包，从而引发数据包相互碰撞的问题：</p><p><img src="/Electronics/Ethernet/Animation-4.gif"></p><p>目前，<strong>总线型拓扑</strong>基本已经被淘汰，并且被基于<code>交换机</code>的<strong>星型拓扑</strong>所取代。而<strong>菊花链</strong>拓扑则依然被应用于<code>交换机级联</code>、<code>环形冗余网络</code>等特定场景，但是在使用时需要注意其与总线型拓扑的区别：</p><ul><li><strong>总线型拓扑</strong>：所有节点通过各自的子线缆，<strong>并联</strong>到一条公共的母线缆上进行通信。</li><li><strong>菊花链拓扑</strong>：各个节点之间，直接通过线缆逐个<strong>串联</strong>起来（不存在公共的总线）。</li></ul><h2 id="载波感知多址冲突检测">载波感知多址/冲突检测</h2><p>以太网规范 <strong>IEEE 802.3</strong>当中，所有节点都共用一条传输介质，为了避免数据传输过程出现混乱，<strong>载波感知多址/冲突检测</strong>（CSMA/CD，CarrierSense Multiple Access/CollisionDetection）提供了一种正确组织数据传输的方法。（一边发送一边检测，发现冲突就停止发送，延迟随机时间之后继续发送），主要用于避免多个设备在同一时刻抢占通信链路，大家可以从如下三个维度进行理解：</p><ul><li><strong>CS载波侦听</strong>：监听线路的空闲状态，减少冲突发生的机会。</li><li><strong>MA多址访问</strong>：多个节点共享一条传输介质，每个节点发送的数据，都可以被其它节点接收。</li><li><strong>CD冲突检测</strong>：当两个节点同时发送的信号发生叠加之后，会导致线路上的电压摆动值超出正常值，基于此可以判断冲突的产生。</li></ul><p><img src="/Electronics/Ethernet/CSMA-CD.png"></p><p>上面的流程图里，完整呈现了 <strong>CSMA/CD</strong>如下面表格当中的处理步骤：</p><ol type="1"><li>首先，终端设备不停的检测共享线路的状态，如果线路空闲才会发送数据，否则就会一直等待；</li><li>然后，如果两个设备同时发送数据，必然会产生冲突，导致线路上传输的信号出现紊乱；</li><li>其次，终端设备检测到传输信号出现紊乱之后，就会立刻中断数据传输，并且产生<strong>JAM</strong> 干扰信号；</li><li>最后，终端设备会发送干扰脉冲通知其他设备，特别是相同时刻发送数据的设备，线路上已经产生了冲突，需要等待一段时间之后再行发送数据（检测到冲突之后的等待时间随机）。</li></ol><blockquote><p><strong>注意</strong>：<strong>CSMA/CD</strong> 主要应用于<code>10/100 Mbps</code> 以太网，对于 <code>1000 Mbps</code>传输速率的千兆以太网以及更高传输速率的以太网，虽然名义上仍然支持<strong>CSMA/CD</strong>，但是实际上只在半双工模式下有效，目前普遍采用的全双工模式已经不再采用<strong>CSMA/CD</strong>。因为在全双工模式下，由于每个设备都存在与交换机的专用连接，设备之间可以通过<strong>交换式以太网络</strong>实现数据的同时收发。</p></blockquote><h2 id="mac-和-phy">MAC 和 PHY</h2><p>在以太网协议的体系结构当中，<strong>介质访问控制 MAC</strong> 和<strong>物理层 PHY</strong>是两个非常重要的子层，它们分别实现了<strong>数据链路层</strong>下半部分和<strong>物理层</strong>的功能。通过两者的协同工作（基于后续介绍的<strong>媒体独立接口</strong><code>MII/RMII/SMII</code> 和 <code>GMII/RGMII/SGMII</code>进行数据交互），才能够实现可靠的以太网数据传输：</p><p><img src="/Electronics/Ethernet/MAC-PHY.png"></p><ul><li><strong>MAC介质访问控制层芯片</strong>：工作在<strong>数据链路层</strong>下半部分，使用<strong>MAC 地址</strong>作为设备唯一标识，主要负责<code>帧的封装/解封</code>、<code>介质访问控制</code>、<code>错误检测</code>、<code>流量控制</code>；</li><li><strong>PHY 物理层芯片</strong>：工作在<strong>物理层</strong>，通过 <code>MII/RMII/SMII</code> 或者<code>GMII/RGMII/SGMII</code> 接口规范与 MAC 连接，主要负责<code>信号的编码/解码</code>、<code>适配不同的传输介质</code>、<code>信号时钟同步</code>、<code>速度和模式协商</code>；</li><li><strong>Magnetics 网络变压器</strong>：本质上是一个匝数比为<code>1:1</code>的电感线圈，主要用于实现信号的<strong>隔离</strong>、<strong>传输</strong>、<strong>匹配</strong>（不使用会导致传输距离受限）；</li><li><strong>RJ45 连接器</strong>：带有 8个引脚，既可以作为<strong>千兆以太网</strong>使用（即<code>MX(0~3)+ ~ MX(0~3)-</code> 4 对 8线差分信号），也可以作为<strong>百兆以太网</strong>使用（<code>TX/RX+ ~ TX/RX-</code>2 对 4 线差分信号）；</li></ul><h2 id="rj45-连接器">RJ45 连接器</h2><p><strong>RJ45</strong> 连接器的英文全称为<code>Registered Jack 45</code>，主要应用于<strong>局域网</strong>（LAN，LocalArea Network）连接。该连接器具有 8 个触点，对应的 8条线缆通过<strong>双绞线</strong>构成 4组差分对。美国电信工业/电子工业协会 <strong>EIA/TIA</strong> 为<strong>RJ45</strong> 连接器及其对应线缆制定了 <strong>568B</strong> 和<strong>568A</strong> 两种线序连接标准：</p><p><img src="/Electronics/Ethernet/T568-1.png"></p><ul><li><strong>T568A 线序标准</strong>:<code>1-绿白</code>、<code>2-绿</code>、<code>3-橙白</code>、<code>4-蓝</code>、<code>5-蓝白</code>、<code>6-橙</code>、<code>7-棕白</code>、<code>8-棕</code>。</li><li><strong>T568B 线序标准</strong>:<code>1-橙白</code>、<code>2-橙</code>、<code>3-绿白</code>、<code>4-蓝</code>、<code>5-蓝白</code>、<code>6-绿</code>、<code>7-棕白</code>、<code>8-棕</code>。</li></ul><p><img src="/Electronics/Ethernet/T568-2.png"></p><p>两种线序衍生出了直通和交叉两种连接方式，其中<strong>直通连接方式</strong>，左右两侧均按照<strong>T568B</strong>线序标准进行连接，通常用于不同种类设备之间的连接（例如计算机与交换机）：</p><p><img src="/Electronics/Ethernet/RJ-45-Crossover.png"></p><p>而<strong>交叉连接方式</strong>，一侧按照 <strong>T568A</strong>线序连接，另外一侧按照 <strong>T568B</strong>线序连接，通常用于两台相似设备的直连（例如两台计算机之间的直连）：</p><p><img src="/Electronics/Ethernet/RJ-45-Straight.png"></p><blockquote><p><strong>注意</strong>：使用 <strong>RJ45</strong>连接的以太网设备，可以划分为用于计算机网卡、路由器等的<strong>数据终端设备</strong>（DTE，DataTerminalEquipment）和用于交换机等的<strong>数字通信设备</strong>（DCE，DigitalCommunicationEquipment）两种类型。<strong>不同类型的以太网设备使用直通连接方式，而相同类型的以太网设备使用交叉连接方式</strong>（某些具备<strong>自协商机制</strong>的DCE 类型设备，也可以使用直通连接方式）。</p></blockquote><p>遵循 <code>10 Mbit/s</code> 传输速率物理层线缆标准<strong>10Base-T</strong> 的 RJ45 连接器引脚功能说明如下表所示：</p><table><thead><tr><th style="text-align: center;">引脚编号</th><th style="text-align: left;">引脚名称</th><th style="text-align: left;">英文说明</th><th style="text-align: left;">中文说明</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>1</strong></td><td style="text-align: left;"><code>TX+</code></td><td style="text-align: left;"><strong>Tranceive Data +</strong></td><td style="text-align: left;">发送数据（正）</td></tr><tr><td style="text-align: center;"><strong>2</strong></td><td style="text-align: left;"><code>TX-</code></td><td style="text-align: left;"><strong>Tranceive Data -</strong></td><td style="text-align: left;">发送数据（负）</td></tr><tr><td style="text-align: center;"><strong>3</strong></td><td style="text-align: left;"><code>RX+</code></td><td style="text-align: left;"><strong>Receive Data +</strong></td><td style="text-align: left;">接收数据（正）</td></tr><tr><td style="text-align: center;"><strong>4</strong></td><td style="text-align: left;">NC</td><td style="text-align: left;">Not Connected</td><td style="text-align: left;">未使用</td></tr><tr><td style="text-align: center;"><strong>5</strong></td><td style="text-align: left;">NC</td><td style="text-align: left;">Not Connected</td><td style="text-align: left;">未使用</td></tr><tr><td style="text-align: center;"><strong>6</strong></td><td style="text-align: left;"><code>RX-</code></td><td style="text-align: left;"><strong>Receive Data -</strong></td><td style="text-align: left;">接收数据（负）</td></tr><tr><td style="text-align: center;"><strong>7</strong></td><td style="text-align: left;">NC</td><td style="text-align: left;">Not Connected</td><td style="text-align: left;">未使用</td></tr><tr><td style="text-align: center;"><strong>8</strong></td><td style="text-align: left;">NC</td><td style="text-align: left;">Not Connected</td><td style="text-align: left;">未使用</td></tr></tbody></table><p>遵循 <code>100 Mbit/s</code> 传输速率物理层线缆标准<strong>100Base-T4</strong> 的 RJ45 连接器引脚功能说明如下表所示：</p><table><thead><tr><th style="text-align: center;">引脚编号</th><th style="text-align: left;">引脚名称</th><th style="text-align: left;">英文说明</th><th style="text-align: left;">中文说明</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>1</strong></td><td style="text-align: left;"><code>TX D1 +</code></td><td style="text-align: left;"><strong>Tranceive Data +</strong></td><td style="text-align: left;">发送数据（正）</td></tr><tr><td style="text-align: center;"><strong>2</strong></td><td style="text-align: left;"><code>TX D1 -</code></td><td style="text-align: left;"><strong>Tranceive Data -</strong></td><td style="text-align: left;">发送数据（负）</td></tr><tr><td style="text-align: center;"><strong>3</strong></td><td style="text-align: left;"><code>RX D2 +</code></td><td style="text-align: left;"><strong>Receive Data +</strong></td><td style="text-align: left;">接收数据（正）</td></tr><tr><td style="text-align: center;"><strong>4</strong></td><td style="text-align: left;"><code>BI D3 +</code></td><td style="text-align: left;"><strong>Bi-Directional Data+</strong></td><td style="text-align: left;">双向数据（正）</td></tr><tr><td style="text-align: center;"><strong>5</strong></td><td style="text-align: left;"><code>BI D3 -</code></td><td style="text-align: left;"><strong>Bi-Directional Data-</strong></td><td style="text-align: left;">双向数据（负）</td></tr><tr><td style="text-align: center;"><strong>6</strong></td><td style="text-align: left;"><code>RX D2 -</code></td><td style="text-align: left;"><strong>Receive Data -</strong></td><td style="text-align: left;">接收数据（负）</td></tr><tr><td style="text-align: center;"><strong>7</strong></td><td style="text-align: left;"><code>BI D4 +</code></td><td style="text-align: left;"><strong>Bi-Directional Data+</strong></td><td style="text-align: left;">双向数据（正）</td></tr><tr><td style="text-align: center;"><strong>8</strong></td><td style="text-align: left;"><code>BI D4 -</code></td><td style="text-align: left;"><strong>Bi-Directional Data+</strong></td><td style="text-align: left;">双向数据（负）</td></tr></tbody></table><h2 id="介质依赖接口-mdimdix">介质依赖接口 MDI/MDIX</h2><p><strong>介质依赖接口</strong>（MDI，Media DependentInterface）是一种用于连接 <strong>PHY 芯片</strong> 与 <strong>RJ45接口</strong> 以及 <strong>网络变压器</strong> 的接口标准：</p><p><img src="/Electronics/Ethernet/MDI.png"></p><blockquote><p><strong>注意</strong>：<strong>交叉介质依赖接口</strong>（MDIX，MediumDependent Interface Crossover）是 MDI 接口的线序交叉版本。</p></blockquote><h2 id="以太网线缆种类-catx">以太网线缆种类 CATx</h2><p>基于<code>速度</code>、<code>带宽</code>、<code>屏蔽</code>、<code>最大传输距离</code>等指标，以太网的传输线缆被划分为了不同的<strong>种类</strong>（CAT，Category）：</p><table><thead><tr><th style="text-align: left;">线缆类别</th><th style="text-align: left;">TEST</th><th style="text-align: left;">传输速率</th><th style="text-align: left;">最大带宽</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>CAT 3</strong></td><td style="text-align: left;">Category 3</td><td style="text-align: left;"><code>10 Mbit/s</code></td><td style="text-align: left;"><code>16 MHz</code></td></tr><tr><td style="text-align: left;"><strong>CAT 5</strong></td><td style="text-align: left;">Category 5</td><td style="text-align: left;"><code>100 Mbit/s</code></td><td style="text-align: left;"><code>100 MHz</code></td></tr><tr><td style="text-align: left;"><strong>CAT 5e</strong></td><td style="text-align: left;">Category 5E</td><td style="text-align: left;"><code>1000 Mbit/s</code></td><td style="text-align: left;"><code>100 MHz</code></td></tr><tr><td style="text-align: left;"><strong>CAT 6</strong></td><td style="text-align: left;">Category 6</td><td style="text-align: left;"><code>1000 Mbit/s</code></td><td style="text-align: left;"><code>250 MHz</code></td></tr><tr><td style="text-align: left;"><strong>CAT 6a</strong></td><td style="text-align: left;">Category 6A</td><td style="text-align: left;"><code>10 Gbit/s</code></td><td style="text-align: left;"><code>500 MHz</code></td></tr><tr><td style="text-align: left;"><strong>CAT 7</strong></td><td style="text-align: left;">Category 7</td><td style="text-align: left;"><code>10 Gbit/s</code></td><td style="text-align: left;"><code>600 MHz</code></td></tr><tr><td style="text-align: left;"><strong>CAT 7a</strong></td><td style="text-align: left;">Category 7A</td><td style="text-align: left;"><code>10 Gbit/s</code></td><td style="text-align: left;"><code>1000 MHz</code></td></tr><tr><td style="text-align: left;"><strong>CAT 8</strong></td><td style="text-align: left;">Category 8</td><td style="text-align: left;"><code>40 Gbit/s</code></td><td style="text-align: left;"><code>2000 MHz</code></td></tr></tbody></table><h2 id="以太网供电标准-poe">以太网供电标准 PoE</h2><p>除了转发信号之外，未使用的以太网双绞线对还可以被用于供电，这种技术被称为<strong>以太网供电</strong>（PoE，Powerover Ethernet），相关的规范被定义在 <strong>IEEE</strong> 的<code>802.3af</code> 及其迭代版本当中：</p><table><thead><tr><th style="text-align: left;">供电技术</th><th style="text-align: left;">对应标准</th><th style="text-align: left;">最大功率</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>PoE</strong></td><td style="text-align: left;"><code>IEEE 802.3af</code></td><td style="text-align: left;"><code>15.4 W</code></td></tr><tr><td style="text-align: left;"><strong>PoE+</strong></td><td style="text-align: left;"><code>IEEE 802.3at</code>（类型 2）</td><td style="text-align: left;"><code>30 W</code></td></tr><tr><td style="text-align: left;"><strong>PoE++</strong></td><td style="text-align: left;"><code>IEEE 802.3bt</code>（类型 3）</td><td style="text-align: left;"><code>60 W</code></td></tr><tr><td style="text-align: left;"><strong>PoE++</strong></td><td style="text-align: left;"><code>IEEE 802.3bt</code>（类型 4）</td><td style="text-align: left;"><code>100 W</code></td></tr></tbody></table><h2 id="ieee-物理层线缆标准">IEEE 物理层线缆标准</h2><p>以太网的传输介质主要有<strong>同轴线缆</strong>、<strong>双绞线</strong>、<strong>光纤</strong>等，<strong>电气电子工程师学会</strong>（IEEE，Instituteof Electrical and ElectronicsEngineers）为以太网物理传输线缆制定了一系列标准，下面的表格汇总了各种传输速率的以太网所对应的<strong>IEEE</strong> 线缆标准：</p><table><colgroup><col style="width: 24%"><col style="width: 25%"><col style="width: 26%"><col style="width: 24%"></colgroup><thead><tr><th style="text-align: left;">10 Mbit/s 线缆标准</th><th style="text-align: left;">100 Mbit/s 线缆标准</th><th style="text-align: left;">1000 Mbit/s 线缆标准</th><th style="text-align: left;">10 Gbit/s 线缆标准</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>10BASE-2</strong></td><td style="text-align: left;"><strong>100BASE-T4</strong></td><td style="text-align: left;"><strong>1000BASE-SX</strong></td><td style="text-align: left;"><strong>10GBASE-T</strong></td></tr><tr><td style="text-align: left;"><strong>10BASE-5</strong></td><td style="text-align: left;"><strong>100BASE-TX</strong></td><td style="text-align: left;"><strong>1000BASE-LX</strong></td><td style="text-align: left;"><strong>10GBASE-LR</strong></td></tr><tr><td style="text-align: left;"><strong>10BASE-T</strong></td><td style="text-align: left;"><strong>100BASE-FX</strong></td><td style="text-align: left;"><strong>1000BASE-TX</strong></td><td style="text-align: left;"><strong>10GBASE-SR</strong></td></tr><tr><td style="text-align: left;"><strong>10BASE-F</strong></td><td style="text-align: left;">-</td><td style="text-align: left;">-</td><td style="text-align: left;">-</td></tr></tbody></table><p>2019 年 <strong>IEEE</strong> 还推出有 <code>10 Mbit/s</code>速率的<strong>车载以太网</strong>物理接口标准<strong>10BASE-T1S</strong>（基于 <code>802.3cg</code>标准），其能够支持至少 8 个节点和 25 米长度的总线拓扑：</p><p><img src="/Electronics/Ethernet/10BASE-T1S.png"></p><blockquote><p><strong>注意</strong>：上述表格当中的前缀<code>10</code>、<code>100</code>、<code>1000</code>、<code>10G</code>表示的是数据传输速率，后面的 <code>BASE</code>表示信号传输采用的是<strong>基带方式</strong>，而 <code>-</code>后续的数字和字母则代表了不同的物理传输介质，例如 <code>T</code>表示<strong>同轴电缆</strong>，<code>TX</code>表示<strong>双绞线</strong>，<code>FX</code>表示<strong>光纤</strong>。</p></blockquote><h3 id="十兆以太网线缆标准">十兆以太网线缆标准</h3><p><code>10 Mbit/s</code> 以太网线缆标准被定义在 <strong>IEEE802.3</strong> 规范当中，其线缆标准如下面表格所示：</p><table><thead><tr><th style="text-align: left;">线缆标准</th><th style="text-align: left;">线缆类型</th><th style="text-align: left;">有效距离</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>10BASE-5</strong></td><td style="text-align: left;">同轴电缆（粗）</td><td style="text-align: left;">500 米</td></tr><tr><td style="text-align: left;"><strong>10BASE-2</strong></td><td style="text-align: left;">同轴电缆（细）</td><td style="text-align: left;">200 米</td></tr><tr><td style="text-align: left;"><strong>10BASE-T</strong></td><td style="text-align: left;">双绞线</td><td style="text-align: left;">100 米</td></tr><tr><td style="text-align: left;"><strong>10BASE-F</strong></td><td style="text-align: left;">光纤</td><td style="text-align: left;">2000 米</td></tr></tbody></table><blockquote><p><strong>注意</strong>：通常情况下，同轴电缆上的设备都是串连在一起的，单点故障就会导致整个网络的崩溃，所以同轴电缆标准<strong>10BASE-2</strong>、<strong>10BASE-5</strong>已经基本被淘汰。</p></blockquote><h3 id="百兆以太网线缆标准">百兆以太网线缆标准</h3><p><code>100 Mbit/s</code> 以太网在<strong>数据链路层</strong>方面与<code>10 Mbit/s</code>以太网没有区别，仅仅是在<strong>物理层</strong>方面提高了传输速率，百兆以太网的线缆标准如下面表格所示：</p><table><thead><tr><th style="text-align: left;">线缆标准</th><th style="text-align: left;">线缆类型</th><th style="text-align: left;">有效距离</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>100Base-T4</strong></td><td style="text-align: left;">四对 3 类双绞线</td><td style="text-align: left;">100 米</td></tr><tr><td style="text-align: left;"><strong>100Base-TXs</strong></td><td style="text-align: left;">两对 5 类双绞线</td><td style="text-align: left;">100 米</td></tr><tr><td style="text-align: left;"><strong>100Base-FX</strong></td><td style="text-align: left;">单模/多模光纤</td><td style="text-align: left;">2000 米</td></tr></tbody></table><blockquote><p><strong>注意</strong>：<strong>10BASE-T</strong> 和<strong>100BASE-TX</strong> 都工作在 5类双绞线上面，两者的不同点在于信号的传输速率，前者只有<code>10 Mbit/s</code> 的传输速率，后者则具备 <code>100 Mbit/s</code>的传输速率。除此之外，<strong>100BASE-T4</strong> 现在很少被使用。</p></blockquote><h3 id="千兆以太网线缆标准">千兆以太网线缆标准</h3><p><code>100 Mbit/s</code> 以太网对 <strong>IEEE 802.3</strong>标准进行扩展，其中 <code>IEEE 802.3z</code>标准用于<strong>光纤传输</strong>，而 <code>802.3ab</code>标准用于<strong>双绞线传输</strong>。传输速率从 <code>100 Mbit/s</code>提高了近十倍（达到<code>1 Gbit/s</code>），千兆以太网的线缆标准如下面表格所示：</p><table><thead><tr><th style="text-align: left;">线缆标准</th><th style="text-align: left;">线缆类型</th><th style="text-align: left;">有效距离</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>1000Base-LX</strong></td><td style="text-align: left;">单模/多模光纤</td><td style="text-align: left;">316 米</td></tr><tr><td style="text-align: left;"><strong>1000Base-SX</strong></td><td style="text-align: left;">多模光纤</td><td style="text-align: left;">316 米</td></tr><tr><td style="text-align: left;"><strong>1000Base-TX</strong></td><td style="text-align: left;">超 5 类、6 类双绞线</td><td style="text-align: left;">100 米</td></tr></tbody></table><blockquote><p><strong>注意</strong>：在前面的以太网传输技术当中，<strong>数据链路层</strong>将8位的数据提交到<strong>物理层</strong>，<strong>物理层</strong>经过变换处理之后发送到数据链路上进行传输，但是变换的结果依然是8 位。而<strong>千兆以太网</strong>采用了 <strong>8B10B</strong>编码技术，数据链路层将 8位数据提交到<strong>物理层</strong>的时候，<strong>物理层</strong>会将这8 位数据映射为 10 位进行发送。</p></blockquote><h3 id="万兆以太网线缆标准">万兆以太网线缆标准</h3><p><code>10 Gbit/s</code> 以太网基于 <code>IEEE 802.3ae</code>附加标准（后续可能会合并至<code>IEEE 802.3</code>），其线缆标准如下表所示。</p><table><thead><tr><th style="text-align: left;">线缆标准</th><th style="text-align: left;">线缆类型</th><th style="text-align: left;">有效距离</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>10GBASE-T</strong></td><td style="text-align: left;">CAT-6A、CAT-7</td><td style="text-align: left;">1 百米</td></tr><tr><td style="text-align: left;"><strong>10GBase-LR</strong></td><td style="text-align: left;">单模光纤</td><td style="text-align: left;">10 千米</td></tr><tr><td style="text-align: left;"><strong>10GBase-SR</strong></td><td style="text-align: left;">多模光纤</td><td style="text-align: left;">数百米</td></tr></tbody></table><blockquote><p><strong>注意</strong>：传输速率更快的 <code>40/100 Gbit/s</code>以太网标准已经于 <strong>2010</strong> 年制定完成，使用了<code>IEEE 802.3ba</code> 附加标准进行说明。</p></blockquote><h2 id="mac-与-phy-的连接规范">MAC 与 PHY 的连接规范</h2><p>十兆/百兆<strong>媒体独立接口</strong> <code>MII/RMII/SMII</code>和<strong>千兆媒体独立接口</strong><code>GMII/RGMII/SGMII</code>，主要用于连接以太网的<strong>媒体访问控制层</strong>（MAC）芯片和<strong>物理层</strong>（PHY）芯片，依照数据传输方式的不同，可以将它们划分为如下两种类型：</p><ol type="1"><li><strong>并行传输协议</strong>：<code>MII</code>、<code>GMII</code>、<code>RMII</code>、<code>RGMII</code>；</li><li><strong>串行传输协议</strong>：<code>SMII</code>、<code>SGMII</code>；</li></ol><h2 id="媒体独立接口-mii-rmii-smii">媒体独立接口 MII RMII SMII</h2><p>媒体独立接口规范<strong>MII</strong>、<strong>RMII</strong>、<strong>SMII</strong>的传输速率可以达到 <code>10 Mbps</code> 或者<code>100 Mbps</code>，目前主要运用于 <strong>ARM</strong>微控制/微处理器内置 MAC 与 PHY 芯片的连接场景。</p><blockquote><p><strong>注意</strong>：接下来内容当中的<strong>数据位宽</strong>，是指一个时钟周期内传输的数据位数。</p></blockquote><h3 id="mii">MII</h3><p><strong>媒体独立接口</strong>（MII，Media IndependentInterface）可以实现 <code>10/100 Mbps</code> 速率的以太网传输（时钟频率<code>2.5/25 MHz</code>，数据位宽 <code>4 bit</code>）：</p><table><colgroup><col style="width: 18%"><col style="width: 11%"><col style="width: 69%"></colgroup><thead><tr><th style="text-align: left;">发送侧 MAC-PHY 引脚</th><th style="text-align: left;">引脚名称</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>TX_CLK</strong></td><td style="text-align: left;">发送时钟</td><td style="text-align: left;">由 MAC 提供，用于同步发送控制信号。</td></tr><tr><td style="text-align: left;"><strong>TX_EN</strong></td><td style="text-align: left;">发送使能</td><td style="text-align: left;">高电平时表示 MAC 正在发送数据。</td></tr><tr><td style="text-align: left;"><strong>TXD [3:0]</strong></td><td style="text-align: left;">发送数据</td><td style="text-align: left;">4 位宽度的数据总线，用于从 MAC 向 PHY传输需要发出的数据。</td></tr><tr><td style="text-align: left;"><strong>TX_ER</strong></td><td style="text-align: left;">发送错误</td><td style="text-align: left;">当 MAC检测到发送错误就会使能该信号（前级的 PHY 通常会丢弃该错误帧）。</td></tr><tr><td style="text-align: left;"><strong>TX_DV</strong></td><td style="text-align: left;">发送数据有效</td><td style="text-align: left;">功能与 <code>TX_EN</code>基本相同（通常会将其与 <code>TX_EN</code> 短接）。</td></tr></tbody></table><table><colgroup><col style="width: 15%"><col style="width: 10%"><col style="width: 74%"></colgroup><thead><tr><th style="text-align: left;">接收侧 PHY-MAC 引脚</th><th style="text-align: left;">引脚名称</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>RX_CLK</strong></td><td style="text-align: left;">接收时钟</td><td style="text-align: left;">由 PHY 提供，用于同步接收控制信号。</td></tr><tr><td style="text-align: left;"><strong>RX_DV</strong></td><td style="text-align: left;">接收数据有效</td><td style="text-align: left;">高电平表示 PHY 正在接收数据。</td></tr><tr><td style="text-align: left;"><strong>RXD [3:0]</strong></td><td style="text-align: left;">接收数据</td><td style="text-align: left;">4 位宽度的数据总线，用于从 PHY 向 MAC传输当前接收的数据。</td></tr><tr><td style="text-align: left;"><strong>RX_ER</strong></td><td style="text-align: left;">接收错误</td><td style="text-align: left;">当 PHY检测到接收错误就会使能该信号（后级的 MAC 可以根据 <code>RX_ER</code>决定是否丢弃该错误帧）。</td></tr><tr><td style="text-align: left;"><strong>CRS</strong></td><td style="text-align: left;">载波侦听</td><td style="text-align: left;">当 PHY检测到介质上存在载波信号的时候使能。</td></tr><tr><td style="text-align: left;"><strong>COL</strong></td><td style="text-align: left;">冲突检测</td><td style="text-align: left;">当 PHY检测到冲突的时候使能（主要用于半双工模式，全双工模式通常不使用）。</td></tr></tbody></table><table><colgroup><col style="width: 13%"><col style="width: 22%"><col style="width: 64%"></colgroup><thead><tr><th style="text-align: left;">管理侧引脚</th><th style="text-align: left;">引脚名称</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>MDC</strong></td><td style="text-align: left;">管理数据时钟</td><td style="text-align: left;">由 MAC 提供，用于同步 <code>MDIO</code>数据的传输。</td></tr><tr><td style="text-align: left;"><strong>MDIO</strong></td><td style="text-align: left;">管理数据输入/输出</td><td style="text-align: left;">双向数据线，用于 MAC 和 PHY之间管理数据的交换。</td></tr></tbody></table><h3 id="rmii">RMII</h3><p><strong>简化媒体独立接口</strong>（RMII，Reduced Media IndependentInterface）是一种精简了引脚的 <code>10/100 Mbps</code>接口，通过提升时钟频率保持与 MII 相同的传输速率（时钟频率<code>50 MHz</code>，数据位宽 <code>2 bit</code>）：</p><table><colgroup><col style="width: 10%"><col style="width: 14%"><col style="width: 74%"></colgroup><thead><tr><th style="text-align: left;">MAC-PHY 共用引脚</th><th style="text-align: left;">引脚名称</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>REF_CLK</strong></td><td style="text-align: left;">参考时钟</td><td style="text-align: left;">RMII 的 <code>50 MHz</code>参考时钟同时被用于接收和发送，可以由 MAC 或者 PHY来提供，另外一个设备必须将其作为输入时钟。</td></tr><tr><td style="text-align: left;"><strong>RXD [1:0]</strong></td><td style="text-align: left;">接收数据</td><td style="text-align: left;">用于从 PHY 向 MAC传输当前接收到的数据（相比于 MII 拥有 4 根数据线，RMII 只有 2根数据线）。</td></tr><tr><td style="text-align: left;"><strong>TXD [1:0]</strong></td><td style="text-align: left;">发送数据</td><td style="text-align: left;">用于从 MAC 向 PHY传输当前需要发送的数据。</td></tr><tr><td style="text-align: left;"><strong>TX_EN</strong></td><td style="text-align: left;">发送使能</td><td style="text-align: left;">高电平时表示 MAC 正在发送数据。</td></tr><tr><td style="text-align: left;"><strong>CRS_DV</strong></td><td style="text-align: left;">载波侦听/接收数据有效</td><td style="text-align: left;"><strong>半双工模式</strong>下作为载波侦听，<strong>全双工模式</strong>下作为接收数据有效。</td></tr><tr><td style="text-align: left;"><strong>RX_ER</strong></td><td style="text-align: left;">接收错误</td><td style="text-align: left;">当 PHY 检测到错误时使能（后级的 MAC可以根据 <code>RX_ER</code> 决定是否丢弃该错误帧）。</td></tr></tbody></table><blockquote><p><strong>注意</strong>：<strong>半双工</strong>是指同一时刻只能接收<strong>或</strong>发送数据，而<strong>全双工</strong>则是指可以同时接收<strong>和</strong>发送数据。</p></blockquote><table><colgroup><col style="width: 13%"><col style="width: 22%"><col style="width: 64%"></colgroup><thead><tr><th style="text-align: left;">管理侧引脚</th><th style="text-align: left;">引脚名称</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>MDC</strong></td><td style="text-align: left;">管理数据时钟</td><td style="text-align: left;">由 MAC 提供，用于同步 <code>MDIO</code>数据的传输。</td></tr><tr><td style="text-align: left;"><strong>MDIO</strong></td><td style="text-align: left;">管理数据输入/输出</td><td style="text-align: left;">双向数据线，用于 MAC 和 PHY之间管理数据的交换。</td></tr></tbody></table><h3 id="smii">SMII</h3><p><strong>串行媒体独立接口</strong>（SMII，Serial Media IndependentInterface）是一种串行化的 <code>10M/100 Mbps</code>接口，通过进一步提升时钟频率，以保持与 MII 相同的传输速率（时钟频率<code>125 MHz</code>，数据位宽 <code>1 bit</code>）：</p><table><colgroup><col style="width: 24%"><col style="width: 10%"><col style="width: 64%"></colgroup><thead><tr><th style="text-align: left;">发送侧 MAC-PHY 引脚</th><th style="text-align: left;">引脚名称</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>TX_CLK</strong></td><td style="text-align: left;">发送时钟</td><td style="text-align: left;">由 MAC 提供，用于同步发送控制信号。</td></tr><tr><td style="text-align: left;"><strong>TX_EN</strong></td><td style="text-align: left;">发送使能</td><td style="text-align: left;">高电平时表示 MAC 正在发送数据。</td></tr><tr><td style="text-align: left;"><strong>TXD</strong></td><td style="text-align: left;">发送数据</td><td style="text-align: left;">串行数据发送信号，用于从 MAC 向 PHY传输发送信号。</td></tr></tbody></table><table><colgroup><col style="width: 21%"><col style="width: 13%"><col style="width: 65%"></colgroup><thead><tr><th style="text-align: left;">接收侧 PHY-MAC 引脚</th><th style="text-align: left;">引脚名称</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>RX_CLK</strong></td><td style="text-align: left;">接收时钟</td><td style="text-align: left;">由 PHY 提供，用于同步接收控制信号。</td></tr><tr><td style="text-align: left;"><strong>RX_DV</strong></td><td style="text-align: left;">接收数据有效</td><td style="text-align: left;">高电平时表示 PHY 正在接收数据。</td></tr><tr><td style="text-align: left;"><strong>RXD</strong></td><td style="text-align: left;">接收数据</td><td style="text-align: left;">串行数据接收信号，用于从 PHY 向 MAC传输当前接收到的数据。</td></tr><tr><td style="text-align: left;"><strong>RX_ER</strong></td><td style="text-align: left;">接收错误</td><td style="text-align: left;">当 PHY 检测到接收错误时使能。</td></tr></tbody></table><table><colgroup><col style="width: 13%"><col style="width: 22%"><col style="width: 64%"></colgroup><thead><tr><th style="text-align: left;">管理侧引脚</th><th style="text-align: left;">引脚名称</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>MDC</strong></td><td style="text-align: left;">管理数据时钟</td><td style="text-align: left;">由 MAC 提供，用于同步 <code>MDIO</code>数据的传输。</td></tr><tr><td style="text-align: left;"><strong>MDIO</strong></td><td style="text-align: left;">管理数据输入/输出</td><td style="text-align: left;">双向数据线，用于 MAC 和 PHY之间管理数据的交换。</td></tr></tbody></table><h2 id="千兆媒体独立接口-gmii-rgmii-sgmii">千兆媒体独立接口 GMII RGMIISGMII</h2><p>千兆媒体独立接口规范<strong>GMII</strong>、<strong>RGMII</strong>、<strong>SGMII</strong>的传输速率可以高达 <code>1000 Mbps</code>，目前主要应用于<strong>FPGA</strong> 芯片内置 MAC 与 PHY 芯片的连接场景。</p><h3 id="gmii">GMII</h3><p><strong>千兆媒体独立接口</strong>（GMII，Gigabit Media IndependentInterface）可以实现 <code>1000 Mbps</code> 速率的以太网传输，其在 MII接口的基础之上，大幅度提升了数据位宽和时钟频率（时钟频率<code>125 MHz</code>，数据位宽 <code>8 bit</code>）：</p><table><colgroup><col style="width: 18%"><col style="width: 11%"><col style="width: 69%"></colgroup><thead><tr><th style="text-align: left;">发送侧 MAC-PHY 引脚</th><th style="text-align: left;">引脚名称</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>TX_CLK</strong></td><td style="text-align: left;">发送时钟</td><td style="text-align: left;">由 MAC 提供，用于同步发送控制信号。</td></tr><tr><td style="text-align: left;"><strong>TX_EN</strong></td><td style="text-align: left;">发送使能</td><td style="text-align: left;">高电平时表示 MAC 正在发送数据。</td></tr><tr><td style="text-align: left;"><strong>TXD [7:0]</strong></td><td style="text-align: left;">发送数据</td><td style="text-align: left;">8 位数据总线，用于从 MAC 向 PHY传输当前需要发送的数据。</td></tr><tr><td style="text-align: left;"><strong>TX_ER</strong></td><td style="text-align: left;">发送错误</td><td style="text-align: left;">当 MAC检测到发送错误就会使能该信号（前级的 PHY 通常会丢弃该错误帧）。</td></tr><tr><td style="text-align: left;"><strong>TX_DV</strong></td><td style="text-align: left;">发送数据有效</td><td style="text-align: left;">功能与 <code>TX_EN</code>基本相同（通常会将其与 <code>TX_EN</code> 短接）。</td></tr></tbody></table><table><colgroup><col style="width: 16%"><col style="width: 10%"><col style="width: 72%"></colgroup><thead><tr><th style="text-align: left;">接收侧 PHY-MAC 引脚</th><th style="text-align: left;">引脚名称</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>RX_CLK</strong></td><td style="text-align: left;">接收时钟</td><td style="text-align: left;">由 PHY 提供，用于同步接收控制信号。</td></tr><tr><td style="text-align: left;"><strong>RX_DV</strong></td><td style="text-align: left;">接收数据有效</td><td style="text-align: left;">高电平时表示 PHY 正在接收数据。</td></tr><tr><td style="text-align: left;"><strong>RXD [7:0]</strong></td><td style="text-align: left;">接收数据</td><td style="text-align: left;">8 位数据总线，用于从 PHY 向 MAC传输当前接收到的数据。</td></tr><tr><td style="text-align: left;"><strong>RX_ER</strong></td><td style="text-align: left;">接收错误</td><td style="text-align: left;">当 PHY 检测到接收错误时使能（后级的 MAC可以根据 <code>RX_ER</code> 决定是否丢弃该错误帧）。</td></tr><tr><td style="text-align: left;"><strong>CRS</strong></td><td style="text-align: left;">载波侦听</td><td style="text-align: left;">当 PHY 检测到介质上有载波信号时使能。</td></tr><tr><td style="text-align: left;"><strong>COL</strong></td><td style="text-align: left;">冲突检测</td><td style="text-align: left;">当 PHY检测到冲突时使能（主要用于半双工模式，全双工模式通常不使用）。</td></tr></tbody></table><h3 id="rgmii">RGMII</h3><p><strong>简化千兆媒体独立接口</strong>（RGMII，Reduced Gigabit MediaIndependent Interface），通过在一个时钟周期的上升沿读取<strong>TX/RX</strong> 数据的 <code>0 ~ 3</code> 位，下降沿读取<code>4 ~ 7</code> 位，实现在一个时钟周期读取 8 位数据（时钟频率<code>125 MHz</code> 数据位宽 <code>4 bit</code>）：</p><table><colgroup><col style="width: 12%"><col style="width: 9%"><col style="width: 77%"></colgroup><thead><tr><th style="text-align: left;">MAC-PHY 共用引脚</th><th style="text-align: left;">引脚名称</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>CLK</strong></td><td style="text-align: left;">双向时钟</td><td style="text-align: left;">通常由 PHY提供，会同时被应用于接收和发送，<strong>RGMII</strong> 需要精确的<code>2.5ns</code>（1/4 个时钟周期）时序对齐</td></tr><tr><td style="text-align: left;"><strong>TXD [3:0]</strong></td><td style="text-align: left;">发送数据</td><td style="text-align: left;">4 位数据总线，用于从 MAC 向 PHY传输需要发送的数据。</td></tr><tr><td style="text-align: left;"><strong>RXD [3:0]</strong></td><td style="text-align: left;">接收数据</td><td style="text-align: left;">4 位数据总线，用于从 PHY 向 MAC传输当前接收到的数据。</td></tr><tr><td style="text-align: left;"><strong>TX_EN</strong></td><td style="text-align: left;">发送使能</td><td style="text-align: left;">高电平时表示 MAC正在发送数据（<code>10/100 Mbps</code> 模式下也可被用于 <code>COL</code>冲突检测）。</td></tr><tr><td style="text-align: left;"><strong>RX_DV</strong></td><td style="text-align: left;">接收数据有效</td><td style="text-align: left;">高电平时表示 PHY正在接收数据（<code>10/100 Mbps</code> 模式下也可被用于 <code>CRS</code>载波侦听）</td></tr></tbody></table><blockquote><p><strong>注意</strong>：<strong>RGMII</strong> 简化了<code>TX_ER</code> 和 <code>RX_ER</code>两个用于错误信号处理的引脚，取而代之的是在时钟信号的上升沿传递<code>TX_EN / RX_DV</code> 信号，而在下降沿传递<code>TX_ER / RX_ER</code> 信号。</p></blockquote><table><colgroup><col style="width: 13%"><col style="width: 22%"><col style="width: 64%"></colgroup><thead><tr><th style="text-align: left;">管理侧引脚</th><th style="text-align: left;">引脚名称</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>MDC</strong></td><td style="text-align: left;">管理数据时钟</td><td style="text-align: left;">由 MAC 提供，用于同步 <code>MDIO</code>数据的传输。</td></tr><tr><td style="text-align: left;"><strong>MDIO</strong></td><td style="text-align: left;">管理数据输入/输出</td><td style="text-align: left;">双向数据线，用于 MAC 和 PHY之间管理数据的交换。</td></tr></tbody></table><h3 id="sgmii">SGMII</h3><p><strong>串行千兆媒体独立接口</strong>（SGMII，Serial Gigabit MediaIndependent Interface）是一种串行传输的 GMII 接口（时钟频率<code>1250 MHz</code>，数据位宽 <code>1 bit</code>）：</p><table><colgroup><col style="width: 13%"><col style="width: 6%"><col style="width: 79%"></colgroup><thead><tr><th style="text-align: left;">MAC-PHY 共用引脚</th><th style="text-align: left;">引脚名称</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>TX+</strong></td><td style="text-align: left;">发送正极</td><td style="text-align: left;">差分<strong>发送</strong>信号的<code>+</code> <strong>正极</strong>。</td></tr><tr><td style="text-align: left;"><strong>TX-</strong></td><td style="text-align: left;">发送负极</td><td style="text-align: left;">差分<strong>发送</strong>信号的<code>-</code> <strong>负极</strong>。</td></tr><tr><td style="text-align: left;"><strong>RX+</strong></td><td style="text-align: left;">接收正极</td><td style="text-align: left;">差分<strong>接收</strong>信号的<code>+</code> <strong>正极</strong>。</td></tr><tr><td style="text-align: left;"><strong>RX-</strong></td><td style="text-align: left;">接收负极</td><td style="text-align: left;">差分<strong>接收</strong>信号的<code>-</code> <strong>负极</strong>。</td></tr><tr><td style="text-align: left;"><strong>REFCLK</strong></td><td style="text-align: left;">参考时钟</td><td style="text-align: left;">通常情况下，SGMII的时钟信号内嵌在串行数据流当中，但是某些 SGMII实现也会需要单独的参考时钟。</td></tr></tbody></table><table><colgroup><col style="width: 13%"><col style="width: 22%"><col style="width: 64%"></colgroup><thead><tr><th style="text-align: left;">管理侧引脚</th><th style="text-align: left;">引脚名称</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>MDC</strong></td><td style="text-align: left;">管理数据时钟</td><td style="text-align: left;">由 MAC 提供，用于同步 <code>MDIO</code>数据的传输。</td></tr><tr><td style="text-align: left;"><strong>MDIO</strong></td><td style="text-align: left;">管理数据输入/输出</td><td style="text-align: left;">双向数据线，用于 MAC 和 PHY之间管理数据的交换。</td></tr></tbody></table><blockquote><p><strong>注意</strong>：SGMII 具备 <code>1.25GHz</code>的串行数据速率，但是由于使用了 <code>8b/10b</code> 编码（将 8 位转换为10 位数据），增加了额外的性能开销，因而实际的数据吞吐量为<code>1Gbps</code>。</p></blockquote>]]></content>
    
    
    <summary type="html">&lt;p&gt;早在 &lt;strong&gt;1972&lt;/strong&gt; 年，就职于&lt;a href=&quot;https://www.xerox.com/en-us&quot;&gt;美国施乐 &lt;strong&gt;Xerox&lt;/strong&gt;
公司&lt;/a&gt;的 &lt;strong&gt;Robert
Metcalfe&lt;/strong&gt;（被称作以太网之父）与另外两位学者，协作发表了一篇名为《&lt;strong&gt;以太网：区域计算机网络的分布式包交换技术&lt;/strong&gt;》的文章，并在不久之后获得了《具有冲突检测的多点数据通信系统》专利，&lt;strong&gt;以太网&lt;/strong&gt;（Ethernet）技术的雏形就此诞生。至此以太网相关的标准不断演进，诞生了&lt;strong&gt;标准以太网&lt;/strong&gt;(&lt;code&gt;10 Mbit/s&lt;/code&gt;)、&lt;strong&gt;快速以太网&lt;/strong&gt;(&lt;code&gt;100 Mbit/s&lt;/code&gt;)、&lt;strong&gt;千兆以太网&lt;/strong&gt;(&lt;code&gt;1000 Mbit/s&lt;/code&gt;)、&lt;strong&gt;万兆以太网&lt;/strong&gt;(&lt;code&gt;10000 Mbit/s&lt;/code&gt;)等一系列标准。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/Electronics/Ethernet/logo.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;以太网&lt;/strong&gt;的底层工作机制基于&lt;strong&gt;载波侦听多路访问/碰撞检测&lt;/strong&gt;（&lt;strong&gt;CSMA/CD&lt;/strong&gt;，Carrier
Sense Multiple Access with Collision
Detection）协议，从而确保多个设备在相同的物理介质上通信。当其中一个设备有数据需要发送时，会先监听线路上是否存在其它信号，线路空闲就开始传输数据，线路繁忙则等待直至线路可用为止。如果在传输过程当中发生了碰撞（即两个设备同时发送数据导致信号叠加），设备就会检测到这种情况并且发送阻塞信号，然后等待随机时间之后再进行重试。&lt;/p&gt;</summary>
    
    
    
    <category term="硬件电子技术" scheme="http://www.uinio.com/categories/%E7%A1%AC%E4%BB%B6%E7%94%B5%E5%AD%90%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="通信总线" scheme="http://www.uinio.com/tags/%E9%80%9A%E4%BF%A1%E6%80%BB%E7%BA%BF/"/>
    
  </entry>
  
  <entry>
    <title>控制器区域网络 CAN 总线协议图解</title>
    <link href="http://www.uinio.com/Electronics/CAN/"/>
    <id>http://www.uinio.com/Electronics/CAN/</id>
    <published>2025-04-30T16:00:00.000Z</published>
    <updated>2025-11-23T17:10:17.527Z</updated>
    
    <content type="html"><![CDATA[<p><strong>控制器区域网络</strong>（CAN，Controller AreaNetwork）总线协议规范正式发布于 1986年，由德国博世公司为解决汽车电子系统当中，复杂的线束问题而设计。1991年发布的 <strong>CAN 2.0 A/B</strong>规范的推出标志着其开启了标准化的进程。1993 年推出的 <strong>ISO11898</strong>标准进一步巩固了其国际规范地位。伴随汽车电子和工业控制增涨的通信需求，2012年发布的 <strong>CAN FD</strong> 进一步提升了带宽与数据长度。而 2020年发布的 <strong>CAN XL</strong>则能够支持更大数据量的传输，从而适应未来的智能化场景。</p><p><img src="/Electronics/CAN/logo.png"></p><p>CAN 总线协议发展至今日，已经以其<code>低成本</code>、<code>高实时性</code>、<code>高可靠性</code>、<code>优秀的抗干扰能力</code>，成为当下使用极为广泛的标准化串行通信协议，被大面积运用于<code>工业控制</code>、<code>汽车电子</code>、<code>航空航天</code>等对于可靠性要求较高的领域。众所周知，<strong>理工类技术的最佳学习方式，往往需要基于最为直观的理解，而大量的示意图和表格正是化繁为简的利器</strong>。本文就将通过一系列丰富的图片与表格，来展示CAN总线协议的各个技术细节，以便让大家能够快速的理解这款倍受工程师欢迎的总线通信协议。</p><span id="more"></span><h2 id="can-总线发展历程">CAN 总线发展历程</h2><p><strong>控制器区域网络</strong>（CAN，Controller AreaNetwork）是一款广泛应用于汽车和工业领域的现场总线协议，由<a href="https://www.bosch.com.cn/"><strong>德国博世 BOSCH公司</strong></a>于 <strong>1983</strong>年推出，用于解决汽车电子系统中复杂的线束连接问题，以实现各个<strong>电子控制单元</strong>（ECU，ElectronicControl Unit）之间的可靠通信：</p><p><img src="/Electronics/CAN/History/1.png"></p><p>接下来的表格里，展示了 CAN 总线规范自发布以来，从 <strong>CAN1.0</strong>、<strong>CAN 2.0</strong>、<strong>CAN FD</strong> 到<strong>CAN XL</strong> 的技术演进路线：</p><table><colgroup><col style="width: 14%"><col style="width: 19%"><col style="width: 25%"><col style="width: 20%"><col style="width: 20%"></colgroup><thead><tr><th style="text-align: left;"><strong>特性</strong></th><th><strong>CAN 1.0</strong></th><th><strong>CAN 2.0</strong></th><th><strong>CAN FD</strong></th><th><strong>CAN XL</strong></th></tr></thead><tbody><tr><td style="text-align: left;"><strong>标准</strong></td><td>博世公司首先发布</td><td>ISO 11898-1:<strong>1993/2003</strong></td><td>ISO 11898-1:<strong>2015</strong></td><td>ISO 11898-1:<strong>2024</strong></td></tr><tr><td style="text-align: left;"><strong>数据长度</strong></td><td>8 字节</td><td>8 字节</td><td>64 字节</td><td>2048 字节</td></tr><tr><td style="text-align: left;"><strong>通信速率</strong></td><td><code>1 Mbit/s</code></td><td><code>1 Mbit/s</code></td><td><code>2/5/8 Mbit/s</code></td><td><code>20 Mbit/s</code></td></tr><tr><td style="text-align: left;"><strong>标识符长度</strong></td><td><code>11 位</code><strong>标准格式</strong></td><td><code>11/29 位</code><strong>扩展格式</strong></td><td>同 CAN 2.0</td><td>同 CAN 2.0</td></tr><tr><td style="text-align: left;"><strong>CRC 校验位</strong></td><td>15 位</td><td>15 位</td><td>17/21 位</td><td>32 位</td></tr></tbody></table><ul><li><strong>CAN 灵活数据速率总线</strong>（<strong>CANFD</strong>，Controller Area Network Flexible Data Rate）；</li><li><strong>CAN 扩展数据域长度总线</strong>（<strong>CANXL</strong>，Controller Area Network Extended Data-field Length）；</li></ul><blockquote><p><strong>注意</strong>：<strong>ISO 11898-1</strong> 国际标准定义了CAN 规范的核心部分，即<strong>数据链路层</strong>（Data LinkLayer）和<strong>物理层</strong>（Physical Layer）的相关标准。</p></blockquote><h2 id="iso-11898-标准化规范">ISO 11898 标准化规范</h2><p><strong>ISO 11898</strong> 是 <strong>ISO 国际标准化组织</strong>针对 CAN总线制定的一系列国际标准，该系列标准被划分为多个部分（通过最后的数字进行区分），分别对应于不同速率的CAN 总线类型：</p><table><thead><tr><th style="text-align: left;">协议部分</th><th style="text-align: left;">协议名称</th><th style="text-align: left;">英文名称</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>ISO 11898-1</strong></td><td style="text-align: left;">CAN 数据链路层</td><td style="text-align: left;">Data Link Layer</td></tr><tr><td style="text-align: left;"><strong>ISO 11898-2</strong></td><td style="text-align: left;">高速 CAN</td><td style="text-align: left;">High-Speed CAN</td></tr><tr><td style="text-align: left;"><strong>ISO 11898-3</strong></td><td style="text-align: left;">低速容错 CAN</td><td style="text-align: left;">Low-Speed Fault-Tolerant CAN</td></tr><tr><td style="text-align: left;"><strong>ISO 11898-4</strong></td><td style="text-align: left;">时间触发 CAN</td><td style="text-align: left;">Time-Triggered CAN</td></tr><tr><td style="text-align: left;"><strong>ISO 11898-5</strong></td><td style="text-align: left;">灵活数据速率 CAN</td><td style="text-align: left;">Flexible Data Rate</td></tr><tr><td style="text-align: left;"><strong>ISO 11898-6</strong></td><td style="text-align: left;">扩展数据域长度 CAN</td><td style="text-align: left;">Extended Data-field Length</td></tr></tbody></table><p>上面表格当中的 <strong>ISO 11898-1</strong> 主要定义了 CAN 总线的<strong>数据链路层</strong>，也就是<strong>定义了数据在单个链路上如何进行传输</strong>，其主要解决了如下几个方面的问题：</p><ul><li><strong>如何将数据组装为数据块</strong>（该数据块就是<strong>帧</strong>，是数据链路层的基本传送单位）；</li><li><strong>如何控制帧在物理信道上的传输</strong>（包括如何处理传输错误，如何调节发送速率）；</li><li><strong>提供网络节点之间数据链路的管理</strong>（建立、维持、释放）。</li></ul><blockquote><p><strong>注意</strong>：许多书籍和资料上提到的 <strong>ISO11519-2</strong> 已经于 2006 年被 <strong>ISO 11898-3</strong>整合并且取代，成为了新的低速容错 CAN 标准。</p></blockquote><h2 id="can-总线与-osi-模型">CAN 总线与 OSI 模型</h2><p><strong>开放系统互连模型</strong>（OSI，Open System Interconnect）由<strong>ISO 国际标准化组织</strong>于 1985年正式制订使用，主要定义了网络互连的七层架构（<code>物理层</code>、<code>数据链路层</code>、<code>网络层</code>、<code>传输层</code>、<code>会话层</code>、<code>表示层</code>、<code>应用层</code>），通常也被称作<strong>OSI 参考模型</strong>：</p><p><img src="/Electronics/CAN/OSI/1.png"></p><p>CAN 总线规范 <strong>ISO 11898</strong> 与 OSI模型的对应关系如下图所示，其中 <strong>ISO 11898-1</strong> 定义了 CAN协议的<strong>数据链路层</strong>（Data Link），而 <strong>ISO11898-2</strong> 则是定义了高速 CAN总线的<strong>物理层</strong>（Physical）。简而言之，<strong>ISO 11898-1是协议基础，而 ISO 11898-2 是物理层实现</strong>：</p><p><img src="/Electronics/CAN/OSI/2.png"></p><p>除此之外，<strong>数据链路层</strong>还被进一步划分为了<strong>媒介访问控制</strong>（MAC，MediumAccess Control）和<strong>逻辑链路控制</strong>（LLC，Logical LinkControl）两个子层。在下面的表格当中，更加详细的展示了 CAN 总线在 OSI模型各层的定义事项：</p><p><img src="/Electronics/CAN/OSI/3.png"></p><h2 id="can-总线的网络拓扑">CAN 总线的网络拓扑</h2><p>如前所述，CAN 总线被划分为<strong>高速 CAN</strong>（定义于<code>ISO 11898-2</code> 规范），以及<strong>低速容错CAN</strong>（定义于 <code>ISO 11519-2</code> 以及后续的<code>ISO 11898-3</code> 规范）两种类型，这种划分方式会体现在<strong>CAN收发器</strong>芯片的规格书当中，进行参数选型时需要格外关注这个参数（下图是<strong>NXP</strong> 公司的经典 CAN 收发器芯片 <a href="https://www.nxp.com.cn/products/interfaces/can-transceivers/legacy-can/high-speed-can-transceiver:TJA1050">TJA1050</a>的数据手册首页）：</p><p><img src="/Electronics/CAN/Topology/1.png"></p><p><strong>高速 CAN</strong>属于<strong>闭环总线</strong>网络，总线两端各连接一个 <code>120 Ω</code>的电阻，并且通过信号线形成回路，适用于高速、短距离的通信，通信速率通常在<code>125Kbps ~ 1Mbps</code>，其在 <code>1 Mbps</code>通讯速率下，总线通信距离可以达到 <code>40m</code>长度，其基本网络拓扑如下图所示：</p><p><img src="/Electronics/CAN/Topology/2.png"></p><p><strong>低速容错 CAN</strong>属于<strong>开环总线</strong>网络，两条信号线分别串联一个<code>2.2KΩ</code> 电阻，然后独立连接到 CAN 总线的 <code>CAN_High</code>与 <code>CAN_Low</code>上面，并<strong>不会构成环路</strong>，适用于低速、远距离的通信。通信速率最高只能达到<code>125 Kbps</code>，其在 <code>40 Kbps</code>速率时，总线最长通信距离可以高达 <code>1000m</code> 长度：</p><p><img src="/Electronics/CAN/Topology/3.png"></p><p>CAN 总线上的数据采用 <code>CANH</code>（即上图中的<code>CAN_High</code>）和 <code>CANL</code>（即上图中的<code>CAN_Low</code>）两条信号线进行<strong>差分传输</strong>（后续会讨论采用差分信号传输的原因），然后通过两个信号之间的差值，来获取当前CAN 总线网络上传输的有效电平值：</p><p><span class="math display">\[V_{有效电平} = V_{CANH} - V_{CANL}\]</span></p><blockquote><p><strong>注意</strong>：有效电平为<strong>显性</strong>（<strong>D</strong>ominant[ˈdɒmɪnənt]）表示逻辑信号<code>0</code>，有效电平为<strong>隐性</strong>（<strong>R</strong>ecessive[rɪˈsesɪv]）表示逻辑信号 <code>1</code>。</p></blockquote><p>根据 <strong>ISO11898-2</strong> 和 <strong>ISO11898-3</strong>两款国际规范，差分信号线 <code>CANH</code> 与 <code>CANL</code>上面传输的电平值，需要遵循下面表格当中定义的范围：</p><p><img src="/Electronics/CAN/Topology/4.png"></p><p>根据上面表格当中的数据，就可以获得不同 CAN总线网络上面，<strong>隐性电平</strong>与<strong>显性电平</strong>的典型电压差值：</p><ul><li><strong>高速 CAN总线</strong>：<strong>隐性电平</strong>（相当于逻辑<code>1</code>）典型值为 <span class="math inline">\(V_{CANH} - V_{CANL}= 0V\)</span> 表示，<strong>显性电平</strong>（相当于逻辑<code>0</code>）典型值为 <span class="math inline">\(V_{CANH} - V_{CANL}= 2.0V\)</span>。</li><li><strong>低速容错 CAN总线</strong>：<strong>隐性电平</strong>（相当于逻辑<code>1</code>）典型值为 <span class="math inline">\(V_{CANH} - V_{CANL}= -1.5V\)</span>，<strong>显性电平</strong>（相当于逻辑<code>0</code>）典型值为 <span class="math inline">\(V_{CANH} - V_{CANL}= 3.0V\)</span>。</li></ul><blockquote><p><strong>注意</strong>：CAN总线网络当中，<strong>只要一个节点输出显性电平，整个总线就会呈现出显性电平。只有当所有的节点都输出隐性电平的时候，总线才会呈现为隐性电平</strong>。</p></blockquote><h2 id="差分信号传输原理">差分信号传输原理</h2><p>下图所示的高速 CAN 总线网络，采用了阻抗为 <code>120Ω</code>的闭环总线结构，两端分别连接有一枚 <code>120Ω</code>的端接电阻（防止信号在 CAN总线上出现反射），线材方面通常使用的是<strong>双绞线</strong>：</p><p><img src="/Electronics/CAN/Protocol/1.png"></p><blockquote><p><strong>注意</strong>：通常情况下，CAN总线上的设备节点都会连接到公共的地平面，从而具备有相等的接地电位。</p></blockquote><p>CAN 总线之所以采用<strong>差分信号</strong>（DifferentialSignaling）进行传输，原因在于<strong>单端信号</strong>（Single-EndedSignaling）的连接方式容易受到电磁干扰，导致传输线路上出现尖峰电压，致使系统错误的将其判断为高电平<code>1</code>，从而破坏传输信号的完整性。</p><p><img src="/Electronics/CAN/Protocol/2.png"></p><p>例如上面的波形图当中，应当传输的正确信号为<code>00011000</code>，由于受到尖峰电压的干扰，接收端实际读取到的信号变成了<code>01011011</code>。而 CAN 总线采用 <code>CANH</code> 和<code>CANL</code>两个<strong>相位相反，幅值一致</strong>的差分信号来传输数据，并且从信号的电位差当中提取有效的电平数据：</p><p><span class="math display">\[V_{有效电平} = V_{CANH} - V_{CANL}\]</span></p><p>例如对于使用 <code>3.3V</code> 电平信号的 CAN总线，其数据使用<strong>显性</strong>和<strong>隐性</strong>两种状态进行传输（这些状态源自于<code>CANH</code> 和 <code>CANL</code> 两条信号线之间的电位差）：</p><p><img src="/Electronics/CAN/Protocol/3.png"></p><ol type="1"><li><strong>显性状态</strong>（Dominant State）：表示逻辑信号<code>0</code>，此时 <code>CANH</code> 和 <code>CANL</code>之间的电位差约为 <code>3.5V - 1.5V = 2V</code>；</li><li><strong>隐性状态</strong>（Recessive State）：表示逻辑信号<code>1</code>，此时 <code>CANH</code> 和 <code>CANL</code>之间的电位差约为 <code>2.5V - 2.5V = 0V</code>；</li></ol><p>CAN 总线差分信号传输方式的抗干扰能力，主要来源于 <code>CANH</code> 和<code>CANL</code>组成的双绞线，它们同时接收到的尖峰电压噪声幅值基本一致。而噪声幅值保持一致的两个信号，其电位差等效于没有受到噪声的干扰，具体可以参考下面的示意图：</p><p><img src="/Electronics/CAN/Protocol/4.png"></p><h2 id="can-总线节点的构成">CAN 总线节点的构成</h2><p>通常情况下，<strong>MCU微控制器</strong>只能产生<strong>数字信号</strong>，因而需要额外连接一片用于产生<strong>差分信号</strong>的<strong>CAN 收发器</strong>，共同形成一个 CAN 总线节点：</p><p><img src="/Electronics/CAN/Protocol/5.png"></p><p>CAN 总线属于<strong>异步半双工</strong>的通信协议，因而 <strong>CAN收发器</strong>具备有 <code>TXD</code>（数据发送）和<code>RXD</code>（数据接收）两个引脚，用于与 MCU微控制器交换数据，并且将单端的 <code>TXD/RXD</code> 数字信号转换为差分的<code>CANH/CANL</code> 信号：</p><p><img src="/Electronics/CAN/Protocol/6.png"></p><p><strong>CAN 收发器</strong> 芯片的额定工作电压通常为<code>5V</code>，在与工作电压同样为 <code>5V</code> 的 MCU微控制器协同工作的时候，双方都可以通过 <code>5V</code> 的<strong>LDO</strong> 或者 <strong>DC-DC</strong>电源进行供电，并且两者需要形成<strong>共地连接</strong>：</p><p><img src="/Electronics/CAN/Protocol/7.png"></p><p>如果 MCU 微控制器的额定工作电压为 <code>3.3V</code>，那么就必须分别采用两颗 <code>3.3V</code> 和 <code>5V</code>的电源进行供电，并且两者依然需要形成<strong>共地连接</strong>关系：</p><p><img src="/Electronics/CAN/Protocol/8.png"></p><h2 id="带屏蔽的双绞线连接">带屏蔽的双绞线连接</h2><p>为了增强 CAN总线网络的抗干扰能力，各个节点之间通常会采用<strong>屏蔽线</strong>进行连接，屏蔽线的显著特征是导线外层包裹有铝箔制成的<strong>屏蔽层</strong>（通常接地处理），下图直观的展示了<code>单层</code> 和 <code>双层</code> 屏蔽线材的剖面结构：</p><p><img src="/Electronics/CAN/Wire/1.png"></p><p>下面的示意图给出了<code>双芯单层屏蔽线</code>、<code>双芯双层屏蔽线</code>、<code>三芯单层屏蔽线</code>三种类型线缆的接线示意图：</p><p><img src="/Electronics/CAN/Wire/2.png"></p><p>这三张示意图当中的 <code>PE</code>指代的是设备的金属外壳（<strong>设备铁壳</strong>），默认情况下其已经连接到<strong>大地</strong>。而在接下来的两张接线示意图当中，线缆的屏蔽层通过左侧节点的<code>PE</code> 端口进行了<strong>单点接地</strong>（右侧节点的<code>PE</code> 端口被断开）：</p><p><img src="/Electronics/CAN/Wire/3.png"></p><p><img src="/Electronics/CAN/Wire/4.png"></p><p><strong>单点接地</strong>（Single PointGrounding）的核心思想是通过将所有接地路径集中到单一的接地点，从而消除<strong>地电位差</strong>和<strong>环路电流</strong>。</p><blockquote><p><strong>注意</strong>：无论是哪种类型的线缆，都需要根据现场的情况进行合理调整，任何时候都要确保<code>屏蔽线</code> 或者 <code>地线</code>可靠的<strong>单点接地</strong>。</p></blockquote><h2 id="can-控制器收发器">CAN 控制器/收发器</h2><p>上面已经简单介绍过一个<strong>CAN 总线节点</strong>通常是由<strong>CAN 控制器</strong>（CAN Controller）和 <strong>CAN收发器</strong>（CANTransceive）共同构成的，接下来的内容会对两者的功能进行明确的定义，以避免大家在器件选型的时候出现混淆：</p><ul><li><strong>CAN 控制器</strong>：负责 CAN总线<strong>数据链路层</strong>的处理，其核心功能包括<code>报文的封装/解析</code>（帧格式、ID、数据长度等）、<code>错误检测</code>（CRC校验、帧校验等）、<code>总线仲裁</code>（管理多节点的优先级）、<code>位定时控制</code>（时序同步、位填充等）。</li><li><strong>CAN 收发器</strong>：负责在<strong>物理层</strong>将 CAN控制器发出的逻辑电平 <code>TX/RX</code> 转换为差分信号<code>CAN_H/CAN_L</code>，并且通常还具备有<code>避免共模干扰</code>、<code>进行电气隔离</code> 的作用。</li></ul><p>为了便于大家理解，在接下来的表格里，言简意赅的总结了 CAN 控制器和 CAN收发器的区别：</p><table><colgroup><col style="width: 10%"><col style="width: 49%"><col style="width: 39%"></colgroup><thead><tr><th style="text-align: center;">特性</th><th style="text-align: left;">CAN 控制器芯片</th><th style="text-align: left;">CAN 收发器芯片</th></tr></thead><tbody><tr><td style="text-align: center;">核心功能</td><td style="text-align: left;">协议处理</td><td style="text-align: left;">电平转换</td></tr><tr><td style="text-align: center;">接口方向</td><td style="text-align: left;">连接至主控芯片</td><td style="text-align: left;">连接至物理 CAN 总线（双绞线）</td></tr><tr><td style="text-align: center;">通信层级</td><td style="text-align: left;"><strong>数据链路层</strong>（OSI Layer2）</td><td style="text-align: left;"><strong>物理层</strong>（OSI Layer1）</td></tr><tr><td style="text-align: center;">典型芯片</td><td style="text-align: left;"><code>MCP2515</code>、<code>SJA1000</code>、<code>MCU 片内外设</code></td><td style="text-align: left;"><code>TJA1050</code>、<code>SN65HVD230</code></td></tr></tbody></table><h2 id="速率单位-mbs-与-mbps">速率单位 MB/s 与 Mbps</h2><p><strong>兆字节每秒</strong>（<strong>MB/s</strong>，​Megabytes PerSecond）和 <strong>兆比特每秒</strong>（<strong>Mbps</strong> 或<strong>Mbit/s</strong>，​​Megabits PerSecond​）都是用于衡量<strong>数据传输速率</strong>的单位：</p><ul><li><code>1 MB/s</code> 表示每秒传输 <code>1</code>百万个<strong>字节</strong> <code>Bytes</code> ​​ 的数据。</li><li><code>1 Mbps</code> 表示每秒传输 <code>1</code>百万个<strong>比特位</strong> <code>bits</code> ​​ 的数据。</li></ul><p>根据 <code>1 Byte = 8 Bits</code>，可以将 <code>MB/s</code> 与<code>Mbps</code> 的换算关系联立为如下的推导公式：</p><p><span class="math display">\[1 Byte = 8 Bits\implies\begin{cases}1 MB/s​ = 8 Mbps​ \\​​1 Mbps = 0.125 MB/s​​\end{cases}\]</span></p><blockquote><p><strong>注意</strong>：大写的 <code>B</code>通常用于表示<strong>字节</strong> <code>Byte</code>，而小写的<code>b</code> 则通常用来表示<strong>比特位</strong><code>bit</code>。</p></blockquote><h2 id="通信帧类型的划分">通信帧类型的划分</h2><p>CAN总线协议当中的<strong>帧类型</strong>，主要用于区分不同用途的<strong>数据传输格式</strong>。CAN总线协议存在有<code>数据帧</code>、<code>遥控帧</code>、<code>错误帧</code>、<code>过载帧</code>、<code>帧间隔</code>五种<strong>帧</strong>（Frame）类型，其中 <code>数据帧</code> 和<code>遥控帧</code>拥有<strong>标准</strong>和<strong>扩展</strong>两种格式（标准格式拥有11 位标识符，扩展格式拥有 29 位的标识符）：</p><ol type="1"><li><strong>数据帧</strong>：用于 <code>发送单元</code> 向<code>接收单元</code> 传送数据。</li><li><strong>远程帧</strong>：用于 <code>接收单元</code>向具有相同<strong>标识符</strong>的 <code>发送单元</code>请求数据。</li><li><strong>错误帧</strong>：用于在检测出 <code>错误</code>的时候，向其它单元发送错误通知。</li><li><strong>过载帧</strong>：用于 <code>接收单元</code>通知其尚未做好接收准备。</li><li><strong>帧间隔</strong>：用于分离<code>数据帧</code>、<code>遥控帧</code>与其它的<strong>帧</strong>。</li></ol><p>CAN总线协议当中的<strong>标识符</strong>，在许多英文资料的原文当中被称为<code>ID</code>，也就是英文 <code>Identifier</code>的缩写形式。在接下来的内容里，我们将会分门别类、图文并茂的介绍这五种帧类型。</p><blockquote><p><strong>注意</strong>：技术资料当中经常提到的<strong>报文</strong>是指通信总线上传输的完整信息单元，而<strong>帧</strong>则主要是指报文在物理层面上的传输格式。</p></blockquote><h2 id="帧类型---数据帧">帧类型 - 数据帧</h2><p>CAN 总线网络里的<strong>数据帧</strong>（DataFrame），主要由如下图所示的 7 个<strong>信号片段</strong>所构成：</p><p><img src="/Electronics/CAN/Frame/1.png"></p><ol type="1"><li><strong>帧起始段</strong>：表示数据帧<strong>开始</strong>的段。</li><li><strong>仲裁段</strong>：表示该数据帧<strong>优先级</strong>的段。</li><li><strong>控制段</strong>：表示数据的<strong>字节数</strong>以及<strong>保留位</strong>的段。</li><li><strong>数据段</strong>：数据携带的具体内容，可以发送<code>0~8</code> 个字节的数据。</li><li><strong>CRC段</strong>：用于检查数据帧<strong>传输错误</strong>的段。</li><li><strong>ACK段</strong>：用于<strong>确认正常接收</strong>的段。</li><li><strong>帧结束段</strong>：表示数据帧<strong>结束</strong>的段</li></ol><h3 id="帧起始段">帧起始段</h3><p><strong>帧起始</strong>指的是帧最开始的一位，也被称为<strong>SOF</strong>（Start ofFrame）。帧起始默认为<strong>显性</strong>（逻辑 <code>0</code>），表示<code>CAN_H</code> 和 <code>CAN_L</code> 上面存在电位差，CAN总线上面一旦出现 SOF 就表明有报文出现。</p><p><img src="/Electronics/CAN/Frame/2.png"></p><p>CAN 总线上总是存在有 <strong>显性电平</strong>（逻辑<code>0</code>）和 <strong>隐性电平</strong>（逻辑<code>1</code>）两种信号：</p><ul><li><strong>显性状态</strong>（Dominant [ˈdɑːmɪnənt]）：相当于逻辑电平<code>0</code>，即本文示例图片当中的英文标识 <code>D</code>；</li><li><strong>隐性状态</strong>（Recessive [rɪˈsesɪv]）：相当于逻辑电平<code>1</code>，即本文示例图片当中的英文标识 <code>R</code>；</li></ul><blockquote><p><strong>注意</strong>：只要有一个节点输出<strong>显性</strong>电平，CAN总线就会表现为<strong>显性</strong>电平。只有当所有节点都输出<strong>隐性</strong>电平，CAN总线才会表现为<strong>隐性</strong>电平。</p></blockquote><h3 id="仲裁段">仲裁段</h3><p><strong>仲裁段</strong>用于判定<strong>帧</strong>的优先级，<strong>标准格式</strong>和<strong>扩展格式</strong>在仲裁段的构成有所不同。其中，<strong>标准格式</strong>拥有<strong>11</strong> 位标识符，而<strong>扩展格式</strong>则拥有<strong>29</strong>位标识符（<code>11位基本标识符 + 18位扩展标识符</code>）：</p><p><img src="/Electronics/CAN/Frame/3.png"></p><ul><li><strong>标准格式</strong>仲裁段当中的<strong>远程传输请求位</strong>（RTR，RemoteTransmission Request）：CAN 总线数据帧 <code>仲裁段</code>的组成部分，主要用于区分数据帧和远程帧，其状态决定了当前帧是用于<code>发送数据</code> 还是 <code>请求数据</code>。</li><li><strong>扩展格式</strong>仲裁段当中的<strong>替代远程请求位</strong>（SRR，SubstituteRemote Request）：主要用于兼容 <code>标准帧</code> 与<code>扩展帧</code> 的仲裁机制，确保 <code>扩展帧</code> 不会错误的覆盖<code>标准帧</code>，同时确保 CAN 总线的优先级机制。</li><li><strong>扩展格式</strong>仲裁段当中的<strong>标识符扩展位</strong>（IDE，IdentifierExtension）：用于区分标准帧和扩展帧，其在扩展帧当中固定取值为<strong>隐性</strong>（逻辑<code>1</code>），其值会影响到标识符<code>ID</code> 的长度与仲裁的优先级。</li></ul><blockquote><p><strong>注意</strong>：标准格式的 11 位标识符，以及扩展格式的 11位基本标识符，都禁止<strong>仲裁段</strong>的高 7位全部是<strong>隐性</strong>的逻辑 <code>1</code>，即禁止被设定为<code>ID = 1111111XXXX</code>。</p></blockquote><h3 id="控制段">控制段</h3><p><strong>控制段</strong>用于表达<strong>数据段</strong>的<strong>字节长度</strong>，主要由6 个位构成（其中 2 个保留位，4个数据长度位），<strong>标准格式</strong>和<strong>扩展格式</strong>在控制段的构成也有所不同：</p><p><img src="/Electronics/CAN/Frame/4.png"></p><p>上图当中的<strong>保留位</strong> <code>r0</code> 和 <code>r1</code>两个位必须全部以<strong>显性电平</strong>（逻辑<code>0</code>）发送。而<strong>数据长度码</strong>（DLC，Data LengthCode）则由四个位构成（也就是 <code>0 ~ 8</code>的四位二进制表示），其与数据段字节长度的对应关系如下面表格所示：</p><table><colgroup><col style="width: 10%"><col style="width: 22%"><col style="width: 22%"><col style="width: 22%"><col style="width: 22%"></colgroup><thead><tr><th style="text-align: center;">数据段长度</th><th style="text-align: center;">数据长度码第 3 位</th><th style="text-align: center;">数据长度码第 2 位</th><th style="text-align: center;">数据长度码第 1 位</th><th style="text-align: center;">数据长度码第 0 位</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>0 字节</strong></td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td></tr><tr><td style="text-align: center;"><strong>1 字节</strong></td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td><td style="text-align: center;"><strong>隐性 R</strong>（逻辑<code>1</code>）</td></tr><tr><td style="text-align: center;"><strong>2 字节</strong></td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td><td style="text-align: center;"><strong>隐性 R</strong>（逻辑<code>1</code>）</td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td></tr><tr><td style="text-align: center;"><strong>3 字节</strong></td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td><td style="text-align: center;"><strong>隐性 R</strong>（逻辑<code>1</code>）</td><td style="text-align: center;"><strong>隐性 R</strong>（逻辑<code>1</code>）</td></tr><tr><td style="text-align: center;"><strong>4 字节</strong></td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td><td style="text-align: center;"><strong>隐性 R</strong>（逻辑<code>1</code>）</td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td></tr><tr><td style="text-align: center;"><strong>5 字节</strong></td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td><td style="text-align: center;"><strong>隐性 R</strong>（逻辑<code>1</code>）</td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td><td style="text-align: center;"><strong>隐性 R</strong>（逻辑<code>1</code>）</td></tr><tr><td style="text-align: center;"><strong>6 字节</strong></td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td><td style="text-align: center;"><strong>隐性 R</strong>（逻辑<code>1</code>）</td><td style="text-align: center;"><strong>隐性 R</strong>（逻辑<code>1</code>）</td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td></tr><tr><td style="text-align: center;"><strong>7 字节</strong></td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td><td style="text-align: center;"><strong>隐性 R</strong>（逻辑<code>1</code>）</td><td style="text-align: center;"><strong>隐性 R</strong>（逻辑<code>1</code>）</td><td style="text-align: center;"><strong>隐性 R</strong>（逻辑<code>1</code>）</td></tr><tr><td style="text-align: center;"><strong>8 字节</strong></td><td style="text-align: center;"><strong>隐性 R</strong>（逻辑<code>1</code>）</td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td><td style="text-align: center;"><strong>显性 D</strong>（逻辑<code>0</code>）</td></tr></tbody></table><blockquote><p><strong>注意</strong>：数据段的有效<strong>字节长度</strong>只有<code>0 ~ 8</code> 个字节，但是接收节点并不会将 <code>9 ~ 15</code>的值视为错误。</p></blockquote><h3 id="数据段">数据段</h3><p><strong>数据段</strong>可以存放 <code>0 ~ 8</code>个字节的数据（长度由控制段中的<strong>数据长度码</strong>进行标识），数据传输时遵循<strong>高位优先</strong>的原则：</p><p><img src="/Electronics/CAN/Frame/5.png"></p><h3 id="crc-段">CRC 段</h3><p><strong>CRC 段</strong>主要是由 <code>15</code> 位的 <strong>CRC计算值</strong>，和 <code>1</code> 位的 <strong>CRC界定符</strong>构成：</p><p><img src="/Electronics/CAN/Frame/6.png"></p><p>CAN 总线引入了<strong>循环冗余校验</strong>（CRC，Cyclic RedundancyCheck）来检测传输错误，即收发双方都会基于<code>帧起始</code>、<code>仲裁段</code>、<code>控制段</code>、<code>数据段</code>计算 <strong>CRC 值</strong>来检测数据传输错误。</p><h3 id="ack-段">ACK 段</h3><p><strong>ACK 段</strong>用来确认是否正常接收（通过<code>接收单元</code> 发送，而 <code>发送单元</code> 无需发送），主要由1 位的 <strong>ACK 槽</strong>（ACK Slot）和 1 位的 <strong>ACK界定符</strong>（ACK Delimiter）共同组成：</p><p><img src="/Electronics/CAN/Frame/7.png"></p><p><strong>ACK</strong> 是英文<code>Acknowledgment</code>（应答信息）的缩写形式，顾名思义，主要是用于确认<strong>数据帧</strong>、<strong>遥控帧</strong>是否被至少一个CAN 总线节点正确接收（并且不会出现<code>填充错误</code>、<code>格式错误</code>、<code>CRC 校验错误</code>）。</p><h3 id="帧结束段">帧结束段</h3><p><strong>帧结束段</strong>（EOF，End of Frame）用于标识<code>数据帧</code>、<code>遥控帧</code>的<strong>结束</strong>，从而确保 CAN 总线恢复到空闲状态，其值固定为 7位 <strong>隐性位</strong>（逻辑 <code>1</code>），也就是连续的 7 个<code>1</code>（也就是 <code>1111111</code>）：</p><p><img src="/Electronics/CAN/Frame/8.png"></p><h2 id="帧类型---远程帧">帧类型 - 远程帧</h2><p><strong>远程帧</strong>（Remote Frame）用于在 CAN总线网络当中<strong>请求数据</strong>，远程帧主要由如下 6个<strong>信号片段</strong>组成（相比于前面介绍的<strong>数据帧</strong>，两者最大的区别在于远程帧没有<strong>数据段</strong>）:</p><p><img src="/Electronics/CAN/Frame/9.png"></p><ol type="1"><li><strong>帧起始段</strong>：表示数据帧<strong>开始</strong>的段。</li><li><strong>仲裁段</strong>：表示该数据帧<strong>优先级</strong>的段。</li><li><strong>控制段</strong>：表示数据的<strong>字节数</strong>以及<strong>保留位</strong>的段。</li><li><strong>CRC段</strong>：用于检查数据帧<strong>传输错误</strong>的段。</li><li><strong>ACK段</strong>：用于<strong>确认正常接收</strong>的段。</li><li><strong>帧结束段</strong>：表示数据帧<strong>结束</strong>的段</li></ol><p>对于<strong>远程帧</strong>与没有 <code>数据段</code>的<strong>数据帧</strong>（可用于各节点之间的心跳连接，或者其<code>仲裁段</code>就携带着有效信息），可以通过<strong>远程帧</strong>当中的<strong>远程传输请求位</strong><code>RTR</code> 进行区分，远程帧的 <code>RTR</code>位总是保持为<strong>隐性</strong>（逻辑<code>1</code>）。除此之外，由于远程帧没有数据段，所以其<strong>控制段</strong>当中的<code>数据长度码</code> 需要以其所请求的数据帧的 <code>数据长度码</code>进行表示。</p><h2 id="帧类型---错误帧">帧类型 - 错误帧</h2><p>CAN 总线的<strong>错误帧</strong>（ErrorFrame）用于在检测到错误时通知其它节点，并且触发错误恢复机制。错误帧主要由<strong>错误标志</strong>（ErrorFlag）和<strong>错误界定符</strong>（Error Delimiter）两部分组成：</p><p><img src="/Electronics/CAN/Frame/10.png"></p><ul><li><strong>错误标志</strong>：包含<strong>主动错误标志</strong>（由 6个显性位逻辑 <code>0</code> 组成）和<strong>被动错误标志</strong>（由 6个隐性位逻辑 <code>1</code>组成）两种类型（具体取决于节点的错误状态属于主动还是被动）。</li><li><strong>错误界定符</strong>：由 8 个隐性位逻辑 <code>1</code>组成，用于标识该错误帧结束。</li></ul><h2 id="帧类型---过载帧">帧类型 - 过载帧</h2><p><strong>过载帧</strong>（Overload Frame）是 CAN总线协议当中，用于处理<strong>节点</strong>接收过载（无法及时处理数据）的一种机制，过载帧由<strong>过载标志</strong>（Overload Flag）和<strong>过载界定符</strong>（Overload Delimiter）两部分组成：</p><p><img src="/Electronics/CAN/Frame/11.png"></p><ul><li><strong>过载标志</strong>：用于标识当前节点出现过载，由 6个显性位逻辑 <code>0</code> 组成。</li><li><strong>过载界定符</strong>：用于标识过载标志的结束，由 8个隐性位逻辑 <code>1</code> 组成。</li></ul><blockquote><p><strong>注意</strong>：过载帧的结构与<strong>错误帧</strong>类似，但是各自的触发条件与用途不同。</p></blockquote><h2 id="帧类型---帧间隔">帧类型 - 帧间隔</h2><p><strong>帧间隔</strong>（Inter Frame Space）用于分隔<strong>数据帧</strong> 和<strong>远程帧</strong>，即将本帧与前面的其它帧分隔开来（<strong>过载帧</strong>和<strong>错误帧</strong>前面，不能插入帧间隔），从而确保前一帧完全结束（此时可以认为总线空闲）。帧间隔由3 个隐性位（逻辑 <code>1</code>）组成，也就是<code>111</code>，通常位于<strong>帧结束段</strong>（EOF）之后：</p><p><img src="/Electronics/CAN/Frame/12.png"></p><h2 id="优先级仲裁机制">优先级仲裁机制</h2><p>当 CAN总线网络空闲的时候，最先发送消息的<strong>节点</strong>优先级更高。当多个节点同时发送数据的时候，每个节点的发送单元会从<strong>仲裁段</strong>的第1 位开始逐位进行仲裁，连续输出<strong>显性电平</strong>（逻辑<code>0</code>）最多的节点，所发送的数据具有更高的优先级：</p><p><img src="/Electronics/CAN/Frame/13.png"></p><blockquote><p><strong>注意</strong>：CAN总线的这种优先级仲裁机制被称作<strong>非破坏性逐位仲裁</strong>（BitwiseArbitration），确保优先级高的报文会优先发送，而优先级低的报文自动延迟发送。</p></blockquote><h3 id="数据帧-遥控帧">数据帧 &amp; 遥控帧</h3><p>具有相同 ID的<strong>数据帧</strong>和<strong>远程帧</strong>在竞争总线优先级时，仲裁段最后的<strong>远程传输请求位</strong><code>RTR</code> 为<strong>显性</strong>（逻辑<code>0</code>）的数据帧具有更高的优先权，其仲裁过程如下面示意图所示：</p><p><img src="/Electronics/CAN/Frame/14.png"></p><h3 id="标准格式-扩展格式">标准格式 &amp; 扩展格式</h3><p>当 CAN 总线当中，标准格式和扩展格式前 11 位的 ID标识符相同时，其优先级将会通过<strong>逐位仲裁机制</strong>进行比较，此时<strong>仲裁段</strong>当中的以下数据会参与到优先级的仲裁：</p><table><colgroup><col style="width: 10%"><col style="width: 40%"><col style="width: 49%"></colgroup><thead><tr><th style="text-align: left;">数据段</th><th style="text-align: left;">标准帧（11 位标识符）</th><th style="text-align: left;">扩展帧（29 位标识符）</th></tr></thead><tbody><tr><td style="text-align: left;">前 11 位</td><td style="text-align: left;">完整 ID（只有 11 位）</td><td style="text-align: left;">扩展帧前 11 位（与标准帧相同）</td></tr><tr><td style="text-align: left;"><code>SRR</code> 位</td><td style="text-align: left;"><strong>无</strong>，等效为显性（逻辑<code>0</code>）</td><td style="text-align: left;"><strong>固定隐性</strong>（逻辑<code>1</code>，替代 RTR 位）</td></tr><tr><td style="text-align: left;"><code>IDE</code> 位</td><td style="text-align: left;"><strong>无</strong>，等效为显性（逻辑<code>0</code>）</td><td style="text-align: left;"><strong>固定隐性</strong>（逻辑<code>1</code>，标识扩展帧）</td></tr></tbody></table><p><img src="/Electronics/CAN/Frame/15.png"></p><p>参考上面的这张示意图，可以将 CAN总线的优先级仲裁流程总结成下面的三个步骤：</p><ol type="1"><li>比较 11 位标识符：如果前 11 位不同，ID 值更小的帧优先级更高（显性 0优先于隐性 1）。如果前 11 位相同，继续比较后续控制位（SRR 和IDE）。</li><li>比较<strong>替代远程请求位</strong><code>SRR</code>（仅扩展帧）：<strong>标准帧</strong>没有显式的<code>SRR</code> 位，默认被隐式的等效为<strong>显性电平</strong>（逻辑<code>0</code>），而 <strong>扩展帧</strong>的 <code>SRR</code>位固定为<strong>隐性电平</strong>（逻辑<code>1</code>）。由于<strong>标准帧</strong>显性电平（逻辑<code>0</code>）的优先级高于<strong>扩展帧</strong>的隐性电平（逻辑<code>1</code>），因而相比较而言，<strong>标准帧的优先级会更高</strong>。</li><li>比较<strong>标识符扩展位</strong><code>IDE</code>：<strong>标准帧</strong>同样没有显式的 <code>IDE</code>位，同样被默认等效为<strong>显性电平</strong>（逻辑 <code>0</code>），而<strong>扩展帧</strong>的 <code>IDE</code>位固定为<strong>隐性电平</strong>（逻辑<code>1</code>），所以<strong>标准帧的优先级依然更高</strong>。</li></ol><h2 id="位填充机制">位填充机制</h2><p>CAN 总线的<strong>位填充</strong>（Bit Stuffing）机制是在连续 5个<strong>相同</strong>电平位之后，自动插入 1个<strong>反向</strong>的电平位。该机制主要用于同步 CAN总线的时钟和进行错误检测，从而确保数据传输的可靠性。</p><p><img src="/Electronics/CAN/Frame/16.png"></p><p>CAN收发器的<strong>发送单元</strong>与<strong>接收单元</strong>，它们各自的位填充机制分别如下面列表所示：</p><ul><li><strong>发送单元</strong>在发送<strong>数据帧</strong>和<strong>远程帧</strong>时，对于<code>SOF ~ CRC</code> 位之间的数据，相同电平如果持续 5 位，就会在第 6位插入一位与前 5 位反向的电平。</li><li><strong>接收单元</strong>在接收<strong>数据帧</strong>和<strong>远程帧</strong>时，对于<code>SOF ~ CRC</code> 位之间的数据，相同电平如果持续 5 位，就需要删除第6 位之后再进行接收。如果第 6 位的电平值与前 5位相同，那么就会被视为<strong>位填充错误</strong>，并且触发<strong>错误帧</strong>的发送。</li></ul><h2 id="错误处理机制">错误处理机制</h2><p>CAN 总线上的错误可以划分为<code>位错误</code>、<code>填充错误</code>、<code>CRC 错误</code>、<code>格式错误</code>、<code>ACK 错误</code>一共五种类型，这些错误的种类、内容、发生帧、检测单元，已经被分门别类的整理到下面的表格当中：</p><p><img src="/Electronics/CAN/Frame/17.png"></p><blockquote><p><strong>注意</strong>：上述表格当中的这些错误，即可能单独发生，也可能同时发生。</p></blockquote><p>接下来的列表里，说明了 <code>位错误</code>、<code>格式错误</code>以及 <code>填充错误</code> 之间，一些容易混淆的触发原因：</p><ul><li>当<strong>仲裁段</strong>输出隐性电平，但是检测出显性电平时，将会被视为<strong>仲裁失利</strong>，而非是<strong>位错误</strong>。</li><li>在<strong>仲裁段</strong>作为填充位输出隐性电平时，但检测出显性电平时，将不会被视为<strong>位错误</strong>，而是<strong>填充错误</strong>。</li><li>发送单元在 <strong>ACK段</strong>输出隐性电平，但检测到显性电平时，将会被判断为<strong>其它单元的ACK 应答</strong>，而非<strong>位错误</strong>。</li><li>当<strong>错误帧</strong>输出由 6 个隐性位（逻辑<code>1</code>）组成的<strong>被动错误标志</strong>，但是检测到其中一位是<strong>显性位</strong>（逻辑<code>0</code>）的时候，这种情况下 CAN 总线将会等待检测出 6个显性或者隐性的连续相同位，并不会被视为<strong>位错误</strong>。</li><li>当接收单元检测出 <code>EOF</code> <strong>帧结束段</strong>（由 7个隐性位组成）的时候，如果接收到的第 8位为显性电平，这种情况不会被视为<strong>格式错误</strong>。</li><li>当接收单元检测到 <code>DLC</code><strong>数据长度码</strong>（长度仅 <code>0 ~ 8</code> 个字节）出现 9∼15的值时，也不会被视为<strong>格式错误</strong>。</li></ul><p>当 CAN总线当中检测到上述的错误时，就会开始在<strong>错误帧</strong>当中输出<code>错误标志</code>（Error Flag）：</p><ul><li><strong>主动错误标志</strong>：由处于<strong>主动错误状态</strong>的CAN 总线节点输出；</li><li><strong>被动错误标志</strong>：由处于<strong>被动错误状态</strong>的CAN 总线节点输出；</li></ul><p>当 CAN总线节点的<strong>错误帧</strong>发送完毕之后，就会再次发送<strong>数据帧</strong>或者<strong>远程帧</strong>。不同错误类型的<strong>输出时序</strong>（也就是输出的时机）会有所区别，具体如下面列表所示：</p><ul><li><code>位错误</code>、<code>填充错误</code>、<code>格式错误</code>、<code>ACK 错误</code>：从检测到错误之后的下一位开始，就会输出错误标志。</li><li><code>CRC 错误</code>：从 <strong>ACK 段</strong> 的 <strong>ACK界定符</strong> 之后的下一位，开始输出错误标志。</li></ul><h2 id="数据位的构成">数据位的构成</h2><p><strong>位速率</strong>（Bit Rate）和<strong>波特率</strong>（BaudRate）都是表达信号传输速率的单位，它们各自的定义分别如下所示：</p><ul><li><strong>位速率</strong>：表示的是每一秒钟所能够传输的<strong>二进制位</strong>的数量，也被称作<strong>比特率</strong>，例如<code>8bit/s</code> 表示的就是 1 秒时间传输了 8 个位。</li><li><strong>波特率</strong>：表示每一种钟所能够传输的<strong>码元数量</strong>（即脉冲个数或者信号变化次数），这里的<strong>码元</strong>可以是多进制的，既可以携带<code>1bit</code>的数据（此时就等效于<strong>比特率</strong>），也可以携带<code>2bit</code> 甚至 <code>4bit</code> 的数据。</li></ul><p>CAN 总线的传输速率采用<strong>比特位</strong> <code>bit</code>来进行描述，其中传输的每一个<strong>比特位</strong>都会被划分为<code>SS</code>、<code>PTS</code>、<code>PBS1</code>、<code>PBS2</code>四个<strong>段</strong>，每个段又会由若干个<strong>时间量子</strong>（Tq,Time Quantum）构成（这里的 <code>Tq</code> 就是 <strong>CAN总线时序的最基本单位</strong>）：</p><p><img src="/Electronics/CAN/Bit/1.png"></p><ul><li><strong>同步段</strong>（SS，Sync Segment）：CAN 总线上 1个位的输出是<strong>从同步段开始的</strong>，如果信号的<strong>跳变沿</strong>位于同步段范围以内，就表示该节点与CAN 总线的时序同步，此时采样点的电平状态就会被采纳，同步段的大小固定为<code>1Tq</code>。</li><li><strong>传播段</strong>（PTS，Propagation Segment）：用于补偿信号在CAN 总线网络传播的<strong>物理延迟</strong>，包括<code>发送节点的输出延迟</code>、<code>CAN 总线信号的传播延迟</code>、<code>接收节点的输入延迟</code>，该<strong>段</strong>的时间为各个延迟时间之和的两倍，该段长度可以被配置为<code>1Tq ~ 8Tq</code>。</li><li><strong>相位缓冲段 1</strong>（PBS1，Phase Buffer Segment1）：用于补偿<strong>信号边沿阶段</strong>产生的误差，其<strong>时间长度可以延长，但是不能缩短</strong>，该段长度可以配置为<code>1Tq ~ 8Tq</code>（CAN 总线电平的采样点位于该段的结束位置）。</li><li><strong>相位缓冲段 2</strong>（PBS2，Phase Buffer Segment2）：同样用于补偿<strong>信号边沿阶段</strong>带来的误差，其<strong>时间长度可以缩短，但是不能延长</strong>，该段长度可以配置为<code>2Tq ~ 8Tq</code>。</li></ul><p>CAN 总线上 1个比特位的组成除了上述四个段之外，还存在着一个<strong>再同步补偿宽度</strong>（SJW，SynchronizationJump Width）的概念，其主要用于补偿<code>时钟频率</code>、<code>传送延迟</code> 等带来的误差，通常取值在<code>1Tq ~ 4Tq</code> 范围。</p><h2 id="位时序同步机制">位时序同步机制</h2><p>CAN总线上的每一个节点，都拥有着自己的本地时钟，由于硬件差异和传输延迟的存在，这个时钟可能存在微小偏差。CAN总线通过<strong>位同步</strong>（BitSynchronization）机制来确保所有节点，都能够正确的识别数据位的起始和结束，避免由于时钟偏差导致的通信错误：</p><ul><li><strong>调整接收节点的采样点</strong>，使其尽可能接近发送节点的最佳采样位置。</li><li><strong>补偿时钟频率偏差</strong>，确保长时间通信不会因为累积误差导致采样错误。</li></ul><blockquote><p><strong>注意</strong>：CAN总线采用<strong>非归零码</strong>（NRZ，Non Return toZero）方式进行数字信号的编码，即恒定使用高低电平来表示逻辑<code>0</code> 和<code>1</code>，电平信号不会在每一个位之后归零，而是保持当前电平状态，直至下一个位的开始。</p></blockquote><p>CAN 总线上传输的每一个比特位 <code>bit</code>的开头或者结尾都没有附加同步信号，<strong>发送节点</strong>以与位时序同步的方式发送数据，<strong>接收节点</strong>根据总线上电平的变化同步进行接收。但是发送节点与接收节点存在的时钟频率误差，以及传输路径上的相位延迟，都会引发位时序同步出现偏差，因而接收节点会通过<strong>硬件同步</strong>或者<strong>再同步</strong>的方法调整接收时序：</p><p><strong>硬同步</strong>（HardSynchronization）发生在<strong>帧起始</strong> <code>SOF</code>位置，用于对齐 CAN总线节点之间的<strong>位时间</strong>（强制<strong>接收节点</strong>的位时间计数器重新从<code>0</code>开始，也就是与<strong>发送节点</strong>帧起始位置的下降沿对齐）。</p><p><img src="/Electronics/CAN/Bit/2.png"></p><p><strong>再同步</strong>（Resynchronization）发生在数据帧的<strong>接收</strong>过程，用于微调接收节点的位时间，当检测到从<code>隐性</code> 到 <code>显性</code>电平的跳变时就会触发（排除帧起始位置）。即每当检测出跳变沿时，就会根据<strong>再同步补偿宽度</strong><code>SJW</code> 的值，通过延长<strong>相位缓冲段 1</strong><code>PBS1</code> 段，或者缩短<strong>相位缓冲段 2</strong><code>PBS2</code>段，达到与位时序同步的目的（如果发生超出<strong>再同步补偿宽度</strong><code>SJW</code> 值的误差，那么其最大调整量不能超过 <code>SJW</code>的取值）。</p><p><img src="/Electronics/CAN/Bit/3.png"></p><p>概而言之，我们可以将上述 CAN总线的<strong>位同步</strong>机制概括为下面三个步骤：</p><ol type="1"><li>检测从 <code>隐性</code> 到 <code>显性</code> 的电平边沿跳变；</li><li>计算相位误差，如果跳变发生在<strong>同步段</strong> <code>SS</code>之外，就说明当前存在着误差；</li><li>通过<strong>相位缓冲段 1</strong> <code>PBS1</code>或<strong>相位缓冲段 2</strong> <code>PBS2</code>调整误差，如果跳变发生在 <code>PBS1</code> 区域，那么延长<code>PBS1</code>；如果跳变发生在 <code>PBS2</code> 区域，那么缩短<code>PBS2</code>（延长和缩短的值都不得超过<strong>再同步补偿宽度</strong><code>SJW</code>）。</li></ol>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;strong&gt;控制器区域网络&lt;/strong&gt;（CAN，Controller Area
Network）总线协议规范正式发布于 1986
年，由德国博世公司为解决汽车电子系统当中，复杂的线束问题而设计。1991
年发布的 &lt;strong&gt;CAN 2.0 A/B&lt;/strong&gt;
规范的推出标志着其开启了标准化的进程。1993 年推出的 &lt;strong&gt;ISO
11898&lt;/strong&gt;
标准进一步巩固了其国际规范地位。伴随汽车电子和工业控制增涨的通信需求，2012
年发布的 &lt;strong&gt;CAN FD&lt;/strong&gt; 进一步提升了带宽与数据长度。而 2020
年发布的 &lt;strong&gt;CAN XL&lt;/strong&gt;
则能够支持更大数据量的传输，从而适应未来的智能化场景。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/Electronics/CAN/logo.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;CAN 总线协议发展至今日，已经以其
&lt;code&gt;低成本&lt;/code&gt;、&lt;code&gt;高实时性&lt;/code&gt;、&lt;code&gt;高可靠性&lt;/code&gt;、&lt;code&gt;优秀的抗干扰能力&lt;/code&gt;，成为当下使用极为广泛的标准化串行通信协议，被大面积运用于
&lt;code&gt;工业控制&lt;/code&gt;、&lt;code&gt;汽车电子&lt;/code&gt;、&lt;code&gt;航空航天&lt;/code&gt;
等对于可靠性要求较高的领域。众所周知，&lt;strong&gt;理工类技术的最佳学习方式，往往需要基于最为直观的理解，而大量的示意图和表格正是化繁为简的利器&lt;/strong&gt;。本文就将通过一系列丰富的图片与表格，来展示
CAN
总线协议的各个技术细节，以便让大家能够快速的理解这款倍受工程师欢迎的总线通信协议。&lt;/p&gt;</summary>
    
    
    
    <category term="硬件电子技术" scheme="http://www.uinio.com/categories/%E7%A1%AC%E4%BB%B6%E7%94%B5%E5%AD%90%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="通信总线" scheme="http://www.uinio.com/tags/%E9%80%9A%E4%BF%A1%E6%80%BB%E7%BA%BF/"/>
    
  </entry>
  
  <entry>
    <title>剖析无刷电机的 FOC 磁场定向控制算法</title>
    <link href="http://www.uinio.com/Embedded/FOC/"/>
    <id>http://www.uinio.com/Embedded/FOC/</id>
    <published>2025-04-14T16:00:00.000Z</published>
    <updated>2025-06-25T14:55:36.758Z</updated>
    
    <content type="html"><![CDATA[<p><strong>磁场定向控制</strong>（FOC，Field-OrientedControl）是一种用于<strong>无刷电机</strong>（BLDC）、<strong>永磁同步电机</strong>（PMSM）的矢量控制算法，其核心思想是将电机定子的<strong>电流</strong>分解为两个正交的分量：用于产生<code>磁场</code> 的<strong>励磁分量</strong> <code>d</code>轴和用于产生 <code>转矩</code> 的<strong>转矩分量</strong><code>q</code> 轴。通过对电机的 <code>转矩</code> 和 <code>磁场</code>进行独立的控制，从而达到快速响应和精确控制的目的，并且降低运行时的噪音和振动。整个算法处理过程可以大致划分为<strong>坐标变换</strong>、<strong>电流控制</strong>、<strong>逆变换</strong>、<strong>SVPWM空间矢量调制</strong> 四个阶段。</p><p><img src="/Embedded/FOC/logo.png"></p><p><strong>坐标变换阶段</strong>：将三相定子电流（<span class="math inline">\(I_a, I_b, I_c\)</span>）通过 Clarke变换转换为两相静止坐标系（<span class="math inline">\(I_\alpha,I_\beta\)</span>），再通过 Park 变换将静止坐标系转换为旋转坐标系（<span class="math inline">\(I_d, I_q\)</span>），其中 <span class="math inline">\(I_d\)</span> 控制磁场，<span class="math inline">\(I_q\)</span>控制转矩。<strong>电流控制阶段</strong>：通过 <code>PI 控制器</code>调节 <span class="math inline">\(I_d\)</span> 和 <span class="math inline">\(I_q\)</span>，使其跟踪参考值。<span class="math inline">\(I_d\)</span>的参考值通常设置为零（永磁同步电机）或根据需要进行调节（无刷电机），而<span class="math inline">\(I_q\)</span>的参考值由转矩需求决定。<strong>逆变换阶段</strong>：将旋转坐标系下的电压（<span class="math inline">\(V_d, V_q\)</span>）通过逆 Park变换转换回静止坐标系（<span class="math inline">\(V_\alpha,V_\beta\)</span>），再通过逆 Clarke变换生成三相电压信号，用于驱动逆变器。<strong>空间矢量调制阶段</strong>：将生成的电压信号调制为PWM 信号，控制逆变器开关驱动电机。</p><span id="more"></span><h2 id="直流有刷电机">直流有刷电机</h2><p><strong>直流有刷电机</strong>（BDC，Brushed DCMotor）是在一个由<strong>永磁体</strong>（作为<strong>定子</strong>）构成的磁场当中，放置三组通电的<strong>线圈</strong>（作为<strong>转子</strong>）。通过顶端由<strong>电刷</strong>构成的<strong>换向器</strong>交替控制三组线圈的通断，从而周而复始的驱动电机不断旋转。例如下图的直流有刷电机，通过换向器切换线圈当中通过的电流方向，然后借助永磁体产生的磁场，使其始终保持向右进行旋转：</p><p><img src="/Embedded/FOC/1.gif"></p><blockquote><p><strong>注意</strong>：直流无刷电机经常会使用廉价的<strong>碳刷</strong>作为换向器，在电机运转过程当中会产生磨损，需要定期进行更换，会增加后期使用的维护成本。</p></blockquote><h2 id="直流无刷电机">直流无刷电机</h2><p><strong>直流无刷电机</strong>（BLDC，Brushless DCMotor）顾名思义，就是不使用电刷进行换向。其在结构上与有刷电机正好相反（使用<strong>永磁体</strong>作为<strong>转子</strong>，而每间隔<code>120°</code>度放置的<strong>线圈</strong>作为<strong>定子</strong>），此时通过外部的MCU 微控制器和 MOS管，合理的控制这些线圈的通断顺序，就能够驱动<strong>转子</strong>进行旋转：</p><p><img src="/Embedded/FOC/2.gif"></p><blockquote><p><strong>注意</strong>：由于直流无刷电机不会使用<strong>电刷</strong>作为换向装置，因此无需定期进行维护，使用寿命也会更加长久。</p></blockquote><h3 id="六步换相法">六步换相法</h3><p><strong>三相直流无刷电机</strong>的<strong>定子</strong>通常是由<code>U</code>、<code>V</code>、<code>W</code> 三组线圈组成：</p><ol type="1"><li><strong>U 相</strong>：即<strong>线圈</strong> <code>U</code>通过的电流路径；</li><li><strong>V 相</strong>：即<strong>线圈</strong> <code>V</code>通过的电流路径；</li><li><strong>W 相</strong>：即<strong>线圈</strong> <code>W</code>通过的电流路径；</li></ol><p>如果当前线圈的通电方向是由 <code>U 相</code> 到<code>W 相</code>，那么相应的在<strong>线圈</strong> <span class="math inline">\(U\)</span> 和<strong>线圈</strong> <span class="math inline">\(W\)</span>上，就会产生如下面箭头所示的两个<strong>磁通量</strong>：</p><p><img src="/Embedded/FOC/3.png"></p><p>上述这两个磁通量，可以合成出一个下图当中，绿色箭头所表示的<strong>等效磁通量</strong>：</p><p><img src="/Embedded/FOC/4.png"></p><p>按照下图右侧的表格，调整通电线圈的顺序（即左图<strong>绿色</strong>箭头），就可以合成出相应的磁通量（即左图<strong>棕色</strong>箭头），从而使得由永磁体制作的<strong>转子</strong>，被这个合成出来的<strong>等效磁通量</strong>持续牵引，进而驱动其不间断的进行旋转：</p><p><img src="/Embedded/FOC/5.gif"></p><p>这种方式合成的<strong>磁通量</strong>只存在六个方向，因而被称作<strong>六步换相法</strong>（每一次控制两个相，只能旋转<code>60°</code>度），但是这种控制方式会导致旋转动作存在抖动，相应的工作噪音也会比较大。</p><h3 id="正弦波换相法">正弦波换相法</h3><p>为了规避六步换相法带来的缺点，可以通过<strong>正弦信号</strong>来控制<code>U</code>、<code>V</code>、<code>W</code>三个相上<strong>电流</strong> 的 <code>幅值</code> 与<code>相位</code>，从而精确的控制<strong>合成磁通量</strong>的<code>大小</code> 与 <code>方向</code>，进而达到流畅平稳旋转的目的：</p><p><img src="/Embedded/FOC/6.gif"></p><p>如果无刷电机的<strong>相电压</strong>属于正弦信号，那么相应的<strong>相电流</strong>也属于正弦信号。换而言之，通过控制相电压的幅值与相位，就可以控制相电流的<code>幅值</code> 与<code>相位</code>。简而言之，<strong>电压是控制手段，电流是控制目的</strong>。</p><p>众所周知，通过逆变电路产生<strong>占空比</strong>变化的<strong>脉冲宽度调制</strong>（PWM，PulseWidth Modulation）信号，就可以控制无刷电机当中<code>线圈的电压方向</code> 乃至于 <code>等效的电流大小</code>：</p><p><img src="/Embedded/FOC/7.png"></p><blockquote><p><strong>注意</strong>：PWM本质上是通过调节占空比来等效调节平均电压，但是由于<strong>欧姆定律</strong>的存在，实际应用当中也会影响到电流的大小。</p></blockquote><p>基于 <strong>PWM</strong> 脉冲宽度调制的思想，衍生出了<strong>SPWM</strong> 和 <strong>SVPWM</strong>这两种无刷电机逆变电路的正弦信号控制方法：</p><ol type="1"><li><strong>正弦脉宽调制</strong>（SPWM，Sinusoidal Pulse WidthModulation）：通过使用<strong>正弦波</strong>作为<strong>调制波</strong>，<strong>三角波</strong>作为<strong>载波</strong>来生成PWM 信号，目标是让逆变电路输出的电压波形尽可能的接近正弦波。</li><li><strong>空间矢量脉宽调制</strong>（SVPWM，Space Vector Pulse WidthModulation）：将三相电压视为一个<strong>空间矢量</strong>，通过组合<strong>八种基本开关状态</strong>（<code>6 个有效矢量 + 2 个零矢量</code>）来合成目标电压，使得无刷电机获得更为平滑的旋转磁场。</li></ol><blockquote><p><strong>注意</strong>：<strong>SPWM</strong>控制方式存在母线电压利用率较低的弊端，同时硬件上需要采用具备有高精度定时器，且运算能力较强的DSP 作为主控芯片，大部分场景下不如 <strong>SVPWM</strong> 运用广泛。</p></blockquote><h3 id="位置传感器">位置传感器</h3><p>直流无刷电机的精确控制，通常需要到获取到当前由永磁体制作的<strong>转子</strong>位置，这项任务通常需要交给专门的位置传感器来完成，常见的位置传感器如下面表格所示：</p><table><colgroup><col style="width: 10%"><col style="width: 17%"><col style="width: 72%"></colgroup><thead><tr><th style="text-align: center;">传感器种类</th><th style="text-align: left;">适用性</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>霍尔传感器</strong></td><td style="text-align: left;">适用于 <code>120°</code> 度三相控制</td><td style="text-align: left;">每间隔 <code>60°</code>度获取一次信号，价格低廉，但是耐热性差。</td></tr><tr><td style="text-align: center;"><strong>光电编码器</strong></td><td style="text-align: left;">适用于正弦波、矢量控制</td><td style="text-align: left;">有增量型（从初始位置移动的距离）和绝对型（当前旋转位置的角度）两种，分辨率比较高，但是防尘埃能力差。</td></tr><tr><td style="text-align: center;"><strong>转角传感器</strong></td><td style="text-align: left;">适用于正弦波、矢量控制</td><td style="text-align: left;">分辨率比较高，适用于较为恶劣的工况。</td></tr></tbody></table><h3 id="逆变电路">逆变电路</h3><p>用于无刷电机控制的<strong>逆变电路</strong>，通常使用<code>Q0</code>、<code>Q1</code>、<code>Q2</code>、<code>Q3</code>、<code>Q4</code>、<code>Q5</code>共计六个 MOS 管来进行搭建，其中每两个 MOS 管组合在一起（<code>Q0</code>与 <code>Q1</code>、<code>Q2</code> 与 <code>Q3</code> 与<code>Q4</code>、<code>Q5</code>），分别形成<strong>上桥臂</strong>（即上管<code>Q1</code>、<code>Q3</code>、<code>Q5</code>）和<strong>下桥臂</strong>（即下管<code>Q0</code>、<code>Q2</code>、<code>Q4</code>），并在<strong>中间位置</strong>引出一条导线连接到无刷电机的<strong>线圈</strong>，从而构成三个<strong>半桥电路</strong>，完整的无刷电机驱动电路示意图如下面所示：</p><p><img src="/Embedded/FOC/8.png"></p><p>综上所述，只需要交替开关各个<strong>相</strong>所对应的 MOS管，就可以驱动无刷电机进行转动。因而对于<strong>无刷电机的控制，本质上就是对于MOS 管开关规律的控制</strong>。而本文重点讨论的 FOC控制算法，其本质是<strong>通过对无刷电机运动模型进行抽象与简化，进而有规律的控制逆变电路当中的MOS 管进行通断的过程</strong>。</p><blockquote><p><strong>注意</strong>：实际生产环境对于 MOS管开关规律的控制，通常是由具备有<strong>浮点处理单元</strong>（FPU，FloatingPoint Unit）的 MCU 微控制器来完成。</p></blockquote><h2 id="矢量控制概述">矢量控制概述</h2><p>磁场定向控制（FOC，Field OrientedControl）也被称作<strong>矢量控制</strong>（VectorControl），可以精确的控制<strong>磁场</strong>的 <code>大小</code> 与<code>方向</code>，是当前 <strong>BLDC 无刷直流电机</strong> 和<strong>PMSM 永磁同步电机</strong> 主流的控制方式。</p><p>众所周知，电流可以产生磁场，磁场大小与电流大小呈正比。</p><p>下面以电流闭环控制为例，让电机始终保持一个恒定的力矩（力矩与电流呈正比）。</p><p><img src="/Embedded/FOC/9.png"></p><h2 id="克拉克变换">克拉克变换</h2><p>克拉克变换的<strong>等幅值形式</strong>（通过达成 <span class="math inline">\(i_{\alpha} = i_a\)</span> 来简化运算）</p><h2 id="克拉克逆变换">克拉克逆变换</h2><h2 id="帕克变换">帕克变换</h2><h2 id="空间矢量脉宽调制">空间矢量脉宽调制</h2>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;strong&gt;磁场定向控制&lt;/strong&gt;（FOC，Field-Oriented
Control）是一种用于&lt;strong&gt;无刷电机&lt;/strong&gt;（BLDC）、&lt;strong&gt;永磁同步电机&lt;/strong&gt;（PMSM）的矢量控制算法，其核心思想是将电机定子的&lt;strong&gt;电流&lt;/strong&gt;分解为两个正交的分量：用于产生
&lt;code&gt;磁场&lt;/code&gt; 的&lt;strong&gt;励磁分量&lt;/strong&gt; &lt;code&gt;d&lt;/code&gt;
轴和用于产生 &lt;code&gt;转矩&lt;/code&gt; 的&lt;strong&gt;转矩分量&lt;/strong&gt;
&lt;code&gt;q&lt;/code&gt; 轴。通过对电机的 &lt;code&gt;转矩&lt;/code&gt; 和 &lt;code&gt;磁场&lt;/code&gt;
进行独立的控制，从而达到快速响应和精确控制的目的，并且降低运行时的噪音和振动。整个算法处理过程可以大致划分为&lt;strong&gt;坐标变换&lt;/strong&gt;、&lt;strong&gt;电流控制&lt;/strong&gt;、&lt;strong&gt;逆变换&lt;/strong&gt;、&lt;strong&gt;SVPWM
空间矢量调制&lt;/strong&gt; 四个阶段。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/Embedded/FOC/logo.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;坐标变换阶段&lt;/strong&gt;：将三相定子电流（&lt;span class=&quot;math inline&quot;&gt;&#92;(I_a, I_b, I_c&#92;)&lt;/span&gt;）通过 Clarke
变换转换为两相静止坐标系（&lt;span class=&quot;math inline&quot;&gt;&#92;(I_&#92;alpha,
I_&#92;beta&#92;)&lt;/span&gt;），再通过 Park 变换将静止坐标系转换为旋转坐标系（&lt;span class=&quot;math inline&quot;&gt;&#92;(I_d, I_q&#92;)&lt;/span&gt;），其中 &lt;span class=&quot;math inline&quot;&gt;&#92;(I_d&#92;)&lt;/span&gt; 控制磁场，&lt;span class=&quot;math inline&quot;&gt;&#92;(I_q&#92;)&lt;/span&gt;
控制转矩。&lt;strong&gt;电流控制阶段&lt;/strong&gt;：通过 &lt;code&gt;PI 控制器&lt;/code&gt;
调节 &lt;span class=&quot;math inline&quot;&gt;&#92;(I_d&#92;)&lt;/span&gt; 和 &lt;span class=&quot;math inline&quot;&gt;&#92;(I_q&#92;)&lt;/span&gt;，使其跟踪参考值。&lt;span class=&quot;math inline&quot;&gt;&#92;(I_d&#92;)&lt;/span&gt;
的参考值通常设置为零（永磁同步电机）或根据需要进行调节（无刷电机），而
&lt;span class=&quot;math inline&quot;&gt;&#92;(I_q&#92;)&lt;/span&gt;
的参考值由转矩需求决定。&lt;strong&gt;逆变换阶段&lt;/strong&gt;：将旋转坐标系下的电压（&lt;span class=&quot;math inline&quot;&gt;&#92;(V_d, V_q&#92;)&lt;/span&gt;）通过逆 Park
变换转换回静止坐标系（&lt;span class=&quot;math inline&quot;&gt;&#92;(V_&#92;alpha,
V_&#92;beta&#92;)&lt;/span&gt;），再通过逆 Clarke
变换生成三相电压信号，用于驱动逆变器。&lt;strong&gt;空间矢量调制阶段&lt;/strong&gt;：将生成的电压信号调制为
PWM 信号，控制逆变器开关驱动电机。&lt;/p&gt;</summary>
    
    
    
    <category term="嵌入式" scheme="http://www.uinio.com/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F/"/>
    
    
    <category term="算法" scheme="http://www.uinio.com/tags/%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>开关电源 SMPS 基本原理 &amp; 拓扑结构剖析</title>
    <link href="http://www.uinio.com/Electronics/Power-Switching/"/>
    <id>http://www.uinio.com/Electronics/Power-Switching/</id>
    <published>2025-03-05T16:00:00.000Z</published>
    <updated>2025-06-25T14:55:36.627Z</updated>
    
    <content type="html"><![CDATA[<p><strong>电源</strong>用于在电路当中将其它形式的能量转换为电能，日常工作当中主要运用的是<strong>化学电源</strong>（碳性电池、碱性电池、锂电池、镍氢电池、铅酸电池）、<strong>开关电源</strong>（效率高、体积小、重量轻）、<strong>线性电源</strong>（输出电压稳定，纹波系数小）三种类型。在之前的<a href="http://uinio.com/Electronics/Battery/">《<strong>锂离子电池技术参数简明选型指南</strong>》</a>这篇文章当中，已经详细阐述了锂离子电池的性能指标与选型思路。本篇文章则从线性电源的原理入手，逐步引出开关电源的知识，并且分门别类的讨论了几种常见的<strong>拓扑结构</strong>。</p><p><img src="/Electronics/Power-Switching/logo.png"></p><p><strong>线性电源</strong>（Linear PowerSupply）的<strong>调整管</strong>工作在<strong>线性状态</strong>（<code>放大</code>），开关电源通常是在对<strong>输出电压</strong>进行采样之后，会将其与参考电压一同送入<strong>比较放大器</strong>，然后通过其输出的控制信号作为<strong>调整管</strong>的输入，从而达到通过<strong>调整管</strong>控制电源输出电压的目的，但是由于调整管工作在放大区，其本身会发热并且消耗电能，因而转换效率相对较差。而<strong>开关电源</strong>（SwitchingPowerSupply）的<strong>功率开关管</strong>工作在<strong>开关状态</strong>（<code>饱和</code>与<code>截止</code>），主要是通过调整<strong>功率开关管</strong>的通断时间（占空比）来改变输出电压。由于功率开关管切换状态时耗散的功率比较少，产生的废热也比较少，相对而言更加节能，属于机电产品当中主流的电源形态。</p><span id="more"></span><h2 id="线性电源原理">线性电源原理</h2><p><strong>线性电源</strong>通常由<code>变压器</code>、<code>整流电路</code>、<code>滤波电路</code>、<code>稳压电路</code>四个部分组成：</p><p><img src="/Electronics/Power-Switching/1-Linear-Power/1.png"></p><ol type="1"><li><strong>变压器</strong>：用于将电网 <code>220V/50Hz</code>交流电压转换为指定的交流电压，通常由两个或者以上的绕组构成（输入端为初级绕组，输出端为次级绕组，绕组之间完全电气隔离）。</li><li><strong>整流电路</strong>：通过具有单向导电作用的<strong>二极管</strong>，将正负交替的<strong>正弦交流电压</strong>转换为单向的<strong>脉动直流电压</strong>。通常由4 只二极管组成的，也被称作<strong>整流桥</strong>。</li><li><strong>滤波电路</strong>：用于滤除脉动直流电压当中掺杂的交流成分，从而获得一个相对平滑的直流电压。中小功率线性电源当中，通常会采用<strong>电容滤波电路</strong>，即将<code>滤波电容</code> 直接并联在整流电路的输出端。</li><li><strong>稳压电路</strong>：用于在电网电压、负载电流发生变化的时候，自动调节相关的参数，确保输出电压保持恒定。</li></ol><p>在下面的原理图当中，展示了线性稳压电源的<strong>基本结构框图</strong>：</p><p><img src="/Electronics/Power-Switching/1-Linear-Power/2.png"></p><ul><li><strong>调整管</strong> <span class="math inline">\(VT\)</span>：作用可以等效为一个可变电阻 <span class="math inline">\(R\)</span>。</li><li><strong>稳压二极管</strong> <span class="math inline">\(VD_z\)</span>：用于产生<strong>基准电压</strong><span class="math inline">\(U_{REF}\)</span>。</li><li><strong>取样电阻</strong> <span class="math inline">\(R_2\)</span>和 <span class="math inline">\(R_3\)</span>：用于检测<strong>输出电压</strong><span class="math inline">\(U_O\)</span>，并且通过分压产生<strong>反馈电压</strong><span class="math inline">\(U_F\)</span>。</li><li><strong>误差放大器</strong> <span class="math inline">\(EA\)</span>：用于将<strong>反馈电压</strong> <span class="math inline">\(U_F\)</span> 与<strong>基准电压</strong> <span class="math inline">\(U_{REF}\)</span>进行比较放大，从而控制<strong>调整管</strong>的导通状态。</li><li><strong>负载电阻</strong> <span class="math inline">\(R_L\)</span>：用于表示负载。</li></ul><p>当某种原因（例如负载电流增大）造成<strong>输出电压</strong> <span class="math inline">\(U_O\)</span> 降低的时候，<strong>反馈电压</strong><span class="math inline">\(U_F\)</span> 也会随之降低。误差放大器<strong>EA</strong> 会将<strong>反馈电压</strong> <span class="math inline">\(U_F\)</span> 与<strong>基准电压</strong> <span class="math inline">\(U_{REF}\)</span>进行比较放大，此时误差放大器输出的<strong>控制电压</strong> <span class="math inline">\(U_C\)</span>将会升高，从而使得<strong>调整管</strong> <span class="math inline">\(VT\)</span>的基极电流增大，<strong>等效电阻</strong> <span class="math inline">\(R\)</span> 减小，引发<strong>输出电压</strong><span class="math inline">\(U_O\)</span> 的回升，并最终保持输出电压<span class="math inline">\(U_O\)</span> 的稳定。</p><blockquote><p><strong>注意</strong>：由于<strong>调整管</strong> <span class="math inline">\(VT\)</span> 被串联在<strong>输入电压</strong><span class="math inline">\(U_I\)</span> 与<strong>输出电压</strong><span class="math inline">\(U_O\)</span>之间，所以也被称作<strong>串联稳压电源</strong>。</p></blockquote><p>而在下面的示意图里，则展示了线性稳压电源的一个<strong>等效电路</strong>：</p><p><img src="/Electronics/Power-Switching/1-Linear-Power/3.png"></p><p>基于上图的等效电路来解释线性电源的稳压原理，当某种原因造成<strong>输入电压</strong><span class="math inline">\(U_O\)</span>升高的时候，由于<strong>可变电阻</strong> <span class="math inline">\(R\)</span> 与<strong>负载电阻</strong> <span class="math inline">\(R_L\)</span> 串联，如果这里的 <span class="math inline">\(R\)</span>为固定电阻，则必然会使得<strong>输出电压</strong> <span class="math inline">\(U_O\)</span> 也随之升高，但是这里的 <span class="math inline">\(R\)</span>是一个可变电阻（等效于结构框图当中的<strong>调整管</strong> <span class="math inline">\(VT\)</span>），当检测到<strong>输出电压</strong><span class="math inline">\(U_O\)</span> 升高的时候，就会自动增大 <span class="math inline">\(R\)</span>的阻值，从而维持<strong>输出电压</strong> <span class="math inline">\(U_O\)</span> 的稳定。</p><blockquote><p><strong>注意</strong>：由于线性稳压电源的<strong>输入电压</strong><span class="math inline">\(U_I\)</span> 低于<strong>输出电压</strong><span class="math inline">\(U_O\)</span>，所以是一种<strong>降压式稳压电源</strong>。</p></blockquote><p>对于线性稳压电源的优缺点，可以言简意赅的总结如下：</p><ul><li><strong>缺点</strong>：体积较大、转换效率较低。</li><li><strong>优点</strong>：响应速度快、输出纹波小、输出噪声低。</li></ul><h2 id="开关电源原理">开关电源原理</h2><p><strong>开关稳压电源</strong>通常由<code>电磁干扰（EMI）滤波器</code>、<code>整流电路</code>、<code>滤波电路</code>、<code>DC/DC 变换器</code>共同组成：</p><p><img src="/Electronics/Power-Switching/2-Switching-Power/1.png"></p><ol type="1"><li><strong>电磁干扰（EMI）滤波器</strong>：用于阻止开关电源产生的噪声影响到电网附近的其它设备。</li><li><strong>整流电路</strong>：使用<strong>整流桥</strong>将正负交替的<strong>正弦交流电压</strong>转换为单向的<strong>脉动直流电压</strong>。</li><li><strong>滤波电路</strong>：滤除脉动直流电压当中掺杂的交流成分，从而获得一个相对平滑的直流电压。</li><li><strong>DC/DC变换器</strong>：属于<strong>开关电源的核心电路</strong>，通常由<code>功率开关管</code>、<code>高频变压器</code>、<code>PWM 控制器</code>等组成，也被称作<strong>功率变换器</strong>。</li></ol><p>为了更加直观的与前面介绍的线性稳压电源进行对比，接下来以<strong>降压式DC/DC变换器</strong>为例，介绍开关稳压电源的基本工作原理，其<strong>电路结构基本框图</strong>如下面所示：</p><p><img src="/Electronics/Power-Switching/2-Switching-Power/2.png"></p><ul><li><strong>功率开关管</strong> <span class="math inline">\(VT\)</span>：作用可以等效为一个能够高速运行的<strong>开关</strong><span class="math inline">\(S\)</span>。</li><li><strong>稳压二极管</strong> <span class="math inline">\(VD_z\)</span>：用于产生<strong>基准电压</strong><span class="math inline">\(U_{REF}\)</span>。</li><li><strong>取样电阻</strong> <span class="math inline">\(R_2\)</span>和 <span class="math inline">\(R_3\)</span>：用于检测<strong>输出电压</strong><span class="math inline">\(U_O\)</span>，并且通过分压网络产生<strong>反馈电压</strong><span class="math inline">\(U_F\)</span>。</li><li><strong>误差放大器</strong> <span class="math inline">\(EA\)</span>：用于将<strong>反馈电压</strong> <span class="math inline">\(U_F\)</span> 与<strong>基准电压</strong> <span class="math inline">\(U_{REF}\)</span> 进行比较放大，从而产生控制电压<span class="math inline">\(U_C\)</span>。</li><li><strong>续流二极管</strong> <span class="math inline">\(VD\)</span>：用于延续电感 L 中的电流。</li><li><strong>储能电感</strong> <span class="math inline">\(L\)</span>：由于需要经过比较大的负载电流，因而也称为<strong>功率电感</strong>。</li><li><strong>输出滤波电容</strong> <span class="math inline">\(C\)</span>：主要起到输出滤波的作用。</li><li><strong>负载电阻</strong> <span class="math inline">\(R_L\)</span>：在这里代表用电的负载。</li><li><strong>PWM 控制器</strong>：用于将<strong>误差放大器</strong> <span class="math inline">\(EA\)</span> 输出的<strong>控制电压</strong> <span class="math inline">\(U_C\)</span>的变化，转换为输出的控制信号<strong>占空比</strong> <span class="math inline">\(D\)</span>的变化，从而使得<strong>功率开关管</strong> <span class="math inline">\(VT\)</span>基于这个占空比进行导通与关断，并最终达到改变<strong>输出电压</strong><span class="math inline">\(U_O\)</span> 的目的。</li></ul><p><strong>开关电源</strong>的工作原理需要结合下面的<strong>等效电路</strong>，以及后续的波形<strong>占空比变化</strong>示意图来进行说明：</p><p><img src="/Electronics/Power-Switching/2-Switching-Power/3.png"></p><p>当 PWM 控制器使得基本框图中的<strong>功率开关管</strong> <span class="math inline">\(VT\)</span>导通时，相当于等效电路里<strong>开关</strong> <span class="math inline">\(S\)</span> 闭合。此时<strong>输入电压</strong><span class="math inline">\(U_I\)</span> 施加到<strong>储能电感</strong><span class="math inline">\(L\)</span> 的左端（<span class="math inline">\(U_L =U_I\)</span>）。在经过<strong>导通时间</strong> <span class="math inline">\(t_{ON}\)</span> 之后，PWM控制器会使得<strong>功率开关管</strong> <span class="math inline">\(VT\)</span>进入关断状态（相当于<strong>开关</strong> <span class="math inline">\(S\)</span> 断开）。此时<strong>续流二极管</strong><span class="math inline">\(VD\)</span>导通，使得<strong>储能电感</strong> <span class="math inline">\(L\)</span> 左端的电压为 <code>0V</code>（即 <span class="math inline">\(U_L =0V\)</span>）。在经过<strong>关断时间</strong> <span class="math inline">\(t_{OFF}\)</span> 之后，PWM控制器再次使得<strong>功率开关管</strong> <span class="math inline">\(VT\)</span>导通，从而进入到下一个开关周期，如此周而复始循环往复。</p><p><strong>导通时间</strong> <span class="math inline">\(t_{ON}\)</span>与<strong>关断时间</strong> <span class="math inline">\(t_{OFF}\)</span>之和等于<strong>开关周期</strong> <span class="math inline">\(T = t_{ON}+ t_{OFF}\)</span>，通常情况下开关周期 <span class="math inline">\(T\)</span> 固定不变，当导通时间 <span class="math inline">\(t_{ON}\)</span> 变长的时候，关断时间 <span class="math inline">\(t_{OFF}\)</span> 就会相应的变短。导通时间 <span class="math inline">\(t_{ON}\)</span> 与开关周期 <span class="math inline">\(T\)</span> 的比值被称作<strong>占空比</strong><span class="math inline">\(D = \frac{t_{ON}}{T}\)</span>。</p><p><img src="/Electronics/Power-Switching/2-Switching-Power/4.png"></p><p>上图展示了<strong>占空比</strong>分别为 <span class="math inline">\(D= 0.25\)</span>、<span class="math inline">\(D = 0.5\)</span>、<span class="math inline">\(D = 0.75\)</span>时候的电压波形，由于<strong>电感</strong> <span class="math inline">\(L\)</span> 和<strong>电容</strong> <span class="math inline">\(C\)</span> 的滤波作用，<span class="math inline">\(U_L\)</span> 位置的电压波形经过 LC滤波之后，将会变为平滑的直流输出电压 <span class="math inline">\(U_O\)</span>。</p><p>如果检测到<strong>输出电压</strong> <span class="math inline">\(U_O\)</span> 升高，那么<strong>误差放大器</strong><span class="math inline">\(EA\)</span> 输出的<strong>控制电压</strong><span class="math inline">\(U_C\)</span> 就会降低，通过 PWM控制器使得<strong>占空比</strong> <span class="math inline">\(D\)</span>随之下降，最终稳定<strong>输出电压</strong> <span class="math inline">\(U_O\)</span> 不变。</p><p>相比于同为降压型的线性稳压电源，开关电源的<strong>功率开关管</strong><span class="math inline">\(VT\)</span> 被等效为<strong>开关</strong><span class="math inline">\(S\)</span> 而非<strong>可变电阻</strong><span class="math inline">\(R\)</span>。当<strong>功率开关管</strong><span class="math inline">\(VT\)</span> 导通的时候，其压降通常仅在<code>1V</code>左右，<strong>导通损耗</strong>远远小于线性稳压电源。</p><p>线性电源<strong>调整管</strong> <span class="math inline">\(VT\)</span>的<strong>功率损耗</strong>，等于输入电压与输出电压之间的压差与负载电流的乘积<span class="math inline">\(P_D = (U_I - U_O) \timesI_L\)</span>。而开关电源<strong>功率开关管</strong> <span class="math inline">\(VT\)</span> 的导通损耗 <span class="math inline">\(P_D = 1 \timesI_L\)</span>，可以看到其与输入与输出之间的的<strong>压差</strong>基本无关。</p><p>例如对于一台 <code>12V</code> 输入 <code>5V</code>输出的<strong>线性电源</strong>，如果其负载电流为<code>1A</code>，则其<strong>调整管</strong> <span class="math inline">\(VT\)</span> 的<strong>功率损耗</strong> <span class="math inline">\(P_D\)</span> 等于 <code>7W</code>：</p><p><span class="math display">\[P_D = (12V - 5V) \times 1A = 7W\]</span></p><p>但是对于一台相同输入输出参数的<strong>开关电源</strong>，则其<strong>功率开关管</strong><span class="math inline">\(VT\)</span> 的<strong>功率损耗</strong><span class="math inline">\(P_D\)</span> 仅为 <code>1W</code>：</p><p><span class="math display">\[P_D = 1A \times 1 = 1W\]</span></p><p>由此可见，同样输入输出参数的开关电源，其功率损耗 <span class="math inline">\(P_D\)</span>要远低于线性电源，这正是开关电源转换效率更高的原因所在。</p><p>相比于线性电源，开关稳压电源的优缺点也可以被言简意赅的总结如下：</p><ul><li><strong>缺点</strong>：体积小巧、功率损耗较小，输入电压范围更宽。</li><li><strong>优点</strong>：输出纹波比较大，产生的电磁干扰也比较大（功率开关管在开关过程中产生的<code>尖峰电压/电流</code> 会带来比较大的电磁干扰）。</li></ul><h2 id="涉及的专业术语">涉及的专业术语</h2><h3 id="拓扑结构">拓扑结构</h3><p>开关电源的<strong>拓扑结构</strong>（Topology[təˈpɒlədʒi]）是指功率变换相关元器件组成的电路结构，其决定了开关电源的工作原理与输出特性。</p><h3 id="正激型">正激型</h3><p><strong>正激型</strong>（Forward）开关电源是在功率开关管<strong>导通</strong>期间向负载传输能量。除了典型的单端正激型之外，常见的<code>降压式</code>、<code>推挽式</code>、<code>半桥式</code>、<code>全桥式</code>开关电源都属于正激型。</p><h3 id="反激型">反激型</h3><p><strong>反激型</strong>（Flyback）开关电源是在功率开关管<strong>截止</strong>期间向负载传输能量。除了典型的单端反激型之外，常见的<code>升压式</code>、<code>极性反转式</code> 开关电源都属于反激型。</p><h3 id="连续模式">连续模式</h3><p><strong>连续模式</strong>（Continuous ConductingMode）也称为<strong>连续导电模式</strong>，该模式一个开关周期 <span class="math inline">\(T\)</span>之内，电感当中的电流（即电感当中存储的磁场能量）始终大于零，该电流的波形示意图如下面所示：</p><p><img src="/Electronics/Power-Switching/3-Term/1.png"></p><p>观察上图可以发现，开关管处于<strong>导通</strong> <span class="math inline">\(t_{ON}\)</span>区间的时候，电感上的<strong>电流</strong> <span class="math inline">\(I_L\)</span>是线性上升的，而在开关管处于<strong>关断</strong> <span class="math inline">\(t_{OFF}\)</span>区间的时候，电感上的<strong>电流</strong> <span class="math inline">\(I_L\)</span>是线性下降。如果开关管在关断期间，电感电流 <span class="math inline">\(I_L\)</span>没有下降到零，那么在下一个周期开关管导通的时候，电感电流 <span class="math inline">\(I_L\)</span> 就会重新上升，此时电感电流 <span class="math inline">\(I_L\)</span>处于连续不被中断的状态，因而被称作<strong>连续模式</strong>。</p><h3 id="不连续模式">不连续模式</h3><p><strong>不连续模式</strong>（Discontinuous ConductingMode）也称为<strong>断续导电模式</strong>，该模式一个开关周期 <span class="math inline">\(T\)</span>之内，电感当中的电流（电感存储的磁场能量）会下降到零，该电流的波形示意图如下面所示：</p><p><img src="/Electronics/Power-Switching/3-Term/2.png"></p><p>观察上图可以发现，开关管处于<strong>关断</strong> <span class="math inline">\(t_{OFF}\)</span>区间的时候，电感上的<strong>电流</strong> <span class="math inline">\(I_L\)</span>已经下降到零。而在开关管处于<strong>导通</strong> <span class="math inline">\(t_{ON}\)</span>区间的时候，电感上的<strong>电流</strong> <span class="math inline">\(I_L\)</span> 又会从零开始上升，此时电感电流 <span class="math inline">\(I_L\)</span>处于断断续续的状态，因而被称作<strong>断续模式</strong>。</p><h3 id="脉冲宽度调制">脉冲宽度调制</h3><p><strong>脉冲宽度调制</strong>（PWM，Pulse WidthModulation）是开关电源当中常用的控制方式，其特点是<strong>开关频率</strong><span class="math inline">\(f\)</span> 固定（即<strong>开关周期</strong><span class="math inline">\(T\)</span>保持不变），通过改变<strong>脉冲宽度</strong>来调整开关电源的输出电压。</p><h3 id="占空比">占空比</h3><p><strong>占空比</strong>（DutyCycle）通常用百分数进行表示，如果一个开关电源的开关周期为 <span class="math inline">\(T\)</span>，功率开关管的导通时间为 <span class="math inline">\(t_{ON}\)</span>，那么其<strong>占空比</strong><span class="math inline">\(D=\frac{t_{ON}}{T}\)</span>。根据开关电源的拓扑结构，占空比<span class="math inline">\(D\)</span> 的变化范围通常在<code>0 ~ 50%</code> 或者 <code>0 ~ 100%</code> 范围。</p><h3 id="基准电压">基准电压</h3><p><strong>基准电压</strong>也称为<strong>参考电压</strong>（ReferenceVoltage），是一个由基准电压源产生的恒定电压 <span class="math inline">\(U_{REF}\)</span>，开关电源的输出电压是基准电压的指定倍数，正是由于基准电压的稳定不变，才使得开关电源的输出电压也能够保持稳定不变。</p><h3 id="采样电路">采样电路</h3><p><strong>采样电路</strong>有时候也被称作<strong>反馈电路</strong>，主要用于检测开关电源输出电压的变化，从而产生相应的反馈电压输入到误差放大器。</p><ul><li><strong>电压采样电路</strong>：采用电阻分压网络，降低电压之后供控制电路使用。</li><li><strong>电流采样电路</strong>：电流路径上串联<strong>极低阻值</strong>的高精度<strong>采样电阻</strong>，通过测量其两端电压，基于<strong>欧姆定律</strong>计算得到经过的电流值。</li></ul><h3 id="误差放大器">误差放大器</h3><p><strong>误差放大器</strong>（EA，ErrorAmplifier）通常由运算放大器（OPAmp）组成，用于将反馈电压和基准电压进行比较放大，然后输出控制信号 <span class="math inline">\(U_C\)</span> 到 <strong>PWM控制器</strong>，再通过其改变功率开关管的占空比，进而达到调节输出电压的目的。</p><h3 id="电压电流模式">电压/电流模式</h3><p><strong>电压模式</strong>和<strong>电流模式</strong>分别属于两种不同的PWM 控制模式：</p><ol type="1"><li><strong>电压模式</strong>：只存在一个控制环路，只能通过<strong>输出电压</strong>的变化来控制PWM 的占空比。</li><li><strong>电流模式</strong>：除了<strong>电压控制环路</strong>之外，还增加了一个<strong>电流控制环路</strong>（通过检测功率开关管的电流变化来控制PWM 占空比），响应速度更快。</li></ol><h3 id="吸收缓冲电路">吸收缓冲电路</h3><p>开关电源工作过程当中，会产生非常高的尖峰电压，为了降低尖峰电压造成的危害，需要加入由<strong>阻容元器件</strong>和<strong>超快恢复二极管</strong>组成的保护电路，以便吸收尖峰电压的能量。</p><h3 id="emi-滤波器">EMI 滤波器</h3><p><strong>电磁干扰</strong>（EMI，Electro MagneticInterference）滤波电路主要由 <code>电感</code> 和 <code>电容</code>组成，主要用于抑制开关电源的电磁噪声，防止电源本身的高频噪声干扰到附近电网当中的其它用电设备，同时也能防止电网当中的高频干扰影响到电源本身。</p><h3 id="安规电容">安规电容</h3><p><strong>安规电容</strong>包括 <strong>X 电容</strong>和 <strong>Y电容</strong>两种类型（都属于金属薄膜电容），其在失效之后并不会导致电路发生短路，从而避免危及人身安全，主要被应用于EMI 滤波器电路当中：</p><ul><li><strong>X电容</strong>：用于抑制<strong>差模干扰</strong>，并联在电网的<strong>火线</strong><code>L</code> 和<strong>零线</strong> <code>N</code> 之间。</li><li><strong>Y电容</strong>：用于抑制<strong>共模干扰</strong>，并联在<strong>火线</strong><code>L</code> 和<strong>保护地</strong><code>E</code>，以及<strong>零线</strong> <code>N</code>和<strong>保护地</strong> <code>E</code> 之间，通常都是成对出现。</li></ul><h3 id="功率因数校正">功率因数校正</h3><p><strong>功率因数校正</strong>（PFC，Power FactorCorrection）是一种用于提高电力系统当中 <code>功率因数</code>的技术。<strong>功率因数</strong>是衡量电力系统效率的重要指标，其值被定义为<strong>有功功率</strong>和<strong>视在功率</strong>的比值，功率因数过低会增加线路损耗。开关电源当中通常会使用<strong>IGBT</strong> 或者 <strong>MOSFET</strong>等元器件，动态的调整输入电流的波形，使其保持与输入电压波形处于相同的<strong>相位</strong>，从而提高开关电源对于电能的利用率。</p><h2 id="主要参数指标">主要参数指标</h2><p>开关电源涉及到的性能指标参数众多，我们这里把比较重要的一些参数列举到下面的表格当中：</p><table><colgroup><col style="width: 7%"><col style="width: 92%"></colgroup><thead><tr><th style="text-align: left;">参数</th><th style="text-align: left;">说明</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>额定输入电压</strong></td><td style="text-align: left;">电源正常工作时候的设计输入电压值，设备在该电压下能够安全、稳定的运行，并且达到其标称性能。</td></tr><tr><td style="text-align: left;"><strong>额定输入电流</strong></td><td style="text-align: left;">电源满载工作时的输入电流，通常给出的是<code>额定输入电压</code> 范围内可能出现的最大输入电流值。</td></tr><tr><td style="text-align: left;"><strong>额定输出电压</strong></td><td style="text-align: left;">电源在额定的输入电压和负载的条件下，输出端能够稳定提供的电压值。</td></tr><tr><td style="text-align: left;"><strong>额定输出电流</strong></td><td style="text-align: left;">电源在额定的输出电压和负载的条件下，输出端能够持续稳定提供的最大电流值。</td></tr><tr><td style="text-align: left;"><strong>电压调整率</strong></td><td style="text-align: left;">当输入电压发生变化时，<strong>输出电压变化量</strong>与<strong>额定输出电压</strong>之间的比值，通常使用百分比进行表示。该参数越小，表明输出的电压越稳定，也称为<strong>线路调整率</strong>。</td></tr><tr><td style="text-align: left;"><strong>电流调整率</strong></td><td style="text-align: left;">指额定输入电压时，由于负载电流变化引发的<strong>输出电压变化量</strong>与<strong>额定输出电压</strong>的比值，通常使用百分比进行表示，该参数越小，表明输出的电压越稳定，也称为<strong>负载调整率</strong>。</td></tr><tr><td style="text-align: left;"><strong>输出纹波噪声</strong></td><td style="text-align: left;">通常使用<strong>峰峰值</strong> <span class="math inline">\(V_{pp}\)</span>进行表示，主要由<strong>功率开关管</strong>的高频切换导致的输出电压波动，以及<strong>滤波电容</strong>在充放电过程当中产生电压波动，以及电源电路的寄生电感和寄生电容在高频下产生的<strong>谐振</strong>所共同导致。</td></tr><tr><td style="text-align: left;"><strong>电源效率</strong></td><td style="text-align: left;">指 <code>输出功率</code> 与<code>输入功率</code>的比值，该参数值越大，开关电源的转换效率就会越高。</td></tr></tbody></table><h2 id="降压式-buck">降压式 Buck</h2><h3 id="拓扑结构-1">拓扑结构</h3><p><strong>降压式变换器</strong>（BuckConverter）用于将较高的直流电压转换为较低的直流电压，由于其损耗小效率高，因而应用十分广泛，其拓扑结构如下图所示。其中<span class="math inline">\(U_I\)</span>表示<strong>直流输入电压</strong>，<span class="math inline">\(VT\)</span> 是<strong>功率开关管</strong>，<span class="math inline">\(VD\)</span> 为<strong>续流二极管</strong>，<span class="math inline">\(L\)</span> 是输出<strong>储能电感</strong>，<span class="math inline">\(C\)</span> 是输出<strong>滤波电容</strong>，<span class="math inline">\(U_O\)</span>表示直流<strong>输出电压</strong>，<span class="math inline">\(R_L\)</span> 表示外部<strong>负载电阻</strong>，而<strong>PWM 脉宽调制器</strong>则用于控制功率开关管 <span class="math inline">\(VT\)</span> 的导通与关断，是整个 Buck变换器的控制核心：</p><p><img src="/Electronics/Power-Switching/4-Buck/1.png"></p><h3 id="工作原理">工作原理</h3><p>降压式变换器的<strong>功率开关管</strong> <span class="math inline">\(VT\)</span> 在 PWM脉宽调制器的控制之下，交替进行导通与关断。为了更加直观的分析电路，在接下来的示意图当中，会使用<strong>开关</strong><span class="math inline">\(S\)</span> 来代替 <span class="math inline">\(VT\)</span> 的 <code>导通</code> 和<code>关断</code> 状态：</p><p><img src="/Electronics/Power-Switching/4-Buck/2.png"></p><p>当<strong>功率开关管</strong> <span class="math inline">\(VT\)</span>导通，也就是<strong>开关</strong> <span class="math inline">\(S\)</span>闭合的时候，<strong>续流二极管</strong> <span class="math inline">\(VD\)</span> 截止，<strong>输入电压</strong> <span class="math inline">\(U_I\)</span> 施加到<strong>储能电感</strong> <span class="math inline">\(L\)</span> 的左端，此时电感两端的电压等于 <span class="math inline">\(U_I - U_O\)</span>，使得通过 <span class="math inline">\(L\)</span> 的<strong>电流</strong> <span class="math inline">\(I_L\)</span>线性增加，电感储存的能量也随之增加，电感的感应电动势为左 <code>+</code>右 <code>-</code>。在此期间，<strong>电感电流</strong> <span class="math inline">\(I_L\)</span>一部分会为负载供电，另外一部分会给<strong>滤波电容</strong> <span class="math inline">\(C\)</span> 充电，即<strong>电感电流</strong> <span class="math inline">\(I_L\)</span> 等于电容 <span class="math inline">\(C\)</span> 的<strong>充电电流</strong> <span class="math inline">\(I_1\)</span>，与负载 <span class="math inline">\(R_L\)</span> 所<strong>消耗电流</strong> <span class="math inline">\(I_O\)</span> 的总和。</p><p><img src="/Electronics/Power-Switching/4-Buck/3.png"></p><p>当<strong>功率开关管</strong> <span class="math inline">\(VT\)</span>关断，也就是<strong>开关</strong> <span class="math inline">\(S\)</span>断开的时候，<strong>储能电感</strong> <span class="math inline">\(L\)</span> 与<strong>输入电压</strong> <span class="math inline">\(U_I\)</span>断开。由于电感当中的电流不能发生突变，因而就会在 <span class="math inline">\(L\)</span> 上就产生左 <code>-</code> 右<code>+</code> 的感应电压，以维持<strong>电感电流</strong> <span class="math inline">\(I_L\)</span>不发生改变。这种情况下，<strong>续流二极管</strong> <span class="math inline">\(VD\)</span> 将会导通，导致储存在电感 <span class="math inline">\(L\)</span>里的磁场能量被转化为电能，经由续流二极管 <span class="math inline">\(VD\)</span>构成的回路继续向负载供电，此时<strong>电感电流</strong> <span class="math inline">\(I_L\)</span> 线性减少，<strong>滤波电容</strong><span class="math inline">\(C\)</span> 释放的电流 <span class="math inline">\(I_2\)</span> 与<strong>电感电流</strong> <span class="math inline">\(I_L\)</span> 叠加之后为<strong>负载</strong> <span class="math inline">\(R_L\)</span>供电。换而言之，<strong>负载</strong>两端的<strong>输出电流</strong><span class="math inline">\(I_O\)</span> 等于<strong>电感电流</strong><span class="math inline">\(I_L\)</span> 与<strong>电容释放电流</strong><span class="math inline">\(I_2\)</span> 之和。</p><blockquote><p><strong>注意</strong>：由于降压式 DC-DC变换器是在功率开关管<strong>导通</strong>时向负载传输能量，因而属于一种<strong>正激型变换器</strong>。</p></blockquote><h3 id="波形分析">波形分析</h3><p>降压式 DC-DC变换器相关的<strong>电压</strong>与<strong>电流</strong>波形如下图所示，其中PWM 指示的是脉宽调制波形（<span class="math inline">\(t_{ON}\)</span>为功率开关管 <span class="math inline">\(VT\)</span>的<strong>导通时间</strong>，<span class="math inline">\(t_{OFF}\)</span> 为功率开关管 <span class="math inline">\(VT\)</span> 的<strong>关断时间</strong>，而 <span class="math inline">\(T\)</span> 表示<strong>开关周期</strong>，其值等于<span class="math inline">\(t_{ON}\)</span> 与 <span class="math inline">\(t_{OFF}\)</span> 之和 <span class="math inline">\(T = t_{ON} + t_{OFF}\)</span>，其中 <span class="math inline">\(t_{ON}\)</span> 与 <span class="math inline">\(T\)</span> 的比值就是<strong>占空比</strong> <span class="math inline">\(D = \frac{t_{ON}}{T}\)</span>）：</p><p><img src="/Electronics/Power-Switching/4-Buck/4.png"></p><p>除此之外，<span class="math inline">\(U_E\)</span>表示的是<strong>功率开关管</strong> <span class="math inline">\(VT\)</span> 的发射极电压波形，<span class="math inline">\(I_C\)</span> 表示的是<strong>功率开关管</strong><span class="math inline">\(VT\)</span> 的集电极电流波形，<span class="math inline">\(I_F\)</span> 表示的是<strong>续流二极管</strong><span class="math inline">\(VD\)</span> 的电流波形，<span class="math inline">\(I_L\)</span> 表示的是<strong>储能电感</strong><span class="math inline">\(L\)</span> 的电流波形。</p><p>观察可以发现，当<strong>功率开关管</strong> <span class="math inline">\(VT\)</span>导通的时候，其<strong>发射极电压</strong> <span class="math inline">\(U_E\)</span> 等于<strong>输入电压</strong> <span class="math inline">\(U_I\)</span>。而在<strong>功率开关管</strong><span class="math inline">\(VT\)</span>关断时，其<strong>发射极电压</strong> <span class="math inline">\(U_E\)</span> 等于<strong>零</strong>。在功率开关管<span class="math inline">\(VT\)</span>导通期间，<strong>电感电流</strong> <span class="math inline">\(I_L\)</span>线性增加。而在<strong>功率开关管</strong> <span class="math inline">\(VT\)</span> 关断期间，<strong>电感电流</strong><span class="math inline">\(I_L\)</span>线性减小。<strong>电感电流</strong> <span class="math inline">\(I_L\)</span> 是由 <span class="math inline">\(VT\)</span> 的<strong>集电极电流</strong> <span class="math inline">\(I_C\)</span> 和续流二极管 <span class="math inline">\(VD\)</span> 的<strong>正向电流</strong> <span class="math inline">\(I_F\)</span> 叠加而成。</p><p>降压式 DC-DC 变换器的<strong>输出电流</strong> <span class="math inline">\(I_O\)</span> 等于<strong>储能电感电流</strong><span class="math inline">\(I_L\)</span>的平均值。在上述的电感电流波形当中，<strong>峰值</strong>与<strong>谷值</strong>之间的差值就是电感的<strong>纹波电流</strong>（即电感电流在开关周期内的<strong>峰峰值</strong>波动），为了降低输出电流的纹波，储能电感<span class="math inline">\(L\)</span> 应当选择得足够大，从而使得降压式Buck 变换器能够工作在<strong>连续模式</strong>。</p><blockquote><p><strong>注意</strong>：通常情况下，<strong>纹波电流值</strong>应当处于<strong>额定输出电流</strong>的<code>20%</code> 左右。</p></blockquote><h3 id="总结">总结</h3><p>降压式 Buck 变换器，具备有如下四个特点：</p><ol type="1"><li>因为<strong>输出电压</strong> <span class="math inline">\(U_O\)</span> 小于<strong>输入电压</strong> <span class="math inline">\(U_I\)</span>，所以被称为<strong>降压式变换器</strong>。</li><li><strong>输出电压</strong> <span class="math inline">\(U_O\)</span>与<strong>输入电压</strong> <span class="math inline">\(U_I\)</span>之间的关系为 <span class="math inline">\(U_O = D \timesU_I\)</span>，由此可见通过控制<strong>占空比</strong> <span class="math inline">\(D\)</span>的大小，就能够调整输出电压，并且<strong>输出电压</strong> <span class="math inline">\(U_O\)</span> 与<strong>输入电压</strong> <span class="math inline">\(U_I\)</span> 的极性相同。</li><li><strong>功率开关管</strong> <span class="math inline">\(VT\)</span><strong>集电极</strong>与<strong>发射极</strong>之间所承受的最大电压<span class="math inline">\(U_{CE}=U_{I}\)</span>，最大<strong>集电极</strong>电流<span class="math inline">\(I_C = I_O\)</span>。</li><li><strong>续流二极管</strong> <span class="math inline">\(VD\)</span>通过的<strong>正向电流</strong> <span class="math inline">\(I_F = (1-D)\times I_O\)</span>，<strong>反向电压</strong> <span class="math inline">\(U_R = U_I\)</span>。</li></ol><h2 id="升压式-boost">升压式 Boost</h2><h3 id="拓扑结构-2">拓扑结构</h3><p><strong>升压式变换器</strong>（BoostConverter）用于将较低的直流电压转换为较高的直流电压，其基本拓扑结构如下图所示（注意其与降压式Buck 变换器的区别）。其中 <span class="math inline">\(U_I\)</span> 和<span class="math inline">\(U_O\)</span>分别为直流的<strong>输入电压</strong>和<strong>输出电压</strong>，而<span class="math inline">\(VT\)</span>是<strong>功率开关管</strong>，<span class="math inline">\(VD\)</span>是<strong>续流二极管</strong>（也称作<strong>升压二极管</strong>），<span class="math inline">\(L\)</span>是<strong>储能电感</strong>（也称为<strong>升压电感</strong>），<span class="math inline">\(C\)</span> 是<strong>输出滤波电容</strong>，<span class="math inline">\(R_L\)</span> 为外部<strong>负载电阻</strong>。而<strong>PWM脉宽调制器</strong>作为整个系统的核心，用于控制<strong>功率开关管</strong><span class="math inline">\(VT\)</span> 的导通与关断。</p><p><img src="/Electronics/Power-Switching/5-Boost/1.png"></p><h3 id="工作原理-1">工作原理</h3><p>升压式 DC-DC 变换器的<strong>功率开关管</strong> <span class="math inline">\(VT\)</span> 会在 PWM脉宽调制信号的控制之下，交替的进行<strong>导通</strong>与<strong>关断</strong>，相当于一个不断闭合与断开的机械<strong>开关</strong><span class="math inline">\(S\)</span>，其工作原理如下图所示：</p><p><img src="/Electronics/Power-Switching/5-Boost/2.png"></p><p>当<strong>功率开关管</strong> <span class="math inline">\(VT\)</span>导通（即上图当中的<strong>开关</strong> <span class="math inline">\(S\)</span> 闭合）的时候，<strong>输入电压</strong><span class="math inline">\(U_I\)</span>直接施加到<strong>储能电感</strong> <span class="math inline">\(L\)</span> 的两端，此刻<strong>续流二极管</strong><span class="math inline">\(VD\)</span> 反向截止。由于电感 <span class="math inline">\(L\)</span> 上被施加了<strong>输入电压</strong><span class="math inline">\(U_I\)</span>，使得通过其的电流 <span class="math inline">\(I_L\)</span>线性增加，电感储存的能量随之增加，此时电感上产生的感应电动势为左<code>+</code> 右<code>-</code>。在这段时间内，输入电流提供的能量以<strong>磁场能量</strong>的形式存储在<strong>储能电感</strong><span class="math inline">\(L\)</span>当中。同时<strong>滤波电容</strong> <span class="math inline">\(C\)</span> 放电为<strong>负载电阻</strong> <span class="math inline">\(R_L\)</span> 提供<strong>输出电流</strong> <span class="math inline">\(I_O\)</span>，<strong>输出滤波电容</strong> <span class="math inline">\(C\)</span> 所释放的电流 <span class="math inline">\(I_1\)</span>，等于<strong>负载电阻</strong> <span class="math inline">\(R_L\)</span> 上获得的<strong>输出电流</strong><span class="math inline">\(I_O\)</span>。</p><p><img src="/Electronics/Power-Switching/5-Boost/3.png"></p><p>当<strong>功率开关管</strong> <span class="math inline">\(VT\)</span>关断（即上图当中的开关 <span class="math inline">\(S\)</span>断开）的时候，因为<strong>电感当中的电流不能发生突变</strong>，所以<strong>储能电感</strong><span class="math inline">\(L\)</span> 上会产生左 <code>-</code> 右<code>+</code> 的感应电压，以维持<strong>电感电流</strong> <span class="math inline">\(I_L\)</span>不会发生改变。此时<strong>续流二极管</strong> <span class="math inline">\(VD\)</span> 导通，电感 <span class="math inline">\(L\)</span>上的感应电动势与<strong>输入电压</strong> <span class="math inline">\(U_I\)</span> 串联合并到一起，储存在电感 <span class="math inline">\(L\)</span>当中的磁场能量被转化为电能，从而能够以超过输入电压 <span class="math inline">\(U_I\)</span>的电压向负载进行供电，并且对<strong>输出滤波电容</strong> <span class="math inline">\(C\)</span>进行充电，此时<strong>储能电感</strong>上通过的电流 <span class="math inline">\(I_L\)</span> 等于电容上的<strong>充电电流</strong><span class="math inline">\(I_2\)</span> 与<strong>负载电流</strong><span class="math inline">\(I_O\)</span> 之和。</p><blockquote><p><strong>注意</strong>：由于升压式 DC-DC变换器是在功率开关管<strong>关断</strong>时向负载传输能量，因而属于一种<strong>反激型变换器</strong>。</p></blockquote><h3 id="波形分析-1">波形分析</h3><p>升压式 DC-DC变换器相关的<strong>电压</strong>与<strong>电流</strong>波形如下图所示，其中PWM 表示的是脉宽调制波形（其中 <span class="math inline">\(t_{ON}\)</span> 和 <span class="math inline">\(t_{OFF}\)</span> 分别是功率开关管 <span class="math inline">\(VT\)</span>的<strong>导通时间</strong>和<strong>关断时间</strong>，而 <span class="math inline">\(T\)</span>表示的是<strong>开关周期</strong>）。<span class="math inline">\(U_C\)</span> 为功率开关管 <span class="math inline">\(VT\)</span> 的<strong>集电极电压</strong>波形，而<span class="math inline">\(I_C\)</span>为其<strong>集电极电流</strong>波形。<span class="math inline">\(I_F\)</span> 为<strong>升压二极管</strong> <span class="math inline">\(VD\)</span> 的正向电流波形，<span class="math inline">\(I_L\)</span> 则为<strong>储能电感</strong> <span class="math inline">\(L\)</span> 上经过的电流波形：</p><p><img src="/Electronics/Power-Switching/5-Boost/4.png"></p><p>观察上述波形可以发现，当<strong>功率开关管</strong> <span class="math inline">\(VT\)</span>导通的时候，其<strong>集电极电压</strong> <span class="math inline">\(U_C\)</span> 为零。而在<strong>功率开关管</strong><span class="math inline">\(VT\)</span>关断的时候，其<strong>集电极电压</strong> <span class="math inline">\(U_C\)</span> 等于<strong>输出电压</strong> <span class="math inline">\(U_O\)</span>。在<strong>功率开关管</strong> <span class="math inline">\(VT\)</span> 导通期间，电感电流线性增加，而在 <span class="math inline">\(VT\)</span>关断期间，电感电流线性的减小。此时<strong>电感电流</strong> <span class="math inline">\(I_L\)</span> 是由<strong>功率开关管</strong> <span class="math inline">\(VT\)</span> 的<strong>集电极电流</strong> <span class="math inline">\(I_C\)</span>，以及<strong>升压二极管</strong><span class="math inline">\(VD\)</span> 的<strong>正向电流</strong><span class="math inline">\(I_F\)</span> 叠加而成。</p><h3 id="总结-1">总结</h3><p>升压式 Boost 变换器，也具备有如下四个特点：</p><ol type="1"><li>因为<strong>输出电压</strong> <span class="math inline">\(U_O\)</span> 大于<strong>输入电压</strong> <span class="math inline">\(U_I\)</span>，所以被称为<strong>升压式变换器</strong>。</li><li><strong>输出电压</strong> <span class="math inline">\(U_O\)</span>与<strong>输入电压</strong> <span class="math inline">\(U_I\)</span>的关系为 <span class="math inline">\(U_O = \frac{U_I}{1 -D}\)</span>，由此可见通过调节<strong>占空比</strong> <span class="math inline">\(D\)</span>的大小，就能够控制输出电压，并且<strong>输出电压</strong> <span class="math inline">\(U_O\)</span> 与<strong>输入电压</strong> <span class="math inline">\(U_I\)</span> 的极性相同。</li><li><strong>功率开关管</strong> <span class="math inline">\(VT\)</span><strong>集电极</strong>与<strong>发射极</strong>之间所承受的最大电压<span class="math inline">\(U_{CE}=U_{O}\)</span>，最大<strong>集电极</strong>电流<span class="math inline">\(I_C = \frac{I_O}{1 - D}\)</span>。</li><li><strong>升压二极管</strong> <span class="math inline">\(VD\)</span>通过的<strong>正向电流</strong> <span class="math inline">\(I_F =I_O\)</span>，<strong>反向电压</strong> <span class="math inline">\(U_R= U_O\)</span>。</li></ol><h2 id="升降压式-buck-boost">升降压式 Buck-Boost</h2><h3 id="拓扑结构-3">拓扑结构</h3><p><strong>降压升压式变换器</strong>（Buck-Boost Converter）的<code>输入电压</code> 与 <code>输出电压</code>的<strong>极性</strong>相反，因而也被称作<strong>极性反转式变换器</strong>。这种变换器的效率比较高，同时极性可以变换，并且同时具备降压和升压的功能。适用于需要电源极性变换，以及各类通过电池供电的场景，其基本拓扑结构如下图所示：</p><p><img src="/Electronics/Power-Switching/6-Buck-Boost/1.png"></p><p>同样的，上面电路当中的 <span class="math inline">\(U_I\)</span>表示<strong>直流输入电压</strong>，<span class="math inline">\(VT\)</span> 是<strong>功率开关管</strong>，<span class="math inline">\(VD\)</span> 为<strong>续流二极管</strong>，<span class="math inline">\(L\)</span> 是输出<strong>储能电感</strong>，<span class="math inline">\(C\)</span> 是输出<strong>滤波电容</strong>，<span class="math inline">\(U_O\)</span>表示直流<strong>输出电压</strong>，<span class="math inline">\(R_L\)</span> 表示外部<strong>负载电阻</strong>，而<strong>PWM 脉宽调制器</strong>则用于控制功率开关管 <span class="math inline">\(VT\)</span> 的导通与关断，同样是整个 Buck-Boost变换器的控制核心。</p><h3 id="工作原理-2">工作原理</h3><p>降压升压式变换器的<strong>功率开关管</strong> <span class="math inline">\(VT\)</span> 在 PWM脉宽调制器的控制之下，交替进行导通与关断。为了更加直观的分析电路，在接下来的示意图当中，会使用<strong>开关</strong><span class="math inline">\(S\)</span> 来代替 <span class="math inline">\(VT\)</span> 的 <code>导通</code> 和<code>关断</code> 状态：</p><p><img src="/Electronics/Power-Switching/6-Buck-Boost/2.png"></p><p>当<strong>功率开关管</strong> <span class="math inline">\(VT\)</span>导通，也就是<strong>开关</strong> <span class="math inline">\(S\)</span>闭合的时候，<strong>续流二极管</strong> <span class="math inline">\(VD\)</span>处于截止状态，<strong>输入电压</strong> <span class="math inline">\(U_I\)</span> 直接施加到<strong>储能电感</strong><span class="math inline">\(L\)</span> 的两端，使得通过 <span class="math inline">\(L\)</span> 的<strong>电流</strong> <span class="math inline">\(I_L\)</span>线性增加，电感储存的能量也随之增加，电感的感应电动势为上 <code>+</code>下 <code>-</code>，<strong>输入电流</strong> <span class="math inline">\(U_I\)</span>的能量被转换为磁场能量，被存储在<strong>储能电感</strong> <span class="math inline">\(L\)</span>当中。与此同时，如果<strong>输出滤波电容</strong> <span class="math inline">\(C\)</span>当中存储有上一次充入的电能，那么就会开始放电为负载 <span class="math inline">\(R_L\)</span> 提供<strong>输出电流</strong> <span class="math inline">\(I_O\)</span>，此时电容 <span class="math inline">\(C\)</span> 的<strong>放电电流</strong> <span class="math inline">\(I_1\)</span> 就等于<strong>输出电流</strong> <span class="math inline">\(I_O\)</span>。</p><p><img src="/Electronics/Power-Switching/6-Buck-Boost/3.png"></p><p>当<strong>功率开关管</strong> <span class="math inline">\(VT\)</span>关断，也就是<strong>开关</strong> <span class="math inline">\(S\)</span>断开的时候，由于<strong>储能电感</strong> <span class="math inline">\(L\)</span>当中的电流不能发生突变，因而会产生一个上 <code>-</code> 下<code>+</code> 的感应电压，以维持通过电感器的电流 <span class="math inline">\(I_L\)</span> 不变，此时<strong>续流二极管</strong><span class="math inline">\(VD\)</span> 被导通，储存在 <span class="math inline">\(L\)</span>当中的磁场能量转化为电能，开始对<strong>输出滤波电容</strong> <span class="math inline">\(C\)</span> 进行充电，并向负载电阻 <span class="math inline">\(R_L\)</span>提供电流。这种情况下电感上通过的<strong>电流</strong> <span class="math inline">\(I_L\)</span>，将会等于<strong>电容充电电流</strong><span class="math inline">\(I_2\)</span> 与<strong>输出电流</strong><span class="math inline">\(I_O\)</span> 之和。</p><blockquote><p><strong>注意</strong>：由于降压升压式 DC-DC变换器是在功率开关管<strong>关断</strong>时向负载传输能量，因而属于一种<strong>反激型变换器</strong>。</p></blockquote><h3 id="波形分析-2">波形分析</h3><p>降压升压式 DC-DC变换器相关的<strong>电压</strong>与<strong>电流</strong>波形如下图所示，其中PWM 表示的是脉宽调制波形（其中 <span class="math inline">\(t_{ON}\)</span> 和 <span class="math inline">\(t_{OFF}\)</span> 分别是功率开关管 <span class="math inline">\(VT\)</span>的<strong>导通时间</strong>和<strong>关断时间</strong>，而 <span class="math inline">\(T\)</span>表示的是<strong>开关周期</strong>）。<span class="math inline">\(U_E\)</span> 为功率开关管 <span class="math inline">\(VT\)</span> 的<strong>发射极电压</strong>波形，而<span class="math inline">\(I_C\)</span>为其<strong>集电极电流</strong>波形。<span class="math inline">\(I_F\)</span> 为<strong>续流二极管</strong> <span class="math inline">\(VD\)</span> 的正向电流波形，<span class="math inline">\(I_L\)</span> 则为<strong>储能电感</strong> <span class="math inline">\(L\)</span> 上经过的电流波形：</p><p><img src="/Electronics/Power-Switching/6-Buck-Boost/4.png"></p><p>观察上述波形可以发现，当<strong>功率开关管</strong> <span class="math inline">\(VT\)</span>导通的时候，其<strong>发射极电压</strong> <span class="math inline">\(U_E\)</span> 等于<strong>输入电压</strong> <span class="math inline">\(U_I\)</span>。而在<strong>功率开关管</strong><span class="math inline">\(VT\)</span>关断的时候，其<strong>发射极电压</strong> <span class="math inline">\(U_E\)</span> 等于<strong>输出电压</strong> <span class="math inline">\(U_O\)</span>（极性相反）。而在<strong>功率开关管</strong><span class="math inline">\(VT\)</span>导通期间，电感上的电流线性增加。而在 <span class="math inline">\(VT\)</span>关断期间，电感上的电流又线性的减少。此时<strong>电感电流</strong> <span class="math inline">\(I_L\)</span> 是由<strong>功率开关管</strong> <span class="math inline">\(VT\)</span> 的<strong>集电极电流</strong> <span class="math inline">\(I_C\)</span>，以及<strong>续流二极管</strong><span class="math inline">\(VD\)</span> 的<strong>正向电流</strong><span class="math inline">\(I_F\)</span> 叠加而成。</p><h3 id="总结-2">总结</h3><p>降压升压式 Buck-Boost 变换器，同样具备有下面的四个特点：</p><ol type="1"><li>因为<strong>输出电压</strong> <span class="math inline">\(U_O\)</span>可以大于和小于<strong>输入电压</strong> <span class="math inline">\(U_I\)</span>，所以被称为<strong>降压升压式变换器</strong>。</li><li><strong>输出电压</strong> <span class="math inline">\(U_O\)</span>与<strong>输入电压</strong> <span class="math inline">\(U_I\)</span>的关系为 <span class="math inline">\(U_O = -D \frac{U_I}{(1 -D)}\)</span>，由此可见通过调节<strong>占空比</strong> <span class="math inline">\(D\)</span>就能控制输出电压，并且<strong>输出电压</strong> <span class="math inline">\(U_O\)</span> 会与<strong>输入电压</strong> <span class="math inline">\(U_I\)</span> 的<strong>极性相反</strong>。</li><li><strong>功率开关管</strong> <span class="math inline">\(VT\)</span><strong>集电极</strong>与<strong>发射极</strong>之间能承受的最大电压<span class="math inline">\(U_{CE}=U_I -U_O\)</span>（由于这里<strong>输出电压</strong> <span class="math inline">\(U_O\)</span> 为负电压，所以 <span class="math inline">\(U_{CE}\)</span>实质上等于两者的绝对值之和）。</li><li><strong>功率开关管</strong> <span class="math inline">\(VT\)</span>的<strong>集电极</strong>最大电流 <span class="math inline">\(I_C =\frac{I_O}{1 - D}\)</span>。</li><li><strong>续流二极管</strong> <span class="math inline">\(VD\)</span>通过的<strong>正向电流</strong> <span class="math inline">\(I_F =I_O\)</span>。</li><li><strong>续流二极管</strong> <span class="math inline">\(VD\)</span>两端承受的<strong>反向电压</strong> <span class="math inline">\(U_R =U_I - U_O\)</span>（由于此处的<strong>输出电压</strong> <span class="math inline">\(U_O\)</span> 是负电压，所以 <span class="math inline">\(U_R\)</span>实质上等于输入与输出电压的绝对值之和）。</li></ol><h2 id="反激式-flyback">反激式 Flyback</h2><h3 id="拓扑结构-4">拓扑结构</h3><p><strong>反激式变换器</strong>（FlybackConverter）也称为<strong>回扫式变换器</strong>，其具有电路结构简单成本低廉，并且输入与输出电气隔离的特点，广泛应用于消费类电子产品的电源适配器，其基本拓扑结构如下图所示。其中<span class="math inline">\(U_I\)</span> 和 <span class="math inline">\(U_O\)</span>分别表示直流的<strong>输入电压</strong>与<strong>输出电压</strong>，<span class="math inline">\(VT\)</span> 表示<strong>功率开关管</strong>，<span class="math inline">\(VD\)</span>表示输出<strong>整流二极管</strong>，<span class="math inline">\(C\)</span>表示<strong>输出滤波电容</strong>，<span class="math inline">\(R_L\)</span>表示外部的<strong>负载电阻</strong>。而 <span class="math inline">\(T\)</span>表示的是<strong>高频变压器</strong>（<span class="math inline">\(N_P\)</span> 为<strong>初级绕组</strong>，<span class="math inline">\(N_S\)</span>为<strong>次级绕组</strong>，两者极性相反，<strong>同名端</strong>位置如图所示），同样的<strong>PWM脉宽调制器</strong>作为整个系统的核心，用于控制<strong>功率开关管</strong><span class="math inline">\(VT\)</span> 的导通与关断：</p><p><img src="/Electronics/Power-Switching/7-Flyback/1.png"></p><h3 id="工作原理-3">工作原理</h3><p>反激式 DC-DC 变换器的<strong>功率开关管</strong> <span class="math inline">\(VT\)</span> 会在 PWM脉宽调制信号的控制之下，交替的进行<strong>导通</strong>与<strong>关断</strong>，相当于一个不断闭合与断开的机械<strong>开关</strong><span class="math inline">\(S\)</span>，其基本工作原理如下图所示：</p><p><img src="/Electronics/Power-Switching/7-Flyback/2.png"></p><p>当<strong>功率开关管</strong> <span class="math inline">\(VT\)</span>导通（即上图当中的<strong>开关</strong> <span class="math inline">\(S\)</span> 闭合）的时候，<strong>输入电压</strong><span class="math inline">\(U_I\)</span>直接施加到高频变压器<strong>初级绕组</strong> <span class="math inline">\(N_P\)</span> 的两端，使得上面通过的电流 <span class="math inline">\(I_P\)</span>线性增加，初级绕组上的<strong>感应电动势</strong>为上 <code>+</code> 下<code>-</code>，初级绕组上电流 <span class="math inline">\(I_P\)</span>产生的能量以磁场形式存储在高频变压器当中。此时根据电磁感应原理，高频变压器<strong>次级绕组</strong><span class="math inline">\(N_S\)</span> 两端的感应电压为上<code>-</code> 下 <code>+</code>，导致输出<strong>整流二极管</strong><span class="math inline">\(VD\)</span>截止，同时输出<strong>滤波电容</strong> <span class="math inline">\(C\)</span>开始放电，从而为<strong>负载电阻</strong> <span class="math inline">\(R_L\)</span> 提供<strong>输出电流</strong> <span class="math inline">\(I_O\)</span>，此时<strong>输出电容</strong> <span class="math inline">\(C\)</span> 所释放的电流 <span class="math inline">\(I_1\)</span> 与<strong>输出电流</strong> <span class="math inline">\(I_O\)</span> 相等。</p><p><img src="/Electronics/Power-Switching/7-Flyback/3.png"></p><p>当<strong>功率开关管</strong> <span class="math inline">\(VT\)</span>关断（即上图当中的<strong>开关</strong> <span class="math inline">\(S\)</span> 断开）的时候，<strong>初级绕组</strong><span class="math inline">\(N_P\)</span> 上通过的<strong>电流</strong><span class="math inline">\(I_P\)</span>突然断开，根据电磁感应原理，此时会在<strong>初级绕组</strong> <span class="math inline">\(N_P\)</span>上产生反极性的感应电压（即<strong>反射电压</strong> <span class="math inline">\(U_{OR}\)</span>），进而导致<strong>次级绕组</strong><span class="math inline">\(N_S\)</span> 上产生了上 <code>+</code> 下<code>-</code> 的<strong>感应电压</strong> <span class="math inline">\(U_S\)</span>，使得输出<strong>整流二极管</strong><span class="math inline">\(VD\)</span> 导通，<strong>次级绕组</strong><span class="math inline">\(N_S\)</span> 上开始产生<strong>电流</strong><span class="math inline">\(I_S\)</span>（即<strong>整流二极管</strong><span class="math inline">\(VD\)</span> 上通过的正向电流 <span class="math inline">\(I_F\)</span>），该电流一方面会对输出<strong>滤波电容</strong><span class="math inline">\(C\)</span>进行充电，另一方面也会向<strong>负载电阻</strong> <span class="math inline">\(R_L\)</span>进行供电，此时<strong>次级绕组</strong> <span class="math inline">\(N_S\)</span> 上通过的电流 <span class="math inline">\(I_S\)</span> 等于<strong>输出电容</strong> <span class="math inline">\(C\)</span> 上的充电<strong>电流</strong> <span class="math inline">\(I_2\)</span> 与<strong>输出电流</strong> <span class="math inline">\(I_O\)</span> 之和。</p><blockquote><p><strong>注意</strong>：由于反激式变换器是在功率开关管<strong>关断</strong>的时候，向负载传输能量，因而属于一种比较典型的<strong>反激型变换器</strong>。</p></blockquote><h3 id="波形分析-3">波形分析</h3><p>反激式 DC-DC变换器相关的<strong>电压</strong>与<strong>电流</strong>波形如下图所示，其中PWM 表示的是<strong>脉冲宽度调制</strong>的波形（其中 <span class="math inline">\(t_{ON}\)</span> 和 <span class="math inline">\(t_{OFF}\)</span> 分别是功率开关管 <span class="math inline">\(VT\)</span>的<strong>导通时间</strong>和<strong>关断时间</strong>，而 <span class="math inline">\(T\)</span>表示的是<strong>开关周期</strong>）。<span class="math inline">\(U_C\)</span> 为功率开关管 <span class="math inline">\(VT\)</span>的<strong>集电极电压</strong>波形，最后的 <span class="math inline">\(I_S\)</span>为<strong>次级绕组</strong>的电流波形（即功率开关管 <span class="math inline">\(VT\)</span>的<strong>集电极电流</strong>波形），而 <span class="math inline">\(U_S\)</span> 则表示的是<strong>次级绕组</strong><span class="math inline">\(N_S\)</span> 的电压波形：</p><p><img src="/Electronics/Power-Switching/7-Flyback/4.png"></p><p>观察上述波形可以发现，当<strong>功率开关管</strong> <span class="math inline">\(VT\)</span>导通的时候，其<strong>集电极电压</strong> <span class="math inline">\(U_C\)</span> 为零。而在<strong>功率开关管</strong><span class="math inline">\(VT\)</span>关断的时候，其<strong>集电极电压</strong> <span class="math inline">\(U_C\)</span> 将会高于<strong>输入电压</strong><span class="math inline">\(U_I\)</span>，这是由于<strong>初级绕组</strong><span class="math inline">\(N_P\)</span> 上产生了上 <code>-</code> 下<code>+</code> 的<strong>反射电压</strong> <span class="math inline">\(U_{OR}\)</span>，其与<strong>输入电压</strong><span class="math inline">\(U_I\)</span> 叠加之后，使得功率开关管 <span class="math inline">\(VT\)</span> 的<strong>集电极电压</strong> <span class="math inline">\(U_C\)</span> 增大。</p><p><strong>功率开关管</strong> <span class="math inline">\(VT\)</span>导通期间，<strong>初级绕组</strong> <span class="math inline">\(N_P\)</span> 上经过的<strong>电流</strong> <span class="math inline">\(I_P\)</span>线性的增加，传输的能量会以磁场的形式存储在<strong>高频变压器</strong><span class="math inline">\(T\)</span>当中，此时<strong>次级绕组</strong> <span class="math inline">\(N_S\)</span> 上的<strong>电压</strong> <span class="math inline">\(U_S\)</span>为负值。而当<strong>功率开关管</strong> <span class="math inline">\(VT\)</span> 关断的时候，<strong>初级绕组</strong><span class="math inline">\(N_P\)</span> 上面通过的<strong>电流</strong><span class="math inline">\(I_P\)</span>会立刻减少至零，高频变压器存储的磁场能量会通过<strong>次级绕组</strong><span class="math inline">\(N_S\)</span>释放，次级绕组上的<strong>感应电压</strong> <span class="math inline">\(U_S\)</span> 为上 <code>+</code> 下<code>-</code>，使得<strong>整流二极管</strong> <span class="math inline">\(VD\)</span>被导通，从而在<strong>次级绕组</strong>上产生<strong>电流</strong> <span class="math inline">\(I_S\)</span>，即<strong>整流二极管</strong> <span class="math inline">\(VD\)</span> 上的<strong>正向导通电流</strong><span class="math inline">\(I_F\)</span>。</p><p><strong>功率开关管</strong> <span class="math inline">\(VT\)</span>关断期间，伴随着<strong>高频变压器</strong> <span class="math inline">\(T\)</span>当中所存储磁场能量的释放，<strong>次级绕组</strong> <span class="math inline">\(N_S\)</span> 上的通过的<strong>电流</strong> <span class="math inline">\(I_S\)</span>线性的减少，次级绕组上的<strong>电压</strong> <span class="math inline">\(U_S\)</span> 与<strong>输出电压</strong> <span class="math inline">\(U_O\)</span>相等（波形如上图），<strong>输出电流</strong> <span class="math inline">\(I_O\)</span>为<strong>次级绕组</strong>上<strong>电流</strong> <span class="math inline">\(I_S\)</span> 的平均值。</p><h3 id="总结-3">总结</h3><p>反激式 Flyback 变换器，同样具备有如下四个显著的特点：</p><ol type="1"><li><strong>输出电压</strong> <span class="math inline">\(U_O\)</span>与<strong>输入电压</strong> <span class="math inline">\(U_I\)</span>的关系为 <span class="math inline">\(U_O = \frac{D}{1 - D} \times\frac{N_S}{N_P} \times U_I\)</span>，换而言之，当高频变压器的 <span class="math inline">\(N_P\)</span>、<span class="math inline">\(N_S\)</span>、<span class="math inline">\(U_I\)</span>确定之后，就可以通过调整<strong>占空比</strong> <span class="math inline">\(D\)</span> 的大小来改变输出电压。</li><li><strong>功率开关管</strong> <span class="math inline">\(VT\)</span>承受的最大<strong>集电极-发射极电压</strong> <span class="math inline">\(U_{CE} = U_I + \frac{N_P}{N_S} \timesU_O\)</span>，其中<strong>反射电压</strong> <span class="math inline">\(U_{OR} = \frac{N_P}{N_S} \timesU_O\)</span>（对于交流 <code>220V</code> 输入的开关电源，<span class="math inline">\(U_{OR}\)</span> 的取值应当介于<code>100V ~ 200V</code> 之间，通常取值在 <code>130V</code>左右）。</li><li><strong>功率开关管</strong> <span class="math inline">\(VT\)</span>的<strong>集电极最大电流</strong> <span class="math inline">\(I_C =\frac{N_S}{N_P} \times I_O\)</span>。</li><li><strong>整流二极管</strong> <span class="math inline">\(VD\)</span>的<strong>正向平均电流</strong> <span class="math inline">\(I_F=I_O\)</span>。</li><li><strong>整流二极管</strong> <span class="math inline">\(VD\)</span>所承受的<strong>反向电压</strong> <span class="math inline">\(U_R = U_O+ \frac{N_S}{N_P} \times U_I\)</span>。</li></ol><p>总体而言，反激式 DC-DC变换器的设计比较灵活，例如通过增加<strong>次级绕组的数量</strong>，就可以实现多路输出。如果改变初级绕组与次级绕组的<strong>匝数比</strong>，就可以变身为升压或者降压式的开关电源。</p><blockquote><p><strong>注意</strong>：不能在反激式 DC-DC变换器的<strong>输出整流二极管</strong> <span class="math inline">\(VD\)</span> 与<strong>滤波电容</strong> <span class="math inline">\(C\)</span>之间串联<strong>滤波电感</strong>（抑制高频干扰的磁珠除外），否则会在<strong>初级绕组</strong>上产生极高的<strong>感应电压</strong><span class="math inline">\(U_{OR}\)</span>，造成<strong>功率开关管</strong><span class="math inline">\(VT\)</span> 被击穿损坏。</p></blockquote><h2 id="正激式-forward">正激式 Forward</h2><h3 id="拓扑结构-5">拓扑结构</h3><p><strong>正激式变换器</strong>（Forward Converter）通常应用于<code>100W ~ 300W</code>的中等功率开关电源当中，可以通过<strong>高频变压器</strong>实现输入与输出电气隔离，只拥有一个功率开关管的<strong>单端正激式变换器</strong>的基本拓扑结构如下图所示：</p><p><img src="/Electronics/Power-Switching/8-Forward/1.png"></p><p>其中 <span class="math inline">\(U_I\)</span> 和 <span class="math inline">\(U_O\)</span>分别表示直流的<strong>输入电压</strong>与<strong>输出电压</strong>，<span class="math inline">\(VT\)</span> 表示<strong>功率开关管</strong>，<span class="math inline">\(VD_1\)</span>表示<strong>整流二极管</strong>，<span class="math inline">\(VD_2\)</span>表示<strong>续流二极管</strong>，<span class="math inline">\(VD_3\)</span>则用于为励磁电流提供<strong>泄放回路</strong>，<span class="math inline">\(L\)</span> 是输出<strong>滤波电感</strong>，<span class="math inline">\(C\)</span> 是输出<strong>滤波电容</strong>，<span class="math inline">\(R_L\)</span>表示外部的<strong>负载电阻</strong>，而 <strong>PWM脉宽调制器</strong>依然作为系统的核心，用于控制<strong>功率开关管</strong><span class="math inline">\(VT\)</span>的导通与关断。除此之外，上述拓扑结构当中的 <span class="math inline">\(T\)</span>表示的是<strong>高频变压器</strong>（<span class="math inline">\(N_P\)</span> 为<strong>初级绕组</strong>，<span class="math inline">\(N_S\)</span>为<strong>次级绕组</strong>，两者极性相同，<strong>同名端</strong>位置如图所示），而<span class="math inline">\(N_R\)</span>是<strong>磁复位绕组</strong>（其匝数与<strong>初级绕组</strong> <span class="math inline">\(N_P\)</span>相同，用于在<strong>功率开关管</strong> <span class="math inline">\(VT\)</span>关断期间，泄放励磁电流，从而使得高频变压器完成磁复位）。</p><h3 id="工作原理-4">工作原理</h3><p>正激式 DC-DC 变换器的<strong>功率开关管</strong> <span class="math inline">\(VT\)</span> 同样会在 PWM脉宽调制信号的控制之下，交替的进行<strong>导通</strong>与<strong>关断</strong>，相当于一个不断闭合与断开的机械<strong>开关</strong><span class="math inline">\(S\)</span>，其基本工作原理如下图所示：</p><p><img src="/Electronics/Power-Switching/8-Forward/2.png"></p><p>当<strong>功率开关管</strong> <span class="math inline">\(VT\)</span>导通（即上图当中的<strong>开关</strong> <span class="math inline">\(S\)</span> 闭合）的时候，输入电压 <span class="math inline">\(U_I\)</span> 直接施加到<strong>高频变压器</strong><span class="math inline">\(T\)</span> 的<strong>初级绕组</strong> <span class="math inline">\(N_P\)</span> 的两端，使得初级绕组上的电流 <span class="math inline">\(I_P\)</span>线性的增加，初级绕组上呈现的<strong>感应电动势</strong>为上<code>+</code> 下<code>-</code>。根据电磁感应原理，<strong>高频变压器</strong> <span class="math inline">\(T\)</span> 的<strong>磁复位绕组</strong> <span class="math inline">\(N_R\)</span> 和<strong>次级绕组</strong> <span class="math inline">\(NS\)</span> 两端的感应电压同样为上 <code>+</code>下 <code>-</code>。此时<strong>二极管</strong> <span class="math inline">\(VD_3\)</span>反向截止，<strong>整流二极管</strong> <span class="math inline">\(VD_1\)</span> 导通，<strong>续流二极管</strong><span class="math inline">\(VD_2\)</span> 截止。</p><p><strong>次级绕组</strong> <span class="math inline">\(N_S\)</span>上产生的电压 <span class="math inline">\(U_S\)</span>会施加到输出<strong>滤波电感</strong> <span class="math inline">\(L\)</span>的左端，形成线性增加的次级绕组<strong>电流</strong> <span class="math inline">\(I_S\)</span>（即<strong>整流二极管</strong> <span class="math inline">\(VD_1\)</span> 上的正向导通<strong>电流</strong><span class="math inline">\(I_{F1}\)</span>），导致<strong>滤波电感</strong><span class="math inline">\(L\)</span> 当中储存的能量也在增加，<span class="math inline">\(L\)</span> 上的感应电动势为左 <code>+</code> 右<code>-</code>。这个次级绕组上的<strong>电流</strong> <span class="math inline">\(I_S\)</span> 将为输出<strong>滤波电容</strong><span class="math inline">\(C\)</span>充电，并且为<strong>负载电阻</strong> <span class="math inline">\(R_L\)</span> 提供<strong>输出电流</strong> <span class="math inline">\(I_O\)</span>，此时次级绕组上通过的<strong>电流</strong><span class="math inline">\(I_S\)</span>等于为输出<strong>滤波电容</strong> <span class="math inline">\(C\)</span> 的<strong>充电电流</strong> <span class="math inline">\(I_1\)</span> 与<strong>负载电流</strong> <span class="math inline">\(I_O\)</span> 之和。</p><p><img src="/Electronics/Power-Switching/8-Forward/3.png"></p><p>当<strong>功率开关管</strong> <span class="math inline">\(VT\)</span>关断（即上图当中的<strong>开关</strong> <span class="math inline">\(S\)</span> 断开）的时候，<strong>初级绕组</strong><span class="math inline">\(N_P\)</span>上的电流突然中断，根据电磁感应的原理，此时会在初级绕组上产生反极性的感应电压。与此同时，<strong>高频变压器</strong><span class="math inline">\(T\)</span> 上的<strong>磁复位绕组</strong><span class="math inline">\(N_R\)</span> 和<strong>次级绕组</strong><span class="math inline">\(N_S\)</span> 也会同时产生极性为上<code>-</code> 下 <code>+</code> 的感应电压。此时<strong>二极管</strong><span class="math inline">\(VD_3\)</span>导通，<strong>整流二极管</strong> <span class="math inline">\(VD_1\)</span> 截止。<strong>高频变压器</strong><span class="math inline">\(T\)</span> 的<strong>励磁电流</strong> <span class="math inline">\(I_R\)</span> 将会通过<strong>二极管</strong> <span class="math inline">\(VD_3\)</span> 回馈到电源输入的 <span class="math inline">\(U_I\)</span> 端，并且线性减少至零。</p><p>由于<strong>滤波电感</strong> <span class="math inline">\(L\)</span>当中的电流不能发生突变，整流二极管 <span class="math inline">\(VD_1\)</span> 截止之后，<span class="math inline">\(L\)</span> 上将会产生一个左 <code>-</code> 右<code>+</code> 的感应电压，使得<strong>续流二极管</strong> <span class="math inline">\(VD_2\)</span> 导通，产生正向导通电流 <span class="math inline">\(I_F\)</span>。此时，储存在 <span class="math inline">\(L\)</span>当中的磁场能量就会转换为电能，经过由二极管 <span class="math inline">\(VD_2\)</span> 构成的回路，继续向负载 <span class="math inline">\(R_L\)</span> 供电。伴随着<strong>滤波电感</strong><span class="math inline">\(L\)</span>当中磁场能量的释放，<strong>电流</strong> <span class="math inline">\(I_F\)</span>将会逐渐减小，而输出<strong>滤波电容</strong> <span class="math inline">\(C\)</span> 将会释放<strong>电流</strong> <span class="math inline">\(I_2\)</span>，此时<strong>输出电流</strong> <span class="math inline">\(I_O\)</span> 等于流过电感的<strong>电流</strong><span class="math inline">\(I_F\)</span> 与滤波电容 <span class="math inline">\(C\)</span> 所释放电流之和。</p><p>不同于<strong>反激式变换器</strong>，正激式变换器<strong>初级绕组</strong><span class="math inline">\(N_P\)</span> 上的<strong>电流</strong> <span class="math inline">\(I_P\)</span> 和<strong>次级绕组</strong> <span class="math inline">\(N_S\)</span> 上的<strong>电流</strong> <span class="math inline">\(I_S\)</span>产生的磁场会在<strong>高频变压器</strong> <span class="math inline">\(T\)</span> 当中相互抵消，从而不会导致变压器 <span class="math inline">\(T\)</span> 的磁芯过度磁化，变压器 <span class="math inline">\(T\)</span> 上面也基本不会储存能量。而在功率开关管<span class="math inline">\(VT\)</span> 关断期间，高频变压器 <span class="math inline">\(T\)</span>当中的<strong>励磁电流</strong>将会通过<strong>磁复位绕组</strong> <span class="math inline">\(N_R\)</span> 反馈至输入电源。</p><blockquote><p><strong>注意</strong>：由于正激式变换器是在功率开关管<strong>导通</strong>期间向负载传输能量，因而属于一种比较典型的<strong>正激型变换器</strong>。</p></blockquote><h3 id="波形分析-4">波形分析</h3><p>正激式 DC-DC变换器相关的<strong>电压</strong>与<strong>电流</strong>波形如下图所示，其中PWM 表示的是<strong>脉冲宽度调制</strong>的波形（其中 <span class="math inline">\(t_{ON}\)</span> 和 <span class="math inline">\(t_{OFF}\)</span> 分别是功率开关管 <span class="math inline">\(VT\)</span>的<strong>导通时间</strong>和<strong>关断时间</strong>，而 <span class="math inline">\(T\)</span>表示的是<strong>开关周期</strong>）。<span class="math inline">\(U_C\)</span> 为功率开关管 <span class="math inline">\(VT\)</span>的<strong>集电极电压</strong>波形，最后的 <span class="math inline">\(I_P\)</span>为<strong>初级绕组</strong>的电流波形（即功率开关管 <span class="math inline">\(VT\)</span>的<strong>集电极电流</strong>波形），而 <span class="math inline">\(I_S\)</span> 表示的是<strong>次级绕组</strong><span class="math inline">\(N_S\)</span>上的电流波形（即<strong>整流二极管</strong> <span class="math inline">\(VD_1\)</span> 的正向电流波形），而 <span class="math inline">\(I_F\)</span> 表示的是<strong>续流二极管</strong><span class="math inline">\(VD_2\)</span> 上的电流波形，<span class="math inline">\(U_S\)</span> 表示的是<strong>次级绕组</strong><span class="math inline">\(N_S\)</span> 两端的电压波形。</p><p><img src="/Electronics/Power-Switching/8-Forward/4.png"></p><p>观察上图可以发现，当<strong>功率开关管</strong> <span class="math inline">\(VT\)</span>导通的时候，其<strong>集电极电压</strong> <span class="math inline">\(U_C\)</span>等于零。而在<strong>功率开关管</strong> <span class="math inline">\(VT\)</span>关断的时候，其<strong>集电极电压</strong> <span class="math inline">\(U_C\)</span> 为<strong>输入电压</strong> <span class="math inline">\(U_I\)</span>的两倍。这是由于磁复位期间<strong>初级绕组</strong> <span class="math inline">\(N_P\)</span> 上产生了上 <code>-</code> 下<code>+</code> 的感应电压，该电压与<strong>输入电压</strong> <span class="math inline">\(U_I\)</span> 相等，并且会与 <span class="math inline">\(U_I\)</span>相互叠加，使得<strong>功率开关管</strong> <span class="math inline">\(VT\)</span> 上的<strong>集电极电压</strong> <span class="math inline">\(U_C = 2 \times U_I\)</span>。</p><blockquote><p><strong>注意</strong>：为确保<strong>高频变压器</strong> <span class="math inline">\(T\)</span> 能够完成磁复位，正激式变换器的 PWM信号<strong>占空比</strong> <span class="math inline">\(D\)</span>不能超过<code>50%</code>。为了保留一定的安全余量，通常会将最大占空比限定在<code>45%</code> 以下。</p></blockquote><h3 id="总结-4">总结</h3><p>正激式 Forward 变换器，具有如下几个显著的特点：</p><ol type="1"><li><strong>输出电压</strong> <span class="math inline">\(U_O\)</span>与<strong>输入电压</strong> <span class="math inline">\(U_I\)</span>的关系为 <span class="math inline">\(U_O = D \times U_I \times\frac{N_S}{N_P}\)</span>，通过改变<strong>初级绕组</strong> <span class="math inline">\(N_P\)</span> 与<strong>次级绕组</strong> <span class="math inline">\(N_S\)</span>的匝数比，就可以构成升压式、降压式开关电源，而改变<strong>占空比</strong><span class="math inline">\(D\)</span>就可以调节<strong>输出电压</strong> <span class="math inline">\(U_O\)</span>。</li><li><strong>功率开关管</strong> <span class="math inline">\(VT\)</span>承受的最大<strong>电压</strong> <span class="math inline">\(U_{CE} = 2\times U_I\)</span>。</li><li><strong>功率开关管</strong> <span class="math inline">\(VT\)</span>的最大<strong>集电极电流</strong> <span class="math inline">\(I_C = I_O\times \frac{N_S}{N_P}\)</span>。</li><li>通过<strong>整流二极管</strong> <span class="math inline">\(VD_1\)</span> 的平均<strong>电流</strong> <span class="math inline">\(I_S = D \times I_O\)</span>。</li><li>通过<strong>整流二极管</strong> <span class="math inline">\(VD_1\)</span> 的<strong>反向电压</strong> <span class="math inline">\(U_R = U_O + U_I \times\frac{N_S}{N_P}\)</span>。</li><li>通过<strong>续流二极管</strong> <span class="math inline">\(VD_2\)</span> 的平均正向<strong>电流</strong><span class="math inline">\(I_F = I_O \times (1 - D)\)</span>。</li></ol><blockquote><p><strong>注意</strong>：正激式变换器必须在<strong>整流二极管</strong><span class="math inline">\(VD_1\)</span> 与<strong>滤波电容</strong><span class="math inline">\(C\)</span>之间串联一个<strong>滤波电感</strong> <span class="math inline">\(L\)</span>，由于该电感还会起到储能的作用，因而也被称作<strong>储能电感</strong>。</p></blockquote><h2 id="推挽式-push-pull">推挽式 Push-Pull</h2><h3 id="拓扑结构-6">拓扑结构</h3><p><strong>推挽式变换器</strong>（Push-Pull Converter）主要是通过 2只功率开关管的交替工作来完成转换，可以将其视为 2 个单管正激式 DC-DC变换器的组合，其输出整流滤波电路也与正激式 DC-DC变换器基本相同，其拓扑结构如下图所示：</p><p><img src="/Electronics/Power-Switching/9-Push-Pull/1.png"></p><p>上述拓扑结构当中的 <span class="math inline">\(T\)</span>表示<strong>高频变压器</strong>，其中的 <span class="math inline">\(N_{P1}\)</span> 和 <span class="math inline">\(N_{P2}\)</span>为<strong>初级绕组</strong>（两者匝数相同），<span class="math inline">\(N_{S1}\)</span> 和 <span class="math inline">\(N_{S2}\)</span>为<strong>次级绕组</strong>（两者匝数相同），初级绕组与次级绕组的<strong>极性相同</strong>，并且均带有<strong>中心抽头</strong>，同名端的位置如上图所示。</p><p><span class="math inline">\(VT_1\)</span> 和 <span class="math inline">\(VT_2\)</span> 为功率开关管，<span class="math inline">\(VD_2\)</span> 和 <span class="math inline">\(VD_2\)</span> 为输出整流二极管，<span class="math inline">\(L\)</span> 为输出滤波电感，<span class="math inline">\(C\)</span> 为输出滤波电容，<span class="math inline">\(U_O\)</span> 为直流输出电压，<span class="math inline">\(R_L\)</span>为外部的负载电阻。除此之外，<strong>PWM脉宽调制器</strong>同样作为变换器的核心，用于产生两路<strong>相位差</strong>为<code>180°</code> 的<strong>控制信号</strong> <span class="math inline">\(U_A\)</span> 和 <span class="math inline">\(U_B\)</span>，从而使得<strong>功率开关管</strong><span class="math inline">\(VT_1\)</span> 与 <span class="math inline">\(VT_2\)</span> 交替工作。</p><h3 id="工作原理-5">工作原理</h3><p><strong>PWM 脉宽调制器</strong>产生的两路控制信号 <span class="math inline">\(U_A\)</span> 和 <span class="math inline">\(U_B\)</span> 交替出现，当 <span class="math inline">\(U_A\)</span> 为高电平的时候，相应的 <span class="math inline">\(U_B\)</span>就会为低电平，反之亦然。<strong>功率开关管</strong> <span class="math inline">\(VT_1\)</span> 和 <span class="math inline">\(VT_2\)</span> 在 PWM脉宽调制信号的控制下，交替的导通与关断。为了便于分析，接下来的原理图分别使用了<strong>开关</strong><span class="math inline">\(S_1\)</span> 和 <span class="math inline">\(S_2\)</span>的闭合与关断，来代替<strong>功率开关管</strong> <span class="math inline">\(VT_1\)</span> 和 <span class="math inline">\(VT_2\)</span> 的导通与关断作用。</p><p><img src="/Electronics/Power-Switching/9-Push-Pull/2.png"></p><p>当 <strong>PWM 控制信号</strong> <span class="math inline">\(U_A\)</span>为高电平时，<strong>功率开关管</strong> <span class="math inline">\(VT_1\)</span> 导通（开关 <span class="math inline">\(S_1\)</span> 闭合），而 <span class="math inline">\(VT_2\)</span> 截止（开关 <span class="math inline">\(S_2\)</span>断开），此时的电流路径如上图所示。<strong>输入电压</strong> <span class="math inline">\(U_I\)</span> 施加到<strong>初级绕组</strong> <span class="math inline">\(N_{P1}\)</span> 的两端，使得通过初级绕组的电流<span class="math inline">\(I_{P1}\)</span>线性的增大，<strong>初级绕组</strong> <span class="math inline">\(N_{P1}\)</span> 上的感应电动势为上 <code>-</code>下 <code>+</code>。根据电磁感应原理，<strong>高频变压器</strong> <span class="math inline">\(T\)</span> 的<strong>初级绕组</strong> <span class="math inline">\(N_{P2}\)</span>，<strong>次级绕组</strong> <span class="math inline">\(N_{S1}\)</span> 和 <span class="math inline">\(N_{S2}\)</span> 两端的感应电压同样为上<code>-</code> 下 <code>+</code>，此时后面的<strong>整流二极管</strong><span class="math inline">\(VD_1\)</span> 截止，而 <span class="math inline">\(VD_2\)</span> 导通。</p><p><strong>次级绕组</strong> <span class="math inline">\(N_{S2}\)</span>上产生的<strong>感应电压</strong> <span class="math inline">\(U_{S2}\)</span>施加到输出<strong>滤波电感</strong> <span class="math inline">\(L\)</span>的左端，从而形成线性增加的次级绕组<strong>电流</strong> <span class="math inline">\(I_{S2}\)</span>（即整流二极管 <span class="math inline">\(VD_2\)</span> 的正向导通电流）。与此同时，电感<span class="math inline">\(L\)</span>上储存的能量也在增加，其感应电动势为左 <code>+</code> 右<code>-</code>。<span class="math inline">\(I_{S2}\)</span>为输出<strong>滤波电容</strong> <span class="math inline">\(C\)</span>充电，并且为负载电阻 <span class="math inline">\(R_L\)</span>提供<strong>输出电流</strong> <span class="math inline">\(I_O\)</span>。此时<strong>次级绕组</strong> <span class="math inline">\(N_{S2}\)</span> 上通过的电流 <span class="math inline">\(I_{S2}\)</span> 等于<strong>电容充电电流</strong><span class="math inline">\(I_1\)</span> 与<strong>输出电流</strong><span class="math inline">\(I_O\)</span> 之和。</p><p><img src="/Electronics/Power-Switching/9-Push-Pull/3.png"></p><p>当 <strong>PWM 控制信号</strong> <span class="math inline">\(U_B\)</span>为高电平时，<strong>功率开关管</strong> <span class="math inline">\(VT_2\)</span> 导通（开关 <span class="math inline">\(S_2\)</span> 闭合），而 <span class="math inline">\(VT_1\)</span> 截止（开关 <span class="math inline">\(S_1\)</span>断开），此时的电流路径如上图所示。<strong>输入电压</strong> <span class="math inline">\(U_I\)</span> 施加到<strong>初级绕组</strong> <span class="math inline">\(N_{P2}\)</span> 的两端，使得通过初级绕组的电流<span class="math inline">\(I_{P2}\)</span>线性的增大，<strong>初级绕组</strong> <span class="math inline">\(N_{P2}\)</span> 上的感应电动势为上 <code>+</code>下 <code>-</code>。根据电磁感应原理，<strong>高频变压器</strong> <span class="math inline">\(T\)</span> 的<strong>初级绕组</strong> <span class="math inline">\(N_{P1}\)</span>，<strong>次级绕组</strong> <span class="math inline">\(N_{S1}\)</span> 和 <span class="math inline">\(N_{S2}\)</span> 两端的感应电压同样为上<code>+</code> 下 <code>-</code>，此时后面的<strong>整流二极管</strong><span class="math inline">\(VD_2\)</span> 截止，而 <span class="math inline">\(VD_1\)</span> 导通。</p><p><strong>次级绕组</strong> <span class="math inline">\(N_{S1}\)</span>上产生的<strong>感应电压</strong> <span class="math inline">\(U_{S1}\)</span>施加到输出<strong>滤波电感</strong> <span class="math inline">\(L\)</span>的左端，从而形成线性增加的次级绕组<strong>电流</strong> <span class="math inline">\(I_{S1}\)</span>（即整流二极管 <span class="math inline">\(VD_1\)</span> 的正向导通电流）。与此同时，电感<span class="math inline">\(L\)</span>上储存的能量也在增加，其感应电动势为左 <code>+</code> 右<code>-</code>。<span class="math inline">\(I_{S1}\)</span>为输出<strong>滤波电容</strong> <span class="math inline">\(C\)</span>充电，并且为负载电阻 <span class="math inline">\(R_L\)</span>提供<strong>输出电流</strong> <span class="math inline">\(I_O\)</span>。此时<strong>次级绕组</strong> <span class="math inline">\(N_{S1}\)</span> 上通过的电流 <span class="math inline">\(I_{S1}\)</span> 等于<strong>电容充电电流</strong><span class="math inline">\(I_2\)</span> 与<strong>输出电流</strong><span class="math inline">\(I_O\)</span> 之和。</p><p><img src="/Electronics/Power-Switching/9-Push-Pull/4.png"></p><p>在推挽式变换器当中，PWM 脉宽调制器产生的两路控制信号 <span class="math inline">\(U_A\)</span> 和 <span class="math inline">\(U_B\)</span>总是交替出现，当控制信号的<strong>占空比</strong> <span class="math inline">\(D &lt; 50\%\)</span> 的时候，就会出现一段 <span class="math inline">\(U_A\)</span> 和 <span class="math inline">\(U_B\)</span>均为<strong>低电平</strong>的时间。同时为了避免 2只<strong>功率开关管</strong> <span class="math inline">\(VT_1\)</span>和 <span class="math inline">\(VT_2\)</span>同时导通，也必须保证足够长的 <span class="math inline">\(U_A\)</span> 与<span class="math inline">\(U_B\)</span>同时为低电平的时间（即<strong>死区时间</strong>，通常使用 <span class="math inline">\(DT\)</span> 来进行表示，通常为<code>1μs ~ 3μs</code>）。当控制信号的<strong>占空比</strong> <span class="math inline">\(D\)</span> 减小的时候，就会相应的延长 <span class="math inline">\(U_A\)</span> 和 <span class="math inline">\(U_B\)</span>同时为<strong>低电平</strong>的时间。</p><blockquote><p><strong>注意</strong>：为避免推挽式变换器当中两只功率开关管同时导通，PWM脉宽调制器所产生两路控制信号的<strong>占空比</strong> <span class="math inline">\(D\)</span> 必须小于 <code>50%</code>。</p></blockquote><p>当两只<strong>功率开关管</strong> <span class="math inline">\(VT_1\)</span> 和 <span class="math inline">\(VT_2\)</span> 同时关断的时候（即 <span class="math inline">\(U_A\)</span> 和 <span class="math inline">\(U_B\)</span>同时为低电平），推挽式变换器的电流路径如上图所示。由于<strong>功率开关管</strong><span class="math inline">\(VT_1\)</span> 和 <span class="math inline">\(VT_2\)</span> 同时关断（即<strong>开关</strong><span class="math inline">\(S_2\)</span> 和 <span class="math inline">\(S_2\)</span> 同时断开），<strong>初级绕组</strong><span class="math inline">\(N_{P1}\)</span> 和 <span class="math inline">\(N_{P2}\)</span>上均无电流通过。在<strong>高频变压器</strong> <span class="math inline">\(T\)</span>次级绕组一侧，由于<strong>滤波电感</strong> <span class="math inline">\(L\)</span> 当中的电流不能突变，从而在 <span class="math inline">\(L\)</span> 上产生一个左 <code>-</code> 右<code>+</code> 的感应电压，使得<strong>整流二极管</strong> <span class="math inline">\(VD_1\)</span> 和 <span class="math inline">\(VD_2\)</span> 导通，从而产生电流 <span class="math inline">\(I_{F1}\)</span> 和 <span class="math inline">\(I_{F2}\)</span>，储存在<strong>电感</strong> <span class="math inline">\(L\)</span>当中的磁场能量就会转换为电能，经过由<strong>整流二极管</strong> <span class="math inline">\(VD_1\)</span> 和 <span class="math inline">\(VD_2\)</span> 构成的回路，继续向负载电阻 <span class="math inline">\(R_L\)</span> 供电。随着电感 <span class="math inline">\(L\)</span> 当中磁场能量的释放，其通过的电流 <span class="math inline">\(I_L\)</span>逐渐减小，此时输出<strong>滤波电容</strong> <span class="math inline">\(C\)</span> 将会释放出电流 <span class="math inline">\(I_3\)</span>，<strong>负载电流</strong> <span class="math inline">\(I_O\)</span> 等于流经电感的<strong>电流</strong><span class="math inline">\(I_L\)</span>与电容所释放的<strong>电流</strong> <span class="math inline">\(I_3\)</span> 之和。</p><p>其中，<strong>储能电感</strong> <span class="math inline">\(L\)</span> 上通过的<strong>电流</strong> <span class="math inline">\(I_L\)</span> 等于 <span class="math inline">\(I_{F1}\)</span> 与 <span class="math inline">\(I_{F2}\)</span>的叠加，由于推挽式变换器的结构对称，通常情况下 <span class="math inline">\(I_{F1}\)</span> 与 <span class="math inline">\(I_{F2}\)</span>相等（两者的值分别等于电感上<strong>电流</strong> <span class="math inline">\(I_L\)</span>的一半）。此种情况下会导致<strong>高频变压器</strong> <span class="math inline">\(T\)</span> 的<strong>次级绕组</strong> <span class="math inline">\(N_{S1}\)</span> 和 <span class="math inline">\(N_{S1}\)</span>产生所谓的<strong>凸台电流</strong>（参见后续的波形分析小节）。由于<span class="math inline">\(I_{F1}\)</span> 与 <span class="math inline">\(I_{F2}\)</span> 在<strong>次级绕组</strong> <span class="math inline">\(N_{S2}\)</span> 和 <span class="math inline">\(I_{S2}\)</span>上产生的磁场相互抵消，<strong>高频变压器</strong> <span class="math inline">\(T\)</span> 上的全部绕组都不会产生感应电压，即<span class="math inline">\(N_{P1}\)</span>、<span class="math inline">\(N_{P2}\)</span>、<span class="math inline">\(N_{S1}\)</span>、<span class="math inline">\(N_{S2}\)</span> 上的感应电压均为零。</p><blockquote><p><strong>注意</strong>：由于推挽式变换器也是在功率开关管 <span class="math inline">\(VT_1\)</span> 与 <span class="math inline">\(VT_2\)</span>导通期间向负载传输能量，因而属于一种<strong>正激型变换器</strong>。</p></blockquote><h3 id="波形分析-5">波形分析</h3><p>推挽式 DC-DC 变换器的电压以及电流波形如下图所示，其中 <span class="math inline">\(U_A\)</span> 与 <span class="math inline">\(U_B\)</span> 分别为<strong>功率开关管</strong><span class="math inline">\(VT_1\)</span> 与 <span class="math inline">\(VT_2\)</span>的控制信号。当控制信号为高电平的时候（即 <span class="math inline">\(t_{ONA}\)</span> 与 <span class="math inline">\(t_{ONB}\)</span>阶段），相应的功率开关管会导通，而其它时候则会关断。</p><ul><li>下图（左侧）展示的是<strong>高频变压器</strong> <span class="math inline">\(T\)</span><strong>初级绕组</strong>一侧的电压以及电流波形，<span class="math inline">\(U_{C1}\)</span> 和 <span class="math inline">\(U_{C2}\)</span> 分别为<strong>功率开关管</strong><span class="math inline">\(VT_1\)</span> 与 <span class="math inline">\(VT_2\)</span> 的集电极电压波形，而 <span class="math inline">\(I_{P1}\)</span> 和 <span class="math inline">\(I_{P2}\)</span>分别为高频变压器<strong>初级绕组</strong> <span class="math inline">\(N_{P1}\)</span> 和 <span class="math inline">\(N_{P2}\)</span>的电流波形，即<strong>功率开关管</strong> <span class="math inline">\(VT_1\)</span> 与 <span class="math inline">\(VT_2\)</span> 的集电极电流波形。</li><li>下图（右侧）展示的则是<strong>高频变压器</strong> <span class="math inline">\(T\)</span><strong>次级绕组</strong>一侧的电压与电流波形，<span class="math inline">\(U_{D1}\)</span> 和 <span class="math inline">\(U_{D2}\)</span>分别为输出<strong>整流二极管</strong> <span class="math inline">\(VD_1\)</span> 和 <span class="math inline">\(VD_2\)</span> 正极的电压波形，而 <span class="math inline">\(I_{S1}\)</span> 和 <span class="math inline">\(I_{S2}\)</span>分别表示的是高频变压器<strong>次级绕组</strong> <span class="math inline">\(N_{S1}\)</span> 和 <span class="math inline">\(N_{S2}\)</span>的电流波形，也就是<strong>整流二极管</strong> <span class="math inline">\(VD_1\)</span> 和 <span class="math inline">\(VD_2\)</span> 的正向电流波形。</li></ul><p><img src="/Electronics/Power-Switching/9-Push-Pull/5.png"></p><p>在上图左侧的波形图当中，当 <span class="math inline">\(U_A\)</span>为<strong>高电平</strong>的时候（即 <span class="math inline">\(t_{ONA}\)</span>阶段），<strong>功率开关管</strong> <span class="math inline">\(VT_1\)</span> 导通，其<strong>集电极电压</strong><span class="math inline">\(U_{C1}\)</span> 为<code>0V</code>，<strong>输入电压</strong> <span class="math inline">\(U_I\)</span> 会施加到<strong>初级绕组</strong><span class="math inline">\(N_{P1}\)</span>的两端，使得<strong>初级电流</strong> <span class="math inline">\(I_{P1}\)</span>（即 <span class="math inline">\(VT_1\)</span> 的集电极电流 <span class="math inline">\(I_{C1}\)</span>）线性的增加。此时<strong>功率开关管</strong><span class="math inline">\(VT_2\)</span>关断，其<strong>集电极电压</strong> <span class="math inline">\(U_{C2}\)</span> 为<strong>输入电压</strong> <span class="math inline">\(U_I\)</span> 的两倍，这是由于 <span class="math inline">\(U_{C2}\)</span> 为<strong>初级绕组</strong> <span class="math inline">\(N_{P2}\)</span> 的感应电压（与 <span class="math inline">\(U_I\)</span> 幅度相同）与<strong>输入电压</strong><span class="math inline">\(U_I\)</span> 叠加形成。</p><p>同样的道理，当 <span class="math inline">\(U_B\)</span>为<strong>高电平</strong>的时候（即 <span class="math inline">\(t_{ONB}\)</span> 阶段），<strong>初级电流</strong><span class="math inline">\(I_{P2}\)</span>（即 <span class="math inline">\(VT_2\)</span> 的集电极电流 <span class="math inline">\(I_{C2}\)</span>）线性的增加。此时<strong>功率开关管</strong><span class="math inline">\(VT_1\)</span>关断，其<strong>集电极电压</strong> <span class="math inline">\(U_{C1}\)</span> 同样为<strong>输入电压</strong><span class="math inline">\(U_I\)</span>的两倍。当<strong>功率开关管</strong> <span class="math inline">\(VT_1\)</span> 与 <span class="math inline">\(VT_2\)</span> 的控制信号 <span class="math inline">\(U_A\)</span> 与 <span class="math inline">\(U_B\)</span>均为<strong>低电平</strong>的时候，功率开关管 <span class="math inline">\(VT_1\)</span> 与 <span class="math inline">\(VT_2\)</span>都处于关断状态，初级绕组没有感应电压，两只功率开关管集电极的电压与<strong>输入电压</strong><span class="math inline">\(U_I\)</span> 相同。</p><p>而在上图右侧的波形图当中，当 <span class="math inline">\(U_A\)</span>为<strong>高电平</strong>的时候（即 <span class="math inline">\(t_{ONA}\)</span> 阶段），<strong>次级绕组</strong><span class="math inline">\(N_{S2}\)</span>的感应电压使得<strong>整流二极管</strong> <span class="math inline">\(VD_2\)</span> 导通，两端的电压 <span class="math inline">\(U_{D2}\)</span>为正，从而在次级绕组上形成线性增加的<strong>电流</strong> <span class="math inline">\(I_{S2}\)</span>。与此同时，<span class="math inline">\(N_{S1}\)</span> 的感应电压使得 <span class="math inline">\(U_{D1}\)</span> 为负，整流二极管 <span class="math inline">\(VD_1\)</span> 截止。同样的道理，当 <span class="math inline">\(U_B\)</span> 为<strong>高电平</strong>的时候（即<span class="math inline">\(t_{ONB}\)</span> 阶段），整流二极管 <span class="math inline">\(VD_1\)</span>导通，从而在<strong>次级绕组</strong>上形成线性增加的<strong>电流</strong><span class="math inline">\(I_{S1}\)</span>，这个时候<strong>整流二极管</strong><span class="math inline">\(VD_2\)</span> 截止。</p><p>当<strong>功率开关管</strong> <span class="math inline">\(VT_1\)</span> 与 <span class="math inline">\(VT_2\)</span> 的控制信号 <span class="math inline">\(U_A\)</span> 与 <span class="math inline">\(U_B\)</span>均为<strong>低电平</strong>期间，两只<strong>整流二极管</strong> <span class="math inline">\(VD_1\)</span> 和 <span class="math inline">\(VD_2\)</span>将会同时导通，从而起到续流作用，每只整流二极管上通过滤波<strong>电感</strong><span class="math inline">\(L\)</span> 所释放电流 <span class="math inline">\(I_L\)</span>的一半。伴随输出<strong>滤波电感</strong> <span class="math inline">\(L\)</span> 当中磁场能量的释放，电流 <span class="math inline">\(I_L\)</span> 将会逐渐减小，使得次级绕组上的电流<span class="math inline">\(I_{S1}\)</span> 和 <span class="math inline">\(I_{S2}\)</span> 出现图中的凸台形状。</p><p>上图当中的次级绕组电流 <span class="math inline">\(I_{S1}\)</span> 和<span class="math inline">\(I_{S2}\)</span>也分别是<strong>整流二极管</strong> <span class="math inline">\(VD_1\)</span> 和 <span class="math inline">\(VD_2\)</span>的正向导通电流，输出<strong>滤波电感</strong> <span class="math inline">\(L\)</span> 上通过的电流则由 <span class="math inline">\(I_{S1}\)</span> 和 <span class="math inline">\(I_{S2}\)</span> 叠加而成（即为两者之和）。</p><h3 id="总结-5">总结</h3><p>推挽式 Push-Pull 变换器，具备有如下几个显著的特点：</p><ol type="1"><li><strong>输出电压</strong> <span class="math inline">\(U_O\)</span>与<strong>输入电压</strong> <span class="math inline">\(U_I\)</span>的关系为 <span class="math inline">\(U_O = 2D \times U_I \times\frac{N_S}{N_P}\)</span>，通过改变<strong>初级绕组</strong> <span class="math inline">\(N_P\)</span> 与<strong>次级绕组</strong> <span class="math inline">\(N_S\)</span>的匝数比，就可以构成升压式、降压式开关电源。</li><li><strong>功率开关管</strong> <span class="math inline">\(VT\)</span>承受的最大<strong>电压</strong> <span class="math inline">\(U_{CE} = 2\timesU_I\)</span>，当输入电压比较高的时候，需要选用耐压值比较高的功率开关管，导致成本上的增加，因而推挽式拓扑结构通常用于低输入电压（例如<code>12V</code>、<code>24V</code>、<code>48V</code>）的大功率 DC-DC开关电源。</li><li><strong>功率开关管</strong> <span class="math inline">\(VT\)</span>的最大<strong>集电极电流</strong> <span class="math inline">\(I_C = I_O\times \frac{N_S}{N_P}\)</span>。</li><li>通过<strong>整流二极管</strong> 承受的<strong>反向电压</strong><span class="math inline">\(U_R = 2 \times U_I \times\frac{N_S}{N_P}\)</span>。</li><li>通过<strong>整流二极管</strong> 通过的<strong>平均电流</strong><span class="math inline">\(I_F = \frac{I_O}{2}\)</span>。</li></ol><blockquote><p><strong>注意</strong>：推挽式变换器必须在<strong>输出整流二极管</strong>与<strong>滤波电容</strong>之间串联<strong>滤波电感</strong>，除此之外，只要增加<strong>次级绕组</strong>的<strong>数量</strong>，就可以组成多路输出式DC-DC变换器，并且<strong>输出电压</strong>的极性可以与<strong>输入电压</strong>的极性相反。</p></blockquote><h2 id="半桥式-half-bridge">半桥式 Half-Bridge</h2><h3 id="拓扑结构-7">拓扑结构</h3><p><strong>半桥式变换器</strong>（Half-BridgeConverter）在推挽式变换器的基础之上，由两只功率开关管构成<strong>半桥</strong>，适用于输出功率在<code>100W ~ 500W</code>范围的隔离式开关电源（通常作为消费类电子产品的主电源），其拓扑结构如下图所示：</p><p><img src="/Electronics/Power-Switching/10-Half-Bridge/1.png"></p><p>在上述的拓扑结构当中，<span class="math inline">\(T\)</span>表示的是<strong>高频变压器</strong>，其中 <span class="math inline">\(N_{P}\)</span> 为<strong>初级绕组</strong>，而<span class="math inline">\(N_{S1}\)</span> 和 <span class="math inline">\(N_{S2}\)</span>为<strong>次级绕组</strong>（两者匝数相同，中心带有抽头）。初级绕组与次级绕组的<strong>极性相同</strong>，同名端的位置如上图所示。</p><p><span class="math inline">\(C_1\)</span> 和 <span class="math inline">\(C_2\)</span>分别为容值相等的输入分压电容，每一个电容上的电压分别为<strong>输入电压</strong><span class="math inline">\(U_I\)</span> 的一半。<span class="math inline">\(VT_1\)</span> 和 <span class="math inline">\(VT_2\)</span> 为<strong>功率开关管</strong>，<span class="math inline">\(VD_1\)</span> 和 <span class="math inline">\(VD_2\)</span>为输出<strong>整流二极管</strong>，<span class="math inline">\(L\)</span> 为输出滤波电感，<span class="math inline">\(C_3\)</span>为输出<strong>滤波电容</strong>，<span class="math inline">\(U_O\)</span>为直流<strong>输出电压</strong>，<span class="math inline">\(R_L\)</span>为外部的<strong>负载电阻</strong>。除此之外，<strong>PWM脉宽调制器</strong>同样作为变换器的核心，用于产生两路<strong>相位差</strong>为<code>180°</code> 的<strong>控制信号</strong> <span class="math inline">\(U_A\)</span> 和 <span class="math inline">\(U_B\)</span>，从而使得<strong>功率开关管</strong><span class="math inline">\(VT_1\)</span> 与 <span class="math inline">\(VT_2\)</span> 交替工作。</p><blockquote><p><strong>注意</strong>：相比于推挽式变换器，<strong>半桥式变换器</strong>增加了两个输入<strong>分压电容</strong>，省去了高频变压器初级绕组的<strong>中心抽头</strong>，并且使得功率开关管承受的电压下降为电源的<strong>输入电压</strong><span class="math inline">\(U_I\)</span>，不过两只功率开关管的<strong>驱动控制信号</strong><span class="math inline">\(U_A\)</span> 和 <span class="math inline">\(U_B\)</span> 需要进行电气隔离。</p></blockquote><h3 id="基本原理">基本原理</h3><p><strong>PWM 脉宽调制器</strong>产生的两路控制信号 <span class="math inline">\(U_A\)</span> 和 <span class="math inline">\(U_B\)</span> 交替出现，当 <span class="math inline">\(U_A\)</span> 为高电平的时候，相应的 <span class="math inline">\(U_B\)</span>就会为低电平，反之亦然。<strong>功率开关管</strong> <span class="math inline">\(VT_1\)</span> 和 <span class="math inline">\(VT_2\)</span> 在 PWM脉宽调制信号的控制下，交替的导通与关断。为了便于分析，接下来的原理图分别使用了<strong>开关</strong><span class="math inline">\(S_1\)</span> 和 <span class="math inline">\(S_2\)</span>的闭合与关断，来代替<strong>功率开关管</strong> <span class="math inline">\(VT_1\)</span> 和 <span class="math inline">\(VT_2\)</span> 的导通与关断作用。</p><p><img src="/Electronics/Power-Switching/10-Half-Bridge/2.png"></p><p>当 <strong>PWM 控制信号</strong> <span class="math inline">\(U_A\)</span>为高电平时，<strong>功率开关管</strong> <span class="math inline">\(VT_1\)</span> 导通（开关 <span class="math inline">\(S_1\)</span> 闭合），而 <span class="math inline">\(VT_2\)</span> 截止（开关 <span class="math inline">\(S_2\)</span>关断），此时的电流路径如上图所示。<strong>输入电压</strong> <span class="math inline">\(U_I\)</span> 通过<strong>初级绕组</strong> <span class="math inline">\(N_P\)</span>，施加接到<strong>分压电容</strong><span class="math inline">\(C_2\)</span>的上端，此时<strong>初级绕组</strong> <span class="math inline">\(N_{P}\)</span> 上的电压为<strong>输入电压</strong><span class="math inline">\(U_I\)</span> 的一半，而<strong>电流</strong><span class="math inline">\(I_{P1}\)</span>线性的增加，绕组上产生的感应电动势为上 <code>+</code> 下<code>-</code>。根据电磁感应原理，<strong>高频变压器</strong> <span class="math inline">\(T\)</span> 的 <strong>次级绕组</strong> <span class="math inline">\(N_{S1}\)</span> 和 <span class="math inline">\(N_{S2}\)</span> 两端的感应电压同样也为上<code>+</code> 下 <code>-</code>，此时后面的<strong>整流二极管</strong><span class="math inline">\(VD_1\)</span> 导通，而 <span class="math inline">\(VD_2\)</span> 截止。</p><p><strong>次级绕组</strong> <span class="math inline">\(N_{S1}\)</span>上产生的<strong>感应电压</strong> <span class="math inline">\(U_{S1}\)</span>施加到输出<strong>滤波电感</strong> <span class="math inline">\(L\)</span>的左端，从而形成线性增加的次级绕组<strong>电流</strong> <span class="math inline">\(I_{S1}\)</span>（即整流二极管 <span class="math inline">\(VD_1\)</span> 的正向导通电流）。与此同时，电感<span class="math inline">\(L\)</span>上储存的能量也在增加，其感应电动势为左 <code>+</code> 右<code>-</code>。电流 <span class="math inline">\(I_{S1}\)</span>开始为输出<strong>滤波电容</strong> <span class="math inline">\(C_3\)</span> 充电，并且为<strong>负载电阻</strong><span class="math inline">\(R_L\)</span> 提供<strong>输出电流</strong><span class="math inline">\(I_O\)</span>。此时<strong>次级绕组</strong><span class="math inline">\(N_{S1}\)</span> 上通过的电流 <span class="math inline">\(I_{S1}\)</span> 等于<strong>电容充电电流</strong><span class="math inline">\(I_1\)</span> 与<strong>输出电流</strong><span class="math inline">\(I_O\)</span> 之和。</p><p><img src="/Electronics/Power-Switching/10-Half-Bridge/3.png"></p><p>当 <strong>PWM 控制信号</strong> <span class="math inline">\(U_B\)</span>为高电平时，<strong>功率开关管</strong> <span class="math inline">\(VT_2\)</span> 导通（开关 <span class="math inline">\(S_2\)</span> 闭合），而 <span class="math inline">\(VT_1\)</span> 截止（开关 <span class="math inline">\(S_1\)</span>关断），此时的电流路径如上图所示。<strong>分压电容</strong> <span class="math inline">\(C_2\)</span>两端的电压，将会直接施加到<strong>初级绕组</strong> <span class="math inline">\(N_P\)</span> 上面，即<strong>初级绕组</strong><span class="math inline">\(N_{P}\)</span>上面施加了大小为<strong>输入电压</strong> <span class="math inline">\(U_I\)</span>的一半的反向电压，导致初级绕组上的<strong>电流</strong> <span class="math inline">\(I_{P2}\)</span>线性的增加，绕组上产生的感应电动势为上 <code>-</code> 下<code>+</code>。根据电磁感应原理，<strong>高频变压器</strong> <span class="math inline">\(T\)</span> 的 <strong>次级绕组</strong> <span class="math inline">\(N_{S1}\)</span> 和 <span class="math inline">\(N_{S2}\)</span> 两端的感应电压同样也为上<code>-</code> 下 <code>+</code>，此时后面的<strong>整流二极管</strong><span class="math inline">\(VD_2\)</span> 导通，而 <span class="math inline">\(VD_1\)</span> 截止。</p><p><strong>次级绕组</strong> <span class="math inline">\(N_{S2}\)</span>上产生的<strong>感应电压</strong> <span class="math inline">\(U_{S2}\)</span>施加到输出<strong>滤波电感</strong> <span class="math inline">\(L\)</span>的左端，从而形成线性增加的次级绕组<strong>电流</strong> <span class="math inline">\(I_{S2}\)</span>（即整流二极管 <span class="math inline">\(VD_2\)</span> 的正向导通电流）。与此同时，电感<span class="math inline">\(L\)</span>上储存的能量也在增加，其感应电动势为左 <code>+</code> 右<code>-</code>。电流 <span class="math inline">\(I_{S2}\)</span>开始为输出<strong>滤波电容</strong> <span class="math inline">\(C_3\)</span> 充电，并且为<strong>负载电阻</strong><span class="math inline">\(R_L\)</span> 提供<strong>输出电流</strong><span class="math inline">\(I_O\)</span>。此时<strong>次级绕组</strong><span class="math inline">\(N_{S2}\)</span> 上通过的电流 <span class="math inline">\(I_{S2}\)</span> 等于<strong>电容充电电流</strong><span class="math inline">\(I_2\)</span> 与<strong>输出电流</strong><span class="math inline">\(I_O\)</span> 之和。</p><p>类似于前面介绍过的推挽式变换器，为了避免两只功率开关管同时导通，半桥式变换器当中的PWM 脉宽调制器产生的两路控制信号，占空比 <span class="math inline">\(D\)</span> 必须小于 <code>50%</code>。当 <span class="math inline">\(U_A\)</span> 和 <span class="math inline">\(U_B\)</span> 均为低电平，即两只功率开关管 <span class="math inline">\(VT_1\)</span> 和 <span class="math inline">\(VT_2\)</span> 同时关断（即开关 <span class="math inline">\(S_1\)</span> 与 <span class="math inline">\(S_2\)</span>同时断开），此时<strong>初级绕组</strong> <span class="math inline">\(N_P\)</span>上面没有电流通过，而<strong>高频变压器</strong> <span class="math inline">\(T\)</span>次级绕组一侧的电流路径与推挽式变换器相同。</p><blockquote><p><strong>注意</strong>：由于半桥式变换器也是在功率开关管 <span class="math inline">\(VT_1\)</span> 与 <span class="math inline">\(VT_2\)</span>导通期间向负载传输能量，因而也属于一种<strong>正激型变换器</strong>。</p></blockquote><h3 id="波形分析-6">波形分析</h3><p>半桥式 DC-DC 变换器的电压以及电流波形如下图所示，其中 <span class="math inline">\(U_A\)</span> 与 <span class="math inline">\(U_B\)</span> 分别为<strong>功率开关管</strong><span class="math inline">\(VT_1\)</span> 与 <span class="math inline">\(VT_2\)</span>的控制信号。当控制信号为高电平的时候（即 <span class="math inline">\(t_{ONA}\)</span> 与 <span class="math inline">\(t_{ONB}\)</span>阶段），相应的功率开关管会导通，而其它时候则会关断。</p><ul><li>下图（左侧）展示的是<strong>高频变压器</strong> <span class="math inline">\(T\)</span><strong>初级绕组</strong>一侧的电压以及电流波形，<span class="math inline">\(U_{E1}\)</span> 和 <span class="math inline">\(U_{C2}\)</span> 分别为<strong>功率开关管</strong><span class="math inline">\(VT_1\)</span> 的<strong>发射极</strong>与<span class="math inline">\(VT_2\)</span>的<strong>集电极</strong>电压波形，而 <span class="math inline">\(I_{P1}\)</span> 和 <span class="math inline">\(I_{P2}\)</span>分别为高频变压器<strong>初级绕组</strong> <span class="math inline">\(N_{P}\)</span>的正向与反向电流波形，即<strong>功率开关管</strong> <span class="math inline">\(VT_1\)</span> 与 <span class="math inline">\(VT_2\)</span> 的集电极电流波形。</li><li>下图（右侧）展示的则是<strong>高频变压器</strong> <span class="math inline">\(T\)</span><strong>次级绕组</strong>一侧的电压与电流波形，<span class="math inline">\(U_{D1}\)</span> 和 <span class="math inline">\(U_{D2}\)</span>分别为输出<strong>整流二极管</strong> <span class="math inline">\(VD_1\)</span> 和 <span class="math inline">\(VD_2\)</span> 正极的电压波形，而 <span class="math inline">\(I_{S1}\)</span> 和 <span class="math inline">\(I_{S2}\)</span>分别为高频变压器<strong>次级绕组</strong> <span class="math inline">\(N_{S1}\)</span> 和 <span class="math inline">\(N_{S2}\)</span>的电流波形，也就是<strong>整流二极管</strong> <span class="math inline">\(VD_1\)</span> 和 <span class="math inline">\(VD_2\)</span> 的正向电流波形。</li></ul><p><img src="/Electronics/Power-Switching/10-Half-Bridge/4.png"></p><p>在上图左侧的波形图当中，当 <span class="math inline">\(U_A\)</span>为<strong>高电平</strong>的时候（即 <span class="math inline">\(t_{ONA}\)</span>阶段），<strong>功率开关管</strong> <span class="math inline">\(VT_1\)</span> 导通，其<strong>发射极电压</strong><span class="math inline">\(U_{E1}\)</span>等于<strong>输入电压</strong> <span class="math inline">\(U_I\)</span>。这样<strong>输入电压</strong> <span class="math inline">\(U_I\)</span> 就会施加到<strong>初级绕组</strong><span class="math inline">\(N_{P}\)</span>的两端，使得<strong>初级电流</strong> <span class="math inline">\(I_{P1}\)</span>（即 <span class="math inline">\(VT_1\)</span> 的集电极电流 <span class="math inline">\(I_{C1}\)</span>）线性的增加。此时<strong>功率开关管</strong><span class="math inline">\(VT_2\)</span>关断，由于其<strong>集电极</strong>与 <span class="math inline">\(VT_{1}\)</span>的发射极连接，所以它的<strong>集电极电压</strong> <span class="math inline">\(U_{C2}\)</span> 同样等于<strong>输入电压</strong><span class="math inline">\(U_I\)</span>。</p><p>同理，当 <span class="math inline">\(U_B\)</span>为<strong>高电平</strong>的时候（即 <span class="math inline">\(t_{ONB}\)</span>阶段），<strong>功率开关管</strong> <span class="math inline">\(VT_2\)</span> 导通，其<strong>集电极电压</strong><span class="math inline">\(U_{C2}\)</span> 等于 <code>0V</code>，电容<span class="math inline">\(C_2\)</span>上的电压施加到<strong>初级绕组</strong> <span class="math inline">\(N_P\)</span>的两端，使得初级绕组上通过的<strong>电流</strong> <span class="math inline">\(I_{P2}\)</span> 线性的增加（即 <span class="math inline">\(VT_2\)</span> 的<strong>集电极电流</strong> <span class="math inline">\(I_{C2}\)</span>）。此时，功率开关管 <span class="math inline">\(VT_1\)</span> 关断，由于其发射极与 <span class="math inline">\(VT_2\)</span> 的集电极相连接，所以其发射极电压<span class="math inline">\(U_{E1}\)</span> 也等于<code>0V</code>。换而言之，<span class="math inline">\(VT_1\)</span>的发射极电压波形与 <span class="math inline">\(VT_2\)</span>的集电极电压波形完全相同。</p><p>当<strong>功率开关管</strong> <span class="math inline">\(VT_1\)</span> 与 <span class="math inline">\(VT_2\)</span> 的控制信号 <span class="math inline">\(U_A\)</span> 与 <span class="math inline">\(U_B\)</span>均为<strong>低电平</strong>的时候，<strong>功率开关管</strong> <span class="math inline">\(VT_1\)</span> 与 <span class="math inline">\(VT_2\)</span>均处于关断状态，初级绕组上没有产生感应电压，<span class="math inline">\(VT_1\)</span> 的发射极电压与 <span class="math inline">\(VT_2\)</span>的集电极电压相同，均为<strong>电容</strong> <span class="math inline">\(C_2\)</span>上端正极的电压，也就是<strong>输入电压</strong> <span class="math inline">\(U_I\)</span> 的一半。</p><p>而在上图右侧的波形图当中，当 <span class="math inline">\(U_A\)</span>为<strong>高电平</strong>的时候（即 <span class="math inline">\(t_{ONA}\)</span> 阶段），<strong>次级绕组</strong><span class="math inline">\(N_{S1}\)</span> 的感应电压使得 <span class="math inline">\(U_{D1}\)</span>为正，导致<strong>整流二极管</strong> <span class="math inline">\(VD_1\)</span>导通，从而在次级绕组上形成线性增加的<strong>电流</strong> <span class="math inline">\(I_{S1}\)</span>。与此同时，<strong>次级绕组</strong><span class="math inline">\(N_{S2}\)</span> 上的感应电压使得 <span class="math inline">\(U_{D2}\)</span> 为负，整流二极管 <span class="math inline">\(VD_2\)</span> 截止。同理在 <span class="math inline">\(U_B\)</span> 为<strong>高电平</strong>的时候（即<span class="math inline">\(t_{ONB}\)</span>阶段），<strong>整流二极管</strong> <span class="math inline">\(VD_2\)</span>将会被导通，同样会在次级绕组上形成线性增加的<strong>电流</strong> <span class="math inline">\(I_{S2}\)</span>，此时<strong>整流二极管</strong><span class="math inline">\(VD_1\)</span> 截止。</p><p>类似于推挽式变换器，在<strong>控制信号</strong> <span class="math inline">\(U_A\)</span> 与 <span class="math inline">\(U_B\)</span>均为<strong>低电平</strong>期间，<strong>整流二极管</strong> <span class="math inline">\(VD_1\)</span> 和 <span class="math inline">\(VD_2\)</span>将会同时导通，从而起到续流作用（通过的电流，等于流经电感的电流的一半）电感电流的一半，次级绕组上的<strong>电流</strong><span class="math inline">\(I_{S1}\)</span> 和 <span class="math inline">\(I_{S1}\)</span> 也会出现图中的凸台形状。</p><h3 id="总结-6">总结</h3><p>半桥式 Half-Bridge 变换器，具备有如下几个显著的特点：</p><ol type="1"><li><strong>输出电压</strong> <span class="math inline">\(U_O\)</span>与<strong>输入电压</strong> <span class="math inline">\(U_I\)</span>的关系为 <span class="math inline">\(U_O = D \times U_I \times\frac{N_S}{N_P}\)</span>。</li><li><strong>功率开关管</strong> <span class="math inline">\(VT\)</span>承受的最大<strong>电压</strong> <span class="math inline">\(U_{CE} =U_I\)</span>。</li><li><strong>功率开关管</strong> <span class="math inline">\(VT\)</span>的最大<strong>集电极电流</strong> <span class="math inline">\(I_C = I_O\times \frac{N_S}{N_P}\)</span>。</li><li>通过<strong>整流二极管</strong> 承受的<strong>反向电压</strong><span class="math inline">\(U_R = U_I \times\frac{N_S}{N_P}\)</span>。</li><li>通过<strong>整流二极管</strong> 通过的<strong>平均正向电流</strong><span class="math inline">\(I_F = \frac{I_O}{2}\)</span>。</li></ol><blockquote><p><strong>注意</strong>：半桥式变换器也必须在<strong>输出整流二极管</strong>与<strong>滤波电容</strong>之间串联<strong>滤波电感</strong>，除此之外，只要增加<strong>次级绕组</strong>的<strong>数量</strong>，就可以组成多路输出式DC-DC变换器，并且<strong>输出电压</strong>的极性同样可以与<strong>输入电压</strong>的极性相反。</p></blockquote><h2 id="全桥式-full-bridge">全桥式 Full-Bridge</h2><h3 id="拓扑结构-8">拓扑结构</h3><p><strong>全桥式变换器</strong>（Full-BridgeConverter）在半桥式变换器的基础之上，将两只分压电容更换为一对功率开关管，适用于输出功率在<code>500W</code>以上场景（通常作为大功率用电设备的电源使用），其拓扑结构如下图所示：</p><p><img src="/Electronics/Power-Switching/11-Full-Bridge/1.png"></p><p>在上述的拓扑结构当中，<span class="math inline">\(T\)</span>表示的是<strong>高频变压器</strong>，其中 <span class="math inline">\(N_{P}\)</span> 为<strong>初级绕组</strong>，而<span class="math inline">\(N_{S1}\)</span> 和 <span class="math inline">\(N_{S2}\)</span>为<strong>次级绕组</strong>（两者匝数相同，中心带有抽头）。初级绕组与次级绕组的<strong>极性相同</strong>，同名端的位置如上图所示。</p><p>四只功率开关管被划分为 <span class="math inline">\(VT_1\)</span> 和<span class="math inline">\(VT_4\)</span>、<span class="math inline">\(VT_2\)</span> 和 <span class="math inline">\(VT_3\)</span> 两组，而 <span class="math inline">\(VD_1\)</span> 和 <span class="math inline">\(VD_2\)</span>为输出<strong>整流二极管</strong>，<span class="math inline">\(L\)</span> 为输出滤波电感，<span class="math inline">\(C\)</span> 为输出<strong>滤波电容</strong>，<span class="math inline">\(U_O\)</span>为直流<strong>输出电压</strong>，<span class="math inline">\(R_L\)</span>为外部的<strong>负载电阻</strong>。除此之外，<strong>PWM脉宽调制器</strong>同样作为变换器的核心，用于产生两路<strong>相位差</strong>为<code>180°</code> 的<strong>控制信号</strong> <span class="math inline">\(U_A\)</span> 和 <span class="math inline">\(U_B\)</span>，其中 <span class="math inline">\(U_A\)</span> 用于驱动 <span class="math inline">\(VT_1\)</span> 和 <span class="math inline">\(VT_4\)</span>，而 <span class="math inline">\(U_B\)</span> 用于驱动 <span class="math inline">\(VT_2\)</span> 和 <span class="math inline">\(VT_3\)</span>，使得<strong>功率开关管</strong><span class="math inline">\(VT_1\)</span> 与 <span class="math inline">\(VT_2\)</span> 能够交替进行工作。</p><blockquote><p><strong>注意</strong>：相比于半桥式变换器，<strong>全桥式变换器</strong>增加了两只功率开关管，通常需要使用<strong>脉冲变压器</strong>来耦合驱动信号，从而使得四只功率开关管的驱动控制信号<span class="math inline">\(U_A\)</span> 和 <span class="math inline">\(U_B\)</span>彼此之间电气隔离，导致电路相对复杂，生产制造成本更高。</p></blockquote><h3 id="基本原理-1">基本原理</h3><p><strong>PWM 脉宽调制器</strong>产生的两路控制信号 <span class="math inline">\(U_A\)</span> 和 <span class="math inline">\(U_B\)</span> 交替出现，当 <span class="math inline">\(U_A\)</span> 为高电平的时候，相应的 <span class="math inline">\(U_B\)</span>就会为低电平，反之亦然。<strong>功率开关管</strong> <span class="math inline">\(VT_1\)</span>、<span class="math inline">\(VT_4\)</span> 和 <span class="math inline">\(VT_2\)</span>、<span class="math inline">\(VT_3\)</span> 在 PWM脉宽调制信号的控制下，交替的导通与关断。为了便于分析，接下来的原理图分别使用了<strong>开关</strong><span class="math inline">\(S_1 \sim S_4\)</span>的闭合与关断，来代替<strong>功率开关管</strong> <span class="math inline">\(VT_1 \sim VT_4\)</span> 的导通与关断作用。</p><p><img src="/Electronics/Power-Switching/11-Full-Bridge/2.png"></p><p>当 <strong>PWM 控制信号</strong> <span class="math inline">\(U_A\)</span>为高电平时，<strong>功率开关管</strong> <span class="math inline">\(VT_1\)</span> 和 <span class="math inline">\(VT_4\)</span> 导通（开关 <span class="math inline">\(S_1\)</span> 和 <span class="math inline">\(S_4\)</span> 闭合），而 <span class="math inline">\(VT_2\)</span> 和 <span class="math inline">\(VT_3\)</span> 截止（开关 <span class="math inline">\(S_2\)</span> 和 <span class="math inline">\(S_3\)</span>关断），此时的电流路径如上图所示。<strong>输入电压</strong> <span class="math inline">\(U_I\)</span> 通过开关 <span class="math inline">\(S_1\)</span> 和 <span class="math inline">\(S_4\)</span> 之后，施加到<strong>初级绕组</strong><span class="math inline">\(N_P\)</span>上面，使得初级绕组上的<strong>电流</strong> <span class="math inline">\(I_{P1}\)</span>线性的增加，绕组上产生的感应电动势为上 <code>+</code> 下<code>-</code>。根据电磁感应原理，<strong>高频变压器</strong> <span class="math inline">\(T\)</span> 的 <strong>次级绕组</strong> <span class="math inline">\(N_{S1}\)</span> 和 <span class="math inline">\(N_{S2}\)</span> 两端的感应电压同样也为上<code>+</code> 下 <code>-</code>，此时<strong>整流二极管</strong> <span class="math inline">\(VD_1\)</span> 导通，而 <span class="math inline">\(VD_2\)</span> 截止。</p><p><strong>次级绕组</strong> <span class="math inline">\(N_{S1}\)</span>上产生的<strong>感应电压</strong> <span class="math inline">\(U_{S1}\)</span>施加到输出<strong>滤波电感</strong> <span class="math inline">\(L\)</span>的左端，从而形成线性增加的次级绕组<strong>电流</strong> <span class="math inline">\(I_{S1}\)</span>（即<strong>整流二极管</strong><span class="math inline">\(VD_1\)</span>的正向导通电流）。与此同时，电感 <span class="math inline">\(L\)</span>上储存的能量也在增加，其感应电动势为左 <code>+</code> 右<code>-</code>。电流 <span class="math inline">\(I_{S1}\)</span>开始为输出<strong>滤波电容</strong> <span class="math inline">\(C\)</span> 充电，并且为<strong>负载电阻</strong><span class="math inline">\(R_L\)</span> 提供<strong>输出电流</strong><span class="math inline">\(I_O\)</span>。此时<strong>次级绕组</strong><span class="math inline">\(N_{S1}\)</span> 上通过的电流 <span class="math inline">\(I_{S1}\)</span> 等于<strong>电容充电电流</strong><span class="math inline">\(I_1\)</span> 与<strong>输出电流</strong><span class="math inline">\(I_O\)</span> 之和。</p><p><img src="/Electronics/Power-Switching/11-Full-Bridge/3.png"></p><p>当 <strong>PWM 控制信号</strong> <span class="math inline">\(U_B\)</span>为高电平时，<strong>功率开关管</strong> <span class="math inline">\(VT_2\)</span> 和 <span class="math inline">\(VT_3\)</span> 导通（开关 <span class="math inline">\(S_2\)</span> 和 <span class="math inline">\(S_3\)</span> 闭合），而 <span class="math inline">\(VT_1\)</span> 和 <span class="math inline">\(VT_4\)</span> 截止（开关 <span class="math inline">\(S_1\)</span> 和 <span class="math inline">\(S_4\)</span>关断），此时的电流路径如上图所示。</p><p><strong>输入电压</strong> <span class="math inline">\(U_I\)</span>通过开关 <span class="math inline">\(S_2\)</span> 和 <span class="math inline">\(S_3\)</span>之后，反向施加到<strong>初级绕组</strong> <span class="math inline">\(N_P\)</span>上面，使得初级绕组上的<strong>反向电流</strong> <span class="math inline">\(I_{P2}\)</span>线性的增加，绕组上产生的感应电动势为上 <code>-</code> 下<code>+</code>。根据电磁感应原理，<strong>高频变压器</strong> <span class="math inline">\(T\)</span> 的 <strong>次级绕组</strong> <span class="math inline">\(N_{S1}\)</span> 和 <span class="math inline">\(N_{S2}\)</span> 两端的感应电压同样也为上<code>-</code> 下 <code>+</code>，此时<strong>整流二极管</strong> <span class="math inline">\(VD_2\)</span> 导通，而 <span class="math inline">\(VD_1\)</span> 截止。</p><p>次级绕组 <span class="math inline">\(N_{S2}\)</span> 上产生的感应电压<span class="math inline">\(U_{S2}\)</span>施加到输出<strong>滤波电感</strong> <span class="math inline">\(L\)</span> 的左端，从而形成线性增加的次级电流<span class="math inline">\(I_{S2}\)</span>（即整流二极管 <span class="math inline">\(VD_2\)</span>的正向导通电流），电感上储存的能量开始增加，电感 <span class="math inline">\(L\)</span> 上面产生的感应电动势为左 <code>+</code>右 <code>-</code>。电流 <span class="math inline">\(I_{S2}\)</span>为输出<strong>滤波电容</strong> <span class="math inline">\(C\)</span>进行充电，并且为<strong>负载电阻</strong> <span class="math inline">\(R_L\)</span> 提供<strong>输出电流</strong> <span class="math inline">\(I_O\)</span>。次级绕组上的<strong>电流</strong><span class="math inline">\(I_{S2}\)</span>等于电容<strong>充电电流</strong> <span class="math inline">\(I_2\)</span> 与<strong>输出电流</strong> <span class="math inline">\(I_O\)</span> 之和。</p><p>类似于<strong>推挽式变换器</strong>，为了避免两组功率开关管同时导通，全桥式变换器当中PWM 脉宽调制器所产生的两路控制信号<strong>占空比</strong> <span class="math inline">\(D\)</span> 必须低于<code>50%</code>。当<strong>控制信号</strong> <span class="math inline">\(U_A\)</span> 和 <span class="math inline">\(U_B\)</span>均为低电平，两组<strong>功率开关管</strong> <span class="math inline">\(VT_1\)</span> 与 <span class="math inline">\(VT_4\)</span>、<span class="math inline">\(VT_2\)</span> 与 <span class="math inline">\(VT_3\)</span> 同时关断（即开关 <span class="math inline">\(S_{1 \sim 4}\)</span>同时断开）的时候，<strong>初级绕组</strong> <span class="math inline">\(N_P\)</span>上面没有电流通过。此时，<strong>高频变压器</strong> <span class="math inline">\(T\)</span>次级侧的电流路径与推挽式变换器相同。</p><blockquote><p><strong>注意</strong>：由于全桥式变换器是在 <span class="math inline">\(VT_1\)</span> 与 <span class="math inline">\(VT_4\)</span>、<span class="math inline">\(VT_2\)</span> 与 <span class="math inline">\(VT_3\)</span>两组功率开关管导通期间，向负载传递能量的，因而属于一种<strong>正激型变换器</strong>。</p></blockquote><h3 id="波形分析-7">波形分析</h3><p>全桥式 DC-DC 变换器的电压以及电流波形如下图所示，其中 <span class="math inline">\(U_A\)</span> 与 <span class="math inline">\(U_B\)</span> 分别为两组<strong>功率开关管</strong><span class="math inline">\(VT_1\)</span> 与 <span class="math inline">\(VT_4\)</span>、<span class="math inline">\(VT_2\)</span> 与 <span class="math inline">\(VT_3\)</span>的控制信号。当控制信号为高电平的时候（即 <span class="math inline">\(t_{ONA}\)</span> 与 <span class="math inline">\(t_{ONB}\)</span>阶段），相应的功率开关管就会导通，而其它时刻则会关断。</p><p><img src="/Electronics/Power-Switching/11-Full-Bridge/4.png"></p><ul><li>上图（左侧）展示的是<strong>高频变压器</strong> <span class="math inline">\(T\)</span><strong>初级绕组</strong>一侧的电压以及电流波形，<span class="math inline">\(U_{E1}\)</span> 和 <span class="math inline">\(U_{C2}\)</span> 分别为<strong>功率开关管</strong><span class="math inline">\(VT_1\)</span> 的<strong>发射极</strong>与<span class="math inline">\(VT_2\)</span>的<strong>集电极</strong>电压波形。而 <span class="math inline">\(U_{E3}\)</span> 和 <span class="math inline">\(U_{C4}\)</span> 分别为<strong>功率开关管</strong><span class="math inline">\(VT_3\)</span> 的<strong>发射极</strong>与<span class="math inline">\(VT_4\)</span>的<strong>集电极</strong>电压波形。除此之外，<span class="math inline">\(I_{P1}\)</span> 和 <span class="math inline">\(I_{P2}\)</span>分别为高频变压器<strong>初级绕组</strong> <span class="math inline">\(N_{P}\)</span>的正向与反向电流波形，即<strong>功率开关管</strong> <span class="math inline">\(VT_1\)</span> 与 <span class="math inline">\(VT_4\)</span>、<span class="math inline">\(VT_2\)</span> 与 <span class="math inline">\(VT_3\)</span> 的集电极电流波形。</li><li>上图（右侧）展示的则是<strong>高频变压器</strong> <span class="math inline">\(T\)</span><strong>次级绕组</strong>一侧的电压与电流波形，<span class="math inline">\(U_{D1}\)</span> 和 <span class="math inline">\(U_{D2}\)</span>分别为输出<strong>整流二极管</strong> <span class="math inline">\(VD_1\)</span> 和 <span class="math inline">\(VD_2\)</span> 正极的电压波形，而 <span class="math inline">\(I_{S1}\)</span> 和 <span class="math inline">\(I_{S2}\)</span>分别为高频变压器<strong>次级绕组</strong> <span class="math inline">\(N_{S1}\)</span> 和 <span class="math inline">\(N_{S2}\)</span>的电流波形，也就是<strong>整流二极管</strong> <span class="math inline">\(VD_1\)</span> 和 <span class="math inline">\(VD_2\)</span> 的正向电流波形。</li></ul><h3 id="总结-7">总结</h3><p>全桥式 DC-DC变换器具备了<strong>半桥式</strong>和<strong>推挽式</strong>两种变换器的全部优点，但是电路结构更加复杂，成本也更高。在全部DC-DC变换器当中，全桥式变换器的输出功率最大，适用于搭建<strong>输出功率</strong><code>1kW ~ 3kW</code>的大功率隔离式开关电源，其主要具备有如下特点：</p><ol type="1"><li><strong>输出电压</strong> <span class="math inline">\(U_O\)</span>与<strong>输入电压</strong> <span class="math inline">\(U_I\)</span>的关系与推挽式相同 <span class="math inline">\(U_O = 2D \times U_I\times \frac{N_S}{N_P}\)</span>。</li><li><strong>功率开关管</strong> <span class="math inline">\(VT\)</span>承受的最大<strong>电压</strong> <span class="math inline">\(U_{CE} =U_I\)</span>。</li><li><strong>功率开关管</strong> <span class="math inline">\(VT\)</span>的最大<strong>集电极电流</strong> <span class="math inline">\(I_C = I_O\times \frac{N_S}{N_P}\)</span>。</li><li>通过<strong>整流二极管</strong>承受的<strong>反向电压</strong>也与推挽式相同 <span class="math inline">\(U_R = 2U_I \times \frac{N_S}{N_P}\)</span>。</li><li>通过<strong>整流二极管</strong> 通过的<strong>平均正向电流</strong><span class="math inline">\(I_F = \frac{I_O}{2}\)</span>。</li></ol><blockquote><p><strong>注意</strong>：全桥式变换器同样必须在<strong>输出整流二极管</strong>与<strong>滤波电容</strong>之间串联<strong>滤波电感</strong>，除此之外，只要增加<strong>次级绕组</strong>的<strong>数量</strong>，就可以组成多路输出式DC-DC变换器，并且<strong>输出电压</strong>的极性同样可以与<strong>输入电压</strong>的极性相反。</p></blockquote><h2 id="关于拓扑选择的建议">关于拓扑选择的建议</h2><p><strong>开关电源的拓扑结构</strong>从选型的角度，可以被划分为隔离与非隔离两种类型：</p><ol type="1"><li><strong>隔离型</strong>：通过高频变压器实现电气隔离，安全性更高，体积更大，效率略低（通常在<code>80% ~ 90%</code> 范围）。</li><li><strong>非隔离型</strong>：输入与输出之间存在电流回路（例如输入输出之间存在共地连接），直接通过储能电感和电容进行功率转换，由于省去了变压器，所以转换效率更高（可以达到<code>95%</code> 以上）。</li></ol><p><strong>非隔离型拓扑</strong>，输入与输出共地连接：</p><ul><li><strong>降压型Buck</strong>，输出电压小于输入电压，主要应用于电源适配器等场景。</li><li><strong>升压型 Boost</strong>，输出电压大于输入电压，主要应用于 LED驱动电路，以及对电池进行升压等场景。</li><li><strong>升降压型Buck-Boost</strong>，输出电压即可以高于也可以低于输入电压，并且极性反转（存在有SEPIC 和 Cuk 两个变种拓扑）。</li></ul><p><strong>隔离型拓扑</strong>，输入与输出之间存在有电气隔离：</p><ul><li><strong>反激 Flyback</strong>，结构简单，适合于低于<code>100W</code> 的小功率场景，例如手机充电器。</li><li><strong>正激Forward</strong>，效率高于反激式拓扑，并且需要额外的<strong>磁复位电路</strong>，主要适用于<code>100W ~ 500W</code> 功率的中等功率场景。</li><li><strong>推挽Push-Pull</strong>，采用两个<strong>功率开关管</strong>交替驱动变压器，效率相对较高，适用于<code>100W ~ 1KW</code> 的中等功率场景。</li><li><strong>半桥Half-Bridge</strong>，同样采用采用两个<strong>功率开关管</strong>交替驱动变压器，但是需要分压电容来平衡输入电压，适用于<code>200W ~ 1KW</code> 的中等功率场景。</li><li><strong>全桥 Full-Bridge</strong>，采用四个开关管组成的 H桥电路驱动变压器，具有高效灵活的控制方式，是高功率密度电源设计的首选方案，特别适用于<code>1KW ~ 10KW</code>的大功率场景，例如：服务器电源、工业电机驱动、电动汽车充电桩、太阳能逆变器等。</li></ul>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;strong&gt;电源&lt;/strong&gt;用于在电路当中将其它形式的能量转换为电能，日常工作当中主要运用的是&lt;strong&gt;化学电源&lt;/strong&gt;（碳性电池、碱性电池、锂电池、镍氢电池、铅酸电池）、&lt;strong&gt;开关电源&lt;/strong&gt;（效率高、体积小、重量轻）、&lt;strong&gt;线性电源&lt;/strong&gt;（输出电压稳定，纹波系数小）三种类型。在之前的&lt;a href=&quot;http://uinio.com/Electronics/Battery/&quot;&gt;《&lt;strong&gt;锂离子电池技术参数简明选型指南&lt;/strong&gt;》&lt;/a&gt;这篇文章当中，已经详细阐述了锂离子电池的性能指标与选型思路。本篇文章则从线性电源的原理入手，逐步引出开关电源的知识，并且分门别类的讨论了几种常见的&lt;strong&gt;拓扑结构&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/Electronics/Power-Switching/logo.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;线性电源&lt;/strong&gt;（Linear Power
Supply）的&lt;strong&gt;调整管&lt;/strong&gt;工作在&lt;strong&gt;线性状态&lt;/strong&gt;（&lt;code&gt;放大&lt;/code&gt;），开关电源通常是在对&lt;strong&gt;输出电压&lt;/strong&gt;进行采样之后，会将其与参考电压一同送入&lt;strong&gt;比较放大器&lt;/strong&gt;，然后通过其输出的控制信号作为&lt;strong&gt;调整管&lt;/strong&gt;的输入，从而达到通过&lt;strong&gt;调整管&lt;/strong&gt;控制电源输出电压的目的，但是由于调整管工作在放大区，其本身会发热并且消耗电能，因而转换效率相对较差。而&lt;strong&gt;开关电源&lt;/strong&gt;（Switching
Power
Supply）的&lt;strong&gt;功率开关管&lt;/strong&gt;工作在&lt;strong&gt;开关状态&lt;/strong&gt;（&lt;code&gt;饱和&lt;/code&gt;
与
&lt;code&gt;截止&lt;/code&gt;），主要是通过调整&lt;strong&gt;功率开关管&lt;/strong&gt;的通断时间（占空比）来改变输出电压。由于功率开关管切换状态时耗散的功率比较少，产生的废热也比较少，相对而言更加节能，属于机电产品当中主流的电源形态。&lt;/p&gt;</summary>
    
    
    
    <category term="硬件电子技术" scheme="http://www.uinio.com/categories/%E7%A1%AC%E4%BB%B6%E7%94%B5%E5%AD%90%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="电路理论" scheme="http://www.uinio.com/tags/%E7%94%B5%E8%B7%AF%E7%90%86%E8%AE%BA/"/>
    
  </entry>
  
  <entry>
    <title>闭环控制算法 PID 的原理剖析与实现</title>
    <link href="http://www.uinio.com/Embedded/PID/"/>
    <id>http://www.uinio.com/Embedded/PID/</id>
    <published>2025-02-04T16:00:00.000Z</published>
    <updated>2025-06-25T14:55:36.769Z</updated>
    
    <content type="html"><![CDATA[<p><strong>比例-积分-微分</strong>（PID，Proportion IntegrationDifferentiation）是一种广泛运用于自动化控制领域的经典算法，属于众多控制算法当中最能够体现反馈思想的算法。该算法由<strong>Nicolas Minorsky</strong> 于 <strong>1922</strong>年船舶舵机控制理论的研究当中提出，随后以其卓越的性能和易于实现的特性，在<code>温度控制</code>、<code>电机调速</code>、<code>过程控制</code>等诸多领域逐渐普及。无论是简单的单变量系统，还是复杂的多变量系统，PID控制算法都能通过调节<code>比例</code>、<code>积分</code>、<code>微分</code>三个参数实现精准的控制。</p><p><img src="/Embedded/PID/logo.png"></p><p>例如把一台无刷电机连接到额定输出电压为 <code>12V</code>的锂电池组，然后通过一个占空比为 <code>50%</code> 的 PWM波进行驱动，刚开始的时候电机运行速度很快且扭矩充足，但是随着时间的流逝，锂电池的放电电压逐步下降，开始影响到电机的转速和转矩。如果这块锂电池组刚充满的时候，输出电压为<code>12V</code>，PWM 波占空比为<code>50%</code>，那么作用在电机两端的等效电压为 <span class="math inline">\(12V \times 50\% =6V\)</span>。放电持续一段时间之后，锂电池电压降低至<code>9V</code>，此时电机两端的等效电压也会降低到 <span class="math inline">\(9V \times 50\% =4.5V\)</span>，电机的转速和转矩开始出现明显的下降。如果需要在锂电池的整个放电周期当中，保持电机<code>转速</code> 和 <code>转矩</code>的稳定，就有必要引入这里将要介绍的 PID 控制理论。</p><span id="more"></span><h2 id="控制系统分类">控制系统分类</h2><p>在众多工业自动化控制算法当中，通常会根据当前是否存在有反馈信号，而将其笼统的划分为<strong>开环控制</strong>和<strong>闭环控制</strong>两种类型：</p><ul><li><strong>开环控制系统</strong>（OpenLoop）：<strong>被控对象</strong>的输出(即<code>被控制量</code>)不会影响到<strong>控制装置</strong>的输出，这种控制系统不需要返回被控量，也不会形成任何的闭环回路。<img src="/Embedded/PID/1.png"></li><li><strong>闭环控制系统</strong>（ClosedLoop）：<strong>被控对象</strong>的输出（通过<code>检测装置</code>）返回并影响到<strong>控制装置</strong>的输出，进而形成闭环的控制回路。<img src="/Embedded/PID/2.png"></li></ul><blockquote><p><strong>注意</strong>：根据反馈信号与控制信号的<strong>极性</strong>是否相同，还可以将闭环控制系统进一步划分为<strong>正反馈</strong>和<strong>负反馈</strong>两种类型。</p></blockquote><p><strong>PID 算法属于一种闭环控制系统</strong>，下图展示了使用 PID控制器对直流无刷电机进行调速的过程，无刷电机的<strong>目标转速</strong><span class="math inline">\(n_0(t)\)</span>将会与<strong>实际转速</strong> <span class="math inline">\(n(t)\)</span> 进行比较，其差值 <span class="math inline">\(e(t)=n_0(t)-n(t)\)</span> 经过 PID控制器调整之后，输出的<strong>电压控制信号</strong> <span class="math inline">\(u(t)\)</span>经过功率放大器处理之后，就可以驱动直流电机并实时调整其 <code>转速</code>与 <code>转矩</code>：</p><p><img src="/Embedded/PID/3.png"></p><h2 id="pid-算法概览">PID 算法概览</h2><p><strong>PID</strong> 是<strong>比例</strong>（Proportional<code>[prəˈpɔːʃən(ə)l]</code>）、<strong>积分</strong>（Integral<code>[ˈɪntɪɡrəl]</code>）、<strong>微分</strong>（Differential<code>[ˌdɪfəˈrenʃ(ə)l]</code>）三个英文单词的首字母缩写。顾名思义，这是一种基于系统运行时产生的<code>偏差</code>，利用<strong>比例</strong>、<strong>积分</strong>、<strong>微分</strong>计算出实际控制量的一种算法。在下面的示意图当中，展示了PID 算法的基本工作流程，其中的 <span class="math inline">\(r(t)\)</span>是设定的<strong>目标值</strong>，<span class="math inline">\(y(t)\)</span>是实际的<strong>输出值</strong>：</p><p><img src="/Embedded/PID/4.png"></p><p>将设定的目标值 <span class="math inline">\(r(t)\)</span> 与实际输出值<span class="math inline">\(y(t)\)</span>相减，就可以计算得到<strong>偏差</strong> <span class="math inline">\(e(t)\)</span> 的值：</p><p><span class="math display">\[e(t) = r(t) - y(t)\]</span></p><p>上面示意图当中的<strong>偏差</strong> <span class="math inline">\(e(t)\)</span> 将会作为 PID控制器的<strong>输入</strong>，而<strong>电压控制信号</strong> <span class="math inline">\(u(t)\)</span> 则会作为 PID控制器的<strong>输出</strong>或者被控对象的<strong>输入</strong>，整个PID 控制器的算法可以被整理为如下的<strong>离散公式</strong>（PID算法的连续公式不利于计算机处理，这里不作介绍）：</p><p><span class="math display">\[\begin{align}u(t) &amp; = \Biggl( K_p \times e(t) \Biggl) + \Biggl( K_i \times\int^t_0 e(t) dt \Biggl) + \Biggl( K_d \times \frac{de(t)}{dt} \Biggl)\\&amp; = K_p \Biggl( e(t) + \frac{1}{T_i} \int^t_0 e(t) dt + T_d\frac{de(t)}{dt} \Biggl)\end{align}\]</span></p><p>上述第 1 个公式中的参数 <span class="math inline">\(K_p\)</span>、<span class="math inline">\(K_i\)</span>、<span class="math inline">\(K_d\)</span> 分别是 PID控制器的<strong>比例系数</strong>、<strong>积分系数</strong>、<strong>微分系数</strong>。而第2 个公式中的 <span class="math inline">\(T_i\)</span>是<strong>积分时间</strong>、<span class="math inline">\(T_d\)</span>则是<strong>微分时间</strong>。基于上面这个公式，就可以把 PID算法的控制流程梳理为如下三个步骤：</p><ol type="1"><li>首先，计算出 <code>设定目标值</code> 与 <code>实际输出值</code>之间的偏差。</li><li>然后，将结果导入<code>比例</code>、<code>积分</code>、<code>微分</code> 三个 PID算法控制环节进行处理。</li><li>最后，通过<strong>闭环控制系统</strong>，不断的将<code>实际输出值</code> 反馈至偏差计算阶段，如此循环往复。</li></ol><p>根据上述 PID 算法的理论公式，可以将其划分为<strong>比例</strong>、<strong>积分</strong>、<strong>微分</strong>三个控制环节，在接下来内容里我们会分别进行讨论。</p><blockquote><p><strong>注意</strong>：实际的工业控制系统当中，并非需要 PID的全部三个环节都参与控制，有些控制场景下只需要比例环节或者积分环节就可以控制。除此之外，每一套控制系统的PID 系数并不是通用的，需要根据实际情况进行标定。</p></blockquote><h2 id="比例-proportional">比例 Proportional</h2><p><strong>比例控制环节</strong>主要用于补偿目标值与实际值之间的偏差，如果产生偏差PID控制器将会立刻产生控制作用，使得控制量向着降低偏差的方向进行变化，比例控制环节的数学式表达如下所示：</p><p><span class="math display">\[比例系数 K_p \times 偏差 e(t)\]</span></p><p>观察上面的数学公式可以发现，比例控制作用的强弱，主要取决于<strong>比例系数</strong><span class="math inline">\(K_p\)</span>，该参数的取值具有如下特点：</p><ul><li><strong>优点</strong>：比例系数越大，控制作用就会越强，过渡过程就会越快，控制过程的静态偏差也就会越小；</li><li><strong>缺点</strong>：比例系数越大，也就越容易让控制信号发生振荡，从而破坏整个控制系统的稳定性；</li></ul><p>因此，必须选用合适的比例系数取值，才能够减少过渡时间，降低振荡发生的概率，进而降低静态偏差，确保整个控制系统的稳定工作。</p><h2 id="积分-integral">积分 Integral</h2><p><strong>积分控制环节</strong>主要用于消除在比例控制环节产生的<strong>静态偏差</strong>（即控制系统达到稳态之后，输出值与期望值之间的偏差），其数学式表达如下所示：</p><p><span class="math display">\[比例系数 K_p \times \frac{1}{积分时间 T_i} \times \int^t_0 偏差 e(t) dt\]</span></p><p>观察上面的数学表达式可知：只要存在着偏差，其控制作用就会不断的增强。只有当偏差<span class="math inline">\(e(t)=0\)</span>的时候，其控制作用才会变成一个常数。虽然积分控制环节可以消除静态误差，但是同时也会降低控制系统的响应速度，导致控制系统出现<strong>超调</strong>（即输出量在达到设定值之前，就已经超过设定值的现象），所以必须根据实际的控制要求来选定<strong>积分时间</strong><span class="math inline">\(T_i\)</span> 的取值：</p><ul><li>积分常数 <span class="math inline">\(T_i\)</span>越大，积分的累积作用就会越弱。虽然控制系统在过渡过程当中不会发生振荡，但是会减缓消除静态偏差的过程。但是可以降低超调量，提高控制系统的稳定性；</li><li>积分常数 <span class="math inline">\(T_i\)</span>越小，积分的累积作用就会越强，此时过渡过程当中可能会产生振荡，不过消除静态偏差所需的时间比较短。</li></ul><h2 id="微分-differential">微分 Differential</h2><p><strong>微分控制环节</strong>用于根据偏差的变化趋势或者变化速度，在偏差来临之前引入一个修正信号，从而将偏差消灭在萌芽状态，进而降低控制系统的<strong>动态偏差</strong>（即控制系统输出与期望值之间的差异随着时间变化的情况），微分控制环节的数学表达式如下所示：</p><p><span class="math display">\[比例系数 K_p \times 微分时间 T_d \times \frac{de(t)}{dt}\]</span></p><p>观察上述公式可以发现，其控制作用主要由<strong>微分时间</strong> <span class="math inline">\(T_d\)</span> 来决定。如果 <span class="math inline">\(T_d\)</span>的值越大，控制系统抑制<strong>偏差</strong> <span class="math inline">\(e(t)\)</span> 变化的能力就会越强。反之如果 <span class="math inline">\(T_d\)</span> 越小，其抑制<strong>偏差</strong><span class="math inline">\(e(t)\)</span>变化的能力就会越弱，因此该参数同样需要合理的进行取值。</p><p>概而言之，PID 控制系统不但需要在<strong>比例控制环节</strong>对<code>偏差量</code> 做出响应，以及在<strong>积分控制环节</strong>消除<code>静态误差</code>之外，还需要在<strong>微分控制环节</strong>根据偏差的变化趋势，预先修正<strong>动态偏差</strong>。</p><ul><li><strong>优点</strong>：微分控制环节有助于避免控制系统出现超调和发生振荡，同时能够提高控制系统的响应速度，并且改善动态性能；</li><li><strong>缺点</strong>：容易引入高频噪声，在干扰信号比较严重的闭环控制系统当中，需要慎重引入微分控制环节，以及选择合理的微分时间<span class="math inline">\(T_d\)</span>；</li></ul><h2 id="pid-算法的直观示例">PID 算法的直观示例</h2><p>本章节内容，通过一个【<strong>阀门向水箱注水</strong>】的形象实例来说明PID算法理论的基本思想，假设现在有下图这样一个透明的水箱，水位高度可以进行实时的观测，现在要通过顶部的阀门向水箱从零开始注水，以达到某个确定的水位（例如<code>100%</code> 完全注满）：</p><p><img src="/Embedded/PID/5.png"></p><h3 id="比例调节阶段">比例调节阶段</h3><p>如果想将水箱里的水灌注到指定位置，那么只需要观测水位实际位置与目标位置的差值即可。如果差值较大，就将阀门开大一些。如果差值较小，就将阀门关小一些；伴随水位差值越来越小，直至完全关闭阀门，从而达到将水灌注到指定水位的目的。这种场景，就属于PID 控制算法的<strong>比例控制环节</strong>，输出水量 <span class="math inline">\(u(t)\)</span> 等于比例系数 <span class="math inline">\(K_p\)</span> 与水位差 <span class="math inline">\(e(t)\)</span> 的乘积：</p><p><span class="math display">\[输出 u(t) = 比例系数 K_p \times 偏差 e(t)\]</span></p><p>这里的比例系数 <span class="math inline">\(K_p\)</span>就相当于阀门的开关幅度，该值越大就说明阀门开启得比较大，阀门的出水量就会越大，水箱里水量的调节速度就会更快；该值越小则说明阀门开启得比较小，阀门出水量和水箱水位的调节速度都会降低。换而言之，总体展现的就是<strong>通过增大比例系数，从而提高控制系统响应</strong>的思想。</p><p><img src="/Embedded/PID/6.png"></p><p>例如在上面的示意图当中，比例系数 <span class="math inline">\(K_p =0.05\)</span> 时的控制输出，将会比 <span class="math inline">\(K_p =0.01\)</span> 的输出要更快的达到 <code>100%</code> 的稳态。</p><h3 id="积分调节阶段">积分调节阶段</h3><p>如果此时添加了一个用于放水的阀门，当放水速度等于注水速度的时候，此时的偏差<span class="math inline">\(e(t) = 0\)</span>。相应的当 <span class="math inline">\(e(t) \neq 0\)</span>的时候，水位的高度就会始终存在着一个<strong>静态误差</strong>。如果此时放水速度并非一个恒定不变的常量，那么单纯按比例进行控制，就无法补足这个静态不变的误差。因而必须引入积分控制环节，依靠动态的调整注水量来解决这个问题，此时的控制算法会扩展为如下的方程式：</p><p><span class="math display">\[输出 u(t) = \Biggl( 比例系数 K_p \times 偏差 e(t) \Biggl) + \Biggl(\frac{比例系数 K_p}{积分时间 T_i} \times \int^t_0 e(t) dt \Biggl)\]</span></p><p>积分控制环节存在着一个重要的参数<strong>积分系数</strong> <span class="math inline">\(K_i = \frac{比例系数 K_p}{积分时间T_i}\)</span>，积分时间用于累计过程误差，累计的误差越大，调节的力度就会越大。在水箱注水的例子里，可以理解为在第1 个注水阀门之外，额外又增加了第 2个注水阀门。这个阀门的工作规则是：当水位低于目标高度时，就持续加大阀门开启力度。当水位高于目标高度时，就不断减少阀门开启力度。这个时候，如果水箱的放水量和放水速度不发生变化，那么在经过若干次的调整之后，就可以消除控制系统的静态误差。换而言之，<strong>积分环节可以消除控制系统的静态误差</strong>。</p><p><img src="/Embedded/PID/7.png"></p><p><strong>积分系数</strong> <span class="math inline">\(K_i\)</span>越大，在<strong>比例系数</strong> <span class="math inline">\(K_p\)</span>为定值的前提下，就必须选用较小的<strong>积分时间</strong> <span class="math inline">\(T_i\)</span>取值，此时相当于降低了积分调节的灵敏度。如果当前没有达到预定水位，那么第2个阀门就会持续向水箱进行注水。当达到目标水位的时候，这个阀门也就达到了最大的出水量，进而开始导致水箱的注水量发生溢出，这部分溢出的注水量就被称作<strong>超调</strong>。因此第2个阀门的开启幅度越大，其达到目标水位的速度也就会越快，但是由于超调而导致的震荡也就会越多。观察上面的示意图，可以发现虽然增大<strong>积分时间</strong> <span class="math inline">\(T_i\)</span>有助于降低控制信号的超调，提升控制系统的稳定性，但是同时也会带来静态偏差消除时间过久的问题。</p><h3 id="微分调节阶段">微分调节阶段</h3><p>如果放水阀门的出水量并非一个稳定的<strong>常数</strong>，而是一个在不断发生变化的<strong>变量</strong>。那么积分调节阶段所引入的第2个阀门，依然在根据原先设定的目标水位进行控制的话，由于很难知晓下一时刻的出水量大小，调整操作往往就会显得滞后。此时仅仅只依靠比例和积分调节就不那么奏效，必须再行引入一个新的<strong>微分调节阶段</strong>的公式：</p><p><span class="math display">\[u(t) = \Biggl( K_p \times e(t) \Biggl) + \Biggl( \frac{K_p}{T_i}\int^t_0 e(t) dt \Biggl) + \Biggl( K_p  \times T_d \frac{de(t)}{dt}\Biggl)\]</span></p><p>微分调节阶段相当于再次在水箱上添加第 3 个注水阀门，以及第 2个放水阀门，从而一边持续的观测水位变化，另一边不断的进行放水和注水，根据水位实际高度与预期高度差值的变化率来调整阀门的状态，从而达到更佳的水位控制效果。</p><p><img src="/Embedded/PID/8.png"></p><p>微分控制环节的重要参数是<strong>微分系数</strong> <span class="math inline">\(K_d = 比例系数 K_p \times 微分时间T_d\)</span>，当<strong>比例系数</strong> <span class="math inline">\(K_p\)</span>的取值一定的情况下，微分调节阶段的控制作用主要由<strong>微分时间</strong><span class="math inline">\(T_d\)</span>来决定，其值越大，控制系统抑制<strong>动态偏差</strong>的能力就越强，反之其值越小，控制系统抑制动态偏差的能力就会越弱。</p><blockquote><p><strong>注意</strong>：本质上而言，<strong>积分控制环节</strong>调节的是整个注入和放水过程的<strong>静态偏差</strong>，而<strong>微分控制环节</strong>调节的则是整个过程的<strong>动态偏差</strong>。</p></blockquote><h2 id="位置式-pid-算法">位置式 PID 算法</h2><p>由于常用的 MCU微控制器作为一种数字芯片，只能根据<strong>采样</strong>时刻的偏差计算控制量，而不能像模拟量那样进行<strong>连续</strong>的采样与控制，因而下面PID 公式中的 <code>积分项</code> 与 <code>微分项</code>无法直接使用，必须进行离散化处理：</p><p><span class="math display">\[\begin{align}u(t) = K_p \Biggl( e(t) + \frac{1}{T_i} \int^t_0 e(t) dt + T_d\frac{de(t)}{dt} \Biggl)\end{align}\]</span></p><p>首先将 <code>T</code> 作为采样周期，<code>k</code>作为采样序号，然后用离散的采样时间 <code>kT</code> 对应连续的时间<code>t</code>，然后就会得到如下一系列近似的变换：</p><p><span class="math display">\[\begin{cases}t \thickapprox k \cdot T，其中 \Big(k = 0,1,2,3...\Big) \\\Biggl( \int^t_0 e(t)dt \Biggl) \thickapprox \Biggl( T \sum^k_{j=0}e(jT) \Biggl) = \Biggl( T \sum^k_{j=0} ej \Biggl) \\\Biggl (\frac{de(t)}{dt} \Biggl) = \Biggl( \frac{e(kT) - e[kT-T]}{T}\Biggl) = \Biggl(\frac{e_k - e_{k-1}}{T} \Biggl)\end{cases}\]</span></p><p>将这些近似的变换代入到前面的 PID 算法公式，并且将 <span class="math inline">\(e(kT)\)</span> 简化为 <span class="math inline">\(e_k\)</span>，就可以得到 <strong>PID算法的离散表达公式</strong>：</p><p><span class="math display">\[\begin{align}u_k &amp; = \Biggl( K_p \times e_k \Biggl) + \Biggl( K_i \times\sum^k_{j=0} e_j\Biggl) + \Biggl[ K_d \times (e_k - e_{k-1}) \Biggl] \\&amp; = K_p \times \Biggl[ e_k + \frac{T}{T_i} \times \sum^k_{j=0} e_j +T_d \times \frac{(e_k - e_{k-1})}{T} \Biggl]\end{align}\]</span></p><p>接下来的表格里，对于上述 PID离散公式当中变量的作用，分别进行了解释和说明。观察可以发现上述公式基本给出了全部控制量，因而也被称作<strong>全量式PID 控制算法</strong>，或者<strong>位置式 PID 控制算法</strong>：</p><table><colgroup><col style="width: 29%"><col style="width: 70%"></colgroup><thead><tr><th style="text-align: center;">PID 离散公式中的变量</th><th>参数说明</th></tr></thead><tbody><tr><td style="text-align: center;"><span class="math inline">\(k\)</span></td><td>采样序号，取值范围为 <span class="math inline">\(k =0,1,2,...\)</span></td></tr><tr><td style="text-align: center;"><span class="math inline">\(u_k\)</span></td><td>第 <span class="math inline">\(k\)</span> 次采样时刻，PID控制器的输出值</td></tr><tr><td style="text-align: center;"><span class="math inline">\(e_k\)</span></td><td>第 <span class="math inline">\(k\)</span> 次采样时刻，输入到 PID控制器的偏差值</td></tr><tr><td style="text-align: center;"><span class="math inline">\(e_k\)</span></td><td>第 <span class="math inline">\(k - 1\)</span> 次采样时刻，输入到 PID控制器的偏差值</td></tr><tr><td style="text-align: center;"><span class="math inline">\(K_i\)</span></td><td>积分系数，<span class="math inline">\(K_i= K_p \times\frac{T}{T_i}\)</span></td></tr><tr><td style="text-align: center;"><span class="math inline">\(K_d\)</span></td><td>微分系数，<span class="math inline">\(K_d= K_p \times\frac{T_d}{T}\)</span></td></tr></tbody></table><p>这里把位置式 PID 控制算法的优缺点，分别总结为下面的列表：</p><ul><li><strong>优点</strong>：如果 PID控制系统反馈回路的采样周期足够小，那么通过这种位置式 PID控制算法就可以近似的计算出控制量，在这个离散控制过程当中获得的效果，会与连续控制过程产生的效果非常之接近。</li><li><strong>缺点</strong>：每次全量输出都会与过去的状态有关，需要对<span class="math inline">\(e_k\)</span>进行累加，计算任务较为繁重；如果 PID控制器出现故障，可能会导致输出的控制量 <span class="math inline">\(u_k\)</span>大幅度发生变化（由于输入的是绝对数值），极有可能导致严重的工业生产事故。接下来将要介绍的<strong>增量式PID 算法</strong>，就为了解决这个问题而出现的。</li></ul><h2 id="增量式-pid-算法">增量式 PID 算法</h2><p>增量式 PID 算法输出的是控制量的<strong>增量</strong> <span class="math inline">\(\Delta U_k\)</span>，相应的 PID控制器的执行机构运行的也是这个增量，而非像位置式 PID算法那样输出一个幅度比较大的绝对数值。增量式 PID控制算法，可以通过前述的如下 PID 离散公式推导得出：</p><p><span class="math display">\[u_k = K_p \times \Biggl[ e(k) + \frac{T}{T_i} \times \sum^k_{j=0} e_j +T_d \times \frac{(e_k - e_{k-1})}{T} \Biggl]\]</span></p><p>根据这个公式，就可以知道 PID 控制器在第 <span class="math inline">\(k－1\)</span> 个采样时刻的输出控制值 <span class="math inline">\(u_{k-1}\)</span> 等于：</p><p><span class="math display">\[u_{k-1} = K_p \times \Biggl[ e_{k-1} + \frac{T}{T_i} \times\sum^{k-1}_{j=0} e_j + T_d \times \frac{(e_{k-1} - e_{k-2})}{T} \Biggl]\]</span></p><p>联立并且化简上述两组公式，就可以整理得到<strong>增量式 PID控制算法的公式</strong>：</p><p><span class="math display">\[\begin{align}\Delta u_k &amp; = u_k - u_{k-1} \\&amp; = K_p \Biggl(e_k - e_{k-1} + \frac{T}{T_i}e_k + T_d \frac{e_k -2e_{k-1} + e_{k-2}}{T} \Biggl) \\&amp; = K_p \Biggl(1 + \frac{T}{T_i} + \frac{T_d}{T} \Biggl) e_k - K_p\Biggl( 1 + \frac{2T_d}{T} \Biggl) e_{k-1} + \Biggl( K_p \frac{T_d}{T}e_{k-2} \Biggl)\end{align}\]</span></p><p>如果使用参数 <code>A</code> 来替代上面公式当中的 <span class="math inline">\(K_p \times \Big(1 + \frac{T}{T_i} + \frac{T_d}{T}\Big)\)</span> 部分，参数 <code>B</code> 替代上面公式当中的 <span class="math inline">\(K_p \times \Big( 1 + \frac{2T_d}{T} \Big)\)</span>部分，参数 <code>C</code> 替代上面公式当中的 <span class="math inline">\(K_p \times \frac{T_d}{T}\)</span>部分，就可以将增量式 PID控制算法的公式<strong>简化</strong>为下面的形式：</p><p><span class="math display">\[\begin{cases}A = K_p \times \Big(1 + \frac{T}{T_i} + \frac{T_d}{T} \Big) \\B = K_p \times \Big( 1 + \frac{2T_d}{T} \Big) \\C = K_p \times \frac{T_d}{T}\end{cases}\implies\Delta u_k = A_{e_k} - B_{e_{k-1}} + C_{e_{k-2}}\]</span></p><p>观察上述推导过程，如果 PID 控制系统采用恒定的采样周期<code>T</code>，一旦确定 <code>A</code>、<code>B</code>、<code>C</code>的参数值，仅仅只需要基于前后三次的测量偏差，就可以由上面的公式求解得到<strong>控制量</strong><span class="math inline">\(u_k\)</span>。增量式 PID控制算法相比于位置式 PID算法的运算量更少，因而实际应用更加广泛。而位置式 PID控制算法也可以通过增量式控制算法，推导得到如下的<strong>数字递推 PID控制算法</strong>的公式：</p><p><span class="math display">\[u_k = u_{k-1} + \Delta u_k\]</span></p><h2 id="pid-算法的-c-程序实现">PID 算法的 C 程序实现</h2><p>本节内容会将前面所述的繁杂 PID 数学推导，抽象为 C语言编写的<strong>板级支持包</strong>（BSP，Board SupportPackage）程序，该程序主要由 <code>BSP_PID.h</code> 头文件和<code>BSP_PID.c</code>源文件组成，以便于大家在实际工程当中参考移植。</p><h3 id="位置式-pid-的代码实现">位置式 PID 的代码实现</h3><p>对于位置式 PID 算法的程序实现，需要在头文件 <code>BSP_PID.h</code>当中定义一个名称为 <code>_PID</code> 的结构体变量，并且同时声明<code>PID_param_init()</code> 与 <code>PID_Realize()</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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">ifndef</span> __BSP_PID_H</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> __BSP_PID_H</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> &#123;</span></span><br><span class="line">  <span class="type">float</span> target_value;   <span class="comment">// 目标值</span></span><br><span class="line">  <span class="type">float</span> actual_value;   <span class="comment">// 实际值</span></span><br><span class="line"></span><br><span class="line">  <span class="type">float</span> err;            <span class="comment">// 偏差值</span></span><br><span class="line">  <span class="type">float</span> err_last;       <span class="comment">// 前一个偏差值</span></span><br><span class="line"></span><br><span class="line">  <span class="type">float</span> Kp, Ki, Kd;     <span class="comment">// 定义比例、积分、微分系数</span></span><br><span class="line"></span><br><span class="line">  <span class="type">float</span> integral;       <span class="comment">// 定义积分值</span></span><br><span class="line">&#125; _PID;</span><br><span class="line"></span><br><span class="line"><span class="keyword">extern</span> <span class="type">void</span> <span class="title function_">PID_Parameter_Init</span><span class="params">(<span class="type">void</span>)</span>;             <span class="comment">// PID 参数初始化</span></span><br><span class="line"><span class="keyword">extern</span> <span class="type">float</span> <span class="title function_">PID_Realize</span><span class="params">(<span class="type">float</span> temporary_value)</span>;  <span class="comment">// PID 算法具体实现</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br></pre></td></tr></table></figure><p>源文件 <code>BSP_PID.c</code> 当中定义的<code>PID_Parameter_Init()</code> 函数主要用于配置 PID 算法所涉及到的<span class="math inline">\(K_p\)</span>、<span class="math inline">\(K_i\)</span>、<span class="math inline">\(K_d\)</span> 等各类结构体成员参数的值：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;./BSP_PID.h&quot;</span></span></span><br><span class="line"></span><br><span class="line">_PID PID; <span class="comment">// 定义全局结构体变量</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/** @brief 初始化 PID 参数 */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">PID_Parameter_Init</span><span class="params">()</span> &#123;</span><br><span class="line">  PID.target_value = <span class="number">0.0</span>;</span><br><span class="line">  PID.actual_value = <span class="number">0.0</span>;</span><br><span class="line"></span><br><span class="line">  PID.err = <span class="number">0.0</span>;</span><br><span class="line">  PID.err_last = <span class="number">0.0</span>;</span><br><span class="line"></span><br><span class="line">  PID.integral = <span class="number">0.0</span>;</span><br><span class="line"></span><br><span class="line">  PID.Kp = <span class="number">0.31</span>;</span><br><span class="line">  PID.Ki = <span class="number">0.070</span>;</span><br><span class="line">  PID.Kd = <span class="number">0.3</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>源文件 <code>BSP_PID.c</code> 当中定义的 <code>PID_Realize()</code>函数是整个工程的核心，通过函数参数 <code>temporary_value</code>将实际值传入，目标值通过代码当中的<code>PID.err = PID.target_value - PID.actual_value</code>参与计算，然后返回一个经过 PID 计算之后的实际值<code>actual_value</code>，整个过程紧密围绕着前面定义的<code>_PID</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief  实现 PID 算法</span></span><br><span class="line"><span class="comment"> * @param  temporary_value 目标值</span></span><br><span class="line"><span class="comment"> * @retval 经过 PID 算法处理之后的输出值</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">float</span> <span class="title function_">PID_Realize</span><span class="params">(<span class="type">float</span> temporary_value)</span> &#123;</span><br><span class="line">  PID.target_value = temporary_value;            <span class="comment">// 传入目标值</span></span><br><span class="line">  PID.err = PID.target_value - PID.actual_value; <span class="comment">// 计算目标值与实际值的偏差</span></span><br><span class="line">  PID.integral += PID.err;                       <span class="comment">// 累积偏差值</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* PID 算法的具体实现 */</span></span><br><span class="line">  PID.actual_value = PID.Kp * PID.err + PID.Ki * PID.integral + PID.Kd * (PID.err - PID.err_last);</span><br><span class="line"></span><br><span class="line">  PID.err_last = PID.err;   <span class="comment">// 传递偏差值</span></span><br><span class="line">  <span class="keyword">return</span> PID.actual_value;  <span class="comment">// 返回实际值</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上面代码当中的 <code>PID 算法具体实现</code>，就是基于前面所述的 PID离散表达公式来进行实现的。不同之处在于下面公式中的第 2 项 <span class="math inline">\(K_i\)</span>使用的是对<code>偏差</code>进行<strong>积分</strong>，而在 C程序代码当中变为对<code>偏差</code>进行<strong>累加</strong>。虽然表达形式上有所不同，但是内涵和作用是基本相同的：</p><p><span class="math display">\[u(k) = K_p err(k) + K_i \sum err(k) + K_d \Big( err(k) - err(k-1) \Big)\]</span></p><p>把函数 <code>PID_Realize()</code>放置到定时器中断里进行调用，定时器每间隔 <code>20ms</code>中断一次，相应的 PID 算法也就会每 <code>20ms</code> 被执行一次（这就是PID 算法的<strong>执行周期</strong>）。通过微控制器运行之后，将<code>PID_Realize()</code> 输出的结果（也就是实际值<code>actual_value</code>）打印到串口，从而得到如下的图像：</p><p><img src="/Embedded/PID/9.png"></p><p>观察上面的数据，可以发现起初相邻两个数据差距较大，振荡较为严重。但是随着算法的持续运行，目标值与实际值之间的偏差变小，直到最后实际值会在目标值附近上下振动，这种微小的振动就是<strong>静态偏差</strong>。</p><p><img src="/Embedded/PID/10.png"></p><p>接着修改参数 <span class="math inline">\(K_p\)</span>并观察曲线的变化，上图左侧是 <span class="math inline">\(K_p =0.31\)</span>时候输出的曲线，明显是在震荡了许多次之后才逐渐趋于稳定。而右侧是 <span class="math inline">\(K_p = 0.21\)</span>时候输出的曲线，调节次数和振荡明显减少，由此可见 PID参数标定的重要性。</p><h3 id="增量式-pid-的代码实现">增量式 PID 的代码实现</h3><p>实现增量式 PID 算法，头文件 <code>BSP_PID.h</code>中依然需要定义一个名为 <code>_PID</code> 的结构体（相比于位置式 PID里的结构体，这里增加了一个 <code>err_next</code>成员变量，移除了一个表示积分值的 <code>integral</code>成员变量），并且同样声明有 <code>PID_param_init()</code> 和<code>PID_Realize()</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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">ifndef</span> __BSP_PID_H</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> __BSP_PID_H</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> &#123;</span></span><br><span class="line">  <span class="type">float</span> target_value;   <span class="comment">// 目标值</span></span><br><span class="line">  <span class="type">float</span> actual_value;   <span class="comment">// 实际值</span></span><br><span class="line"></span><br><span class="line">  <span class="type">float</span> err;            <span class="comment">// 当前偏差值</span></span><br><span class="line">  <span class="type">float</span> err_next;       <span class="comment">// 下一个偏差值</span></span><br><span class="line">  <span class="type">float</span> err_last;       <span class="comment">// 最后一个偏差值</span></span><br><span class="line"></span><br><span class="line">  <span class="type">float</span> Kp, Ki, Kd;     <span class="comment">// 比例、积分、微分系数</span></span><br><span class="line">&#125; _PID;</span><br><span class="line"></span><br><span class="line"><span class="keyword">extern</span> <span class="type">void</span> <span class="title function_">PID_Parameter_Init</span><span class="params">(<span class="type">void</span>)</span>;             <span class="comment">// PID 参数初始化</span></span><br><span class="line"><span class="keyword">extern</span> <span class="type">float</span> <span class="title function_">PID_Realize</span><span class="params">(<span class="type">float</span> temporary_value)</span>;  <span class="comment">// PID 算法具体实现</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br></pre></td></tr></table></figure><p>源文件 <code>BSP_PID.c</code> 当中定义的<code>PID_Parameter_Init()</code> 函数，同样用于设定 PID 算法所涉及到的<span class="math inline">\(K_p\)</span>、<span class="math inline">\(K_i\)</span>、<span class="math inline">\(K_d\)</span> 以及 <span class="math inline">\(err\)</span>、<span class="math inline">\(err_{last}\)</span>、<span class="math inline">\(err_{next}\)</span> 等结构体成员参数：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;./BSP_PID.h&quot;</span></span></span><br><span class="line"></span><br><span class="line">_PID PID; <span class="comment">// 定义全局结构体变量</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/** @brief 初始化 PID 参数 */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">PID_Parameter_Init</span><span class="params">()</span> &#123;</span><br><span class="line">  PID.target_value = <span class="number">0.0</span>;</span><br><span class="line">  PID.actual_value = <span class="number">0.0</span>;</span><br><span class="line"></span><br><span class="line">  PID.err = <span class="number">0.0</span>;</span><br><span class="line">  PID.err_last = <span class="number">0.0</span>;</span><br><span class="line">  PID.err_next = <span class="number">0.0</span>;</span><br><span class="line"></span><br><span class="line">  PID.Kp = <span class="number">0.20</span>;</span><br><span class="line">  PID.Ki = <span class="number">0.80</span>;</span><br><span class="line">  PID.Kd = <span class="number">0.01</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>源文件 <code>BSP_PID.c</code> 当中定义的 <code>PID_Realize()</code>函数也同样是整个工程的核心，依然是通过参数 <code>temporary_value</code>将实际值传入，然后经过一系列 PID 的计算处理之后，返回得到的实际值<code>actual_value</code>，区别主要在于代码当中 PID算法的具体实现部分：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/**</span></span><br><span class="line"><span class="comment"> * @brief  实现 PID 算法</span></span><br><span class="line"><span class="comment"> * @param  temporary_value 目标值</span></span><br><span class="line"><span class="comment"> * @retval 经过 PID 算法处理之后的输出值</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="type">float</span> <span class="title function_">PID_Realize</span><span class="params">(<span class="type">float</span> temporary_value)</span> &#123;</span><br><span class="line">  PID.target_value = temporary_value;             <span class="comment">// 传入目标值</span></span><br><span class="line">  PID.err = PID.target_value - PID.actual_value;  <span class="comment">// 计算目标值与实际值的偏差</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* PID 算法的具体实现 */</span></span><br><span class="line">  <span class="type">float</span> increment_value = PID.Kp * (PID.err - PID.err_next) + PID.Ki * PID.err + PID.Kd * (PID.err - <span class="number">2</span> * PID.err_next + PID.err_last);</span><br><span class="line">  PID.actual_value += increment_value;  <span class="comment">// 对 PID 算法的处理结果进行累加处理</span></span><br><span class="line"></span><br><span class="line">  PID.err_last = PID.err_next;          <span class="comment">// 将下一个偏差，赋值给最后一个偏差</span></span><br><span class="line">  PID.err_next = PID.err;               <span class="comment">// 将当前偏差，赋值给下一个偏差</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">return</span> PID.actual_value;              <span class="comment">// 返回实际值</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>上面代码当中的<code>PID 算法具体实现</code>，就是基于前面所述的增量式 PID算法的两个公式来进行实现的，程序代码的处理步骤（即代码中对于<code>increment_value</code> 和 <code>actual_value</code>变量值的处理过程）与 PID算法公式基本保持一致。仔细观察可以发现，<strong>增量式 PID算法总是与最近三次的偏差值相关</strong>：</p><p><span class="math display">\[\begin{cases}\Delta u(k) = \Bigg( K_p \times \Big( err(k) - err(k - 1) \Big) \Bigg) +\Bigg( K_i \times \Big( err(k) \Big) \Bigg) + \Bigg( K_d \times\Big(err(k) - 2 \times err(k-1) + err(k-2) \Big) \Bigg) \\u(k) = u(k-1) + \Delta u(k)\end{cases}\]</span></p><p>下图分别展示了 PID 系数分别等于 <span class="math inline">\(K_p=0.05\)</span>、<span class="math inline">\(K_i=0.10\)</span>、<span class="math inline">\(K_d=0.01\)</span>（下图左），以及分别为 <span class="math inline">\(K_p=0.20\)</span>、<span class="math inline">\(K_i=0.80\)</span>、<span class="math inline">\(K_d=0.01\)</span>（下图右）时候的输出曲线，可以看到不同的PID 参数标定对于输出结果的影响：</p><p><img src="/Embedded/PID/11.png"></p><h2 id="控制参数的标定">控制参数的标定</h2><p>在本文前面的内容当中，已经再三强调过 PID控制参数的标定，对于控制输出结果的重要性。虽然可以通过理想化的数学模型，计算出PID控制相关的参数，但是这种方法并不总是能完美的匹配实际工况，还需要结合一些工程化的标定方法进行调参，这些方法包括<strong>试凑法</strong>、<strong>临界比例法</strong>、<strong>一般调节法</strong>等。</p><p>首先，我们总结一下 PID 算法各个控制系数的调节作用，以便于在后续的 PID参数标定当中做到有的放矢：</p><ol type="1"><li><strong>比例系数</strong>：调节作用快，PID控制系统一旦出现<strong>偏差</strong>，就会立刻对偏差进行放大输出。</li><li><strong>积分系数</strong>：用于调节 <code>输入偏差值</code> 对于<code>输出控制信号</code> 的影响程度，如果积分系数标定得越大，那么 PID控制系统消除静态偏差的时间就会越短（但是过大的积分系数又会导致<strong>超调</strong>现象的发生）。</li><li><strong>微分系数</strong>：用于调节偏差<strong>变化量</strong>对于控制系统输出的影响程度，如果微分系数标定得越大，那么PID控制系统对于偏差量的变化就会越敏感，也就越能提前进行响应，从而抑制超调现象，但是过大的微分系数又会导致<strong>振荡</strong>现象的出现。</li></ol><h3 id="试凑法">试凑法</h3><p>基于当前控制系统的具体情况，首先试凑出几组经验值，然后观察系统输出曲线的变化规律，大致确定各个系数对于曲线的具体影响，最后再根据具体的曲线进行调整。试凑法需要遵循首先调节<code>比例系数</code>，然后调节 <code>积分系数</code>，最后调节<code>微分系数</code> 的顺序，大致上遵循如下的标定过程：</p><ol type="1"><li>按照纯比例控制系统来标定<code>比例系数</code>，得到一个比较理想的控制信号输出曲线。</li><li>把比例系数缩小 <code>1.2</code> 倍左右，再将 <code>积分系数</code>从小到大进行调整，使其输出一个满意的控制信号输出曲线。</li><li>基于上面的 <code>积分系数</code> 重新标定<code>比例系数</code>，观察输出的控制信号曲线是否有所改善。</li><li>如果存在改善，就再次修改<code>积分系数</code>，如此多次反复，直至得到一组合适的<code>比例系数</code> 和 <code>积分系数</code>。</li><li>如果外界存在干扰信号，控制系统的稳定性不佳，可以适当缩小<code>比例系数</code> 和<code>积分系数</code>，确保控制系统的稳定工作。</li><li>如果控制系统存在小幅超调，则可以在缩小 <code>比例系数</code> 和<code>积分系数</code> 的同时，适当的增大<code>微分系数</code>，从而获得超调量最小，调节作用时间最短的控制信号输出曲线。</li></ol><h3 id="临界比例法">临界比例法</h3><p>基于纯比例控制系统，按照从小到大的顺序逐渐调节<code>比例系数</code>，直至控制系统输出信号曲线出现等幅振荡，再根据经验公式计算参数。该方法大体上遵循如下的标定过程：</p><ol type="1"><li>将 <code>积分系数</code>、<code>微分系数</code> 置零，调节<code>比例系数</code>选取一个适当的值，使得控制系统按照纯比例的方式运行。</li><li>逐步增大比例系数，观察控制信号输出曲线的变化。如果曲线波动衰减，则继续增大比例系数。如果曲线波动发散，则减小比例系数，直至曲线波动呈现出等幅振荡，此时记录下这个<code>临界</code>的<strong>比例系数</strong><span class="math inline">\(\delta K\)</span>和<strong>振荡周期</strong> <span class="math inline">\(T_k\)</span>的值。</li><li>根据前面记录下的比例系数 <span class="math inline">\(\deltaK\)</span> 和振荡周期 <span class="math inline">\(T_k\)</span>值，采用如下表格当中的经验公式，就可以计算出 <span class="math inline">\(K_p\)</span>、<span class="math inline">\(K_i\)</span>、<span class="math inline">\(K_d\)</span> 的参数。</li></ol><table><colgroup><col style="width: 9%"><col style="width: 25%"><col style="width: 34%"><col style="width: 31%"></colgroup><thead><tr><th style="text-align: center;">控制环节</th><th style="text-align: center;">比例系数 <span class="math inline">\(K_p\)</span></th><th style="text-align: center;">积分系数 <span class="math inline">\(K_i\)</span></th><th style="text-align: center;">微分系数 <span class="math inline">\(K_d\)</span></th></tr></thead><tbody><tr><td style="text-align: center;"><strong>P</strong></td><td style="text-align: center;"><span class="math inline">\(\frac{\deltaK}{2}\)</span></td><td style="text-align: center;"><span class="math inline">\(0\)</span></td><td style="text-align: center;"><span class="math inline">\(0\)</span></td></tr><tr><td style="text-align: center;"><strong>PI</strong></td><td style="text-align: center;"><span class="math inline">\(\frac{\deltaK}{2.2}\)</span></td><td style="text-align: center;"><span class="math inline">\(\frac{K_p}{0.833 \times T_k}\)</span></td><td style="text-align: center;"><span class="math inline">\(0\)</span></td></tr><tr><td style="text-align: center;"><strong>PID</strong></td><td style="text-align: center;"><span class="math inline">\(\frac{\deltaK}{1.7}\)</span></td><td style="text-align: center;"><span class="math inline">\(\frac{K_p}{0.5 \times T_k}\)</span></td><td style="text-align: center;"><span class="math inline">\(0.125 \timesT_k \cdot K_p\)</span></td></tr></tbody></table><h3 id="通用调节法">通用调节法</h3><p>这种方法主要针对于一些通用的 PID控制系统，具体的标定调试过程如下面列表所示：</p><ol type="1"><li>首先，将积分系数与微分系数置零，简化控制系统为纯比例控制。</li><li>把比例系数的值设定为控制系统允许最大值的<code>60% ~ 70%</code>，逐步增大比例系数直至出现<strong>振荡</strong>，再逐渐减小比例系数直至消除<strong>振荡</strong>。</li><li>记录下此时的<strong>比例系数</strong>，并且再次将控制系统的比例系数设定为当前值的<code>60% ~ 70%</code>。</li><li>确定好比例系数后，设定一个较小的积分系数，然后逐渐增大该积分系数，同样直至出现<strong>振荡</strong>，再逐渐减小积分系数直至消除<strong>振荡</strong>。</li><li>记录下此时的<strong>积分系数</strong>，并且将控制系统的积分系数标定为当前值的<code>55% ~ 65%</code>。</li><li>通常情况下，不需要设置微分系数（标定为 <code>0</code>即可），如果出现小幅振荡，并且通过比例和积分环节无法消除，那么就可以考虑采纳与上述比例系数和积分系数标定类似的方法，此时<strong>微分系数</strong>可以取控制系统不发生振荡时值的<code>30%</code> 左右。</li><li>基于上述步骤获取的参数进行标定，分别对控制系统进行<strong>空载</strong>和<strong>带载</strong>的调试，然后再进行相应的微调，直至满足目标需求。</li></ol><h2 id="pid-参数标定实例">PID 参数标定实例</h2><p>本节内容会基于一个实际的 PID 控制系统输出曲线，展示 PID各个系数的调节效果。首先，调整<strong>比例系数</strong>（积分系数和微分系数全部设置为零），此时控制系统只有比例环节参与控制，如果控制系统的输出曲线出现下图所示的大幅振荡。需要先排除<strong>硬件</strong>上的故障（例如电压不稳、电机堵转等），排除硬件因素的影响之后，说明当前的比例系数可能标定得过大，需要可以适当减小比例系数，同时观察曲线的变化，直至曲线的大幅度振荡消失。</p><p><img src="/Embedded/PID/12.png"></p><p>若输出曲线依旧存在有如下图所示的小幅超调，并且无法再通过比例系数来优化曲线。此时可以逐步增大<strong>微分系数</strong>，同时观察输出曲线的变化，进而找出比较合适的参数。增大微分系数之后，如果输出曲线趋近于理想，则说明该控制系统只需要保留<code>比例环节</code> 和 <code>微分环节</code> 的控制。</p><p><img src="/Embedded/PID/13.png"></p><p>如果此时控制系统的实际输出值，依然无法达到目标值，始终存在有下图所示的<strong>静态误差</strong>。那么就可以改为逐步增大<strong>积分系数</strong>，并且同时观察输出曲线的变化，如果消除静态误差的时间过长，则可以继续增大积分系数（注意控制系统的超调幅度）。经过调整之后，如果输出曲线趋于理想，则说明该控制系统仅需要保留<code>比例环节</code> 和 <code>积分环节</code> 的控制：</p><p><img src="/Embedded/PID/14.png"></p><p>如果此时依然存在小幅的超调现象，那么就可以逐步增大微分系数，同时观察输出曲线的变化，进而找出最为合适的参数。实际生产环境下，自动化控制系统纷繁复杂，上面展示的标定过程仅仅只能作为参考。实际的日常工作当中，建议选择一款PID调试上位机软件，借助直观的图形化输出，便于调试出更加合理的参数标定。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;strong&gt;比例-积分-微分&lt;/strong&gt;（PID，Proportion Integration
Differentiation）是一种广泛运用于自动化控制领域的经典算法，属于众多控制算法当中最能够体现反馈思想的算法。该算法由
&lt;strong&gt;Nicolas Minorsky&lt;/strong&gt; 于 &lt;strong&gt;1922&lt;/strong&gt;
年船舶舵机控制理论的研究当中提出，随后以其卓越的性能和易于实现的特性，在
&lt;code&gt;温度控制&lt;/code&gt;、&lt;code&gt;电机调速&lt;/code&gt;、&lt;code&gt;过程控制&lt;/code&gt;
等诸多领域逐渐普及。无论是简单的单变量系统，还是复杂的多变量系统，PID
控制算法都能通过调节
&lt;code&gt;比例&lt;/code&gt;、&lt;code&gt;积分&lt;/code&gt;、&lt;code&gt;微分&lt;/code&gt;
三个参数实现精准的控制。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/Embedded/PID/logo.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;例如把一台无刷电机连接到额定输出电压为 &lt;code&gt;12V&lt;/code&gt;
的锂电池组，然后通过一个占空比为 &lt;code&gt;50%&lt;/code&gt; 的 PWM
波进行驱动，刚开始的时候电机运行速度很快且扭矩充足，但是随着时间的流逝，锂电池的放电电压逐步下降，开始影响到电机的转速和转矩。如果这块锂电池组刚充满的时候，输出电压为
&lt;code&gt;12V&lt;/code&gt;，PWM 波占空比为
&lt;code&gt;50%&lt;/code&gt;，那么作用在电机两端的等效电压为 &lt;span class=&quot;math inline&quot;&gt;&#92;(12V &#92;times 50&#92;% =
6V&#92;)&lt;/span&gt;。放电持续一段时间之后，锂电池电压降低至
&lt;code&gt;9V&lt;/code&gt;，此时电机两端的等效电压也会降低到 &lt;span class=&quot;math inline&quot;&gt;&#92;(9V &#92;times 50&#92;% =
4.5V&#92;)&lt;/span&gt;，电机的转速和转矩开始出现明显的下降。如果需要在锂电池的整个放电周期当中，保持电机
&lt;code&gt;转速&lt;/code&gt; 和 &lt;code&gt;转矩&lt;/code&gt;
的稳定，就有必要引入这里将要介绍的 PID 控制理论。&lt;/p&gt;</summary>
    
    
    
    <category term="嵌入式" scheme="http://www.uinio.com/categories/%E5%B5%8C%E5%85%A5%E5%BC%8F/"/>
    
    
    <category term="算法" scheme="http://www.uinio.com/tags/%E7%AE%97%E6%B3%95/"/>
    
  </entry>
  
  <entry>
    <title>直流无刷电机的 PWM 驱动控制原理简述</title>
    <link href="http://www.uinio.com/Electronics/Motor-PWM/"/>
    <id>http://www.uinio.com/Electronics/Motor-PWM/</id>
    <published>2024-11-06T16:00:00.000Z</published>
    <updated>2025-06-25T14:55:36.554Z</updated>
    
    <content type="html"><![CDATA[<p><strong>直流无刷电机</strong>（BLDCM，Brushless Direct CurrentMotor）没有电刷和换向装置，需要采用 PWM脉冲波来进行控制，相比于传统的直流有刷电机，其交换了定子与转子的位置（线圈绕组作为定子，钕硼永磁铁作为转子，以霍尔传感器取代碳刷进行换向），相比于传统的直流有刷电机，无刷电机需要配备专门的驱动控制电路，但是其具备更高的效率，并且能耗和噪音更低，可以伺服控制，并进行无级变频调速。</p><p><img src="/Electronics/Motor-PWM/logo.png"></p><p>普通有刷电机发生旋转的部分是绕组，而无刷电机无论是<code>内转子</code> 还是 <code>外转子</code>结构，其旋转的部分（转子）永远都是<strong>永磁体</strong>（钕铁硼磁铁）。而其<strong>定子</strong>则属于产生旋转磁场的部分，主要由<code>硅钢片</code> 和 <code>绕组</code>构成，本文旨在简单明了的介绍无刷电机的相关工作原理，作为后续撰写<strong>FOC</strong> 矢量控制算法相关内容的铺垫。</p><span id="more"></span><h1 id="左手定则">左手定则</h1><p><strong>左手定则</strong>（Left HandRule）是由英国电机工程师约翰.安布罗斯.弗莱明（John Ambrose Fleming）于1885年提出，其具体内容是让<strong>左手</strong>的<code>拇指</code>、<code>食指</code>、<code>中指</code>三个手指相互垂直，此时<strong>拇指</strong>指向就是<code>导体受力</code>的方向（即安培力），而<strong>食指</strong>指向的则是<code>磁场</code>的方向，<strong>中指</strong>则是指向的<code>电流</code>的方向：</p><p><img src="/Electronics/Motor-PWM/1-Left-Hand-Rule.png"></p><p><strong>导体受力</strong> <code>F</code>（单位为<code>N</code>）等于<strong>磁通密度</strong> <code>B</code>（单位为<code>Wb/m²</code>）与<strong>电流</strong> <code>I</code>（单位为<code>A</code>），以及磁场中的<strong>导体长度</strong><code>L</code>（单位为 <code>m</code>）的乘积：</p><p><span class="math display">\[F = B \times I \times L\]</span></p><p>左手定则说明：<strong>通电的导体在磁场当中会受到磁场力的作用</strong>。当磁场不变的时候，电流越大，导体长度越长，那么其所受到的力就会越大。这个力的大小与电流大小，以及导体的长度呈正比。</p><h1 id="右手螺旋定则">右手螺旋定则</h1><p>右手螺旋定则也称为<strong>安培定则</strong>（Ampere’sRule），由物理学家安德烈·玛丽·安培（André Marie Ampère）于 1820年提出，主要用于判断<strong>电流产生的磁场的方向</strong>。右手握持住通电的螺旋状导线，如果手掌四个指头指向的是电流环绕的方向，那么<strong>拇指</strong>所指向的就是通电螺旋状导线产生的磁场<strong>N</strong> 极。</p><p><img src="/Electronics/Motor-PWM/2-Ampere-Rule.png"></p><p>右手螺旋定则说明：通电线圈会在其周围产生一定强度的磁场，磁场方向与电流的方向有关。换而言之，如果将通电线圈放置在两个<strong>永磁体</strong>的磁极之间，那么在两个磁场力的相互作用下，线圈就会发生移动，这正是电机运行的最底层基本原理。</p><blockquote><p><strong>注意</strong>：电磁学当中的 <strong>N</strong>是指北极（North），而 <strong>S</strong> 则是指南极（South）。</p></blockquote><h1 id="有刷电机基本原理">有刷电机基本原理</h1><p>如果在中空的圆柱体形状之间放置两个永磁体，并且使它们的南北磁极相对，中间放置通电线圈。根据右手螺旋定则，线圈两端将会产生<strong>N</strong> 和 <strong>S</strong>两个极性。此时<strong>如果线圈的一个磁极被吸引，那么另外一个磁极就会被排斥</strong>，从而推动线圈朝着一个方向旋转，直到通电线圈的磁极方向与南北磁极方向相反（即通电线圈的<strong>N</strong> 极被永磁体的 <strong>S</strong> 极吸引，而<strong>S</strong> 极则被永磁体的 <strong>N</strong> 极吸引）。</p><p>此时如果改变电流的方向，就会让线圈产生的磁场极性发生变换，之前相互吸引的磁极由于磁场极性发生变换，就会产生排斥力，促使线圈开始新一轮的转动。这就是<strong>直流有刷电机</strong>（BrushMotor）的基本工作原理。</p><p><strong>有刷直流电机</strong>主要由<strong>定子</strong>、<strong>转子</strong>、<strong>换向器</strong>、<strong>电刷</strong>组成，其中定子固定不动，通常由永磁体制作。而换向器负责在特定位置改变电流的方向，使得转子上线圈的磁场始终与定子的磁场保持一定角度，确保在磁场力的作用下能够持续进行旋转。</p><p><img src="/Electronics/Motor-PWM/3-Brush-Motor.png"></p><p>上面示意图当中的 <strong>N</strong> 极与 <strong>S</strong>极是由永磁体制作的定子的两个磁极，内部则是由三组线圈绕制而成的转子。电刷的两端分别连接电源和换向器，每组线圈的换向器之间会使用绝缘材料进行隔离。</p><p>直流有刷电机通过电刷进行换向，可以方便的通过<strong>电压</strong>进行调速。并且励磁方向始终与定子磁场方向呈现一定角度，从而可以保持较大的转矩。但是缺点在于电刷容易磨损，运行噪音会比较大，需要定期进行更换，且电刷与换向器的接触面上会产生摩擦粉尘。</p><h1 id="无刷电机工作原理">无刷电机工作原理</h1><p><strong>直流无刷电机</strong>通过微控制器代替电刷进行换向，同时采用<strong>霍尔传感器</strong>或者<strong>对感应电动势的过零点进行采样</strong>，来实时检测转子的位置。其基本工程流程是：微控制器根据霍尔传感器或者感应电动势获取转子的状态，然后通过驱动电路控制三相线圈的通断顺序，从而完成换向。下图展示了三相直流无刷电机的内部结构，该示意图当中只是简单描述了三相定子的<code>U</code>、<code>V</code>、<code>W</code>三组线圈（<strong>每一组线圈</strong>就称为无刷电机的一个<strong>相</strong>），实际上的线圈通常会采用多组对称缠绕方式：</p><p><img src="/Electronics/Motor-PWM/4-Brushless-Motor.png"></p><p>而下面是一个典型的无刷直流电机的驱动电路原理图，通过三组共 6 枚功率MOS 管（每一组拥有 2 枚功率 MOS管，其<strong>源极</strong>分别会连接到正极和负极）的通断状态来控制三相无刷电机的转动：</p><p><img src="/Electronics/Motor-PWM/5-Brushless-Motor-Driver.png"></p><p>由于直流无刷电机需要增加额外的微控制器、霍尔传感器、过零点采样电路，所以整体生产制造成本会更高，但是也会获得更加灵活的编程控制方式。</p><h1 id="无刷和有刷电机结构区别">无刷和有刷电机结构区别</h1><p><strong>有刷电机</strong>由永磁体制作的<strong>定子</strong>（Stator）位于电机的外侧，而线圈绕制的<strong>转子</strong>（Rotor）则位于电机的中心位置：</p><p><img src="/Electronics/Motor-PWM/6-Brush.png"></p><p><strong>无刷电机</strong> <code>定子</code> 与 <code>转子</code>的位置正好相反，其永磁体制作的<strong>转子</strong>（Rotor）位于电机的中心位置，而线圈绕制的<strong>定子</strong>（Stator）则处于电机的外侧：</p><p><img src="/Electronics/Motor-PWM/7-Brushless.png"></p><blockquote><p><strong>注意</strong>：在上述两张结构示意图当中，有刷电机与无刷电机的<strong>线圈绕组</strong>都采用了<strong>多组对称</strong>的方式进行绕制。</p></blockquote><h1 id="无刷电机的换向原理">无刷电机的换向原理</h1><p>无刷电机的换向主要依靠<strong>霍尔传感器</strong>或者对<strong>感应电动势</strong>进行过零点采样，其中开关型的<strong>霍尔传感器</strong>是一种磁场敏感元件，经过南北磁极时，其输出信号会呈现高低电平变化。通常会将三个霍尔传感器放置在定子的换向边，并像下图那样分别呈<code>120°</code> 电角度进行摆放：</p><p><img src="/Electronics/Motor-PWM/8-Hall.png"></p><p>当定子发生换向时，霍尔传感器就会输出高低电平的变化，从而检测出定子的换向行为。每当霍尔传感器经过磁极的时候，其输出状态就会改变一次，每旋转1 个磁场旋转周期，每个霍尔传感器会改变 2次状态，三个霍尔传感器一共会改变 6次状态。除了基于霍尔传感器的有感换向方案之外，基于感应电动势的无感换向控制方案，则会在本文后续内容当中进行更为详细的探讨。</p><h1 id="无刷电机的主要性能指标">无刷电机的主要性能指标</h1><p>在下面的表格当中，总结了直流无刷电机的几个重要性能指标：</p><table><colgroup><col style="width: 11%"><col style="width: 88%"></colgroup><thead><tr><th>性能指标</th><th>参数说明</th></tr></thead><tbody><tr><td><strong>槽数 N</strong></td><td>定子上面硅钢片齿槽的数量。</td></tr><tr><td><strong>极数 P</strong></td><td>转子上面永磁体的数量。</td></tr><tr><td><strong>额定工作电压</strong></td><td>是指无刷电机在指定负载条件下能够正常稳定工作的电压值，通常会基于额定电压来标注额定转速。</td></tr><tr><td><strong>最大工作电流</strong></td><td>直流无刷电机能够安全稳定工作的最大电流值。</td></tr><tr><td><strong>KV 值</strong></td><td>无刷电机在 <code>1V</code>工作电压下的每分钟转速，直流无刷电机的<strong>转速</strong>与<strong>电压</strong>呈正比关系，因而<code>最大空转转速 = KV值 * 工作电压</code>。</td></tr><tr><td><strong>转矩</strong></td><td>无刷电机当中转子产生的可以用来带动机械负载的驱动力矩，可以简单的理解为电机转动的力量。</td></tr><tr><td><strong>转速</strong></td><td>无刷电机每分钟的转动速度，转矩和转速两个参数属于此消彼长的关系，转速越高，转矩就会越低，反之亦然。</td></tr><tr><td><strong>相电感</strong> <span class="math inline">\(L_S\)</span></td><td>单位为<strong>亨利</strong><code>H</code>，即电机静止时候，定子<strong>绕组两端</strong>的电感值的一半。</td></tr><tr><td><strong>相电阻</strong> <span class="math inline">\(R_S\)</span></td><td>单位为<strong>欧姆</strong><code>Ω</code>，无刷电机<strong>两相之间</strong>电阻值的一半。</td></tr></tbody></table><h1 id="pwm-方波控制原理">PWM 方波控制原理</h1><p>采用 PWM脉冲波驱动三相无刷电机时，每次只会为其中的<strong>两相</strong>进行通电（一相连接到电源正极，一相连接到电源负极，另外一相浮空）。此时，电流会从电源正极流入，进入其中的一相，然后从另外一相回流至电源负极。</p><p><img src="/Electronics/Motor-PWM/9-Control.png"></p><ol type="1"><li>关断 <strong>A 相</strong>连接的 <span class="math inline">\(Q_1\)</span> 与 <span class="math inline">\(Q_2\)</span> 两个功率管，使得电机的 A相<strong>浮空</strong>。</li><li>开启 <strong>B 相</strong>连接的上桥臂功率管 <span class="math inline">\(Q_3\)</span>，使得 B相连被接至<strong>电源正极</strong>（由于上下两个功率管同时导通会发生短路，因而<span class="math inline">\(Q_3\)</span> 开通的时候 <span class="math inline">\(Q_4\)</span> 必须关断）。</li><li>关断 <strong>C 相</strong>连接的上桥臂功率管 <span class="math inline">\(Q_5\)</span>，下桥臂功率管 <span class="math inline">\(Q_6\)</span> 开通，使得 C相连接至<strong>电源负极</strong>。</li></ol><p>这种情况下，电流就会从<strong>电源正极</strong>经过 <span class="math inline">\(Q_3\)</span> 流入电机的 <strong>B相</strong>，然后从电机的 <strong>C 相</strong>流出，最后通过 C相的下桥臂功率管 <span class="math inline">\(Q_6\)</span>进入<strong>电源负极</strong>。</p><p>通电的线圈会产生磁场，从而在定子磁场的作用下产生一定角度旋转。此时如果根据霍尔传感器输出的状态，改变功率管的通断顺序，转子就会转动至下一个位置。每改变一次功率管的通断顺序就进行了一次<strong>换向</strong>，一个旋转周期需要进行<strong>六次换向</strong>。如果根据霍尔传感器的输出状态，按照下面表格所示的顺序。周期性切换功率管的通断，那么转子就会持续进行旋转：</p><table><colgroup><col style="width: 21%"><col style="width: 21%"><col style="width: 21%"><col style="width: 18%"><col style="width: 5%"><col style="width: 5%"><col style="width: 5%"></colgroup><thead><tr><th style="text-align: center;">霍尔传感器 <span class="math inline">\(H_1\)</span></th><th style="text-align: center;">霍尔传感器 <span class="math inline">\(H_2\)</span></th><th style="text-align: center;">霍尔传感器 <span class="math inline">\(H_3\)</span></th><th style="text-align: center;">导通的功率管</th><th style="text-align: center;">A 相</th><th style="text-align: center;">B 相</th><th style="text-align: center;">C 相</th></tr></thead><tbody><tr><td style="text-align: center;">高电平</td><td style="text-align: center;">低电平</td><td style="text-align: center;">高电平</td><td style="text-align: center;"><span class="math inline">\(Q_3\)</span>和 <span class="math inline">\(Q_6\)</span></td><td style="text-align: center;">浮空</td><td style="text-align: center;">正极</td><td style="text-align: center;">负极</td></tr><tr><td style="text-align: center;">低电平</td><td style="text-align: center;">低电平</td><td style="text-align: center;">高电平</td><td style="text-align: center;"><span class="math inline">\(Q_3\)</span>和 <span class="math inline">\(Q_2\)</span></td><td style="text-align: center;">负极</td><td style="text-align: center;">正极</td><td style="text-align: center;">浮空</td></tr><tr><td style="text-align: center;">低电平</td><td style="text-align: center;">高电平</td><td style="text-align: center;">高电平</td><td style="text-align: center;"><span class="math inline">\(Q_5\)</span>和 <span class="math inline">\(Q_2\)</span></td><td style="text-align: center;">负极</td><td style="text-align: center;">浮空</td><td style="text-align: center;">正极</td></tr><tr><td style="text-align: center;">低电平</td><td style="text-align: center;">高电平</td><td style="text-align: center;">低电平</td><td style="text-align: center;"><span class="math inline">\(Q_5\)</span>和 <span class="math inline">\(Q_4\)</span></td><td style="text-align: center;">浮空</td><td style="text-align: center;">负极</td><td style="text-align: center;">正极</td></tr><tr><td style="text-align: center;">高电平</td><td style="text-align: center;">高电平</td><td style="text-align: center;">低电平</td><td style="text-align: center;"><span class="math inline">\(Q_1\)</span>和 <span class="math inline">\(Q_4\)</span></td><td style="text-align: center;">正极</td><td style="text-align: center;">负极</td><td style="text-align: center;">浮空</td></tr><tr><td style="text-align: center;">高电平</td><td style="text-align: center;">低电平</td><td style="text-align: center;">低电平</td><td style="text-align: center;"><span class="math inline">\(Q_1\)</span>和 <span class="math inline">\(Q_6\)</span></td><td style="text-align: center;">正极</td><td style="text-align: center;">浮空</td><td style="text-align: center;">负极</td></tr></tbody></table><p>上述表格体现的是转子<strong>逆时针</strong>旋转时，<strong>霍尔传感器输出状态</strong>与<strong>电机各相</strong>的通电顺序。如果是顺时针旋转，那么通电顺序正好相反。</p><blockquote><p><strong>注意</strong>：旋转过程当中，<strong>定子磁场</strong>与<strong>转子磁场</strong>始终会保持适当的角度差，通过调整定子磁场领先转子磁场的角度，可以提高电机产生的力矩。</p></blockquote><p>由于由于电机的三相每间隔 <code>120°</code>电角度（磁场旋转角度，其值等于<code>机械角度 x 电极对数</code>）进行摆放，所以三个霍尔传感器的输出信号波形也会间隔<code>120°</code>。除此之外，每个霍尔传感器的输出状态会每间隔<code>180°</code>改变一次，由于三个霍尔传感器会将整个平面划分为六个扇区，所以每间隔<code>60°</code>电角度，三个霍尔传感器的输出状态组合就会改变一次，下面的示意图展示了霍尔传感器的输出状态与其电角度之间的这种位置关系：</p><p><img src="/Electronics/Motor-PWM/10-Control.png"></p><p>直流电机的<strong>转速</strong>与<strong>电压</strong>呈正比，这意味着通过改变功率管的PWM 占空比就可以进行调速（相当于改变了电机相线上的等效电压），PWM频率一般在 20KHz 左右，常见的调节方式具有如下几种：</p><ul><li><span class="math inline">\(H_{PWM}/L_{ON}\)</span>：其中一相的<strong>下桥臂</strong>一直开通，只调节另一相的<strong>上桥臂</strong>。例如上面表格里的第一个状态，设置B 相为正 C 相为负，功率管 <span class="math inline">\(Q_3\)</span> 和<span class="math inline">\(Q_6\)</span> 导通，电流从电源的正极经过<span class="math inline">\(Q_3\)</span> 流向电机的 B 相，再经过 C相流出，最后经过功率管 <span class="math inline">\(Q_6\)</span>进入电源负极，此时可以只调节上桥臂 <span class="math inline">\(Q_3\)</span> 的占空比，而 <span class="math inline">\(Q_6\)</span> 一直保持开启。</li><li><span class="math inline">\(H_{ON}/L_{PWM}\)</span>：其中一相的<strong>上桥臂</strong>一直开通，只调节另一相的<strong>下桥臂</strong>。例如功率管<span class="math inline">\(Q_3\)</span> 保持打开状态，而只调节功率管<span class="math inline">\(Q_6\)</span>。</li><li><span class="math inline">\(H_{PWM}/L_{PWM}\)</span>：<strong>互补调节</strong>两相桥臂对应的功率管，例如<span class="math inline">\(Q_3\)</span> 和 <span class="math inline">\(Q_4\)</span> 为一组互补输出，<span class="math inline">\(Q_5\)</span> 与 <span class="math inline">\(Q_6\)</span> 为一组互补输出，而 <span class="math inline">\(Q_1\)</span> 和 <span class="math inline">\(Q_0\)</span>关断。互补的优点在于上管关断的瞬间，电流可以立刻由下管进行续流，而不需要经过功率管内部的续流二极管，从而避免大电流损坏功率管。这种方式是实际开发工作当中，相对比较常用的一种方式。</li></ul><h1 id="更为简单直观的演示总结">更为简单直观的演示总结</h1><p><strong>无刷直流电机</strong>（BLDC，Brushless DirectCurrent）属于同步电机，下面是一款 <code>1400KV</code>的航模用三相无刷电机的实物图：</p><p><img src="/Electronics/Motor-PWM/11-BLDC.png"></p><p>无刷电机的<strong>定子</strong>通常由三个星形连接的<code>线圈绕组</code>构成，而<strong>转子</strong>则使用<code>永磁体</code>制作。通过合适的顺序为<strong>定子</strong>通电，就可以在定子上产生一个旋转的磁场，使得<strong>转子</strong>的固定磁极跟随这个旋转的磁场，有序的进行旋转：</p><p><img src="/Electronics/Motor-PWM/12-Animation.gif"></p><p>无刷电机一般通过 6 个 MOS管组成的<strong>三相逆变电路</strong>进行驱动，这个逆变电路通常都是由 3组<strong>半桥 MOS 管电路</strong>（即由 2 个 MOS管组成<code>上桥臂</code>和<code>下桥臂</code>，并从中间抽出一条输出线）制作而成。通过控制上下桥臂MOS 管的开关顺序，就可以在定子上产生出上述的旋转磁场：</p><p><img src="/Electronics/Motor-PWM/13-MOS.png"></p><p>下面的表格，展示了<strong>上桥臂</strong>、<strong>下桥臂</strong>的导通顺序，与<strong>相电流</strong>的流向之间的关系：</p><table><thead><tr><th style="text-align: center;">上臂导通</th><th style="text-align: center;">下臂导通</th><th style="text-align: center;">相电流 A</th><th style="text-align: center;">相电流 B</th><th style="text-align: center;">相电流 C</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>UH</strong></td><td style="text-align: center;"><strong>WL</strong></td><td style="text-align: center;"><code>DC+</code></td><td style="text-align: center;"><code>悬空</code></td><td style="text-align: center;"><code>DC-</code></td></tr><tr><td style="text-align: center;"><strong>UH</strong></td><td style="text-align: center;"><strong>VL</strong></td><td style="text-align: center;"><code>DC+</code></td><td style="text-align: center;"><code>DC-</code></td><td style="text-align: center;"><code>悬空</code></td></tr><tr><td style="text-align: center;"><strong>WH</strong></td><td style="text-align: center;"><strong>VL</strong></td><td style="text-align: center;"><code>悬空</code></td><td style="text-align: center;"><code>DC-</code></td><td style="text-align: center;"><code>DC+</code></td></tr><tr><td style="text-align: center;"><strong>WH</strong></td><td style="text-align: center;"><strong>UL</strong></td><td style="text-align: center;"><code>DC-</code></td><td style="text-align: center;"><code>悬空</code></td><td style="text-align: center;"><code>DC+</code></td></tr><tr><td style="text-align: center;"><strong>VH</strong></td><td style="text-align: center;"><strong>UL</strong></td><td style="text-align: center;"><code>DC-</code></td><td style="text-align: center;"><code>DC+</code></td><td style="text-align: center;"><code>悬空</code></td></tr><tr><td style="text-align: center;"><strong>VH</strong></td><td style="text-align: center;"><strong>WL</strong></td><td style="text-align: center;"><code>悬空</code></td><td style="text-align: center;"><code>DC+</code></td><td style="text-align: center;"><code>DC-</code></td></tr></tbody></table><p>通过将<strong>上桥臂</strong>的控制信号设置为 PWM信号，就可以通过控制 PWM 的占空比，达到控制无刷电机转动速度的目的：</p><p><img src="/Electronics/Motor-PWM/14-PWM.png"></p><blockquote><p><strong>注意</strong>：上下桥臂不能同时导通，否则会短路。因此需要引入<strong>死区控制</strong>，来避免同一个<strong>相</strong>的上下桥臂同时被导通。</p></blockquote><h1 id="关于换相原理的进一步讨论">关于换相原理的进一步讨论</h1><p>如前所述，在实际的电机控制场景当中，需要获取当前<strong>转子</strong>的位置，并且计算出下一步导通的<strong>桥臂</strong>，从而使得电机开始旋转。获取转子的位置，一般会采用<strong>有感</strong>和<strong>无感</strong>两种检测方式。</p><h2 id="有感检测">有感检测</h2><h3 id="基于霍尔传感器的有感检测">基于霍尔传感器的有感检测</h3><p>无刷电机一般使用 3个开关型霍尔传感器来检测<strong>转子</strong>的位置，每一个霍尔传感器相隔<code>120°</code> 进行安装，如下图所示：</p><p><img src="/Electronics/Motor-PWM/15-Hall.png"></p><p>当<strong>转子</strong>的 N 极靠近霍尔传感器时输出高电平，当 N极远离霍尔传感器时输出低电平。当转子转动一圈时，就会产生如下的波形：</p><p><img src="/Electronics/Motor-PWM/16-Hall-PWM.png"></p><p>使用有感的霍尔传感器，会增加无刷电机的生产制造成本，并且增加接线安装费用。同时传感器一旦发生故障，就会导致电机无法正常工作。</p><h2 id="无感检测">无感检测</h2><p>无感控制策略主要包括<strong>反电动势法</strong>、<strong>电感法</strong>、<strong>续流二极管法</strong>等等，其中<strong>反电动势法</strong>的应用最为广泛和成熟。根据<strong>楞次定律</strong>（感应电流的方向总是使其产生的磁场阻碍引起感应电流的磁通量变化），<strong>反电动势</strong>的<code>极性</code>与绕组上<strong>主电压</strong>的<code>极性</code>相反，反电动势<code>BEMF</code> 的计算公式如下所示：</p><p><span class="math display">\[反电动势 BEMF = 绕组匝数 N \times 转子长度 l \times 转子内半径 r \times转子磁场 B \times 转子角速度 \omega\]</span></p><p>无刷电机生产制作完成之后，<code>转子磁场</code> 和<code>绕组匝数</code>等参数都是固定的，唯一能够决定反电动势的参数就是<code>角速度</code>，即<strong>转子</strong>的<code>转速</code>。每一次换向的时候，都有一个绕组为正，另外一个为负，第三个则保持开路状态。通过检测各相绕组的<strong>反电动势过零点</strong>，就能够在一个电周期内，获得转子的6个位置。下面的示意图，展示了无刷电机旋转一个周期时，每个<strong>相</strong>通过的<code>电流</code>与<code>反电动势</code>的波形：</p><p><img src="/Electronics/Motor-PWM/17-BEMF.png"></p><blockquote><p><strong>注意</strong>：每一相的反电动势均存在由<code>正</code>到<code>负</code>，以及由<code>负</code>到<code>正</code>的情况，因此三相无刷电机一共存在有6 种过零状态。</p></blockquote><p>实际开发工作当中，基于反电动势 <code>BEMF</code>的过零点检测，主要存在有 <strong>ADC采样</strong>、<strong>比较器检测</strong>、<strong>相电流采集</strong>三种方案，其中最后一种属于<strong>无感 FOC控制方案</strong>，而前面两种则属于<strong>无感方波控制方案</strong>，接下来将分别介绍这两种方案。</p><blockquote><p><strong>注意</strong>：当无刷电机的转速极慢的时候，反电动势的幅度值非常低，因而很难检测到过零点。</p></blockquote><h3 id="基于-adc-采样的无感检测">基于 ADC 采样的无感检测</h3><p>无刷电机转动的时候，反电动势在<strong>过零点</strong>会出现浮空相，此时通过检测各<strong>相</strong>的对<strong>地</strong>电压，并与<strong>直流母线电压</strong>进行对比。当端电压等于直流母线电压的一半时，就认为发生了过零点事件。换而言之，基于ADC的过零点检测方案，就是通过同时测量<strong>端电压</strong>与<strong>直流母线电压</strong>，通过对比来判断当前是否处于过零点：</p><p><img src="/Electronics/Motor-PWM/18-ADC.png"></p><p>下面展示的是一个 ADC过零点检测电路的硬件原理图，通常为了简化计算流程，<code>端电压</code>与<code>直流母线电压</code>会采用相同的分压系数。例如在<code>12V</code> 无刷电机控制方案中，可以采用 <span class="math inline">\(1:21\)</span>的分压方案，从而控制<code>直流母线电压</code>与<code>端电压</code>处于在电机控制芯片ADC 能够采集的范围：</p><p><img src="/Electronics/Motor-PWM/18-ADC-Hardware.png"></p><h3 id="基于比较器的无感检测">基于比较器的无感检测</h3><p>无刷电机转动的时候，反电动势在<strong>过零点</strong>会出现浮空相，此时通过检测各<strong>相</strong>的对<strong>地</strong>电压，并与<strong>中性点电压</strong>进行比较。当<code>端电压</code>从大于<code>中性点电压</code>，转变为小于<code>中性点电压</code>，或者<code>端电压</code>从小于<code>中性点电压</code>，变为大于<code>中性点电压</code>，就可以将其视为过零点。通常情况下，无刷电机不会引出中性点，导致无法直接测量中性点的电压。</p><p><img src="/Electronics/Motor-PWM/19-Comparator.png"></p><p>在基于比较器的过零点检测方案当中，可以将三相绕组通过<strong>相同阻值</strong>的电阻器连接到公共点，以此来构建一个中性点，并将该<code>中性点电压</code>与<code>端电压</code>通过<strong>比较器</strong>进行比较，从而获得过零点的信号。</p><p><img src="/Electronics/Motor-PWM/20-Comparator-Hardware.png"></p><p>上面是一个基于比较器的无感检测电路原理图，通过使用相同阻值的<code>R46</code>、<code>R47</code>、<code>R48</code>电阻连接各相，从而构建出了一个虚拟的中性点。</p><h1 id="pwm-控制方式的缺陷">PWM 控制方式的缺陷</h1><p>虽然 PWM 电机控制算法比较简单，而且硬件 BOM成本也比较低，但是也存在着如下一系列显著的缺点：</p><ol type="1"><li>采用 PWM脉冲宽度调制方式驱动无刷电机，由于电机的<strong>相电流</strong>只有<code>通</code>和<code>断</code>两种状态，即使在占空比和平均电流都很小的情况下，线圈上的<strong>脉动峰值电流</strong>也会比较大。由于发热量与电流的平方成正比，因而PWM 方式控制的电机，功率损耗和发热量都会比较大。</li><li>由于 PWM 控制的电磁场不够连续，导致电机的转矩出现脉动。因而 PWM并不适用于转矩要求较高的场合，否则会导致控制精度降低。除此之外，转矩的脉动还会使得系统振动产生噪声，干扰PCB 上其它芯片和传感器的工作。</li></ol><p>为了解决上述问题，西门子公司的工程师 <strong>F.Blaschke</strong>在上世纪 70 年代提出了<strong>矢量控制方法</strong>（VectorControl），即处理时会将三相输出电流与电压以矢量方式来进行表示。其本质是将三相交流信号经过一系列坐标变换，转变为直流可控的两相正交电流。从而解耦复杂的电流关系，使得交流电机变得简单可控。这种控制方法，也被称作<strong>磁场导向控制</strong>（FOC，FieldOriented Control），后续我会为此再撰写一篇专题文章。</p><blockquote><p><strong>注意</strong>：笔者在撰写本文过程当中，还发现了这篇图文并茂的英文资料<a href="https://howtomechatronics.com/how-it-works/how-brushless-motor-and-esc-work/">《HowBrushless DC MotorWorks?》</a>，大家可以结合本文一起阅读，便于快速的理解并掌握三相无刷电机的PWM 波控制原理。</p></blockquote>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;strong&gt;直流无刷电机&lt;/strong&gt;（BLDCM，Brushless Direct Current
Motor）没有电刷和换向装置，需要采用 PWM
脉冲波来进行控制，相比于传统的直流有刷电机，其交换了定子与转子的位置（线圈绕组作为定子，钕硼永磁铁作为转子，以霍尔传感器取代碳刷进行换向），相比于传统的直流有刷电机，无刷电机需要配备专门的驱动控制电路，但是其具备更高的效率，并且能耗和噪音更低，可以伺服控制，并进行无级变频调速。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/Electronics/Motor-PWM/logo.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;普通有刷电机发生旋转的部分是绕组，而无刷电机无论是
&lt;code&gt;内转子&lt;/code&gt; 还是 &lt;code&gt;外转子&lt;/code&gt;
结构，其旋转的部分（转子）永远都是&lt;strong&gt;永磁体&lt;/strong&gt;（钕铁硼磁铁）。而其&lt;strong&gt;定子&lt;/strong&gt;则属于产生旋转磁场的部分，主要由
&lt;code&gt;硅钢片&lt;/code&gt; 和 &lt;code&gt;绕组&lt;/code&gt;
构成，本文旨在简单明了的介绍无刷电机的相关工作原理，作为后续撰写
&lt;strong&gt;FOC&lt;/strong&gt; 矢量控制算法相关内容的铺垫。&lt;/p&gt;</summary>
    
    
    
    <category term="硬件电子技术" scheme="http://www.uinio.com/categories/%E7%A1%AC%E4%BB%B6%E7%94%B5%E5%AD%90%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="电机" scheme="http://www.uinio.com/tags/%E7%94%B5%E6%9C%BA/"/>
    
  </entry>
  
  <entry>
    <title>美国电子工业联盟 E 系列标准参数值速查手册</title>
    <link href="http://www.uinio.com/Electronics/E-Series/"/>
    <id>http://www.uinio.com/Electronics/E-Series/</id>
    <published>2024-11-05T16:00:00.000Z</published>
    <updated>2025-06-25T14:55:36.413Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://ecia.memberclicks.net/"><strong>电子工业联盟</strong></a>（<strong>ECIA</strong>，ElectronicsIndustry Alliance）是一个由美国电子产品生产制造企业组成的一个组织，由其<a href="https://ecia.memberclicks.net/eia-standards-committee">EIA标准化委员会</a> 提出的 <strong>E系列标准参数值（E-series）</strong>是现代全球电子工业当中，<code>电阻器</code>、<code>电容器</code>、<code>电感器</code>、<code>齐纳二极管</code>等分立式电子元器件的<strong>标准参数值系统</strong>，其主要包括<strong>E3</strong>、<strong>E6</strong>、<strong>E12</strong>、<strong>E24</strong>、<strong>E48</strong>、<strong>E96</strong>和 <strong>E192</strong>七个系列，每个系列都对应着不同的<strong>精度</strong>与<strong>误差</strong>。基于产品通用性和兼容性的考量，目前全球各大半导体企业都基于该标准生产制造分立式元件。</p><p><img src="/Electronics/E-Series/logo.png"></p><p>系统电源树乃至于开关电源的设计，是广大电子工程师在日常工作当中，绕不开的一个重要环节。而在开关电源的选型设计过程当中，经常需要使用精密电阻器作为DC-DC电源芯片的外围配置电阻。但是临时抱佛脚在网络上检索的标准取值往往不够严谨与权威，难以保证参数值选取的准确性。所以我才基于EIA标准化委员会的相关官方资料，整理并且撰写了本文，便于在日常工作当中快速的确定各种精密分立式元器件的电气参数。</p><span id="more"></span><h1 id="标准值与误差">标准值与误差</h1><p><strong>E系列标准参数值</strong>（E-series）是一套十倍进制的<strong>标准参数值</strong>系统，例如以E6 标准参数值生产的电阻器，在 <code>1Ω~10Ω</code> 范围拥有着 6个不同阻值的电阻器，而在 <code>10Ω~100Ω</code> 范围之间依然有着 6个不同阻值的电阻器。除此之外需要注意的是，每一套 E系列标准参数值对应的元器件精度都会有所不同，具体的对应关系请参照下面的表格：</p><table><thead><tr><th style="text-align: center;">E 系列名称</th><th style="text-align: left;">精度/误差</th><th style="text-align: center;">每十倍进制标准参数值的个数</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>E3</strong></td><td style="text-align: left;">高于 <code>&gt;20%</code></td><td style="text-align: center;"><strong>3</strong> 个标准参数值</td></tr><tr><td style="text-align: center;"><strong>E6</strong></td><td style="text-align: left;"><code>20%</code></td><td style="text-align: center;"><strong>6</strong> 个标准参数值</td></tr><tr><td style="text-align: center;"><strong>E12</strong></td><td style="text-align: left;"><code>10%</code></td><td style="text-align: center;"><strong>12</strong> 个标准参数值</td></tr><tr><td style="text-align: center;"><strong>E24</strong></td><td style="text-align: left;"><code>5%</code></td><td style="text-align: center;"><strong>24</strong> 个标准参数值</td></tr><tr><td style="text-align: center;"><strong>E48</strong></td><td style="text-align: left;"><code>2%</code></td><td style="text-align: center;"><strong>48</strong> 个标准参数值</td></tr><tr><td style="text-align: center;"><strong>E96</strong></td><td style="text-align: left;"><code>1%</code></td><td style="text-align: center;"><strong>96</strong> 个标准参数值</td></tr><tr><td style="text-align: center;"><strong>E192</strong></td><td style="text-align: left;"><code>0.5%</code> 或 <code>0.25%</code>甚至更低</td><td style="text-align: center;"><strong>192</strong> 个标准参数值</td></tr></tbody></table><blockquote><p><strong>注意</strong>：<strong>E</strong>字母后面的数值，即表示该标准值系统所拥有的<strong>基本参数值</strong>个数。</p></blockquote><h1 id="e3-系列标准值">E3 系列标准值</h1><p><strong>E3 系列</strong>只拥有<strong>1.0</strong>、<strong>2.2</strong>、<strong>4.7</strong>三个标准参数值，例如该系列对应的电阻值如下面表格所示：</p><table><thead><tr><th style="text-align: center;">E 系列</th><th>对应的电阻值示例</th><th style="text-align: center;">单位</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>E3</strong></td><td>1.0、2.2、4.7</td><td style="text-align: center;"><code>Ω</code></td></tr><tr><td style="text-align: center;"><strong>E3</strong></td><td>10、 22、 47</td><td style="text-align: center;"><code>Ω</code></td></tr><tr><td style="text-align: center;"><strong>E3</strong></td><td>100、220、470</td><td style="text-align: center;"><code>Ω</code></td></tr><tr><td style="text-align: center;"><strong>E3</strong></td><td>1.0、2.2、4.7</td><td style="text-align: center;"><code>KΩ</code></td></tr><tr><td style="text-align: center;"><strong>E3</strong></td><td>10、 22、 47</td><td style="text-align: center;"><code>KΩ</code></td></tr></tbody></table><h1 id="e6-系列标准值">E6 系列标准值</h1><p><strong>E6 系列</strong>拥有<strong>1.0</strong>、<strong>1.5</strong>、<strong>2.2</strong>、<strong>3.3</strong>、<strong>4.7</strong>、<strong>6.8</strong>六个标准参数值，例如该系列对应的电阻值如下面表格所示：</p><table><thead><tr><th style="text-align: center;">E 系列</th><th>对应的电阻值示例</th><th style="text-align: center;">单位</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>E6</strong></td><td>1.0、1.5、2.2、3.3、4.7、6.8</td><td style="text-align: center;"><code>Ω</code></td></tr><tr><td style="text-align: center;"><strong>E6</strong></td><td>10、15、22、33、47、68</td><td style="text-align: center;"><code>Ω</code></td></tr><tr><td style="text-align: center;"><strong>E6</strong></td><td>100、150、220、330、470、680</td><td style="text-align: center;"><code>Ω</code></td></tr><tr><td style="text-align: center;"><strong>E6</strong></td><td>1.0、1.5、2.2、3.3、4.7、6.8</td><td style="text-align: center;"><code>KΩ</code></td></tr><tr><td style="text-align: center;"><strong>E6</strong></td><td>10、15、22、33、47、68</td><td style="text-align: center;"><code>KΩ</code></td></tr></tbody></table><h1 id="e12-系列标准值">E12 系列标准值</h1><p><strong>E12 系列</strong>拥有<strong>1.0</strong>、<strong>1.2</strong>、<strong>1.5</strong>、<strong>1.8</strong>、<strong>2.2</strong>、<strong>2.7</strong>、<strong>3.3</strong>、<strong>3.9</strong>、<strong>4.7</strong>、<strong>5.6</strong>、<strong>6.8</strong>、<strong>8.2</strong>十二个标准参数值，例如该系列对应的电阻值如下面表格所示：</p><table><colgroup><col style="width: 10%"><col style="width: 84%"><col style="width: 5%"></colgroup><thead><tr><th style="text-align: center;">E 系列</th><th>对应的电阻值示例</th><th style="text-align: center;">单位</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>E12</strong></td><td>1.0、1.2、1.5、1.8、2.2、2.7、3.3、3.9、4.7、5.6、6.8、8.2</td><td style="text-align: center;"><code>Ω</code></td></tr><tr><td style="text-align: center;"><strong>E12</strong></td><td>10、12、15、18、22、27、33、39、47、56、68、82</td><td style="text-align: center;"><code>Ω</code></td></tr><tr><td style="text-align: center;"><strong>E12</strong></td><td>100、120、150、180、220、270、330、390、470、560、680、820</td><td style="text-align: center;"><code>Ω</code></td></tr><tr><td style="text-align: center;"><strong>E12</strong></td><td>1.0、1.2、1.5、1.8、2.2、2.7、3.3、3.9、4.7、5.6、6.8、8.2</td><td style="text-align: center;"><code>KΩ</code></td></tr><tr><td style="text-align: center;"><strong>E12</strong></td><td>10、12、15、18、22、27、33、39、47、56、68、82</td><td style="text-align: center;"><code>KΩ</code></td></tr></tbody></table><h1 id="e24-系列标准值">E24 系列标准值</h1><p><strong>E24 系列</strong>拥有<strong>1.0</strong>、<strong>1.1</strong>、<strong>1.2</strong>、<strong>1.3</strong>、<strong>1.5</strong>、<strong>1.6</strong>、<strong>1.8</strong>、<strong>2.0</strong>、<strong>2.2</strong>、<strong>2.4</strong>、<strong>2.7</strong>、<strong>3.0</strong>、<strong>3.3</strong>、<strong>3.6</strong>、<strong>3.9</strong>、<strong>4.3</strong>、<strong>4.7</strong>、<strong>5.1</strong>、<strong>5.6</strong>、<strong>6.2</strong>、<strong>6.8</strong>、<strong>7.5</strong>、<strong>8.2</strong>、<strong>9.1</strong>二十四个标准参数值，例如该系列对应的电阻值如下面表格所示：</p><table><colgroup><col style="width: 5%"><col style="width: 91%"><col style="width: 3%"></colgroup><thead><tr><th style="text-align: center;">E 系列</th><th>E24 系列标准电阻值</th><th style="text-align: center;">单位</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>E24</strong></td><td>1.0、1.1、1.2、1.3、1.5、1.6、1.8、2.0、2.2、2.4、2.7、3.0、3.3、3.6、3.9、4.3、4.7、5.1、5.6,6.2、6.8、7.5、8.2、9.1</td><td style="text-align: center;"><code>Ω</code></td></tr><tr><td style="text-align: center;"><strong>E24</strong></td><td>10、11、12、13、15、16、18、20、22、24、27、30、33、36、39、43、47、51、56、62、68、75、82、91</td><td style="text-align: center;"><code>Ω</code></td></tr><tr><td style="text-align: center;"><strong>E24</strong></td><td>100、110、120、130、150、160、180、200、220、240、270、300、330、360、390、430、470、510、560、62、680、750、820、910</td><td style="text-align: center;"><code>Ω</code></td></tr><tr><td style="text-align: center;"><strong>E24</strong></td><td>1.0、1.1、1.2、1.3、1.5、1.6、1.8、2.0、2.2、2.4、2.7、3.0、3.3、3.6、3.9、4.3、4.7、5.1、5.6,6.2、6.8、7.5、8.2、9.1</td><td style="text-align: center;"><code>KΩ</code></td></tr></tbody></table><h1 id="e48-系列标准值">E48 系列标准值</h1><p><strong>E48 系列</strong>拥有下面表格所示的四十八个标准参数值：</p><table style="width:100%;"><colgroup><col style="width: 16%"><col style="width: 16%"><col style="width: 16%"><col style="width: 16%"><col style="width: 16%"><col style="width: 16%"></colgroup><thead><tr><th style="text-align: center;">E48 系列标准值</th><th style="text-align: center;">E48 系列标准值</th><th style="text-align: center;">E48 系列标准值</th><th style="text-align: center;">E48 系列标准值</th><th style="text-align: center;">E48 系列标准值</th><th style="text-align: center;">E48 系列标准值</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>1.00</strong></td><td style="text-align: center;"><strong>1.05</strong></td><td style="text-align: center;"><strong>1.10</strong></td><td style="text-align: center;"><strong>1.15</strong></td><td style="text-align: center;"><strong>1.21</strong></td><td style="text-align: center;"><strong>1.27</strong></td></tr><tr><td style="text-align: center;"><strong>1.33</strong></td><td style="text-align: center;"><strong>1.40</strong></td><td style="text-align: center;"><strong>1.47</strong></td><td style="text-align: center;"><strong>1.54</strong></td><td style="text-align: center;"><strong>1.62</strong></td><td style="text-align: center;"><strong>1.69</strong></td></tr><tr><td style="text-align: center;"><strong>1.78</strong></td><td style="text-align: center;"><strong>1.87</strong></td><td style="text-align: center;"><strong>1.96</strong></td><td style="text-align: center;"><strong>2.05</strong></td><td style="text-align: center;"><strong>2.15</strong></td><td style="text-align: center;"><strong>2.26</strong></td></tr><tr><td style="text-align: center;"><strong>2.37</strong></td><td style="text-align: center;"><strong>2.49</strong></td><td style="text-align: center;"><strong>2.61</strong></td><td style="text-align: center;"><strong>2.74</strong></td><td style="text-align: center;"><strong>2.87</strong></td><td style="text-align: center;"><strong>3.01</strong></td></tr><tr><td style="text-align: center;"><strong>3.16</strong></td><td style="text-align: center;"><strong>3.32</strong></td><td style="text-align: center;"><strong>3.48</strong></td><td style="text-align: center;"><strong>3.65</strong></td><td style="text-align: center;"><strong>3.83</strong></td><td style="text-align: center;"><strong>4.02</strong></td></tr><tr><td style="text-align: center;"><strong>4.22</strong></td><td style="text-align: center;"><strong>4.42</strong></td><td style="text-align: center;"><strong>4.64</strong></td><td style="text-align: center;"><strong>4.87</strong></td><td style="text-align: center;"><strong>5.11</strong></td><td style="text-align: center;"><strong>5.36</strong></td></tr><tr><td style="text-align: center;"><strong>5.62</strong></td><td style="text-align: center;"><strong>5.90</strong></td><td style="text-align: center;"><strong>6.19</strong></td><td style="text-align: center;"><strong>6.49</strong></td><td style="text-align: center;"><strong>6.81</strong></td><td style="text-align: center;"><strong>7.15</strong></td></tr><tr><td style="text-align: center;"><strong>7.50</strong></td><td style="text-align: center;"><strong>7.87</strong></td><td style="text-align: center;"><strong>8.25</strong></td><td style="text-align: center;"><strong>8.66</strong></td><td style="text-align: center;"><strong>9.09</strong></td><td style="text-align: center;"><strong>9.53</strong></td></tr></tbody></table><p>例如，<strong>E48 系列</strong>对应的电阻值如下面的表格所示：</p><table><colgroup><col style="width: 2%"><col style="width: 96%"><col style="width: 1%"></colgroup><thead><tr><th style="text-align: center;">E 系列</th><th>对应的电阻值示例</th><th style="text-align: center;">单位</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>E48</strong></td><td>1.00、1.05、1.10、1.15、1.21、1.27、1.33,1.40、1.47、1.54、1.62,1.69、1.78、1.87、1.96、2.05、2.15、2.26、2.37、2.49、2.61、2.74、2.87、3.01、3.16、3.32、3.48、3.65、3.83、4.02、4.22、4.42、4.64、4.87、5.11、5.36、5.62、5.90、6.19、6.49、6.81、7.15、7.50、7.87、8.25、8.66、9.09、9.53</td><td style="text-align: center;"><code>Ω</code></td></tr><tr><td style="text-align: center;"><strong>E48</strong></td><td>10.0、10.5、11.0、11.5、12.1、12.7、13.3,14.0、14.7、15.4、16.2,16.9、17.8、18.7、19.6、20.5、21.5、22.6、23.7、24.9、26.1、27.4、28.7、30.1、31.6、33.2、34.8、36.5、38.3、40.2、42.2、44.2、46.4、48.7、51.1、53.6、56.2、59.0、61.9、64.9、68.1、71.5、75.0、78.7、82.5、86.6、90.9、95.3</td><td style="text-align: center;"><code>Ω</code></td></tr><tr><td style="text-align: center;"><strong>E48</strong></td><td>100、105、110、115、121、127、133,140、147、154、162,169、178、187、196、205、215、226、237、249、261、274、287、301、316、332、348、365、383、402、422、442、464、487、511、536、562、590、619、649、681、715、750、787、825、866、909、953</td><td style="text-align: center;"><code>Ω</code></td></tr><tr><td style="text-align: center;"><strong>E48</strong></td><td>1.00、1.05、1.10、1.15、1.21、1.27、1.33,1.40、1.47、1.54、1.62,1.69、1.78、1.87、1.96、2.05、2.15、2.26、2.37、2.49、2.61、2.74、2.87、3.01、3.16、3.32、3.48、3.65、3.83、4.02、4.22、4.42、4.64、4.87、5.11、5.36、5.62、5.90、6.19、6.49、6.81、7.15、7.50、7.87、8.25、8.66、9.09、9.53</td><td style="text-align: center;"><code>KΩ</code></td></tr></tbody></table><h1 id="e96-系列标准值">E96 系列标准值</h1><p><strong>E96 系列</strong>拥有下面表格所示的九十六个标准参数值：</p><table style="width:100%;"><colgroup><col style="width: 16%"><col style="width: 16%"><col style="width: 16%"><col style="width: 16%"><col style="width: 16%"><col style="width: 16%"></colgroup><thead><tr><th style="text-align: center;">E96 系列标准值</th><th style="text-align: center;">E96 系列标准值</th><th style="text-align: center;">E96 系列标准值</th><th style="text-align: center;">E96 系列标准值</th><th style="text-align: center;">E96 系列标准值</th><th style="text-align: center;">E96 系列标准值</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>1.00</strong></td><td style="text-align: center;"><strong>1.02</strong></td><td style="text-align: center;"><strong>1.05</strong></td><td style="text-align: center;"><strong>1.07</strong></td><td style="text-align: center;"><strong>1.10</strong></td><td style="text-align: center;"><strong>1.13</strong></td></tr><tr><td style="text-align: center;"><strong>1.15</strong></td><td style="text-align: center;"><strong>1.18</strong></td><td style="text-align: center;"><strong>1.21</strong></td><td style="text-align: center;"><strong>1.24</strong></td><td style="text-align: center;"><strong>1.27</strong></td><td style="text-align: center;"><strong>1.30</strong></td></tr><tr><td style="text-align: center;"><strong>1.33</strong></td><td style="text-align: center;"><strong>1.37</strong></td><td style="text-align: center;"><strong>1.40</strong></td><td style="text-align: center;"><strong>1.43</strong></td><td style="text-align: center;"><strong>1.47</strong></td><td style="text-align: center;"><strong>1.50</strong></td></tr><tr><td style="text-align: center;"><strong>1.54</strong></td><td style="text-align: center;"><strong>1,58</strong></td><td style="text-align: center;"><strong>1.62</strong></td><td style="text-align: center;"><strong>1.65</strong></td><td style="text-align: center;"><strong>1.69</strong></td><td style="text-align: center;"><strong>1.74</strong></td></tr><tr><td style="text-align: center;"><strong>1.78</strong></td><td style="text-align: center;"><strong>1.82</strong></td><td style="text-align: center;"><strong>1.87</strong></td><td style="text-align: center;"><strong>1.91</strong></td><td style="text-align: center;"><strong>1.96</strong></td><td style="text-align: center;"><strong>2.00</strong></td></tr><tr><td style="text-align: center;"><strong>2.05</strong></td><td style="text-align: center;"><strong>2.10</strong></td><td style="text-align: center;"><strong>2.16</strong></td><td style="text-align: center;"><strong>2.21</strong></td><td style="text-align: center;"><strong>2.26</strong></td><td style="text-align: center;"><strong>2.32</strong></td></tr><tr><td style="text-align: center;"><strong>2.37</strong></td><td style="text-align: center;"><strong>2.43</strong></td><td style="text-align: center;"><strong>2.49</strong></td><td style="text-align: center;"><strong>2.55</strong></td><td style="text-align: center;"><strong>2.61</strong></td><td style="text-align: center;"><strong>2.67</strong></td></tr><tr><td style="text-align: center;"><strong>2.74</strong></td><td style="text-align: center;"><strong>2.80</strong></td><td style="text-align: center;"><strong>2.87</strong></td><td style="text-align: center;"><strong>2.94</strong></td><td style="text-align: center;"><strong>3.01</strong></td><td style="text-align: center;"><strong>3.09</strong></td></tr><tr><td style="text-align: center;"><strong>3.16</strong></td><td style="text-align: center;"><strong>3.24</strong></td><td style="text-align: center;"><strong>3.32</strong></td><td style="text-align: center;"><strong>3.40</strong></td><td style="text-align: center;"><strong>3.48</strong></td><td style="text-align: center;"><strong>3.57</strong></td></tr><tr><td style="text-align: center;"><strong>3.65</strong></td><td style="text-align: center;"><strong>3.74</strong></td><td style="text-align: center;"><strong>3.83</strong></td><td style="text-align: center;"><strong>3.92</strong></td><td style="text-align: center;"><strong>4.02</strong></td><td style="text-align: center;"><strong>4.12</strong></td></tr><tr><td style="text-align: center;"><strong>4.22</strong></td><td style="text-align: center;"><strong>4.32</strong></td><td style="text-align: center;"><strong>4.42</strong></td><td style="text-align: center;"><strong>4.53</strong></td><td style="text-align: center;"><strong>4.64</strong></td><td style="text-align: center;"><strong>4.75</strong></td></tr><tr><td style="text-align: center;"><strong>4.87</strong></td><td style="text-align: center;"><strong>4.99</strong></td><td style="text-align: center;"><strong>5.11</strong></td><td style="text-align: center;"><strong>5.23</strong></td><td style="text-align: center;"><strong>5.36</strong></td><td style="text-align: center;"><strong>5.49</strong></td></tr><tr><td style="text-align: center;"><strong>5.62</strong></td><td style="text-align: center;"><strong>5.76</strong></td><td style="text-align: center;"><strong>5.90</strong></td><td style="text-align: center;"><strong>6.04</strong></td><td style="text-align: center;"><strong>6.19</strong></td><td style="text-align: center;"><strong>6.34</strong></td></tr><tr><td style="text-align: center;"><strong>6.49</strong></td><td style="text-align: center;"><strong>6.65</strong></td><td style="text-align: center;"><strong>6,81</strong></td><td style="text-align: center;"><strong>6.98</strong></td><td style="text-align: center;"><strong>7.15</strong></td><td style="text-align: center;"><strong>7.32</strong></td></tr><tr><td style="text-align: center;"><strong>7.50</strong></td><td style="text-align: center;"><strong>7.68</strong></td><td style="text-align: center;"><strong>7.87</strong></td><td style="text-align: center;"><strong>8.06</strong></td><td style="text-align: center;"><strong>8.25</strong></td><td style="text-align: center;"><strong>8.45</strong></td></tr><tr><td style="text-align: center;"><strong>8.66</strong></td><td style="text-align: center;"><strong>8.87</strong></td><td style="text-align: center;"><strong>9.09</strong></td><td style="text-align: center;"><strong>9.31</strong></td><td style="text-align: center;"><strong>9.53</strong></td><td style="text-align: center;"><strong>9.76</strong></td></tr></tbody></table><p>例如，<strong>E96 系列</strong>对应的电阻值如下面的表格所示：</p><table><colgroup><col style="width: 1%"><col style="width: 98%"><col style="width: 0%"></colgroup><thead><tr><th style="text-align: center;">E 系列</th><th>对应的电阻值示例</th><th style="text-align: center;">单位</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>E96</strong></td><td>1.00、1.02、1.05、1.07、1.10,1.13、1.15、1.18,1.21、1.24、1.27、1.30、1.33、1.37.1.40、1.43、1.47、1.50、1.54、1.58、1.62、1.65、1.69、1.74、1.78、1.82、1.87、1.91、1.96、2.00、2.05、2.10、2.16、2.21、2.26、2.32、2.37、2.43、2.49、2.55、2.61、2.67、2.74、2.80、2.87、2.94、3.01、3.09、3.16、3.24、3.32、3.40、3.48、3.57、3.65、3.74、3.83、3.92、4.02、4.12、4.22、4.32、4.42、4.53、4.64、4.75、4.87、4.99、5.11、5.23,5.36、5.49、5.62、5.76、5.90、6.04、6.19、6.34、6.49、6.65、6,81、6.98、7.15、7.32、7.50、7.68、7.87、8.06、8.25、8.45、8.66、8.87、9.09、9.31、9.53、9.76</td><td style="text-align: center;"><code>Ω</code></td></tr><tr><td style="text-align: center;"><strong>E96</strong></td><td>10.0、10.2、10.5、10.7、11.0,11.3、11.5、11.8,12.1、12.4、12.7、13.0、13.3、13.7.14.0、14.3、14.7、15.0、15.4、15.8、16.2、16.5、1.69、17.4、17.8、18.2、18.7、19.1、19.6、20.0、20.5、21.0、21.6、22.1、22.6、23.2、23.7、24.3、24.9、25.5、26.1、26.7、27.4、28.0、28.7、29.4、30.1、30.9、31.6、32.4、33.2、34.0、34.8、35.7、36.5、37.4、38.3、39.2、40.2、41.2、42.2、43.2、44.2、45.3、46.4、47.5、48.7、49.9、51.1、52.3、53.6、54.9、56.2、57.6、59.0、60.4、61.9、63.4、64.9、66.5、68.1、69.8、71.5、73.2、75.0、76.8、78.7、80.6、82.5、84.5、86.6、88.7、90.9、93.1、95.3、97.6</td><td style="text-align: center;"><code>Ω</code></td></tr><tr><td style="text-align: center;"><strong>E96</strong></td><td>100、102、105、107、110,113、115、118,121、124、127、130、133、137.140、143、147、150、154、158、162、165、169、174、178、182、187、191、196、200、205、210、216、221、226、232、237、243、249、255、261、267、274、280、287、294、301、309、316、324、332、340、348、357、365、374、383、392、402、412、422、432、442、453、464、475、487、499、511、523、536、549、562、576、590、604、619、634、649、665、681、698、715、732、750、768、787、806、825、845、866、887、909、931、953、976</td><td style="text-align: center;"><code>Ω</code></td></tr><tr><td style="text-align: center;"><strong>E96</strong></td><td>1.00、1.02、1.05、1.07、1.10,1.13、1.15、1.18,1.21、1.24、1.27、1.30、1.33、1.37.1.40、1.43、1.47、1.50、1.54、1.58、1.62、1.65、1.69、1.74、1.78、1.82、1.87、1.91、1.96、2.00、2.05、2.10、2.16、2.21、2.26、2.32、2.37、2.43、2.49、2.55、2.61、2.67、2.74、2.80、2.87、2.94、3.01、3.09、3.16、3.24、3.32、3.40、3.48、3.57、3.65、3.74、3.83、3.92、4.02、4.12、4.22、4.32、4.42、4.53、4.64、4.75、4.87、4.99、5.11、5.23、5.36、5.49、5.62、5.76、5.90、6.04、6.19、6.34、6.49、6.65、6,81、6.98、7.15、7.32、7.50、7.68、7.87、8.06、8.25、8.45、8.66、8.87、9.09、9.31、9.53、9.76</td><td style="text-align: center;"><code>KΩ</code></td></tr></tbody></table><h1 id="e192-系列标准值">E192 系列标准值</h1><p><strong>E192系列</strong>由下面表格所示的一百九十二个标准参数值所组成：</p><table><colgroup><col style="width: 12%"><col style="width: 12%"><col style="width: 12%"><col style="width: 12%"><col style="width: 12%"><col style="width: 12%"><col style="width: 12%"><col style="width: 12%"></colgroup><thead><tr><th style="text-align: center;">E192 系列标准值</th><th style="text-align: center;">E192 系列标准值</th><th style="text-align: center;">E192 系列标准值</th><th style="text-align: center;">E192 系列标准值</th><th style="text-align: center;">E192 系列标准值</th><th style="text-align: center;">E192 系列标准值</th><th style="text-align: center;">E192 系列标准值</th><th style="text-align: center;">E192 系列标准值</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>1.00</strong></td><td style="text-align: center;"><strong>1.01</strong></td><td style="text-align: center;"><strong>1.02</strong></td><td style="text-align: center;"><strong>1.04</strong></td><td style="text-align: center;"><strong>1.05</strong></td><td style="text-align: center;"><strong>1.06</strong></td><td style="text-align: center;"><strong>1.07</strong></td><td style="text-align: center;"><strong>1.09</strong></td></tr><tr><td style="text-align: center;"><strong>1.10</strong></td><td style="text-align: center;"><strong>1.11</strong></td><td style="text-align: center;"><strong>1.13</strong></td><td style="text-align: center;"><strong>1.14</strong></td><td style="text-align: center;"><strong>1.15</strong></td><td style="text-align: center;"><strong>1.17</strong></td><td style="text-align: center;"><strong>1.18</strong></td><td style="text-align: center;"><strong>1.20</strong></td></tr><tr><td style="text-align: center;"><strong>1.21</strong></td><td style="text-align: center;"><strong>1.23</strong></td><td style="text-align: center;"><strong>1.24</strong></td><td style="text-align: center;"><strong>1.26</strong></td><td style="text-align: center;"><strong>1.27</strong></td><td style="text-align: center;"><strong>1.29</strong></td><td style="text-align: center;"><strong>1.30</strong></td><td style="text-align: center;"><strong>1.32</strong></td></tr><tr><td style="text-align: center;"><strong>1.33</strong></td><td style="text-align: center;"><strong>1.35</strong></td><td style="text-align: center;"><strong>1.37</strong></td><td style="text-align: center;"><strong>1.38</strong></td><td style="text-align: center;"><strong>1.40</strong></td><td style="text-align: center;"><strong>1.42</strong></td><td style="text-align: center;"><strong>1.43</strong></td><td style="text-align: center;"><strong>1.45</strong></td></tr><tr><td style="text-align: center;"><strong>1.47</strong></td><td style="text-align: center;"><strong>1.49</strong></td><td style="text-align: center;"><strong>1.50</strong></td><td style="text-align: center;"><strong>1.52</strong></td><td style="text-align: center;"><strong>1.54</strong></td><td style="text-align: center;"><strong>1.56</strong></td><td style="text-align: center;"><strong>1.58</strong></td><td style="text-align: center;"><strong>1.60</strong></td></tr><tr><td style="text-align: center;"><strong>1.62</strong></td><td style="text-align: center;"><strong>1.64</strong></td><td style="text-align: center;"><strong>1.65</strong></td><td style="text-align: center;"><strong>1.67</strong></td><td style="text-align: center;"><strong>1.69</strong></td><td style="text-align: center;"><strong>1.72</strong></td><td style="text-align: center;"><strong>1.74</strong></td><td style="text-align: center;"><strong>1.76</strong></td></tr><tr><td style="text-align: center;"><strong>1.78</strong></td><td style="text-align: center;"><strong>1.80</strong></td><td style="text-align: center;"><strong>1.82</strong></td><td style="text-align: center;"><strong>1.84</strong></td><td style="text-align: center;"><strong>1.87</strong></td><td style="text-align: center;"><strong>1.89</strong></td><td style="text-align: center;"><strong>1.91</strong></td><td style="text-align: center;"><strong>1.93</strong></td></tr><tr><td style="text-align: center;"><strong>1.96</strong></td><td style="text-align: center;"><strong>1.98</strong></td><td style="text-align: center;"><strong>2.00</strong></td><td style="text-align: center;"><strong>2.03</strong></td><td style="text-align: center;"><strong>2.05</strong></td><td style="text-align: center;"><strong>2.08</strong></td><td style="text-align: center;"><strong>2.10</strong></td><td style="text-align: center;"><strong>2.13</strong></td></tr><tr><td style="text-align: center;"><strong>2.15</strong></td><td style="text-align: center;"><strong>2.18</strong></td><td style="text-align: center;"><strong>2.21</strong></td><td style="text-align: center;"><strong>2.23</strong></td><td style="text-align: center;"><strong>2.26</strong></td><td style="text-align: center;"><strong>2.29</strong></td><td style="text-align: center;"><strong>2.32</strong></td><td style="text-align: center;"><strong>2.34</strong></td></tr><tr><td style="text-align: center;"><strong>2.37</strong></td><td style="text-align: center;"><strong>2.40</strong></td><td style="text-align: center;"><strong>2.43</strong></td><td style="text-align: center;"><strong>2.46</strong></td><td style="text-align: center;"><strong>2.49</strong></td><td style="text-align: center;"><strong>2.52</strong></td><td style="text-align: center;"><strong>2.55</strong></td><td style="text-align: center;"><strong>2.58</strong></td></tr><tr><td style="text-align: center;"><strong>2.61</strong></td><td style="text-align: center;"><strong>2.64</strong></td><td style="text-align: center;"><strong>2.67</strong></td><td style="text-align: center;"><strong>2.71</strong></td><td style="text-align: center;"><strong>2.74</strong></td><td style="text-align: center;"><strong>2.77</strong></td><td style="text-align: center;"><strong>2.80</strong></td><td style="text-align: center;"><strong>2.84</strong></td></tr><tr><td style="text-align: center;"><strong>2.87</strong></td><td style="text-align: center;"><strong>2.91</strong></td><td style="text-align: center;"><strong>2.94</strong></td><td style="text-align: center;"><strong>2.98</strong></td><td style="text-align: center;"><strong>3.01</strong></td><td style="text-align: center;"><strong>3.05</strong></td><td style="text-align: center;"><strong>3.09</strong></td><td style="text-align: center;"><strong>3.12</strong></td></tr><tr><td style="text-align: center;"><strong>3.16</strong></td><td style="text-align: center;"><strong>3.20</strong></td><td style="text-align: center;"><strong>3.24</strong></td><td style="text-align: center;"><strong>3.28</strong></td><td style="text-align: center;"><strong>3.32</strong></td><td style="text-align: center;"><strong>3.36</strong></td><td style="text-align: center;"><strong>3.40</strong></td><td style="text-align: center;"><strong>3.44</strong></td></tr><tr><td style="text-align: center;"><strong>3.48</strong></td><td style="text-align: center;"><strong>3.52</strong></td><td style="text-align: center;"><strong>3.57</strong></td><td style="text-align: center;"><strong>3.61</strong></td><td style="text-align: center;"><strong>3.65</strong></td><td style="text-align: center;"><strong>3.70</strong></td><td style="text-align: center;"><strong>3.74</strong></td><td style="text-align: center;"><strong>3.79</strong></td></tr><tr><td style="text-align: center;"><strong>3.83</strong></td><td style="text-align: center;"><strong>3.88</strong></td><td style="text-align: center;"><strong>3.92</strong></td><td style="text-align: center;"><strong>3.97</strong></td><td style="text-align: center;"><strong>4.02</strong></td><td style="text-align: center;"><strong>4.07</strong></td><td style="text-align: center;"><strong>4.12</strong></td><td style="text-align: center;"><strong>4.17</strong></td></tr><tr><td style="text-align: center;"><strong>4.22</strong></td><td style="text-align: center;"><strong>4.27</strong></td><td style="text-align: center;"><strong>4.32</strong></td><td style="text-align: center;"><strong>4.37</strong></td><td style="text-align: center;"><strong>4.42</strong></td><td style="text-align: center;"><strong>4.48</strong></td><td style="text-align: center;"><strong>4.53</strong></td><td style="text-align: center;"><strong>4.59</strong></td></tr><tr><td style="text-align: center;"><strong>4.64</strong></td><td style="text-align: center;"><strong>4.70</strong></td><td style="text-align: center;"><strong>4.75</strong></td><td style="text-align: center;"><strong>4.81</strong></td><td style="text-align: center;"><strong>4.87</strong></td><td style="text-align: center;"><strong>4.93</strong></td><td style="text-align: center;"><strong>4.99</strong></td><td style="text-align: center;"><strong>5.05</strong></td></tr><tr><td style="text-align: center;"><strong>5.11</strong></td><td style="text-align: center;"><strong>5.17</strong></td><td style="text-align: center;"><strong>5.23</strong></td><td style="text-align: center;"><strong>5.30</strong></td><td style="text-align: center;"><strong>5.36</strong></td><td style="text-align: center;"><strong>5.42</strong></td><td style="text-align: center;"><strong>5.49</strong></td><td style="text-align: center;"><strong>5.56</strong></td></tr><tr><td style="text-align: center;"><strong>5.62</strong></td><td style="text-align: center;"><strong>5.69</strong></td><td style="text-align: center;"><strong>5.76</strong></td><td style="text-align: center;"><strong>5.83</strong></td><td style="text-align: center;"><strong>5.90</strong></td><td style="text-align: center;"><strong>5.97</strong></td><td style="text-align: center;"><strong>6.04</strong></td><td style="text-align: center;"><strong>6.12</strong></td></tr><tr><td style="text-align: center;"><strong>6.19</strong></td><td style="text-align: center;"><strong>6.26</strong></td><td style="text-align: center;"><strong>6.34</strong></td><td style="text-align: center;"><strong>6.42</strong></td><td style="text-align: center;"><strong>6.49</strong></td><td style="text-align: center;"><strong>6.57</strong></td><td style="text-align: center;"><strong>6.65</strong></td><td style="text-align: center;"><strong>6.73</strong></td></tr><tr><td style="text-align: center;"><strong>6.81</strong></td><td style="text-align: center;"><strong>6.90</strong></td><td style="text-align: center;"><strong>6.98</strong></td><td style="text-align: center;"><strong>7.06</strong></td><td style="text-align: center;"><strong>7.15</strong></td><td style="text-align: center;"><strong>7.23</strong></td><td style="text-align: center;"><strong>7.32</strong></td><td style="text-align: center;"><strong>7.41</strong></td></tr><tr><td style="text-align: center;"><strong>7.50</strong></td><td style="text-align: center;"><strong>7.59</strong></td><td style="text-align: center;"><strong>7.68</strong></td><td style="text-align: center;"><strong>7.77</strong></td><td style="text-align: center;"><strong>7.87</strong></td><td style="text-align: center;"><strong>7.96</strong></td><td style="text-align: center;"><strong>8.06</strong></td><td style="text-align: center;"><strong>8.16</strong></td></tr><tr><td style="text-align: center;"><strong>8.25</strong></td><td style="text-align: center;"><strong>8.35</strong></td><td style="text-align: center;"><strong>8.45</strong></td><td style="text-align: center;"><strong>8.56</strong></td><td style="text-align: center;"><strong>8.66</strong></td><td style="text-align: center;"><strong>8.76</strong></td><td style="text-align: center;"><strong>8.87</strong></td><td style="text-align: center;"><strong>8.98</strong></td></tr><tr><td style="text-align: center;"><strong>9.09</strong></td><td style="text-align: center;"><strong>9.20</strong></td><td style="text-align: center;"><strong>9.31</strong></td><td style="text-align: center;"><strong>9.42</strong></td><td style="text-align: center;"><strong>9.53</strong></td><td style="text-align: center;"><strong>9.65</strong></td><td style="text-align: center;"><strong>9.76</strong></td><td style="text-align: center;"><strong>9.88</strong></td></tr></tbody></table><style>table th {  white-space:nowrap;}</style>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;a href=&quot;https://ecia.memberclicks.net/&quot;&gt;&lt;strong&gt;电子工业联盟&lt;/strong&gt;&lt;/a&gt;（&lt;strong&gt;ECIA&lt;/strong&gt;，Electronics
Industry Alliance）是一个由美国电子产品生产制造企业组成的一个组织，由其
&lt;a href=&quot;https://ecia.memberclicks.net/eia-standards-committee&quot;&gt;EIA
标准化委员会&lt;/a&gt; 提出的 &lt;strong&gt;E
系列标准参数值（E-series）&lt;/strong&gt;是现代全球电子工业当中，&lt;code&gt;电阻器&lt;/code&gt;、&lt;code&gt;电容器&lt;/code&gt;、&lt;code&gt;电感器&lt;/code&gt;、&lt;code&gt;齐纳二极管&lt;/code&gt;等分立式电子元器件的&lt;strong&gt;标准参数值系统&lt;/strong&gt;，其主要包括
&lt;strong&gt;E3&lt;/strong&gt;、&lt;strong&gt;E6&lt;/strong&gt;、&lt;strong&gt;E12&lt;/strong&gt;、&lt;strong&gt;E24&lt;/strong&gt;、&lt;strong&gt;E48&lt;/strong&gt;、&lt;strong&gt;E96&lt;/strong&gt;
和 &lt;strong&gt;E192&lt;/strong&gt;
七个系列，每个系列都对应着不同的&lt;strong&gt;精度&lt;/strong&gt;与&lt;strong&gt;误差&lt;/strong&gt;。基于产品通用性和兼容性的考量，目前全球各大半导体企业都基于该标准生产制造分立式元件。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/Electronics/E-Series/logo.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;系统电源树乃至于开关电源的设计，是广大电子工程师在日常工作当中，绕不开的一个重要环节。而在开关电源的选型设计过程当中，经常需要使用精密电阻器作为
DC-DC
电源芯片的外围配置电阻。但是临时抱佛脚在网络上检索的标准取值往往不够严谨与权威，难以保证参数值选取的准确性。所以我才基于
EIA
标准化委员会的相关官方资料，整理并且撰写了本文，便于在日常工作当中快速的确定各种精密分立式元器件的电气参数。&lt;/p&gt;</summary>
    
    
    
    <category term="硬件电子技术" scheme="http://www.uinio.com/categories/%E7%A1%AC%E4%BB%B6%E7%94%B5%E5%AD%90%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="元器件" scheme="http://www.uinio.com/tags/%E5%85%83%E5%99%A8%E4%BB%B6/"/>
    
  </entry>
  
  <entry>
    <title>瞬态电压抑制二极管 TVS 选型简述</title>
    <link href="http://www.uinio.com/Electronics/TVS/"/>
    <id>http://www.uinio.com/Electronics/TVS/</id>
    <published>2024-09-05T16:00:00.000Z</published>
    <updated>2025-07-20T06:38:47.123Z</updated>
    
    <content type="html"><![CDATA[<p><strong>瞬态电压抑制二极管</strong>（TVS，Transient VoltageSuppressors）二极管，是一种在传统<strong>齐纳二极管</strong>工艺基础之上制造的一种电路保护元器件，也被称为<code>瞬变抑制二极管</code>、<code>瞬态电压抑制器</code>、<code>雪崩击穿二极管</code>等。其具有单向与双向之分，当两端经受瞬间高能量冲击时，就会以皮秒级别的速度将两端的阻抗值由<strong>高阻抗</strong>变化为<strong>低阻抗</strong>，从而将瞬间大电流接地，并把两端的电压箝制在一个预定的数值上，进而确保后级电路不会受到瞬态高压尖峰脉冲的影响。</p><p><img src="/Electronics/TVS/logo.png"></p><p>总而言之，TVS二极管凭借<code>皮秒级导通速率</code>、<code>大瞬态功率</code>、<code>低漏电流与电容</code>、<code>容易控制的箝位电压</code>、<code>击穿电压偏差小</code>、<code>可靠性高</code>、<code>体积小</code>等优势，被广泛应用于敏感电路的过压保护当中（特别是 ESD静电防护）。目前国际市场上比较主流的 TVS 生产制造企业有 <a href="https://www.vishay.com/zh/diodes/tvs-protection/">美国威世Vishay</a>、<a href="https://m.littelfuse.com/products/emc-components.aspx?lang=ZH">美国力特Littelfuse</a>、<a href="https://www.onsemi.cn/products/discrete-power-modules">日本安森美Onsemi</a>、<a href="https://www.nexperia.cn/products/diodes/zener-diodes">荷兰安世Nexperia</a> 等厂家，而国内最近几年也涌现出了 <a href="https://www.lrc.cn/product/protector.html">乐山无线电 LRC</a>、<a href="https://www.techpublic.com/home/product/index.html">台州电子TechPublic</a> 以及国巨旗下的 <a href="https://brightking.yageo.com/Products/list_12.aspx?lcid=47">君耀电子BrightKing</a> 等比较有实力的供应商。</p><span id="more"></span><h2 id="原理图符号">原理图符号</h2><p><strong>瞬态电压抑制器</strong>（TVS，Transient VoltageSuppressors）狭义上是指<strong>雪崩击穿二极管</strong>，这是一种二极管形式的高效保护器件，通常采用较大尺寸的<strong>SMA</strong> 或者 <strong>SMB</strong>封装，结电容比较大，主要运用在防浪涌防护以及电源 ESD 等领域。而广义上的TVS 是指包含有 TVS 二极管的 ESD专用防护器件，其原理图符号如下图所示：</p><p><img src="/Electronics/TVS/1.png"></p><h2 id="单向-双向">单向 &amp; 双向</h2><p>TVS二极管可以具体划分为<strong>单向</strong>和<strong>双向</strong>两种类型，双向TVS 主要应用于交流电压电路，而单向 TVS一般运用于直流电路（使用的时候需要<strong>反接</strong>在电路当中，这意味着使用的时候需要注意极性。考虑到物料规格的统一，以及采购成本的差异较为细微，双向TVS 在实际生产环境下使用更为普遍）。</p><p><img src="/Electronics/TVS/2.png"></p><p>当单向 TVS 二极管被应用于直流电路，在电路正常工作的时候，TVS处于截止状态（高阻态），不影响正常工作。但是当电路中出现<strong>瞬态电压突变</strong>（达到TVS 的<strong>雪崩击穿电压</strong>），TVS二极管就会迅速由高阻态转变为<strong>低阻态</strong>，将由于异常过压所导致的<strong>瞬态电流</strong>接入到地平面，同时将这个瞬态电压箝位在一个比较低的水平，进而保护后级电路免遭瞬态电压突变的损坏（瞬态电压突变消失以后，TVS二极管又会恢复为高阻态）。</p><h2 id="伏安特性参数">伏安特性参数</h2><p>涉及选型的 TVS 二极管伏安特性参数，主要涉及到 <span class="math inline">\(V_{RWM}\)</span>、<span class="math inline">\(I_R\)</span>、<span class="math inline">\(V_{BR}\)</span>、<span class="math inline">\(I_{PP}\)</span>、<span class="math inline">\(V_C\)</span>、<span class="math inline">\(C_j\)</span>六个，阅读时请结合如下的伏安特性曲线图：</p><p><img src="/Electronics/TVS/3.png"></p><ol type="1"><li><strong>反向截止电压</strong> <span class="math inline">\(V_{RWM}\)</span>：不会造成 TVS二极管损坏的最高峰值电压（如果是交流电压则使用真有效值表示），低于该参数时TVS 不会导通，设计电路的额定工作电压（<code>5V</code> 或者<code>3.3V</code>）应当低于这个参数。</li><li><strong>反向漏电流</strong> <span class="math inline">\(I_R\)</span>：当工作在低于反向截止电压 <span class="math inline">\(V_{RWM}\)</span> 的时候，TVS所承受的最大反向电流。也就是说如果向 TVS 两端施加电压 <span class="math inline">\(V_{RWM}\)</span>，此时通过的电流就是 TVS 的漏电流<span class="math inline">\(I_R\)</span>。通常情况下，这个参数小于<code>0.1uA</code> 微安。</li><li><strong>击穿电压</strong> <span class="math inline">\(V_{BR}\)</span>：即 ESD防护生效的电压，只要超过该参数，TVS二极管就会击穿导通。导通时间一般不会超过 <code>400</code>毫秒，避免较大电流损坏元器件。</li><li><strong>脉冲峰值电流</strong> <span class="math inline">\(I_{PP}\)</span>：峰值反向脉冲电流是指 TVS 按照 <a href="https://webstore.iec.ch/en/publication/4223">IEC61000-4-5:2014</a>或者 <a href="https://openstd.samr.gov.cn/bzgk/gb/newGbInfo?hcno=534499018FB30E7FC5E646F89937B3A8">GB/T17626.5-2019</a> 标准，使其工作在规定的 <code>8/20</code> 微秒或<code>10/1000</code> 微秒的脉冲波形下，此时 TVS所允许通过的最大峰值电流。也就是达到<strong>箝位电压</strong> <span class="math inline">\(V_C\)</span> 的时候，通过 TVS二极管的电流，超过该参数会导致 TVS 的损毁。</li><li><strong>箝位电压</strong> <span class="math inline">\(V_C\)</span>：即通过峰值脉冲电流 <span class="math inline">\(I_{PP}\)</span> 的时候，TVS两端产生的峰值电压。<span class="math inline">\(I_{PP}\)</span> 以及<span class="math inline">\(V_C\)</span>这两个参数相互联系，主要用于衡量 TVS抵抗浪涌脉冲电流以及限制电压的能力。<span class="math inline">\(I_{PP}\)</span> 越大耐电流冲击能力越强，<span class="math inline">\(V_C\)</span> 越小说明 TVS 的箝位特性越好。</li><li><strong>脉冲峰值功率</strong> <span class="math inline">\(P_{pp}\)</span>：即 <strong>箝位电压</strong><span class="math inline">\(V_C\)</span> 与<strong>峰值脉冲电流</strong><span class="math inline">\(I_{PP}\)</span> 的乘积，超过该参数同样会造成TVS 二极管的损毁。</li><li><strong>结电容</strong> <span class="math inline">\(C_j\)</span>：即TVS当中的寄生电容，高速电路设计过程当中，需要重点关注这个参数，结电容过大会影响到信号的完整性。</li></ol><p>本文接下来的内容当中，会对上述一系列的 TVS二极管选型参数，进行更加详细的说明。</p><h2 id="反向截止电压-v_rwm">反向截止电压 <span class="math inline">\(V_{RWM}\)</span></h2><p>正常情况下，TVS 二极管应当处于截止状态（没有导通），因此 TVS的<strong>反向截止电压</strong> <span class="math inline">\(V_{RWM}\)</span>应当大于被保护电路的工作电压，从而确保 TVS不会影响被保护电路的正常工作，反向截止电压 <span class="math inline">\(V_{RWM}\)</span>的取值可以通过下面的参考公式计算得到：</p><p><span class="math display">\[V_{RWM} = (1.1 \sim 1.2) \times V_{CC}\]</span></p><p>如果 <span class="math inline">\(V_{RWM}\)</span>比被保护电路的额定工作电压更大，那么 TVS二极管的漏电流就会越小。反之，<span class="math inline">\(V_{RWM}\)</span> 越小，TVS二极管的<strong>箝位电压</strong> <span class="math inline">\(V_C\)</span>就会越小，对于后级电路的保护效果会相对更好。</p><blockquote><p><strong>注意</strong>：上述公式当中的 <span class="math inline">\(V_{CC}\)</span> 等于被保护电路的工作电压，例如<code>12V</code>、<code>5V</code>、<code>3.3V</code>、<code>1.8V</code>等等。</p></blockquote><h2 id="箝位电压-v_c">箝位电压 <span class="math inline">\(V_C\)</span></h2><p>TVS 二极管的<strong>箝位电压</strong> <span class="math inline">\(V_C\)</span>，应当小于被保护电路最大可承受的瞬态安全电压，否则当TVS 处于箝位状态的时候，<span class="math inline">\(V_C\)</span>会损坏后级的被保护电路:</p><p><span class="math display">\[V_C &lt; V_{max}\]</span></p><blockquote><p><strong>注意</strong>：上述公式当中的 <span class="math inline">\(V_{max}\)</span>等于被保护电路所能承受的最高电压。</p></blockquote><h2 id="额定瞬态功率-p_ppm">额定瞬态功率 <span class="math inline">\(P_{PPM}\)</span></h2><p>TVS 二极管的<strong>额定瞬态功率</strong> <span class="math inline">\(P_{PPM}\)</span>是指发生浪涌的时候，不会被浪涌脉冲电流损毁的功率值。该参数在选型时应当大于电路当中可能出现的最大瞬态浪涌功率，该参数越大，TVS二极管所能够承受的冲击能量就会越大，但是封装尺寸就会更大，相应的价格也就会越高。</p><p>对于<strong>箝位电压</strong> <span class="math inline">\(V_C\)</span> 相同，但是额定瞬态功率 <span class="math inline">\(P_{PPM}\)</span> 不同的 TVS二极管，两者最大的区别主要在于能够通过的<strong>峰值电流</strong> <span class="math inline">\(I_{PP}\)</span> 不同，这样 <span class="math inline">\(P_{PPM}\)</span> 与 <span class="math inline">\(I_{PP}\)</span>就会呈正比，此时被保护电路所需通过的真实峰值电流 <span class="math inline">\(I_{actual}\)</span>可以通过下面的公式进行计算：</p><p><span class="math display">\[I_{actual} = \frac{U_{actual}}{R_{i}}\]</span></p><blockquote><p><strong>注意</strong>：上述公式当中的 <span class="math inline">\(U_{actual}\)</span> 为实际测试电压，而 <span class="math inline">\(R_{i}\)</span> 为测试内阻。</p></blockquote><h2 id="结电容-c_j">结电容 <span class="math inline">\(C_j\)</span></h2><p>根据被保护电路上信号的通信速率，选择具有恰当<strong>结电容</strong><span class="math inline">\(C_j\)</span> 参数的 TVS二极管。下面的表格给出了对于常见通信接口，所推荐的 ESD防静电结电容大小：</p><table><thead><tr><th style="text-align: left;">通信接口</th><th style="text-align: left;">推荐结电容 <span class="math inline">\(C_j\)</span></th><th style="text-align: left;">通信接口</th><th style="text-align: left;">推荐结电容 <span class="math inline">\(C_j\)</span></th></tr></thead><tbody><tr><td style="text-align: left;"><strong>GPIO</strong></td><td style="text-align: left;"><code>&lt; 30pF</code></td><td style="text-align: left;"><strong>USB 2.0</strong></td><td style="text-align: left;"><code>&lt; 4pF</code></td></tr><tr><td style="text-align: left;"><strong>按键</strong></td><td style="text-align: left;"><code>&lt; 30pF</code></td><td style="text-align: left;"><strong>USB 3.0</strong></td><td style="text-align: left;"><code>&lt; 0.5pF</code></td></tr><tr><td style="text-align: left;"><strong>音频接口</strong></td><td style="text-align: left;"><code>&lt; 10pF</code></td><td style="text-align: left;"><strong>USB 3.1</strong></td><td style="text-align: left;"><code>&lt; 0.3pF</code></td></tr><tr><td style="text-align: left;"><strong>以太网接口</strong></td><td style="text-align: left;"><code>&lt; 4pF</code></td><td style="text-align: left;"><strong>HDMI 1.4</strong></td><td style="text-align: left;"><code>&lt; 0.7pF</code></td></tr><tr><td style="text-align: left;"><strong>天线</strong></td><td style="text-align: left;"><code>&lt; 0.2pF</code></td><td style="text-align: left;"><strong>HDMI 2.0</strong></td><td style="text-align: left;"><code>&lt; 0.3pF</code></td></tr></tbody></table><h2 id="符合-esd-等级">符合 ESD 等级</h2><p><a href="https://www.silabs.com/documents/public/application-notes/AN895.pdf"><strong>IEC61000-4-2</strong></a>是<strong>国际电工委员会</strong>颁布的电磁兼容性测试标准，与之相对应的国内测试标准是<a href="https://en.vfe.ac.cn/Storage/article/140129f7eb864405a54f1a1e66ce13e1.pdf#:~:text=GB%2FT%2017626.2-2006,%E7%94%B5%E7%A3%81%E5%85%BC%E5%AE%B9%20%E8%AF%95%E9%AA%8C%E5%92%8C%E6%B5%8B%E9%87%8F%E6%8A%80%E6%9C%AF%20%E9%9D%99%E7%94%B5%E6%94%BE%E7%94%B5%E6%8A%97%E5%B9%B2%E6%89%B0%E5%BA%A6%E8%AF%95%E9%AA%8C%E8%A7%84%E5%AE%9A%E4%BA%86%E7%94%B5%E6%B0%94%E5%92%8C%E7%94%B5%E5%AD%90%E8%AE%BE%E5%A4%87%E9%81%AD%E5%8F%97%E7%9B%B4%E6%8E%A5%E6%9D%A5%E8%87%AA%E6%93%8D%E4%BD%9C%E8%80%85%E5%92%8C%E5%AF%B9%E9%82%BB%E8%BF%91%E7%89%A9%E4%BD%93%E7%9A%84%E9%9D%99%E7%94%B5%E6%94%BE%E7%94%B5%E6%97%B6%E7%9A%84%E6%8A%97%E6%89%B0%E5%BA%A6%E8%A6%81%E6%B1%82%E5%92%8C%E8%AF%95%E9%AA%8C%E6%96%B9%E6%B3%95%2C%E8%BF%98%E8%A7%84%E5%AE%9A%E4%BA%86%E4%B8%8D%E5%90%8C%E7%8E%AF%E5%A2%83%E5%92%8C%E5%AE%89%E8%A3%85%E6%9D%A1%E4%BB%B6%E4%B8%8B%E8%AF%95%E9%AA%8C%E7%AD%89%E7%BA%A7%E7%9A%84%E8%8C%83%E5%9B%B4%E5%92%8C%E8%AF%95%E9%AA%8C%E7%A8%8B%E5%BA%8F%E3%80%82"><strong>GB/T17626.2</strong></a>，生产环境下选择的 TVS 二极管，需要符合<strong>IEC61000-4-2</strong> 的 <strong>Level4</strong>标准（<strong>接触放电</strong>与<strong>空气放电</strong>）：</p><p><img src="/Electronics/TVS/4.png"></p><p>如果 TVS 二极管数据手册当中，<strong>箝位电压</strong> <span class="math inline">\(V_C\)</span> 测试标准选择的是<strong>IEC61000-4-5</strong>，那么测试用的浪涌波形主要有如下两种规格：</p><ul><li><code>8/20 us</code> 微秒：指 <code>8 us</code>达到<strong>峰值脉冲电流</strong> <span class="math inline">\(I_{PP}\)</span> 的<code>100%</code>，<code>20 us</code> 达到<strong>峰值脉冲电流</strong><span class="math inline">\(I_{PP}\)</span> 的 <code>50%</code>。</li><li><code>10/1000 us</code> 微秒：指 <code>10 us</code>达到<strong>峰值脉冲电流</strong> <span class="math inline">\(I_{PP}\)</span> 的<code>100%</code>，<code>1000 us</code>达到<strong>峰值脉冲电流</strong> <span class="math inline">\(I_{PP}\)</span> 的 <code>50%</code>。</li></ul><blockquote><p><strong>注意</strong>：该标准只能确保 TVS二极管本身，在面对测试电压的时候不会被损坏。而后级被保护电路是否受到影响，还是要取决于当前<strong>箝位电压</strong><span class="math inline">\(V_C\)</span> 参数的选择。</p></blockquote><h2 id="tlp-脉冲等级">TLP 脉冲等级</h2><p><strong>传输线触波产生器</strong>（TLP，Transmission Line Pulsingsystem，）用于测量 TVS 二极管在瞬时高电压情况下的伏安特性曲线，TLP所释放的脉冲等级，可以与 <strong>IEC61000-4-2</strong>测试标准相互对应：</p><table><thead><tr><th style="text-align: left;">TLP 释放的脉冲等级</th><th style="text-align: center;">IEC61000-4-2 接触放电测试等级</th></tr></thead><tbody><tr><td style="text-align: left;"><code>2 A</code>，<code>100 ns</code></td><td style="text-align: center;"><code>1 kV</code></td></tr><tr><td style="text-align: left;"><code>4 A</code>，<code>100 ns</code></td><td style="text-align: center;"><code>2 kV</code></td></tr><tr><td style="text-align: left;"><code>8 A</code>，<code>100 ns</code></td><td style="text-align: center;"><code>4 kV</code></td></tr><tr><td style="text-align: left;"><code>12 A</code>，<code>100 ns</code></td><td style="text-align: center;"><code>6 kV</code></td></tr><tr><td style="text-align: left;"><code>16 A</code>，<code>100 ns</code></td><td style="text-align: center;"><code>8 kV</code></td></tr></tbody></table><p>当两个 TVS 二极管都能够通过 <strong>IEC61000-4-2</strong> 的<code>8kV</code> 静电脉冲测试时，TVS 二极管数据手册当中 <strong>TLP曲线</strong>（如下图）所对应的箝位电压越低，就代表这款 TVS的性能越好。我们可以根据被保护电路所能够承受的最大电压，选择 TLP曲线当中箝位电压适合的 TVS：</p><p><img src="/Electronics/TVS/5.png"></p><blockquote><p><strong>注意</strong>：TLP 曲线当中的箝位电压是瞬态<code>100ns</code> 时测试得到的，与 TVS持续工作时不会损坏的箝位电压会有所区别。</p></blockquote><h2 id="tvs-选型总结">TVS 选型总结</h2><p>TVS二极管在使用的时候，通常会反接在被保护电路当中，选型思路可以归纳为如下四个要点：</p><ol type="1"><li><strong>反向截止电压</strong> <span class="math inline">\(V_{RWM}\)</span>要大于被保护电路的正常工作电压（最好高于主控芯片的<strong>典型工作电压</strong>）。</li><li><strong>箝位电压</strong> <span class="math inline">\(V_C\)</span>能够有效的保护后级电路（最好低于主控芯片<strong>额定工作电压</strong>的<strong>上限值</strong>）。</li><li><strong>结电容</strong> <span class="math inline">\(C_j\)</span>不能影响后级被保护电路的信号完整性。</li><li><strong>额定瞬态功率</strong> <span class="math inline">\(P_{PPM}\)</span>充裕，满足测试标准的同时，不能比电路中的保险丝更早损毁。</li></ol>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;strong&gt;瞬态电压抑制二极管&lt;/strong&gt;（TVS，Transient Voltage
Suppressors）二极管，是一种在传统&lt;strong&gt;齐纳二极管&lt;/strong&gt;工艺基础之上制造的一种电路保护元器件，也被称为
&lt;code&gt;瞬变抑制二极管&lt;/code&gt;、&lt;code&gt;瞬态电压抑制器&lt;/code&gt;、&lt;code&gt;雪崩击穿二极管&lt;/code&gt;
等。其具有单向与双向之分，当两端经受瞬间高能量冲击时，就会以皮秒级别的速度将两端的阻抗值由&lt;strong&gt;高阻抗&lt;/strong&gt;变化为&lt;strong&gt;低阻抗&lt;/strong&gt;，从而将瞬间大电流接地，并把两端的电压箝制在一个预定的数值上，进而确保后级电路不会受到瞬态高压尖峰脉冲的影响。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/Electronics/TVS/logo.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;总而言之，TVS
二极管凭借&lt;code&gt;皮秒级导通速率&lt;/code&gt;、&lt;code&gt;大瞬态功率&lt;/code&gt;、&lt;code&gt;低漏电流与电容&lt;/code&gt;、&lt;code&gt;容易控制的箝位电压&lt;/code&gt;、&lt;code&gt;击穿电压偏差小&lt;/code&gt;、&lt;code&gt;可靠性高&lt;/code&gt;、&lt;code&gt;体积小&lt;/code&gt;
等优势，被广泛应用于敏感电路的过压保护当中（特别是 ESD
静电防护）。目前国际市场上比较主流的 TVS 生产制造企业有 &lt;a href=&quot;https://www.vishay.com/zh/diodes/tvs-protection/&quot;&gt;美国威世
Vishay&lt;/a&gt;、&lt;a href=&quot;https://m.littelfuse.com/products/emc-components.aspx?lang=ZH&quot;&gt;美国力特
Littelfuse&lt;/a&gt;、&lt;a href=&quot;https://www.onsemi.cn/products/discrete-power-modules&quot;&gt;日本安森美
Onsemi&lt;/a&gt;、&lt;a href=&quot;https://www.nexperia.cn/products/diodes/zener-diodes&quot;&gt;荷兰安世
Nexperia&lt;/a&gt; 等厂家，而国内最近几年也涌现出了 &lt;a href=&quot;https://www.lrc.cn/product/protector.html&quot;&gt;乐山无线电 LRC&lt;/a&gt;、&lt;a href=&quot;https://www.techpublic.com/home/product/index.html&quot;&gt;台州电子
TechPublic&lt;/a&gt; 以及国巨旗下的 &lt;a href=&quot;https://brightking.yageo.com/Products/list_12.aspx?lcid=47&quot;&gt;君耀电子
BrightKing&lt;/a&gt; 等比较有实力的供应商。&lt;/p&gt;</summary>
    
    
    
    <category term="硬件电子技术" scheme="http://www.uinio.com/categories/%E7%A1%AC%E4%BB%B6%E7%94%B5%E5%AD%90%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="元器件" scheme="http://www.uinio.com/tags/%E5%85%83%E5%99%A8%E4%BB%B6/"/>
    
  </entry>
  
  <entry>
    <title>锂离子电池技术参数简明选型指南</title>
    <link href="http://www.uinio.com/Electronics/Battery/"/>
    <id>http://www.uinio.com/Electronics/Battery/</id>
    <published>2024-08-28T16:00:00.000Z</published>
    <updated>2025-06-25T14:52:26.710Z</updated>
    
    <content type="html"><![CDATA[<p><strong>锂离子电池</strong>是一种采用锂金属化合物作为正负极材料，中间再填充电解质溶液的化学电池，属于一种可反复充放电的<strong>二次电池</strong>。内部主要依靠<strong>锂离子</strong>在正极与负极之间的移动来进行充放电。在充放电过程中，锂离子在两个电极之间不断的往返，嵌入正负极材料或者从正负极材料当中脱嵌。例如在充电时，锂离子就会从正极材料脱嵌，穿过电解质溶液之后再嵌入负极材料，使得负极逐渐呈现出富锂状态，而在放电的时候这个化学过程正好相反。</p><p><img src="/Electronics/Battery/logo.png"></p><p>长期以来，围绕锂离子电池安全性的话题层出不穷，大量的行业规范与政策法规，伴随着锂离子电池的大规模市场化应用而被不断推出。自从2024 年 8 月 1 日起，我国已经对锂离子电池实施 <strong>3C</strong>强制认证管理，未获得 <strong>3C</strong> 认证并且标注<strong>3C</strong>认证标识的锂电池产品，将不得出厂进行销售和进行其它经营活动。本文总结了各类锂离子电池材料的特性，以及选型过程当中的一些重要事项，希冀能够对于广大电子工程师的物料选型工作有所裨益。</p><span id="more"></span><h2 id="基本原理">基本原理</h2><p>锂离子电池主要是由<strong>正极</strong>（锂化合物）和<strong>负极</strong>（石墨）材料，以及两极之间填充的<strong>电解液</strong>和<strong>隔膜</strong>构成。主要依靠锂离子在正负极之间移动，从而将<strong>化学能</strong>转换为<strong>电能</strong>。下面的示意图分别展示了锂离子电池在充电与放电的时刻，电池内部锂离子的运动方向，以及外电路当中电流的运动方向：</p><p><img src="/Electronics/Battery/Basic-Theory.png"></p><h2 id="寿命参数">寿命参数</h2><p>锂离子电池（后续直接简称为<strong>锂电池</strong>）通常会使用循环次数和日历寿命两指标来表示电池的寿命：</p><ul><li><strong>循环次数</strong>：将电池从 <code>0％</code> 充电至<code>100％</code>，再从 <code>100％</code> 放电到 <code>0％</code>作为一个循环，能够反复进行充放电的次数。</li><li><strong>日历寿命</strong>：表示电池在规定的充电状态下即使静置也能够使用的时间，即从生产之日起至电池寿命结束的时间长度。</li></ul><p>在接下来的表格里，展示了三种常用电池（铅蓄电池、镍氢电池、锂离子电池）的循环次数和日历寿命：</p><table><thead><tr><th style="text-align: left;">电池类型</th><th style="text-align: left;">循环次数</th><th style="text-align: left;">日历寿命</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>铅蓄电池</strong></td><td style="text-align: left;"><code>3150 次</code></td><td style="text-align: left;"><code>17 年</code></td></tr><tr><td style="text-align: left;"><strong>镍氢电池</strong></td><td style="text-align: left;"><code>2000 次</code></td><td style="text-align: left;"><code>5~7 年</code></td></tr><tr><td style="text-align: left;"><strong>锂离子电池</strong></td><td style="text-align: left;"><code>3500 次</code></td><td style="text-align: left;"><code>6~10 年</code></td></tr></tbody></table><blockquote><p><strong>注意</strong>：虽然铅蓄电池的寿命长于锂离子电池，但是其能量密度相较于锂离子电池要差上许多。综合循环次数与日历寿命两个指标，</p></blockquote><h2 id="材料分类">材料分类</h2><p>根据<strong>正极</strong>材料所采用锂化合物的不同，可以将锂离子电池划分为如下几个种类：</p><ol type="1"><li><strong>钴酸锂</strong>电池：钴酸锂比较容易合成，但是钴是稀有金属，价格比较昂贵，并且化学性质非常活泼，需要限制充放电电流，避免出现热失控。</li><li><strong>锰酸锂</strong>电池：放电电压与钴酸锂电池相类似，但是制造成本更加低廉，但是充放电过程当中，锰可能会溶入电解质，缩短电池寿命。</li><li><strong>三元锂</strong>电池：即<strong>镍钴锰酸锂</strong>，优点在于安全性相对高，而且以铁作为原材料，生成成本相比锰酸锂更低，缺点在于放电电压非常低。</li><li><strong>磷酸铁锂</strong>电池：为了减少钴的用量，同时使用了钴、镍、锰三种材料，其中镍的比例较高，虽然放电电压相比钴酸锂、锰酸锂略低，但是能够降低生产成本，并且容量较高。但是缺点在于材料化学属性较为活泼，高温性能不稳定。</li><li><strong>钛酸锂</strong>电池：负极材料采用钛酸锂，正极材料采用上述其它几种锂离子材料，稳定性和安全性更好，循环寿命更长。但是价格昂贵，且能量密度过低，不太适合作为动力电池。</li></ol><p><img src="/Electronics/Battery/Li.png"></p><table><colgroup><col style="width: 13%"><col style="width: 8%"><col style="width: 13%"><col style="width: 10%"><col style="width: 10%"><col style="width: 14%"><col style="width: 8%"><col style="width: 21%"></colgroup><thead><tr><th style="text-align: left;">锂离子电池类型</th><th style="text-align: left;">标称电压</th><th style="text-align: left;">典型工作电压范围</th><th style="text-align: left;">充电截止电压</th><th style="text-align: left;">放电截止电压</th><th style="text-align: left;">循环寿命</th><th style="text-align: left;">热失控温度</th><th style="text-align: left;">容量（能量密度法，Wh/Kg）</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>钴酸锂</strong>电池</td><td style="text-align: left;"><code>3.6V</code></td><td style="text-align: left;"><code>3.0V ~ 4.2V</code></td><td style="text-align: left;"><code>4.2V</code></td><td style="text-align: left;"><code>2.5V</code></td><td style="text-align: left;"><code>500 ～ 1000</code> 次</td><td style="text-align: left;"><code>150°C</code></td><td style="text-align: left;"><code>150 ~ 200 Wh/Kg</code></td></tr><tr><td style="text-align: left;"><strong>锰酸锂</strong>电池</td><td style="text-align: left;"><code>3.7/3.8V</code></td><td style="text-align: left;"><code>3.0V ~ 4.2V</code></td><td style="text-align: left;"><code>4.2V</code></td><td style="text-align: left;"><code>2.5V</code></td><td style="text-align: left;"><code>300 ～ 700</code> 次</td><td style="text-align: left;"><code>250°C</code></td><td style="text-align: left;"><code>100 ~ 150 Wh/Kg</code></td></tr><tr><td style="text-align: left;"><strong>三元锂</strong>电池</td><td style="text-align: left;"><code>3.6/3.7V</code></td><td style="text-align: left;"><code>3.0V ~ 4.2V</code></td><td style="text-align: left;"><code>4.2V</code></td><td style="text-align: left;"><code>2.5V</code></td><td style="text-align: left;"><code>1000 ～ 2000</code> 次</td><td style="text-align: left;"><code>210°C</code></td><td style="text-align: left;"><code>150 ~ 220 Wh/Kg</code></td></tr><tr><td style="text-align: left;"><strong>磷酸铁锂</strong>电池</td><td style="text-align: left;"><code>3.2/3.3V</code></td><td style="text-align: left;"><code>2.5V ~ 3.65V</code></td><td style="text-align: left;"><code>3.65V</code></td><td style="text-align: left;"><code>2.5V</code></td><td style="text-align: left;"><code>1000 ～ 2000</code> 次</td><td style="text-align: left;"><code>270°C</code></td><td style="text-align: left;"><code>90 ~ 120 Wh/Kg</code></td></tr><tr><td style="text-align: left;"><strong>钛酸锂</strong>电池</td><td style="text-align: left;"><code>2.4V</code></td><td style="text-align: left;"><code>1.8V ~ 2.85V</code></td><td style="text-align: left;"><code>2.85V</code></td><td style="text-align: left;"><code>1.8V</code></td><td style="text-align: left;"><code>3000 ～ 7000</code> 次</td><td style="text-align: left;"><code>500°C</code></td><td style="text-align: left;"><code>50 ~ 80 Wh/Kg</code></td></tr></tbody></table><h2 id="封装规格">封装规格</h2><p>根据封装形式的不同，大体上可以将锂离子电池划分为<strong>软包</strong>（下图左，尺寸形状可定制）和<strong>金属壳</strong>（下图右，尺寸形状固定）两种类型，</p><p><img src="/Electronics/Battery/18650.png"></p><p>其中在 <a href="https://webstore.iec.ch/en/publication/27451"><strong>国际电工技术委员会IEC61960 规范</strong></a>当中，对于<strong>圆柱形金属壳</strong>锂离子电池的命名形式进行了定义：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">正极材料代码 + 负极材料代码 + 直径 + 高度</span><br></pre></td></tr></table></figure><p>其中，<strong>正极</strong>材料包括有<code>C/U</code>（钴酸锂）、<code>M</code>（锰酸锂）、<code>NB</code>（氧化铌）、<code>V</code>（氧化钒）、<code>T</code>（钛酸锂），而<strong>负极</strong>材料包括有<code>C</code>（碳）、<code>L</code>（铝酸锂）、<code>S</code>（硅酸锂）、<code>T/TL</code>（钛酸锂）。除此之外，直径和高度的单位均为<code>mm</code><strong>毫米</strong>。为了书写方便，通常会省去前面的正负极材料代码，而直接使用外形尺寸来描述不同的电池规格。例如在下面的表格里，就展示了常用<strong>圆柱形金属壳</strong>锂离子电池的型号与规格：</p><table><thead><tr><th style="text-align: left;">型号</th><th style="text-align: left;">直径（mm）</th><th style="text-align: left;">高度（mm）</th><th style="text-align: left;">容量（时间乘积法，mAh）</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>14500</strong> 型</td><td style="text-align: left;"><code>14 毫米</code></td><td style="text-align: left;"><code>50 毫米</code></td><td style="text-align: left;"><code>800  ~ 1000 毫安时</code></td></tr><tr><td style="text-align: left;"><strong>18650</strong> 型</td><td style="text-align: left;"><code>18 毫米</code></td><td style="text-align: left;"><code>65 毫米</code></td><td style="text-align: left;"><code>2000 ~ 3500 毫安时</code></td></tr><tr><td style="text-align: left;"><strong>18500</strong> 型</td><td style="text-align: left;"><code>18 毫米</code></td><td style="text-align: left;"><code>50 毫米</code></td><td style="text-align: left;"><code>1000 ~ 2000 毫安时</code></td></tr><tr><td style="text-align: left;"><strong>26650</strong> 型</td><td style="text-align: left;"><code>26 毫米</code></td><td style="text-align: left;"><code>65 毫米</code></td><td style="text-align: left;"><code>3200 ~ 3500 毫安时</code></td></tr><tr><td style="text-align: left;"><strong>21700</strong> 型</td><td style="text-align: left;"><code>21 毫米</code></td><td style="text-align: left;"><code>70 毫米</code></td><td style="text-align: left;"><code>3000 ~ 4800 毫安时</code></td></tr><tr><td style="text-align: left;"><strong>32650</strong> 型</td><td style="text-align: left;"><code>32 毫米</code></td><td style="text-align: left;"><code>65 毫米</code></td><td style="text-align: left;"><code>4500 ~ 6500 毫安时</code></td></tr><tr><td style="text-align: left;"><strong>32700</strong> 型</td><td style="text-align: left;"><code>32 毫米</code></td><td style="text-align: left;"><code>70 毫米</code></td><td style="text-align: left;"><code>4500 ~ 6500 毫安时</code></td></tr></tbody></table><blockquote><p><strong>注意</strong>：上述表格当中，电池型号末尾的 <code>0</code>代表其为<strong>圆柱形</strong>锂电池。</p></blockquote><h2 id="串并联关系">串并联关系</h2><p>概而言之，电阻器是<strong>串联分压，并联分流</strong>，而锂电池则是<strong>串联增压，并联增流增容</strong>，它们各自的连接方式分别如下图所示：</p><p><img src="/Electronics/Battery/Series-Parallel.png"></p><ul><li><strong>串联</strong>（上图左）：将锂电池单体首尾相连，此时负载<code>Load</code> 两端的输出电压，等于各个单体的端电压之和<code>36V</code>。</li><li><strong>并联</strong>（上图右）：将锂电池单体的正极分别相互连接到一起，此时负载<code>Load</code> 两端的输出电压不变，输出电流等于各个单体的输出电流之和<code>3A</code>，并且最终构成的电池包总容量也会相应的提升至三个单体容量之和。</li></ul><blockquote><p><strong>注意</strong>：由单体<strong>锂电芯</strong>组成的<strong>锂电池包</strong>，其串并联关系的选型，要依据电源电路所需要的<strong>工作电压范围</strong>、后级负载的<strong>持续运行时间</strong>以及其所<strong>消耗的电流</strong>来综合进行判断。特别需要注意满足在后级负载<strong>上电启动</strong>的一瞬间，所产生的<strong>瞬时峰值电流</strong>需求。最好先将后级负载连接至<strong>可编程电源</strong>，观察一下该峰值电流的大小，并以该电流值作为锂电池包输出电流的<strong>上限值</strong>来进行选型，并且尽量保留一定的性能冗余。</p></blockquote><h2 id="电池容量">电池容量</h2><p>锂电池容量的计算方法，根据表达意义所侧重的不同，可以进一步划分为<strong>能量密度法</strong>和<strong>时间乘积法</strong>两种方式：</p><ul><li><strong>能量密度法</strong>：即电池容量与电池质量的比值，通常以<strong>瓦时/千克</strong>（<code>Wh/kg</code>）作为单位进行表示。</li><li><strong>时间乘积法</strong>：通常以<strong>安时</strong>（<code>Ah</code>，Ampere-hour）作为单位，表示在一定放电条件下（环境温度<code>25°C</code>左右），其所能够提供的电流和持续时间的乘积。例如，如果一节锂电池能够以 1安培的电流持续放电 1 小时，那么其容量就等于 <code>1Ah</code> 安时。</li></ul><blockquote><p><strong>注意</strong>：这两种表达方式都已经体现到了前述内容的表格当中。</p></blockquote><h2 id="充放电倍率">充放电倍率</h2><p><strong>充放电倍率</strong> <code>C</code>用于表示锂电池在单位时间内，完全放电所输出的电流大小。例如一节标称为<code>3300mAh</code> 容量的 18650 型三元锂电池，其放电倍率为<code>3C</code>，则其以 1 小时单位时间内进行放电，输出的电流应当为<code>9.9A</code> 安培，具体计算公式如下所示：</p><p><span class="math display">\[I_{输出电流} = C_{充放电倍率} \times P_{锂电池额定容量}\]</span></p><p>根据放电倍率的不同，还可以将锂电池划分为<strong>功率/动力型</strong>（放电倍率大于<code>10C</code>）和<strong>容量型</strong>（放电倍率<code>1C ~ 3C</code>）两种类型。下图是某国产 18650型锂电池的规格书，注意其中关于锂电池充放电倍率的描述：</p><p><img src="/Electronics/Battery/Datasheet.png"></p><h2 id="锂电池内阻">锂电池内阻</h2><p>锂电池的内阻是指电池在工作时，电流经过电池内部所受到的阻力（不是常量，会随时间和温度变化）。主要由<strong>欧姆内阻</strong>（电解液、电极材料、隔膜的体电阻或者接触电阻）和<strong>极化内阻</strong>（正负极发生电化学反应时极化所产生的阻抗）两个部分组成。</p><p>较低的锂电池内阻可以减少充放电过程当中的能量损失，也有助于降低锂电池在大电流充放电时候所产生的热量，从而降低热失控的风险。除此之外，锂电池内阻的增高通常与锂电池内部材料的老化过程相关，因而监测内阻的变化对于预测电池的健康状态也具有重要意义。锂电阻的内阻测量方法主要包括直流和交流两种：</p><ul><li><strong>直流测量法</strong>：通过在锂电池两端施加恒定电压并测量通过锂电池的电流来计算内阻。</li><li><strong>交流测量法</strong>：通过在锂电池两端施加小幅的交流电压，并测量其电流响应来计算内阻。</li></ul><h2 id="充电的三个过程">充电的三个过程</h2><p>为了确保锂电池充电过程的安全，需要采用特定的电流与电压（即<strong>限压恒流</strong>）进行充电，整个充电过程主要划分为<strong>涓流充电</strong>、<strong>恒流充电</strong>、<strong>恒压充电</strong>三个阶段，下面以三元锂电池的充电过程为例进行说明：</p><p><img src="/Electronics/Battery/Charge.png"></p><ul><li><strong>涓流充电</strong>阶段：当电池电压低于 <code>3V</code>时进行低压预充，充电电流为恒流充电倍率的 <code>0.1C</code>。</li><li><strong>恒流充电</strong>阶段：当电池电压上升至涓流充电电压的阈值之上时，就可以提高充电电流至<code>0.2C ~ 1C</code> 进行恒流充电，直至电压上升至 <code>4.2V</code>时结束恒流充电。</li><li><strong>恒压充电</strong>阶段：保持充电电压为<code>4.2V</code>，伴随着电池电量的逐渐饱和，当充电电流逐渐减小至<code>0.01C</code> 的时候，就可以终止充电。</li></ul><h2 id="bms-充放电参数">BMS 充放电参数</h2><p>接下来的内容，展示了锂离子<strong>电池管理系统</strong>（BMS，BatteryManagement System）固件开发过程当中，一些常用的头文件配置参数标定：</p><ol type="1"><li><strong>单体过压保护电压</strong>：单节锂电池的过压保护值，充电时不得超过该上限电压（厂家数据手册）。</li><li><strong>单体过压恢复电压</strong>：低于该参数的时候，就可以认为单节锂电池已经处于不饱和状态（可自定义）。</li><li><strong>单体欠压保护电压</strong>：单节锂电池低于该电压的时候，就会停止继续放电，避免损坏电池（厂家数据手册）。</li><li><strong>单体欠压恢复电压</strong>：单节锂电池高于该电压的时候，可以认为其已经退出欠压保护状态（可自定义）。</li><li><strong>自动关机电压</strong>：低于该电压，就会关闭硬件系统（可自定义）。</li><li><strong>均衡起始电压</strong>：高于该参数时，就会启动电池均衡过程（可自定义）。</li></ol><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 三元锂（Trihydride Lithium）电池 BMS 参数 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TL_Over_Voltage_Protect   4.20 <span class="comment">// 单体过压保护电压</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TL_Over_Voltage_Rcovery   4.18 <span class="comment">// 单体过压恢复电压</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TL_Under_Voltage_Protect  2.65 <span class="comment">// 单体欠压保护电压</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TL_Under_Voltage_Rcovery  2.70 <span class="comment">// 单体欠压恢复电压</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TL_Shutdown_Voltage       3.00 <span class="comment">// 自动关机电压</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TL_Balance_Voltage        3.30 <span class="comment">// 均衡起始电压</span></span></span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 磷酸铁锂（Lithium Iron Phosphate）电池 BMS 参数 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TL_Over_Voltage_Protect   3.60 <span class="comment">// 单体过压保护电压</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TL_Over_Voltage_Rcovery   3.55 <span class="comment">// 单体过压恢复电压</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TL_Under_Voltage_Protect  2.60 <span class="comment">// 单体欠压保护电压</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TL_Under_Voltage_Rcovery  2.65 <span class="comment">// 单体欠压恢复电压</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TL_Shutdown_Voltage       2.50 <span class="comment">// 自动关机电压</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TL_Balance_Voltage        3.00 <span class="comment">// 均衡起始电压</span></span></span><br></pre></td></tr></table></figure><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 钛酸锂（Lithium Titanate）电池 BMS 参数 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> LT_Over_Voltage_Protect   2.70 <span class="comment">// 单体过压保护电压</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> LT_Over_Voltage_Rcovery   2.65 <span class="comment">// 单体过压恢复电压</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> LT_Under_Voltage_Protect  1.80 <span class="comment">// 单体欠压保护电压</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> LT_Under_Voltage_Rcovery  1.85 <span class="comment">// 单体欠压恢复电压</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> LT_Shutdown_Voltage       1.70 <span class="comment">// 自动关机电压</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> LT_Balance_Voltage        2.30 <span class="comment">// 均衡起始电压</span></span></span><br></pre></td></tr></table></figure>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;strong&gt;锂离子电池&lt;/strong&gt;是一种采用锂金属化合物作为正负极材料，中间再填充电解质溶液的化学电池，属于一种可反复充放电的&lt;strong&gt;二次电池&lt;/strong&gt;。内部主要依靠&lt;strong&gt;锂离子&lt;/strong&gt;在正极与负极之间的移动来进行充放电。在充放电过程中，锂离子在两个电极之间不断的往返，嵌入正负极材料或者从正负极材料当中脱嵌。例如在充电时，锂离子就会从正极材料脱嵌，穿过电解质溶液之后再嵌入负极材料，使得负极逐渐呈现出富锂状态，而在放电的时候这个化学过程正好相反。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/Electronics/Battery/logo.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;长期以来，围绕锂离子电池安全性的话题层出不穷，大量的行业规范与政策法规，伴随着锂离子电池的大规模市场化应用而被不断推出。自从
2024 年 8 月 1 日起，我国已经对锂离子电池实施 &lt;strong&gt;3C&lt;/strong&gt;
强制认证管理，未获得 &lt;strong&gt;3C&lt;/strong&gt; 认证并且标注
&lt;strong&gt;3C&lt;/strong&gt;
认证标识的锂电池产品，将不得出厂进行销售和进行其它经营活动。本文总结了各类锂离子电池材料的特性，以及选型过程当中的一些重要事项，希冀能够对于广大电子工程师的物料选型工作有所裨益。&lt;/p&gt;</summary>
    
    
    
    <category term="硬件电子技术" scheme="http://www.uinio.com/categories/%E7%A1%AC%E4%BB%B6%E7%94%B5%E5%AD%90%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="元器件" scheme="http://www.uinio.com/tags/%E5%85%83%E5%99%A8%E4%BB%B6/"/>
    
  </entry>
  
  <entry>
    <title>如何使用新版本的 LTspice 进行模拟电路仿真</title>
    <link href="http://www.uinio.com/Electronics/LTspice/"/>
    <id>http://www.uinio.com/Electronics/LTspice/</id>
    <published>2024-05-21T16:00:00.000Z</published>
    <updated>2025-06-25T14:52:27.083Z</updated>
    
    <content type="html"><![CDATA[<p><strong>集成电路仿真程序</strong>（<strong>SPICE</strong>，SimulationProgram with Integrated CircuitsEmphasis）是一款以<strong>文本</strong>进行描述，可以通过<strong>数学</strong>方法来预测电路行为的仿真工具，也是电子自动化设计与现代半导体工业的基石。其被广泛应用于<strong>模拟电路</strong>（例如运放算放大器、稳压电源，模数与数模转换等），<strong>混合信号电路</strong>（锁相环、存储器、高速GPIO），<strong>精密数字电路</strong>（延时、时序、功耗、漏电流等）等场景的模拟与仿真（大型电子元器件生产企业通常都提供了元件配套的<a href="https://www.ni.com/zh-cn/shop/electronic-test-instrumentation/application-software-for-electronic-test-and-instrumentation-category/what-is-multisim/spice-simulation-fundamentals/spice-simulation-models.html">SPICE模型</a>）。</p><p><img src="/Electronics/LTspice/logo.png"></p><p><a href="https://www.analog.com/cn/index.html"><strong>亚德诺半导体公司</strong></a>（AnalogDevices）推出的 <strong>LTspice</strong>是一款界面简洁，但是功能强大的免费 <strong>SPICE</strong>电路仿真工具，其可以基于原理图快速准确的生成仿真结果，并且将这些结果通过内置的波形查看器进行展示，除此之外还内置有丰富的SPICE 模型（包含有基本的<strong>无源元件</strong>以及 ADI公司的<code>电源管理</code>和<code>信号链</code>产品），可以预先为模拟电路的设计以及元器件的选型提供重要的实验数据参考，从而降低电路设计过程当中产生的各种试错成本，有效的提高设计工作效率。</p><span id="more"></span><h2 id="基础操作">基础操作</h2><p><strong>LTspice</strong> 自带有一系列后缀名称为 <code>.asc</code>的<strong>仿真原理图示例文件</strong>，它们都位于 Windows 操作系统的<code>C:\Users\hank\AppData\Local\LTspice\examples</code>目录下面，主要包含有如下两个目录：</p><ul><li><strong>Educational目录</strong>：提供有一些基础的参考示例电路。</li><li><strong>Applications目录</strong>：亚德诺半导体公司产品相关的仿真原理图。</li></ul><p>在 <strong>LTspice</strong> 的主界面，鼠标依次点击菜单栏上的【File-&gt; Open Examples...】，就可以打开 <code>examples</code>目录，从而可以查看选中的 <code>.asc</code> 仿真原理图文件：</p><p><img src="/Electronics/LTspice/1-Basic/1.png"></p><p>这里打开 <code>Educational</code> 目录下的 <code>colpits.asc</code>振荡电路示例文件，然后按下键盘上的【<strong>空格</strong>】键，就可以将仿真原理图缩放至一个适配当前屏幕的显示尺寸：</p><p><img src="/Electronics/LTspice/1-Basic/2.png"></p><blockquote><p><strong>注意</strong>：鼠标滚轮向前是<strong>缩小</strong>操作，鼠标滚轮向后是<strong>放大</strong>操作。</p></blockquote><p>鼠标点击 <strong>LTspice</strong>顶部菜单栏上的【<strong>Run/Pause</strong>】按钮，或者按下快捷键【<strong>Alt+ R</strong>】，此时就会在 <code>Educational</code> 目录下自动生成一个<code>colpits.raw</code><strong>波形数据文件</strong>，同时也会在主界面打开一个可以单独进行<code>拖动</code>、<code>关闭</code>、<code>最大化</code>、<code>最小化</code>的波形数据预览窗口：</p><p><img src="/Electronics/LTspice/1-Basic/3.png"></p><p>鼠标点击 <strong>LTspice</strong> 顶部菜单栏上的【<strong>Window-&gt; TileHorizontally/Vertically</strong>】按钮，可以设置主界面当中窗口的平铺方向（<code>垂直</code>或者<code>水平</code>）：</p><p><img src="/Electronics/LTspice/1-Basic/4.png"></p><p>此时，把鼠标移动到主界面右侧的 <code>colpits.asc</code>仿真原理图上面，就可以使用下图所示的<strong>电压探头</strong>或者<strong>电流探头</strong>（会有<strong>箭头</strong>标识出电流的方向），查看该<strong>点</strong>所对应的电压或者电流信号的情况：</p><p><img src="/Electronics/LTspice/1-Basic/5.png"></p><p>电压与电流信号的相关波形，将会自动展示到主界面当中的<code>colpits.raw</code> 波形数据文件预览窗口：</p><p><img src="/Electronics/LTspice/1-Basic/6.png"></p><blockquote><p><strong>注意</strong>：除此之外，按下键盘上的【<strong>ALT</strong>】键不放，将鼠标移动到仿真电路当中的元器件上面，此时鼠标会显示为一个<strong>温度计符号</strong>，按下鼠标左键就可以在<strong>波形显示窗口</strong>查看到该元器件所消耗的功率情况。</p></blockquote><p>使用鼠标框选 <code>colpits.raw</code>波形数据文件预览窗口当中的波形，就可以放大该区域的波形细节（此时如果按下【<strong>空格键</strong>】或者在波形上展开鼠标右键菜单点击【<strong>Zoomto Fit</strong>】可以恢复波形预览到初始状态）：</p><p><img src="/Electronics/LTspice/1-Basic/7.png"></p><p><img src="/Electronics/LTspice/1-Basic/8.png"></p><blockquote><p><strong>注意</strong>：当使用 <strong>LTspice</strong>绘制仿真原理图的时候，必须手动为<strong>电源负极</strong>添加一个<code>GND</code> 符号。</p></blockquote><h2 id="常用快捷键">常用快捷键</h2><p>在下面的表格里，展示了 <strong>LTspice</strong>当中使用频率非常高的一些快捷键（这些快捷键也可以通过展开菜单栏上的【<strong>Edit</strong>】进行查看或者使用）：</p><table><colgroup><col style="width: 42%"><col style="width: 33%"><col style="width: 23%"></colgroup><thead><tr><th style="text-align: left;">快捷键</th><th style="text-align: left;">英文</th><th style="text-align: left;">中文</th></tr></thead><tbody><tr><td style="text-align: left;">【<strong>Ctrl + Z</strong>】</td><td style="text-align: left;">Undo</td><td style="text-align: left;">撤消</td></tr><tr><td style="text-align: left;">【<strong>Ctrl + Shift + Z</strong>】</td><td style="text-align: left;">Redo</td><td style="text-align: left;">重做</td></tr><tr><td style="text-align: left;">【<strong>T</strong>】</td><td style="text-align: left;">Text</td><td style="text-align: left;">文本</td></tr><tr><td style="text-align: left;">【 <strong>.</strong> 】</td><td style="text-align: left;">SPICE Directive</td><td style="text-align: left;">输入 SPICE 点命令</td></tr><tr><td style="text-align: left;">【<strong>A</strong>】</td><td style="text-align: left;">Configure SPICE Analysis</td><td style="text-align: left;">SPICE 分析配置</td></tr><tr><td style="text-align: left;">【<strong>R</strong>】</td><td style="text-align: left;">Resistor</td><td style="text-align: left;">电阻</td></tr><tr><td style="text-align: left;">【<strong>C</strong>】</td><td style="text-align: left;">Capacitor</td><td style="text-align: left;">电容</td></tr><tr><td style="text-align: left;">【<strong>L</strong>】</td><td style="text-align: left;">Inductor</td><td style="text-align: left;">电感</td></tr><tr><td style="text-align: left;">【<strong>D</strong>】</td><td style="text-align: left;">Diode</td><td style="text-align: left;">二极管</td></tr><tr><td style="text-align: left;">【<strong>P</strong>】</td><td style="text-align: left;">Component</td><td style="text-align: left;">放置元件</td></tr><tr><td style="text-align: left;">【<strong>Ctrl + R</strong>】</td><td style="text-align: left;">Rotate</td><td style="text-align: left;">旋转</td></tr><tr><td style="text-align: left;">【<strong>Ctrl + E</strong>】</td><td style="text-align: left;">Mirror</td><td style="text-align: left;">镜像</td></tr><tr><td style="text-align: left;">【<strong>W</strong>】</td><td style="text-align: left;">Draw Wire</td><td style="text-align: left;">绘制连线</td></tr><tr><td style="text-align: left;">【<strong>N</strong>】</td><td style="text-align: left;">Label Net</td><td style="text-align: left;">网络标号</td></tr><tr><td style="text-align: left;">【<strong>G</strong>】</td><td style="text-align: left;">Place GND</td><td style="text-align: left;">放置 GND 标签</td></tr><tr><td style="text-align: left;">【<strong>B</strong>】</td><td style="text-align: left;">Place BUS tap</td><td style="text-align: left;">放置总线抽头</td></tr><tr><td style="text-align: left;">【<strong>M</strong>】</td><td style="text-align: left;">Move</td><td style="text-align: left;">移动</td></tr><tr><td style="text-align: left;">【<strong>S</strong>】</td><td style="text-align: left;">Stretch</td><td style="text-align: left;">伸缩</td></tr><tr><td style="text-align: left;">【<strong>Backspace</strong>】或【<strong>Del</strong>】</td><td style="text-align: left;">Delete</td><td style="text-align: left;">删除</td></tr><tr><td style="text-align: left;">【<strong>Ctrl + C</strong>】</td><td style="text-align: left;">Duplicate</td><td style="text-align: left;">复制</td></tr><tr><td style="text-align: left;">【<strong>Ctrl + V</strong>】</td><td style="text-align: left;">Paste</td><td style="text-align: left;">粘贴</td></tr></tbody></table><h2 id="快捷键设置">快捷键设置</h2><p>鼠标依次点击 <strong>LTspice</strong> 菜单栏上的【<strong>Simulate-&gt;Settings</strong>】打开设置对话框，选中该对话框里的【<strong>Schematic</strong>】选项卡，按下该界面上的【<strong>KeyboardShortcuts[*]</strong>】按钮：</p><p><img src="/Electronics/LTspice/2-Shortkey/1.png"></p><p>这样就可以查看和修改 <strong>LTspice</strong>全部的快捷键设置，其最新的 <code>24.0.0</code>版本与早期其它版本的默认快捷键设置有所不同，具体请参考如下界面当中的默认设置：</p><p><img src="/Electronics/LTspice/2-Shortkey/2.png"></p><h2 id="常量符号">常量符号</h2><table><colgroup><col style="width: 23%"><col style="width: 17%"><col style="width: 23%"><col style="width: 34%"></colgroup><thead><tr><th style="text-align: center;">LTspice 常量符号</th><th>释义</th><th style="text-align: center;">LTspice 常量符号</th><th>释义</th></tr></thead><tbody><tr><td style="text-align: center;"><code>e</code></td><td>欧拉数</td><td style="text-align: center;"><code>true</code></td><td><span class="math inline">\(1\)</span></td></tr><tr><td style="text-align: center;"><code>pi</code></td><td>圆周率 <span class="math inline">\(\pi\)</span></td><td style="text-align: center;"><code>false</code></td><td><span class="math inline">\(0\)</span></td></tr><tr><td style="text-align: center;"><code>k</code></td><td>波尔兹曼常数</td><td style="text-align: center;"><code>mil</code></td><td><span class="math inline">\(25.4 \times 10^{-6} m\)</span></td></tr><tr><td style="text-align: center;"><code>q</code></td><td>电荷常数</td><td style="text-align: center;">-</td><td>-</td></tr></tbody></table><h2 id="单位符号">单位符号</h2><table><thead><tr><th style="text-align: center;">单位名称</th><th style="text-align: center;">LTspice 单位符号</th><th style="text-align: center;">英文释义</th><th style="text-align: center;">数量级</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>太</strong></td><td style="text-align: center;"><code>T</code> 或者 <code>t</code></td><td style="text-align: center;">Tera</td><td style="text-align: center;"><span class="math inline">\(10^{12}\)</span></td></tr><tr><td style="text-align: center;"><strong>吉</strong></td><td style="text-align: center;"><code>G</code> 或者 <code>g</code></td><td style="text-align: center;">Giga</td><td style="text-align: center;"><span class="math inline">\(10^{9}\)</span></td></tr><tr><td style="text-align: center;"><strong>兆</strong></td><td style="text-align: center;"><code>meg</code></td><td style="text-align: center;">Mega</td><td style="text-align: center;"><span class="math inline">\(10^{6}\)</span></td></tr><tr><td style="text-align: center;"><strong>千</strong></td><td style="text-align: center;"><code>K</code> 或者 <code>k</code></td><td style="text-align: center;">Kilo</td><td style="text-align: center;"><span class="math inline">\(10^{3}\)</span></td></tr><tr><td style="text-align: center;"><strong>毫</strong></td><td style="text-align: center;"><code>M</code> 或者 <code>m</code></td><td style="text-align: center;">Milli</td><td style="text-align: center;"><span class="math inline">\(10^{-3}\)</span></td></tr><tr><td style="text-align: center;"><strong>微</strong></td><td style="text-align: center;"><code>U</code> 或者 <code>u</code></td><td style="text-align: center;">Micro</td><td style="text-align: center;"><span class="math inline">\(10^{-6}\)</span></td></tr><tr><td style="text-align: center;"><strong>纳</strong></td><td style="text-align: center;"><code>N</code> 或者 <code>n</code></td><td style="text-align: center;">Nano</td><td style="text-align: center;"><span class="math inline">\(10^{-9}\)</span></td></tr><tr><td style="text-align: center;"><strong>皮</strong></td><td style="text-align: center;"><code>P</code> 或者 <code>p</code></td><td style="text-align: center;">Pico</td><td style="text-align: center;"><span class="math inline">\(10^{-12}\)</span></td></tr><tr><td style="text-align: center;"><strong>飞</strong></td><td style="text-align: center;"><code>F</code> 或者 <code>f</code></td><td style="text-align: center;">Femto</td><td style="text-align: center;"><span class="math inline">\(10^{-15}\)</span></td></tr></tbody></table><blockquote><p><strong>注意</strong>：表达 <span class="math inline">\(10^6\)</span>数量级要使用 <code>MEG</code> 或者 <code>meg</code>，而不是使用<code>M</code> 或者 <code>m</code>；电容器的参数设置里输入<code>1</code> 表示的是 <code>1</code> 法拉第，而不能使用<code>1F</code> 或者 <code>1f</code>。</p></blockquote><h2 id="spice-点命令">SPICE 点命令</h2><p><strong>LTspice</strong> 当中运行的 SPICE 命令总是以一个点<code>.</code>作为前缀，因而也被称作<strong>点命令</strong>，常用的点命令如下面的表格所示：</p><table><colgroup><col style="width: 8%"><col style="width: 60%"><col style="width: 30%"></colgroup><thead><tr><th>点命令</th><th>英文描述</th><th>中文描述</th></tr></thead><tbody><tr><td><code>.AC</code></td><td>Perform an Small Signal AC Analysis Linearized About the DCOperating Point</td><td>进行关于直流工作点的线性小信号交流分析</td></tr><tr><td><code>.BACKANNO</code></td><td>Annotate the Subcircuit Pin Names on Port Currents</td><td>在端口电流上面标注子电路的引脚名称</td></tr><tr><td><code>.DC</code></td><td>Perform a DC Source Sweep Analysis</td><td>执行直流源扫描分析</td></tr><tr><td><code>.END</code></td><td>End of Netlist</td><td>标识网表的结束</td></tr><tr><td><code>.ENDS</code></td><td>End of Subcircuit Definition</td><td>标识子电路定义的结束</td></tr><tr><td><code>.FERRET</code></td><td>Download a File Given the URL</td><td>从指定的 URL 地址下载文件</td></tr><tr><td><code>.FOUR</code></td><td>Compute a Fourier Component</td><td>计算傅里叶分量</td></tr><tr><td><code>.FRA</code></td><td>Perfom a Time-Domain Frequency Response Analysis</td><td>执行时域频率响应分析</td></tr><tr><td><code>.FUNC</code></td><td>User Defined Functions</td><td>用户定义的功能</td></tr><tr><td><code>.GLOBAL</code></td><td>Declare Global Nodes</td><td>声明全局节点</td></tr><tr><td><code>.IC</code></td><td>Set Initial Conditions</td><td>设置初始条件</td></tr><tr><td><code>.INCLUDE</code></td><td>Include Another File</td><td>包含另一个文件</td></tr><tr><td><code>.LIB</code></td><td>Include a Library</td><td>包含一个库</td></tr><tr><td><code>.LOADBIAS</code></td><td>Load a Previously Solved DC Solution</td><td>加载已经解析过的直流解决方案</td></tr><tr><td><code>.MACHINE</code></td><td>Arbitrary State Machine</td><td>任意状态机</td></tr><tr><td><code>.MEASURE</code></td><td>Evaluate User-Defined Electrical Quantities</td><td>求解用户自定义的工程量</td></tr><tr><td><code>.MODEL</code></td><td>Define a SPICE Model</td><td>定义一个 SPICE 模型</td></tr><tr><td><code>.NET</code></td><td>Compute Network Parameters in a .AC Analysis</td><td>在一个交流分析当中，计算电路网络的参数</td></tr><tr><td><code>.NODESET</code></td><td>Supply Hints for Initial DC Solution</td><td>为初始的直流解决方案提供提示</td></tr><tr><td><code>.NOISE</code></td><td>Perform a Noise Analysis</td><td>进行噪音分析</td></tr><tr><td><code>.OP</code></td><td>Find the DC Operating Point</td><td>查询直流工作点</td></tr><tr><td><code>.OPTIONS</code></td><td>Set Simulator Options</td><td>设置仿真工具的选项</td></tr><tr><td><code>.PARAM</code></td><td>User-Defined Parameters</td><td>用户定义的参数</td></tr><tr><td><code>.SAVE</code></td><td>Limit the Quantity of Saved Data</td><td>限制保存数据的数量</td></tr><tr><td><code>.SAVEBIAS</code></td><td>Save Operating Point to Disk</td><td>保存工作点到磁盘</td></tr><tr><td><code>.STEP</code></td><td>Parameter Sweeps</td><td>参数扫描</td></tr><tr><td><code>.SUBCKT</code></td><td>Define a Subcircuit</td><td>定义一个子电路</td></tr><tr><td><code>.TEMP</code></td><td>Temperature Sweeps</td><td>温度扫描</td></tr><tr><td><code>.TEXT</code></td><td>User-Defined Strings</td><td>用户定义的字符串</td></tr><tr><td><code>.TF</code></td><td>Find the DC Small-Signal Transfer Function</td><td>查找直流小信号传递函数</td></tr><tr><td><code>.TRAN</code></td><td>Do a Nonlinear Transient Analysis</td><td>执行非线性瞬态分析</td></tr><tr><td><code>.WAVE</code></td><td>Write Selected Nodes to a .Wav File</td><td>将选定的节点写入 <code>.wav</code> 文件</td></tr></tbody></table><blockquote><p><strong>注意</strong>：在 <code>.asc</code>源文件当中，<strong>点命令</strong>以 <code>!</code>符号作为开始，而<strong>注释</strong>则是以 <code>;</code>作为开始。</p></blockquote><h2 id="spice-分析类型">SPICE 分析类型</h2><p>鼠标点击 <strong>LTspice</strong>主界面顶部菜单栏上的【<strong>Simulate -&gt; ConfigureAnalysis</strong>】或者直接按下快捷键【<strong>A</strong>】，就可以进入如下的 SPICE仿真命令配置对话框：</p><p><img src="/Electronics/LTspice/3-SPICE/1.png"></p><h3 id="瞬态分析-transient">瞬态分析 Transient</h3><p>瞬态分析指令 <code>.tran</code>用于描述电路当中，各个节点的<strong>电压</strong>与通过元件的<strong>电流</strong>跟随时间的变化关系，即仿真电路在<strong>时域</strong>下的行为：</p><p><img src="/Electronics/LTspice/3-SPICE/2.png"></p><p>瞬态分析指令 <code>.tran</code> 主要拥有如下几个参数：</p><ul><li><code>StopTime</code>：停止时间，该参数用于以<strong>秒</strong>为单位设定仿真的持续时间。</li><li><code>Time to Start Saving Data</code>：仿真数据保存至<code>.raw</code> 波形文件的开始时间。</li><li><code>Maximum Timestep</code>：最大时间间隔，也就是时间的步进长度（缺省表示无限大）。</li></ul><p>瞬态分析指令 <code>.tran</code> 主要拥有如下几个修饰符：</p><ul><li><code>Start external DC supply voltages at 0V</code>：让直流电源从<code>0V</code> 开始上升，并于 <code>20</code>微秒之后达到设定的电压值。</li><li><code>Stop simulating if steady state is detected</code>：如果检测到稳定状态就会停止仿真（只会保存最后10 组重复数据）。</li><li><code>Don't reset = 0 when steady state is detected</code>：如果检测到稳定状态就会停止仿真（将会保存全部数据）。</li><li><code>Step the load current source</code>：使用电流源作为负载时，可以使得负载的电流值逐步变化（即每达到一个稳定状态之后，就会向下变换为另外一个电流值）。</li><li><code>Skip initial operating point solution</code>：启用元器件的初始状态值。</li></ul><h3 id="交流分析-ac-analysis">交流分析 AC Analysis</h3><p>交流分析指令 <code>.ac</code>可以用于分析小信号的交流频率特性，即仿真电路在<strong>频域</strong>下的行为（由于目标分析频率处于<code>0.1Hz ~ 100MHz</code>之间较为宽广的范围，所以频率轴通常被表达为<strong>对数刻度</strong>，计算基准可以设置为每间隔<code>2</code> 倍或者 <code>10</code> 倍）：</p><p><img src="/Electronics/LTspice/3-SPICE/3.png"></p><ul><li><code>Type of sweep</code>：扫描类型，每两倍（<code>Octave</code>）、每十倍（<code>Decade</code>）、线性（<code>Linear</code>）、列表（<code>List</code>）。</li><li><code>Number of points per X</code>：这里的 <code>X</code>是上面设置的扫描类型，通常在 <code>Octave</code> 情况下配置为<code>20 ~ 40</code> 点，而在 <code>Decade</code> 情况下配置为<code>30 ~ 100</code>点。虽然点的数量越多就越精确，但是会花费掉额外的计算时间，所以需要具体情况具体分析。</li><li><code>Start fequency</code>：计算开始频率，单位为<code>Hz</code>。</li><li><code>Stop fequency</code>：计算截止频率，单位为<code>Hz</code>。</li></ul><h3 id="直流扫描分析-dc-sweep">直流扫描分析 DC Sweep</h3><p>直流扫描分析指令 <code>.dc</code>可以动态变换直流源的输出值（最大可以设置 3组扫描变量），可以用于分析<strong>二极管</strong>的伏安特性，<strong>晶体管</strong>的静态特性（将基极电流作为参数，观察集电极电流的变化情况），以及<strong>放大器</strong>的输入输出关系：</p><p><img src="/Electronics/LTspice/3-SPICE/4.png"></p><ul><li><code>Name of 1st/2nd/3rd Source to Sweep</code>：输入用于扫描的电压源、电流源的元件名名称，例如<code>V1</code> 或者 <code>I2</code>。</li><li><code>Type of Sweep</code>：每两倍（<code>Octave</code>）、每十倍（<code>Decade</code>）、线性（<code>Linear</code>）、列表（<code>List</code>）。</li><li><code>Start Value</code>：扫描起始的电压或者电流。</li><li><code>Stop Value</code>：扫描结束的电压或者电流。</li><li><code>Increment</code>：扫描增量，即间隔的幅度值。</li></ul><h3 id="噪声分析-noise">噪声分析 Noise</h3><p>噪声分析指令 <code>.noise</code>用于仿真电路当中<strong>输入</strong>与<strong>输出</strong>相关的频率噪声特性，也就是在<strong>频域</strong>下进行噪声分析（<strong>横轴</strong>是<code>频率</code>，<strong>纵轴</strong>是<code>噪声密度</code>）。其中噪声的单位为<span class="math inline">\(\frac{nV}{\sqrt{Hz}}\)</span>（如果想分析某个<strong>频带</strong>的噪声，只需要将该频带振幅的<strong>频率</strong>进行平方之后，再乘以噪声的<strong>电压密度</strong>即可推算出来）。</p><p><img src="/Electronics/LTspice/3-SPICE/5.png"></p><ul><li><code>Input</code>：输入噪声的结点网络标签。</li><li><code>Qutput</code>：输出噪声的结点网络标签。</li><li><strong>其它参数</strong>：与交流分析（ACAnalysis）相关的参数相同。</li></ul><blockquote><p><strong>注意</strong>：在该模式下按住键盘上的【<strong>CTRL</strong>】键，然后鼠标左键点击波形预览窗口上的<span class="math inline">\(V(onoise)\)</span>标签，就可以查看<strong>总电压噪声</strong>的均方根值（<strong>RMS</strong>，RootMean Square）。</p></blockquote><h3 id="直流传递分析-dc-transfer">直流传递分析 DC Transfer</h3><p>直流传输分析命令 <code>.tf</code>通过将偏置点附近的微小变化视为直线，从而计算出小信号的<strong>输入输出的传递函数值</strong>，以及<strong>输入阻抗</strong>和<strong>输出阻抗</strong>。</p><p><img src="/Electronics/LTspice/3-SPICE/6.png"></p><ul><li><code>Source</code>：电压源或者电流源的网络标签名称（不能使用<code>节点电压</code>、<code>元件电流</code>的名称）。</li><li><code>Output</code>：指定结点的电压，或者指定元件上面通过的电流。</li></ul><blockquote><p><strong>注意</strong>：<strong>传递函数</strong>用于描述一个电路网络的<strong>输出</strong>与<strong>输入</strong>的拉普拉斯变换之比。</p></blockquote><h3 id="直流工作点分析-dc-op-pnt">直流工作点分析 DC op pnt</h3><p>直流工作点分析指令 <code>.op</code>用于分析晶体管电路当中不含有交流成分的直流偏置信号，该指令通常不会单独使用，而是会与其它分析方式结合起来使用。这条指令没有扩展的修饰词，所以在点击下面界面当中的【<strong>OK</strong>】按钮之后，就可以将该指令放置在仿真原理图上的任意位置进行执行：</p><p><img src="/Electronics/LTspice/3-SPICE/7.png"></p><blockquote><p><strong>注意</strong>：当在仿真原理图上放置好 <code>.op</code>命令，并且运行完毕之后，就会自动弹出一个【OperatingPoint】工作点列表窗口界面。</p></blockquote><h3 id="瞬态频率响应分析-transient-frequency-response">瞬态频率响应分析Transient Frequency Response</h3><p>瞬态频率响应分析指令 <code>.fra</code>用于分析电路反馈回路的频率响应，使用时仿真原理图电路当中必须包含有一个以<code>@</code> 作为前缀的<strong>频率响应分析器</strong>（FRA，FrequencyResponse Analyzer），：</p><p><img src="/Electronics/LTspice/3-SPICE/8.png"></p><p>选择 <strong>LTspice</strong> 菜单栏上的【Edit -&gt;Component】或者直接按下快捷键【<strong>P</strong>】，然后在元件对话框的<strong>Search</strong> 里输入<code>fra</code>，就可以完成频率响应分析器的放置：</p><p><img src="/Electronics/LTspice/3-SPICE/9.png"></p><p>运用 <code>.fra</code>指令的时候，需要对<strong>频率响应分析器</strong>的相关分析参数进行详细配置，这些配置参数被划分为了<strong>分析类型</strong>、<strong>激励频率</strong>、<strong>激励幅值</strong>、<strong>通用</strong>四个部分：</p><p><img src="/Electronics/LTspice/3-SPICE/10.png"></p><h2 id="独立电压-电流源">独立电压 &amp; 电流源</h2><h3 id="独立电压源">独立电压源</h3><p>在 <strong>LTspice</strong>仿真原理图编辑界面，按下快捷键【<strong>P</strong>】，在弹出的元件选择窗口<strong>Search</strong> 里输入<code>voltage</code>，然后点击【确定】按钮，就可以向当前的仿真原理图上添加一个独立电压源：</p><p><img src="/Electronics/LTspice/4-Source/1.png"></p><p>在仿真原理图的电压源符号上点击【鼠标右键】，就会弹出一个电压源参数设置窗口，可以用于输入<code>电源的直流输出电压值</code>(单位为伏特<code>V</code>)，以及<code>电源的内阻</code>(单位为欧姆<code>Ω</code>)：</p><p><img src="/Electronics/LTspice/4-Source/2.png"></p><p>此时如果点击电压源参数设置窗口上的【<strong>Advanced</strong>】按钮，就可以设置更多关于独立电压源的参数：</p><p><img src="/Electronics/LTspice/4-Source/3.png"></p><h3 id="独立电流源">独立电流源</h3><p>在 <strong>LTspice</strong>仿真原理图编辑界面，按下快捷键【<strong>P</strong>】，在弹出的元件选择窗口<strong>Search</strong> 里输入<code>current</code>，然后点击【确定】按钮，就可以向当前的仿真原理图上添加一个独立电流源：</p><p><img src="/Electronics/LTspice/4-Source/4.png"></p><p>在仿真原理图的电流源符号上点击【鼠标右键】，就会弹出一个电流源参数设置窗口，该窗口只可以用于输入<code>电源的直流输出电流值</code>(单位为安培<code>A</code>)：</p><p><img src="/Electronics/LTspice/4-Source/5.png"></p><p>此时如果点击电流源参数设置窗口上的【<strong>Advanced</strong>】按钮，就可以设置更多关于独立电流源的参数：</p><p><img src="/Electronics/LTspice/4-Source/6.png"></p><h3 id="参考方向">参考方向</h3><p><strong>LTspice</strong>仿真原理图同样遵循电路原理当中<strong>关联参考方向</strong>的相关定义，即当<strong>独立电压源</strong>（由正极指向负极）与<strong>独立电流源</strong>的方向<strong>相反</strong>时（即<strong>非关联参考方向</strong>），电路网络当中的电压与电流为<strong>负数</strong>：</p><p><img src="/Electronics/LTspice/4-Source/7.png"></p><p>而当<strong>独立电压源</strong>（由正极指向负极）与<strong>独立电流源</strong>的方向<strong>相同</strong>时（即<strong>关联参考方向</strong>），则电路网络当中的电压与电流的仿真结果为<strong>正数</strong>：</p><p><img src="/Electronics/LTspice/4-Source/8.png"></p><h2 id="波形信号的产生">波形信号的产生</h2><p>打开 <strong>LTspice</strong> 主界面，选择菜单栏上的【<strong>VoltageSource</strong>】或者按下快捷键【<strong>V</strong>】放置一个电压源，然后在该电压源上面点击<strong>鼠标右键</strong>，打开电压源参数设置对话框：</p><p><img src="/Electronics/LTspice/5-Waveform/1.png"></p><h3 id="方波">方波</h3><p>鼠标点击上面电压源参数设置对话框当中的【<strong>Advanced</strong>】按钮，在弹出的独立电压源详细参数设置界面选择【<strong>PULSE</strong>】项，就可以配置脉冲波的相关参数：</p><p><img src="/Electronics/LTspice/5-Waveform/2.png"></p><p>这里我们将<strong>脉冲电压</strong>设置为<code>3.3V</code>，<strong>脉冲持续时间</strong>设置为 <code>1m</code>秒，<strong>周期</strong>设置为 <code>2m</code>秒，输出的<strong>周期数量</strong>设置为 <code>200</code>个，<strong>上升和下降沿时间</strong>分别设置为 <code>10n</code>秒：</p><p><img src="/Electronics/LTspice/5-Waveform/3.png"></p><p>然后按下快捷键【<strong>Alt +R</strong>】运行仿真原理图，就可以从下图左侧独立电压源的<code>OUT</code> 端口，查看到下图右侧所示的方波脉冲信号：</p><p><img src="/Electronics/LTspice/5-Waveform/4.png"></p><h3 id="正弦波">正弦波</h3><p>在弹出的参数设置对话框当中，选择【<strong>Advance</strong>】按钮，打开如下的独立电压源详细参数设置窗口，选择其中的【<strong>SINE</strong>】正弦信号，就可以进一步配置相关的参数：</p><p><img src="/Electronics/LTspice/5-Waveform/5.png"></p><p>这里我们将<strong>电压幅度</strong>设置为<code>220V</code>，<strong>频率</strong>设置为<code>50Hz</code>，从而就可以获得一个 <code>200V</code>民用交流市电的波形：</p><p><img src="/Electronics/LTspice/5-Waveform/6.png"></p><p>按下快捷键【<strong>Alt +R</strong>】运行仿真原理图，就能够从下图左侧独立电压源的<code>OUT</code> 端口，查看到下图右侧所示的正弦脉冲信号：</p><p><img src="/Electronics/LTspice/5-Waveform/7.png"></p><h2 id="四种受控源">四种受控源</h2><h3 id="电压控制电压源">电压控制电压源</h3><p><strong>电压控制电压源</strong>以 <code>E</code>作为网络标号的前缀，在仿真原理图界面按下元件放置快捷键【<strong>P</strong>】之后，在<code>Search</code> 栏输入 <code>e</code> 或者 <code>e2</code>就可以查找并且放置：</p><p><img src="/Electronics/LTspice/6-Controlled/1.png"></p><p>上述仿真原理图当中的<strong>电压源</strong> <code>V1</code>，输出一个<code>3.3V</code> 的直流电压，以此作为<strong>电压控制电压源</strong><code>E1</code> 的控制电压。将 <code>E1</code>的<strong>控制系数</strong>设置为<code>3</code>，那么其输出端就会得到一个 <code>9.9V</code>的直流电压。</p><blockquote><p><strong>注意</strong>：<strong>LTspice</strong> 默认元件库当中的<code>e</code> 和 <code>e2</code>两种电压控制电压源，主要区别在于输入端正负极的先后顺序，其中<code>e</code> 是上正下负，而 <code>e2</code> 则是上负下正。</p></blockquote><h3 id="电压控制电流源">电压控制电流源</h3><p><strong>电压控制电流源</strong>以 <code>G</code>作为网络标号的前缀，在仿真原理图界面按下元件放置快捷键【<strong>P</strong>】之后，在<code>Search</code> 栏输入 <code>g</code> 或者 <code>g2</code>就可以查找并且放置：</p><p><img src="/Electronics/LTspice/6-Controlled/2.png"></p><p>上述仿真原理图当中的<strong>电压源</strong><code>V1</code>，输出一个幅值为 <code>3.3V</code>，频率为<code>1KHz</code> 的正弦信号，以此作为<strong>电压控制电流源</strong><code>G1</code> 的控制电压。将 <code>G1</code>的<strong>控制系数</strong>设置为 <code>2</code>，那么电阻<code>R1</code> 上面就会通过一个变化幅值达到<code>6.6A</code>，变化频率同样为 <code>1KHz</code> 的电流信号。</p><blockquote><p><strong>注意</strong>：<strong>LTspice</strong> 默认元件库当中的<code>g</code> 和 <code>g2</code>两种电压控制电流源，主要区别在于输入端正负极的先后顺序，其中<code>g</code> 是上正下负，而 <code>g2</code> 则是上负下正。</p></blockquote><h3 id="电流控制电压源">电流控制电压源</h3><p><strong>电流控制电压源</strong>以 <code>H</code>作为网络标号的前缀，在仿真原理图界面按下元件放置快捷键【<strong>P</strong>】之后，在<code>Search</code> 栏输入 <code>h</code> 就可以查找并且放置：</p><p><img src="/Electronics/LTspice/6-Controlled/3.png"></p><p>上述仿真原理图当中的<strong>电压源</strong><code>V1</code>，输出一个幅值为 <code>5V</code>，频率为<code>1KHz</code> 的正弦信号，导致电阻 <code>R2</code>上通过的电流也呈正弦规律变化，以此作为<strong>电流控制电压源</strong><code>H1</code> 的控制电流。将 <code>H1</code>的<strong>控制系数</strong>设置为 <code>3</code>，那么电阻<code>R1</code> 上面就会通过一个变化幅值为<code>15V</code>，变化频率同样为 <code>1KHz</code> 的电压信号。</p><blockquote><p><strong>注意</strong>：电流控制电压源的 <code>Value</code>参数，需要采用 <code>电源网络标号 + 空格 + 控制系数</code>的格式进行定义。</p></blockquote><h3 id="电流控制电流源">电流控制电流源</h3><p><strong>电流控制电流源</strong>以 <code>F</code>作为网络标号的前缀，在仿真原理图界面按下元件放置快捷键【<strong>P</strong>】之后，在<code>Search</code> 栏输入 <code>f</code> 就可以查找并且放置：</p><p><img src="/Electronics/LTspice/6-Controlled/4.png"></p><p>上述仿真原理图当中的<strong>电压源</strong><code>V1</code>，输出一个幅值为 <code>5V</code>，频率为<code>1KHz</code> 的正弦信号，导致电阻 <code>R2</code>上通过的电流也呈正弦规律变化，以此作为<strong>电流控制电流源</strong><code>F1</code> 的控制电流。将 <code>F1</code>的<strong>控制系数</strong>设置为 <code>6</code>，那么电阻<code>R1</code> 上面就会通过一个变化幅值为<code>30A</code>，变化频率同样为 <code>1KHz</code> 的电流信号。</p><blockquote><p><strong>注意</strong>：电流控制电流源的 <code>Value</code>参数，需要采用 <code>电源网络标号 + 空格 + 控制系数</code>的格式进行定义。</p></blockquote><h2 id="无源元件-伏安特性">无源元件-伏安特性</h2><h3 id="电阻的伏安特性">电阻的伏安特性</h3><p><strong>欧姆定律</strong>是指一个电阻器两端的<strong>电压</strong><span class="math inline">\(V_R\)</span>，与通过该电阻器的<strong>电流</strong><span class="math inline">\(I_R\)</span>呈正比，而比例常数就是<strong>电阻值</strong> <span class="math inline">\(R\)</span>：</p><p><span class="math display">\[电压 V_R = 电流 I_R \times 电阻 R\]</span></p><p>仿真电阻的伏安特性需要使用 <strong>LTspice</strong>的<strong>直流扫描分析</strong>（DCSweep）功能，将扫描电源指定为仿真原理图里的<code>V1</code>，扫描方式采用 <code>Linear</code>线性，起始和截止扫描电压分别为<code>-10V ~ + 10V</code>，步进增长值则指定为<code>0.1V</code>，具体如下图所示：</p><p><img src="/Electronics/LTspice/7-RCL-VI/1.png"></p><p>将电压源 <code>V1</code> 的输出设置为 <code>5V</code>，而串联电阻<code>R1</code> 的阻值设置为<code>1Ω</code>。运行仿真任务之后，就可以看到电阻器的伏安特性曲线是一个以<strong>电压</strong>作为<code>X</code> 横轴，<strong>电流</strong>作为 <code>Y</code>纵轴，斜率为<strong>电阻值</strong> <span class="math inline">\(R\)</span>，并且经过<strong>原点</strong>的一条直线：</p><p><img src="/Electronics/LTspice/7-RCL-VI/2.png"></p><h3 id="电容的伏安特性">电容的伏安特性</h3><p>电容器两端的<strong>电压</strong> <span class="math inline">\(V_C\)</span>与所存储的<strong>电量</strong>（即通过电容器电流的时间<strong>积分</strong><span class="math inline">\(\int I_Cdt\)</span>）呈正比，与<strong>电容值</strong> <span class="math inline">\(C\)</span> 呈反比：</p><p><span class="math display">\[V_C = \frac{1}{C} \int I_C dt\]</span></p><p>对上面的公式两侧，按照时间进行进行<strong>微分</strong>，并且再分别乘以<strong>电容</strong><span class="math inline">\(C\)</span>，就可以得到如下通过电容器的<strong>电流</strong><span class="math inline">\(I_C\)</span>与电容器两端<strong>电压</strong> <span class="math inline">\(V_C\)</span> 的关系：</p><p><span class="math display">\[C \times \frac{dV_C}{dt} = I_C\]</span></p><p>仿真电容的伏安特性需要使用 <strong>LTspice</strong>的<strong>瞬态分析</strong>（Transient）功能，将停止时间设置为<code>2</code>秒，并且勾选<code>启用元器件的初始状态值</code>，具体如下图所示：</p><p><img src="/Electronics/LTspice/7-RCL-VI/3.png"></p><p>仿真原理图当中的<strong>电流源</strong> <code>I1</code>输出的是<strong>峰峰值</strong>为 <span class="math inline">\(\pm1mA\)</span> 的方波电流信号，相关的详细设置如下图所示：</p><p><img src="/Electronics/LTspice/7-RCL-VI/4.png"></p><p>仿真原理图上串联电容器 <code>C1</code> 的值设置为<code>1F</code>，并联等效电阻设置为<code>1TΩ</code>（以便于在电容器完成充电之后进行放电操作）：</p><p><img src="/Electronics/LTspice/7-RCL-VI/5.png"></p><p>当电容器上通过的<strong>电流</strong> <span class="math inline">\(I\)</span> 增大至 <code>1mA</code> 的时候，电容器<code>C1</code> 开始进入充电状态，两端的<strong>电压</strong> <span class="math inline">\(V_C\)</span>随之线性增大。而当通过电容器的<strong>电流</strong> <span class="math inline">\(I\)</span> 降低至 <code>0mA</code> 的时候，电容器<code>C1</code> 开始通过 <code>1TΩ</code>的并联等效电阻进行放电，此时两端的<strong>电压</strong> <span class="math inline">\(V_C\)</span> 也就随之线性下降：</p><p><img src="/Electronics/LTspice/7-RCL-VI/6.png"></p><h3 id="电感的伏安特性">电感的伏安特性</h3><p>电感器两端的<strong>电压</strong> <span class="math inline">\(V_L\)</span>和单位时间内通过电感器的<strong>电流</strong> <span class="math inline">\(I_L\)</span>的变化量呈<strong>正比</strong>，而与电感器的<strong>电感值</strong><span class="math inline">\(I\)</span>同样也呈<strong>正比</strong>：</p><p><span class="math display">\[V_L = L \times \frac{dI_L}{dt} \xrightarrow{逆关系} I_L = \frac{1}{L}\times \int V_L dt\]</span></p><p>当下面仿真原理图上的<strong>独立电流源</strong> <code>I1</code> 输出<code>5A</code> 直流电流的时候，<strong>电感</strong> <code>L1</code>可以近似为一条两端电压为 <code>5mV</code>的导线（<strong>LTspice</strong> 当中的电感器都会默认带有<code>1mΩ</code> 等效串联电阻）：</p><p><img src="/Electronics/LTspice/7-RCL-VI/7.png"></p><p>当仿真原理图上的<strong>独立电流源</strong> <code>I1</code> 输出的是<code>5A</code> 的正弦直流信号的时候，此时<strong>电感器</strong><code>L1</code> 两端电压 <span class="math inline">\(V_L\)</span>的相位，要超前于电流 <span class="math inline">\(I_L\)</span> 的相位<code>90</code> 度：</p><p><img src="/Electronics/LTspice/7-RCL-VI/8.png"></p><h2 id="无源元件-交流特性">无源元件-交流特性</h2><h3 id="电容的交流特性">电容的交流特性</h3><p>一个容值为 <span class="math inline">\(C\)</span>的电容器，对于<strong>频率</strong>为 <span class="math inline">\(f\)</span> 的信号所产生的<strong>电抗</strong><span class="math inline">\(X_C\)</span>，可以通过如下的公式进行计算得到：</p><p><span class="math display">\[X_C = \frac{1}{2 \pi fC}\]</span></p><p>利用电容器的这种频率依赖特性，可以和电阻一起构成可以只允许特定频率通过的RC滤波电路。根据电路的基本理论，可以知道当<strong>电阻器</strong>通过<strong>交流电流信号</strong><span class="math inline">\(I_C\)</span>时，其两端的<strong>电压</strong> <span class="math inline">\(V_C = R_C\timesI_C\)</span>。而当<strong>电容器</strong>通过<strong>交流电流信号</strong><span class="math inline">\(I_C\)</span>时，其两端的<strong>电压</strong> <span class="math inline">\(V_C = X_C\timesI_C\)</span>。接下来，分别对<strong>电阻器</strong>（<code>10KΩ</code>）和<strong>电容器</strong>（<code>0.001uF</code>、<code>0.01uF</code>、<code>0.1uF</code>）的频率依赖特性进行仿真实验：</p><p><img src="/Electronics/LTspice/7-RCL-VI/9.png"></p><p><img src="/Electronics/LTspice/7-RCL-VI/10.png"></p><p><span class="math display">\[N=a^{x}\ (a &gt; 0, a \neq 1)\impliesx = \log_{a} N\]</span></p><p><span class="math display">\[x = \log_{10} N\impliesx = \lg N\]</span></p><p><span class="math display">\[N_{dB} = 10 \times \lg \frac{P_{输入功率}}{P_{输出功率}}\]</span></p><!-- ### 电感的交流特性## 有源元件-伏安特性### 双极型晶体管的伏安特性### 场效应管的伏安特性## 基本放大电路的仿真## 基本数字逻辑电路的仿真## 导入外部 SPICE 模型 --><h2 id="仿真实例">仿真实例</h2><h3 id="暂态仿真实例">暂态仿真实例</h3><p>模拟电路当中，电阻串联之后具备分压的功能，例如<strong>电压源</strong><span class="math inline">\(V\)</span> 两端的电压为<code>6V</code>，三枚阻值分别为<code>R1 = 1Ω</code>、<code>R2 = 2Ω</code>、<code>R3 = 3Ω</code>的电阻串联之后，每一枚电阻上通过的<strong>电流</strong> <span class="math inline">\(I\)</span> 与所分得的<strong>电压</strong> <span class="math inline">\(V\)</span> 如下面计算所示：</p><p><span class="math display">\[\begin{cases}I_1 = I_2 = I_3 = \frac{V}{R_1 + R_2 + R_3} = 1A; \\V_1 = V = 6V \\V_2 = V \times \frac{R_2 + R_3}{R_1 + R_2 + R_3} = 6V \times \frac{2Ω +3Ω}{1Ω + 2Ω + 3Ω} = 5V \\V_3 = V \times \frac{R_3}{R_1 + R_2 + R_3} = 6V \times \frac{3Ω}{1Ω + 2Ω+ 3Ω} = 3V \\V_{12} = V \times \frac{R_1}{R_1 + R_2 + R_3} = 6V \times \frac{1Ω}{1Ω +2Ω + 3Ω} = 1V \\V_{23} = V \times \frac{R_2}{R_1 + R_2 + R_3} = 6V \times \frac{2Ω}{1Ω +2Ω + 3Ω} = 2V \\V_{13} = V \times \frac{R_3}{R_1 + R_2 + R_3} = 6V \times \frac{3Ω}{1Ω +2Ω + 3Ω} = 3V \\\end{cases}\]</span></p><p>接下来绘制出这个电阻串联电路，打开 <strong>LTspice</strong>的主界面之后，按下键盘上的快捷键【<strong>Ctrl + N</strong>】，就可以在<code>C:\Users\hank\Documents\LTspice</code> 目录下面新建一个默认名称为<code>Draft1.asc</code> 的仿真原理图文件：</p><p><img src="/Electronics/LTspice/Example/1-Transient/1.png"></p><p>完成仿真原理图的绘制之后，鼠标点击 <strong>LTspice</strong>主界面顶部的【ConfigureAnalysis】按钮，或者直接按下快捷键【<strong>A</strong>】，选择暂态分析【<strong>Transient</strong>】选项卡，并将仿真的停止时间设置为<code>1</code> 秒：</p><p><img src="/Electronics/LTspice/Example/1-Transient/2.png"></p><p>在 <strong>LTspice</strong>的仿真原理图上面移动鼠标，就可以使用<strong>电流探头</strong>或者<strong>电压探头</strong>测量相应位置的参数（仔细观察可以发现，这些参数与上面手动计算的结果一致），并将这些参数显示到波形预览界面（同时会在仿真原理图文件<code>Draft1.asc</code> 所在的目录，自动生成出一个<code>Draft1.raw</code> 波形文件）：</p><p><img src="/Electronics/LTspice/Example/1-Transient/3.png"></p><blockquote><p><strong>注意</strong>：测量两点之间的相对电压，需要<strong>鼠标左键</strong>选定第<strong>1</strong>个点的位置之后（此时电压探头为红色），继续按住<strong>鼠标左键</strong>拖动至第2 个点的位置（此时电压探头为黑色）。</p></blockquote><h3 id="交流仿真实例">交流仿真实例</h3><p>在模拟电路当中，由一个<strong>电阻</strong> <code>R = 10kΩ</code>和一个<strong>电容</strong> <code>C = 0.1uF</code> 组成的 <strong>RC低通滤波器</strong>，其<strong>截止频率</strong> <span class="math inline">\(f_{C}\)</span> 的计算公式如下面所示：</p><p><span class="math display">\[f_{C} = \frac{1}{2 \pi RC} = \frac{1}{2 \pi \times 10000 \times0.0000001} \approx \frac{1}{0.00628} \approx 159.24 Hz\]</span></p><p>接下来绘制出这个 RC 低通滤波器电路，打开 <strong>LTspice</strong>的主界面之后，按下键盘上的快捷键【<strong>Ctrl + N</strong>】，就可以在<code>C:\Users\hank\Documents\LTspice</code> 目录下面新建一个默认名称为<code>Draft1.asc</code> 的仿真原理图文件：</p><p><img src="/Electronics/LTspice/Example/2-AC/1.png"></p><p>完成仿真原理图的绘制之后，鼠标点击 <strong>LTspice</strong>主界面顶部的【ConfigureAnalysis】按钮，或者直接按下快捷键【<strong>A</strong>】，选择【ACAnalysis】<strong>交流分析</strong>选项卡，配置相关的仿真分析参数：</p><p><img src="/Electronics/LTspice/Example/2-AC/2.png"></p><p>鼠标点击 <strong>LTspice</strong>主界面顶部的【Run/Pause】按钮，或者按下快捷键【<strong>Alt +R</strong>】开始运行仿真，紧接着将鼠标移动到 <code>OUT</code>端口查看<strong>输出电压</strong> <span class="math inline">\(V(out)\)</span> 的波形：</p><p><img src="/Electronics/LTspice/Example/2-AC/3.png"></p><p>RC 低通滤波器的<strong>截止频率</strong> <span class="math inline">\(f_C\)</span> 就是增益降低至 <code>-3dB</code>时候的频率，使用<strong>鼠标左键双击</strong>右侧波形预览窗口顶部的<span class="math inline">\(V(out)\)</span>，然后移动光标至<code>-3dB</code> 位置，就可以查看到该位置对应的频率为<code>159.78631Hz</code>，与前面计算的结果相类似：</p><p><img src="/Electronics/LTspice/Example/2-AC/4.png"></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;strong&gt;集成电路仿真程序&lt;/strong&gt;（&lt;strong&gt;SPICE&lt;/strong&gt;，Simulation
Program with Integrated Circuits
Emphasis）是一款以&lt;strong&gt;文本&lt;/strong&gt;进行描述，可以通过&lt;strong&gt;数学&lt;/strong&gt;方法来预测电路行为的仿真工具，也是电子自动化设计与现代半导体工业的基石。其被广泛应用于&lt;strong&gt;模拟电路&lt;/strong&gt;（例如运放算放大器、稳压电源，模数与数模转换等），&lt;strong&gt;混合信号电路&lt;/strong&gt;（锁相环、存储器、高速
GPIO），&lt;strong&gt;精密数字电路&lt;/strong&gt;（延时、时序、功耗、漏电流等）等场景的模拟与仿真（大型电子元器件生产企业通常都提供了元件配套的
&lt;a href=&quot;https://www.ni.com/zh-cn/shop/electronic-test-instrumentation/application-software-for-electronic-test-and-instrumentation-category/what-is-multisim/spice-simulation-fundamentals/spice-simulation-models.html&quot;&gt;SPICE
模型&lt;/a&gt;）。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/Electronics/LTspice/logo.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.analog.com/cn/index.html&quot;&gt;&lt;strong&gt;亚德诺半导体公司&lt;/strong&gt;&lt;/a&gt;（Analog
Devices）推出的 &lt;strong&gt;LTspice&lt;/strong&gt;
是一款界面简洁，但是功能强大的免费 &lt;strong&gt;SPICE&lt;/strong&gt;
电路仿真工具，其可以基于原理图快速准确的生成仿真结果，并且将这些结果通过内置的波形查看器进行展示，除此之外还内置有丰富的
SPICE 模型（包含有基本的&lt;strong&gt;无源元件&lt;/strong&gt;以及 ADI
公司的&lt;code&gt;电源管理&lt;/code&gt;和&lt;code&gt;信号链&lt;/code&gt;产品），可以预先为模拟电路的设计以及元器件的选型提供重要的实验数据参考，从而降低电路设计过程当中产生的各种试错成本，有效的提高设计工作效率。&lt;/p&gt;</summary>
    
    
    
    <category term="硬件电子技术" scheme="http://www.uinio.com/categories/%E7%A1%AC%E4%BB%B6%E7%94%B5%E5%AD%90%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="仿真" scheme="http://www.uinio.com/tags/%E4%BB%BF%E7%9C%9F/"/>
    
  </entry>
  
  <entry>
    <title>基于 Polar Si9000e 计算传输线特征阻抗的全攻略</title>
    <link href="http://www.uinio.com/Electronics/SI9000/"/>
    <id>http://www.uinio.com/Electronics/SI9000/</id>
    <published>2024-04-04T16:00:00.000Z</published>
    <updated>2025-06-25T14:52:27.473Z</updated>
    
    <content type="html"><![CDATA[<p>伴随近几年集成电路制程工艺的进步，PCB传输线上信号的频率逐年提高，非常容易导致信号在传输过程当中，由于受到传输线的阻力而出现<strong>插损</strong>（插入损耗，单位为<strong>分贝</strong>），这种信号在传输过程中受到的阻力被称为<strong>特性阻抗</strong>或者<strong>特征阻抗</strong>。换而言之，如果信号在传输过程当中，传输路径上的<strong>特征阻抗</strong>发生了变化，信号就会在<code>阻抗不连续</code>的结点发生<strong>反射</strong>。因而PCB上的传输线仅仅只解决<strong>通</strong>和<strong>断</strong>的问题还远远不够，还需要进一步确保其传输链路上特性阻抗的匹配和连续。</p><p><img src="/Electronics/SI9000/logo.png"></p><p><strong>英国宝拉</strong> <a href="https://www.polarinstruments.com/index.html"><strong>POLAR</strong></a>公司推出的 <a href="https://www.polarinstruments.com/products/si/Si9000.html"><strong>Si9000e</strong></a>，正是一款这样可以预测PCB走线阻抗的计算工具，该工具已经成为高速电路设计当中，必不可少的辅助工具。该工具提取了100 余种 PCB传输线的典型结构，并且基于这些结构对指定频率下的传输线阻抗进行建模计算。<strong>Si9000e</strong>将影响 PCB传输线阻抗的主要因素：<code>板材厚度</code>、<code>顶层走线宽度</code>、<code>铜泊厚度</code>、<code>走线周围的包地间距</code>、<code>表面绿油的厚度</code>作为输入参数，就可以计算出<strong>表面单端/差分</strong>和<strong>共面单端/差分</strong>类型走线的阻抗。</p><span id="more"></span><h1 id="英文词汇准备">英文词汇准备</h1><p>由于 <strong>Si9000e 传输线场求解器</strong>（Si9000e TransmissionLine FieldSolver）采用的是全英文界面，因而在开始正式的内容之前，需要将软件界面高频出现的专业英文词汇，整理在下面的表格当中：</p><table><colgroup><col style="width: 53%"><col style="width: 46%"></colgroup><thead><tr><th style="text-align: left;">Si9000e 界面英文词汇</th><th style="text-align: left;">Si9000e 界面英文词汇</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>Stripline</strong> [ˈstrɪplaɪn]n.带状线，电介质条状线</td><td style="text-align: left;"><strong>Coplanar</strong> [kəʊˈpleɪnə(r)]adj.共面的</td></tr><tr><td style="text-align: left;"><strong>Microstrip</strong>[ˈmaɪkrəʊstrɪp] n.微带线，微波传输带</td><td style="text-align: left;"><strong>Coated</strong> [ˈkəʊtɪd] adj.覆盖有阻焊油墨的</td></tr><tr><td style="text-align: left;"><strong>Waveguide</strong> [ˈweɪvˌɡaɪd]n.波导</td><td style="text-align: left;"><strong>Coarse</strong> [kɔːs] adj.粗略的</td></tr><tr><td style="text-align: left;"><strong>Substrate</strong> [ˈsʌbstreɪt]n.基层</td><td style="text-align: left;"><strong>Single-End</strong> [ˈsɪŋɡl end]adj.单端的</td></tr><tr><td style="text-align: left;"><strong>Dielectric</strong>[ˌdaɪɪˈlektrɪk] n.电介质</td><td style="text-align: left;"><strong>Differential</strong>[ˌdɪfəˈrenʃ(ə)l] adj.差分的</td></tr><tr><td style="text-align: left;"><strong>Thickness</strong> [ˈθɪknəs]n.厚度</td><td style="text-align: left;"><strong>Separation</strong> [ˌsepəˈreɪʃn]n.隔离</td></tr><tr><td style="text-align: left;"><strong>Cutout</strong> [ˈkʌtaʊt]n.分割</td><td style="text-align: left;"><strong>Lossless</strong> [ˈlɒsləs]adj.无损的</td></tr><tr><td style="text-align: left;"><strong>Tolerance</strong> [ˈtɒlərəns]n.公差</td><td style="text-align: left;"><strong>Trace</strong> [treɪs] n. PCB上的铜质走线</td></tr></tbody></table><blockquote><p><strong>注意</strong>：本文后续内容会将 <strong>Si9000e</strong>直接简写为 <strong>Si9000</strong>。</p></blockquote><h1 id="微带线-带状线">微带线 &amp; 带状线</h1><p>PCB 电路网络当中的信号走线，可以划分为<strong>微带线</strong>（Microstrip）和<strong>带状线</strong>（Stripline）两种主要类型：</p><p><img src="/Electronics/SI9000/Stripline-Microstrip.png"></p><ul><li><strong>微带线</strong>（Microstrip）：即 PCB表面的带状走线，由于一面裸露在空气中，可以向周围形成辐射或受到周围的辐射干扰，而另一面附着在PCB 绝缘电介质上，所以其形成的电场一部分分布在空气中，另一部分分布在 PCB的绝缘介质里，其信号传输速率高于<strong>带状线</strong>。</li><li><strong>带状线</strong>（Stripline）：即 PCB内层的带状走线，由于嵌在两层导体之间，所以其电场分布在两层导体所形成的平面之间，能量不会被辐射出去，也不会受到外部辐射的干扰。由于其周围分布的是介电常数大于<code>1</code>的电介质，所以信号传输速率要慢于<strong>微带线</strong>。</li></ul><p>无论是微带线还是带状线，在 PCB当中这些走线的单位通常会采用<strong>密尔</strong><code>mil</code>，其与公制<strong>毫米</strong> <code>mm</code>的换算关系如下面等式所示：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">1</span> 密耳(mil) = <span class="number">0.0254</span> 毫米(mm)</span><br></pre></td></tr></table></figure><h1 id="共面单端-共面波导">共面单端 &amp; 共面波导</h1><p>传输线理论当中的<strong>共面波导</strong>（下图左）与<strong>共面单端</strong>（下图右）两种走线模型，是非常容易混淆的两个概念：</p><p><img src="/Electronics/SI9000/Waveguide-Single-Ended.png"></p><ul><li><strong>共面波导</strong>（CPW，CoplanarWaveguide）是指在介质平面上制作出中心导体带，并在紧邻中心导体带的两侧制作出<strong>导体平面</strong>，这样就构成了共面波导，其本质上属于一种<strong>共面微带传输线</strong>（上图左）。</li><li><strong>共面单端</strong>（CoplanarSingle-Ended）走线的概念类似于共面波导，不同之处在于其中心导体带两侧是<strong>指定宽度的接地走线</strong>，而非一个完整的地平面（上图右）。</li></ul><blockquote><p><strong>注意</strong>：当采用 <strong>Si9000</strong>计算阻抗的时候，由于<strong>共面单端</strong>需要输入的计算参数更多。因此，在没有特别严格要求的情况下，可以直接使用<strong>共面波导</strong>作为阻抗计算的模型，同样参数情况下两者的计算结果差异非常细微。</p></blockquote><h1 id="常用-pcb-叠层结构">常用 PCB 叠层结构</h1><p>实际的 PCB 设计工作当中，在完成元件的布局摆放之后，会首先对 PCB布线的瓶颈位置进行分析，根据敏感信号线的种类和数量来确定<strong>信号层</strong>的层数。然后再根据电源的性能参数要求，来确定<strong>内电层</strong>的层数。从而最终确定整个PCB 的<strong>叠层设计方案</strong>。下面的表格对比了 3 种常见<strong>四层 PCB 叠层方案</strong> 的优缺点（通常会优先选择第<code>2</code> 和第 <code>3</code> 号叠层方案）：</p><p><img src="/Electronics/SI9000/Level-4.png"></p><p>而在接下来的表格里，则是对比了 4 种常见 <strong>六层 PCB叠层方案</strong> 的优缺点（通常会优先选择第 <code>3</code> 和第<code>4</code> 号叠层方案）：</p><p><img src="/Electronics/SI9000/Level-6.png"></p><h1 id="si9000-主界面介绍">Si9000 主界面介绍</h1><p><strong>Si9000</strong>软件的主界面可以被划分为【功能选择标签】、【模型选择区域】、【参数输入与计算区域】、【单位切换区域】四个区域：</p><p><img src="/Electronics/SI9000/UI.png"></p><ol type="1"><li>【功能选择标签】：在计算 PCB特征阻抗的时候，需要将切换至<strong>无损计算</strong>（LosslessCalculation）标签。</li><li>【模型选择区域】主要用于选择 PCB典型层叠结构与走线方式的<strong>特征阻抗模型</strong>。</li><li>【单位切换区域】用于在<strong>米尔</strong>（<code>Mils</code>）、<strong>英寸</strong>（<code>Inches</code>）、<strong>微米</strong>（<code>Microns</code>）、<strong>毫米</strong>（<code>Millimetres</code>）计算单位之间进行切换。</li><li>【参数输入与计算区域】用于输入 PCB各种基材、铜层、阻焊油墨、走线的参数信息，并且利用这些信息计算出相应的特征阻抗。</li></ol><blockquote><p><strong>注意</strong>：勾选软件底部的【AutoCalc】可以开启自动计算功能，即当参数输入区域发生变化的时候，<strong>Si9000</strong>就会自动计算出对应的特征阻抗结果。</p></blockquote><h1 id="常见的阻抗模型">常见的阻抗模型</h1><p>现代传输线理论认为，信号在传输过程当中，特征阻抗的不连续会造成反射现象。而在信号完整性领域，<code>反射</code>、<code>串扰</code>、<code>参考平面分割</code>都会导致阻抗的不连续问题，因而传输线特征阻抗的匹配显得尤为重要。在下面的列表里，对高速电路设计当中存在的一些概念进行了解释：</p><ul><li><strong>时延</strong>：高速信号从电路网络的一端传送至另一端所需的时间。</li><li><strong>串扰</strong>：信号线之间的<strong>互感</strong>与<strong>互容</strong>所引发的噪声。</li><li><strong>反射</strong>：在传输线上阻抗不连续的位置，一部分信号会继续向前传输，另外一部分则会被反射形成回波。</li><li><strong>振铃</strong>：由于传输线的阻抗不匹配，导致信号被多次反射叠加之后，所出现的振荡波形。</li></ul><p>常见的阻抗计算模型可以划分为<strong>内层</strong>或者<strong>外层</strong>的<code>单端</code>、<code>差分</code>、<code>共面单端</code>、<code>共面波导</code>、<code>差分共面地</code>、<code>差分共面波导</code>一共 12 种模型：</p><table><colgroup><col style="width: 49%"><col style="width: 50%"></colgroup><thead><tr><th style="text-align: center;"><strong>外层单端</strong></th><th style="text-align: center;"><strong>内层单端</strong></th></tr></thead><tbody><tr><td style="text-align: center;"><img src="/Electronics/SI9000/Impedance-Model-1.png"></td><td style="text-align: center;"><img src="/Electronics/SI9000/Impedance-Model-7.png"></td></tr><tr><td style="text-align: center;"><strong>外层差分</strong></td><td style="text-align: center;"><strong>内层差分</strong></td></tr><tr><td style="text-align: center;"><img src="/Electronics/SI9000/Impedance-Model-2.png"></td><td style="text-align: center;"><img src="/Electronics/SI9000/Impedance-Model-8.png"></td></tr><tr><td style="text-align: center;"><strong>外层共面单端</strong></td><td style="text-align: center;"><strong>内层共面单端</strong></td></tr><tr><td style="text-align: center;"><img src="/Electronics/SI9000/Impedance-Model-3.png"></td><td style="text-align: center;"><img src="/Electronics/SI9000/Impedance-Model-9.png"></td></tr><tr><td style="text-align: center;"><strong>外层共面波导</strong></td><td style="text-align: center;"><strong>内层共面波导</strong></td></tr><tr><td style="text-align: center;"><img src="/Electronics/SI9000/Impedance-Model-4.png"></td><td style="text-align: center;"><img src="/Electronics/SI9000/Impedance-Model-10.png"></td></tr><tr><td style="text-align: center;"><strong>外层差分共面地</strong></td><td style="text-align: center;"><strong>内层差分共面地</strong></td></tr><tr><td style="text-align: center;"><img src="/Electronics/SI9000/Impedance-Model-5.png"></td><td style="text-align: center;"><img src="/Electronics/SI9000/Impedance-Model-11.png"></td></tr><tr><td style="text-align: center;"><strong>外层差分共面波导</strong></td><td style="text-align: center;"><strong>内层差分共面波导</strong></td></tr><tr><td style="text-align: center;"><img src="/Electronics/SI9000/Impedance-Model-6.png"></td><td style="text-align: center;"><img src="/Electronics/SI9000/Impedance-Model-12.png"></td></tr></tbody></table><p>影响上述模型当中<strong>特征阻抗</strong>的因素有<code>基材厚度</code>、<code>介电常数</code>、<code>铜层厚度</code>、<code>线宽</code>、<code>线距</code>、<code>阻焊油墨厚度</code>等，具体请参考下面的表格：</p><table><colgroup><col style="width: 8%"><col style="width: 30%"><col style="width: 61%"></colgroup><thead><tr><th style="text-align: center;">缩写</th><th style="text-align: left;">英文名称</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>H1</strong></td><td style="text-align: left;"><code>Substrate 1 Height</code></td><td style="text-align: left;">第 1层基材的<strong>厚度</strong>（不包含铜厚）；</td></tr><tr><td style="text-align: center;"><strong>H2</strong></td><td style="text-align: left;"><code>Substrate 2 Height</code></td><td style="text-align: left;">第 2层基材的<strong>厚度</strong>（不包含铜厚）；</td></tr><tr><td style="text-align: center;"><strong>Er1</strong></td><td style="text-align: left;"><code>Substrate 1 Dielectric</code></td><td style="text-align: left;">第 1层基材的<strong>介电常数</strong>（多种基材压合时取平均值）；</td></tr><tr><td style="text-align: center;"><strong>Er2</strong></td><td style="text-align: left;"><code>Substrate 2 Dielectric</code></td><td style="text-align: left;">第 2层基材的<strong>介电常数</strong>（多种基材压合时取平均值）；</td></tr><tr><td style="text-align: center;"><strong>W1</strong></td><td style="text-align: left;"><code>Lower Trace Width</code></td><td style="text-align: left;">阻抗走线的<strong>下线宽</strong>；</td></tr><tr><td style="text-align: center;"><strong>W2</strong></td><td style="text-align: left;"><code>Upper Trace Width</code></td><td style="text-align: left;">阻抗走线的<strong>上线宽</strong>；</td></tr><tr><td style="text-align: center;"><strong>G1</strong></td><td style="text-align: left;"><code>Lower Ground Strip Width</code></td><td style="text-align: left;">接地走线的<strong>上线宽</strong>。</td></tr><tr><td style="text-align: center;"><strong>G2</strong></td><td style="text-align: left;"><code>Upper Ground Strip Width</code></td><td style="text-align: left;">接地走线的<strong>下线宽</strong>。</td></tr><tr><td style="text-align: center;"><strong>D1</strong></td><td style="text-align: left;"><code>Ground Strip Separation</code></td><td style="text-align: left;">接地走线的<strong>间隔距离</strong>；</td></tr><tr><td style="text-align: center;"><strong>T1</strong></td><td style="text-align: left;"><code>Trace Thickness</code></td><td style="text-align: left;">走线的<strong>铜层厚度</strong>；</td></tr><tr><td style="text-align: center;"><strong>C1</strong></td><td style="text-align: left;"><code>Coating Above Substrate</code></td><td style="text-align: left;">基材的<strong>阻焊油墨厚度</strong>；</td></tr><tr><td style="text-align: center;"><strong>C2</strong></td><td style="text-align: left;"><code>Coating Above Trace</code></td><td style="text-align: left;">铜皮或者走线的<strong>阻焊油墨厚度</strong>；</td></tr><tr><td style="text-align: center;"><strong>C3</strong></td><td style="text-align: left;"><code>Coating Between Traces</code></td><td style="text-align: left;">铜层走线间隙的<strong>阻焊油墨厚度</strong>；</td></tr><tr><td style="text-align: center;"><strong>CEr</strong></td><td style="text-align: left;"><code>Coating Dielectric</code></td><td style="text-align: left;">阻焊油墨的<strong>介电常数</strong>；</td></tr></tbody></table><blockquote><p><strong>注意</strong>：<strong>残铜率</strong>是指板 PCB上面<code>覆铜面积</code>与<code>整板面积</code>之比，例如未经加工的覆铜芯板的残铜率为<code>100%</code>，而将表面铜层全部被蚀刻掉之后残铜率就变为<code>0%</code>。</p></blockquote><h1 id="导线的上下线宽换算关系">导线的上/下线宽换算关系</h1><p>目前的 PCB蚀刻制造工艺，会导致铜层走线出现<strong>上窄下宽</strong>的情况，形成类似下图这样的梯形截面走线：</p><p><img src="/Electronics/SI9000/Trapezoid.png"></p><p>接下来的表格展现了不同基础铜厚情况下，铜层走线的 <span class="math inline">\(W_{上/下线宽}\)</span> 以及 <span class="math inline">\(D_{线距}\)</span>，与 <span class="math inline">\(W_{设计线宽}\)</span> 和 <span class="math inline">\(D_{设计线距}\)</span>之间的换算关系（如果不需要精确的计算，那么可以默认 <span class="math inline">\(W_{上线宽}\)</span> 比 <span class="math inline">\(W_{下线宽}\)</span> 要窄约<code>1mil</code>，具体参数建议咨询 PCB 生产厂家）：</p><table><colgroup><col style="width: 25%"><col style="width: 25%"><col style="width: 25%"><col style="width: 25%"></colgroup><thead><tr><th style="text-align: center;">基础铜厚</th><th style="text-align: center;">上线宽 <span class="math inline">\(W_{上线宽}\)</span></th><th style="text-align: center;">下线宽 <span class="math inline">\(W_{下线宽}\)</span></th><th style="text-align: center;">线距 <span class="math inline">\(D_{线距}\)</span></th></tr></thead><tbody><tr><td style="text-align: center;"><strong>18μm</strong>（内层）</td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}- 0.1 mil\)</span></td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}\)</span></td><td style="text-align: center;"><span class="math inline">\(D_{设计线距}\)</span></td></tr><tr><td style="text-align: center;"><strong>35μm</strong>（内层）</td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}- 0.4 mil\)</span></td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}\)</span></td><td style="text-align: center;"><span class="math inline">\(D_{设计线距}\)</span></td></tr><tr><td style="text-align: center;"><strong>70μm</strong>（内层）</td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}- 1.2 mil\)</span></td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}\)</span></td><td style="text-align: center;"><span class="math inline">\(D_{设计线距}\)</span></td></tr><tr><td style="text-align: center;"><strong>42μm</strong>（负片层）</td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}- 0.4 mil\)</span></td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}+ 0.4 mil\)</span></td><td style="text-align: center;"><span class="math inline">\(D_{设计线距}- 0.4 mil\)</span></td></tr><tr><td style="text-align: center;"><strong>48μm</strong>（负片层）</td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}- 0.5 mil\)</span></td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}+ 0.5 mil\)</span></td><td style="text-align: center;"><span class="math inline">\(D_{设计线距}- 0.5 mil\)</span></td></tr><tr><td style="text-align: center;"><strong>65μm</strong>（负片层）</td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}- 0.8 mil\)</span></td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}+ 0.8 mil\)</span></td><td style="text-align: center;"><span class="math inline">\(D_{设计线距}- 0.8 mil\)</span></td></tr><tr><td style="text-align: center;"><strong>12μm</strong>（外层）</td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}- 0.6 mil\)</span></td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}+ 0.6 mil\)</span></td><td style="text-align: center;"><span class="math inline">\(D_{设计线距}- 0.6 mil\)</span></td></tr><tr><td style="text-align: center;"><strong>18μm</strong>（外层）</td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}- 0.6 mil\)</span></td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}+ 0.7 mil\)</span></td><td style="text-align: center;"><span class="math inline">\(D_{设计线距}- 0.7 mil\)</span></td></tr><tr><td style="text-align: center;"><strong>35μm</strong>（外层）</td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}- 0.9 mil\)</span></td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}+ 0.9 mil\)</span></td><td style="text-align: center;"><span class="math inline">\(D_{设计线距}- 0.9 mil\)</span></td></tr><tr><td style="text-align: center;"><strong>12μm</strong>（镀金工艺外层）</td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}- 1.2 mil\)</span></td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}\)</span></td><td style="text-align: center;"><span class="math inline">\(D_{设计线距}\)</span></td></tr><tr><td style="text-align: center;"><strong>18μm</strong>（镀金工艺外层）</td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}- 1.2 mil\)</span></td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}\)</span></td><td style="text-align: center;"><span class="math inline">\(D_{设计线距}\)</span></td></tr><tr><td style="text-align: center;"><strong>35μm</strong>（镀金工艺外层）</td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}- 2.0 mil\)</span></td><td style="text-align: center;"><span class="math inline">\(W_{设计线宽}\)</span></td><td style="text-align: center;"><span class="math inline">\(D_{设计线距}\)</span></td></tr></tbody></table><blockquote><p><strong>注意</strong>：<strong>信号层</strong>主要用于走线，通常采用<strong>正片</strong>方式处理；而<strong>电源层</strong>和<strong>接地层</strong>通常采用<strong>负片</strong>方式处理，这样只需指定无需铺铜的位置即可，可以较大程度降低EDA 工具的数据处理量。</p></blockquote><h1 id="芯板与半固化片">芯板与半固化片</h1><p>多层 PCB 都是由 <code>FR-4</code> 材料的<strong>覆铜芯板</strong>（Core）与具有粘结功能的<strong>半固化片</strong>（PP，Prepreg [priːpreɡ]）热压合而成，当使用<strong>Si9000</strong> 计算带有叠层结构的 PCB特性阻抗时，纳入计算的板材厚度应当由两者共同叠加而成，下图清晰的展示了覆铜芯板与半固化片之间的这种叠加关系：</p><p><img src="/Electronics/SI9000/PCB-Structure.png"></p><h2 id="芯板的介电常数">芯板的介电常数</h2><p>普通 FR-4 材料的<strong>覆铜芯板</strong>（Core），主要有南亚、建滔、生益、宏瑞等板材生产厂家，下面两个表格展示了<strong>Tg≤ 170</strong> 型与 <strong>IT180A S1000-2</strong> 型的 <strong>生益FR-4 芯板</strong>，在各种厚度下所对应的<strong>介电常数</strong>：</p><table><colgroup><col style="width: 18%"><col style="width: 10%"><col style="width: 12%"><col style="width: 10%"><col style="width: 12%"><col style="width: 11%"><col style="width: 11%"><col style="width: 11%"></colgroup><thead><tr><th style="text-align: center;">生益 FR-4 芯板厚度</th><th style="text-align: center;">0.051mm/2mil</th><th style="text-align: center;">0.075mm/3.0mil</th><th style="text-align: center;">0.102mm/4mil</th><th style="text-align: center;">0.11mm/4.33mil</th><th style="text-align: center;">0.13mm/5.1mil</th><th style="text-align: center;">0.15mm/5.9mil</th><th style="text-align: center;">0.18mm/7.0mil</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>Tg ≤ 170</strong> 型</td><td style="text-align: center;">3.6</td><td style="text-align: center;">3.65</td><td style="text-align: center;">3.95</td><td style="text-align: center;">无此规格</td><td style="text-align: center;">3.95</td><td style="text-align: center;">3.65</td><td style="text-align: center;">4.2</td></tr><tr><td style="text-align: center;"><strong>IT180A S1000-2</strong> 型</td><td style="text-align: center;">3.9</td><td style="text-align: center;">3.95</td><td style="text-align: center;">4.25</td><td style="text-align: center;">4</td><td style="text-align: center;">4.25</td><td style="text-align: center;">4.25</td><td style="text-align: center;">4.5</td></tr></tbody></table><table><colgroup><col style="width: 21%"><col style="width: 14%"><col style="width: 12%"><col style="width: 14%"><col style="width: 12%"><col style="width: 12%"><col style="width: 15%"></colgroup><thead><tr><th style="text-align: center;">生益 FR-4 芯板厚度</th><th style="text-align: center;">0.21mm/8.27mil</th><th style="text-align: center;">0.25mm/10mil</th><th style="text-align: center;">0.36mm/14.5mil</th><th style="text-align: center;">0.51mm/20mil</th><th style="text-align: center;">0.71mm/28mil</th><th style="text-align: center;">≥0.8mm/≥31.5mil</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>Tg ≤ 170</strong> 型</td><td style="text-align: center;">3.95</td><td style="text-align: center;">3.95</td><td style="text-align: center;">4.2</td><td style="text-align: center;">4.1</td><td style="text-align: center;">4.2</td><td style="text-align: center;">4.2</td></tr><tr><td style="text-align: center;"><strong>IT180A S1000-2</strong> 型</td><td style="text-align: center;">4.25</td><td style="text-align: center;">4.25</td><td style="text-align: center;">4.5</td><td style="text-align: center;">4.4</td><td style="text-align: center;">4.5</td><td style="text-align: center;">4.5</td></tr></tbody></table><h2 id="半固化片的介电常数">半固化片的介电常数</h2><p><strong>半固化片</strong>（PP）比较有名的厂家是罗杰斯（Rogers），主要有<code>106</code>、<code>1080</code>、<code>3313</code>、<code>2116</code>、<code>7628</code>等规格，下面的这个表格展示了 <strong>Tg ≤ 170</strong> 型与<strong>IT180A S1000-2</strong>型半固化片，在各种规格下所对应的介电常数：</p><table style="width:100%;"><colgroup><col style="width: 45%"><col style="width: 9%"><col style="width: 11%"><col style="width: 11%"><col style="width: 11%"><col style="width: 11%"></colgroup><thead><tr><th style="text-align: center;">Tg≤170 半固化片规格</th><th style="text-align: center;">106</th><th style="text-align: center;">1080</th><th style="text-align: center;">3313</th><th style="text-align: center;">2116</th><th style="text-align: center;">7628</th></tr></thead><tbody><tr><td style="text-align: center;">理论厚度 (mm)</td><td style="text-align: center;">0.0513</td><td style="text-align: center;">0.0773</td><td style="text-align: center;">0.1034</td><td style="text-align: center;">0.1185</td><td style="text-align: center;">0.1951</td></tr><tr><td style="text-align: center;">介电常数</td><td style="text-align: center;">3.6</td><td style="text-align: center;">3.65</td><td style="text-align: center;">3.85</td><td style="text-align: center;">3.95</td><td style="text-align: center;">4.2</td></tr><tr><td style="text-align: center;"><strong>IT180A S1000-2B半固化片规格</strong></td><td style="text-align: center;"><strong>106</strong></td><td style="text-align: center;"><strong>1080</strong></td><td style="text-align: center;"><strong>3313</strong></td><td style="text-align: center;"><strong>2116</strong></td><td style="text-align: center;"><strong>7628</strong></td></tr><tr><td style="text-align: center;">理论厚度 (mm)</td><td style="text-align: center;">0.0511</td><td style="text-align: center;">0.07727</td><td style="text-align: center;">0.0987</td><td style="text-align: center;">0.1174</td><td style="text-align: center;">0.1933</td></tr><tr><td style="text-align: center;">介电常数</td><td style="text-align: center;">3.9</td><td style="text-align: center;">3.95</td><td style="text-align: center;">4.15</td><td style="text-align: center;">4.25</td><td style="text-align: center;">4.5</td></tr></tbody></table><h1 id="si9000-阻抗计算实例">Si9000 阻抗计算实例</h1><p>在高速电路设计过程当中，通常情况下<strong>DDR</strong>、<strong>eMMC</strong>、<strong>SDIO</strong>等单端信号会要求 <code>50Ω</code> 阻抗（可以将其设置为 EDA工具走线的默认线宽）。而 <strong>HDMI</strong>、<strong>DDR</strong>时钟 等差分信号则会要求 <code>100Ω</code> 阻抗，除此之外<strong>USB</strong> 差分线则会要求 <code>90Ω</code> 阻抗。</p><p>为了匹配这些各不相同的特征阻抗需求，需要基于 <strong>Si9000</strong>对走线的各种参数进行计算，从而获得合理的走线<strong>宽度</strong>与<strong>距离</strong>。由于使用<strong>Si9000</strong>进行<strong>无损计算</strong>的时候，所采用的参数与 PCB生产厂家所使用的材料以及工艺密切相关，因而必须遵循厂家提供的相关参数，确保阻抗计算结果的准确性。这里的表格，展示的是某工厂最新使用的<strong>半固化片</strong>规格与其介电常数：</p><table><thead><tr><th style="text-align: center;">半固化片规格</th><th style="text-align: center;">7628</th><th style="text-align: center;">2216</th><th style="text-align: center;">3313</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>介电常数</strong></td><td style="text-align: center;"><code>4.4</code></td><td style="text-align: center;"><code>4.16</code></td><td style="text-align: center;"><code>4.1</code></td></tr></tbody></table><p>而接下来的表格，则展示了该工厂所使用<strong>阻焊油墨</strong>的厚度以及介电常数：</p><table><thead><tr><th style="text-align: center;">基材上的油墨厚度</th><th style="text-align: center;">导线上的油墨厚度</th><th style="text-align: center;">阻焊油墨介电常数</th></tr></thead><tbody><tr><td style="text-align: center;"><code>0.8mil</code></td><td style="text-align: center;"><code>0.5mil</code></td><td style="text-align: center;"><code>3.8</code></td></tr></tbody></table><blockquote><p><strong>注意</strong>：<strong>盎司</strong> <code>oz</code>原本是一个用于表示重量的单位 <code>1oz = 28.350g</code>，在 PCB设计当中通常将其用于描述铜层的厚度，<code>1OZ</code> 铜层对应的厚度约为<code>0.035mm</code>。</p></blockquote><h2 id="四层层叠方案-jlc04161h-7628">四层层叠方案 JLC04161H-7628</h2><p>以某 PCB 生产厂家所提供的 <code>JLC04161H-7628</code> 型四层 PCB叠层方案为例（PCB 成品厚度 <code>1.59mm</code>，内层铜厚<code>0.5oz</code>，外层铜厚 <code>1oz</code>）：</p><p><img src="/Electronics/SI9000/JLC04161H-7628.png"></p><p>下图是使用 <strong>Si9000</strong> 计算 <code>50Ω</code>欧姆<strong>外层单端</strong>阻抗走线的结果（即上下线宽度分别为<code>14.1614/13.1614mil</code> 或者<code>0.35970/0.33430mm</code>）：</p><p><img src="/Electronics/SI9000/JLC04161H-7628-1.png"></p><h2 id="四层层叠方案-jlc04161h-3313">四层层叠方案 JLC04161H-3313</h2><p>以某 PCB 生产厂家所提供的 <code>JLC04161H-3313</code> 型四层 PCB叠层方案为例（PCB 成品厚度 <code>1.56mm</code>，内层铜厚<code>0.5oz</code>，外层铜厚 <code>1oz</code>）：</p><p><img src="/Electronics/SI9000/JLC04161H-3313.png"></p><p>下图是使用 <strong>Si9000</strong> 计算 <code>100Ω</code>欧姆<strong>外层差分共面</strong>阻抗走线的结果（即上下线宽度分别为<code>5.1623/4.1623mil</code> 或者<code>0.13112/0.10572mm</code>）：</p><p><img src="/Electronics/SI9000/JLC04161H-3313-1.png"></p><h2 id="六层层叠方案-jlc06161h-3313">六层层叠方案 JLC06161H-3313</h2><p>以某 PCB 生产厂家所提供的 <code>JLC06161H-3313</code> 型六层 PCB叠层方案为例（上下线宽度分别为 <code>1.6mm</code>，内层铜厚<code>0.5oz</code>，外层铜厚 <code>1oz</code>）：</p><p><img src="/Electronics/SI9000/JLC06161H-3313.png"></p><p>下图是使用 <strong>Si9000</strong> 计算 <code>90Ω</code>欧姆<strong>内层差分共面</strong>阻抗走线的结果（即上下线宽度分别为<code>4.9260/3.9260mil</code> 或者<code>0.12512/0.09972mm</code>）：</p><p><img src="/Electronics/SI9000/JLC06161H-3313-1.png"></p>]]></content>
    
    
    <summary type="html">&lt;p&gt;伴随近几年集成电路制程工艺的进步，PCB
传输线上信号的频率逐年提高，非常容易导致信号在传输过程当中，由于受到传输线的阻力而出现&lt;strong&gt;插损&lt;/strong&gt;（插入损耗，单位为&lt;strong&gt;分贝&lt;/strong&gt;），这种信号在传输过程中受到的阻力被称为&lt;strong&gt;特性阻抗&lt;/strong&gt;或者&lt;strong&gt;特征阻抗&lt;/strong&gt;。换而言之，如果信号在传输过程当中，传输路径上的&lt;strong&gt;特征阻抗&lt;/strong&gt;发生了变化，信号就会在&lt;code&gt;阻抗不连续&lt;/code&gt;的结点发生&lt;strong&gt;反射&lt;/strong&gt;。因而
PCB
上的传输线仅仅只解决&lt;strong&gt;通&lt;/strong&gt;和&lt;strong&gt;断&lt;/strong&gt;的问题还远远不够，还需要进一步确保其传输链路上特性阻抗的匹配和连续。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/Electronics/SI9000/logo.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;英国宝拉&lt;/strong&gt; &lt;a href=&quot;https://www.polarinstruments.com/index.html&quot;&gt;&lt;strong&gt;POLAR&lt;/strong&gt;&lt;/a&gt;
公司推出的 &lt;a href=&quot;https://www.polarinstruments.com/products/si/Si9000.html&quot;&gt;&lt;strong&gt;Si9000e&lt;/strong&gt;&lt;/a&gt;，正是一款这样可以预测
PCB
走线阻抗的计算工具，该工具已经成为高速电路设计当中，必不可少的辅助工具。该工具提取了
100 余种 PCB
传输线的典型结构，并且基于这些结构对指定频率下的传输线阻抗进行建模计算。&lt;strong&gt;Si9000e&lt;/strong&gt;
将影响 PCB
传输线阻抗的主要因素：&lt;code&gt;板材厚度&lt;/code&gt;、&lt;code&gt;顶层走线宽度&lt;/code&gt;、&lt;code&gt;铜泊厚度&lt;/code&gt;、&lt;code&gt;走线周围的包地间距&lt;/code&gt;、&lt;code&gt;表面绿油的厚度&lt;/code&gt;
作为输入参数，就可以计算出&lt;strong&gt;表面单端/差分&lt;/strong&gt;和&lt;strong&gt;共面单端/差分&lt;/strong&gt;类型走线的阻抗。&lt;/p&gt;</summary>
    
    
    
    <category term="硬件电子技术" scheme="http://www.uinio.com/categories/%E7%A1%AC%E4%BB%B6%E7%94%B5%E5%AD%90%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="PCB" scheme="http://www.uinio.com/tags/PCB/"/>
    
  </entry>
  
  <entry>
    <title>电路设计 の 常用分立元器件选型大全</title>
    <link href="http://www.uinio.com/Electronics/Element/"/>
    <id>http://www.uinio.com/Electronics/Element/</id>
    <published>2024-03-30T16:00:00.000Z</published>
    <updated>2026-02-10T17:47:51.417Z</updated>
    
    <content type="html"><![CDATA[<p>自从 <strong>1883</strong>年电子管作为人类第一个电子元器件诞生以来，<strong>电子元器件</strong>的发展历程，见证了人类科技进步的辉煌成就。从最初的<code>电阻</code>、<code>电容</code>、<code>电感</code>等基础元器件，发展到<code>晶闸管</code>、<code>场效应管</code>、<code>IGBT</code>等半导体元器件，再进一步发展到现如今各种琳琅满目的<strong>微处理器</strong>、<strong>微控制器</strong>、<strong>传感器</strong>。电子元器件的功能越来越强大，体积越来越小，集成度越来越高。这些变化不仅极大地提升了电子产品的性能和可靠性，也为我们带来了更加便捷与智能的生活方式。</p><p><img src="/Electronics/Element/logo.png"></p><p>电子元器件如同电子设备的细胞，承载着实现各种复杂功能的基础任务，它们是电路设计和调试中不可或缺的元素。实际的电路设计过程当中，各类电子元器件的选择、连接、调试都至关重要，正确的选型能够确保设备的性能和稳定性，而合理的连接方式更是能够降低信号的损失与干扰。本文旨在以简单明了的方式介绍<code>电阻器</code>、<code>电容器</code>、<code>电感器</code>、<code>变压器</code>、<code>二极管</code>、<code>三极管</code>、<code>晶闸管</code>、<code>场效应管</code>、<code>IGBT</code>等常用分立式电子元器件的参数与选型注意事项。</p><span id="more"></span><h1 id="知识准备-basic">知识准备 Basic</h1><h2 id="电流">电流</h2><p><strong>电荷</strong>的定向移动形成<strong>电流</strong>，电流通常使用字母<code>I</code> 表示，其单位为 <code>A</code><strong>安培</strong>，更小的单位有<strong>毫安</strong>(<code>mA</code>)和<strong>微安</strong>(<code>μA</code>)，它们之间的换算关系为：</p><p><span class="math display">\[1A = 10^3mA = 10^6 \mu A\]</span></p><blockquote><p><strong>注意</strong>：习惯上约定将<strong>电荷</strong>（电子带有<strong>负电</strong>）运动的<strong>反方向</strong>作为电流的方向，即将<strong>正电荷</strong>在电路当中的移动方向规定为电流的方向，也就是从正极流向负极。</p></blockquote><h2 id="电阻">电阻</h2><p><strong>导体</strong>对电流的阻碍作用称为<strong>电阻</strong>，通常使用字母<code>R</code> 进行表示，其单位为 <code>Ω</code>欧姆，更大的单位有<strong>千欧</strong>(KΩ)、<strong>兆欧</strong>(MΩ)，它们之间的换算关系为：</p><p><span class="math display">\[1 MΩ = 10^3 KΩ = 10^6 Ω\]</span></p><p>一段导体的电阻主要是由导体的<strong>长度</strong> <span class="math inline">\(L\)</span>（单位<code>米</code>）、<strong>横截面积</strong><span class="math inline">\(S\)</span>（单位<code>平方米</code>）、<strong>电阻率</strong><span class="math inline">\(\rho\)</span>（单位<code>欧姆·米</code>）共同来决定，它们之间的数学关系如下所示：</p><p><span class="math display">\[R = \rho \frac{L}{S}\]</span></p><p>下面的表格，给出了一些常用导体的电阻率：</p><table><colgroup><col style="width: 9%"><col style="width: 40%"><col style="width: 9%"><col style="width: 40%"></colgroup><thead><tr><th style="text-align: center;">导体</th><th style="text-align: center;">电阻率</th><th style="text-align: center;">导体</th><th style="text-align: center;">电阻率</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>银</strong></td><td style="text-align: center;"><span class="math inline">\(1.62 \times10^{-8}\)</span> Ω·m</td><td style="text-align: center;"><strong>锡</strong></td><td style="text-align: center;"><span class="math inline">\(11.4 \times10^{-8}\)</span> Ω·m</td></tr><tr><td style="text-align: center;"><strong>铜</strong></td><td style="text-align: center;"><span class="math inline">\(1.69 \times10^{-8}\)</span> Ω·m</td><td style="text-align: center;"><strong>铁</strong></td><td style="text-align: center;"><span class="math inline">\(10.0 \times10^{-8}\)</span> Ω·m</td></tr><tr><td style="text-align: center;"><strong>铝</strong></td><td style="text-align: center;"><span class="math inline">\(2.83 \times10^{-8}\)</span> Ω·m</td><td style="text-align: center;"><strong>铅</strong></td><td style="text-align: center;"><span class="math inline">\(21.9 \times10^{-8}\)</span> Ω·m</td></tr><tr><td style="text-align: center;"><strong>金</strong></td><td style="text-align: center;"><span class="math inline">\(2.4 \times10^{-8}\)</span> Ω·m</td><td style="text-align: center;"><strong>汞</strong></td><td style="text-align: center;"><span class="math inline">\(95.8 \times10^{-8}\)</span> Ω·m</td></tr><tr><td style="text-align: center;"><strong>钨</strong></td><td style="text-align: center;"><span class="math inline">\(5.51 \times10^{-8}\)</span> Ω·m</td><td style="text-align: center;"><strong>碳</strong></td><td style="text-align: center;"><span class="math inline">\(3500 \times10^{-8}\)</span> Ω·m</td></tr></tbody></table><h2 id="电压">电压</h2><p><strong>电位</strong>是衡量电荷在电路当中某点所具有能量的物理量，也称为<strong>电势</strong>。电位是相对的，电路中某点电位的大小，与参考点（即零电位点）的选择有关。</p><p><strong>电压</strong>则用于衡量单位电荷在静电场当中，由于电位不同而产生的能量差，也被称为<strong>电位差</strong>。电压的常用单位有<strong>伏</strong>(<code>V</code>)、<strong>毫伏</strong>(<code>mV</code>)、<strong>微伏</strong>(<code>μV</code>)：</p><p><span class="math display">\[1V = 10^3 mV = 10^6 \mu V\]</span></p><blockquote><p><strong>注意</strong>：电源消耗能量在两极之间，所建立的电位差称为<strong>电动势</strong>（电源的电动势方向是从电源<strong>负极</strong>指向<strong>正极</strong>）。</p></blockquote><h2 id="欧姆定律">欧姆定律</h2><p><strong>欧姆定律</strong>是指电路当中，流经导体的<strong>电流</strong><code>I</code> 与导体两端的<strong>电压</strong> <code>U</code>成正比，与这段导体的<strong>电阻</strong> <code>R</code> 成反比：</p><p><span class="math display">\[I = \frac{U}{R}  \implies R = \frac{U}{I} \implies U = R \cdot I\]</span></p><p>对于上述的欧姆定律换算公式，可以借助下面图形来帮助记忆：</p><p><img src="/Electronics/Element/1-Basic/0.png"></p><h2 id="电功">电功</h2><p><strong>电功</strong>是指电能所做的<strong>功</strong>，单位为<strong>焦耳</strong>(<code>J</code>)，其值与通过的<strong>电流</strong>(<code>A</code>)、<strong>电压</strong>(<code>V</code>)、以及<strong>通电时间</strong>(<code>s</code>)有关：</p><p><span class="math display">\[W = U \cdot I \cdot t\]</span></p><p>实际工作当中，经常使用到电功的另外一个单位<strong>千瓦时</strong>(<code>kW·h</code>)，也被称为<strong>度</strong>，即<code>1千瓦时 = 1 度</code>。千瓦时与焦耳的换算关系如下面所示：</p><p><span class="math display">\[1kW·h = (1 \times 10^3)W \times (60 \times 60)s = (3.6 \times 10^6) W·s= (3.6 \times 10^6) J\]</span></p><h2 id="电功率">电功率</h2><p><strong>电功率</strong>是指<strong>单位时间</strong>内<strong>电流</strong>通过用电设备所做的<strong>功</strong>，使用字母<code>P</code>表示，单位为<strong>瓦特</strong>(<code>W</code>)，其计算公式为：</p><p><span class="math display">\[P = U \cdot I\]</span></p><p>根据<strong>欧姆定律</strong>的公式 <span class="math inline">\(U = R\cdot I\)</span> 以及 <span class="math inline">\(I =\frac{U}{R}\)</span>，可以将上述电功率的计算公式，转换为下面两种形式：</p><p><span class="math display">\[\begin{align}P &amp;= I^2 \cdot R \\P &amp;= \frac{U^2}{R}\end{align}\]</span></p><h2 id="焦耳定律">焦耳定律</h2><p>电流通过导体时，导体发出的<strong>热量</strong><code>Q</code>(焦耳)与导体经过的<strong>电流</strong><code>I</code>(安培)、导体的<strong>电阻</strong><code>R</code>(欧姆)、通电的<strong>时间</strong> <code>t</code>(秒)有关：</p><p><span class="math display">\[Q = I^2 R t\]</span></p><blockquote><p><strong>注意</strong>：换而言之，电流经过导体产生的<strong>热量</strong><span class="math inline">\(Q\)</span> 与<strong>电流</strong> <span class="math inline">\(I\)</span> 的平方、导体的<strong>电阻</strong><span class="math inline">\(R\)</span>、通电的<strong>时间</strong><span class="math inline">\(t\)</span> 呈<strong>正比关系</strong>。</p></blockquote><h2 id="电阻的串并联">电阻的串并联</h2><h3 id="电阻的串联">电阻的串联</h3><p><strong>电阻的串联</strong>是指两个或者以上的电阻，在电路当中以<strong>首尾相接</strong>的方式进行连接：</p><p><img src="/Electronics/Element/1-Basic/1.png"></p><p>电阻的<strong>串联</strong>电路，主要具备有如下四个特点：</p><ol type="1"><li>流过每一个串联电阻的<strong>电流</strong>都相等，也就是都等于 <span class="math inline">\(I\)</span>；</li><li><strong>总电压</strong>等于各个串联电阻上面的电压之和，即 <span class="math inline">\(U = U_{R1} + U_{R2}\)</span>；</li><li>电阻串联之后的<strong>总电阻</strong>增大，总电阻等于各个串联电阻之和，即<span class="math inline">\(R = R_1 + R_2\)</span>；</li><li>串联电阻的<strong>阻值</strong>越大，电阻两端的<strong>电压</strong>就越高，即<span class="math inline">\(R_1 &lt; R_2 \implies U_{R1} &lt;U_{R2}\)</span>；</li></ol><h3 id="电阻的并联">电阻的并联</h3><p><strong>电阻的并联</strong>是指两个或者以上的电阻，在电路当中分别以<strong>首首相接</strong>和<strong>尾尾相连</strong>的方式进行连接：</p><p><img src="/Electronics/Element/1-Basic/2.png"></p><p>电阻的<strong>并联</strong>电路，主要具备有如下四个特点：</p><ol type="1"><li>每一个并联电阻两端的<strong>电压</strong>都相等，即 <span class="math inline">\(U_{R1} = U_{R2}\)</span>；</li><li><strong>总电流</strong>等于各个并联电阻上通过的电流之和，即 <span class="math inline">\(I = I_1 + I_2\)</span>；</li><li>电阻并联之后的<strong>总电阻</strong>减小，总电阻的倒数等于各个并联电阻的倒数之和，即<span class="math inline">\(\frac{1}{R} = \frac{1}{R_1} +\frac{1}{R_2}\)</span>；</li><li>并联电阻的<strong>阻值</strong>越小，通过电阻的<strong>电流</strong>就会越高，即<span class="math inline">\(R_1 &lt; R_2 \implies I_{R1} &gt;I_{R2}\)</span>；</li></ol><h2 id="直流电-交流电">直流电 &amp; 交流电</h2><h3 id="直流电">直流电</h3><p><strong>直流电</strong>是指<strong>方向</strong>始终固定不变的<strong>电压</strong>或者<strong>电流</strong>，<strong>直流电源</strong>通常使用如下的符号进行表示：</p><p><img src="/Electronics/Element/1-Basic/3.png"></p><blockquote><p><strong>注意</strong>：直流电的电流总是由电源的<strong>正极</strong>流出，再经由电路回流至电源的<strong>负极</strong>。</p></blockquote><p>直流电可以划分为<strong>稳定直流电</strong>（<code>方向</code>和<code>大小</code>都不发生变化）和<strong>脉动直流电</strong>（<code>方向</code>不变，<code>大小</code>随时间变化）两种类型：</p><p><img src="/Electronics/Element/1-Basic/4.png"></p><h3 id="交流电">交流电</h3><p><strong>交流电</strong>是指<strong>方向</strong>与<strong>大小</strong>都随时间进行<strong>周期性</strong>变化的<strong>电压</strong>或者<strong>电流</strong>，其中最为常见的是<strong>正弦交流信号</strong>，其符号与波形如下所示：</p><p><img src="/Electronics/Element/1-Basic/5.png"></p><p>正弦交流信号的<strong>周期</strong>、<strong>频率</strong>、<strong>瞬时值</strong>、<strong>有效值</strong>都是电子学当中非常重要的概念：</p><p><img src="/Electronics/Element/1-Basic/6.png"></p><ul><li><strong>周期</strong>是指交流信号重复变化一次所需的时间，通常使用字母<code>T</code>表示，单位是<strong>秒</strong>(<code>s</code>)；例如上图当中交流信号的周期<span class="math inline">\(T = 0.02s\)</span>，表示该交流信号每间隔<code>0.02</code> 秒就会重复变化一次。</li><li><strong>频率</strong>是指交流信号在每一秒钟之内重复变化的次数，使用字母<code>f</code>表示，单位为<strong>赫兹</strong>(<code>Hz</code>)，其值为周期的倒数<span class="math inline">\(f =\frac{1}{T}\)</span>；例如上图当中交流信号的频率 <span class="math inline">\(f = \frac{1}{0.02} = 50Hz\)</span>，表明该信号在 1秒钟之内会重复变化 50 次。</li><li><strong>有效值</strong>用于计量交流电的大小（也称为<strong>均方根值</strong>），例如上图的<code>220V</code>正弦交流信号就是一个有效值，正弦交流电的<code>有效值</code>等于其<code>最大瞬时值</code>的<span class="math inline">\(\frac{1}{\sqrt{2}} \approx 0.707\)</span>倍。</li><li><strong>瞬时值</strong>是指交流信号在某一个具体时刻的参数值；例如上图交流信号在<span class="math inline">\(t_1\)</span> 时刻的瞬时值为 <span class="math inline">\(（220V \times \sqrt{2})V \approx331V\)</span>，而在 <span class="math inline">\(t_2\)</span>时刻的瞬时值为 <span class="math inline">\(0V\)</span>。</li></ul><p>除此之外，正弦交流信号的<strong>相位</strong>与<strong>相位差</strong>，也属于电子学当中比较重要的概念：</p><p><img src="/Electronics/Element/1-Basic/7.png"></p><p><strong>相位</strong>是指交流信号在某一个具体时刻的<strong>角度</strong>，上图当中交流信号在<span class="math inline">\(t = 0.005s\)</span> 时刻的相位为 <span class="math inline">\(\frac{\pi}{2}\)</span> 或者 <code>90°</code>度，而在 <span class="math inline">\(t = 0.01s\)</span> 时刻的相位为<span class="math inline">\(\pi\)</span> 或者 <code>180°</code> 度。</p><ul><li><strong>初相位</strong>就是交流信号在 <code>0</code>时刻的角度。</li><li><strong>相位差</strong>是指两个相同频率正弦交流信号的相位之差。</li><li>同一个坐标系上面，位置偏<strong>左</strong>的相位称为<strong>超前</strong>，位置偏<strong>右</strong>的相位称为<strong>滞后</strong>。</li></ul><h2 id="电路网络图论">电路网络图论</h2><p>分析只包含有一个电源的<strong>简单电路</strong>，只需要运用<code>欧姆定律</code>和<code>电阻的串并联关系</code>即可，而对于拥有着多个电源的<strong>复杂电路</strong>，则需要进一步借助<code>基尔霍夫定律</code>、<code>叠加定理</code>、<code>戴维南定理</code>等。在进行更深入的讨论之前，需要引入电路网络图论的相关内容：</p><p><img src="/Electronics/Element/1-Basic/8.png"></p><ul><li><strong>支路</strong>：由一个或多个元器件首尾相接构成的一段电路（无其它分支），相同支路内通过所有元器件的电流都相等。上图电路当中拥有<code>BAFE</code>、<code>BE</code>、<code>BCDE</code>一共三条支路，其中包含有电源的称为<strong>有源支路</strong>，没有电源的称为<strong>无源支路</strong>。</li><li><strong>结点</strong>：三条或者以上支路的共同连接点，例如上面电路当中的<code>B</code> 点和 <code>E</code> 点。</li><li><strong>回路</strong>：即电路当中任意的闭合路径，例如上图所示电路当中的<code>ABEFA</code>、<code>BCDEB</code>、<code>ABCDEFA</code>。</li><li><strong>网孔</strong>：即内部不再包含有任何支路的回路，例如上图所示电路当中的<code>ABEFA</code>、<code>BCDEB</code>，而 <code>ABCDEFA</code>由于包含有支路 <code>BE</code>，因而不属于网孔。</li></ul><h2 id="基尔霍夫定律">基尔霍夫定律</h2><p><strong>基尔霍夫定律</strong>可以分为<strong>基尔霍夫第一定律</strong>（也称为<strong>基尔霍夫电流定律</strong>）和<strong>基尔霍夫第二定律</strong>（又称<strong>基尔霍夫电压定律</strong>）。</p><h3 id="基尔霍夫电流定律">基尔霍夫电流定律</h3><p>基尔霍夫电流定律：<strong>流入任意一个结点的电流之和，等于流出该结点的电流之和</strong>，即<span class="math inline">\(\Sigma I_{流入结点} = \SigmaI_{流出结点}\)</span>：</p><p><img src="/Electronics/Element/1-Basic/9.png"></p><p>上图所示的电路当中，流入 <strong>A</strong> 点的电流有 <span class="math inline">\(I_1\)</span>、<span class="math inline">\(I_2\)</span>、<span class="math inline">\(I_3\)</span> 三个，而流出 <strong>A</strong>点的电流有 <span class="math inline">\(I_4\)</span> 和 <span class="math inline">\(I_5\)</span>两个，根据基尔霍夫电流定律可以得出如下的关系：</p><p><span class="math display">\[I_1 + I_2 + I_3 = I_4 + I_5\]</span></p><blockquote><p><strong>注意</strong>：基尔霍夫电流定律不仅适用于电路当中的<strong>节点</strong>，同样也适用于一个<strong>封闭平面</strong>。</p></blockquote><h3 id="基尔霍夫电压定律">基尔霍夫电压定律</h3><p>基尔霍夫电压定律：<strong>任意一个回路内，所有支路的电压代数和为零</strong>（需要先确定参考方向），即<span class="math inline">\(\Sigma U = 0V\)</span>：</p><p><img src="/Electronics/Element/1-Basic/10.png"></p><p>指定上图电路当中 <code>BCDFB</code>回路的参考方向，经过<strong>电阻</strong> <span class="math inline">\(R_2\)</span> 的<strong>电流</strong> <span class="math inline">\(I_2\)</span>，与经过<strong>电阻</strong> <span class="math inline">\(R_3\)</span> 的<strong>电流</strong> <span class="math inline">\(I_3\)</span> 的绕行方向一致，所以 <span class="math inline">\(I_2 \times R_2 = U_2\)</span> 和 <span class="math inline">\(I_3 \times R_3 = U_3\)</span>两者都取<strong>正</strong>。由于电源的电动势方向是从<strong>负极</strong>到<strong>正极</strong>，所以<strong>电源</strong><span class="math inline">\(E_2\)</span>的电动势方向与参考方向相反取<strong>负</strong>，根据基尔霍夫电压定律可以得出如下关系：</p><p><span class="math display">\[E_2 = (I_2 \times R_2) + (I_3 \times R_3)\]</span></p><p>接下来，再指定上面电路当中 <code>ABFHA</code>回路的参考方向，流过<strong>电阻</strong> <span class="math inline">\(R_1\)</span> 的<strong>电流</strong> <span class="math inline">\(I_1\)</span> 方向与参考方向相同，所以 <span class="math inline">\(I_1 \times R_1 = U_1\)</span>取<strong>正</strong>；而流过<strong>电阻</strong> <span class="math inline">\(R_2\)</span> 的<strong>电流</strong> <span class="math inline">\(I_2\)</span> 方向与参考方向相反，所以 <span class="math inline">\(I_2 \times R_2 = U_2\)</span>取<strong>负</strong>；同样由于电源的电动势方向是从<strong>负极</strong>到<strong>正极</strong>，所以<strong>电源</strong><span class="math inline">\(E_2\)</span>的电动势方向与参考方向相同取<strong>正</strong>，而<strong>电源</strong><span class="math inline">\(E_1\)</span>的电动势方向与参考方向相反取<strong>负</strong>，从而可以得出如下的关系：</p><p><span class="math display">\[E_2 - E_1 = (I_1 \times R_1) - (I_2 \times R_2)\]</span></p><h2 id="叠加定理">叠加定理</h2><p><strong>叠加定理</strong>是一个反映<strong>线性电路</strong>基本性质的重要定理，其是指<strong>在线性电路当中，任意一条支路上的电流或者电压等于每一个电源单独作用在该条支路，所产生的电流或者电压的代数和</strong>。接下来，以下图所示电路为例来说明叠加定理的应用。已知下面电路当中的<span class="math inline">\(E_1 = 14V\)</span>、<span class="math inline">\(R_1 = 0.5Ω\)</span>、<span class="math inline">\(E_2 = 12V\)</span>、<span class="math inline">\(R_2 = 0.2Ω\)</span>、<span class="math inline">\(R= 4Ω\)</span>，试求解支路电流 <span class="math inline">\(I\)</span>、<span class="math inline">\(I_1\)</span>、<span class="math inline">\(I_2\)</span> ？</p><p><img src="/Electronics/Element/1-Basic/11.png"></p><p>首先，标识出上述电路当中各条支路的<strong>电流</strong>方向，然后绘制出只存在一个<strong>电源</strong><span class="math inline">\(E_1\)</span>作用时的电路（将另外一个<strong>电源</strong> <span class="math inline">\(E_2\)</span>视为<strong>短路</strong>），并且标识出简化电路上各条支路的<strong>电流</strong>方向，再分别求解出各条支路上的电流大小：</p><p><img src="/Electronics/Element/1-Basic/12.png"></p><p>接下来，再绘制出只存在一个<strong>电源</strong> <span class="math inline">\(E_2\)</span>作用时的电路（再将另外一个<strong>电源</strong> <span class="math inline">\(E_1\)</span>视为<strong>短路</strong>），同样标识出简化电路上各条支路的<strong>电流</strong>方向，再分别求解出各条支路上的电流大小：</p><p><img src="/Electronics/Element/1-Basic/13.png"></p><p>最后，叠加每一条支路上的电流或者电压（凡是与上面电路标识出的参考方向一致就为<strong>正</strong>，反之就为<strong>负</strong>），从而就可以求解出各条支路上的<strong>电流</strong><span class="math inline">\(I\)</span>、<span class="math inline">\(I_1\)</span>、<span class="math inline">\(I_2\)</span>：</p><p><span class="math display">\[\begin{align}&amp; I_1 = I_1&#39; - I_1&#39;&#39; = (20.28 - 16.56) = 3.72A \\&amp; I_2 = I_2&#39;&#39; - I_2&#39; = (18.6 - 19.3) = -0.7A \\&amp; I = I&#39; + I&#39;&#39; = (0.98 + 2.04) = 3.02A \\\end{align}\]</span></p><blockquote><p><strong>注意</strong>：如果元器件两端的<strong>电压</strong>与流过的<strong>电流</strong>呈正比，那么这类元器件（例如电阻）就被称作<strong>线性元件</strong>，而由线性元件组成的电路相应的就被称为<strong>线性电路</strong>。</p></blockquote><h2 id="戴维南定理">戴维南定理</h2><p><strong>二端网络</strong>顾名思义就是具有两个出线端子的电路，而包含有<strong>电源</strong>的二端网络就称为<strong>有源二端网络</strong>，否则就称为<strong>无源二端网络</strong>。例如下图左侧的电路，就可以简化为右侧的二端口网络：</p><p><img src="/Electronics/Element/1-Basic/14.png"></p><p><strong>戴维南定理</strong>是指对于任何一个有源二端口网络，都可以用一个等效的电源<strong>电动势</strong><span class="math inline">\(E_0\)</span> 与<strong>内阻</strong> <span class="math inline">\(R_0\)</span>的串联组合来代替，根据该定理同样可以将下图左侧的电路简化为右侧的形式：</p><p><img src="/Electronics/Element/1-Basic/15.png"></p><p><strong>戴维南定理</strong>还规定了等效的<strong>电源电动势</strong><span class="math inline">\(E_0\)</span> 以及<strong>内阻</strong> <span class="math inline">\(R\)</span> 的计算方法：</p><ul><li><strong>电源电动势</strong> <span class="math inline">\(E_0\)</span>指的是该有源二端口网络<strong>开路</strong>时候的端口电压。</li><li><strong>内阻</strong> <span class="math inline">\(R\)</span>是指从两个端口看进去，将电源视为<strong>短路</strong>时候的等效电阻。</li></ul><p>接下来，以下图所示的电路为例来展示<strong>戴维南定理</strong>的应用，已知该电路当中的<span class="math inline">\(E_1 = 14V\)</span>、<span class="math inline">\(R_1 = 0.5Ω\)</span>、<span class="math inline">\(E_2 = 12V\)</span>、<span class="math inline">\(R_2 = 0.2Ω\)</span>、<span class="math inline">\(R= 4Ω\)</span>，试求解通过<strong>电阻</strong> <span class="math inline">\(R\)</span> 的<strong>电流</strong> <span class="math inline">\(I\)</span> 的大小？</p><p><img src="/Electronics/Element/1-Basic/16.png"></p><p>首先，将电路划分为<strong>待求支路</strong>和<strong>有源二端口网络</strong>两个部分（如上图所示），然后假设待求支路处于断开状态，并且求解出有源二端网络开路时候的<strong>端口电压</strong>，该电压就等效为电源的<strong>电动势</strong><span class="math inline">\(E_0\)</span>：</p><p><img src="/Electronics/Element/1-Basic/17.png"></p><p>然后，再假设有源二端口网络内部的所有<strong>电源短路</strong>，从而就可以获得其<strong>内部电阻</strong><span class="math inline">\(R_0\)</span> 的阻值：</p><p><img src="/Electronics/Element/1-Basic/18.png"></p><p>接下来，基于上述步骤获得的<strong>电源电动势</strong> <span class="math inline">\(E_0\)</span> 以及<strong>内阻</strong> <span class="math inline">\(R\)</span>，就可以绘制出如下图所示的<strong>戴维南等效电路</strong>，并且求解出<strong>支路电流</strong><span class="math inline">\(I\)</span> 的大小：</p><p><img src="/Electronics/Element/1-Basic/19.png"></p><blockquote><p><strong>注意</strong>：对于拥有多个电源的复杂电路，如果需要求解多条支路上的电流大小，可以运用<strong>基尔霍夫定律</strong>或者<strong>叠加定理</strong>。如果只需要求解一条支路上的电流大小，则使用<strong>戴维南定理</strong>更加方便。</p></blockquote><h2 id="最大功率传输定理">最大功率传输定理</h2><p>最大功率传输定理是指负载要从电源获得最大功率的条件是：<strong>负载的内阻或者阻抗与电源的内阻相等</strong>，也就是电路设计工作当中经常提到的<strong>阻抗匹配</strong>。例如下图所示的电路，其中的<strong>电阻</strong><span class="math inline">\(R\)</span> 是<strong>电源</strong> <span class="math inline">\(E\)</span> 的内阻，而 <span class="math inline">\(I\)</span> 和 <span class="math inline">\(U\)</span> 则是<strong>负载电阻</strong> <span class="math inline">\(R_L\)</span>上通过的<strong>电压</strong>与<strong>电流</strong>：</p><p><img src="/Electronics/Element/1-Basic/20.png"></p><p><strong>负载电阻</strong> <span class="math inline">\(R_L\)</span>上获得的<strong>功率</strong> <span class="math inline">\(P =UI\)</span>，如果增大<strong>负载电阻</strong> <span class="math inline">\(R_L\)</span> 的阻值，虽然<strong>电压</strong><span class="math inline">\(U\)</span>会随之增大，但是<strong>电流</strong> <span class="math inline">\(I\)</span>会减小。如果减小<strong>负载电阻</strong> <span class="math inline">\(R_L\)</span> 的阻值，虽然<strong>电流</strong><span class="math inline">\(I\)</span>会随之增大，但是<strong>电压</strong> <span class="math inline">\(U\)</span>又会减小。根据最大功率传输定理，此时<strong>负载电阻</strong> <span class="math inline">\(R_L\)</span> 要从<strong>电源</strong> <span class="math inline">\(E\)</span> 获得最大功率的条件是 <span class="math inline">\(R_L = R\)</span>，这样<strong>负载电阻</strong><span class="math inline">\(R_L\)</span>上获得的<strong>最大功率</strong> <span class="math inline">\(P\)</span>为：</p><p><span class="math display">\[P = \frac{E^2}{4 \cdot R_L}\]</span></p><p>对于下面这种拥有<strong>多个电源</strong>的复杂电路，则需要先使用<strong>戴维南定理</strong>求解出该电路的<strong>等效内阻</strong><span class="math inline">\(R_0\)</span> 和<strong>等效电动势</strong><span class="math inline">\(E_0\)</span>：</p><p><img src="/Electronics/Element/1-Basic/21.png"></p><p>然后同样只要<strong>负载电阻</strong> <span class="math inline">\(R_L\)</span> 与电源的<strong>等效内阻</strong><span class="math inline">\(R_0\)</span>相等，那么<strong>负载电阻</strong> <span class="math inline">\(R_L\)</span> 就可以获得到<strong>最大功率</strong><span class="math inline">\(P\)</span>：</p><p><span class="math display">\[P = \frac{E_0^2}{4 \cdot R_L}\]</span></p><h2 id="贴片元件封装规格">贴片元件封装规格</h2><p>下面的表格体现了电路设计当中，常用元件的贴片封装规格，以及对应的尺寸信息：</p><p><img src="/Electronics/Element/1-Basic/22.png"></p><h2 id="电磁兼容性-emc">电磁兼容性 EMC</h2><p><strong>EMC</strong>是电磁兼容性（<strong>E</strong>lectro<strong>m</strong>agnetic[ɪˌlektroʊmæɡˈnetɪk]<strong>C</strong>ompatibility）的英文缩写，其意思是<strong>不对其它设备产生电磁干扰，即使受到来自其它设备的电磁干扰，也仍然能够保持原始的性能</strong>。由于需要同时兼具<strong>不干扰其它设备</strong>，以及<strong>抗其它设备干扰</strong>两种性能指标，因而被称为<strong>电磁兼容性</strong>。</p><p><img src="/Electronics/Element/1-Basic/23.png"></p><ul><li><strong>EMI</strong>（Electromagnetic Interference[ˌɪntəˈfɪərəns]）是<strong>电磁干扰</strong>的英文缩写，表示因发射电磁波而对周围环境造成的干扰，即<strong>干扰其它设备</strong>。</li><li><strong>EMS</strong>（Electromagnetic Susceptibility[səˌseptəˈbɪləti]）是<strong>电磁敏感性</strong>的英文缩写，代表的是对于电磁波干扰的耐受度，即<strong>被其它设备干扰</strong>。</li></ul><blockquote><p><strong>注意</strong>：上图中的<strong>传导</strong>表示的是<strong>传输导线</strong>，而<strong>辐射</strong>代表的是<strong>电磁辐射</strong>。</p></blockquote><h1 id="电阻器-resistor">电阻器 Resistor</h1><p>电阻器可以具体划分为<strong>固定电阻器</strong>、<strong>电位器</strong>、<strong>敏感电阻器</strong>三种类型，其中<strong>固定电阻器</strong>的阻值固定不变，通常使用如下的电路符号来进行表示：</p><p><img src="/Electronics/Element/2-Resistance/1.png"></p><p>固定电阻器通常在电路中起到<strong>降压/限流</strong>、<strong>分流</strong>、<strong>分压</strong>的作用：</p><p><img src="/Electronics/Element/2-Resistance/2.png"></p><h2 id="标称阻值">标称阻值</h2><p><strong>标称阻值</strong>是标注在电阻器上的阻值，使用<strong>单位</strong>来代表<strong>小数点</strong>是一种经常被使用到的阻值表示方法：</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></pre></td><td class="code"><pre><span class="line"><span class="number">1</span>k2 = <span class="number">1.2</span>kΩ</span><br><span class="line"><span class="number">3</span>M3 = <span class="number">3.3</span>MΩ</span><br><span class="line"><span class="number">3</span>R3 = <span class="number">3.3</span>Ω</span><br><span class="line">R33 = <span class="number">0.33</span>Ω</span><br></pre></td></tr></table></figure><p>贴片电阻器通常采用<strong>数值标注法</strong>，其最后一位表示阻值当中<code>0</code> 的个数，而前面的三到四位才是真正的有效数值：</p><p><img src="/Electronics/Element/2-Resistance/3.png"></p><h2 id="误差">误差</h2><p><strong>E系列标准参数值</strong>（E-series）是一套由美国电子工业联盟（<strong>ECIA</strong>，ElectronicsIndustry Alliance）制定的十倍进制<strong>标准参数值</strong>系统，例如以E6 标准参数值生产的电阻器，在 <code>1Ω~10Ω</code> 范围拥有着 6个不同阻值的电阻器，而在 <code>10Ω~100Ω</code> 范围之间依然有着 6个不同阻值的电阻器。除此之外需要注意的是，每一套 E系列标准参数值对应的元器件精度都会有所不同，具体的对应关系请参照下面的表格：</p><table><thead><tr><th style="text-align: center;">E 系列名称</th><th style="text-align: left;">精度/误差</th><th style="text-align: center;">每十倍进制标准参数值的个数</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>E3</strong></td><td style="text-align: left;">高于 <code>&gt;20%</code></td><td style="text-align: center;"><strong>3</strong> 个标准参数值</td></tr><tr><td style="text-align: center;"><strong>E6</strong></td><td style="text-align: left;"><code>20%</code></td><td style="text-align: center;"><strong>6</strong> 个标准参数值</td></tr><tr><td style="text-align: center;"><strong>E12</strong></td><td style="text-align: left;"><code>10%</code></td><td style="text-align: center;"><strong>12</strong> 个标准参数值</td></tr><tr><td style="text-align: center;"><strong>E24</strong></td><td style="text-align: left;"><code>5%</code></td><td style="text-align: center;"><strong>24</strong> 个标准参数值</td></tr><tr><td style="text-align: center;"><strong>E48</strong></td><td style="text-align: left;"><code>2%</code></td><td style="text-align: center;"><strong>48</strong> 个标准参数值</td></tr><tr><td style="text-align: center;"><strong>E96</strong></td><td style="text-align: left;"><code>1%</code></td><td style="text-align: center;"><strong>96</strong> 个标准参数值</td></tr><tr><td style="text-align: center;"><strong>E192</strong></td><td style="text-align: left;"><code>0.5%</code> 或 <code>0.25%</code>甚至更低</td><td style="text-align: center;"><strong>192</strong> 个标准参数值</td></tr></tbody></table><blockquote><p><strong>注意</strong>：<strong>E</strong>字母后面的数值，即表示该标准值系统所拥有的<strong>基本参数值</strong>个数。</p></blockquote><p>更完整的关于 E 系列标准参数值的内容，请查阅我之前整理撰写的<a href="/Electronics/E-Series/"><strong>《美国电子工业联盟 E系列标准参数值速查手册》</strong></a>一文。</p><h2 id="额定功率">额定功率</h2><p>电阻器的<strong>额定功率</strong>是指一定条件下，长期使用所允许承受的最大功率。额定功率越大，允许流过电阻器的<strong>电流</strong>就越大。国家规定的固定电阻器额定功率有<code>1/8W</code>、<code>1/4W</code>、<code>1/2W</code>、<code>1W</code>、<code>2W</code>、<code>5W</code>、<code>10W</code>等，下面的表格体现了各种封装的贴片电阻与其额定功率的对应关系：</p><table><thead><tr><th style="text-align: center;">封装规格</th><th style="text-align: center;">额定功率</th><th style="text-align: center;">封装规格</th><th style="text-align: center;">额定功率</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>0402</strong> 封装</td><td style="text-align: center;"><code>1/16</code> W</td><td style="text-align: center;"><strong>1210</strong> 封装</td><td style="text-align: center;"><code>1/3</code> W</td></tr><tr><td style="text-align: center;"><strong>0603</strong> 封装</td><td style="text-align: center;"><code>1/10</code> W</td><td style="text-align: center;"><strong>1812</strong> 封装</td><td style="text-align: center;"><code>1/2</code> W</td></tr><tr><td style="text-align: center;"><strong>0805</strong> 封装</td><td style="text-align: center;"><code>1/8</code> W</td><td style="text-align: center;"><strong>2010</strong> 封装</td><td style="text-align: center;"><code>3/4</code> W</td></tr><tr><td style="text-align: center;"><strong>1206</strong> 封装</td><td style="text-align: center;"><code>1/4</code> W</td><td style="text-align: center;"><strong>2512</strong> 封装</td><td style="text-align: center;"><code>1</code> W</td></tr></tbody></table><h2 id="电阻器的选型">电阻器的选型</h2><p>对电阻器进行选型时，会主要考虑其<strong>标称阻值</strong>、<strong>误差</strong>、<strong>额定功率</strong>、<strong>最大工作电压</strong>、<strong>温度系数</strong>，例如对于下面这个电路：</p><p><img src="/Electronics/Element/2-Resistance/4.png"></p><p>首先，在<strong>考虑到误差</strong>的前提下确定<strong>阻值</strong>，基于欧姆定律可以求解得到电阻器的取值：</p><p><span class="math display">\[R = \frac{U}{I} = \frac{220V}{0.01A} = 22000Ω = 22kΩ\]</span></p><p>然后，根据功率的计算公式获得该电阻器消耗的功率，基于下面的公式可以计算得到<code>2.2W</code>。由于选取的电阻器<strong>额定功率应当在实际功率的两倍以上</strong>，所以这里选择的电阻器额定功率应当为<code>5W</code>：</p><p><span class="math display">\[P = I^2R = (0.01A)^2 \times 22000Ω = 2.2W\]</span></p><p>最后，还需要关注该电阻器所能够承受的<strong>最大工作电压</strong>，避免低于电路当中两端的实际电压而导致烧毁。除此之外，电阻器选型过程当中，<strong>温度系数</strong>和 <strong>噪声</strong> 也是非常重要的两个选型参数：</p><ul><li><strong>温度系数</strong>也是一个十分需要关注的参数（例如<code>±100 ppm/℃</code>、<code>±200 ppm/℃</code>），其表示了温度每变化<code>1℃</code>所引发的阻值相对变化。通常情况下，<strong>温度系数越小越好</strong>。</li><li><strong>噪声</strong>是产生于电阻器当中的一种不规则电压起伏，主要是由于内部不规则的自由电子运动所导致，<strong>噪声越低越好</strong>。</li></ul><blockquote><p><strong>注意</strong>：元器件的参数值，伴随着温度的升高而增大就称为<strong>正温度系数</strong>，反之则称为<strong>负温度系数</strong>。</p></blockquote><h2 id="薄膜厚膜电阻器">薄膜/厚膜电阻器</h2><p><strong>薄膜电阻</strong>或者<strong>厚膜电阻</strong>通常用于标注<strong>贴片电阻器</strong>，这是因为贴片电阻器是将<code>金属粉</code>与<code>玻璃釉粉</code>混合之后，印刷在基板上制作而成，根据印刷厚度可以大致划分为<strong>薄膜电阻</strong>或者<strong>厚膜电阻</strong>两种类型：</p><p><img src="/Electronics/Element/2-Resistance/5.png"></p><blockquote><p><strong>注意</strong>：通常情况下，<strong>薄膜电阻的温度系数要优于厚膜电阻</strong>。</p></blockquote><h2 id="碳膜金属膜电阻器">碳膜/金属膜电阻器</h2><p>这类电阻器是将一层<strong>碳膜</strong>或者<strong>金属膜</strong>附着在陶瓷基底上面制作而成，材料膜的厚度决定了阻值的大小：</p><p><img src="/Electronics/Element/2-Resistance/6.png"></p><blockquote><p><strong>注意</strong>：<strong>金属膜电阻器</strong>精度更高，噪声更小，温度系数更低。而<strong>碳膜电阻器</strong>的优势则主要在于成本低廉。</p></blockquote><h2 id="采样电阻器">采样电阻器</h2><p><strong>采样电阻</strong>通常采用铜镍、锰铜等合金材料制作，具备<strong>低温度系数</strong>（通常为<code>±50ppm/℃</code>或者更低）和<strong>极低的电阻值</strong>（毫欧级别，通常不会超过<code>1Ω</code>），可以在极宽的温度范围内具有比较稳定的电阻值。主要用于在电路当中进行<code>电压</code>或者<code>电流</code>的采样（<strong>电流采样</strong>时<strong>串联</strong>一个较小阻值的采样电阻，<strong>电压采样</strong>时则需要<strong>并联</strong>一个较大阻值的采样电阻）。</p><p><img src="/Electronics/Element/2-Resistance/7.png"></p><blockquote><p><strong>注意</strong>：万用表当中经常使用的<strong>康铜丝电阻</strong>，实质上就采用了<strong>铜镍</strong>或者<strong>锰铜</strong>合金材料。</p></blockquote><h2 id="电位器">电位器</h2><p><strong>电位器</strong>是一种阻值可以变化调节的电阻器，也被称作<strong>可变电阻器</strong>，其电路符号如下图所示：</p><p><img src="/Electronics/Element/2-Resistance/8.png"></p><p>电位器的基本结构如下图所示，其拥有<code>A</code>、<code>C</code>、<code>B</code> 三个引脚，在<code>A</code> 与 <code>B</code> 引脚之间连接着一段阻值为 <span class="math inline">\(R_{AB}\)</span>的电阻材料，该阻值就是这个电位器的<strong>标称阻值</strong>:</p><p><img src="/Electronics/Element/2-Resistance/9.png"></p><p>上面电位器的引脚 <code>C</code> 连接着一个滑动片，此时 <code>A</code>与 <code>C</code> 引脚之间的阻值为 <span class="math inline">\(R_{AC}\)</span>，而 <code>B</code> 与<code>C</code> 引脚之间的阻值为 <span class="math inline">\(R_{BC}\)</span>，三个引脚之间的电阻值存在着如下关系：</p><p><span class="math display">\[R_{AB} = R_{AC} + R_{BC}\]</span></p><p>类似于固定电阻器，电位器同样具备<strong>降压/限流</strong>、<strong>分流</strong>、<strong>分压</strong>的作用，不过由于其阻值可调，因而随时可以通过改变上述三个引脚之间的电阻值来调整相关的参数。</p><p>除了<strong>标称阻值</strong>、<strong>额定功率</strong>等电阻器通用参数之外，电位器的另外一个重要参数是<strong>阻值变化特性</strong>，也就是<strong>电位器阻值</strong>与滑动片旋转角度之间的关系，根据阻值变化特性不同可以划分为如下三种类型：</p><p><img src="/Electronics/Element/2-Resistance/10.png"></p><ol type="1"><li><strong>直线式</strong>：阻值与旋转角度呈直线关系，当旋转滑动片时，电位器的阻值会匀速变化，即电位器的阻值变化与旋转角度大小呈<strong>正比</strong>。</li><li><strong>指数式</strong>：阻值与旋转角度呈指数关系，刚开始旋转滑动片时，阻值变化很<strong>慢</strong>，随着转动角度的增大，阻值变化<strong>增大</strong>。</li><li><strong>对数式</strong>：阻值与旋转角度呈对数关系，刚开始旋转滑动片时，阻值变化很<strong>快</strong>，随着转动角度的增大，阻值变化<strong>减小</strong>。</li></ol><p>电位器的类型比较多，可以被划分为<strong>普通电位器</strong>、<strong>微调电位器</strong>、<strong>带开关电位器</strong>、<strong>多联电位器</strong>等种类：</p><p><img src="/Electronics/Element/2-Resistance/11.png"></p><ul><li><strong>普通电位器</strong>一般是指带有调节手柄的电位器。</li><li><strong>微调电位器</strong>通常不带调节手柄，需要使用螺丝刀进行调节。</li><li><strong>带开关电位器</strong>结合了开关（引脚数量会多出 2个）与电位器的功能。</li><li><strong>多联电位器</strong>把多个电位器组合在一起，可以同时进行调节。</li></ul><h2 id="热敏电阻器">热敏电阻器</h2><p><strong>热敏电阻器</strong>是一种对于温度敏感的电阻器，当温度变化时其阻值也会随之变化，其电路符号如下图所示：</p><p><img src="/Electronics/Element/2-Resistance/12.png"></p><p>通常情况下，热敏电阻器可以被划分为<strong>负温度系数</strong>和<strong>正温度系数</strong>热敏电阻器两种类型：</p><p><img src="/Electronics/Element/2-Resistance/13.png"></p><ol type="1"><li><strong>负温度系数</strong>热敏电阻器（NTC）：<strong>阻值</strong>随着温度的<strong>升高</strong>而<strong>减小</strong>。</li><li><strong>正温度系数</strong>热敏电阻器（PTC）：<strong>阻值</strong>随着温度的<strong>升高</strong>而<strong>增大</strong>。</li></ol><p>除此之外，热敏电阻器还可以被划分为<strong>缓慢型</strong>和<strong>开关型</strong>两种：</p><ul><li><strong>缓慢型</strong>热敏电阻器：温度每变化<code>1℃</code>，其阻值就会随之发生 <code>0.5% ~ 8%</code>的线性变化。</li><li><strong>开关型</strong>热敏电阻器：具有一个转折温度，当低于或者高于该温度时，阻值就会急剧增大或者减小。</li></ul><blockquote><p><strong>注意</strong>：热敏电阻器的<strong>标称阻值</strong>，是指当处于<code>25℃</code> 室温情况下所测得的电阻值。</p></blockquote><h2 id="压敏电阻器">压敏电阻器</h2><p><strong>压敏电阻器</strong>是指当两端电压低于<strong>压敏电压</strong>时，其阻值接近于无穷大。当两端电压超过<strong>压敏电压</strong>时，阻值又会急剧变小，其电路符号如下图所示：</p><p><img src="/Electronics/Element/2-Resistance/14.png"></p><p>利用压敏电阻器<strong>过电压</strong>时阻值变小的特性，可以将其应用于一些<strong>过压保护</strong>或者<strong>浪涌保护</strong>电路：</p><p><img src="/Electronics/Element/2-Resistance/15.png"></p><p>在上图的电路当中，<code>220V</code> 交流电通过保险丝 <code>F</code>连接至家用电器，当发生雷击的时候，就会导致电压瞬间上升。如果该电压被施加到压敏电阻器两端，就会使得压敏电阻器的阻值迅速降低至<strong>零</strong>，此时流过保险丝和压敏电阻器的电流急剧增大，致使保险丝被瞬间熔断，从而防止雷击的电压触及家用电器。</p><p><img src="/Electronics/Element/2-Resistance/16.png"></p><blockquote><p><strong>注意</strong>：大多数情况下，<strong>压敏电压</strong>是指使用<code>1mA</code> 直流电流经过压敏电阻器时所测得的电压值。对于<code>220V</code>的交流市电保护电路，通常会选用<strong>压敏电压</strong>介于<code>480V ~ 560V</code> 范围的压敏电阻。</p></blockquote><h2 id="光敏电阻器">光敏电阻器</h2><p><strong>光敏电阻器</strong>是一种对光照敏感的电阻器，当照射的光线强弱发生变化时，其阻值也会随之变化（通常情况下<strong>光线越强阻值越小</strong>），其电路符号如下图所示：</p><p><img src="/Electronics/Element/2-Resistance/17.png"></p><p>下面分别展示了贴片式和直插式光敏电阻器的实物，在进行光敏电阻器的选型时，需要重点关注如下三个参数：</p><p><img src="/Electronics/Element/2-Resistance/18.png"></p><ol type="1"><li><strong>最高工作电压</strong>：光敏电阻器正常工作时，两端所允许的最大电压。</li><li><strong>暗电阻</strong>：关闭光线照射（<code>0 Lux</code>）之后，第10秒钟时刻的阻值，此时在其<code>最高工作电压</code>下通过的电流的称为<strong>暗电流</strong>。</li><li><strong>亮电阻</strong>：使用光线照射（<code>10 Lux</code>）之后，所测得的阻值，此时在其<code>最高工作电压</code>下通过的电流的称为<strong>亮电流</strong>。</li></ol><p>下图是光敏电阻器的两个典型应用电路，即分别将其<strong>串联</strong>或者<strong>并联</strong>在电路当中使用：</p><p><img src="/Electronics/Element/2-Resistance/19.png"></p><ul><li>上图左侧电路是将<strong>光敏电阻串联使用</strong>，如果光敏电阻器<span class="math inline">\(R_2\)</span>无光线照射，那么阻值增大，流经灯的电流较小，灯亮度较暗。如果 <span class="math inline">\(R_2\)</span>被光线照射，那么阻值降低，流经灯的电流增大，灯的亮度就会增强。</li><li>上图右侧电路是将<strong>光敏电阻并联使用</strong>，当光敏电阻器<span class="math inline">\(R_2\)</span>无光线照射，那么其阻值将会增大，并联分得的电流就会减少，此时灯的亮度就会增强。反之，如果<span class="math inline">\(R_2\)</span>被光线照射，那么阻值就会降低，并联分得的电流就会增多，流经灯的电流将会减小，导致其亮度降低。</li></ul><h1 id="电容器-capacitor">电容器 Capacitor</h1><p><strong>电容器</strong>是一种可以储存电荷的元器件，由相距很近且中间隔有绝缘介质的两块导电极板构成，按照有无极性可以划分为如下两种类型：</p><ol type="1"><li><strong>无极性电容</strong>：引脚没有正负极性之分，主要是<code>MLCC 多层陶瓷电容</code>、<code>瓷片电容</code>。</li><li><strong>有极性电容</strong>：需要区分引脚的正负极（正极连接高电位，负极连接低电位，反接会导致损毁），例如常见的<code>电解电容</code>、<code>钽电容</code>。</li></ol><p><img src="/Electronics/Element/3-Capacitor/1.png"></p><p>上图分别展示了<strong>有极性电容</strong>和<strong>无极性电容</strong>的电路符号，使用的时候要注意加以区分。</p><h2 id="主要参数">主要参数</h2><p>电容器选型主要关注的参数有<strong>容值</strong>、<strong>精度</strong>、<strong>额定电压</strong>、<strong>等效串联电阻</strong>（ESR）：</p><ul><li><strong>容值</strong>：电容器存储电荷的多少，单位有<strong>法拉</strong>(F)、<strong>毫法</strong>(mF)、<strong>微法</strong>(μF)、<strong>纳法</strong>(nF)、<strong>皮法</strong>(pF)，相互之间的换算关系为<span class="math inline">\(1F = 10^3mF= 10^6 \mu F = 10^9 nF =10^{12}pF\)</span>；</li><li><strong>精度</strong>：标称容量与实际容量之间所允许的最大误差值，常见的精度有<code>±10%</code> 或者 <code>±20%</code>，比较高精度的甚至可以达到<code>±5%</code>；</li><li><strong>额定电压</strong>：也称为<strong>耐压值</strong>，是指在正常工作情况下，电容器两端所允许承受的最大电压值。一旦超过额定电压，极板之间的绝缘介质就会被击穿。常见的耐压值有<code>10V</code>、<code>16V</code>、<code>25V</code>、<code>50V</code>等。</li><li><strong>等效串联电阻</strong>：由于制作电容的材料具有一定的电阻性，导致工作时电信号出现损耗，这个损耗在外部会体现为一个串联的电阻，因而称为等效串联电阻（ESR），通常使用的单位为<strong>毫欧</strong>(mΩ)。通常情况下ESR 越小越好，但是某些稳压电路反而会选择具备一定 ESR 的电容器。</li><li><strong>损耗角正切值</strong>：由于电容器介电质损耗的原因，导致电容器上电压与电流的<strong>相位角</strong>并非理想的90° 度，而是偏离了一个 <span class="math inline">\(\delta\)</span>度，这个 <span class="math inline">\(\delta\)</span>角就被称为电容器的<strong>损耗角</strong>，该参数用于衡量电容器内部的<strong>电能损耗程度</strong>，因而越小越好。</li><li><strong>漏电流</strong>：虽然电容器内部的电介质对于直流电流具有阻碍作用，但是依然会有少部分漏电流通过，此参数会伴随温度与电压的升高而增大。</li></ul><h2 id="充放电特性">充放电特性</h2><p><strong>充电</strong>（电容器上获得电荷的过程）与<strong>放电</strong>（电容器上电荷流失的过程）是电容器非常重要的性质，电容器极板上存储的电荷数量与两个极板之间的电压具有一定的关系，即<strong>容值C</strong>（法拉<code>F</code>）不变的情况下，电容器储存的<strong>电荷数量Q</strong>（库伦 <code>C</code>）与其两端的<strong>电压 U</strong>（伏特<code>V</code>）呈正比：</p><p><span class="math display">\[Q = C \cdot U\]</span></p><h2 id="隔直通交特性">隔直通交特性</h2><p>电容器的一个显著特征是具有<strong>隔离直流</strong>、<strong>通过交流</strong>的特性：</p><ul><li><strong>隔直</strong>：直流电可以对电容器充电，这个过程持续时间很短，充电结束之后，直流电就无法再通过电容器。</li><li><strong>通交</strong>：由于交流电极性不断变化，电容器的充放电过程反复交替进行，因而始终会有交流电流通过电容器。</li></ul><h2 id="容抗">容抗</h2><p>电容器虽然能够通过交流信号，但是对于交流信号也存在一定的阻碍，这种阻碍作用就被称为<strong>容抗</strong>，使用<span class="math inline">\(X_C\)</span>进行表示，单位为<strong>欧姆</strong>(Ω)。电容器的<strong>容抗</strong>与交流信号的<strong>频率</strong><span class="math inline">\(f\)</span>，乃至于电容器<strong>容值</strong><span class="math inline">\(C\)</span> 之间的关系如下面公式所示：</p><p><span class="math display">\[X_C = \frac{1}{2 \pi f C}\]</span></p><p>观察这个公式可以得出结论：<strong>交流信号的频率越高，电容器的容抗就越小；或者电容器的容值越大，电容器的容抗也会越小</strong>。</p><h2 id="容值的标注">容值的标注</h2><p><strong>铝电解电容</strong>体积较大，通常使用直标法，即直接在外壳上标识出<strong>容值</strong>、<strong>耐压值</strong>、<strong>误差</strong>三个指标：</p><p><img src="/Electronics/Element/3-Capacitor/2.png"></p><p><strong>直插式瓷片电容</strong>，由于容值较小（皮法 <code>pF</code>级别），则通常会采用更为简单明了的<strong>整数标注法</strong>：</p><p><img src="/Electronics/Element/3-Capacitor/3.png"></p><ul><li>如果标注的整数值末位为 <code>0</code>，例如 <code>330</code>就表示容值为 <span class="math inline">\(330\ pF\)</span>。</li><li>如果标注的整数值末位不为 <code>0</code>，例如 <code>103</code>就表示容值为 <span class="math inline">\(10 \times 10^3\pF\)</span>。</li><li>如果标注的整数值末位为 <code>9</code>，并不是表示 <span class="math inline">\(10^9\)</span>，而是表示 <span class="math inline">\(10^{-1}\)</span>，例如 <code>339</code> 表示容值为<span class="math inline">\(3.3\ pF\)</span>。</li></ul><blockquote><p><strong>注意</strong>：对于容量较大的无极性电容器，少数情况下会采用<strong>小数点标注法</strong>，即分别使用<span class="math inline">\(\mu\)</span>、<span class="math inline">\(n\)</span>、<span class="math inline">\(p\)</span>来表示小数点，例如 <code>p1</code> 表示<code>0.1pF</code>、<code>4n7</code> 表示<code>4.7nF</code>、<code>3u3</code> 表示 <code>3.3uF</code>。</p></blockquote><h2 id="电容器误差的标注">电容器误差的标注</h2><p>电容器的误差标注方法，除了直接进行标注以外，还有<strong>罗马数字</strong>和<strong>字母</strong>两种标注方法，其中前者就是使用罗马数字的<code>0</code>、<code>Ⅰ</code>、<code>Ⅱ</code>、<code>Ⅲ</code>来分别标识误差值：</p><table><thead><tr><th style="text-align: center;">罗马数字</th><th style="text-align: center;">对应误差</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>0</strong></td><td style="text-align: center;"><code>±2%</code></td></tr><tr><td style="text-align: center;"><strong>Ⅰ</strong></td><td style="text-align: center;"><code>±5%</code></td></tr><tr><td style="text-align: center;"><strong>Ⅱ</strong></td><td style="text-align: center;"><code>±10</code></td></tr><tr><td style="text-align: center;"><strong>Ⅲ</strong></td><td style="text-align: center;"><code>±20%</code></td></tr></tbody></table><p>相应的，字母表示法则是通过在电容器上标注字母<code>B</code>、<code>C</code>、<code>D</code>、<code>F</code>、<code>G</code>、<code>J</code>、<code>K</code>、<code>M</code>、<code>N</code>、<code>Q</code>、<code>S</code>、<code>Z</code>、<code>P</code>来表示误差的大小：</p><table><thead><tr><th style="text-align: center;">字母</th><th style="text-align: center;">对应误差</th><th style="text-align: center;">字母</th><th style="text-align: center;">对应误差</th><th style="text-align: center;">字母</th><th style="text-align: center;">对应误差</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>B</strong></td><td style="text-align: center;"><code>±0.1%</code></td><td style="text-align: center;"><strong>J</strong></td><td style="text-align: center;"><code>±5%</code></td><td style="text-align: center;"><strong>S</strong></td><td style="text-align: center;"><code>+50% ~ -20%</code></td></tr><tr><td style="text-align: center;"><strong>C</strong></td><td style="text-align: center;"><code>+0.25%</code></td><td style="text-align: center;"><strong>K</strong></td><td style="text-align: center;"><code>+10%</code></td><td style="text-align: center;"><strong>Z</strong></td><td style="text-align: center;"><code>+80% ~ -20%</code></td></tr><tr><td style="text-align: center;"><strong>D</strong></td><td style="text-align: center;"><code>+0.5%</code></td><td style="text-align: center;"><strong>M</strong></td><td style="text-align: center;"><code>+20%</code></td><td style="text-align: center;"><strong>P</strong></td><td style="text-align: center;"><code>+100% ~ 0%</code></td></tr><tr><td style="text-align: center;"><strong>F</strong></td><td style="text-align: center;"><code>±1%</code></td><td style="text-align: center;"><strong>N</strong></td><td style="text-align: center;"><code>+30%</code></td><td style="text-align: center;"></td><td style="text-align: center;"></td></tr><tr><td style="text-align: center;"><strong>G</strong></td><td style="text-align: center;"><code>+2%</code></td><td style="text-align: center;"><strong>Q</strong></td><td style="text-align: center;"><code>+30% ~ -10%</code></td><td style="text-align: center;"></td><td style="text-align: center;"></td></tr></tbody></table><h2 id="陶瓷电容介质分类">陶瓷电容介质分类</h2><p><strong>多层陶瓷贴片电容器</strong>（MLCC）根据<strong>介质</strong>或者<strong>介电材料</strong>的不同，可以具体划分为<strong>NPO</strong>、<strong>COG</strong>、<strong>X7R</strong>、<strong>X5R</strong>、<strong>Y5V</strong>、<strong>Z5U</strong>六种材质，不同的介质类型会导致电容器的<code>电场响应速度</code>、<code>极化率</code>、<code>稳定性</code>、<code>介质损耗</code>、<code>容量</code>出现差异，这六种材质按照温度稳定性和容量变化率可以进一步被划分为<strong>Ⅰ</strong>、<strong>Ⅱ</strong>、<strong>Ⅲ</strong>三种类型：</p><table><colgroup><col style="width: 9%"><col style="width: 7%"><col style="width: 16%"><col style="width: 66%"></colgroup><thead><tr><th style="text-align: center;">介质类型</th><th style="text-align: left;">英文缩写名称</th><th style="text-align: left;">类型名称</th><th style="text-align: left;">温度与容量变化率</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>Ⅰ 类陶瓷电容</strong></td><td style="text-align: left;">NPO、COG</td><td style="text-align: left;">具有温度补偿特性的陶瓷电容器</td><td style="text-align: left;">温度从 <code>-55°C ~ +125°C</code>时容量变化为 <code>0±30ppm/°C</code>，电容量随频率的变化小于<code>±0.3ΔC</code>。</td></tr><tr><td style="text-align: center;"><strong>Ⅱ 类陶瓷电容</strong></td><td style="text-align: left;">X7R、X5R</td><td style="text-align: left;">温度稳定型陶瓷电容器</td><td style="text-align: left;"><strong>X7R</strong> 在<code>-55°C ~ +125°C</code> 时容值变化为<code>15%</code>，<strong>X5R</strong> 在 <code>-55°C ~ +85°C</code>时容量变化为 <code>15%</code>。</td></tr><tr><td style="text-align: center;"><strong>Ⅲ 类陶瓷电容</strong></td><td style="text-align: left;">Y5V、Z5U</td><td style="text-align: left;">具有一定温度限制的陶瓷电容器</td><td style="text-align: left;"><strong>Y5V</strong> 在<code>-30°C ~ +85°C</code> 时容值变化为<code>+22% ~ -82%</code>；<strong>Z5U</strong> 在<code>-30°C ~ +85°C</code> 时容值变化为 <code>+10% ~ -85%</code>；</td></tr></tbody></table><h2 id="电容器的串联">电容器的串联</h2><p>电容器的<strong>串联</strong>是指两个或者以上的电容器，在电路当中首尾相连，例如下面的电路：</p><p><img src="/Electronics/Element/3-Capacitor/4.png"></p><p>电容器串联之后的总容值会降低（小于容值最小的电容器），串联之后<strong>总容值</strong>的倒数等于<strong>每一个电容器</strong>容值的倒数之和，所以上面的两个电路相互等效：</p><p><span class="math display">\[\frac{1}{C} = \frac{1}{C_1} + \frac{1}{C_2}\impliesC = \frac{C_1 \cdot C_2}{C_1 + C_2} = \frac{1000pF \times 100pF}{1000pF+ 100pF} \approx 91pF\]</span></p><blockquote><p><strong>注意</strong>：电容器串联之后，<strong>容值较大</strong>的电容器两端的<strong>电压较小</strong>，而<strong>容值较小</strong>的电容器两端的<strong>电压较大</strong>。所以进行电容器选型的时候，对于容值较小的串联电容器，应当选择耐压值更高的型号。</p></blockquote><h2 id="电容器的并联">电容器的并联</h2><p>电容器的<strong>并联</strong>是指两个或者以上的电容器，在电路当中分别首首相连和尾尾相连，例如下面的电路：</p><p><img src="/Electronics/Element/3-Capacitor/5.png"></p><p>电容器并联之后的总容值会增大，<strong>总容值</strong>等于全部并联电容器的容值之和，所以上述两个电路相互等效：</p><p><span class="math display">\[C = C_1 + C_2 + C_3 = 5\mu F + 5\mu F + 10\mu F = 20 \mu F\]</span></p><blockquote><p><strong>注意</strong>：电容器并联之后，每一个电容器两端的<strong>电压都相等</strong>。所以在电容器的选型时，最好为并联电容器选择耐压值都相同的型号。</p></blockquote><h2 id="常用电容器">常用电容器</h2><table><colgroup><col style="width: 8%"><col style="width: 11%"><col style="width: 1%"><col style="width: 77%"></colgroup><thead><tr><th>名称</th><th>实物</th><th>极性</th><th>优缺点</th></tr></thead><tbody><tr><td><strong>多层陶瓷电容器</strong></td><td><img src="/Electronics/Element/3-Capacitor/6.png"></td><td>无</td><td>串联等效电阻 <strong>ESR</strong> 比较低，容值范围介于<code>0.1pF ~ 470uF</code>，耐压值介于<code>2.5V ~ 10kV</code>，可以进一步划分为 <strong>I</strong>类(温度系数相对较低)和 <strong>II</strong>类(温度系数相对较高)两种类型。</td></tr><tr><td><strong>铝电解电容器</strong></td><td><img src="/Electronics/Element/3-Capacitor/7.png"></td><td>有</td><td>铝壳顶部带有防爆纹，容值范围较宽<code>0.1uF ~ 2.2F</code>，耐压值介于<code>2.5V ~ 700V</code>，价格低廉，但是使用寿命较短，漏电流会随着温度和电压的升高而增大，过压和反接时会发生爆炸。</td></tr><tr><td><strong>铝固态聚合物电容器</strong></td><td><img src="/Electronics/Element/3-Capacitor/8.png"></td><td>有</td><td>铝壳顶部通常没有防爆纹，<strong>ESR</strong>非常低（毫欧级别），容值范围 <code>2.2uF ~ 0.02F</code>，耐压值介于<code>2V ~ 250kV</code>，价格相对较贵（通常是电解电容的 5倍），在工作温度高于 <code>105℃</code>以上时，各项参数指标会迅速恶化。</td></tr><tr><td><strong>钽电容</strong></td><td><img src="/Electronics/Element/3-Capacitor/9.png"></td><td>有</td><td><strong>ESR</strong>相对较低（欧姆级别），体积小容值大（<code>22nF ~ 0.1F</code>），耐压性能差（<code>2V ~ 125V</code>），价格昂贵，工作范围宽，使用寿命长，反接和过压发生爆炸时会出现<strong>明火</strong>，使用时需要特别注意。</td></tr></tbody></table><h2 id="安规电容器">安规电容器</h2><p><strong>安规电容</strong>也被称为 <strong>EMI抑制电容器</strong>，顾名思义在电路里主要用于减少电磁干扰，通常用于电源电路当中，可以滤除雷电或者插拔插座带来的高频脉冲，这类电容必须通过如下一系列的安全规范测试认证：</p><p><img src="/Electronics/Element/3-Capacitor/10.png"></p><p><strong>X 电容</strong>通常使用的是聚酯材料，用于滤除<strong>差模干扰</strong>，使用时主要放置在<strong>零线</strong>与<strong>火线</strong>之间：</p><p><img src="/Electronics/Element/3-Capacitor/11.png"></p><p><strong>Y 电容</strong>通常使用的是陶瓷材料，用于滤除<strong>共模干扰</strong>，使用时分别放置在<strong>火线</strong>与<strong>地</strong>、<strong>零线</strong>与<strong>地</strong>之间：</p><p><img src="/Electronics/Element/3-Capacitor/12.png"></p><p>对于 <strong>X 电容</strong> 和 <strong>Y 电容</strong>的选型，主要关注的参数是其可以耐受的<strong>浪涌峰值电压</strong>（通常在千伏左右），两者通常配合起来使用，其典型的应用电路如下所示（图中的<code>L</code> 表示<strong>火线</strong>，<code>N</code>表示<strong>零线</strong>，<code>G/PE</code>表示<strong>地线</strong>）：</p><p><img src="/Electronics/Element/3-Capacitor/13.png"></p><blockquote><p><strong>注意</strong>：<strong>X2</strong>（浪涌峰值电压小于或等于<code>2.5KV</code>）和 <strong>Y2</strong>（浪涌峰值电压为<code>5KV</code>）<strong>子类</strong>是国内比较常用的安规电容。</p></blockquote><h1 id="电感器-inductor">电感器 Inductor</h1><p>将导线在<strong>绝缘支架</strong>上绕制出一定的匝数就可以构成一个<strong>电感器</strong>，其电路符号如下图所示：</p><p><img src="/Electronics/Element/4-Inductance/1.png"></p><p>根据绕制支架材料的不同，可以将其划分为：<strong>空心电感器</strong>(无支架)、<strong>磁芯电感器</strong>(磁性材料支架)、<strong>铁芯电感器</strong>(硅钢片支架)：</p><p><img src="/Electronics/Element/4-Inductance/2.png"></p><p>电感器在电路当中，主要具备如下几个用途：</p><ul><li><strong>功率电感</strong>：主要用于电压转换，例如 DC-DC电路都需要使用到功率电感。</li><li><strong>去耦电感</strong>：主要用于 EMC滤除电源线或者信号线上面的噪声，也就是所谓的<strong>扼流圈</strong>。</li><li><strong>高频电感</strong>：主要用于射频电路，实现偏置、匹配、滤波等功能。</li></ul><h2 id="电感量">电感量</h2><p>当电感器通过电流时就会产生<strong>磁场</strong>，电流越大产生的磁场就会越强，穿过电感器的磁通量也就会越大。磁场的<strong>磁感线方向</strong>与<strong>电流方向</strong>遵循<strong>右手螺旋定则</strong>，也称为<strong>安培定则</strong>：右手握住电感线圈，让大拇指指向<strong>磁场</strong>的方向（从<strong>N</strong> 极出发回到 <strong>S</strong>极），那么其余四指所指向的就是<strong>电流</strong>的方向：</p><p><img src="/Electronics/Element/4-Inductance/3.png"></p><p>穿过电感器的<strong>磁通量</strong> <span class="math inline">\(\varPhi\)</span>与通过电感器的<strong>电流</strong> <span class="math inline">\(I\)</span>的比值叫做<strong>自感系数</strong>，也被称为<strong>电感量</strong>，通常使用字母<strong>L</strong> 进行表示：</p><p><span class="math display">\[L = \frac{\varPhi}{I}\]</span></p><p>电感量的基本单位为<strong>亨利</strong>，简称<strong>亨</strong>(H)，常用的单位还有<strong>毫亨</strong>(mH)、<strong>微亨</strong>(uH)，它们之间的换算关系如下面所示：</p><p><span class="math display">\[1H = 10^3mH = 10^6 \mu H\]</span></p><p>电感器所具有的电感量大小，主要取决于线圈的匝数、绕制的方式，以及磁芯的材料：</p><ol type="1"><li>线圈<strong>匝数</strong>越多，绕制的线圈就会越密集，电感量也就会越大；</li><li><strong>有磁芯</strong>的电感器，相比<strong>无磁芯</strong>的电感器的电感量要更大:</li><li>电感器磁芯的<strong>磁导率</strong>越高，其电感量也就会越大。</li></ol><h2 id="感抗">感抗</h2><p>电感器对于直流信号的阻碍非常小，而对于交流信号的阻碍非常大，也就是所谓的<strong>通直隔交</strong>。导致这种现象出现的原因，是由于变化的电信号通过电感器时，会让电感器产生<strong>自感电动势</strong>来阻碍这个变化的电信号。</p><p>电感器对于交流信号的这种阻碍作用称为<strong>感抗</strong>，其单位为<strong>欧姆</strong><code>Ω</code>，电感器<strong>感抗</strong> <span class="math inline">\(X_L\)</span>(欧姆)的大小与其<strong>电感量</strong> <span class="math inline">\(L\)</span> (亨利)以及通过的<strong>频率</strong><span class="math inline">\(f\)</span> (赫兹)相关：</p><p><span class="math display">\[X_L = 2\pi fL\]</span></p><blockquote><p><strong>注意</strong>：通过的信号频率 <span class="math inline">\(f\)</span> 越高，电感器的感抗 <span class="math inline">\(X_L\)</span> 也就越大。电感器的电感量 <span class="math inline">\(L\)</span> 越大，其对交流信号的感抗 <span class="math inline">\(X_L\)</span> 也就会越大。</p></blockquote><h2 id="品质因数-q-值">品质因数 Q 值</h2><p><strong>品质因数</strong>当向电感器两端施加特定<strong>频率</strong><span class="math inline">\(f\)</span>的交流信号时，其<strong>感抗</strong> <span class="math inline">\(X_L\)</span> 与<strong>直流电阻</strong> <span class="math inline">\(R\)</span>的比值被称为<strong>品质因数</strong>。该参数是衡量电感器品质的一个重要参数，通常也被称作<strong>Q 值</strong>：</p><p><span class="math display">\[Q = \frac{X_L}{R}\]</span></p><blockquote><p><strong>注意</strong>：品质因数通常用于表征储能元件（电感器、电容器）<strong>储存能量</strong>与<strong>损耗能量</strong>的比值，品质因数越<strong>大</strong>，表示吸收与储存能量的损耗就越小，转换效率就会越高。</p></blockquote><h2 id="电感器的选型">电感器的选型</h2><p>按照电感器在电路当中的用处，还可以将其大致划分为用于<strong>信号系统</strong>的<strong>高频电感器</strong>，以及用于<strong>电源系统</strong>的<strong>功率电感器</strong>：</p><p><img src="/Electronics/Element/4-Inductance/4.png"></p><p><strong>高频电感器</strong>主要运用在信号频率介于 <code>MHz</code>或者 <code>GHz</code> 的场景，对于 Q值的要求非常高，通常会采用空心结构，其主要用途如下表所示：</p><p><img src="/Electronics/Element/4-Inductance/5.png"></p><p><strong>功率电感器</strong>主要被运用在电源电路当中，有时候也被称作<strong>工字型电感</strong>，其主要用途如下面的表格所示：</p><p><img src="/Electronics/Element/4-Inductance/6.png"></p><p>电感器的选型，除了电感量这个参数之外，还需要重点关注如下几个参数：</p><ul><li><strong>温升额定电流</strong>：以电感器的发热量（温升为<code>40℃</code>）作为指标的额定电流。</li><li><strong>电感值变化率额定电流</strong>：由通电时<strong>磁饱和</strong>所导致的电感值下降（直流叠加特性）作为指标的额定电流。</li><li><strong>工作温度范围</strong>：电感器正常工作的时候，环境温度所允许的范围。</li><li><strong>直流阻抗</strong>：能够通过的直流信号阻抗值，直流阻抗越小，损耗也就越少。</li></ul><blockquote><p><strong>注意</strong>：电路当中经常使用到的<strong>扼流圈</strong>，本质也是一种可以扼制交流信号通过的电感线圈，它利用<strong>感抗</strong><span class="math inline">\(X_L\)</span> 与<strong>频率</strong> <span class="math inline">\(f\)</span>呈正比的关系，从而能够扼制特定频率的交流信号通过电感器。</p></blockquote><h2 id="共模-差模噪声">共模 &amp; 差模噪声</h2><p>导线上的<strong>传导噪声</strong>可以划分为<strong>差模噪声</strong>和<strong>共模噪声</strong>两种类型，在下面的示意图当中，把PCB 电路板安装在了一个外壳里面：</p><p><img src="/Electronics/Element/4-Inductance/7.png"></p><ul><li><strong>差模噪声</strong>：产生于电源线之间，由噪声信号串入电源线导致。噪声信号<strong>流入</strong>与<strong>流出</strong>两条电源线的方向<strong>相反</strong>，所以被称为<strong>差模</strong>（DifferentialMode）。</li><li><strong>共模噪声</strong>：由于噪声信号通过大地之后，再返回电源线所导致，噪声信号<strong>流入</strong>与<strong>流出</strong>两条电源线的方向<strong>相同</strong>，所以被称为<strong>共模</strong>（CommonMode）。</li></ul><h2 id="共模-差模电感">共模 &amp; 差模电感</h2><p><strong>共模电感</strong>是一种用于滤除共模干扰信号的专用元器件，通常被运用在开关电源当中，可以滤除EMI 电磁干扰，或者抑制高速信号传输时产生的电磁辐射。</p><p><img src="/Electronics/Element/4-Inductance/8.png"></p><p>共模电感的工作原理是基于其特殊的<strong>双绕组结构</strong>：两个线圈绕制在相同的铁芯上面（匝数和相位相同，但是绕制的方向相反），从而形成一个<strong>四端元件</strong>。因而拥有4个外接引脚（这是共模电感器的典型外观特征），共模电感在电路原理图当中使用如下符号进行表示：</p><p><img src="/Electronics/Element/4-Inductance/9.png"></p><ol type="1"><li>当<strong>差模干扰信号</strong>经过共模电感时，信号会在同相位绕制的电感线圈中产生<strong>反向</strong>的磁场而相互抵消，此时正常信号电流只会受到线圈自身电阻的影响。</li><li>当<strong>共模干扰信号</strong>流过共模电感时，由于共模信号的同向性，就会在线圈内产生<strong>相同方向</strong>的磁场，进而增大线圈的感抗，致使线圈表现为高阻抗，从而衰减共模信号达到滤除的目的。</li></ol><p>相应的，<strong>差模电感</strong>本质上就是就是普通的绕线电感（两个引脚），其主要用于滤除差模干扰信号，通常被运用在一些<strong>大电流</strong>的场合，结构较为简单（主要由铁芯上绕制的线圈构成）。经常在电源电路当中，与电容一起构成用于减小噪声的LC 滤波器。</p><h2 id="磁珠">磁珠</h2><p><strong>磁珠</strong>对于高频信号具有较大的阻碍作用（将其转换为<strong>热能</strong>），主要用于抑制<strong>信号线</strong>、<strong>电源线</strong>上面的高频噪声与尖峰干扰。磁珠的单位是按照其在某一频率（通常为<code>100MHz</code>）下产生的<strong>阻抗</strong>来进行标识的，所以其采用<strong>欧姆</strong><code>Ω</code> 作为单位（而非<strong>亨利</strong>）：</p><p><img src="/Electronics/Element/4-Inductance/10.png"></p><p>通常情况下，制作<strong>磁珠</strong>的材料是<strong>铁氧体</strong>，大部分<strong>磁珠</strong>都会被制作为贴片元器件，只有<strong>穿芯磁珠</strong>属于直插式元器件。</p><blockquote><p><strong>注意</strong>：磁珠在选型时要重点关注其<code>标称阻抗@测试频率</code>、<code>直流电阻</code>、<code>额定工作电流</code>三个参数。</p></blockquote><h1 id="变压器-transformer">变压器 Transformer</h1><p><strong>变压器</strong>基于 <code>电→磁</code> 和 <code>磁→电</code>的转换原理，主要用于调整交流电压与电流的大小，通常由绝缘铜质线圈绕制而成的<strong>绕组</strong>（漆包线）和具备导磁性能的<strong>铁/磁芯</strong>（E形、C形、环形）构成，其电路符号（下图左）和结构示意图（下图右）分别如下所示：</p><p><img src="/Electronics/Element/5-Transformer/1.png"></p><p>其中，连接到输入端的绕组称为<strong>一次绕组</strong>或者<strong>初级绕组</strong>（源边），而连接至输出端的绕组被称为<strong>二次绕组</strong>或者<strong>次级绕组</strong>（副边）。变压器按照用途，可以进一步被划分为<strong>电源变压器</strong>、<strong>隔离变压器</strong>、<strong>信号处理变压器</strong>、<strong>电流互感器</strong>等。</p><h2 id="工作原理">工作原理</h2><p>当<strong>交流电压</strong> <span class="math inline">\(U_1\)</span>传递到变压器的<strong>一次绕组</strong> <span class="math inline">\(L_1\)</span>（<strong>匝数</strong>为 <span class="math inline">\(N_1\)</span>）两端时，就会有交流电流 <span class="math inline">\(I_1\)</span> 通过 <span class="math inline">\(L_1\)</span>，导致 <span class="math inline">\(L_1\)</span>立刻产生磁场，磁场的磁感线沿着具备导磁能力的铁芯或者磁芯穿过<strong>二次绕组</strong><span class="math inline">\(L_2\)</span>（匝数为 <span class="math inline">\(N_2\)</span>），使得 <span class="math inline">\(L_2\)</span>绕组马上产生方向相反的<strong>感应电动势</strong>。</p><p><img src="/Electronics/Element/5-Transformer/2.png"></p><p>此时 <span class="math inline">\(L_2\)</span> 与<strong>电阻</strong><span class="math inline">\(R\)</span>形成闭合电路，开始输出<strong>交流电流</strong> <span class="math inline">\(I_2\)</span>，电阻 <span class="math inline">\(R\)</span> 两端的<strong>电压</strong>为 <span class="math inline">\(U_2\)</span>。概而言之，变压器的<strong>一次绕组</strong>进行的是<strong>电→ 磁</strong>转换，而<strong>二次绕组</strong>进行的则是<strong>磁 →电</strong>转换。</p><h2 id="交流电压的转换">交流电压的转换</h2><p>变压器可以改变<strong>交流电压</strong>，在忽略电能损耗的情况下，变压器的<strong>一次电压</strong><span class="math inline">\(U_1\)</span>、<strong>二次电压</strong><span class="math inline">\(U_2\)</span> 与<strong>一次绕组匝数</strong><span class="math inline">\(N_1\)</span>、<strong>二次绕组匝数</strong><span class="math inline">\(N_2\)</span> 的关系如下所示，其中的<code>n</code>被称为<strong>匝数比</strong>或者<strong>电压比</strong>：</p><p><span class="math display">\[\frac{U_1}{U_2} = \frac{N_1}{N_2} = n\]</span></p><ol type="1"><li>当一次绕组匝数 <span class="math inline">\(N_1\)</span><strong>少于</strong>二次绕组的匝数 <span class="math inline">\(N_2\)</span> 时，一次电压 <span class="math inline">\(U_1\)</span> 就会<strong>低于</strong>二次电压<span class="math inline">\(U_2\)</span>。换而言之，当 <span class="math inline">\(\frac{N_1}{N_2} = n &lt; 1\)</span>的时候，变压器可以提高交流电压（同时也降低了输出电流），即<strong>升压变压器</strong>。</li><li>当一次绕组匝数 <span class="math inline">\(N_1\)</span><strong>多于</strong>二次绕组的匝数 <span class="math inline">\(N_2\)</span> 时，一次电压 <span class="math inline">\(U_1\)</span> 就会<strong>高于</strong>二次电压<span class="math inline">\(U_2\)</span>。换而言之，当 <span class="math inline">\(\frac{N_1}{N_2} = n &gt; 1\)</span>的时候，变压器可以降低交流电压（同时也提高了输出电流），即<strong>降压变压器</strong>。</li><li>当一次绕组匝数 <span class="math inline">\(N_1\)</span><strong>等于</strong>二次绕组的匝数 <span class="math inline">\(N_2\)</span> 时，一次电压 <span class="math inline">\(U_1\)</span> 就会<strong>等于</strong>二次电压<span class="math inline">\(U_2\)</span>。换而言之，当 <span class="math inline">\(\frac{N_1}{N_2} = n = 1\)</span>的时候，虽然变压器不会改变交流电压的大小，但是依然能够起到电气隔离的作用，也就是所谓的<strong>隔离变压器</strong>。</li></ol><h2 id="交流电流的转换">交流电流的转换</h2><p>变压器在改变交流电压大小的同时，也会相应的改变交流电流的大小。假设变压器对于电能的损耗较小，根据<strong>功率守恒定律</strong>，可以将变压器的<strong>输入功率</strong><span class="math inline">\(P_1\)</span> 与<strong>输出功率</strong><span class="math inline">\(P_2\)</span>视为相等，从而可以得到如下的推导过程：</p><p><span class="math display">\[P_1 = P_2 \implies U_1 \cdot I_1 = U_2 \cdot I_2 \implies\frac{U_1}{U_2} = \frac{I_2}{I_1}\]</span></p><p>根据上述的推导过程，可以知道变压器的一二次电压 <span class="math inline">\(U_1\)</span> 和 <span class="math inline">\(U_2\)</span> 与一二次电流 <span class="math inline">\(I_1\)</span> 和 <span class="math inline">\(I_2\)</span>呈现出<strong>反比关系</strong>。换而言之，变压器的<strong>匝数</strong>越多，绕组两端的<strong>电压</strong>就会越高，通过的<strong>电流</strong>相应的也就会越小。</p><p><img src="/Electronics/Element/5-Transformer/3.png"></p><p>例如上面这个输入电压为 <code>220V</code>，输出电压为 <code>12V</code>的<strong>电源变压器</strong>，它的一次绕组与二次绕组的<strong>匝数比</strong><code>n</code>，可以基于如下的计算获得：</p><p><span class="math display">\[n = \frac{U_1}{U_2} = \frac{220V}{12V} = \frac{55}{3}\xrightarrow{电压与电流成反比关系} \frac{I_2}{I_1} = \frac{55}{3}\approx 18.33\]</span></p><p>根据上面的推导过程可以得出结论：该变压器二次绕组的<strong>输出电流</strong>是一次绕组<strong>输入电流</strong>的<code>18.33</code> 倍。</p><h2 id="符号与结构">符号与结构</h2><p>接下来的表格里，展示了各种常见的变压器符号，并对其结构进行了简要的说明：</p><table><colgroup><col style="width: 11%"><col style="width: 88%"></colgroup><thead><tr><th>变压器符号</th><th>功能描述</th></tr></thead><tbody><tr><td><img src="/Electronics/Element/5-Transformer/4.png"></td><td>该变压器拥有 2 组二次绕组，其中 <code>3 ~ 4</code> 为一组，而<code>5 ~ 6</code>为另一组。符号中的<strong>虚线</strong>表示一次和二次绕组之间存在着<strong>屏蔽层</strong>（接地，起到抗干扰作用），通常表示的是<strong>电源变压器</strong>。</td></tr><tr><td><img src="/Electronics/Element/5-Transformer/5.png"></td><td>一次和二次绕组的一端标记的<strong>黑点</strong>表示的是变压器的<strong>同名端</strong>，表示这两处的<strong>电压极性相同</strong>。</td></tr><tr><td><img src="/Electronics/Element/5-Transformer/6.png"></td><td>该变压器的一次和二次绕组之间<strong>没有实线</strong>，即表示该变压器没有<strong>铁芯</strong>或者<strong>磁芯</strong>。</td></tr><tr><td><img src="/Electronics/Element/5-Transformer/7.png"></td><td>变压器的<strong>二次绕组</strong>上面存在着一个<strong>抽头</strong>，也就是二次绕组<code>3 ~ 5</code> 之间的 <code>4</code> 号引脚。</td></tr><tr><td><img src="/Electronics/Element/5-Transformer/8.png"></td><td>变压器的<strong>一次绕组</strong>上面存在一个<strong>抽头</strong>（即<code>2</code> 号引脚），表示可以输入不同电压的交流电。</td></tr><tr><td><img src="/Electronics/Element/5-Transformer/9.png"></td><td>变压器只拥有<strong>一个绕组</strong>，其中的 <code>2</code>号引脚是其抽头，也被称作<strong>自耦变压器</strong>。如果将<code>2 ~ 3</code> 作为一次绕组，而 <code>1 ~ 3</code>作为二次绕组，就可以将其视为一个<strong>升压变压器</strong>；而如果把<code>1 ~ 3</code> 作为一次绕组，而 <code>2 ~ 3</code>作为二次绕组，则可以将其视为一个<strong>降压变压器</strong>。</td></tr></tbody></table><blockquote><p><strong>注意</strong>：变压器的<strong>同名端</strong>（极性相同的端口，通常在电路图当中使用实心黑点进行标注）和<strong>异名端</strong>（极性相反的端口）描述的是<code>初级绕组</code>与<code>次级绕组</code>之间的<strong>缠绕方式</strong>和<strong>极性关系</strong>。</p></blockquote><h2 id="变压器选型指标">变压器选型指标</h2><p>实际工作当中进行变压器的选型时，除了<strong>变压比/匝数比</strong><code>n</code> 之外，还需要关注下面几个性能指标：</p><ul><li><strong>额定功率</strong>：在规定频率和电压之下，变压器长时间工作而不超过规定温升的最大输出功率，单位为<strong>伏安</strong>(<code>V·A</code>)。由于额定功率当中会存在一部分<strong>无功功率</strong>，所以这里不会使用<strong>瓦特</strong>(<code>W</code>)作为单位。</li><li><strong>绝缘电阻</strong>：实际的变压器，很难在绕组与铁/磁芯之间做到完全绝缘，因而变压器<strong>绝缘电阻</strong>指标的大小（等于<span class="math inline">\(\frac{典型测试电压}{变压器漏电流}\)</span>，通常在<strong>兆欧</strong><code>MΩ</code>级别），不仅关系到变压器本身的质量，还关系到用电安全，选型时需要额外注意。</li><li><strong>转换效率</strong>：表示变压器正常工作时，对于电能的损耗程度，其值等于<span class="math inline">\(\frac{输出功率}{输入功率}\)</span>的百分比。</li><li><strong>温升</strong>：变压器通电之后，其工作温度上升至稳定值时，比环境温度高出的数值（该参数越小越好）。</li></ul><h1 id="二极管-diode">二极管 Diode</h1><p><strong>半导体</strong>是导电性能介于导体与绝缘体之间的材料，根据掺杂元素的情况，可以具体划分为<code>本征半导体</code>、<code>N 型半导体</code>、<code>P 型半导体</code>三种类型：</p><ol type="1"><li><strong>本征半导体</strong>：纯净的半导体（原子核最外层有 4个电子的<code>硅</code>、<code>锗</code>、<code>硒</code>等），导电能力较弱（掺入杂质后可通过富余的空穴和电子提高导电能力）。</li><li><strong>N型半导体</strong>：向纯净半导体中掺入<strong>五价元素</strong>（原子核最外层只有5个电子的<code>磷</code>、<code>砷</code>、<code>锑</code>等），半导体中存在大量带有<strong>负电荷</strong>的<strong>电子</strong>。</li><li><strong>P型半导体</strong>：向纯净半导体中掺入<strong>三价杂质</strong>（原子核最外层只有3个电子的<code>硼</code>、<code>铝</code>、<code>镓</code>等），半导体中存在大量带有<strong>正电荷</strong>的<strong>空穴</strong>。</li></ol><p>当包含有空穴的 <strong>P 型半导体</strong>和包含有电子的 <strong>N型半导体</strong>结合在一起时，由于两边正负电荷的相互扩散，就会在 P 型和N 型半导体中间形成 <strong>PN 结</strong>：</p><p><img src="/Electronics/Element/6-Diode/1.png"></p><p>从包含有 PN 结的<strong>P 型半导体</strong>和 <strong>N型半导体</strong>两端，分别引出一个电极并且封装起来，就构成了<strong>二极管</strong>，其基本结构与电路符号如下面示意图所示：</p><p><img src="/Electronics/Element/6-Diode/2.png"></p><blockquote><p><strong>注意</strong>：<strong>P型</strong>半导体一侧引出的电极称为<strong>正极</strong>（Positive），<strong>N型</strong>半导体一侧引出的电极称为<strong>负极</strong>（Negative）。</p></blockquote><h2 id="单向导电性">单向导电性</h2><p>二极管具有<strong>正向导通、反向截止</strong>的特性，也就是所谓的二极管的<strong>单向导电性</strong>：</p><p><img src="/Electronics/Element/6-Diode/3.png"></p><ul><li><strong>正向导通</strong>：二极管的<strong>正极</strong>连接电源的<strong>正极</strong>，而<strong>负极</strong>连接电源的<strong>负极</strong>，此时二极管处于导通状态。</li><li><strong>反向截止</strong>：二极管的<strong>正极</strong>连接电源的<strong>负极</strong>，而<strong>负极</strong>连接电源的<strong>正极</strong>，此时二极管处于截止状态。</li></ul><h2 id="伏安特性曲线">伏安特性曲线</h2><p>二极管的<strong>伏安特性曲线</strong>用来说明施加到二极管两端的<strong>电压</strong><span class="math inline">\(U\)</span> 与通过的<strong>电流</strong><span class="math inline">\(I\)</span>之间的关系（第一象限的曲线描述的是二极管的<strong>正向特性</strong>，而第三象限的曲线描述的则是二极管的<strong>反向特性</strong>）：</p><p><img src="/Electronics/Element/6-Diode/4.png"></p><ul><li><strong>正向特性</strong>：即二极管被施加<strong>正向电压</strong>（二极管正极接高电位，负极接低电位）时表现出的特性，向二极管施加正向电压时不一定能导通，只有正向电压达到<strong>正向导通电压</strong>时才能够导通。</li><li><strong>反向特性</strong>：即二极管被施加<strong>反向电压</strong>（二极管正极接低电位，负极接高电位）时表现出的特性，向二极管施加反向电压时并不一定会导通，只有达到其<strong>反向击穿电压</strong>的时候，才会由于被反向击穿，导致通过电流急剧增大，进而失去单向导电性。</li></ul><blockquote><p><strong>注意</strong>：<strong>硅基二极管</strong>的正向导通电压通常为<code>0.7V</code>，而<strong>锗基二极管</strong>的正向导通电压一般为<code>0.3V</code>。</p></blockquote><h2 id="性能参数">性能参数</h2><p>阅读二极管数据手册进行选型工作的时候，需要重点关注下面表格当中列出的参数指标：</p><table><colgroup><col style="width: 13%"><col style="width: 6%"><col style="width: 79%"></colgroup><thead><tr><th style="text-align: left;">参数名称</th><th style="text-align: center;">符号</th><th style="text-align: left;">参数功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>反向电流</strong></td><td style="text-align: center;"><span class="math inline">\(I_R\)</span></td><td style="text-align: left;">二极管反向截止时，通过二极管的<strong>漏电流</strong>（通常在<strong>微安</strong><code>uA</code> 级别）。</td></tr><tr><td style="text-align: left;"><strong>正向电流</strong></td><td style="text-align: center;"><span class="math inline">\(I_F\)</span></td><td style="text-align: left;">二极管长时间正向导通时，在允许温升的条件下，所通过的最大平均电流值（该参数与PN 结的尺寸以及封装的散热能力有关）。</td></tr><tr><td style="text-align: left;"><strong>正向电压</strong></td><td style="text-align: center;"><span class="math inline">\(V_F\)</span></td><td style="text-align: left;">二极管正向导通时，当 <span class="math inline">\(I_F\)</span> 为额定电流值（例如<code>10mA</code>、<code>20mA</code>）的时候，所测得的导通电压。</td></tr><tr><td style="text-align: left;"><strong>最大反向峰值电压</strong></td><td style="text-align: center;"><span class="math inline">\(V_{RRM}\)</span></td><td style="text-align: left;">二极管反向截止时，二极管所允许承受的最大反向重复峰值电压。</td></tr><tr><td style="text-align: left;"><strong>最大有效值电压</strong></td><td style="text-align: center;"><span class="math inline">\(V_{RMS}\)</span></td><td style="text-align: left;">二极管所能承受最大交流电压的有效值（峰值电压的<code>0.707</code> 倍）。</td></tr><tr><td style="text-align: left;"><strong>正向峰值浪涌电流</strong></td><td style="text-align: center;"><span class="math inline">\(I_{FSM}\)</span></td><td style="text-align: left;">二极管正向导通时，在特定的短暂时间内（例如<code>8.3 ms</code>），最大所允许通过的瞬时电流，一旦超过将会导致损坏。</td></tr><tr><td style="text-align: left;"><strong>PN 结工作温度</strong></td><td style="text-align: center;"><span class="math inline">\(T_J\)</span></td><td style="text-align: left;">PN 结长时间正常工作时的温度范围，例如<code>–55°C ~ +150°C</code>。</td></tr><tr><td style="text-align: left;"><strong>典型 PN 结电容</strong></td><td style="text-align: center;"><span class="math inline">\(C_J\)</span></td><td style="text-align: left;">二极管反向截止时，施加 <code>4.0V</code>的反向电压，在 <code>1MHz</code> 频率下测得的 PN 结电容值。</td></tr><tr><td style="text-align: left;"><strong>反向恢复时间</strong></td><td style="text-align: center;"><span class="math inline">\(t_{rr}\)</span></td><td style="text-align: left;">二极管从正向导通状态，切换至反向截止状态所需要的时间。</td></tr></tbody></table><blockquote><p><strong>注意</strong>：通常情况下，普通二极管带有<strong>划线标记</strong>的一端为<strong>负极</strong>，而另外一端则属于<strong>正极</strong>。</p></blockquote><h2 id="整流二极管">整流二极管</h2><p>利用二极管的单向导电特性，可以将交流电转换为直流电。因为只有在交流电的正半周，二极管才会导通，而在交流电的负半周，二极管不会导通，所以整流二极管只会保留交流电的<strong>正半周</strong>，这种方式称作<strong>半波段整流</strong>：</p><p><img src="/Electronics/Element/6-Diode/5.png"></p><p>要实现<strong>全波段整流</strong>的效果，提升转换效率，则必须使用<strong>整流桥</strong>，这是一种由多个二极管组合在一起构成的元器件（整流桥<strong>缺角</strong>的一端属于<strong>正极</strong>）：</p><p><img src="/Electronics/Element/6-Diode/6.png"></p><p>整流桥也称为<strong>桥式整流器</strong>，其通常带有四个引脚（其中标注有<code>~</code> 的两个引脚为<strong>交流输入端</strong>，而分别标注有<code>+</code> 和 <code>-</code>的则属于<strong>直流输出端</strong>），典型的应用电路如下图所示：：</p><p><img src="/Electronics/Element/6-Diode/7.png"></p><h2 id="开关二极管">开关二极管</h2><p><strong>开关二极管</strong>正是利用了二极管的<strong>正向导通、反向截止</strong>特性，实现了类似开关一样的功能，并且开关速度极为迅速：</p><p><img src="/Electronics/Element/6-Diode/8.png"></p><p>开关二极管最大的特点在于它的<strong>反向恢复时间</strong> <span class="math inline">\(t_{rr}\)</span>通常在<code>纳秒</code>级别，而普通二极管的 <span class="math inline">\(t_{rr}\)</span> 则在<code>微秒</code>级别：</p><p><img src="/Electronics/Element/6-Diode/9.png"></p><p>向开关二极管施加<strong>正向电压</strong>时电流通过（表示打开），施加<strong>反向电压</strong>时电流停止（表示关闭），具体过程可以参考下面的示意图：</p><p><img src="/Electronics/Element/6-Diode/10.png"></p><h2 id="肖特基二极管">肖特基二极管</h2><p>肖特基二极管也称为<strong>肖特基势垒二极管</strong>（SBD，SchottkyBarrier Diode），利用的是<strong>金属</strong>与 <strong>N型半导体</strong>结合时，所产生的<strong>肖特基势垒</strong>原理。具有较低的<strong>正向压降</strong>和<strong>结电容</strong>，以及较高的<strong>开关速度</strong>（相比于传统的硅锗半导体二极管，其<strong>反向漏电流</strong>比较高，而<strong>反向击穿电压</strong>比较低，选型时需要格外注意）：</p><p><img src="/Electronics/Element/6-Diode/11.png"></p><p>肖特基二极管的优点在于<strong>正向导通电压</strong> <span class="math inline">\(V_F\)</span>相比普通二极管更低，通过相同电流时所消耗的功率更少。同时<strong>反向恢复时间</strong><span class="math inline">\(t_{rr}\)</span>非常短，开关频率特别高。而缺点在于<strong>漏电流</strong> <span class="math inline">\(I_R\)</span>比较大，可能会因为持续的发热而损毁，使用时需要特别注意：</p><p><img src="/Electronics/Element/6-Diode/12.png"></p><h2 id="齐纳稳压二极管">齐纳稳压二极管</h2><p><strong>稳压二极管</strong>也称为<strong>齐纳二极管</strong>（ZenerDiode），通常在电路当中起到稳压的作用，其电路符号如下图所示：</p><p><img src="/Electronics/Element/6-Diode/13.png"></p><p>稳压二极管使用的时候，需要<strong>反接</strong>在电路当中（负极接高电位，正极接低电位），其<strong>正接</strong>时的性质与普通二极管相同：</p><p><img src="/Electronics/Element/6-Diode/14.png"></p><p>下面的电路是稳压二极管的典型接法，其中的 <span class="math inline">\(E\)</span> 代表<strong>电压源</strong>，而 <span class="math inline">\(U_{VZ}\)</span>代表的是<strong>稳压二极管</strong>（稳压值为<code>5V</code>）的输出电压：</p><p><img src="/Electronics/Element/6-Diode/15.png"></p><ol type="1"><li>当外加电压<strong>低于</strong>稳压二极管的<strong>稳压值</strong>时，稳压二极管<strong>无法导通</strong>，此时没有稳压功能（这种情况下，如果上述电路当中的<span class="math inline">\(E = 4V\)</span>，那么 <span class="math inline">\(U_{VZ} = 4V\)</span>）。</li><li>当外加电压<strong>高于</strong>稳压二极管的<strong>稳压值</strong>时，稳压二极管<strong>反向击穿</strong>导通，并且会保持两端电压不变，电压的大小等于稳压值（这种情况下，如果上述电路当中的<span class="math inline">\(E = 8V\)</span>，那么 <span class="math inline">\(U_{VZ} = 5V\)</span>）。</li></ol><p>进行稳压二极管选型的时候，需要特别关注如下表格当中的三个参数：</p><table><colgroup><col style="width: 10%"><col style="width: 7%"><col style="width: 82%"></colgroup><thead><tr><th style="text-align: left;">参数名称</th><th style="text-align: center;">符号</th><th style="text-align: left;">参数功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>稳压范围</strong></td><td style="text-align: center;"><span class="math inline">\(V_{ZT}\)</span></td><td style="text-align: left;">也称为<strong>齐纳电压范围</strong>，稳压二极管工作在反向击穿状态时，两端的电压范围。</td></tr><tr><td style="text-align: left;"><strong>反向电流</strong></td><td style="text-align: center;"><span class="math inline">\(I_R\)</span></td><td style="text-align: left;">稳压二极管正常工作时所允许通过的反向电流。</td></tr><tr><td style="text-align: left;"><strong>耗散功率</strong></td><td style="text-align: center;"><span class="math inline">\(P_D\)</span></td><td style="text-align: left;">稳压二极管通过反向电流时允许消耗的最大功率，其值等于稳压值<span class="math inline">\(V_{ZT}\)</span> 与反向电流 <span class="math inline">\(I_R\)</span> 的乘积。</td></tr></tbody></table><blockquote><p><strong>注意</strong>：为了确保稳压二极管能够可靠工作，使用的时候总是需要串联上一枚<strong>限流电阻</strong>。</p></blockquote><h2 id="瞬态电压抑制二极管">瞬态电压抑制二极管</h2><p><strong>瞬态电压抑制二极管</strong>（TVS，Transient VoltageSuppressors）是一种用于<strong>过电压保护</strong>和<strong>静电释放</strong>（ESD，Electro-staticDischarge）的元器件，当两极之间的电压超过一定值时，就能够以极快的速度导通，并且钳制电压到预定值范围。根据导通方向的不同，可以将其划分为<strong>单向型</strong>和<strong>双向型</strong>两种类型：</p><p><img src="/Electronics/Element/6-Diode/16.png"></p><p>瞬态电压抑制二极管通常会在<strong>接地</strong>之后，<strong>并联</strong>在电路当中使用。下面的电路将瞬态电压抑制二极管并联在电源与IC之间，当电路正常工作时，二极管处于<strong>截止状态</strong>，只会消耗一定的<strong>漏电流</strong>。而当电路上出现<strong>浪涌电压</strong>的时候，二极管就会转换为<strong>导通状态</strong>，此时耗散的则是<strong>脉冲电流</strong>，同时还会钳制通过的电压，进而保护后级IC 的正常稳定工作：</p><p><img src="/Electronics/Element/6-Diode/17.png"></p><p>瞬态电压抑制二极管的<strong>极性</strong>，主要用于标识其保护作用属于<strong>单向</strong>还是<strong>双向</strong>，通常情况下采用的都是双向瞬态电压抑制二极管，因为它可以同时钳制浪涌电压的<strong>正负脉冲</strong>：</p><p><img src="/Electronics/Element/6-Diode/18.png"></p><blockquote><p><strong>注意</strong>：<strong>整流二极管</strong>和<strong>肖特基势垒二极管</strong>利用的都是二极管的<strong>正向特性</strong>，而<strong>瞬态电压抑制二极管</strong>与<strong>齐纳稳压二极管</strong>利用的则是二极管的<strong>反向特性</strong>。</p></blockquote><h2 id="发光二极管">发光二极管</h2><p><strong>发光二极管</strong>（<strong>LED</strong>，Light EmittingDiode）同样是由 N 型半导体和 P型半导体结合而成，当两端施加<strong>正向电压</strong>时，电子与空穴不断结合所释放的能量，就会转变为可见光，这个过程可以参考下面的示意图：</p><p><img src="/Electronics/Element/6-Diode/19.png"></p><p><strong>发光二极管的亮度主要取决于电流</strong>，电流越大亮度越高。虽然电压也会影响亮度，但是其与亮度的关系并非线性。一旦高于<strong>阈值电压</strong><span class="math inline">\(V_F\)</span>（也称为<strong>开启电压</strong>，即LED开始导通且微微发光的最小正向电压），通过的电流就会猛增，因而需要与一枚<strong>限流电阻</strong><span class="math inline">\(R\)</span> 串联起来进行使用：</p><p><img src="/Electronics/Element/6-Diode/20.png"></p><blockquote><p><strong>注意</strong>：发光二极管的 <strong>正向电压</strong> <span class="math inline">\(V_F\)</span>也被称作阈值电压或者开启电压，指的是其在额定工作电流之下，引脚两端的电压降。</p></blockquote><p>避免通过的电流过大，而损坏发光二极管，这个串联的<strong>限流电阻</strong>需要进行合适的取值，具体可以通过下面公式计算得到：</p><p><span class="math inline">\(限流电阻 R = \frac{输入电压 V_{in} -发光二极管正向电压 V_F}{发光二极管正向电流 I_F}\)</span></p><p>最后以 <a href="https://www.nationstar.com/"><strong>国星光电</strong></a>生产的贴片式发光二极管为例，其<code>0402</code>、<code>0603</code>、<code>0805</code> 三种常用封装的<strong>正向电压</strong> <span class="math inline">\(V_F\)</span>、<strong>正向电流</strong> <span class="math inline">\(I_F\)</span>、<strong>耗散功率</strong> <span class="math inline">\(P_D\)</span>三个参数基本一致，仅<strong>发光强度</strong>上有所区别（大尺寸封装的LED 亮度会更高）：</p><table><thead><tr><th style="text-align: center;">LED 颜色</th><th style="text-align: center;">正向电压 <span class="math inline">\(V_F\)</span></th><th style="text-align: center;">正向电流 <span class="math inline">\(I_F\)</span></th><th style="text-align: center;">耗散功率 <span class="math inline">\(P_D\)</span></th></tr></thead><tbody><tr><td style="text-align: center;"><strong>红色</strong></td><td style="text-align: center;"><code>1.6V ~ 2.6V</code></td><td style="text-align: center;"><code>20mA</code></td><td style="text-align: center;"><code>65mW</code></td></tr><tr><td style="text-align: center;"><strong>黄色</strong></td><td style="text-align: center;"><code>1.6V ~ 2.6V</code></td><td style="text-align: center;"><code>20mA</code></td><td style="text-align: center;"><code>65mW</code></td></tr><tr><td style="text-align: center;"><strong>橙色</strong></td><td style="text-align: center;"><code>1.6V ~ 2.6V</code></td><td style="text-align: center;"><code>20mA</code></td><td style="text-align: center;"><code>65mW</code></td></tr><tr><td style="text-align: center;"><strong>黄绿色</strong></td><td style="text-align: center;"><code>1.6V ~ 2.6V</code></td><td style="text-align: center;"><code>5mA</code></td><td style="text-align: center;"><code>65mW</code></td></tr><tr><td style="text-align: center;"><strong>白色</strong></td><td style="text-align: center;"><code>2.6V ~ 3.6V</code></td><td style="text-align: center;"><code>5mA</code></td><td style="text-align: center;"><code>72mW</code></td></tr><tr><td style="text-align: center;"><strong>蓝色</strong></td><td style="text-align: center;"><code>2.6V ~ 3.6V</code></td><td style="text-align: center;"><code>10mA</code></td><td style="text-align: center;"><code>72mW</code></td></tr><tr><td style="text-align: center;"><strong>翠绿色</strong></td><td style="text-align: center;"><code>2.6V ~ 3.6V</code></td><td style="text-align: center;"><code>10mA</code></td><td style="text-align: center;"><code>72mW</code></td></tr></tbody></table><h1 id="三极管-triode">三极管 Triode</h1><p><strong>三极管</strong>又称为晶体三极管，根据其结构和电气特性可以划分为<strong>NPN</strong> 和 <strong>PNP</strong>两种类型，它们的电路符号如下所示（<strong>箭头朝外 NPN，箭头朝内PNP</strong>）：</p><p><img src="/Electronics/Element/7-Triode/Basic-1.png"></p><h2 id="基本结构">基本结构</h2><p><strong>PNP 型三极管</strong>是由两个 <strong>P 型半导体</strong>和一个 <strong>N 型半导体</strong>共同构成（电流是从<strong>发射极</strong>进入）：</p><p><img src="/Electronics/Element/7-Triode/Basic-2.png"></p><p><strong>NPN 型三极管</strong>则是由两个 <strong>N 型半导体</strong>和一个 <strong>P 型半导体</strong>共同构成（电流是从<strong>集电极</strong>进入）：</p><p><img src="/Electronics/Element/7-Triode/Basic-3.png"></p><p>三极管的 3个电极分别被称为<strong>集电极</strong>（<strong>C</strong>ollector）、<strong>基极</strong>（<strong>B</strong>ase）、<strong>发射极</strong>（<strong>E</strong>mitter），这三个电极之间会形成2 个 PN 结：</p><ul><li><strong>发射结</strong>：基极和发射极之间的 <strong>PN结</strong>。</li><li><strong>集电结</strong>：基极与集电极之间的 <strong>PN结</strong>。</li></ul><p>正是<strong>发射结</strong>和<strong>集电结</strong>这两个 PN结，会把三极管内部进一步划分为如下 3 个区域：</p><p><img src="/Electronics/Element/7-Triode/Basic-4.png"></p><ol type="1"><li><strong>发射区</strong>：跟<strong>发射极</strong>相连的区域，发射区的本征半导体掺杂浓度较高，存在有大量电荷，可以<strong>发射电荷</strong>。</li><li><strong>集电区</strong>：跟<strong>集电极</strong>相连的区域，集电区本征半导体的面积非常大，从而便于<strong>收集发射区传递过来的电荷</strong>。</li><li><strong>基区</strong>：与<strong>基极</strong>相连的区域，基区处于上述两者之间，掺杂浓度低并且面积较小。由于从发射区进入集电区的电荷都要经过基区，所以基区可以<strong>控制发射区流向集电区的电荷数量</strong>。</li></ol><h2 id="三种工作状态">三种工作状态</h2><p><strong>偏置电路</strong>（<strong>Bias</strong> [ˈbaɪəs]）用于向<strong>NPN</strong> 或者 <strong>PNP</strong>型三极管的各个<strong>极</strong>，提供相应的工作电压，从而使其运行在 3种不同的工作状态：</p><p><img src="/Electronics/Element/7-Triode/Status-1.png"></p><ol type="1"><li><strong>放大状态</strong>：<strong>发射结正偏导通，集电结反偏</strong>。此时<strong>基极电流</strong><span class="math inline">\(I_B\)</span>流入，三极管内部导通，<strong>集电极电流</strong> <span class="math inline">\(I_C\)</span>进入到三极管内部，在与<strong>基极电流</strong> <span class="math inline">\(I_B\)</span>汇合之后，形成<strong>发射极电流</strong> <span class="math inline">\(I_E\)</span> 输出；</li><li><strong>饱和状态</strong>：<strong>发射结和集电结都正偏导通</strong>。此时<strong>基极电流</strong><span class="math inline">\(I_B\)</span>不断增大，<strong>集电极电流</strong> <span class="math inline">\(I_C\)</span>也会不断增大，当两者增大到一定程度时，<span class="math inline">\(I_C\)</span> 无法再伴随 <span class="math inline">\(I_B\)</span>进一步增大，两者的大小关系就会维持不变。换而言之，<strong>基极电流</strong><span class="math inline">\(I_B\)</span> 无法再控制<strong>集电极电流</strong> <span class="math inline">\(I_C\)</span>；</li><li><strong>截止状态</strong>：<strong>发射结电压小于开启电压（例如<code>0.7V</code>），集电结反偏</strong>。这种情况下<strong>基极电流</strong><span class="math inline">\(I_B\)</span>为零，三极管内部无法导通，<strong>集电极电流</strong> <span class="math inline">\(I_C\)</span>无法进入三极管，致使<strong>发射极电流</strong> <span class="math inline">\(I_E\)</span> 也为零；</li></ol><blockquote><p><strong>注意</strong>：三极管不同的工作状态对应着不同的功能，例如当三极管处于<strong>放大状态</strong>时，可以用于对信号进行增益放大。而当三极管处于<strong>饱和状态</strong>和<strong>截止状态</strong>时，则可以当作数字开关来使用。</p></blockquote><p>接下来，我们以如下的<strong>共集电极</strong>接法的放大电路来作为示例，分别讨论上述的这3 种工作状态：</p><p><img src="/Electronics/Element/7-Triode/Status-2.png"></p><p>下图 <strong>NPN 三极管偏置电路</strong> 当中的 <span class="math inline">\(U_C = 4V\)</span>、<span class="math inline">\(U_B= 2.5V\)</span>、<span class="math inline">\(U_E = 1.8V\)</span>，此时<span class="math inline">\(U_B - U_E = 0.7V\)</span> 发射结正偏导通，而<span class="math inline">\(U_C &gt; U_B\)</span>集电结反偏，三极管处于<strong>放大状态</strong>：</p><p><img src="/Electronics/Element/7-Triode/Status-3.png"></p><p>当偏置电路中的 NPN 与 PNP三极管工作在<strong>放大状态</strong>时，其三个引脚之间的<strong>电压</strong>与<strong>电流</strong>关系总是会遵循下面的规律（其中的<span class="math inline">\(\beta\)</span>是三极管的电流放大倍数）：</p><p><span class="math display">\[\begin{align}所有三极管&amp;   \implies I_E = I_B + I_C \\所有三极管&amp;   \implies I_C = \beta \cdot I_B \\NPN 型三极管&amp; \implies U_E &lt; U_B &lt; U_C  \\PNP 型三极管&amp; \implies U_E &gt; U_B &gt; U_C\end{align}\]</span></p><p>下图 <strong>NPN 三极管偏置电路</strong> 当中的 <span class="math inline">\(U_C = 4.7V\)</span>、<span class="math inline">\(U_B = 5V\)</span>、<span class="math inline">\(U_E= 4.3V\)</span>，此时 <span class="math inline">\(U_B - U_E =0.7V\)</span> 发射结正偏导通，而 <span class="math inline">\(U_B &gt;U_C\)</span> 集电结同样正偏，三极管处于<strong>饱和状态</strong>：</p><p><img src="/Electronics/Element/7-Triode/Status-4.png"></p><p>下图 <strong>PNP 三极管偏置电路</strong> 当中的 <span class="math inline">\(U_C = 0V\)</span>、<span class="math inline">\(U_B= 6V\)</span>、<span class="math inline">\(U_E = 6V\)</span>，此时 <span class="math inline">\(U_B - U_E = 0V\)</span> 发射结零偏不导通，而 <span class="math inline">\(U_B &gt; U_C\)</span>集电结反偏，三极管处于<strong>截止状态</strong>：</p><p><img src="/Electronics/Element/7-Triode/Status-5.png"></p><h2 id="基本放大电路的接法">基本放大电路的接法</h2><p>由单个三极管构成的放大电路称为<strong>基本放大电路</strong>，根据不同的偏置电路连接方法，可以划分为如下三种基本接法：</p><p><img src="/Electronics/Element/7-Triode/Basic-Amplifying-Circuit.png"></p><ul><li><strong>共射极放大电路</strong>：既能放大<strong>电流</strong>又能放大<strong>电压</strong>，<strong>输入电阻</strong>居于三种接法的中位，<strong>输出电阻</strong>比较大，频带较窄，通常用于<strong>低频电压放大电路</strong>。</li><li><strong>共集极放大电路</strong>：只能放大<strong>电流</strong>不能放大<strong>电压</strong>，<strong>输入电阻</strong>在三种接法当中最大，<strong>输出电阻</strong>最小，并且具有<strong>电压跟随</strong>的特点，通常用于<strong>电压或功率放大电路</strong>。</li><li><strong>共基极放大电路</strong>：只能放大<strong>电压</strong>不能放大<strong>电流</strong>，<strong>输入电阻</strong>最小，<code>电压放大倍数</code>和<code>输出电阻</code>与共射极放大电路相当，且具有<strong>电流跟随</strong>的特点，在三种接法当中高频特性最好，通常用于<strong>宽频带放大电路</strong>。</li></ul><blockquote><p><strong>注意</strong>：基本放大电路的<strong>输入回路</strong>与<strong>输出回路</strong>的公共端（也就是<strong>地</strong>）在三极管的哪个极，就可以称其为<strong>共X 极放大电路</strong>。</p></blockquote><h2 id="数据手册参数">数据手册参数</h2><p>三极管的数据手册，通常会将重点参数划分为<strong>最大额定值</strong>（MaximumRatings）和<strong>电器特性</strong>（ElectricalCharacteristics）两个部分，具体可以参见下面的表格：</p><table><colgroup><col style="width: 26%"><col style="width: 31%"><col style="width: 41%"></colgroup><thead><tr><th style="text-align: center;">参数（最大额定值）</th><th style="text-align: left;">参数名称（中文）</th><th style="text-align: left;">参数名称（英文）</th></tr></thead><tbody><tr><td style="text-align: center;"><span class="math inline">\(V_{CBO}\)</span></td><td style="text-align: left;"><strong>集电极-基极电压</strong></td><td style="text-align: left;">Collector-Base Voltage</td></tr><tr><td style="text-align: center;"><span class="math inline">\(V_{CEO}\)</span></td><td style="text-align: left;"><strong>集电极-发射极电压</strong></td><td style="text-align: left;">Collector-Emitter Voltage</td></tr><tr><td style="text-align: center;"><span class="math inline">\(V_{EBO}\)</span></td><td style="text-align: left;"><strong>发射极-基极电压</strong></td><td style="text-align: left;">Emitter-Base Voltage</td></tr><tr><td style="text-align: center;"><span class="math inline">\(I_{B}\)</span></td><td style="text-align: left;"><strong>基极电流</strong></td><td style="text-align: left;">Base Current-Continuous</td></tr><tr><td style="text-align: center;"><span class="math inline">\(I_{C}\)</span></td><td style="text-align: left;"><strong>集电极电流</strong></td><td style="text-align: left;">Collector Current-Continuous</td></tr><tr><td style="text-align: center;"><span class="math inline">\(I_{E}\)</span></td><td style="text-align: left;"><strong>发射极电流</strong></td><td style="text-align: left;">Emitter Current-Continuous</td></tr><tr><td style="text-align: center;"><span class="math inline">\(P_{C}\)</span></td><td style="text-align: left;"><strong>耗散功率</strong></td><td style="text-align: left;">Collector Power Dissipation</td></tr><tr><td style="text-align: center;"><span class="math inline">\(T_{j}\)</span></td><td style="text-align: left;"><strong>结温</strong></td><td style="text-align: left;">Junction Temperature</td></tr><tr><td style="text-align: center;"><span class="math inline">\(T_{stg}\)</span></td><td style="text-align: left;"><strong>储存温度</strong></td><td style="text-align: left;">Storage Temperature</td></tr></tbody></table><table><colgroup><col style="width: 20%"><col style="width: 32%"><col style="width: 46%"></colgroup><thead><tr><th style="text-align: center;">参数（电器特性）</th><th style="text-align: left;">参数名称（中文）</th><th style="text-align: left;">参数名称（英文）</th></tr></thead><tbody><tr><td style="text-align: center;"><span class="math inline">\(V_{(BR)CBO}\)</span></td><td style="text-align: left;"><strong>集电极-基极击穿电压</strong></td><td style="text-align: left;">Collector-base Breakdown Voltage</td></tr><tr><td style="text-align: center;"><span class="math inline">\(V_{(BR)CEO}\)</span></td><td style="text-align: left;"><strong>集电极-发射极击穿电压</strong></td><td style="text-align: left;">Collector-emitter Breakdown Voltage</td></tr><tr><td style="text-align: center;"><span class="math inline">\(V_{(BR)EBO}\)</span></td><td style="text-align: left;"><strong>发射极-基极击穿电压</strong></td><td style="text-align: left;">Emitter-base Breakdown Voltage</td></tr><tr><td style="text-align: center;"><span class="math inline">\(I_{CBO}\)</span></td><td style="text-align: left;"><strong>集电极-基极截止电流</strong></td><td style="text-align: left;">Collector Cut-off Current</td></tr><tr><td style="text-align: center;"><span class="math inline">\(I_{CEO}\)</span></td><td style="text-align: left;"><strong>集电极-发射极截止电流</strong></td><td style="text-align: left;">Collector Cut-off Current</td></tr><tr><td style="text-align: center;"><span class="math inline">\(I_{EBO}\)</span></td><td style="text-align: left;"><strong>发射极-基极截止电流</strong></td><td style="text-align: left;">Emitter Cut-off Current</td></tr><tr><td style="text-align: center;"><span class="math inline">\(hFE\)</span></td><td style="text-align: left;"><strong>直流电流增益</strong></td><td style="text-align: left;">DC Current Gain</td></tr><tr><td style="text-align: center;"><span class="math inline">\(V_{CE}（sat）\)</span></td><td style="text-align: left;"><strong>集电极-发射极饱和压降</strong></td><td style="text-align: left;">Collector-emitter Saturation Voltage</td></tr><tr><td style="text-align: center;"><span class="math inline">\(V_{BE}（sat）\)</span></td><td style="text-align: left;"><strong>发射极-基极饱和压降</strong></td><td style="text-align: left;">Base-emitter Saturation Voltage</td></tr></tbody></table><blockquote><p><strong>注意</strong>：三极管之所以被称为<strong>电流控制元件</strong>，是因为其本质是通过控制一个较小的电流（基极电流<span class="math inline">\(I_B\)</span>）来影响或者控制一个较大的电流（集电极电流<span class="math inline">\(I_C\)</span>、发射极电流 <span class="math inline">\(I_E\)</span>）。</p></blockquote><h2 id="达林顿管">达林顿管</h2><p><strong>达林顿管</strong>包含有两个或者多个三极管，其中第 1个三极管的<strong>集电极</strong>直接连接至第 2个三极管的<strong>基极</strong>。这种连接方式会让其具有<strong>高电流放大倍数</strong>、<strong>大输入电阻</strong>、<strong>良好的温度稳定性</strong>等特点，被广泛应用于开关电路、放大电路、功率控制电路：</p><p><img src="/Electronics/Element/7-Triode/Darlington-1.png"></p><ul><li><strong>第 1个三极管</strong>放大之后的<strong>电流</strong>，可以进一步被<strong>第2个三极管</strong>放大，从而实现了电流放大特性的成倍叠加，因而具有更高的电流<strong>放大倍数</strong><span class="math inline">\(\beta\)</span>。</li><li>增大了达林顿三极管的<strong>输入电阻</strong>，有助于降低输入电路对于信号源的影响，提高输出信号的稳定性。</li><li>改善温度稳定性，虽然内部各个三极管的工作参数会受到温度的影响而变化，但是各极之间的相互连接关系，往往能够部分抵消这些变化。</li></ul><p><img src="/Electronics/Element/7-Triode/Darlington-2.png"></p><p>上图当中的 <strong>TIP122</strong>（NPN，上图右）以及<strong>TIP127</strong>（PNP，上图左）都属于比较常见的达林顿管，它们都具备高达<code>1000</code> 的电流放大倍数，且基极与发射极之间只需要维持 <span class="math inline">\(V_{EBO} = 5V\)</span>的电压，而<strong>基极电流</strong>仅为 <span class="math inline">\(I_B= 120mA\)</span>，通常外接至微控制器的 GPIO端口，对一些<strong>大电流</strong>的负载进行开关控制。</p><p><img src="/Electronics/Element/7-Triode/Darlington-3.png"></p><p>而上图当中的 <strong>ULN2003A</strong>则属于高电压、大电流的达林顿管<strong>阵列</strong>，片上主要由 7对具备高压输出能力的 <strong>NPN</strong>型达林顿管组成，并且带有用于开关感性负载的<strong>共阴极钳位二极管</strong>。下图是使用其驱动电机、电位器、电磁阀等感性负载时的典型应用电路：</p><p><img src="/Electronics/Element/7-Triode/Darlington-4.png"></p><blockquote><p><strong>注意</strong>：微控制器的外围电路经常会使用到<strong>ULN2003A</strong>去驱动一些高电压（<code>50V</code>）或者大电流（<code>500mA</code>）的外设。</p></blockquote><h2 id="光电耦合器">光电耦合器</h2><p><strong>光电耦合器</strong>（OC，OpticalCoupler）简称<strong>光耦</strong>，是一种以光作为媒介来传递电平信号的元器件。内部由一个<strong>发光元件</strong>（发光二极管）和一个<strong>光敏元件</strong>（光电三极管）共同组成，通过不断的执行<code>电 → 光 → 电</code>的转换过程，在传输信号的同时还可以起到保护隔离的作用，下面是经典的<strong>PC817A</strong> 型光耦的剖面示意图：</p><p><img src="/Electronics/Element/7-Triode/OC-1.png"></p><p>对于一侧是低电压的微控制器电路，而另外一侧是高电压的功率控制端，这种情况下就可以选用光耦进行隔离控制。除此之外，由于光耦的输入端属于电流驱动的低阻元件，因而具备较强的<strong>共模抑制</strong>能力，可以应用在长距离信号传输当中提升信噪比（光耦封装上的<strong>小圆点</strong>标注的是第<code>1</code> 号引脚）。</p><p><img src="/Electronics/Element/7-Triode/OC-2.png"></p><p>对光电耦合器进行选型时，需要分别关注其<strong>输入端</strong>（可视为<strong>发光二极管</strong>）和<strong>输出端</strong>（可视为<strong>光电三极管</strong>的<code>集电极</code>和<code>发射极</code>）的相关参数。下图左侧展示的是光耦典型应用电路，而右侧呈现的是光耦通信时的输入输出信号状态：</p><p><img src="/Electronics/Element/7-Triode/OC-3.png"></p><p>除开二极管、三极管的各种通用参数之外，还需要额外关注输出脉冲信号的<strong>上升时间</strong><span class="math inline">\(t_r\)</span>（从输出脉冲的<code>10% → 90%</code> 所需的时间）和<strong>下降时间</strong> <span class="math inline">\(t_f\)</span>（从输出脉冲的 <code>90% → 10%</code>所需的时间），这两个参数通常在<strong>微秒</strong>级别，两者之和（不考虑信号的持续时间）即为光耦通信速率的上限。</p><h2 id="三端稳压器">三端稳压器</h2><p><strong>三端稳压器</strong>（3-TerminalRegulator）是一款由诸多三极管构成的串联型线性稳压器件，用于将不稳定的直流电压转换为稳定的直流电压。比较常用的有<strong>正电压输出</strong>的<strong>78XX</strong> 系列，以及<strong>负电压输出</strong>的<strong>79XX</strong> 系列（型号最后的尾数 <code>XX</code>表示的是稳压值），它们通常会采用如下三个引脚的封装形式（这些引脚分别为<strong>输入</strong>、<strong>地</strong>、<strong>输出</strong>）：</p><p><img src="/Electronics/Element/7-Triode/3TR-1.png"></p><p><strong>三端稳压器</strong>的工作原理主要依赖于反馈控制，即当输入电压发生变化时，通过内部<code>基准电压源</code>、<code>比较放大器</code>、<code>误差放大器</code>的协同工作，以维持一个稳定的电压输出（下面是 <strong>78XX</strong>系列的内部原理图）：</p><p><img src="/Electronics/Element/7-Triode/3TR-2.png"></p><blockquote><p><strong>注意</strong>：在进行三端稳压器选型的时候，需要额外注意<strong>输入电压</strong> <span class="math inline">\(V_{in}\)</span>必须始终高于 <strong>输出电压</strong> <span class="math inline">\(V_{out}\)</span>，两者之间必须维持一个合理的压差。</p></blockquote><h1 id="可控硅-scr">可控硅 SCR</h1><p><strong>可控硅</strong>（SCR，Silicon ControlledRectifier）通常被称作<strong>晶闸管</strong>，是一种外形尺寸比较硕大的元器件（也存在尺寸相对小巧的贴片或者直插式封装），被广泛应用于<code>高电压</code>、<code>大电流</code>、<code>大功率</code>的工作场景：</p><p><img src="/Electronics/Element/8-SCR/0.png"></p><h2 id="单向可控硅">单向可控硅</h2><p><strong>单向晶闸管</strong>顾名思义只能单向导通，其拥有着<strong>阳极</strong>（A）、<strong>控制极</strong>（G）、<strong>阴极</strong>（K）三个引脚，对应的电路符号如下图所示：</p><p><img src="/Electronics/Element/8-SCR/1.png"></p><p>单向晶闸管的内部结构如下图左侧所示，我们可以将其等效为下图右侧的一个<strong>PNP</strong> 型三极管与一个 <strong>NPN</strong>型三极管的相互连接：</p><p><img src="/Electronics/Element/8-SCR/2.png"></p><p>下面是一个单向晶闸管的偏置电路，其中的<strong>电源</strong> <span class="math inline">\(E_2\)</span> 通过<strong>电阻</strong> <span class="math inline">\(R_2\)</span> 为单向晶闸管的 <strong>A 极</strong>与 <strong>K 极</strong> 提供<strong>正向电压</strong> <span class="math inline">\(U_{AK}\)</span>，而<strong>电源</strong> <span class="math inline">\(E_1\)</span> 经过<strong>电阻</strong> <span class="math inline">\(R_1\)</span> 和<strong>开关</strong> <span class="math inline">\(S\)</span> 为单向晶闸管的 <strong>G 极</strong> 与<strong>K 极</strong> 提供<strong>正向电压</strong> <span class="math inline">\(U_{GK}\)</span>：</p><p><img src="/Electronics/Element/8-SCR/3.png"></p><ul><li>当<strong>开关</strong> <span class="math inline">\(S\)</span>处于<strong>断开</strong>状态的时候，单向晶闸管内部的<strong>三极管</strong><span class="math inline">\(VT_1\)</span> 没有<strong>基极电流</strong><span class="math inline">\(I_{B1}\)</span> 通过无法导通，同样的 <span class="math inline">\(VT_2\)</span> 也无法导通（电流 <span class="math inline">\(I_2 =0A\)</span>），此时单向晶闸管处于<strong>截止状态</strong>。</li><li>当<strong>开关</strong> <span class="math inline">\(S\)</span>处于<strong>闭合</strong>状态的时候，<strong>电源</strong> <span class="math inline">\(E_1\)</span> 开始向<strong>三极管</strong> <span class="math inline">\(VT_1\)</span> 提供<strong>基极电流</strong> <span class="math inline">\(I_{B1}\)</span>，此时由于三极管 <span class="math inline">\(VT_2\)</span> 的<strong>基极电流</strong> <span class="math inline">\(I_{B2}\)</span> 会经过<strong>三极管</strong><span class="math inline">\(VT_1\)</span>的集电极和发射极，从而使得<strong>三极管</strong> <span class="math inline">\(VT_1\)</span> 和 <span class="math inline">\(VT_2\)</span>先后导通。此时<strong>三极管</strong> <span class="math inline">\(VT_2\)</span> 的<strong>集电极电流</strong> <span class="math inline">\(I_{C2}\)</span> 与<strong>电源</strong> <span class="math inline">\(E_1\)</span>提供的电流汇合，形成一股更大的<strong>电流</strong> <span class="math inline">\(I_{B1}\)</span> 进入<strong>三极管</strong> <span class="math inline">\(VT_1\)</span>的发射极，由于<strong>三极管</strong> <span class="math inline">\(VT_1\)</span>的导通程度越深，通过的<strong>集电极电流</strong> <span class="math inline">\(I_{C1}\)</span>就会越大，导致<strong>三极管</strong> <span class="math inline">\(VT_2\)</span> 的<strong>基极电流</strong> <span class="math inline">\(I_{B2}\)</span> 以及<strong>集电极电流</strong><span class="math inline">\(I_{C2}\)</span>也随之增大，从而形成<strong>正反馈</strong>。</li></ul><p><img src="/Electronics/Element/8-SCR/4.png"></p><ol type="1"><li><strong>正反馈</strong>会使得<strong>三极管</strong> <span class="math inline">\(VT_1\)</span> 和 <span class="math inline">\(VT_2\)</span>都进入饱和状态，<strong>基极电流</strong> <span class="math inline">\(I_{B2}\)</span> 以及<strong>集电极电流</strong><span class="math inline">\(I_{C2}\)</span>都来源于<strong>三极管</strong> <span class="math inline">\(VT_2\)</span>的<strong>发射极</strong>（即单向晶闸管的 <strong>A极</strong>），最后从<strong>三极管</strong> <span class="math inline">\(VT_1\)</span> 的<strong>发射极</strong>流出（即单向晶闸管的 <strong>K极</strong>），此时单向晶闸管<strong>导通</strong>。</li><li>单向晶闸管导通之后，即使<strong>开关</strong> <span class="math inline">\(S\)</span> 断开，<strong>三极管</strong> <span class="math inline">\(VT_2\)</span> 的 <strong>基极电流</strong> <span class="math inline">\(I_{B2}\)</span> 以及 <strong>集电极电流</strong><span class="math inline">\(I_{C2}\)</span>会继续存在，单向晶闸管<strong>持续导通</strong>。</li><li>如果此时调低<strong>电源</strong> <span class="math inline">\(E_2\)</span> 的电压，那么流入单向晶闸管 <strong>A极</strong>的电流也会随之减小，当 <span class="math inline">\(E_2\)</span> 的电压被调整至极低的时候（接近于<code>0V</code>），流入单向晶闸管 <strong>A极</strong>的电流也就会接近于<code>0A</code>，此时单向晶闸管就<strong>进入截止</strong>状态。</li></ol><p>综上所述，我们可以将单向晶闸管的主要特点，归结为如下这四个方面：</p><ol type="1"><li>无论 <strong>A 极</strong> 与 <strong>K 极</strong>之间施加<strong>任何电压</strong>，只要 <strong>G 极</strong> 与<strong>K 极</strong>之间未被施加<strong>正向电压</strong>，单向晶闸管都<strong>无法导通</strong>。</li><li>只有 <strong>A 极</strong> 与 <strong>K极</strong>之间施加<strong>正向电压</strong>，并且 <strong>G 极</strong>与 <strong>K 极</strong>之间也施加一定的<strong>正向电压</strong>，单向晶闸管才<strong>能够导通</strong>。</li><li>单向晶闸管导通之后，即使撤掉其 <strong>G 极</strong> 与 <strong>K极</strong>之间的<strong>正向电压</strong>，单向晶闸管仍然能够继续<strong>维持导通</strong>状态。</li><li>如果要让已经导通的单向晶闸管<strong>进入截止</strong>状态，要么让流入单向晶闸管<strong>A 极</strong>的电流减小至其<strong>维持电流</strong> <span class="math inline">\(I_H\)</span>，要么使其 <strong>A 极</strong> 与<strong>K 极</strong> 之间的<strong>正向电压</strong> <span class="math inline">\(U_{AK}\)</span> 减小至<code>0V</code>，或者直接施加一个<strong>反向电压</strong>（简而言之，只能控制开，无法控制关）。</li></ol><h2 id="重点选型参数">重点选型参数</h2><p><strong>单向晶闸管</strong>元器件进行选型时，需要重点关注下面表格当中的一系列参数：</p><table><colgroup><col style="width: 14%"><col style="width: 5%"><col style="width: 80%"></colgroup><thead><tr><th style="text-align: left;">参数名称</th><th style="text-align: left;">符号</th><th style="text-align: left;">解释</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>正向断态重复峰值电压</strong></td><td style="text-align: left;"><span class="math inline">\(U_{DRM}\)</span></td><td style="text-align: left;">指在单向晶闸管关断，并且 <strong>G极</strong> 开路的情况下，允许重复施加到 <strong>A 极</strong> 与<strong>K 极</strong> 之间的最大正向峰值电压。</td></tr><tr><td style="text-align: left;"><strong>反向重复峰值电压</strong></td><td style="text-align: left;"><span class="math inline">\(U_{RRM}\)</span></td><td style="text-align: left;">是指在 G极开路的时候，允许施加到单向晶闸管 <strong>A 极</strong> 与 <strong>K极</strong> 之间的最大反向峰值电压（<span class="math inline">\(U_{DRM}\)</span> 与 <span class="math inline">\(U_{RRM}\)</span> 两个参数通常比较接近）。</td></tr><tr><td style="text-align: left;"><strong>控制极 / G极触发电压</strong></td><td style="text-align: left;"><span class="math inline">\(U_{GT}\)</span></td><td style="text-align: left;">指室温条件下，当 <strong>A 极</strong> 与<strong>K 极</strong>之间施加指定电压的时候，能够使单向晶闸管从截止转变为导通，所需的最小<strong>G 极</strong>直流<strong>电压</strong>。</td></tr><tr><td style="text-align: left;"><strong>控制极 / G极触发电流</strong></td><td style="text-align: left;"><span class="math inline">\(I_{GT}\)</span></td><td style="text-align: left;">指室温条件下，当 <strong>A 极</strong> 与<strong>K 极</strong>之间施加指定电压的时候，能够使单向晶闸管从截止转变为导通，所需的最小<strong>G 极</strong>直流<strong>电流</strong>。</td></tr><tr><td style="text-align: left;"><strong>通态平均电流</strong></td><td style="text-align: left;"><span class="math inline">\(I_T\)</span></td><td style="text-align: left;">指室温条件下，能够连续通过<code>50Hz</code> 正弦波的电流平均值。</td></tr><tr><td style="text-align: left;"><strong>维持电流</strong></td><td style="text-align: left;"><span class="math inline">\(I_H\)</span></td><td style="text-align: left;">指在 <strong>G极</strong>开路的条件下，能够维持单向晶闸管持续导通的最小正向电流。</td></tr></tbody></table><h2 id="双向可控硅">双向可控硅</h2><p><strong>双向晶闸管</strong>能够双向导通，其拥有<strong>主电极</strong><span class="math inline">\(T_1\)</span>、<strong>主电极</strong> <span class="math inline">\(T_2\)</span>、<strong>控制极</strong> <span class="math inline">\(G\)</span>三个引脚，对应的<strong>电路符号</strong>（下图左侧）和<strong>内部结构</strong>（下图右侧）如下所示：</p><p><img src="/Electronics/Element/8-SCR/5.png"></p><p>当向<strong>双向晶闸管</strong>的 <span class="math inline">\(T_1\)</span> 与 <span class="math inline">\(T_2\)</span>极之间施加<strong>正向电压</strong>（<span class="math inline">\(U_{T2}&gt; U_{T1}\)</span>）的时候，如果其 <strong>G极</strong>没有施加电压，那么 <span class="math inline">\(T_1\)</span>与 <span class="math inline">\(T_2\)</span> 极之间就不会导通。如果在<span class="math inline">\(G\)</span> 极与 <span class="math inline">\(T_1\)</span>极之间施加<strong>正向电压</strong>（<span class="math inline">\(U_{G}&gt; U_{T1}\)</span>），那么 <span class="math inline">\(T_1\)</span> 与<span class="math inline">\(T_2\)</span> 极之间将会马上导通，电流会由<span class="math inline">\(T_2\)</span> 极流入，并从 <span class="math inline">\(T_1\)</span> 极流出。此时即使移除 <strong>G极</strong>电压，双向晶闸管的 <span class="math inline">\(T_1\)</span>与 <span class="math inline">\(T_2\)</span>极之间仍然处于导通状态。换而言之，当 <span class="math inline">\(U_{T2}&gt; U_{G} &gt; U_{T1}\)</span> 的时候，双向晶闸管就会导通，电流会从<span class="math inline">\(T_2\)</span> 极流入 <span class="math inline">\(T_1\)</span> 极流出，此时即使移除 <strong>G极</strong>电压，晶闸管仍然能够保持导通：</p><p><img src="/Electronics/Element/8-SCR/6.png"></p><p>当向<strong>双向晶闸管</strong>的 <span class="math inline">\(T_1\)</span> 与 <span class="math inline">\(T_2\)</span>极之间施加<strong>反向电压</strong>（<span class="math inline">\(U_{T2}&lt; U_{T1}\)</span>）时，如果其 <strong>G 极</strong>没有施加电压，那么<span class="math inline">\(T_1\)</span> 与 <span class="math inline">\(T_2\)</span> 极之间就不会导通。如果在 <span class="math inline">\(G\)</span> 极与 <span class="math inline">\(T_1\)</span>极之间施加<strong>反向电压</strong>（<span class="math inline">\(U_{G}&lt; U_{T1}\)</span>），那么 <span class="math inline">\(T_1\)</span> 与<span class="math inline">\(T_2\)</span> 极之间将会立刻导通，电流会由<span class="math inline">\(T_1\)</span> 极流入，并从 <span class="math inline">\(T_2\)</span> 极流出。此时即使移除 <strong>G极</strong>电压，双向晶闸管的 <span class="math inline">\(T_1\)</span>与 <span class="math inline">\(T_2\)</span>极之间仍然处于导通状态。换而言之，当 <span class="math inline">\(U_{T1}&gt; U_{G} &gt; U_{T2}\)</span> 的时候，双向晶闸管就会导通，电流会从<span class="math inline">\(T_1\)</span> 极流入 <span class="math inline">\(T_2\)</span> 极流出，此时即使移除 <strong>G极</strong>电压，晶闸管仍然能够保持导通：</p><p><img src="/Electronics/Element/8-SCR/7.png"></p><p>当双向晶闸管导通之后，即使移除 <strong>G极</strong>电压其仍然能够保持导通状态。此时如果需要关断双向晶闸管，使其进入截止状态，那么可以采取如下任意一种措施：</p><ol type="1"><li>让流过<strong>主电极</strong> <span class="math inline">\(T_1\)</span> 和 <strong>主电极</strong> <span class="math inline">\(T_2\)</span>极的电流减小至<strong>维持电流</strong> <span class="math inline">\(I_H\)</span> 以下。</li><li>将<strong>主电极</strong> <span class="math inline">\(T_1\)</span>与 <strong>主电极</strong> <span class="math inline">\(T_2\)</span>极之间的电压置为<code>0V</code>，或者直接施加一个<strong>反向电压</strong>（依然是只能导通，无法关断(•ิ_•ิ) ）。</li></ol><h1 id="场效应管-fet">场效应管 FET</h1><p><strong>晶体管</strong>（Transistor）是一种以固态半导体作为制造原材料的元器件，通常都至少拥有三只引脚，可以划分为如下一系列类型：</p><p><img src="/Electronics/Element/9-FET/1.png"></p><ul><li><strong>双极型晶体管</strong>（<strong>BJT</strong>，BipolarJunctionTransistor）：即前面介绍的<strong>三极管</strong>，如前所述，可以划分为<strong>NPN</strong> 型和 <strong>PNP</strong> 型两种。</li><li><strong>单极型晶体管</strong>（<strong>FET</strong>，Field EffectTransistor）：即本节内容即将介绍的<strong>场效应管</strong>，根据材料还可以细分为<strong>JFET</strong>（结型）和<strong>MOSFET</strong>（金属氧化物型），两者还可以进一步被划分为<strong>N 沟道</strong>和 <strong>P 沟道</strong> 类型。</li></ul><blockquote><p><strong>注意</strong>：<strong>双极型晶体管</strong>的载流子包含<strong>电子</strong>和<strong>空穴</strong>两种，类似于拥有两个极性，所以称为<strong>双极型</strong>；而在<strong>单极型晶体管</strong>当中，只存在<strong>电子</strong>或者<strong>空穴</strong>两种载流子当中的一种，类似于只存在着一个极性，因而被称为<strong>单极型</strong>。</p></blockquote><p><img src="/Electronics/Element/9-FET/2.png"></p><p>虽然<strong>场效应管</strong>和之前讨论过的<strong>三极管</strong>在外形上都拥有着<strong>三只引脚</strong>，但是<strong>场效应管</strong>的核心原理是通过<strong>栅极</strong>与<strong>源极</strong>两端的电压，来控制<strong>漏极</strong>的电流，因而被称为<strong>压控型</strong>元器件。而<strong>三极管</strong>则是通过<strong>基极电流</strong><span class="math inline">\(I_B\)</span> 控制<strong>集电极电流</strong><span class="math inline">\(I_C\)</span>，所以被称为<strong>流控型</strong>元器件。</p><h2 id="结型场效应管-jfet">结型场效应管 JFET</h2><p>如前所述，<strong>结型场效应管</strong> JFET 可以划分为 <strong>P沟道</strong>和 <strong>N沟道</strong>两种类型，因其工作电流非常小（最大仅有<code>500mA</code>，大部分低于<code>100mA</code>），导致应用场合十分有限，仅有百余种型号，它们的电路符号如下图所示：</p><p><img src="/Electronics/Element/9-FET/3.png"></p><ul><li><strong>N 沟道结型场效应管</strong>（下图左侧）：内部两块 <strong>P型半导体</strong>通过导线连接（引出 <strong>G极</strong>），除此之外的部分均为 <strong>N 型半导体</strong>，在 P 型和N 型半导体的交界处会形成两个 <strong>PN结</strong>，它们中间的区域称为<strong>沟道</strong>（两端分别引出<strong>D 极</strong>与 <strong>S 极</strong>）。由于该沟道由 <strong>N型半导体</strong>构成，所以称为 <strong>N 沟道</strong>。</li><li><strong>P 沟道结型场效应管</strong>（下图右侧）：内部两块 <strong>N型半导体</strong>同样通过导线连接（引出 <strong>G极</strong>），中间的<strong>沟道</strong>由 <strong>P型半导体</strong>制成（分别引出 <strong>D 极</strong>与 <strong>S极</strong>），此时交界处会形成两个 <strong>PN结</strong>，中间的沟道也就称作 <strong>P 沟道</strong>。</li></ul><p><img src="/Electronics/Element/9-FET/4.png"></p><blockquote><p><strong>注意</strong>：上述示意图当中的<strong>栅极</strong>（<strong>G</strong>ate）也被称作<strong>G极</strong>，<strong>漏极</strong>（<strong>D</strong>rain）也称作<strong>D 极</strong>，而<strong>源极</strong>（<strong>S</strong>ource）被称为 <strong>S极</strong>。</p></blockquote><p>以下图虚线框中的 <strong>N 沟道结型场效应管</strong> 为例，当向<strong>D 极</strong>和 <strong>S极</strong>之间施加<strong>正向电压</strong> <span class="math inline">\(U_{DS}\)</span> 时，就会有电流从 <strong>D极</strong> 流向 <strong>S 极</strong>。此时如果再在 <strong>G极</strong> 和 <strong>S极</strong>之间施加一个<strong>反向电压</strong> <span class="math inline">\(U_{GS}\)</span>，就会导致内部的两个 PN结增厚（沟道变窄），由 <strong>D 极</strong>流向 <strong>S极</strong>的电流 <span class="math inline">\(I_D\)</span>就会随之减小：</p><p><img src="/Electronics/Element/9-FET/5.png"></p><p>由此可见，改变 <strong>G 极</strong>与 <strong>S极</strong>之间的电压 <span class="math inline">\(U_{GS}\)</span>，就能改变从 <strong>D 极</strong>流向 <strong>S 极</strong> 的电流 <span class="math inline">\(I_D\)</span>，并且<strong>电流</strong> <span class="math inline">\(I_D\)</span>的变化幅度要远大于<strong>电压</strong> <span class="math inline">\(U_{GS}\)</span>，这正是结型场效应管的放大原理所在。通常我们使用<strong>跨导</strong> <span class="math inline">\(g_m\)</span>来衡量<strong>结型场效应管</strong> JFET的放大能力（单位为<strong>西门子</strong> <code>S</code>）：</p><p><span class="math display">\[g_m = \frac{\Delta I_D}{\Delta U_{GS}}\]</span></p><p>如果向 <strong>N 沟道结型场效应管</strong>的 <strong>G 极</strong> 和<strong>S 极</strong> 之间施加<strong>正向电压</strong> <span class="math inline">\(U_G &gt; U_S\)</span>，其内部两个 PN结就会导通，此时无论如何增大 <strong>G 极</strong> 与 <strong>S极</strong> 之间的正向电压，沟道宽度都不会变化，<strong>电流</strong><span class="math inline">\(I_D\)</span> 也不会发生变化。换而言之，向<strong>G 极</strong> 与 <strong>S极</strong>之间施加<strong>正向电压</strong>的时候，无法控制<strong>电流</strong><span class="math inline">\(I_D\)</span> 的变化：</p><p><img src="/Electronics/Element/9-FET/6.png"></p><p>综上所述，向 <strong>N 沟道结型场效应管</strong>的 <strong>G极</strong> 与 <strong>S 极</strong> 之间施加<strong>反向电压</strong><span class="math inline">\(U_G &lt; U_S\)</span>，而 <strong>P沟道结型场效应管</strong>的 <strong>G 极</strong>与 <strong>S极</strong>之间施加<strong>正向电压</strong> <span class="math inline">\(U_G &gt;U_S\)</span>，就可以确保它们能够正常工作。无论是 N 沟道还是 P沟道的结型场效应管，它们都存在有如下几个重要参数：</p><ul><li><strong>跨导</strong> <span class="math inline">\(g_m\)</span>：当电压 <span class="math inline">\(U_{DS}\)</span> 为一个确定值的时候，该参数的值等于<strong>电流</strong> <span class="math inline">\(I_D\)</span>变化量与<strong>电压</strong> <span class="math inline">\(U_{GS}\)</span> 变化量的比值 <span class="math inline">\(g_m = \frac{\Delta I_D}{\DeltaU_{GS}}\)</span>，这个参数主要反映了 <strong>G 极</strong>和 <strong>S极</strong>之间的电压，对于 <strong>D 极</strong>电流的控制能力。</li><li><strong>夹断电压</strong> <span class="math inline">\(U_{P}\)</span>：当<strong>电压</strong> <span class="math inline">\(U_{DS}\)</span> 为一个确切的值，使得<strong>电流</strong> <span class="math inline">\(I_D\)</span>减小至近似为 <code>0A</code> 时候，<span class="math inline">\(U_{GS}\)</span> 的电压值。</li><li><strong>漏源极最大电压</strong> <span class="math inline">\(U_{DS}\)</span>：是指漏极与源极之间的最大击穿电压，即<strong>电流</strong><span class="math inline">\(I_D\)</span> 急剧增大时候的 <span class="math inline">\(U_{DS}\)</span> 值。</li><li><strong>漏极饱和电流</strong> <span class="math inline">\(I_{DSS}\)</span>：是指当 <span class="math inline">\(U_{GS} = 0V\)</span>，并且 <span class="math inline">\(U_{DS}\)</span> 大于<strong>夹断电压</strong><span class="math inline">\(U_P\)</span>时候的<strong>沟道电流</strong>。</li></ul><h2 id="金属氧化物场效应管-mosfet">金属氧化物场效应管 MOSFET</h2><p><strong>金属氧化物场效应管</strong>（MOSFET，Metal-Oxide-SemiconductorField-Effect Transistor）由于名称过于冗长，所以经常被简称为 <strong>MOS管</strong>，主要分为<strong>耗尽型</strong>和<strong>增强型</strong>两种，每种类型又可以进一步细分为<strong>P 沟道</strong> 和 <strong>N沟道</strong>，具体关系可以参考下面的示意图：</p><p><img src="/Electronics/Element/9-FET/7.png"></p><h3 id="增强型">增强型</h3><p>根据<strong>增强型 MOS管</strong>内部的<strong>导电沟道</strong>是形成在 <strong>N 型</strong>还是 <strong>P 型</strong> 半导体之间，可以将其细分为 <strong>N沟道</strong>和 <strong>P 沟道</strong> 两种类型，分别称作<strong>增强型NMOS 管</strong> 和 <strong>增强型 PMOS管</strong>，它们的电路符号分别如下图所示：</p><p><img src="/Electronics/Element/9-FET/8.png"></p><p>实际生产环境下，<strong>增强型 NMOS</strong>会更加常用，所以接下来就以 <strong>NMOS</strong>管为例来讨论其内部结构。首先，增强型 <strong>NMOS</strong> 管采用<strong>P 型</strong>半导体作为<strong>衬底</strong>，在上面制作出两个含有较多杂质的<strong>N 型</strong> 半导体，并覆盖上一层极薄的 <span class="math inline">\(SiO_2\)</span><strong>二氧化硅绝缘层</strong>。然后在两个 <strong>N 型</strong>半导体上分别引出<strong>漏极</strong>（<strong>D</strong>rain）和<strong>源极</strong>（<strong>S</strong>ource），再在两极中间的二氧化硅绝缘层上制作出一层<strong>金属导电层</strong>，并从该导电层上引出<strong>栅极</strong>（<strong>G</strong>ate）：</p><p><img src="/Electronics/Element/9-FET/9.png"></p><p>增强型 <strong>NMOS</strong>管需要施加相应的电压才能够正常工作，在下面的示例电路当中，<strong>电源</strong><span class="math inline">\(E_1\)</span> 在与<strong>电阻</strong> <span class="math inline">\(R_1\)</span> 串联之后，分别连接至<strong>NMOS</strong> 管的 <strong>D 极</strong> 和 <strong>S极</strong>。而<strong>电源</strong> <span class="math inline">\(E_2\)</span> 则在串接了一枚<strong>开关</strong><span class="math inline">\(S\)</span> 之后，再分别连接到这个<strong>NMOS</strong> 管的 <strong>G 极</strong> 和 <strong>S极</strong>：</p><p><img src="/Electronics/Element/9-FET/10.png"></p><ol type="1"><li>当开关 <span class="math inline">\(S\)</span> 断开时，增强型<strong>NMOS</strong> 管的 <strong>G 极</strong>上没有电压，并且<strong>D 极</strong>和 <strong>S 极</strong>所连接的两个 N型半导体区域之间<strong>没有导电沟道</strong>，所以两个 N型半导体区域之间无法导通，通过的电流为 <code>0A</code>；</li><li>当开关 <span class="math inline">\(S\)</span> 闭合时，增强型<strong>NMOS</strong> 管的 <strong>G极</strong>获得<strong>正向电压</strong>（<span class="math inline">\(U_G &gt; U_S\)</span>），此时与 <strong>G极</strong>相连接的<strong>金属导电层</strong>上存在有<strong>电荷</strong>，产生的电场会穿过二氧化硅绝缘层，将P 型半导体衬底上的大量电子吸引到 <span class="math inline">\(SiO_2\)</span> 层一侧，进而在两个 N型半导体区域之间<strong>形成一条导电沟道</strong>，导通 <strong>D极</strong> 与 <strong>S 极</strong> 并且输出<strong>电流</strong> <span class="math inline">\(I_D\)</span>；</li><li>改变<strong>电源</strong> <span class="math inline">\(E_2\)</span>输出电压的大小，就会相应的改变 <strong>G 极</strong>与 <strong>S极</strong>之间的<strong>电压</strong> <span class="math inline">\(U_{GS}\)</span>，致使 <strong>G极</strong>所连接铝电极上的电场也随之变化，进而引发 <span class="math inline">\(SiO_2\)</span> 绝缘层下电子数量的变化，并使得两个N型半导体区域之间的<strong>沟道宽度发生改变</strong>，流过的<strong>电流</strong><span class="math inline">\(I_D\)</span> 也就相应的改变。</li></ol><p>综上所述，就是依靠<strong>金属导电层上产生的电场，吸引半导体衬底上的电子，从而产生导电沟道与电流</strong>，基于此原理可以总结出增强型<strong>NMOS</strong> 管所具备的如下特点：</p><ol type="1"><li>当没有向 <strong>G 极</strong> 与 <strong>S 极</strong>之间施加<strong>电压</strong>的时候（<span class="math inline">\(U_{GS}= 0V\)</span>），在 <strong>D 极</strong> 与 <strong>S极</strong>之间不会形成导电沟道，<strong>D极</strong>上的<strong>输出电流</strong> <span class="math inline">\(I_D= 0A\)</span>；</li><li>当 <strong>G 极</strong>与 <strong>S极</strong>之间施加上合适的电压时（<strong>开启电压</strong>，即刚形成导电沟道时的栅源极电压<span class="math inline">\(U_{GS(th)}\)</span>），就会在 <strong>D极</strong>与 <strong>S 极</strong>之间形成导电沟道，<strong>D极</strong>上开始输出电流 <span class="math inline">\(I_D\)</span>；</li><li>当<strong>G 极</strong>与 <strong>S极</strong>之间的<strong>电压</strong> <span class="math inline">\(U_{GS}\)</span>发生变化时，导电沟道的宽度也会随之变化，致使<strong>电流</strong> <span class="math inline">\(I_D\)</span> 也会发生变化；</li></ol><p>增强型 <strong>NMOS</strong> 管和 <strong>PMOS</strong>管形成导电沟道的条件，分别如下面所示：</p><ul><li><strong>增强型 NMOS 管</strong>：需要向 G 极与 S极之间施加<strong>正向电压</strong>（<span class="math inline">\(U_G&gt; U_S\)</span>），才会在 D 极与 S 极之间形成导电沟道；</li><li><strong>增强型 PMOS 管</strong>：需要向 G 极与 S极之间施加<strong>反向电压</strong>（<span class="math inline">\(U_G&lt; U_S\)</span>），才会在 D 极与 S 极之间形成导电沟道；</li></ul><blockquote><p><strong>注意</strong>：<strong>跨导</strong> <span class="math inline">\(g_m = \frac{\Delta I_D}{\Delta U_{GS}}\)</span>同样可以用于衡量<strong>金属氧化物场效应管</strong> MOSFET的放大能力（单位为<strong>西门子</strong> <code>S</code>）。</p></blockquote><h3 id="耗尽型">耗尽型</h3><p><strong>耗尽型 MOS管</strong>同样根据内部<strong>导电沟道</strong>是形成在 <strong>N型</strong> 还是 <strong>P 型</strong> 半导体之间，被细分为 <strong>N沟道</strong> 和 <strong>P 沟道</strong>两种类型，分别称作<strong>耗尽型 NMOS 管</strong> 和 <strong>耗尽型 PMOS管</strong>，它们的电路符号分别如下面所示：</p><p><img src="/Electronics/Element/9-FET/11.png"></p><blockquote><p><strong>注意</strong>：相比于<strong>增强型 MOS 管</strong>，耗尽型MOS 管的型号非常稀少（仅十余种），因而实际工作当中极少被使用。</p></blockquote><p><strong>耗尽型 NMOS 管</strong>的内部构造与<strong>增强型 NMOS管</strong>类似，不同之处在于 <span class="math inline">\(SiO_2\)</span><strong>绝缘层</strong>中掺有大量含有<strong>正电荷</strong>的杂质（而<strong>耗尽型PMOS管</strong>掺入的是带有<strong>负电荷</strong>的杂质），从而吸引衬底当中的大量电子，并在两个N 型半导体区域之间形成<strong>导电沟道</strong>：</p><p><img src="/Electronics/Element/9-FET/12.png"></p><p>相较于增强型 MOSFET，<strong>耗尽型 MOS 管</strong>由于向 <span class="math inline">\(SiO_2\)</span><strong>绝缘层</strong>掺入了大量带有<strong>正电荷</strong>的杂质，即使<strong>G 极</strong> 和 <strong>S 极</strong>之间没有施加电压（<span class="math inline">\(U_{GS}=0V\)</span>），在 <strong>D 极</strong> 和<strong>S极</strong>之间依然也会存在着导电沟道，此时<strong>电流</strong> <span class="math inline">\(I_D\)</span> 并不会等于 <code>0A</code>；当<strong>G 极</strong> 和 <strong>S极</strong>之间施加<strong>反向电压</strong> <span class="math inline">\(U_{GS}\)</span>的时候，才会影响到导电沟道的宽度，进而使得通过的<strong>电流</strong><span class="math inline">\(I_D\)</span>发生变化。换而言之，<strong>耗尽型 MOSFET的最大特点在于栅极电压为零或者比较小的时候就已经处于导通状态</strong>（因为导电沟道已经存在）。</p><ul><li><strong>耗尽型 NMOS 管</strong>：如果 G 极与 S极之间施加<strong>正向电压</strong>（<span class="math inline">\(U_G&gt; U_S\)</span>），那么 <strong>D 极</strong>与 <strong>S极</strong>之间的导电沟道变宽，<strong>漏极电流</strong> <span class="math inline">\(I_D\)</span>才会增大；反之如果施加<strong>反向电压</strong>（<span class="math inline">\(U_G &lt; U_S\)</span>），那么 <strong>D极</strong>与 <strong>S极</strong>之间的导电沟道变窄，<strong>漏极电流</strong> <span class="math inline">\(I_D\)</span> 就会减小。</li><li><strong>耗尽型 PMOS 管</strong>：如果 G 极与 S极之间施加<strong>反向电压</strong>（<span class="math inline">\(U_G&lt; U_S\)</span>），那么 <strong>D 极</strong>与 <strong>S极</strong>之间的导电沟道变宽，<strong>漏极电流</strong> <span class="math inline">\(I_D\)</span>才会增大；反之如果施加<strong>正向电压</strong>（<span class="math inline">\(U_G &gt; U_S\)</span>），那么 <strong>D极</strong>与 <strong>S极</strong>之间的导电沟道变窄，<strong>漏极电流</strong> <span class="math inline">\(I_D\)</span> 就会减小。</li></ul><p>综上所述，<strong>耗尽型 MOS 管</strong> 分别在 <span class="math inline">\(U_{GS} &gt; 0\)</span>、<span class="math inline">\(U_{GS} = 0\)</span>、<span class="math inline">\(U_{GS} &lt; 0\)</span>这三种情况下，都总是会形成导电沟道并且通过<strong>电流</strong> <span class="math inline">\(I_D\)</span>（但是通过的电流大小会有所区别），因而电路设计时可以将其作为<strong>常开开关</strong>来使用，选型的时候则需要注意如下表格当中的三个参数：</p><table><colgroup><col style="width: 11%"><col style="width: 5%"><col style="width: 82%"></colgroup><thead><tr><th style="text-align: left;">参数名称</th><th style="text-align: center;">符号</th><th style="text-align: left;">描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>漏极到源极的击穿电压</strong></td><td style="text-align: center;"><span class="math inline">\(BV_{DSX}\)</span></td><td style="text-align: left;">选型时注意保留一定的安全裕量，以适应正常的电压波动，以及瞬态浪涌或者干扰引发的电压尖峰。</td></tr><tr><td style="text-align: left;"><strong>漏极到源极的最小饱和电流</strong></td><td style="text-align: center;"><span class="math inline">\(I_{DSS}\)</span></td><td style="text-align: left;">栅极与源极电压为零 <span class="math inline">\(U_{GS} = 0\)</span> 时，在特定漏极与源极电压 <span class="math inline">\(U_{DS}\)</span> 下面通过的漏极电流。</td></tr><tr><td style="text-align: left;"><strong>栅极到源极的截止电压</strong></td><td style="text-align: center;"><span class="math inline">\(V_{GS(OFF)}\)</span></td><td style="text-align: left;">反向增加 <strong>耗尽型 NMOS 管</strong>的栅极与源极电压 <span class="math inline">\(U_{GS}\)</span>，或者正向增加 <strong>耗尽型 PMOS管</strong> 的栅极与源极电压 <span class="math inline">\(U_{GS}\)</span>的时候，漏极电流 <span class="math inline">\(I_D\)</span>都将会逐渐减小，直至 <span class="math inline">\(U_{GS} =V_{GS(OFF)}\)</span> 的时候就会停止导通。</td></tr></tbody></table><h1 id="绝缘栅双极晶体管-igbt">绝缘栅双极晶体管 IGBT</h1><p><strong>绝缘栅双极晶体管</strong>（IGBT，Insulated Gate BipolarTransistor）是一种由<strong>场效应管</strong>和<strong>三极管</strong>共同构成的复合型元器件，其兼具有三极管的<strong>大功率特性</strong>和场效应管的<strong>高速转换</strong>与<strong>电压驱动</strong>特点，被广泛运用于各种功率电路当中（耐压值达到<code>6500V</code>，单管芯电流可达到 <code>200A</code>，开关频率可以达到<code>300kHz</code>）。该元器件同样被划分为 <strong>N 沟道</strong>和<strong>P 沟道</strong>两种类型，它们的电路符号分别如下图所示：</p><p><img src="/Electronics/Element/10-IGBT/1.png"></p><p>观察上面的符号，可以看到 <strong>IGBT</strong> 拥有着<strong>集电极</strong>（<strong>C</strong>ollector）、<strong>栅极</strong>（<strong>G</strong>ate）、<strong>发射极</strong>（<strong>E</strong>mitter）三个引脚，接下来以目前<strong>比较主流的N 沟道型 IGBT</strong> 为例展开介绍。这里可以将内部结构为下图左侧的<strong>N 沟道型 IGBT</strong>，等效为下图右侧那样由 <strong>PNP型三极管</strong> 与 <strong>增强型 NMOS 管</strong>组合而成的电路：</p><p><img src="/Electronics/Element/10-IGBT/2.png"></p><p>在下面的 N 沟道型 IGBT 偏置电路里，<strong>电源</strong> <span class="math inline">\(E_2\)</span> 通过<strong>开关</strong> <span class="math inline">\(S\)</span> 为 <strong>IGBT</strong> 提供 <span class="math inline">\(U_{GE}\)</span> 电压，<strong>电源</strong> <span class="math inline">\(E_1\)</span> 经过 <span class="math inline">\(R_1\)</span> 为 <strong>IGBT</strong> 提供 <span class="math inline">\(U_{CE}\)</span> 电压：</p><p><img src="/Electronics/Element/10-IGBT/3.png"></p><ul><li>当<strong>开关</strong> <span class="math inline">\(S\)</span>闭合的时候，如果 <strong>IGBT</strong> 的 <strong>G 极</strong>与<strong>E 极</strong>之间的<strong>电压</strong> <span class="math inline">\(U_{GE}\)</span>大于<strong>开启电压</strong>，那么 <strong>IGBT</strong> 内部的<strong>NMOS</strong> 管就会形成<strong>导电沟道</strong>，使得<strong>NMOS</strong> 管的 <strong>D 极</strong>与 <strong>S极</strong>导通，从而为三极管的<strong>基极电流</strong> <span class="math inline">\(I_B\)</span>提供通路，进而导通三极管，<strong>电流</strong> <span class="math inline">\(I_C\)</span> 开始从 <strong>IGBT</strong> 的<strong>C 极</strong>流入，经过三极管的 <strong>E 极</strong>之后分为<span class="math inline">\(I_1\)</span>（通过 NMOS 管的 <strong>D极</strong>与 <strong>S 极</strong>）和 <span class="math inline">\(I_2\)</span>（从三极管的 <strong>C极</strong>流出）两路电流。这两路<strong>电流</strong> <span class="math inline">\(I_1\)</span> 和 <span class="math inline">\(I_2\)</span> 汇合之后形成 <span class="math inline">\(I_E\)</span>（从 <strong>IGBT</strong> 的<strong>E 极</strong>流出），此时 IGBT就处于<strong>导通状态</strong>。</li><li>当<strong>开关</strong> <span class="math inline">\(S\)</span>断开的时候，<strong>IGBT</strong> 的 <strong>G 极</strong>与 <strong>E极</strong>之间的<strong>电压</strong> <span class="math inline">\(U_{GE} = 0V\)</span>，此时 NMOS管的导电沟道<strong>夹断</strong>消失，<strong>电流</strong> <span class="math inline">\(I_1\)</span> 和 <span class="math inline">\(I_2\)</span> 都为<code>0A</code>，<strong>电流</strong> <span class="math inline">\(I_C\)</span> 和 <span class="math inline">\(I_E\)</span> 也等于 <code>0A</code>，此时<strong>IGBT</strong> 就会处于<strong>截止状态</strong>。</li><li>通过<strong>电源</strong> <span class="math inline">\(E_2\)</span>调节<strong>电压</strong> <span class="math inline">\(U_{GE}\)</span>的大小，就可以改变 <strong>IGBT</strong> 内部 <strong>NMOS</strong>管导电沟道的宽度，使得<strong>电流</strong> <span class="math inline">\(I_1\)</span> 发生变化。此时 <span class="math inline">\(I_1\)</span>（即三极管的<strong>基极电流</strong><span class="math inline">\(I_B\)</span>）的微小变化，就会引发 <span class="math inline">\(I_2\)</span>（即三极管的<strong>集电极电流</strong><span class="math inline">\(I_C\)</span>）的大幅度变化。例如当<strong>电压</strong><span class="math inline">\(U_{GE}\)</span>增大的时候，<strong>NMOS</strong>管的导电沟道将会变宽，<strong>电流</strong> <span class="math inline">\(I_1\)</span> 和 <span class="math inline">\(I_2\)</span> 都会增大，从 <strong>IGBT</strong> 的<strong>C 极</strong>流入 <strong>E极</strong>流出的电流也<strong>随之增大</strong>。</li></ul><p><img src="/Electronics/Element/10-IGBT/4.png"></p><blockquote><p><strong>注意</strong>：上图右侧的三款元器件被称作<strong>功率型 IGBT模块</strong>，通常运用在一些<strong>大电流高电压</strong>的场景，主要由IGBT 和续流二极管通过特定的电路<strong>桥接封装</strong>而成。</p></blockquote><h1 id="碳化硅功率器件-sic">碳化硅功率器件 SiC</h1><p><strong>碳化硅</strong>（SiC，Silicon Carbide）是由硅 <code>Si</code>和碳 <code>C</code>共同构成的化合物半导体材料，可以通过向碳化硅材料当中掺入<code>氮</code>或<code>磷</code>来形成N型半导体，或者向碳化硅材料当中掺入<code>铍</code>、<code>硼</code>、<code>铝</code>、<code>镓</code>来形成P 型半导体。其在 <code>禁带宽度</code>（3倍）、<code>击穿电场强度</code>（10倍以上）、<code>饱和电子漂移速率</code>、<code>热传导率</code>（3倍）方面远远优于传统硅基半导体材料。目前使用碳化硅材料生产的元器件主要有<strong>SBD</strong> 肖特基势垒二极管和 <strong>MOSFET</strong>金属氧化物场效应管。</p><p><img src="/Electronics/Element/11-SiC/1.png"></p><h2 id="碳化硅二极管-sic-sbd">碳化硅二极管 SiC-SBD</h2><p>由碳化硅材料制作的<strong>肖特基势垒二极管</strong>（SBD）不仅具备出色的高速开关性能，还实现了更高的<strong>耐压值</strong>，而与高耐压型的硅基<strong>快速恢复二极管</strong>相比，其<strong>反向恢复时间</strong>更快，可以实现更低的损耗与小型化：</p><p><img src="/Electronics/Element/11-SiC/2.png"></p><h2 id="碳化硅场效应管-sic-mosfet">碳化硅场效应管 SiC-MOSFET</h2><p>使用<strong>碳化硅</strong>作为衬底材料的<strong>金属氧化物场效应管</strong>（MOSFET）耐压值可以高达<code>1000V</code> 以上，相比传统 IGBT其<strong>工作频率</strong>更高，从而有效降低了开关损耗。而相对于同等<strong>耐压值</strong>的硅基MOSFET，其<strong>导通电阻</strong>更小，在同等导通电阻条件下可以有效减小元器件的体积，并且显著的降低恢复损耗：</p><p><img src="/Electronics/Element/11-SiC/3.png"></p><h1 id="半导体元器件总结">半导体元器件总结</h1><table><colgroup><col style="width: 9%"><col style="width: 4%"><col style="width: 85%"></colgroup><thead><tr><th>BJT 与 MOSFET 比较</th><th>缩写</th><th>描述</th></tr></thead><tbody><tr><td><strong>三极管</strong></td><td><strong>BJT</strong></td><td>电流控制型元件，通过<strong>基极</strong>流向<strong>发射极</strong>的电流<span class="math inline">\(I_{BE}\)</span>来控制<strong>集电极</strong>与<strong>发射极</strong>之间通过<strong>电流</strong><span class="math inline">\(I_{CE}\)</span> 的大小。</td></tr><tr><td><strong>金属氧化物场效应管</strong></td><td><strong>MOSFET</strong></td><td>电压控制型元件，通过<strong>栅级</strong>与<strong>源极</strong>之间的<strong>电压</strong><span class="math inline">\(V_{GS}\)</span>来控制<strong>漏极</strong>与<strong>源极</strong>之间的<strong>电阻</strong><span class="math inline">\(R_{DS}\)</span>，从而实现对<strong>漏极</strong>与<strong>源极</strong>之间<strong>电压</strong><span class="math inline">\(V_{DS} = \frac{I_{DS}}{R_{DS}}\)</span>的控制。</td></tr></tbody></table><table><colgroup><col style="width: 17%"><col style="width: 7%"><col style="width: 75%"></colgroup><thead><tr><th>功率型半导体元器件比较</th><th>缩写</th><th>描述</th></tr></thead><tbody><tr><td><strong>金属氧化物场效应管</strong></td><td><strong>MOSFET</strong></td><td>大电流，低耐压，开关频率极高（可以高达数十<code>兆赫兹</code>），即有功率型器件，也有高频小信号器件。</td></tr><tr><td><strong>可控硅</strong></td><td><strong>SCR</strong></td><td>大功率器件，频率极低（仅数<code>千赫兹</code>），只能控制开，不能控制关，但是抗过载能力极强。</td></tr><tr><td><strong>绝缘栅双极晶体管</strong></td><td><strong>IGBT</strong></td><td>大功率器件，频率较低（几十至几百<code>千赫兹</code>），可以控制开和关，成本比可控硅略高，逐渐在替代可控硅。</td></tr></tbody></table><blockquote><p><strong>注意</strong>：<strong>三极管</strong>可以理解为使用<code>二极管</code>控制另外一个<code>二极管</code>，而<strong>场效应管</strong>可以理解为用<code>电容</code>控制<code>电阻</code>，<strong>IGBT</strong>则是使用<code>电容</code>控制<code>二极管</code>。</p></blockquote><h1 id="连接器-connector">连接器 Connector</h1><p><strong>SH1.0</strong>、<strong>ZH1.5</strong>、<strong>PH2.0</strong>、<strong>XH2.5</strong>系列连接器应用广泛， <a href="https://www.xunpu.com.cn/">东莞讯普（XUNPU）</a>、<a href="http://www.zx-precise.com/">深圳兆星（Megastar）</a>等厂家均有生产：</p><table><thead><tr><th style="text-align: center;">连接器型号</th><th style="text-align: center;">额定电压</th><th style="text-align: left;">额定电流</th><th style="text-align: left;">耐压值</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>SH1.0</strong> 型</td><td style="text-align: center;"><code>50V  交直流</code></td><td style="text-align: left;"><code>1A 交直流</code></td><td style="text-align: left;"><code>500V 交流/分钟</code></td></tr><tr><td style="text-align: center;"><strong>MX1.25</strong> 型</td><td style="text-align: center;"><code>125V 交直流</code></td><td style="text-align: left;"><code>1A 交直流</code></td><td style="text-align: left;"><code>500V 交流/分钟</code></td></tr><tr><td style="text-align: center;"><strong>ZH1.5</strong> 型</td><td style="text-align: center;"><code>100V 交直流</code></td><td style="text-align: left;"><code>1A 交直流</code></td><td style="text-align: left;"><code>500V 交流/分钟</code></td></tr><tr><td style="text-align: center;"><strong>PH2.0</strong> 型</td><td style="text-align: center;"><code>250V 交直流</code></td><td style="text-align: left;"><code>2A 交直流</code></td><td style="text-align: left;"><code>500V 交流/分钟</code></td></tr><tr><td style="text-align: center;"><strong>XH2.5</strong> 型</td><td style="text-align: center;"><code>250V 交直流</code></td><td style="text-align: left;"><code>3A 交直流</code></td><td style="text-align: left;"><code>1000V 交流/分钟</code></td></tr></tbody></table><p>锂电池上面常用的 <strong>XT</strong> 系列连接器是 <a href="https://www.china-amass.com/">常州艾迈斯（AMASS）</a>的专利产品，主要运用于低压直流大电流的场景：</p><table><thead><tr><th style="text-align: center;">连接器型号</th><th style="text-align: left;">额定电压</th><th style="text-align: left;">额定电流</th><th style="text-align: left;">瞬时电流</th><th style="text-align: left;">公头线规</th></tr></thead><tbody><tr><td style="text-align: center;"><strong>XT30</strong> 型</td><td style="text-align: left;"><code>500V 直流</code></td><td style="text-align: left;"><code>15A</code></td><td style="text-align: left;"><code>30A</code></td><td style="text-align: left;"><code>18AWG</code></td></tr><tr><td style="text-align: center;"><strong>XT60</strong> 型</td><td style="text-align: left;"><code>500V 直流</code></td><td style="text-align: left;"><code>30A</code></td><td style="text-align: left;"><code>60A</code></td><td style="text-align: left;"><code>12AWG</code></td></tr><tr><td style="text-align: center;"><strong>XT90</strong> 型</td><td style="text-align: left;"><code>500V 直流</code></td><td style="text-align: left;"><code>40A</code></td><td style="text-align: left;"><code>90A</code></td><td style="text-align: left;"><code>10AWG</code></td></tr></tbody></table>]]></content>
    
    
    <summary type="html">&lt;p&gt;自从 &lt;strong&gt;1883&lt;/strong&gt;
年电子管作为人类第一个电子元器件诞生以来，&lt;strong&gt;电子元器件&lt;/strong&gt;的发展历程，见证了人类科技进步的辉煌成就。从最初的
&lt;code&gt;电阻&lt;/code&gt;、&lt;code&gt;电容&lt;/code&gt;、&lt;code&gt;电感&lt;/code&gt;
等基础元器件，发展到
&lt;code&gt;晶闸管&lt;/code&gt;、&lt;code&gt;场效应管&lt;/code&gt;、&lt;code&gt;IGBT&lt;/code&gt;
等半导体元器件，再进一步发展到现如今各种琳琅满目的&lt;strong&gt;微处理器&lt;/strong&gt;、&lt;strong&gt;微控制器&lt;/strong&gt;、&lt;strong&gt;传感器&lt;/strong&gt;。电子元器件的功能越来越强大，体积越来越小，集成度越来越高。这些变化不仅极大地提升了电子产品的性能和可靠性，也为我们带来了更加便捷与智能的生活方式。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/Electronics/Element/logo.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;电子元器件如同电子设备的细胞，承载着实现各种复杂功能的基础任务，它们是电路设计和调试中不可或缺的元素。实际的电路设计过程当中，各类电子元器件的选择、连接、调试都至关重要，正确的选型能够确保设备的性能和稳定性，而合理的连接方式更是能够降低信号的损失与干扰。本文旨在以简单明了的方式介绍
&lt;code&gt;电阻器&lt;/code&gt;、&lt;code&gt;电容器&lt;/code&gt;、&lt;code&gt;电感器&lt;/code&gt;、&lt;code&gt;变压器&lt;/code&gt;、&lt;code&gt;二极管&lt;/code&gt;、&lt;code&gt;三极管&lt;/code&gt;、&lt;code&gt;晶闸管&lt;/code&gt;、&lt;code&gt;场效应管&lt;/code&gt;、&lt;code&gt;IGBT&lt;/code&gt;
等常用分立式电子元器件的参数与选型注意事项。&lt;/p&gt;</summary>
    
    
    
    <category term="硬件电子技术" scheme="http://www.uinio.com/categories/%E7%A1%AC%E4%BB%B6%E7%94%B5%E5%AD%90%E6%8A%80%E6%9C%AF/"/>
    
    
    <category term="元器件" scheme="http://www.uinio.com/tags/%E5%85%83%E5%99%A8%E4%BB%B6/"/>
    
  </entry>
  
  <entry>
    <title>兆易创新 UINIO-MCU-GD32F350 固件库开发指南</title>
    <link href="http://www.uinio.com/Project/UINIO-MCU-GD32/"/>
    <id>http://www.uinio.com/Project/UINIO-MCU-GD32/</id>
    <published>2024-03-17T16:00:00.000Z</published>
    <updated>2025-06-25T14:52:28.292Z</updated>
    
    <content type="html"><![CDATA[<p>早在新冠疫情爆发前的 <strong>2019</strong> 年，就曾经撰写过一篇关于<strong>ARM</strong> 标准库的技术长文 <a href="http://uinio.com/Embedded/STM32F103/"><strong>《意法半导体STM32F103 标准库典型实例》</strong></a>，文章非常详尽的介绍了各种常见片上外设资源的应用。时至 4年以后的今天，国产微控制器在工程实践领域已经得到了广泛运用，因而基于<a href="https://www.gigadevice.com.cn/product/mcu"><strong>兆易创新</strong></a>推出的国产 ARM 微控制器，设计和制作了 <a href="https://github.com/uinika/UINIO-MCU-GD32F350RBT6"><strong>UINIO-MCU-GD32F350RBT6</strong></a>这款开源核心板，同时撰写了本篇文章作为配套的资料教程，希冀为国产芯片的商业化普及尽自己一份绵薄之力。</p><p><img src="/Project/UINIO-MCU-GD32/logo.png"></p><p><a href="https://github.com/uinika/UINIO-MCU-GD32F350RBT6"><strong>UINIO-MCU-GD32F350RBT6</strong></a>是一款采用 LQFP64 封装的 <strong>GD32F350RBT6</strong>微控制器核心板，基于 <strong>ARM Cortex-M4</strong> 内核架构，主频高达<code>108MHz</code>，拥有 <code>128K</code> 容量 Flash，以及<code>16K</code> 的 SRAM。而 <a href="https://github.com/uinika/UINIO-MCU-GD32F103C"><strong>UINIO-MCU-GD32F103C</strong></a>采用 LQFP48 封装的 <strong>GD32F103Cxxx</strong> 系列微控制器（包括<code>GD32F103CBT6</code>、<code>GD32F103C8T6</code>、<code>GD32F103C6T6</code>、<code>GD32F103C4T6</code>），基于<strong>ARM Cortex-M3</strong> 内核架构，主频达到<code>108MHz</code>，拥有 <code>16K ~ 128K</code> 容量 Flash，以及<code>6K ~ 20K</code> 的 SRAM。</p><span id="more"></span><h1 id="准备-gd32-支持包-固件库">准备 GD32 支持包 &amp; 固件库</h1><p>这里以 <strong>UINIO-MCU-GD32F350RBT6</strong>核心板作为例子，首先需要前往兆易创新的 <a href="https://www.gd32mcu.com/cn/download/7?kw=GD32F3x0"><strong>GD32MCU 微控制器</strong></a>官方网站，把如下两个开发资源下载到本地计算机：</p><ol type="1"><li><strong>GD32F350RBT6</strong> 固件库<code>GD32F3x0_Firmware_Library_V2.2.1</code>。</li><li><strong>Keil uVision5</strong> 开发环境的支持包<code>GigaDevice.GD32F3x0_DFP.3.0.2.pack</code>。</li></ol><p>然后，启动 <strong>Keil uVision5</strong>开发环境，开始导入或者在线安装<code>GigaDevice.GD32F3x0_DFP.3.0.2.pack</code> 支持包：</p><p><img src="/Project/UINIO-MCU-GD32/1-Keil/0.png"></p><p>接下来，解压 <code>GD32F3x0_Firmware_Library_V2.2.1</code>固件库，此时会得到如下一系列目录：</p><ul><li><strong>Docs</strong>：包含有官方评估板的<strong>原理图</strong>和固件库的<strong>使用指南</strong>。</li><li><strong>Examples</strong>：各种 <strong>GD32F350RBT6</strong>片上外设的官方示例源程序。</li><li><strong>Firmware</strong>：包含有<strong>内核库</strong><code>CMSIS</code>、<strong>标准外设库</strong><code>GD32F3x0_standard_peripheral</code>、<strong>USB文件系统库</strong> <code>GD32F3x0_usbfs_library</code>三个子目录。</li><li><strong>Template</strong>：集成开发环境 <strong>IAR</strong> 和<strong>Keil uVision4</strong> 的工程模板，包含有 LED 闪烁、USART打印、按键控制的简单示例程序。</li><li><strong>Utilities</strong>：一些第三方组件和 GD32配套的评估板测试文件。</li></ul><p>其中 <strong>Examples</strong>下面的每一个子目录，都对应着一种片上外设的示例程序，里面通常会包含有如下的源文件：</p><ul><li><code>main.c</code>：主程序源文件。</li><li><code>systick.h</code>：SysTick 精准延时头文件；</li><li><code>systick.c</code>：SysTick 精准延时源文件；</li><li><code>GD32f3x0.it.h</code>：中断处理程序头文件；</li><li><code>GD32f3x0_it.c</code>：中断处理程序源文件（未使用中断，所有函数体为空）；</li><li><code>GD32f3x0_libopt.h</code>：通过预处理语句 <code>#include</code>包含指定的外设库 <code>.h</code> 头文件（默认导入全部外设）；</li></ul><p>而 <strong>Firmware</strong> 目录下面包含有<strong>GD32F350RBT6</strong> 固件库的核心源文件：</p><ul><li><code>CMSIS</code> 子目录包含有 <strong>ARM Cortex-M4</strong>内核的支持文件、启动代码、库引导文件，以及 <code>GD32F3x0</code>的全局头文件和系统配置文件。</li><li><code>GD32F3x0_standard_peripheral</code> 子目录下的<code>Include</code> 包含了固件库所需要的头文件，而 <code>Source</code>则包含有固件库所需的源文件。</li></ul><h1 id="测试-uinio-mcu-gd32-核心板">测试 UINIO-MCU-GD32 核心板</h1><p>打开 <code>GD32F3x0_Firmware_Library_V2.2.1</code> 固件库下面的<code>Template</code> 目录，删掉除开 <code>Keil_project</code>目录之外的其它文件与目录，然后将 <code>Examples\GPIO\Running_led</code>内的全部源文件，拷贝至 <code>Template</code>目录当中，从而获得如下的文件目录结构：</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line">Template</span><br><span class="line">├── Keil_project</span><br><span class="line">│   ├── Project.uvopt</span><br><span class="line">│   └── Project.uvproj</span><br><span class="line">├── gd32f3x0_it.c</span><br><span class="line">├── gd32f3x0_it.h</span><br><span class="line">├── gd32f3x0_libopt.h</span><br><span class="line">├── main.c</span><br><span class="line">├── readme.txt</span><br><span class="line">├── systick.c</span><br><span class="line">└── systick.h</span><br></pre></td></tr></table></figure><p>鼠标双击 <code>Template</code> 目录下面的工程描述文件<code>Project.uvproj</code>，启动 <strong>Keil uVision5</strong>。由于<code>GD32F3x0_Firmware_Library_V2.2.1</code> 当中的示例工程采用的是<strong>Keil uVision4</strong>建立和编译，因而此时会弹出下面的错误信息：</p><p><img src="/Project/UINIO-MCU-GD32/1-Keil/1.png"></p><p>按下【确定】按钮忽略这些错误信息，依次选择顶部菜单栏上面的【Project-&gt; Manage -&gt; Migrate to Version 5 Format...】，把工程迁移成为<strong>Keil uVision5</strong> 兼容的格式：</p><p><img src="/Project/UINIO-MCU-GD32/1-Keil/2.png"></p><p>此时会提示工程描述文件需要从 <strong>Keil uVision4</strong> 的<code>Project.uvproj</code> 保存为 <strong>Keil uVision5</strong> 的<code>Project.uvprojx</code>，直接按下【确定】按钮即可：</p><p><img src="/Project/UINIO-MCU-GD32/1-Keil/3.png"></p><p>在开始接下来的操作之前，需要先将 <strong>Keil uVision5</strong>工程的编译目标切换为 <strong>UINIO-MCU-GD32F350RBT6</strong>核心板所使用的型号【GD32F350】：</p><p><img src="/Project/UINIO-MCU-GD32/1-Keil/4.png"></p><p>点击顶部工具栏上的【Options forTarget...】按钮，指定<strong>目标选项对话框</strong>里的【ARMCompiler】版本为 <code>compiler version 5</code>：</p><p><img src="/Project/UINIO-MCU-GD32/1-Keil/5.png"></p><blockquote><p><strong>注意</strong>：这里必须修改 <strong>Keil uVision5</strong>当中 ARM 编译器版本，否则会导致后续的编译操作出现错误，具体请参考 <a href="http://uinio.com/Project/UINIO-DAP-Link">《ARM 调试工具UINIO-DAP-Link 应用详解》</a> 一文的 <a href="http://uinio.com/Project/UINIO-DAP-Link/#%E6%B7%BB%E5%8A%A0-arm-compiler-version-5">添加ARM Compiler version 5</a> 小节内容。</p></blockquote><p>切换至对话框的【Output】选项卡，在勾选【Create HEXFile】的同时，把【Name of Executable】修改为<code>Project.hex</code>（务必添加 <code>.hex</code>后缀，否则默认烧录的是 <code>.axf</code> 文件）：</p><p><img src="/Project/UINIO-MCU-GD32/1-Keil/6.png"></p><p>再切换至对话框当中的【Debug】选项卡，此时需要将 <a href="http://uinio.com/Project/UINIO-DAP-Link/"><strong>UINIO-DAP-Link</strong></a>插入至计算机的 USB 接口，然后在下拉选择【CMSIS-DAPDebugger】之后，再按下右侧的【Settings】按钮：</p><p><img src="/Project/UINIO-MCU-GD32/1-Keil/7.png"></p><p>此时会弹出<strong>调试器设置对话框</strong>，这里我们选择【UINIO-CMSIS-DAP】，并且将【MaxClock】配置为 <code>10MHz</code>：</p><p><img src="/Project/UINIO-MCU-GD32/1-Keil/8.png"></p><p>最后再切换至【Flash Download】选项卡，勾选【Reset andRun】，并且点击【Add】按钮添加片上 Flash 的编程算法：</p><p><img src="/Project/UINIO-MCU-GD32/1-Keil/9.png"></p><p>完成上述配置步骤之后点击【OK】，回到 <strong>Keil uVision5</strong>的主界面，此时按下快捷键【F7】或者顶部工具栏上的【Build】按钮编译示例工程，再按下快捷键【F8】或者【Download】按钮将编译后得到的<code>.hex</code> 程序下载至 <strong>UINIO-MCU-GD32F350RBT6</strong>核心板运行，此时整个工程的目录文件结构如下所示，其中的 <code>Out</code>目录保存着编译后产生的十六进制 <code>.hex</code> 文件：</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line">Template</span><br><span class="line">├── Keil_project</span><br><span class="line">│   ├── Project.uvguix.hank</span><br><span class="line">│   ├── Project.uvopt</span><br><span class="line">│   ├── Project.uvoptx</span><br><span class="line">│   ├── Project.uvproj.saved_uv4</span><br><span class="line">│   ├── Project.uvprojx</span><br><span class="line">│   ├── RTE</span><br><span class="line">│   │   ├── _GD32F310</span><br><span class="line">│   │   │   └── RTE_Components.h</span><br><span class="line">│   │   ├── _GD32F330</span><br><span class="line">│   │   │   └── RTE_Components.h</span><br><span class="line">│   │   └── _GD32F350</span><br><span class="line">│   │       └── RTE_Components.h</span><br><span class="line">│   ├── list</span><br><span class="line">│   │   ├── Project.map</span><br><span class="line">│   │   └── startup_gd32f3x<span class="number">0.l</span>st</span><br><span class="line">│   └── output</span><br><span class="line">├── gd32f3x0_it.c</span><br><span class="line">├── gd32f3x0_it.h</span><br><span class="line">├── gd32f3x0_libopt.h</span><br><span class="line">├── main.c</span><br><span class="line">├── readme.txt</span><br><span class="line">├── systick.c</span><br><span class="line">└── systick.h</span><br></pre></td></tr></table></figure><p>该示例程序会每间隔 4 秒的时间，循环切换<strong>UINIO-MCU-GD32F350RBT6</strong> 的四个 GPIO 引脚<code>C2</code>、<code>C10</code>、<code>C11</code>、<code>C12</code>的高低电平状态，此时通过万用表就可以测量出运行结果，从而方便的判断出程序是否下载成功，以及核心板运行是否存在有故障。</p><blockquote><p><strong>注意</strong>：<strong>DAPLink</strong> 是 ARM系列微控制器开发过程当中，程序下载与调试不可少的工具，相关资料和设计资源可以参考笔者之前撰写的<a href="http://uinio.com/Project/UINIO-DAP-Link/">《ARM 调试工具UINIO-DAP-Link 应用详解》</a> 一文。</p></blockquote><h1 id="搭建-keil-uvision5-自定义工程">搭建 Keil uVision5自定义工程</h1><h2 id="新建目录与拷贝源文件">新建目录与拷贝源文件</h2><p>本节内容开始尝试自己动手搭建 <strong>Keil uVision5</strong>工程，首先新建一个名称为 <code>Keil-GD32F350RBT6</code> 的 <strong>KeiluVision5</strong>工程，并将其保存至同名的目录下面，然后再新建如下一系列子目录，并且将固件库里的源文件拷贝至对应的子目录：</p><ul><li><strong>Applications</strong>：保存应用层相关的源文件。</li><li><strong>Documents</strong>：用于存放 Markdown说明文档，可以预先放置一个 <code>README.md</code> 文件。</li><li><strong>Drivers</strong>：存放针对<strong>UINIO-MCU-GD32F350RBT6</strong> 定制的板级驱动程序。</li><li><strong>Firmware</strong>：用于放置<code>GD32F3x0_Firmware_Library_V2.2.1</code> 当中 <code>Firmware</code>目录下的全部内容（即<code>CMSIS</code>、<code>GD32F3x0_standard_peripheral</code>、<code>GD32F3x0_usbfs_library</code>三个子目录）。</li><li><strong>Sources</strong>：用于保存<code>GD32F3x0_Firmware_Library_V2.2.1</code> 下面的<code>Template</code> 目录当中，除<code>IAR_project</code>、<code>Keil_project</code>、<code>readme.txt</code>之外的文件（即<code>main.c/h</code>、<code>systick.c/h</code>、<code>gd32f3x0_it.c/h</code>、<code>gd32f3x0_libopt.h</code>七个源文件）。</li></ul><h2 id="创建分组与添加源文件">创建分组与添加源文件</h2><p>鼠标点击 <strong>Keil uVision5</strong> 顶部菜单栏上面的【FileExtensions, Books and Environment...】按钮：</p><p><img src="/Project/UINIO-MCU-GD32/2-Project/0.png"></p><p>在弹出的<strong>工程管理项</strong>对话框当中，分别将左侧的【ProjectTargets】命名为<code>Keil-GD32F350RBT6</code>，而中间的【Groups】则分别建立如下几个分组，并且通过右侧的<code>Files</code> 向指定分组添加相应的源文件：</p><p><img src="/Project/UINIO-MCU-GD32/2-Project/1.png"></p><ul><li><strong>CMSIS 分组</strong>：分别添加<code>Keil-GD32F350RBT6\Firmware\CMSIS\GD\GD32F3x0\Source</code>目录下的 <code>system_gd32f3x0.c</code> 外设接入层源文件，以及<code>Keil-GD32F350RBT6\Firmware\CMSIS\GD\GD32F3x0\Source\ARM</code>目录下的 <code>startup_gd32f3x0.s</code>启动文件（添加对话框的文件类型要修改为 <code>.s</code>）。</li><li><strong>Drivers 分组</strong>：暂时不需要添加任何源文件。</li><li><strong>Firmware 分组</strong>：按需添加<code>Keil-GD32F350RBT6\Firmware\GD32F3x0_standard_peripheral\Source</code>目录下的 <code>.c</code> 源文件（其中的 <code>gd32f3x0_rcu.c</code> 和<code>gd32f3x0_gpio.c</code> 属于必须添加）。</li><li><strong>Documents 分组</strong>：将<code>Keil-GD32F350RBT6\Documents</code> 目录下新建的<code>README.md</code> 文件添加进去。</li><li><strong>Applications</strong> 分组：添加<code>Keil-GD32F350RBT6\Sources</code> 目录下的<code>main.c</code>、<code>systick.c</code>、<code>gd32f3x0_it.c</code>三个源文件。</li><li><strong>Sources 分组</strong>：暂时不需要添加任何源文件。</li></ul><p>完成上述操作之后，在<strong>工程管理项</strong>对话框当中，各个分组下面的源文件情况如下图所示：</p><p><img src="/Project/UINIO-MCU-GD32/2-Project/2.png"></p><p>点击【OK】按钮关闭<strong>工程管理项</strong>对话框，此时<strong>Keil uVision5</strong> 左侧呈现的工程目录结构如下面所示：</p><p><img src="/Project/UINIO-MCU-GD32/2-Project/3.png"></p><h2 id="移除-source-目录下的冗余代码">移除 Source 目录下的冗余代码</h2><p>为了避免工程搭建过程当中，直接拷贝官方固件库 <code>Template</code>目录下的源文件，出现冗余代码导致编译错误的情况，接下来还需要对<code>Source</code> 目录进行一些清理工作。首先需要删除掉该目录下<code>main.c</code> 源文件里多余的内容，只需要保留如下所示的代码：</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;systick.h&quot;</span></span></span><br><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">&quot;main.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">int</span> <span class="title">main</span><span class="params">(<span class="type">void</span>)</span> </span>&#123;</span><br><span class="line">    <span class="comment">/* configure systick */</span></span><br><span class="line">    <span class="built_in">systick_config</span>();</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span>(<span class="number">1</span>) &#123;&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>除此之外，还需要再移除掉 <code>Source</code> 目录下<code>gd32f3x0_it.c</code> 源文件里面，如下所示的无效代码片段：</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*!</span></span><br><span class="line"><span class="comment">    \brief      this function handles SysTick exception</span></span><br><span class="line"><span class="comment">    \param[in]  none</span></span><br><span class="line"><span class="comment">    \param[out] none</span></span><br><span class="line"><span class="comment">    \retval     none</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">SysTick_Handler</span><span class="params">(<span class="type">void</span>)</span></span></span><br><span class="line"><span class="function"></span>&#123;</span><br><span class="line">    <span class="built_in">led_spark</span>();</span><br><span class="line">    <span class="built_in">delay_decrement</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="配置编译器路径与选项">配置编译器路径与选项</h2><p>点击 <strong>Keil uVision5</strong> 工具栏顶部的【Options fortarget】，在弹出的<strong>目标选项对话框</strong>当中，首先切换至【C/C++】选项卡，将【Define】输入框设置为<code>USE_STDPERIPH_DRIVER,GD32F3X0,GD32F350</code>：</p><p><img src="/Project/UINIO-MCU-GD32/2-Project/4.png"></p><p>然后再点击对话框当中【Include Paths】输入框右侧的按钮，配置 ARM编译器分别包含 <strong>Keil-GD32F350RBT6</strong>工程目录下的如下路径：</p><ul><li><code>.\Sources</code></li><li><code>.\Firmware\CMSIS</code></li><li><code>.\Firmware\CMSIS\GD\GD32F3x0\Include</code></li><li><code>.\Firmware\GD32F3x0_standard_peripheral\Include</code></li></ul><p><img src="/Project/UINIO-MCU-GD32/2-Project/5.png"></p><p>接下来切换至【Target】选项卡，选择 ARM 编译器的版本为<strong>5</strong>，并勾选界面上 <strong>Keil uVision5</strong>自带的用于串口重定向的【Use MicroLIB】工具库：</p><p><img src="/Project/UINIO-MCU-GD32/2-Project/6.png"></p><p>最后切换到【Output】选项卡，将【Name of Executable】输入框设置为<code>Keil-GD32F350RBT6.hex</code>，并且勾选 <strong>Create HEXFile</strong> 使得编译结果为十六进制 <code>.hex</code> 格式：</p><p><img src="/Project/UINIO-MCU-GD32/2-Project/7.png"></p><h2 id="测试工程的编译下载">测试工程的编译下载</h2><p>完成上述配置工作之后，关闭 <strong>Keil uVision5</strong>界面上的全部对话框，然后按下快捷键【F7】或者顶部工具栏上的【Build】按钮，将新建工程里的相关源文件编译为一个<code>Keil-GD32F350RBT6.hex</code> 文件：</p><figure class="highlight cmd"><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></pre></td><td class="code"><pre><span class="line">Build started: Project: Keil-GD32F350RBT6</span><br><span class="line">*** Using Compiler &#x27;V5.<span class="number">06</span> update <span class="number">7</span> (build <span class="number">960</span>)&#x27;, folder: &#x27;D:\Software\Tech\Keil\ARM\ARMCC\Bin&#x27;</span><br><span class="line">Build target &#x27;Keil-GD32F350RBT6&#x27;</span><br><span class="line">assembling startup_gd32f3x0.s...</span><br><span class="line">compiling gd32f3x0_dma.c...</span><br><span class="line">compiling gd32f3x0_dbg.c...</span><br><span class="line">compiling gd32f3x0_crc.c...</span><br><span class="line">compiling gd32f3x0_ctc.c...</span><br><span class="line">compiling gd32f3x0_cec.c...</span><br><span class="line">compiling gd32f3x0_dac.c...</span><br><span class="line">compiling gd32f3x0_exti.c...</span><br><span class="line">compiling gd32f3x0_adc.c...</span><br><span class="line">compiling gd32f3x0_cmp.c...</span><br><span class="line">compiling system_gd32f3x0.c...</span><br><span class="line">compiling gd32f3x0_fmc.c...</span><br><span class="line">compiling gd32f3x0_fwdgt.c...</span><br><span class="line">compiling gd32f3x0_i2c.c...</span><br><span class="line">compiling gd32f3x0_misc.c...</span><br><span class="line">compiling gd32f3x0_gpio.c...</span><br><span class="line">compiling gd32f3x0_pmu.c...</span><br><span class="line">compiling gd32f3x0_spi.c...</span><br><span class="line">compiling gd32f3x0_syscfg.c...</span><br><span class="line">compiling gd32f3x0_rcu.c...</span><br><span class="line">compiling gd32f3x0_rtc.c...</span><br><span class="line">compiling gd32f3x0_tsi.c...</span><br><span class="line">compiling gd32f3x0_timer.c...</span><br><span class="line">compiling gd32f3x0_wwdgt.c...</span><br><span class="line">compiling gd32f3x0_usart.c...</span><br><span class="line">compiling gd32f3x0_it.c...</span><br><span class="line">compiling main.c...</span><br><span class="line">compiling systick.c...</span><br><span class="line">linking...</span><br><span class="line">Program Size: Code=<span class="number">1104</span> RO-data=<span class="number">368</span> RW-data=<span class="number">4</span> ZI-data=<span class="number">1028</span></span><br><span class="line"><span class="function">FromELF: <span class="title">creating</span> <span class="title">hex</span> <span class="title">file</span>...</span></span><br><span class="line"><span class="function">&quot;.\<span class="title">Objects</span>\<span class="title">Keil</span>-<span class="title">GD32F350RBT6.hex</span>&quot; - 0 <span class="title">Error</span>(<span class="title">s</span>), 0 <span class="title">Warning</span>(<span class="title">s</span>).</span></span><br><span class="line"><span class="function"><span class="title">Build</span> <span class="title">Time</span> <span class="title">Elapsed</span>:  00:00:03</span></span><br></pre></td></tr></table></figure><p>如果编译结果显示 <code>0 Error(s), 0 Warning(s)</code>，说明这个<strong>Keil uVision5</strong>工程已经搭建成功。接下来，就可以按下快捷键【F8】或者顶部工具栏上的【Download】按钮，把编译后得到的十六进制文件<code>Keil-GD32F350RBT6.hex</code>，通过 <strong>UINIO-DAP-Link</strong>下载至 <strong>UINIO-MCU-GD32F350RBT6</strong> 核心板上面运行：</p><figure class="highlight cmd"><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></pre></td><td class="code"><pre><span class="line">Load &quot;D:\\Workspace\\UINIO-MCU-GD32F350RBT6\\Keil-GD32F350RBT6\\Objects\\Keil-GD32F350RBT6.hex&quot;</span><br><span class="line"><span class="built_in">Erase</span> Done.</span><br><span class="line">Programming Done.</span><br><span class="line"><span class="built_in">Verify</span> OK.</span><br><span class="line">Flash Load finished <span class="built_in">at</span> <span class="number">18</span>:<span class="number">22</span>:<span class="number">55</span></span><br></pre></td></tr></table></figure><blockquote><p><strong>注意</strong>：为了大家能够方便快速的搭建测试项目，该自定义工程已被保存到开源硬件项目<a href="https://github.com/uinika/UINIO-MCU-GD32F350RBT6"><strong>UINIO-MCU-GD32F350RBT6</strong></a>的 <code>Keil-GD32F350RBT6</code> 目录里面。</p></blockquote><h2 id="让-keil-uvision5-支持中文注释">让 Keil uVision5支持中文注释</h2><p>鼠标依次选择 <strong>Keil uVision5</strong> 菜单栏上的 【Edit -&gt;Configration... -&gt; 】，将弹出窗口【Editor】选项卡下的<code>Encoding</code> 选择为 <code>Chinese GB2312 (Simplified)</code>就可以支持中文注释：</p><p><img src="/Project/UINIO-MCU-GD32/2-Project/8.png"></p><blockquote><p><strong>注意</strong>：这种方式会导致 Keil uVision显示的源代码字体非常不美观，更佳的处理办法是利用<strong>Sublime</strong> 等文本编辑器提供的 <a href="https://github.com/seanliang/ConvertToUTF8">ConvertToUTF8</a>插件，将源代码文件全部转换为 <strong>UTF-8</strong> 格式的编码。</p></blockquote><h2 id="使用-astyle-格式化源代码">使用 AStyle 格式化源代码</h2><p><a href="https://astyle.sourceforge.net/">AStyle</a> 是一款用于对C/C++ 源代码进行格式化的开源插件，鼠标点击 <strong>KeiluVision5</strong> 菜单栏上的【Tools -&gt; Customize Tools Menu】：</p><p><img src="/Project/UINIO-MCU-GD32/2-Project/9.png"></p><p>在弹出的对话框当中进行如下的设置，其中的 <strong>Command</strong>就是 <code>astyle.exe</code> 可执行文件所在的路径：</p><ul><li><strong>Command</strong>:<code>D:\Software\Tech\AStyle\astyle.exe</code></li><li><strong>AStyleAll</strong>：<code>"$E*.c" "$E*.h" --style=google --indent=spaces=2</code>。</li><li><strong>AStyleFile</strong>：<code>!E --style=google --indent=spaces=2</code>。</li></ul><p>完成上述步骤之后，就可以在 <strong>Keil uVision5</strong>的菜单栏上发现【Tools -&gt; AStyle All】和【Tools -&gt; AStyleFile】两条自定义菜单项：</p><p><img src="/Project/UINIO-MCU-GD32/2-Project/10.png"></p><h1 id="mcu-微控制器系统结构概览">MCU 微控制器系统结构概览</h1><h2 id="芯片资源简介">芯片资源简介</h2><p><strong>GD32F350RBT6</strong> 是一款采用 Arm Cortex-M4 内核架构的 32位微控制器，工作频率为 <code>108MHz</code>，工作电压范围在<code>2.6V ~ 3.6V</code> 之间，工作温度介于 <code>-40°C ~ +85°C</code>范围。提供高达 <code>128KB</code> 的片上 <strong>Flash</strong> 闪存和<code>16KB</code> 的 <strong>SRAM</strong>内存，其它的片上资源情况可以参考下面表格：</p><table><thead><tr><th style="text-align: left;">资源名称</th><th style="text-align: left;">数量</th><th style="text-align: left;">资源名称</th><th style="text-align: left;">数量</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>12 位 ADC</strong></td><td style="text-align: left;">1 个</td><td style="text-align: left;"><strong>SPI</strong></td><td style="text-align: left;">2 个</td></tr><tr><td style="text-align: left;"><strong>12 位 DAC</strong></td><td style="text-align: left;">1 个</td><td style="text-align: left;"><strong>I2C</strong></td><td style="text-align: left;">2 个</td></tr><tr><td style="text-align: left;"><strong>通用比较器 CMP</strong></td><td style="text-align: left;">2 个</td><td style="text-align: left;"><strong>USART</strong></td><td style="text-align: left;">2 个</td></tr><tr><td style="text-align: left;"><strong>通用 16 位定时器</strong></td><td style="text-align: left;">5 个</td><td style="text-align: left;"><strong>I2S</strong></td><td style="text-align: left;">1 个</td></tr><tr><td style="text-align: left;"><strong>通用 32 位定时器</strong></td><td style="text-align: left;">1 个</td><td style="text-align: left;"><strong>HDMI-CEC</strong></td><td style="text-align: left;">1 个</td></tr><tr><td style="text-align: left;"><strong>基本定时器</strong></td><td style="text-align: left;">1 个</td><td style="text-align: left;"><strong>TSI</strong></td><td style="text-align: left;">1 个</td></tr><tr><td style="text-align: left;"><strong>PWM 高级定时器</strong></td><td style="text-align: left;">1 个</td><td style="text-align: left;"><strong>USBFS 全速 USB</strong></td><td style="text-align: left;">1 个</td></tr></tbody></table><p><strong>UINIO-MCU-GD32F350RBT6</strong> 采用的<strong>GD32F350RBT6</strong> 微控制器使用的是 <code>LQFP64</code>封装形式，其具体 <strong>64</strong> 个引脚的功能分配可以参见下图：</p><p><img src="/Project/UINIO-MCU-GD32/3-ARM/0.png"></p><h2 id="arm-cortex-m4-内核架构">ARM Cortex-M4 内核架构</h2><p><strong>ARM Cortex-M4</strong> 系列微控制器基于<strong>ARMv7</strong> 架构，其内核主要由下面一系列的功能单元构成：</p><p><img src="/Project/UINIO-MCU-GD32/3-ARM/1.png"></p><ul><li><strong>嵌套式向量型中断控制器</strong>（<strong>NVIC</strong>，NestedVectored Interrupt Controller）。</li><li><strong>浮点运算单元</strong>（<strong>FPU</strong>，Floating PointUnit）。</li><li><strong>闪存地址重载及断点单元</strong>（<strong>FPB</strong>，FlashPatch Breakpoint）。</li><li><strong>串行线调试接口</strong>（<strong>SW-DP</strong>，Serial-WireDebug Port）。</li><li><strong>数据观测点及跟踪单元</strong>（<strong>DWT</strong>，DataWatchpoint And Trace）。</li><li><strong>指令跟踪宏单元</strong>（<strong>ITM</strong>，InstrumentationTrace Macrocell）。</li><li><strong>跟踪端口接口单元</strong>（<strong>TPIU</strong>，Trace PortInterface Unit）。</li><li><strong>内部总线矩阵</strong>（<strong>Bus Matrix</strong>，用于实现<strong>I-Code</strong> 指令总线、<strong>D-Code</strong>数据总线、<strong>System</strong> 系统总线、<strong>PPB</strong>专用总线、<strong>AHB-AP</strong> 调试专用总线的相互联接）。</li></ul><h2 id="gd32f350rbt6-外设架构">GD32F350RBT6 外设架构</h2><p><strong>GD32F350RBT6</strong>微控制器的整体系统架构如下面的框图所示，其中<strong>AHB</strong>（Advanced High performanceBus）高级高性能总线矩阵采用的是多层总线结构，支持多个主从设备之间实现并行通信，其中<strong>主设备</strong>包含有来自<strong>ARM Cortex-M4</strong> 内核架构的<code>I-Code 指令总线</code>、<code>D-Code 数据总线</code>、<code>System 系统总线</code>，以及来自于内核外部的<code>DMA 总线</code>：</p><ul><li><strong>I-Code 总线</strong>：即 Instruction Code，用于从<code>0x 0000 0000 ~ 0x 1FFF FFFF</code><strong>代码区域</strong>获取向量。</li><li><strong>D-Code 总线</strong>：即 DataCode，用于加载和存储数据，以及调试访问<strong>代码区域</strong>。</li><li><strong>System系统总线</strong>：用于获取指令和向量、加载与存储数据、调试访问<strong>系统区域</strong>（包括内部SRAM 和外设区域）。</li><li><strong>DMA总线</strong>：用于直接内存访问（<strong>DMA</strong>，Direct MemoryAccess）的传输总线。</li></ul><p><img src="/Project/UINIO-MCU-GD32/3-ARM/2.png"></p><p>除此之外，<strong>AHB总线矩阵</strong>的<strong>从设备</strong>包含有来自 Flash 存储控制器的<strong>IBUS</strong> 和 <strong>DBUS</strong> 总线、<strong>SRM控制器</strong>总线，以及 <strong>AHB1</strong> 和 <strong>AHB2</strong>总线：</p><ul><li><strong>AHB2</strong> 总线连接了<strong>A</strong>、<strong>B</strong>、<strong>C</strong>、<strong>D</strong>、<strong>F</strong>一共五组 GPIO 端口。</li><li><strong>AHB1</strong> 总线连接的是其它片上外设资源，其通过两组<strong>AHB-APB 总线桥</strong>（AHB to APB Bridge 1/2）分别提供了<strong>AHB1</strong>总线与<strong>高级外设总线</strong>（<strong>APB</strong>，AdvancedPeripheral Bus）之间的同步连接。</li></ul><h2 id="地址空间映射">地址空间映射</h2><p><strong>ARM Cortex M4</strong>内核采用了<strong>哈佛结构</strong>，使用相互独立的总线来读取<strong>指令</strong>和操作<strong>数据</strong>。这些指令和数据都存储在一个大小为<code>4GB</code> 的相同<strong>地址空间</strong>（因为 <strong>ARMCortex M4</strong> 的地址总线宽度为 <strong>32位</strong>，所以其对应的地址范围为 <code>2</code> 的 <code>32</code>次方等于<strong>4GB</strong>），但是处于不同的<strong>地址范围</strong>：</p><p><img src="/Project/UINIO-MCU-GD32/3-ARM/3.png"></p><p>观察上面的表格可以发现 <strong>GD32F350RBT6</strong> 的片上外设地址空间被划分为 <strong>AHB1</strong> 和<strong>AHB2</strong> 总线、<strong>APB1</strong> 和<strong>APB2</strong>总线共四个部分，这些总线的最低地址被称为<strong>总线基地址</strong>，也就是挂载在该总线上第1个外设的地址，而每个外设的最低地址则被称为<strong>外设基地址</strong>，每个外设的地址范围内都分布着该外设所对应的<strong>寄存器</strong>，通过<strong>操作这些寄存器就可以达到控制外设的目的</strong>。</p><h1 id="操作寄存器-运用固件库">操作寄存器 → 运用固件库</h1><h2 id="操作寄存器">操作寄存器</h2><p>如果需要将 <strong>AHB</strong> 总线上的 <strong>GPIOA</strong>外设对应的 16 个引脚全部置为<code>1</code>，那么就需要去配置<strong>端口输出控制寄存器</strong><code>GPIOx_OCTL</code>，通过查询用户手册可以知道其地址偏移量为<code>0x14</code>：</p><p><img src="/Project/UINIO-MCU-GD32/4-Register/1.png"></p><p>由于 <strong>GPIOA</strong> 的外设基地址为<code>0x4800 0000</code>，所以寄存器 <code>GPIOA_OCTL</code>的地址计算方式如下所示：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="number">0x4800</span> <span class="number">0000</span> + <span class="number">0x0000</span> <span class="number">0014</span> = <span class="number">0x4800</span> <span class="number">0014</span></span><br></pre></td></tr></table></figure><p>换而言之，将寄存器 <code>OCTL(0~15)</code>相应的<strong>位</strong>设置为 <code>1</code>，就可以把对应的<code>GPIOA(0~15)</code> 控制为高电平。如果要让全部 16个引脚输出高电平，那么相应的 <code>GPIOA_OCTL</code> 寄存器的高 16位可以置为 <code>0</code> 而低 16 位置为 <code>1</code>，即<code>0000 0000 0000 0000 1111 1111 1111 1111</code>，转换为十六进制就是<code>0x0000FFFF</code>：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">*(<span class="type">unsigned</span> <span class="type">int</span>*)(<span class="number">0x48000014</span>) = <span class="number">0x0000FFFF</span>;      <span class="comment">// 将 GPIOA 外设对应的 16 个引脚全部输出高电平</span></span><br></pre></td></tr></table></figure><p>像上面这样直接对寄存器地址进行操作会比较麻烦，下面可以通过宏定义<code>#define</code>，为每一个寄存器地址都分配一个名称：</p><figure class="highlight c"><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"><span class="meta">#<span class="keyword">define</span> GPIOA_OCTL (unsigned int*)(0x48000014)  <span class="comment">// 将寄存器地址 0x48000014 定义为指针类型的 GPIOA_OCTL</span></span></span><br><span class="line">*GPIOA_OCTL = <span class="number">0x0000FFFF</span>;                       <span class="comment">// 将 GPIOA 外设对应的 16 个引脚全部输出高电平</span></span><br></pre></td></tr></table></figure><p>为了进一步简化代码，可以将指针类型 <code>*</code> 的声明合并到<code>GPIOA_OCTL</code> 的宏定义当中：</p><figure class="highlight c"><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"><span class="meta">#<span class="keyword">define</span> GPIOA_OCTL *(unsigned int*)(0x48000014) <span class="comment">// 将寄存器地址 0x48000014 定义为 GPIOA_OCTL</span></span></span><br><span class="line">GPIOA_OCTL = <span class="number">0x0000FFFF</span>;                        <span class="comment">// 将 GPIOA 外设对应的 16 个引脚全部输出高电平</span></span><br></pre></td></tr></table></figure><h2 id="运用库函数">运用库函数</h2><p><strong>兆易创新</strong>官方固件库<code>GD32F3x0_Firmware_Library_V2.2.1</code>当中<strong>标准外设库</strong><code>Firmware\GD32F3x0_standard_peripheral</code> 目录下的<code>Include\gd32f3x0_gpio.h</code> 和<code>Source\gd32f3x0_gpio.c</code> 两个源文件，提供有一系列用于操作GPIO 的库函数：</p><p><img src="/Project/UINIO-MCU-GD32/4-Register/2.png"></p><p>其中的<code>void gpio_port_write(uint32_t gpio_periph, uint16_t data)</code>函数可以用于向特定的 GPIO 端口写入状态值：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpio_port_write(GPIOB, <span class="number">0xFFFF</span>);</span><br></pre></td></tr></table></figure><p>该函数被定义在 <code>Source\gd32f3x0_gpio.c</code>源文件当中，可以看到其函数体内调用了 <code>GPIO_OCTL(gpio_periph)</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*!</span></span><br><span class="line"><span class="comment">    \brief      write data to the specified GPIO port</span></span><br><span class="line"><span class="comment">    \param[in]  gpio_periph: GPIOx(x = A,B,C,D,F)</span></span><br><span class="line"><span class="comment">                only one parameter can be selected which is shown as below:</span></span><br><span class="line"><span class="comment">      \arg        GPIOx(x = A,B,C,D,F)</span></span><br><span class="line"><span class="comment">    \param[in]  data: specify the value to be written to the port output control register</span></span><br><span class="line"><span class="comment">    \param[out] none</span></span><br><span class="line"><span class="comment">    \retval     none</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">gpio_port_write</span><span class="params">(<span class="type">uint32_t</span> gpio_periph, <span class="type">uint16_t</span> data)</span></span><br><span class="line">&#123;</span><br><span class="line">    GPIO_OCTL(gpio_periph) = (<span class="type">uint32_t</span>)data;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>而这个 <code>GPIO_OCTL(gpio_periph)</code> 函数又被预定义在了<code>Include\gd32f3x0_gpio.h</code> 头文件里面，其最终调用的是<code>REG32(addr)</code> 函数：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_OCTL(gpiox)           REG32((gpiox) + 0x00000014U)    <span class="comment">/*!&lt; GPIO port output control register */</span></span></span><br></pre></td></tr></table></figure><p><code>REG32(addr)</code> 函数的定义位于官方固件库<code>Firmware\CMSIS\GD\GD32F3x0\Include</code> 目录下的<code>gd32f3x0.h</code> 头文件当中：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> REG32(addr)                  (*(volatile uint32_t *)(uint32_t)(addr))</span></span><br></pre></td></tr></table></figure><p>把前面寄存器 <code>GPIOA_OCTL</code> 的地址计算式<code>0x4800 0000 + 0x0000 0014</code> 作为 <code>addr</code>参数代入之后，就会发现标准外设库底层也是在操作寄存器，只是在使用的时候更加直观简单：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> REG32(addr) (*(volatile uint32_t *)(uint32_t)(0x4800 0000 + 0x0000 0014))</span></span><br></pre></td></tr></table></figure><blockquote><p><strong>注意</strong>：通过<strong>寄存器</strong>直接控制外设，性能开销更少，运行更加迅速，适用于片上资源有限，且对于实时性要求较高的场景。而使用<strong>标准外设库</strong>来操控外设，其优势主要体现在提升代码的开发效率以及可读性与可维护性。</p></blockquote><h1 id="通过-gpio-寄存器控制-led">通过 GPIO 寄存器控制 LED</h1><p>使用 <strong>UINIO-MCU-GD32F350RBT6</strong> 核心板来控制 GPIO端口的输出，整体需要经历下面几个步骤：</p><ol type="1"><li>开启指定 GPIO 的<strong>端口时钟</strong>；</li><li>配置指定 GPIO 的<strong>工作模式</strong>；</li><li>配置指定 GPIO 的<strong>输出类型</strong>；</li></ol><p>开始编写代码之前，首先需要将一枚 <code>4.7K</code> 的电阻<code>R1</code> 与一枚 LED 发光二极管串联，然后再连接到<strong>UINIO-MCU-GD32F350RBT6</strong> 核心板的 <code>GPIOB8</code>引脚，当该引脚输出<strong>高电平</strong>的时候 LED发光二极管就会点亮，而输出<strong>低电平</strong>的时候 LED发光二极管就会熄灭，具体的电路连接关系请参考下面的示意图：</p><p><img src="/Project/UINIO-MCU-GD32/5-LED/0.png"></p><h2 id="开启-gpio-的端口时钟">开启 GPIO 的端口时钟</h2><p>由于 <strong>GD32F350RBT6</strong>的外设时钟资源默认情况下都是<strong>关闭</strong>的，所以在配置外设之前需要先<strong>开启其对应的时钟</strong>。</p><h3 id="ahb-总线使能寄存器-rcu_ahben">AHB 总线使能寄存器 RCU_AHBEN</h3><p><code>GPIOB</code> 引脚分组被挂载到了 <strong>GD32F350RBT6</strong>微控制器的 <strong>AHB</strong> 总线下面，在用户手册的<code>复位和时钟单元(RCU)</code> 章节里，描述了 <strong>AHB总线使能寄存器</strong> <code>RCU_AHBEN</code> 的地址偏移量为<code>0x14</code>、复位值为 <code>0x0000 0014</code>，可以按照 8位的<strong>字节</strong>、16 位的<strong>半字</strong>以及 32位的<strong>字</strong>进行访问：</p><p><img src="/Project/UINIO-MCU-GD32/5-LED/1.png"></p><p>而 <strong>AHB 总线使能寄存器</strong><code>RCU_AHBEN</code>位于<strong>复位和时钟单元 RCU</strong>外设的地址范围之内，由于 RCU 的外设基地址为<code>0x4002 1000</code>，所以 <code>RCU_AHB1EN</code>寄存器的实际地址计算过程如下面等式所示：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="variable constant_">RCU_AHBEN</span> = <span class="variable constant_">RCU</span> 的外设基地址 + <span class="variable constant_">AHB</span> 总线使能寄存器偏移量 = <span class="number">0x4002</span> <span class="number">1000</span> + <span class="number">0x14</span> = <span class="number">0x4002</span> <span class="number">1014</span></span><br></pre></td></tr></table></figure><p>根据用户手册当中接下来的内容，可以发现 <code>RCU_AHB1EN</code>寄存器的第 <code>18</code> 位 <code>PBEN</code> 就是 GPIOB时钟的<strong>使能位</strong>：</p><p><img src="/Project/UINIO-MCU-GD32/5-LED/2.png"></p><p>所以只需要往 <code>RCU_AHB1EN</code> 寄存器的第 18 位写入<code>1</code>，其它位保持不变，就可以实现对 <strong>GPIOB</strong>外设时钟的使能，这里我们可以通过一个<strong>或运算</strong>和<strong>移位运算</strong>来完成：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">RCU_AHBEN |= (<span class="number">1</span> &lt;&lt; <span class="number">18</span>)</span><br></pre></td></tr></table></figure><blockquote><p><strong>注意</strong>：上面等式要使能的是第几位，就向右移多少位。例如上面等式向第18 位写入 <code>1</code>，所以就右移 <code>18</code> 位。</p></blockquote><h2 id="配置-gpio-的工作模式">配置 GPIO 的工作模式</h2><p>接下来，着手配置 <strong>GD32F350RBT6</strong> 的 GPIO工作模式，这里具体可以划分为下面两个步骤：</p><ol type="1"><li>将<strong>端口控制寄存器</strong> <code>GPIOx_CTL</code>配置为<code>输入模式(默认)</code> / <code>输出模式</code> /<code>备用功能模式</code> / <code>模拟模式</code>；</li><li>将<strong>端口上下拉寄存器</strong> <code>GPIOx_PUD</code>配置为<code>上拉模式</code> / <code>下拉模式</code> /<code>悬空模式(默认)</code>；</li></ol><h3 id="配置端口控制寄存器-gpiob_ctl">配置端口控制寄存器 GPIOB_CTL</h3><p>已知 <strong>GPIOB</strong> 寄存器的基地址为<code>0x4800 0400</code>，而端口控制寄存器 <code>GPIOB_CTL</code>的地址偏移量为 <code>0x00</code>：</p><p><img src="/Project/UINIO-MCU-GD32/5-LED/3.png"></p><p>从而就可以计算出 <strong>GPIOB</strong> 端口控制寄存器<code>GPIOB_CTL</code> 的实际地址为：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GPIOB_CTL = <span class="number">0x4800</span> <span class="number">0400</span> + <span class="number">0x00</span> = <span class="number">0x4800</span> <span class="number">0400</span></span><br></pre></td></tr></table></figure><p><img src="/Project/UINIO-MCU-GD32/5-LED/4.png"></p><p>该寄存器通过两个位来进行控制，例如这里需要操作的是 <code>Pin8</code>引脚，就是需要控制 <code>GPIOB_CTL</code> 寄存器的第 17 和 16位。通过将这两位配置为 <code>01</code>，就可以将 <strong>GPIOB8</strong>端口配置为输出模式。此时向 <code>GPIOB_CTL</code>寄存器写入的二进制数据为<code>0000 0000 0000 0001 0000 0000 0000 0000</code>，转换为十六进制就是<code>00010000</code>。为了确保其它位不会被修改，需要先将第 15 和第 14两位置零，然后再将其配置为 <code>0</code> 和 <code>1</code>：</p><figure class="highlight c"><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">GPIOB_CTL &amp;= <span class="number">0xFFFCFFFF</span>;  <span class="comment">// 把第 17 和 16 位置为 00</span></span><br><span class="line">GPIOB_CTL |= <span class="number">0x00004000</span>;  <span class="comment">// 配置第 17 和 16 位为 01</span></span><br></pre></td></tr></table></figure><p>除此之外，还可以采用下面的计算方式进行配置：</p><figure class="highlight c"><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">GPIOB_CTL &amp;= ~(<span class="number">0x03</span> &lt;&lt; (<span class="number">2</span> * <span class="number">8</span>)); <span class="comment">// 把第 17 和 16 位置为 00</span></span><br><span class="line">GPIOB_CTL |= (<span class="number">0x01</span> &lt;&lt; (<span class="number">2</span> * <span class="number">8</span>));  <span class="comment">// 配置第 17 和 16 位为 01</span></span><br></pre></td></tr></table></figure><blockquote><p><strong>注意</strong>：上面代码当中的数值 <code>8</code> 对应的是<code>GPIOB8</code>，反之如果是 <code>GPIOB5</code> 则可以将该值替换为<code>5</code>。</p></blockquote><h3 id="配置端口上下拉寄存器-gpiob_pud">配置端口上下拉寄存器GPIOB_PUD</h3><p>将 <strong>GPIOB8</strong>引脚配置为输出模式之后，还需要再进一步通过<strong>端口上下拉寄存器</strong><code>GPIOB_PUD</code>将其进一步配置为<strong>悬空模式</strong>(默认值，即没有上下拉电阻)：</p><p><img src="/Project/UINIO-MCU-GD32/5-LED/5.png"></p><p>同样已知 <strong>GPIOB</strong> 寄存器的基地址为<code>0x4800 0400</code>，而端口上下拉寄存器 <code>GPIOB_PUD</code>的地址偏移量为 <code>0x0C</code>，从而就可以计算出其实际地址为：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GPIOB_PUD = <span class="number">0x4800</span> <span class="number">0400</span> + <span class="number">0x0C</span> = <span class="number">0x4800</span> <span class="number">040</span>C</span><br></pre></td></tr></table></figure><p>该寄存器同样通过 <code>GPIOB_PUD</code> 寄存器的第 17 和第 16两个位来进行控制：</p><p><img src="/Project/UINIO-MCU-GD32/5-LED/6.png"></p><p>使用时也依然需要先进行清零，然后再将其配置为 <code>00</code>所代表的<strong>悬空模式</strong>：</p><figure class="highlight c"><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">GPIOB_PUD &amp;= ~(<span class="number">0x03</span> &lt;&lt; (<span class="number">2</span> * <span class="number">8</span>)); <span class="comment">// 将第 17 和 16 位清零</span></span><br><span class="line">GPIOB_PUD |= (<span class="number">0x00</span> &lt;&lt; (<span class="number">2</span> * <span class="number">8</span>));  <span class="comment">// 配置第 17 和 16 位为 00</span></span><br></pre></td></tr></table></figure><h2 id="配置-gpio-的输出类型">配置 GPIO 的输出类型</h2><p>配置 <strong>UINIO-MCU-GD32F350RBT6</strong> 的 GPIO输出类型也可以划分为如下两个步骤：</p><ol type="1"><li>配置端口输出模式寄存器<code>GPIOx_OMODE</code>，也就是选择<strong>推挽输出</strong>还是<strong>开漏输出</strong>；</li><li>配置端口速度寄存器 <code>GPIOx_OSPD</code>的输出速度等级，在这里我们选择 <code>50MHz</code> 的频率；</li></ol><h3 id="端口输出模式寄存器-gpiob_omode">端口输出模式寄存器GPIOB_OMODE</h3><p>GPIO的<strong>开漏输出</strong>模式需要外接上拉电阻，才能够输出高电平，不适用于当前的电路连接关系，在这里我们需要通过<strong>端口输出模式寄存器</strong><code>GPIOB_OMODE</code>，将其设置为<strong>推挽输出</strong>模式：</p><p><img src="/Project/UINIO-MCU-GD32/5-LED/7.png"></p><p>同样已知 <strong>GPIOB</strong> 的寄存器基地址为<code>0x4800 0400</code>，而端口输出模式寄存器 <code>GPIOB_OMODE</code>的地址偏移量为 <code>0x04</code>，那么 <code>GPIOB_OMODE</code>的准确寄存器地址为：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GPIOB_OMODE = <span class="number">0x4800</span> <span class="number">0400</span> + <span class="number">0x04</span> = <span class="number">0x4800</span> <span class="number">0404</span></span><br></pre></td></tr></table></figure><p><img src="/Project/UINIO-MCU-GD32/5-LED/8.png"></p><p>根据上图的描述可知，向 <code>GPIOB_OMODE</code> 寄存器的第 8 位写入<code>0</code>，就可以将其配置为<strong>推挽输出模式</strong>：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GPIOB_OMODE &amp;= ~(<span class="number">0x01</span> &lt;&lt; <span class="number">8</span>) <span class="comment">// 将 GPIOB_OMODE 的第 8 位置为 0</span></span><br></pre></td></tr></table></figure><h3 id="端口速度寄存器-gpiob_ospd">端口速度寄存器 GPIOB_OSPD</h3><p>接下来，需要再将<strong>端口速度寄存器</strong><code>GPIOx_OSPD</code> 的输出频率设置为 <code>50MHz</code>：</p><p><img src="/Project/UINIO-MCU-GD32/5-LED/9.png"></p><p>根据前面的计算方法，已知 <strong>GPIOB</strong> 的寄存器基地址为<code>0x4800 0400</code>，而端口速度寄存器 <code>GPIOB_OSPD</code>的地址偏移量为 <code>0x08</code>，则 <code>GPIOB_OSPD</code>的准确寄存器地址，可以按照如下方式进行计算得到：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GPIOB_OSPD = <span class="number">0x4800</span> <span class="number">0400</span> + <span class="number">0x08</span> = <span class="number">0x4800</span> <span class="number">0408</span></span><br></pre></td></tr></table></figure><p><img src="/Project/UINIO-MCU-GD32/5-LED/10.png"></p><p>根据上图描述的信息，可以向 <code>GPIOB_OSPD</code> 寄存器的第 17 和第 16 位写入 <code>10</code>（复位值），就可以将其配置为<code>2MHz</code> 的输出速率：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GPIOB_OSPD |=  (<span class="number">0x02</span> &lt;&lt; (<span class="number">2</span> * <span class="number">8</span>));  <span class="comment">// 向第 17 和 16 位写入 10</span></span><br></pre></td></tr></table></figure><p>而向 <code>GPIOB_OSPD</code> 寄存器的第 17 和 第 16 位写入<code>01</code>，则可以将其配置为 <code>10MHz</code> 的输出速率：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GPIOB_OSPD |=  (<span class="number">0x01</span> &lt;&lt; (<span class="number">2</span> * <span class="number">8</span>));  <span class="comment">// 向第 17 和 16 位写入 10</span></span><br></pre></td></tr></table></figure><p>如果向 <code>GPIOB_OSPD</code> 寄存器的第 17 和 第 16 位写入的是<code>11</code>，则可以将其配置为 <code>50MHz</code>的输出速率，也就是当前需要为 <strong>UINIO-MCU-GD32F350RBT6</strong> 的<code>GPIOB</code> 配置的目标频率：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GPIOB_OSPD &amp;=  ~(<span class="number">0x03</span> &lt;&lt; (<span class="number">2</span> * <span class="number">8</span>)); <span class="comment">// 向第 17 和 16 位写入 11</span></span><br></pre></td></tr></table></figure><blockquote><p><strong>注意</strong>：十六进制 <code>0x03</code> 的二进制形式为<code>0000 0011</code>，十六进制 <code>0x02</code> 的二进制形式为<code>0000 0010</code>，十六进制 <code>0x01</code> 的二进制形式为<code>0000 0001</code>。</p></blockquote><h2 id="控制-gpio-的输出状态">控制 GPIO 的输出状态</h2><p>配置好 <strong>GPIOB8</strong>对应的<code>端口时钟</code>、<code>工作模式</code>、<code>输出类型</code>之后，就可以通过使其输出<strong>高电平</strong>点亮LED 发光二极管，或者通过<strong>低电平</strong>熄灭 LED 发光二极管。</p><h3 id="端口输出控制寄存器-gpiob_octl">端口输出控制寄存器GPIOB_OCTL</h3><p>根据用户手册已知 <strong>GPIOB</strong> 的寄存器基地址为<code>0x4800 0400</code>，而端口输出模式寄存器 <code>GPIOB_OCTL</code>的地址偏移量为 <code>0x14</code>：</p><p><img src="/Project/UINIO-MCU-GD32/5-LED/11.png"></p><p>那么端口输出控制寄存器 <code>GPIOB_OCTL</code>的实际地址，就可以通过下面的等式计算得到：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GPIOB_OCTL = <span class="number">0x4800</span> <span class="number">0400</span> + <span class="number">0x14</span> = <span class="number">0x4800</span> <span class="number">0414</span></span><br></pre></td></tr></table></figure><p>通过向上图当中 <code>GPIOB_OCTL</code> 寄存器的第 8 位<code>OCTL8</code> 位写入 <code>1</code> 或者<code>0</code>，就可以控制相应的 GPIO引脚输出<strong>高电平</strong>或者<strong>低电平</strong>：</p><figure class="highlight c"><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">GPIOB_OCTL &amp;= ~ (<span class="number">0x01</span> &lt;&lt; <span class="number">8</span>); <span class="comment">// 输出低电平</span></span><br><span class="line">GPIOB_OCTL |=  (<span class="number">0x01</span> &lt;&lt; <span class="number">8</span>);  <span class="comment">// 输出高电平</span></span><br></pre></td></tr></table></figure><h3 id="端口位操作寄存器-gpiob_bop">端口位操作寄存器 GPIOB_BOP</h3><p>除此之外，我们还可以通过<strong>端口位操作寄存器</strong><code>GPIOB_BOP</code> 来操作 GPIO 端口的状态。根据用户手册已知<strong>GPIOB</strong> 的寄存器基地址为<code>0x4800 0400</code>，而端口输出模式寄存器 <code>GPIOB_BOP</code>的地址偏移量为 <code>0x18</code>：</p><p><img src="/Project/UINIO-MCU-GD32/5-LED/12.png"></p><p>那么端口输出控制寄存器 <code>GPIOB_BOP</code>的实际地址，就可以通过下面的计算过程获得：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">GPIOB_BOP = <span class="number">0x4800</span> <span class="number">0400</span> + <span class="number">0x18</span> = <span class="number">0x4800</span> <span class="number">0418</span></span><br></pre></td></tr></table></figure><p>观察可以发现 <code>GPIOB_BOP</code> 寄存器的高 16 位和低 16位的每一位，都分别对应着一个 GPIO 引脚。其中<strong>低十六位</strong><span class="math inline">\(CR_{0 \sim 15}\)</span> 是置 <code>1</code>位，而<strong>高十六位</strong> <span class="math inline">\(BOP_{0 \sim15}\)</span> 则属于清 <code>0</code> 位：</p><ul><li><code>GPIOB_BOP</code> 寄存器的高十六位 <span class="math inline">\(CR_{0 \sim 15}\)</span>：置为 <code>1</code>输出<strong>低电平</strong>，置 <code>0</code> 电平状态不改变；</li><li><code>GPIOB_BOP</code> 寄存器的低十六位 <span class="math inline">\(BOP_{0 \sim 15}\)</span>：置为 <code>1</code>输出<strong>高电平</strong>，置 <code>0</code> 电平状态不改变；</li></ul><figure class="highlight c"><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">GPIOB_BOP |= (<span class="number">0x01</span> &lt;&lt; (<span class="number">8</span> + <span class="number">16</span>)); <span class="comment">// 输出低电平</span></span><br><span class="line">GPIOB_BOP |= (<span class="number">0x01</span> &lt;&lt; <span class="number">8</span>);        <span class="comment">// 输出高电平</span></span><br></pre></td></tr></table></figure><h2 id="完整-keil-µvision-工程代码">完整 Keil µVision 工程代码</h2><p>在 <strong>Keil-GD32F350RBT6</strong> 工程的 <code>Driver</code>目录下建立一个名为 <code>LED</code> 的子目录，然后分别新建<code>LED.h</code> 和 <code>LED.c</code> 两个源文件，并且在<code>main.c</code> 里包含 <code>LED.h</code>头文件，全部的示例代码内容如下面所示，即<strong>UINIO-MCU-GD32F350RBT6</strong> 工程 <code>Examples</code>目录下的 <code>1-LED-Register</code> 工程：</p><h3 id="driversled.h">Drivers/LED.h</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><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== LED.h ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> UINIO_Driver_LED_H</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_Driver_LED_H</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;systick.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_RCU_BASE (unsigned int)0x40021000U                      <span class="comment">// RCU 寄存器的基地址</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_RCU_AHBEN *(unsigned int *)(UINIO_RCU_BASE + 0x14U)     <span class="comment">// AHB 使能寄存器地址</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_GPIOB_BASE (unsigned int)0x48000400U                    <span class="comment">// GPIOB 的基地址</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_GPIOB_CTL *(unsigned int *)(UINIO_GPIOB_BASE + 0x00U)   <span class="comment">// GPIOB 控制寄存器的地址</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_GPIOB_PUD *(unsigned int *)(UINIO_GPIOB_BASE + 0x0CU)   <span class="comment">// GPIOB 的上下拉寄存器的地址</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_GPIOB_OMODE *(unsigned int *)(UINIO_GPIOB_BASE + 0x04U) <span class="comment">// GPIOB 的输出模式寄存器的地址</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_GPIOB_OSPD *(unsigned int *)(UINIO_GPIOB_BASE + 0x08U)  <span class="comment">// GPIOB 的速度寄存器的地址</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_GPIOB_OCTL *(unsigned int *)(UINIO_GPIOB_BASE + 0x14U)  <span class="comment">// GPIOB 的输出控制寄存器的地址</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_GPIOB_BOP *(unsigned int *)(UINIO_GPIOB_BASE + 0x18U)   <span class="comment">// GPIOB 的位操作寄存器的地址</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_LED_GPIO_Config</span><span class="params">(<span class="type">void</span>)</span>; <span class="comment">// LED 相关的 GPIO 端口配置函数</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">/* UINIO_Driver_LED_H */</span></span></span><br></pre></td></tr></table></figure><h3 id="driversled.c">Drivers/LED.c</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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== LED.c ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;LED.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* LED 相关的 GPIO 端口配置函数 */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_LED_GPIO_Config</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">  <span class="comment">/* AHB 总线使能寄存器 RCU_AHBEN */</span></span><br><span class="line">  UINIO_RCU_AHBEN |= (<span class="number">0x01</span> &lt;&lt; <span class="number">18</span>);         <span class="comment">// RCU_AHBEN 寄存器的第 18 位置为 1</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 配置端口控制寄存器 GPIOB_CTL */</span></span><br><span class="line">  UINIO_GPIOB_CTL &amp;= ~(<span class="number">0x03</span> &lt;&lt; (<span class="number">2</span>*<span class="number">8</span>));     <span class="comment">// 把 GPIOB_CTL 的第 17 和 16 位置为 00</span></span><br><span class="line">  UINIO_GPIOB_CTL |= (<span class="number">0x01</span> &lt;&lt; (<span class="number">2</span>*<span class="number">8</span>));      <span class="comment">// 配置 GPIOB_CTL 的第 17 和 16 位为 01</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 配置端口上下拉寄存器 GPIOB_PUD */</span></span><br><span class="line">  UINIO_GPIOB_PUD &amp;= ~(<span class="number">0x03</span> &lt;&lt; (<span class="number">2</span> * <span class="number">8</span>));   <span class="comment">// 将 GPIOB_PUD 的第 17 和 16 位清零</span></span><br><span class="line">  UINIO_GPIOB_PUD |= (<span class="number">0x00</span> &lt;&lt; (<span class="number">2</span> * <span class="number">8</span>));    <span class="comment">// 配置 GPIOB_PUD 的第 17 和 16 位为 00</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 端口输出模式寄存器 GPIOB_OMODE */</span></span><br><span class="line">  UINIO_GPIOB_OMODE &amp;= ~(<span class="number">0x01</span> &lt;&lt; <span class="number">8</span>);       <span class="comment">// 将 GPIOB_OMODE 的第 8 位置为 0</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 端口速度寄存器 GPIOB_OSPD */</span></span><br><span class="line">  UINIO_GPIOB_OSPD &amp;=  (<span class="number">0x03</span> &lt;&lt; (<span class="number">2</span> * <span class="number">8</span>));  <span class="comment">// 向 GPIOB_OSPD 的第 17 和 16 位写入 11</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="sourcesmain.c">Sources/main.c</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><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== main.c ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;main.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/LED/LED.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">  systick_config();         <span class="comment">// 配置系统滴答定时器</span></span><br><span class="line">  UINIO_LED_GPIO_Config();  <span class="comment">// 配置连接 LED 的 GPIO 端口</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 端口输出控制寄存器 GPIOB_OCTL 方式控制 LED */</span></span><br><span class="line">  UINIO_GPIOB_OCTL &amp;= ~(<span class="number">0x01</span> &lt;&lt; <span class="number">8</span>);      <span class="comment">// 输出低电平，LED 熄灭</span></span><br><span class="line">  UINIO_GPIOB_OCTL |=  (<span class="number">0x01</span> &lt;&lt; <span class="number">8</span>);      <span class="comment">// 输出高电平，LED 点亮</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 端口位操作寄存器 GPIOB_BOP 方式控制 LED */</span></span><br><span class="line">  UINIO_GPIOB_BOP |= (<span class="number">0x01</span> &lt;&lt; (<span class="number">8</span> + <span class="number">16</span>)); <span class="comment">// 输出低电平，LED 熄灭</span></span><br><span class="line">  UINIO_GPIOB_BOP |= (<span class="number">0x01</span> &lt;&lt; <span class="number">8</span>);        <span class="comment">// 输出高电平，LED 点亮</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span>(<span class="number">1</span>) &#123;&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="通过-gpio-固件库控制-led">通过 GPIO 固件库控制 LED</h1><p>本节内容将采用<strong>兆易创新</strong>官方提供的标准外设固件库<code>GD32F3x0_Firmware_Library_V2.2.1</code> 来完成点亮 LED的实验，这通常需要经历如下四个步骤：</p><ol type="1"><li>调用 <code>rcu_periph_clock_enable()</code> 固件库函数使能 GPIO端口对应的<strong>外设时钟</strong>：</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">rcu_periph_clock_enable</span><span class="params">(rcu_periph_enum periph)</span>;</span><br></pre></td></tr></table></figure><ol start="2" type="1"><li>通过 <code>gpio_mode_set()</code> 函数配置 GPIO端口的<strong>工作模式</strong>以及设置<strong>上下拉电阻状态</strong>：</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">gpio_mode_set</span><span class="params">(<span class="type">uint32_t</span> gpio_periph, <span class="type">uint32_t</span> mode, <span class="type">uint32_t</span> pull_up_down, <span class="type">uint32_t</span> pin)</span>;</span><br></pre></td></tr></table></figure><ol start="3" type="1"><li>通过 <code>gpio_output_options_set()</code> 函数配置指定 GPIO引脚的输出类型与速率：</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">`<span class="type">void</span> <span class="title function_">gpio_output_options_set</span><span class="params">(<span class="type">uint32_t</span> gpio_periph, <span class="type">uint8_t</span> otype, <span class="type">uint32_t</span> speed, <span class="type">uint32_t</span> pin)</span>;</span><br></pre></td></tr></table></figure><ol start="4" type="1"><li>通过 <code>gpio_bit_set/write()</code> 指定 GPIO引脚的电平状态：</li></ol><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> gpio_bit_set/write(<span class="type">uint32_t</span> gpio_periph, <span class="type">uint32_t</span> pin)</span><br></pre></td></tr></table></figure><h2 id="使能-gpio-外设时钟">使能 GPIO 外设时钟</h2><p>官方固件库 <code>Firmware\GD32F3x0_standard_peripheral\Include</code>目录下的头文件 <code>gd32f3x0_rcu.h</code>里，定义了一个专门用于使能<strong>外设时钟</strong>的库函数：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">rcu_periph_clock_enable</span><span class="params">(rcu_periph_enum periph)</span></span><br></pre></td></tr></table></figure><p>这个函数的 <code>periph</code> 参数是一个<code>rcu_periph_enum</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/* peripheral clock enable */</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">enum</span> &#123;</span></span><br><span class="line">    <span class="comment">/* AHB peripherals */</span></span><br><span class="line">    RCU_DMA     = RCU_REGIDX_BIT(IDX_AHBEN, <span class="number">0U</span>),                  <span class="comment">/*!&lt; DMA clock */</span></span><br><span class="line">    RCU_CRC     = RCU_REGIDX_BIT(IDX_AHBEN, <span class="number">6U</span>),                  <span class="comment">/*!&lt; CRC clock */</span></span><br><span class="line">    RCU_GPIOA   = RCU_REGIDX_BIT(IDX_AHBEN, <span class="number">17U</span>),                 <span class="comment">/*!&lt; GPIOA clock */</span></span><br><span class="line">    RCU_GPIOB   = RCU_REGIDX_BIT(IDX_AHBEN, <span class="number">18U</span>),                 <span class="comment">/*!&lt; GPIOB clock */</span></span><br><span class="line">    RCU_GPIOC   = RCU_REGIDX_BIT(IDX_AHBEN, <span class="number">19U</span>),                 <span class="comment">/*!&lt; GPIOC clock */</span></span><br><span class="line">    RCU_GPIOD   = RCU_REGIDX_BIT(IDX_AHBEN, <span class="number">20U</span>),                 <span class="comment">/*!&lt; GPIOD clock */</span></span><br><span class="line">    RCU_GPIOF   = RCU_REGIDX_BIT(IDX_AHBEN, <span class="number">22U</span>),                 <span class="comment">/*!&lt; GPIOF clock */</span></span><br><span class="line">    RCU_TSI     = RCU_REGIDX_BIT(IDX_AHBEN, <span class="number">24U</span>),                 <span class="comment">/*!&lt; TSI clock */</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* APB2 peripherals */</span></span><br><span class="line">    RCU_CFGCMP  = RCU_REGIDX_BIT(IDX_APB2EN, <span class="number">0U</span>),                 <span class="comment">/*!&lt; CFGCMP clock */</span></span><br><span class="line">    RCU_ADC     = RCU_REGIDX_BIT(IDX_APB2EN, <span class="number">9U</span>),                 <span class="comment">/*!&lt; ADC clock */</span></span><br><span class="line">    RCU_TIMER0  = RCU_REGIDX_BIT(IDX_APB2EN, <span class="number">11U</span>),                <span class="comment">/*!&lt; TIMER0 clock */</span></span><br><span class="line">    RCU_SPI0    = RCU_REGIDX_BIT(IDX_APB2EN, <span class="number">12U</span>),                <span class="comment">/*!&lt; SPI0 clock */</span></span><br><span class="line">    RCU_USART0  = RCU_REGIDX_BIT(IDX_APB2EN, <span class="number">14U</span>),                <span class="comment">/*!&lt; USART0 clock */</span></span><br><span class="line">    RCU_TIMER14 = RCU_REGIDX_BIT(IDX_APB2EN, <span class="number">16U</span>),                <span class="comment">/*!&lt; TIMER14 clock */</span></span><br><span class="line">    RCU_TIMER15 = RCU_REGIDX_BIT(IDX_APB2EN, <span class="number">17U</span>),                <span class="comment">/*!&lt; TIMER15 clock */</span></span><br><span class="line">    RCU_TIMER16 = RCU_REGIDX_BIT(IDX_APB2EN, <span class="number">18U</span>),                <span class="comment">/*!&lt; TIMER16 clock */</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* APB1 peripherals */</span></span><br><span class="line">    RCU_TIMER1  = RCU_REGIDX_BIT(IDX_APB1EN, <span class="number">0U</span>),                 <span class="comment">/*!&lt; TIMER1 clock */</span></span><br><span class="line">    RCU_TIMER2  = RCU_REGIDX_BIT(IDX_APB1EN, <span class="number">1U</span>),                 <span class="comment">/*!&lt; TIMER2 clock */</span></span><br><span class="line">    RCU_TIMER13 = RCU_REGIDX_BIT(IDX_APB1EN, <span class="number">8U</span>),                 <span class="comment">/*!&lt; TIMER13 clock */</span></span><br><span class="line">    RCU_WWDGT   = RCU_REGIDX_BIT(IDX_APB1EN, <span class="number">11U</span>),                <span class="comment">/*!&lt; WWDGT clock */</span></span><br><span class="line">    RCU_SPI1    = RCU_REGIDX_BIT(IDX_APB1EN, <span class="number">14U</span>),                <span class="comment">/*!&lt; SPI1 clock */</span></span><br><span class="line">    RCU_USART1  = RCU_REGIDX_BIT(IDX_APB1EN, <span class="number">17U</span>),                <span class="comment">/*!&lt; USART1 clock */</span></span><br><span class="line">    RCU_I2C0    = RCU_REGIDX_BIT(IDX_APB1EN, <span class="number">21U</span>),                <span class="comment">/*!&lt; I2C0 clock */</span></span><br><span class="line">    RCU_I2C1    = RCU_REGIDX_BIT(IDX_APB1EN, <span class="number">22U</span>),                <span class="comment">/*!&lt; I2C1 clock */</span></span><br><span class="line">    RCU_PMU     = RCU_REGIDX_BIT(IDX_APB1EN, <span class="number">28U</span>),                <span class="comment">/*!&lt; PMU clock */</span></span><br><span class="line"><span class="meta">#<span class="keyword">if</span> defined(GD32F350)</span></span><br><span class="line">    RCU_DAC     = RCU_REGIDX_BIT(IDX_APB1EN, <span class="number">29U</span>),                <span class="comment">/*!&lt; DAC clock */</span></span><br><span class="line">    RCU_CEC     = RCU_REGIDX_BIT(IDX_APB1EN, <span class="number">30U</span>),                <span class="comment">/*!&lt; CEC clock */</span></span><br><span class="line">    RCU_TIMER5  = RCU_REGIDX_BIT(IDX_APB1EN, <span class="number">4U</span>),                 <span class="comment">/*!&lt; TIMER5 clock */</span></span><br><span class="line">    RCU_USBFS   = RCU_REGIDX_BIT(IDX_AHBEN, <span class="number">12U</span>),                 <span class="comment">/*!&lt; USBFS clock */</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">/* GD32F350 */</span></span></span><br><span class="line">    RCU_RTC     = RCU_REGIDX_BIT(IDX_BDCTL, <span class="number">15U</span>),                 <span class="comment">/*!&lt; RTC clock */</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* RCU_ADDAPB1EN */</span></span><br><span class="line">    RCU_CTC     = RCU_REGIDX_BIT(IDX_ADDAPB1EN, <span class="number">27U</span>)              <span class="comment">/*!&lt; CTC clock */</span></span><br><span class="line">&#125; rcu_periph_enum;</span><br></pre></td></tr></table></figure><p>观察可以发现，如果向 <code>rcu_periph_clock_enable()</code>函数传入上述枚举类型变量当中的<strong>枚举值</strong><code>RCU_GPIOB</code>，就可以使能 <strong>GPIOB</strong>对应的外设时钟：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rcu_periph_clock_enable(RCU_GPIOB);</span><br></pre></td></tr></table></figure><h2 id="配置-gpio-模式">配置 GPIO 模式</h2><p>类似的，固件库<code>Firmware\GD32F3x0_standard_peripheral\Include</code>目录下的头文件 <code>gd32f3x0_gpio.h</code> 里定义了一个用于设置<strong>GPIO 工作模式</strong>的函数：</p><figure class="highlight c"><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"><span class="comment">/* set GPIO mode */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">gpio_mode_set</span><span class="params">(<span class="type">uint32_t</span> gpio_periph, <span class="type">uint32_t</span> mode, <span class="type">uint32_t</span> pull_up_down, <span class="type">uint32_t</span> pin)</span>;</span><br></pre></td></tr></table></figure><p>该函数的四个参数，分别用于<code>设置 GPIO 分组</code>、<code>配置工作模式</code>、<code>选择上下拉状态</code>、<code>指定 GPIO 引脚</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/* GPIOx(x=A,B,C,D,F) definitions */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOA                      (GPIO_BASE + 0x00000000U)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOB                      (GPIO_BASE + 0x00000400U)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOC                      (GPIO_BASE + 0x00000800U)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOD                      (GPIO_BASE + 0x00000C00U)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOF                      (GPIO_BASE + 0x00001400U)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* output mode definitions */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_MODE_INPUT            CTL_CLTR(0)           <span class="comment">/*!&lt; input mode */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_MODE_OUTPUT           CTL_CLTR(1)           <span class="comment">/*!&lt; output mode */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_MODE_AF               CTL_CLTR(2)           <span class="comment">/*!&lt; alternate function mode */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_MODE_ANALOG           CTL_CLTR(3)           <span class="comment">/*!&lt; analog mode */</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* pull-up/pull-down definitions */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> PUD_PUPD(regval)           (BITS(0,1) &amp; ((uint32_t)(regval) &lt;&lt; 0))</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_PUPD_NONE             PUD_PUPD(0)           <span class="comment">/*!&lt; floating mode, no pull-up and pull-down resistors */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_PUPD_PULLUP           PUD_PUPD(1)           <span class="comment">/*!&lt; with pull-up resistor */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_PUPD_PULLDOWN         PUD_PUPD(2)           <span class="comment">/*!&lt; with pull-down resistor */</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* GPIO pin definitions */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_PIN_0                 BIT(0)                <span class="comment">/*!&lt; GPIO pin 0 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_PIN_1                 BIT(1)                <span class="comment">/*!&lt; GPIO pin 1 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_PIN_2                 BIT(2)                <span class="comment">/*!&lt; GPIO pin 2 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_PIN_3                 BIT(3)                <span class="comment">/*!&lt; GPIO pin 3 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_PIN_4                 BIT(4)                <span class="comment">/*!&lt; GPIO pin 4 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_PIN_5                 BIT(5)                <span class="comment">/*!&lt; GPIO pin 5 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_PIN_6                 BIT(6)                <span class="comment">/*!&lt; GPIO pin 6 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_PIN_7                 BIT(7)                <span class="comment">/*!&lt; GPIO pin 7 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_PIN_8                 BIT(8)                <span class="comment">/*!&lt; GPIO pin 8 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_PIN_9                 BIT(9)                <span class="comment">/*!&lt; GPIO pin 9 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_PIN_10                BIT(10)               <span class="comment">/*!&lt; GPIO pin 10 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_PIN_11                BIT(11)               <span class="comment">/*!&lt; GPIO pin 11 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_PIN_12                BIT(12)               <span class="comment">/*!&lt; GPIO pin 12 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_PIN_13                BIT(13)               <span class="comment">/*!&lt; GPIO pin 13 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_PIN_14                BIT(14)               <span class="comment">/*!&lt; GPIO pin 14 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_PIN_15                BIT(15)               <span class="comment">/*!&lt; GPIO pin 15 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_PIN_ALL               BITS(0,15)            <span class="comment">/*!&lt; GPIO pin all */</span></span></span><br></pre></td></tr></table></figure><p>例如现在要配置 <strong>GPIOB8</strong>引脚为<strong>悬空输出模式</strong>，则只需要向<code>gpio_mode_set()</code> 函数传入相应的参数即可：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, GPIO_PIN_8);</span><br></pre></td></tr></table></figure><h2 id="配置-gpio-输出类型与速度">配置 GPIO 输出类型与速度</h2><p>固件库 <code>Firmware\GD32F3x0_standard_peripheral\Include</code>目录下的 <code>gd32f3x0_gpio.h</code> 头文件里面，同样定义有一个用于设置<strong>GPIO 输出类型和速率</strong>的库函数：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="type">void</span> <span class="title function_">gpio_output_options_set</span><span class="params">(<span class="type">uint32_t</span> gpio_periph, <span class="type">uint8_t</span> otype, <span class="type">uint32_t</span> speed, <span class="type">uint32_t</span> pin)</span>;</span><br></pre></td></tr></table></figure><p>这个函数的四个参数，则是分别用于<code>设置 GPIO 分组</code>、<code>配置输出类型</code>、<code>最大输出速率</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">/* GPIO output type */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_OTYPE_PP              ((uint8_t)(0x00U))    <span class="comment">/*!&lt; push pull mode */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_OTYPE_OD              ((uint8_t)(0x01U))    <span class="comment">/*!&lt; open drain mode */</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* GPIO output max speed value */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_OSPEED_2MHZ           OSPD_OSPD0(0)                     <span class="comment">/*!&lt; output max speed 2MHz */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_OSPEED_10MHZ          OSPD_OSPD0(1)                     <span class="comment">/*!&lt; output max speed 10MHz */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_OSPEED_50MHZ          OSPD_OSPD0(3)                     <span class="comment">/*!&lt; output max speed 50MHz */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIO_OSPEED_MAX            ((uint32_t)0x0000FFFFU)           <span class="comment">/*!&lt; GPIO very high output speed, max speed more than 50MHz */</span></span></span><br></pre></td></tr></table></figure><p>例如当前要配置 <strong>GPIOB8</strong>引脚为<strong>推挽输出</strong>方式，其最大输出速率为<code>50MHz</code>，则只需要向 <code>gpio_output_options_set()</code>函数传入下面的参数即可：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, GPIO_PIN_8);</span><br></pre></td></tr></table></figure><h2 id="指定-gpio-引脚电平状态">指定 GPIO 引脚电平状态</h2><p>固件库的 <code>gd32f3x0_gpio.h</code>头文件里，存在着下面三个可以用于定义 <strong>GPIO引脚电平状态</strong>的函数：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/* set GPIO pin bit */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">gpio_bit_set</span><span class="params">(<span class="type">uint32_t</span> gpio_periph, <span class="type">uint32_t</span> pin)</span>;</span><br><span class="line"><span class="type">void</span> <span class="title function_">gpio_bit_reset</span><span class="params">(<span class="type">uint32_t</span> gpio_periph, <span class="type">uint32_t</span> pin)</span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* write data to the specified GPIO pin */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">gpio_bit_write</span><span class="params">(<span class="type">uint32_t</span> gpio_periph, <span class="type">uint32_t</span> pin, bit_status bit_value)</span>;</span><br></pre></td></tr></table></figure><p>其中 <code>gpio_bit_set()</code> 和 <code>gpio_bit_reset()</code>函数用于指定 GPIO 引脚为固定的高电平状态：</p><figure class="highlight c"><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">gpio_bit_set(GPIOB, GPIO_PIN_8);    <span class="comment">// 指定 GPIOB8 引脚为高电平</span></span><br><span class="line">gpio_bit_reset(GPIOB, GPIO_PIN_8);  <span class="comment">// 指定 GPIOB8 引脚为低电平</span></span><br></pre></td></tr></table></figure><p>而 <code>gpio_bit_write()</code> 函数则可以用来灵活的设置 GPIO引脚为高电平或者低电平状态：</p><figure class="highlight c"><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">gpio_bit_write(GPIOB, GPIO_PIN_8, <span class="number">0</span>);  <span class="comment">// 让 GPIOB8 引脚输出低电平</span></span><br><span class="line">gpio_bit_write(GPIOB, GPIO_PIN_8, <span class="number">1</span>);  <span class="comment">// 让 GPIOB8 引脚输出高电平</span></span><br></pre></td></tr></table></figure><h2 id="完整-keil-µvision-工程代码-1">完整 Keil µVision 工程代码</h2><p>接下来，将 <strong>Keil-GD32F350RBT6</strong> 示例工程里的<code>LED.h</code> 和 <code>LED.c</code> 以及 <code>main.c</code>替换为使用固件库的版本，全部的示例代码内容如下面所示，即<strong>UINIO-MCU-GD32F350RBT6</strong> 工程 <code>Examples</code>目录下的 <code>2-LED-Library</code> 工程：</p><h3 id="driversled.h-1">Drivers/LED.h</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== UINIO_LED.h ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> UINIO_LED_H</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_LED_H</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_LED_RCU  RCU_GPIOB   <span class="comment">// 宏定义 LED 对应的 GPIO 端口时钟</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_LED_PORT GPIOB       <span class="comment">// 宏定义 LED 对应的 GPIO 端口</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_LED_PIN  GPIO_PIN_8  <span class="comment">// 宏定义 LED 对应的 GPIO 引脚</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_LED_GPIO_Config</span><span class="params">(<span class="type">void</span>)</span>;  <span class="comment">// LED 关联 GPIO 引脚的配置函数</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">/* UINIO_LED_H */</span></span></span><br></pre></td></tr></table></figure><h3 id="driversled.c-1">Drivers/LED.c</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== UINIO_LED.c ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;LED.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* LED 对应 GPIO 引脚的配置函数 */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_LED_GPIO_Config</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">  rcu_periph_clock_enable(UINIO_LED_RCU);                                                   <span class="comment">// 使能 GIPO 外设对应的 RCU 复位和时钟单元</span></span><br><span class="line">  gpio_mode_set(UINIO_LED_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, UINIO_LED_PIN);           <span class="comment">// 配置 GPIO 为浮空输出模式</span></span><br><span class="line">  gpio_output_options_set(UINIO_LED_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, UINIO_LED_PIN); <span class="comment">// 设置 GPIO 的输出模式为推挽输出，速度为 50MHz</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="sourcesmain.c-1">Sources/main.c</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">/*========== main.c ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;main.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/LED/LED.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">  UINIO_LED_GPIO_Config();  <span class="comment">// 初始化 LED 相关的 GPIO 引脚</span></span><br><span class="line"></span><br><span class="line">  gpio_bit_set(UINIO_LED_PORT, UINIO_LED_PIN);             <span class="comment">// GPIOB8 输出高电平</span></span><br><span class="line">  gpio_bit_reset(UINIO_LED_PORT, UINIO_LED_PIN);           <span class="comment">// GPIOB8 输出低电平</span></span><br><span class="line"></span><br><span class="line">  gpio_bit_write(UINIO_LED_PORT, UINIO_LED_PIN, RESET);    <span class="comment">// GPIOB8 输出低电平</span></span><br><span class="line">  gpio_bit_write(UINIO_LED_PORT, UINIO_LED_PIN, SET);      <span class="comment">// GPIOB8 输出高电平</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span>(<span class="number">1</span>) &#123;&#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="启动文件-startup_gd32f3x0.s-剖析">启动文件 startup_gd32f3x0.s剖析</h1><p>在开启进一步的标准固件库学习之前，首先需要了解<strong>Keil-GD32F350RBT6</strong> 工程的启动顺序，其中<code>Firmware\CMSIS\GD\GD32F3x0\Source\ARM</code> 目录下的<code>startup_gd32f3x0.s</code> 源文件是 <strong>GD32F350RBT6</strong>微控制器上电复位之后，执行的第一段程序（由汇编语言编写），该程序主要完成了如下几项工作：</p><ol type="1"><li>配置<strong>栈</strong>信息；</li><li>配置<strong>堆</strong>信息；</li><li>映射<strong>向量表</strong>；</li><li>设置<strong>复位处理程序</strong>；</li><li>定义<strong>异常/外部中断处理程序</strong>；</li><li>初始化<strong>用户堆栈</strong>；</li></ol><p>在接下来的内容当中，将会根据执行顺序依次探讨<code>startup_gd32f3x0.s</code> 当中各个代码块的功能与用途。</p><h2 id="配置栈信息">配置栈信息</h2><p><strong>栈</strong>主要用于存放<code>局部变量</code>、<code>函数调用</code>、<code>函数形式参数</code>，其<strong>由高向低生长</strong>，且容量不能超过片上SRAM 存储器的容量大小。</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">; &lt;h&gt; Stack Configuration</span><br><span class="line">;   &lt;o&gt; Stack Size (in Bytes) &lt;0x0-0xFFFFFFFF:8&gt;</span><br><span class="line">; &lt;/h&gt;</span><br><span class="line"></span><br><span class="line">Stack_Size      EQU     0x00000400</span><br><span class="line"></span><br><span class="line">                AREA    STACK, NOINIT, READWRITE, ALIGN=3</span><br><span class="line">Stack_Mem       SPACE   Stack_Size</span><br><span class="line">__initial_sp</span><br></pre></td></tr></table></figure><p>上面的汇编代码，开辟了一个大小为 <code>0X00000400</code> (1KB) 名称为<code>STACK</code> 的<strong>栈</strong>，其中 <code>NOINIT</code>表示不初始化，<code>READWRITE</code> 表示可读可写，<code>ALIGN=3</code>表示 <span class="math inline">\(2^3 = 8\)</span> 字节对齐。最后的<code>__initial_sp</code> 表示栈的结束地址，也就是栈顶地址。</p><h2 id="配置堆信息">配置堆信息</h2><p><strong>堆</strong>主要用于完成动态内存分配，其<strong>由低向高生长</strong>，例如<code>malloc()</code> 函数申请的内存就位于在堆上面。</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><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br></pre></td><td class="code"><pre><span class="line">; &lt;h&gt; Heap Configuration</span><br><span class="line">;   &lt;o&gt;  Heap Size (in Bytes) &lt;0x0-0xFFFFFFFF:8&gt;</span><br><span class="line">; &lt;/h&gt;</span><br><span class="line"></span><br><span class="line">Heap_Size       EQU     0x00000400</span><br><span class="line"></span><br><span class="line">                AREA    HEAP, NOINIT, READWRITE, ALIGN=3</span><br><span class="line">__heap_base</span><br><span class="line">Heap_Mem        SPACE   Heap_Size</span><br><span class="line">__heap_limit</span><br><span class="line"></span><br><span class="line">                PRESERVE8</span><br><span class="line">                THUMB</span><br></pre></td></tr></table></figure><p>上面的汇编代码，开辟了一个大小为 <code>0X00000400</code> (1KB) 名称为<code>HEAP</code> 的<strong>堆</strong>，同样的 <code>NOINIT</code>表示不初始化，<code>READWRITE</code> 表示可读可写，<code>ALIGN=3</code>表示 <span class="math inline">\(2^3 = 8\)</span> 字节对齐。</p><p>除此之外，<code>__heap_base</code> 表示堆的起始地址，而<code>__heap_limit</code> 表示堆的结束地址。后续的<code>PRESERVE8</code> 表示保留 8 字节对齐，而 <code>THUMB</code>表示兼容 <strong>THUMB</strong> 指令集。</p><h2 id="映射向量表">映射向量表</h2><p><strong>向量表</strong>是一个 32 位 <code>WORD</code><strong>字</strong>数组，其按照 4 字节进行边界对齐，从片上 Flash的零地址开始进行放置，这个数组保存着一系列程序的入口地址，当<strong>GD32F350RBT6</strong>微控制器处于不同的预定义状态时，就会通过查找向量表，进入执行对应地址的程序：</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><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><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br></pre></td><td class="code"><pre><span class="line">;               /* reset Vector Mapped to at Address 0 */</span><br><span class="line">                AREA    RESET, DATA, READONLY</span><br><span class="line">                EXPORT  __Vectors</span><br><span class="line">                EXPORT  __Vectors_End</span><br><span class="line">                EXPORT  __Vectors_Size</span><br><span class="line"></span><br><span class="line">__Vectors       DCD     __initial_sp                      ; Top of Stack</span><br><span class="line">                DCD     Reset_Handler                     ; Reset Handler</span><br><span class="line">                DCD     NMI_Handler                       ; NMI Handler</span><br><span class="line">                DCD     HardFault_Handler                 ; Hard Fault Handler</span><br><span class="line">                DCD     MemManage_Handler                 ; MPU Fault Handler</span><br><span class="line">                DCD     BusFault_Handler                  ; Bus Fault Handler</span><br><span class="line">                DCD     UsageFault_Handler                ; Usage Fault Handler</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     SVC_Handler                       ; SVCall Handler</span><br><span class="line">                DCD     DebugMon_Handler                  ; Debug Monitor Handler</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     PendSV_Handler                    ; PendSV Handler</span><br><span class="line">                DCD     SysTick_Handler                   ; SysTick Handler</span><br><span class="line"></span><br><span class="line">;               /* external interrupts handler */</span><br><span class="line">                DCD     WWDGT_IRQHandler                  ; 16:Window Watchdog Timer</span><br><span class="line">                DCD     LVD_IRQHandler                    ; 17:LVD through EXTI Line detect</span><br><span class="line">                DCD     RTC_IRQHandler                    ; 18:RTC through EXTI Line</span><br><span class="line">                DCD     FMC_IRQHandler                    ; 19:FMC</span><br><span class="line">                DCD     RCU_CTC_IRQHandler                ; 20:RCU and CTC</span><br><span class="line">                DCD     EXTI0_1_IRQHandler                ; 21:EXTI Line 0 and EXTI Line 1</span><br><span class="line">                DCD     EXTI2_3_IRQHandler                ; 22:EXTI Line 2 and EXTI Line 3</span><br><span class="line">                DCD     EXTI4_15_IRQHandler               ; 23:EXTI Line 4 to EXTI Line 15</span><br><span class="line">                DCD     TSI_IRQHandler                    ; 24:TSI</span><br><span class="line">                DCD     DMA_Channel0_IRQHandler           ; 25:DMA Channel 0</span><br><span class="line">                DCD     DMA_Channel1_2_IRQHandler         ; 26:DMA Channel 1 and DMA Channel 2</span><br><span class="line">                DCD     DMA_Channel3_4_IRQHandler         ; 27:DMA Channel 3 and DMA Channel 4</span><br><span class="line">                DCD     ADC_CMP_IRQHandler                ; 28:ADC and Comparator 0-1</span><br><span class="line">                DCD     TIMER0_BRK_UP_TRG_COM_IRQHandler  ; 29:TIMER0 Break,Update,Trigger and Commutation</span><br><span class="line">                DCD     TIMER0_Channel_IRQHandler         ; 30:TIMER0 Channel Capture Compare</span><br><span class="line">                DCD     TIMER1_IRQHandler                 ; 31:TIMER1</span><br><span class="line">                DCD     TIMER2_IRQHandler                 ; 32:TIMER2</span><br><span class="line">                DCD     TIMER5_DAC_IRQHandler             ; 33:TIMER5 and DAC</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     TIMER13_IRQHandler                ; 35:TIMER13</span><br><span class="line">                DCD     TIMER14_IRQHandler                ; 36:TIMER14</span><br><span class="line">                DCD     TIMER15_IRQHandler                ; 37:TIMER15</span><br><span class="line">                DCD     TIMER16_IRQHandler                ; 38:TIMER16</span><br><span class="line">                DCD     I2C0_EV_IRQHandler                ; 39:I2C0 Event</span><br><span class="line">                DCD     I2C1_EV_IRQHandler                ; 40:I2C1 Event</span><br><span class="line">                DCD     SPI0_IRQHandler                   ; 41:SPI0</span><br><span class="line">                DCD     SPI1_IRQHandler                   ; 42:SPI1</span><br><span class="line">                DCD     USART0_IRQHandler                 ; 43:USART0</span><br><span class="line">                DCD     USART1_IRQHandler                 ; 44:USART1</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     CEC_IRQHandler                    ; 46:CEC</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     I2C0_ER_IRQHandler                ; 48:I2C0 Error</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     I2C1_ER_IRQHandler                ; 50:I2C1 Error</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     USBFS_WKUP_IRQHandler             ; 58:USBFS Wakeup</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     DMA_Channel5_6_IRQHandler         ; 64:DMA Channel5 and Channel6</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     0                                 ; Reserved</span><br><span class="line">                DCD     USBFS_IRQHandler                  ; 83:USBFS</span><br><span class="line">__Vectors_End</span><br><span class="line"></span><br><span class="line">__Vectors_Size  EQU     __Vectors_End - __Vectors</span><br></pre></td></tr></table></figure><p>上述汇编代码中的 <code>__Vectors</code>表示向量表的<strong>起始地址</strong>，而 <code>__Vectors_End</code>表示向量表的<strong>结束地址</strong>。除此之外，其中的 <code>DCD</code>指令用于<strong>分配</strong>和<strong>初始化</strong>一个或者多个以<strong>字</strong><code>Word</code> 为单位的内存空间，并且以 4 字节进行对齐。</p><h2 id="设置复位处理程序">设置复位处理程序</h2><p>复位处理程序是 <strong>GD32F350RBT6</strong>上电之后首个要运行的程序，其首先会调用 <code>SystemInit</code>函数初始化系统时钟，然后再调用 C 库函数 <code>__main</code>进入用户定义的主函数 <code>main()</code>：</p><ol type="1"><li><code>SystemInit()</code> 是一个 ARM 标准库函数，定义在<strong>Keil-GD32F350RBT6</strong> 工程<code>Firmware\CMSIS\GD\GD32F3x0\Source</code> 目录下的<code>system_gd32f3x0.c</code> 当中（即 CMSIS Cortex-M4外设接入层源文件），主要用于初始化各种系统时钟。</li><li><code>__main</code> 是一个标准 C库函数，主要用于初始化用户堆栈，并且会在最后调用自定义的<code>main()</code> 函数，这也就是 <code>main()</code> 总是作为<strong>Keil uVision5</strong> 工程入口函数的原因所在。</li></ol><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><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line">                AREA    |.text|, CODE, READONLY</span><br><span class="line"></span><br><span class="line">;/* reset Handler */</span><br><span class="line">Reset_Handler   PROC</span><br><span class="line">                EXPORT  Reset_Handler                     [WEAK]</span><br><span class="line">                IMPORT  SystemInit</span><br><span class="line">                IMPORT  __main</span><br><span class="line">                LDR     R0, =SystemInit</span><br><span class="line">                BLX     R0</span><br><span class="line">                LDR     R0, =__main</span><br><span class="line">                BX      R0</span><br><span class="line">                ENDP</span><br></pre></td></tr></table></figure><blockquote><p><strong>注意</strong>：上述源文件当中的第一句代码，用于定义一个名称为<code>.text</code> 的只读代码段区域。</p></blockquote><h2 id="定义异常外部中断处理程序">定义异常/外部中断处理程序</h2><p>接下来的代码片段，定义了一系列的<strong>异常处理程序</strong>和<strong>外部中断处理程序</strong>，而这些程序的完整实现则保存在外部的<code>.c</code>源文件当中。当出现相关异常或者发生指定外部中断的时候，程序的执行流程就会跳转至这里指定的各种服务程序当中：</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><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><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br><span class="line">111</span><br><span class="line">112</span><br><span class="line">113</span><br><span class="line">114</span><br><span class="line">115</span><br><span class="line">116</span><br><span class="line">117</span><br><span class="line">118</span><br><span class="line">119</span><br><span class="line">120</span><br></pre></td><td class="code"><pre><span class="line">;/* dummy Exception Handlers */</span><br><span class="line">NMI_Handler     PROC</span><br><span class="line">                EXPORT  NMI_Handler                       [WEAK]</span><br><span class="line">                B       .</span><br><span class="line">                ENDP</span><br><span class="line">HardFault_Handler\</span><br><span class="line">                PROC</span><br><span class="line">                EXPORT  HardFault_Handler                 [WEAK]</span><br><span class="line">                B       .</span><br><span class="line">                ENDP</span><br><span class="line">MemManage_Handler\</span><br><span class="line">                PROC</span><br><span class="line">                EXPORT  MemManage_Handler                 [WEAK]</span><br><span class="line">                B       .</span><br><span class="line">                ENDP</span><br><span class="line">BusFault_Handler\</span><br><span class="line">                PROC</span><br><span class="line">                EXPORT  BusFault_Handler                  [WEAK]</span><br><span class="line">                B       .</span><br><span class="line">                ENDP</span><br><span class="line">UsageFault_Handler\</span><br><span class="line">                PROC</span><br><span class="line">                EXPORT  UsageFault_Handler                [WEAK]</span><br><span class="line">                B       .</span><br><span class="line">                ENDP</span><br><span class="line">SVC_Handler     PROC</span><br><span class="line">                EXPORT  SVC_Handler                       [WEAK]</span><br><span class="line">                B       .</span><br><span class="line">                ENDP</span><br><span class="line">DebugMon_Handler\</span><br><span class="line">                PROC</span><br><span class="line">                EXPORT  DebugMon_Handler                  [WEAK]</span><br><span class="line">                B       .</span><br><span class="line">                ENDP</span><br><span class="line">PendSV_Handler\</span><br><span class="line">                PROC</span><br><span class="line">                EXPORT  PendSV_Handler                    [WEAK]</span><br><span class="line">                B       .</span><br><span class="line">                ENDP</span><br><span class="line">SysTick_Handler\</span><br><span class="line">                PROC</span><br><span class="line">                EXPORT  SysTick_Handler                   [WEAK]</span><br><span class="line">                B       .</span><br><span class="line">                ENDP</span><br><span class="line"></span><br><span class="line">Default_Handler PROC</span><br><span class="line">;               /* external interrupts handler */</span><br><span class="line">                EXPORT  WWDGT_IRQHandler                  [WEAK]</span><br><span class="line">                EXPORT  LVD_IRQHandler                    [WEAK]</span><br><span class="line">                EXPORT  RTC_IRQHandler                    [WEAK]</span><br><span class="line">                EXPORT  FMC_IRQHandler                    [WEAK]</span><br><span class="line">                EXPORT  RCU_CTC_IRQHandler                [WEAK]</span><br><span class="line">                EXPORT  EXTI0_1_IRQHandler                [WEAK]</span><br><span class="line">                EXPORT  EXTI2_3_IRQHandler                [WEAK]</span><br><span class="line">                EXPORT  EXTI4_15_IRQHandler               [WEAK]</span><br><span class="line">                EXPORT  TSI_IRQHandler                    [WEAK]</span><br><span class="line">                EXPORT  DMA_Channel0_IRQHandler           [WEAK]</span><br><span class="line">                EXPORT  DMA_Channel1_2_IRQHandler         [WEAK]</span><br><span class="line">                EXPORT  DMA_Channel3_4_IRQHandler         [WEAK]</span><br><span class="line">                EXPORT  ADC_CMP_IRQHandler                [WEAK]</span><br><span class="line">                EXPORT  TIMER0_BRK_UP_TRG_COM_IRQHandler  [WEAK]</span><br><span class="line">                EXPORT  TIMER0_Channel_IRQHandler         [WEAK]</span><br><span class="line">                EXPORT  TIMER1_IRQHandler                 [WEAK]</span><br><span class="line">                EXPORT  TIMER2_IRQHandler                 [WEAK]</span><br><span class="line">                EXPORT  TIMER5_DAC_IRQHandler             [WEAK]</span><br><span class="line">                EXPORT  TIMER13_IRQHandler                [WEAK]</span><br><span class="line">                EXPORT  TIMER14_IRQHandler                [WEAK]</span><br><span class="line">                EXPORT  TIMER15_IRQHandler                [WEAK]</span><br><span class="line">                EXPORT  TIMER16_IRQHandler                [WEAK]</span><br><span class="line">                EXPORT  I2C0_EV_IRQHandler                [WEAK]</span><br><span class="line">                EXPORT  I2C1_EV_IRQHandler                [WEAK]</span><br><span class="line">                EXPORT  SPI0_IRQHandler                   [WEAK]</span><br><span class="line">                EXPORT  SPI1_IRQHandler                   [WEAK]</span><br><span class="line">                EXPORT  USART0_IRQHandler                 [WEAK]</span><br><span class="line">                EXPORT  USART1_IRQHandler                 [WEAK]</span><br><span class="line">                EXPORT  CEC_IRQHandler                    [WEAK]</span><br><span class="line">                EXPORT  I2C0_ER_IRQHandler                [WEAK]</span><br><span class="line">                EXPORT  I2C1_ER_IRQHandler                [WEAK]</span><br><span class="line">                EXPORT  USBFS_WKUP_IRQHandler             [WEAK]</span><br><span class="line">                EXPORT  DMA_Channel5_6_IRQHandler         [WEAK]</span><br><span class="line">                EXPORT  USBFS_IRQHandler                  [WEAK]</span><br><span class="line"></span><br><span class="line">;/* external interrupts handler */</span><br><span class="line">WWDGT_IRQHandler</span><br><span class="line">LVD_IRQHandler</span><br><span class="line">RTC_IRQHandler</span><br><span class="line">FMC_IRQHandler</span><br><span class="line">RCU_CTC_IRQHandler</span><br><span class="line">EXTI0_1_IRQHandler</span><br><span class="line">EXTI2_3_IRQHandler</span><br><span class="line">EXTI4_15_IRQHandler</span><br><span class="line">TSI_IRQHandler</span><br><span class="line">DMA_Channel0_IRQHandler</span><br><span class="line">DMA_Channel1_2_IRQHandler</span><br><span class="line">DMA_Channel3_4_IRQHandler</span><br><span class="line">ADC_CMP_IRQHandler</span><br><span class="line">TIMER0_BRK_UP_TRG_COM_IRQHandler</span><br><span class="line">TIMER0_Channel_IRQHandler</span><br><span class="line">TIMER1_IRQHandler</span><br><span class="line">TIMER2_IRQHandler</span><br><span class="line">TIMER5_DAC_IRQHandler</span><br><span class="line">TIMER13_IRQHandler</span><br><span class="line">TIMER14_IRQHandler</span><br><span class="line">TIMER15_IRQHandler</span><br><span class="line">TIMER16_IRQHandler</span><br><span class="line">I2C0_EV_IRQHandler</span><br><span class="line">I2C1_EV_IRQHandler</span><br><span class="line">SPI0_IRQHandler</span><br><span class="line">SPI1_IRQHandler</span><br><span class="line">USART0_IRQHandler</span><br><span class="line">USART1_IRQHandler</span><br><span class="line">CEC_IRQHandler</span><br><span class="line">I2C0_ER_IRQHandler</span><br><span class="line">I2C1_ER_IRQHandler</span><br><span class="line">USBFS_WKUP_IRQHandler</span><br><span class="line">DMA_Channel5_6_IRQHandler</span><br><span class="line">USBFS_IRQHandler</span><br><span class="line"></span><br><span class="line">                B       .</span><br><span class="line">                ENDP</span><br></pre></td></tr></table></figure><blockquote><p><strong>注意</strong>：上述汇编代码当中的 <code>B .</code>语句表示进入了一个<strong>无限循环</strong>，即通俗意义上的<strong>死循环</strong>。</p></blockquote><h2 id="初始化用户堆栈">初始化用户堆栈</h2><p>接着判断当前 <strong>Keil uVision5</strong> 工程是否启用有<code>__MICROLIB</code> 库，如果有启用就赋予栈顶地址<code>__initial_sp</code>、堆起始地址<code>__heap_base</code>、堆结束地址<code>__heap_limit</code>。如果没有启用，则会使用<strong>双段存储器模式</strong>，并且由用户来初始化堆栈空间：</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><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></pre></td><td class="code"><pre><span class="line">                ALIGN</span><br><span class="line"></span><br><span class="line">; user Initial Stack &amp; Heap</span><br><span class="line"></span><br><span class="line">                IF      :DEF:__MICROLIB</span><br><span class="line"></span><br><span class="line">                EXPORT  __initial_sp</span><br><span class="line">                EXPORT  __heap_base</span><br><span class="line">                EXPORT  __heap_limit</span><br><span class="line"></span><br><span class="line">                ELSE</span><br><span class="line"></span><br><span class="line">                IMPORT  __use_two_region_memory</span><br><span class="line">                EXPORT  __user_initial_stackheap</span><br><span class="line"></span><br><span class="line">__user_initial_stackheap PROC</span><br><span class="line">                LDR     R0, =  Heap_Mem</span><br><span class="line">                LDR     R1, =(Stack_Mem + Stack_Size)</span><br><span class="line">                LDR     R2, = (Heap_Mem +  Heap_Size)</span><br><span class="line">                LDR     R3, = Stack_Mem</span><br><span class="line">                BX      LR</span><br><span class="line">                ENDP</span><br><span class="line"></span><br><span class="line">                ALIGN</span><br><span class="line"></span><br><span class="line">                ENDIF</span><br><span class="line"></span><br><span class="line">                END</span><br></pre></td></tr></table></figure><blockquote><p><strong>注意</strong>：上述代码当中的 <code>END</code>是一个<strong>汇编程序结束标记</strong>。</p></blockquote><h1 id="时钟配置-system_gd32f3x0.c-解析">时钟配置 system_gd32f3x0.c解析</h1><p>前面已经介绍过，由汇编语言编写的<strong>系统启动文件</strong><code>startup_gd32f3x0.s</code> 调用了<strong>Keil-GD32F350RBT6</strong> 工程的<code>Firmware\CMSIS\GD\GD32F3x0\Source\system_gd32f3x0.c</code>源文件当中，由 C 语言编写的<strong>系统初始化函数</strong><code>SystemInit()</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*!</span></span><br><span class="line"><span class="comment">    \brief      setup the microcontroller system, initialize the system</span></span><br><span class="line"><span class="comment">    \param[in]  none</span></span><br><span class="line"><span class="comment">    \param[out] none</span></span><br><span class="line"><span class="comment">    \retval     none</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">SystemInit</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">    ... ... ... ...</span><br><span class="line">    <span class="comment">/* configure system clock */</span></span><br><span class="line">    system_clock_config();</span><br><span class="line">    ... ... ... ...</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>可以看到该函数最终调用的是同样定义在这个源文件里的<code>system_clock_config()</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*!</span></span><br><span class="line"><span class="comment">    \brief      configure the system clock</span></span><br><span class="line"><span class="comment">    \param[in]  none</span></span><br><span class="line"><span class="comment">    \param[out] none</span></span><br><span class="line"><span class="comment">    \retval     none</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">system_clock_config</span><span class="params">(<span class="type">void</span>)</span></span><br><span class="line">&#123;</span><br><span class="line"><span class="meta">#<span class="keyword">ifdef</span> __SYSTEM_CLOCK_8M_HXTAL</span></span><br><span class="line">    system_clock_8m_hxtal();</span><br><span class="line"><span class="meta">#<span class="keyword">elif</span> defined (__SYSTEM_CLOCK_108M_PLL_HXTAL)</span></span><br><span class="line">    system_clock_108m_hxtal();</span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line">    system_clock_8m_irc8m();</span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">/* __SYSTEM_CLOCK_8M_HXTAL */</span></span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>由于在 <code>system_gd32f3x0.c</code>源文件的开头位置，存在着如下针对 <strong>GDF350</strong>系列微控制器的宏定义：</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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">if</span> defined (GD32F350)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> __SYSTEM_CLOCK_108M_PLL_HXTAL        (uint32_t)(108000000)</span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">/* GD32F350 */</span></span></span><br></pre></td></tr></table></figure><p>所以 <code>system_clock_config()</code>方法最终实际调用的是该源文件中的函数<code>system_clock_108m_hxtal()</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><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">elif</span> defined (__SYSTEM_CLOCK_108M_PLL_HXTAL)</span></span><br><span class="line"><span class="comment">/*!</span></span><br><span class="line"><span class="comment">    \brief      configure the system clock to 84M by PLL which selects HXTAL as its clock source</span></span><br><span class="line"><span class="comment">    \param[in]  none</span></span><br><span class="line"><span class="comment">    \param[out] none</span></span><br><span class="line"><span class="comment">    \retval     none</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">system_clock_108m_hxtal</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">    <span class="type">uint32_t</span> timeout = <span class="number">0U</span>;</span><br><span class="line">    <span class="type">uint32_t</span> stab_flag = <span class="number">0U</span>;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* enable HXTAL */</span></span><br><span class="line">    RCU_CTL0 |= RCU_CTL0_HXTALEN;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* wait until HXTAL is stable or the startup time is longer than HXTAL_STARTUP_TIMEOUT */</span></span><br><span class="line">    <span class="keyword">do</span> &#123;</span><br><span class="line">        timeout++;</span><br><span class="line">        stab_flag = (RCU_CTL0 &amp; RCU_CTL0_HXTALSTB);</span><br><span class="line">    &#125; <span class="keyword">while</span>((<span class="number">0U</span> == stab_flag) &amp;&amp; (HXTAL_STARTUP_TIMEOUT != timeout));</span><br><span class="line">    <span class="comment">/* if fail */</span></span><br><span class="line">    <span class="keyword">if</span>(<span class="number">0U</span> == (RCU_CTL0 &amp; RCU_CTL0_HXTALSTB)) &#123;</span><br><span class="line">        <span class="keyword">return</span>;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">/* HXTAL is stable */</span></span><br><span class="line">    <span class="comment">/* AHB = SYSCLK */</span></span><br><span class="line">    RCU_CFG0 |= RCU_AHB_CKSYS_DIV1;</span><br><span class="line">    <span class="comment">/* APB2 = AHB/2 */</span></span><br><span class="line">    RCU_CFG0 |= RCU_APB2_CKAHB_DIV2;</span><br><span class="line">    <span class="comment">/* APB1 = AHB/2 */</span></span><br><span class="line">    RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* PLL = HXTAL/2 * 27 = 108 MHz */</span></span><br><span class="line">    RCU_CFG0 &amp;= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PLLMF | RCU_CFG0_PLLMF4 | RCU_CFG0_PLLPREDV);</span><br><span class="line">    RCU_CFG1 &amp;= ~(RCU_CFG1_PLLPRESEL | RCU_CFG1_PLLMF5 | RCU_CFG1_PREDV);</span><br><span class="line">    RCU_CFG0 |= (RCU_PLLSRC_HXTAL_IRC48M | (RCU_PLL_MUL27 &amp; (~RCU_CFG1_PLLMF5)));</span><br><span class="line">    RCU_CFG1 |= (RCU_PLLPRESEL_HXTAL | RCU_PLL_PREDV2);</span><br><span class="line">    RCU_CFG1 |= (RCU_PLL_MUL27 &amp; RCU_CFG1_PLLMF5);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* enable PLL */</span></span><br><span class="line">    RCU_CTL0 |= RCU_CTL0_PLLEN;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* wait until PLL is stable */</span></span><br><span class="line">    <span class="keyword">while</span>(<span class="number">0U</span> == (RCU_CTL0 &amp; RCU_CTL0_PLLSTB)) &#123;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* select PLL as system clock */</span></span><br><span class="line">    RCU_CFG0 &amp;= ~RCU_CFG0_SCS;</span><br><span class="line">    RCU_CFG0 |= RCU_CKSYSSRC_PLL;</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* wait until PLL is selected as system clock */</span></span><br><span class="line">    <span class="keyword">while</span>(<span class="number">0U</span> == (RCU_CFG0 &amp; RCU_SCSS_PLL)) &#123;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p><strong>锁相环</strong>（PLL，Phase LockingLoop）是一种反馈控制电路，其工作过程当中，当输出信号频率与输入信号频率相同时，可以使输出电压与输入电压保持固定的相位差，就像输入/输出电压的相位被锁住了一样，所以这种电路被称为锁相环。<strong>GD32F350RBT6</strong>内部的 PLL 主要用于根据特定的外部晶振信号来生成其它频率的信号。</p><p><img src="/Project/UINIO-MCU-GD32/6-Clock/1.png"></p><p>观察可以发现，上述代码使能了 <strong>GD32F350RBT6</strong> 内部的 PLL锁相坏，由于当前 <strong>UINIO-MCU-GD32F350RBT6</strong>核心板的外部贴片晶振频率为<code>8MHz</code>，所以<strong>高速外部晶体振荡器时钟</strong><code>HXTAL = 8MHz</code>，这样锁相环的输出频率可以按照如下方式进行计算：</p><p><span class="math display">\[PLL = \frac{HXTAL}{2} \times 27 = \frac{8MHz}{2} \times 27 = 108 MHz\]</span></p><p>上述代码选择了锁相环的输出作为<strong>系统时钟</strong><code>SYSCLK</code>，并且将<strong>高级高性能总线</strong>（<strong>AHB</strong>，AdvancedHigh-performance Bus）时钟配置为了与系统时钟的频率相等：</p><p><span class="math display">\[AHB = SYSCLK = 108 MHz\]</span></p><p>而两条<strong>高级外设总线</strong>（<strong>APB</strong>，AdvancedPeripheral Bus）时钟频率分别为 AHB 总线时钟的二分之一：</p><p><span class="math display">\[\begin{cases}APB1 = \frac{AHB}{2} = \frac{108MHz}{2} = 54MHz \\APB2 = \frac{AHB}{2} = \frac{108MHz}{2} = 54MHz\end{cases}\]</span></p><h1 id="系统滴答定时器-systick">系统滴答定时器 SysTick</h1><p><strong>SysTick 定时器</strong>是一个拥有自动重装载能力的 24位<strong>向下计数器</strong>，所有 ARM Cortex-M4内核微控制器都具备该定时器，从而能够方便的在不同型号微控制器之间进行代码移植。当设定SysTick定时器的初始值并且使能之后，每经过一个系统时钟周期，定时器的计数值就会减去<code>1</code>，当减至 <code>0</code> 的时候，SysTick就会自动重新装载初始值，并且继续开始计数，同时置位内部的<code>COUNTFLAG</code>标志位，并且触发中断（如果使能有相应的定时器中断）。</p><p><img src="/Project/UINIO-MCU-GD32/7-SysTick/1.png"></p><p>观察 <strong>GD32F350RBT6</strong>微控制器<strong>时钟树</strong>可以发现，<code>108MHz</code> 频率的 AHB总线时钟 <code>CK_AHB</code>，在经过 8 分频之后，默认作为了 SysTick系统定时器的时钟源。</p><h2 id="使用-systick_config-配置寄存器">使用 SysTick_Config()配置寄存器</h2><p>标准固件库 <code>Firmware\CMSIS\core_cm4.h</code> 源文件中的<code>SysTick_Type</code> 结构体类型，定义了系统滴答定时器 SysTick相关的寄存器：</p><p><img src="/Project/UINIO-MCU-GD32/7-SysTick/2.png"></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">/** \brief  Structure type to access the System Timer (SysTick).</span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> &#123;</span></span><br><span class="line">    __IO <span class="type">uint32_t</span> CTRL;                    <span class="comment">/*!&lt; Offset: 0x000 (R/W)  SysTick Control and Status Register */</span></span><br><span class="line">    __IO <span class="type">uint32_t</span> LOAD;                    <span class="comment">/*!&lt; Offset: 0x004 (R/W)  SysTick Reload Value Register       */</span></span><br><span class="line">    __IO <span class="type">uint32_t</span> VAL;                     <span class="comment">/*!&lt; Offset: 0x008 (R/W)  SysTick Current Value Register      */</span></span><br><span class="line">    __I  <span class="type">uint32_t</span> CALIB;                   <span class="comment">/*!&lt; Offset: 0x00C (R/ )  SysTick Calibration Register        */</span></span><br><span class="line">&#125; SysTick_Type;</span><br></pre></td></tr></table></figure><p>该源文件中的 <code>SysTick_Config()</code> 函数，则是用于对上述SysTick相关的寄存器进行配置，在初始化和启动系统滴答定时器的同时，产生周期性的中断。概而言之，其主要完成了下面四个步骤的工作：</p><ol type="1"><li>设置 <code>LOAD</code> 重载寄存器的初始值；</li><li>设置 SysTick 定时器中断的优先级为<code>(1 &lt;&lt; 4) - 1 = 15</code>，即优先级为最低；</li><li>配置 <code>VAL</code> 寄存器，装载 SysTick 的计数值；</li><li>配置 <code>CTRL</code> 寄存器，使能 SysTick的时钟源、中断、以及外设本身；</li></ol><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/** \brief  System Tick Configuration</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">    The function initializes the System Timer and its interrupt, and starts the System Tick Timer.</span></span><br><span class="line"><span class="comment">    Counter is in free running mode to generate periodic interrupts.</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">    \param [in]  ticks  Number of ticks between two interrupts.</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">    \return          0  Function succeeded.</span></span><br><span class="line"><span class="comment">    \return          1  Function failed.</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment">    \note     When the variable &lt;b&gt;__Vendor_SysTickConfig&lt;/b&gt; is set to 1, then the</span></span><br><span class="line"><span class="comment">    function &lt;b&gt;SysTick_Config&lt;/b&gt; is not included. In this case, the file &lt;b&gt;&lt;i&gt;device&lt;/i&gt;.h&lt;/b&gt;</span></span><br><span class="line"><span class="comment">    must contain a vendor-specific implementation of this function.</span></span><br><span class="line"><span class="comment"></span></span><br><span class="line"><span class="comment"> */</span></span><br><span class="line">__STATIC_INLINE <span class="type">uint32_t</span> <span class="title function_">SysTick_Config</span><span class="params">(<span class="type">uint32_t</span> ticks)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span>((ticks - <span class="number">1</span>) &gt; SysTick_LOAD_RELOAD_Msk) &#123;</span><br><span class="line">        <span class="keyword">return</span> (<span class="number">1</span>);    <span class="comment">/* Reload value impossible */</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    SysTick-&gt;LOAD  = ticks - <span class="number">1</span>;                                  <span class="comment">/* set reload register */</span></span><br><span class="line">    NVIC_SetPriority(SysTick_IRQn, (<span class="number">1</span> &lt;&lt; __NVIC_PRIO_BITS) - <span class="number">1</span>); <span class="comment">/* set Priority for SysTick Interrupt */</span></span><br><span class="line">    SysTick-&gt;VAL   = <span class="number">0</span>;                                          <span class="comment">/* Load the SysTick Counter Value */</span></span><br><span class="line">    SysTick-&gt;CTRL  = SysTick_CTRL_CLKSOURCE_Msk |</span><br><span class="line">                     SysTick_CTRL_TICKINT_Msk   |</span><br><span class="line">                     SysTick_CTRL_ENABLE_Msk;                    <span class="comment">/* Enable SysTick IRQ and SysTick Timer */</span></span><br><span class="line">    <span class="keyword">return</span> (<span class="number">0</span>);                                                  <span class="comment">/* Function successful */</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="滴答定时器官方示例-systick.c">滴答定时器官方示例 systick.c</h2><p><strong>Keil-GD32F350RBT6</strong> 示例工程 <code>Sources</code>目录下提供的 <code>systick.c</code> 源文件，其中的<code>systick_config()</code> 方法就封装并且调用了上面的<code>SysTick_Config()</code> 函数，在使能 SysTick中断服务程序与定时器的同时，以系统时钟频率的千分之一<code>SystemCoreClock / 1000U</code> 作为 SysTick滴答定时器配置参数，也就是<strong>每 1 秒计数一千次，每一次 1毫秒</strong>（如果修改为 <code>SystemCoreClock / 1000000U</code>则可以实现微秒级的延时）。</p><p>而 <code>systick.c</code> 源文件当中提供的另一个函数<code>delay_1ms()</code>，则是以 <code>count</code>参数（单位为毫秒）进行定时计数，当 <code>volatile</code>关键字修饰的<strong>全局变量</strong> <code>delay</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="comment">/* the systick configuration file */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;systick.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">volatile</span> <span class="type">static</span> <span class="type">uint32_t</span> delay;</span><br><span class="line"></span><br><span class="line"><span class="comment">/*!</span></span><br><span class="line"><span class="comment">    \brief      configure systick</span></span><br><span class="line"><span class="comment">    \param[in]  none</span></span><br><span class="line"><span class="comment">    \param[out] none</span></span><br><span class="line"><span class="comment">    \retval     none</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">systick_config</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">    <span class="comment">/* setup systick timer for 1000Hz interrupts */</span></span><br><span class="line">    <span class="keyword">if</span>(SysTick_Config(SystemCoreClock / <span class="number">1000U</span>)) &#123;</span><br><span class="line">        <span class="comment">/* capture error */</span></span><br><span class="line">        <span class="keyword">while</span>(<span class="number">1</span>) &#123;&#125;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">/* configure the systick handler priority */</span></span><br><span class="line">    NVIC_SetPriority(SysTick_IRQn, <span class="number">0x00U</span>);</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      delay a time in milliseconds</span></span><br><span class="line"><span class="comment">    \param[in]  count: count in milliseconds</span></span><br><span class="line"><span class="comment">    \param[out] none</span></span><br><span class="line"><span class="comment">    \retval     none</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">delay_1ms</span><span class="params">(<span class="type">uint32_t</span> count)</span> &#123;</span><br><span class="line">    delay = count;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">while</span>(<span class="number">0U</span> != delay) &#123;&#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      delay decrement</span></span><br><span class="line"><span class="comment">    \param[in]  none</span></span><br><span class="line"><span class="comment">    \param[out] none</span></span><br><span class="line"><span class="comment">    \retval     none</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">delay_decrement</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span>(<span class="number">0U</span> != delay) &#123;</span><br><span class="line">        delay--;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>除此之外，上面 <code>systick.c</code> 代码中定义的<code>delay_decrement()</code> 函数，则会被<strong>Keil-GD32F350RBT6</strong> 工程下<code>Sources/gd32f3x0_it.h/c</code> 源文件内的 SysTick 中断服务程序<code>SysTick_Handler()</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">/*!</span></span><br><span class="line"><span class="comment">    \brief      this function handles SysTick exception</span></span><br><span class="line"><span class="comment">    \param[in]  none</span></span><br><span class="line"><span class="comment">    \param[out] none</span></span><br><span class="line"><span class="comment">    \retval     none</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">SysTick_Handler</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">    delay_decrement();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>当每一次进入 SysTick系统滴答定时器中断的时候，上面这个函数就会被调用一次，从而就完成了一次对于<code>delay</code> 变量的自减。</p><h2 id="编写-main.c-测试代码">编写 main.c 测试代码</h2><p>接下来，将前面 <strong>LCD</strong> 示例工程当中的<code>main.c</code> 源文件修改为如下的代码，使得 LED发光二极管可以每间隔 1 秒钟循环进行闪烁：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== main.c ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;systick.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;main.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/LED/LED.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">  systick_config();         <span class="comment">// 初始化系统滴答定时器</span></span><br><span class="line">  UINIO_LED_GPIO_Config();  <span class="comment">// 初始化 LED 相关的 GPIO 引脚</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span>(<span class="number">1</span>) &#123;</span><br><span class="line">    gpio_bit_set(UINIO_LED_PORT, UINIO_LED_PIN);             <span class="comment">// GPIOB8 输出高电平</span></span><br><span class="line">    delay_1ms(<span class="number">1000</span>);</span><br><span class="line"></span><br><span class="line">    gpio_bit_reset(UINIO_LED_PORT, UINIO_LED_PIN);           <span class="comment">// GPIOB8 输出低电平</span></span><br><span class="line">    delay_1ms(<span class="number">1000</span>);</span><br><span class="line"></span><br><span class="line">    gpio_bit_write(UINIO_LED_PORT, UINIO_LED_PIN, SET);      <span class="comment">// GPIOB8 输出高电平</span></span><br><span class="line">    delay_1ms(<span class="number">1000</span>);</span><br><span class="line"></span><br><span class="line">    gpio_bit_write(UINIO_LED_PORT, UINIO_LED_PIN, RESET);    <span class="comment">// GPIOB8 输出低电平</span></span><br><span class="line">    delay_1ms(<span class="number">1000</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="uinio_systick_delay_usms">UINIO_SysTick_Delay_us/ms()</h2><p>SysTick 系统滴答定时器的 <code>counter</code> 从 <code>reload</code>值往下递减到零的时候，<code>CTRL</code>寄存器相应的<strong>位</strong>就会被置为<code>1</code>，而读取该位的时候，其值又会自动被清零，所以利用这个特点就能够以非常简短的代码，实现类似于官方SysTic 示例的定时器延时功能：</p><h3 id="driverssystick.h">Drivers/SysTick.h</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== SysTick.h ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> UINIO_SysTick_H</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_SysTick_H</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_SysTick_Delay_us</span><span class="params">(__IO <span class="type">uint32_t</span> us)</span>;  <span class="comment">// 微秒级延时，参数 us 的单位为微秒</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_SysTick_Delay_ms</span><span class="params">(__IO <span class="type">uint32_t</span> ms)</span>;  <span class="comment">// 毫秒级延时，参数 ms 的单位为毫秒</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">/* UINIO_SysTick_H */</span></span></span><br></pre></td></tr></table></figure><h3 id="driverssystick.c">Drivers/SysTick.c</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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== SysTick.c ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;SysTick.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 微秒级延时，参数 us 的单位为微秒 */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_SysTick_Delay_us</span> <span class="params">(__IO <span class="type">uint32_t</span> us)</span> &#123;</span><br><span class="line">  <span class="type">uint32_t</span> index;</span><br><span class="line">  SysTick_Config(SystemCoreClock/<span class="number">1000000U</span>);      <span class="comment">// 调用 core_cm4.h 头文件中定义的 SysTick_Config() 函数</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">for</span> (index = <span class="number">0</span>; index &lt; us; index++) &#123;</span><br><span class="line">    <span class="keyword">while</span> ( !((SysTick-&gt;CTRL) &amp; (<span class="number">1UL</span> &lt;&lt; <span class="number">16</span>)) );  <span class="comment">// 当计数值减小到 0 时，CRTL 寄存器相应的位会被置为 1</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  SysTick-&gt;CTRL &amp;= ~SysTick_CTRL_ENABLE_Msk;     <span class="comment">// 失能 SysTick 系统滴答定时器</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 毫秒级延时，参数 ms 的单位为毫秒 */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_SysTick_Delay_ms</span> <span class="params">(__IO <span class="type">uint32_t</span> ms)</span> &#123;</span><br><span class="line">  <span class="type">uint32_t</span> index;</span><br><span class="line">  SysTick_Config(SystemCoreClock/<span class="number">1000U</span>);         <span class="comment">// 调用 core_cm4.h 头文件中定义的 SysTick_Config() 函数</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">for</span> (index = <span class="number">0</span>; index &lt; ms; index++) &#123;</span><br><span class="line">    <span class="keyword">while</span> ( !((SysTick-&gt;CTRL) &amp; (<span class="number">1UL</span> &lt;&lt; <span class="number">16</span>)) );  <span class="comment">// 当计数值减小到 0 时，CRTL 寄存器相应的位会被置为 1</span></span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  SysTick-&gt;CTRL &amp;= ~SysTick_CTRL_ENABLE_Msk;     <span class="comment">// 失能 SysTick 系统滴答定时器</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="修改-main.c-测试代码">修改 main.c 测试代码</h2><p>这里可以修改前面的 <code>main.c</code> 源文件，通过自定义的<code>UINIO_SysTick_Delay_us()</code> 和<code>UINIO_SysTick_Delay_ms()</code> 函数来进行延时，从而实现相同的 LED间隔 1 秒循环闪烁的效果：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== main.c ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;main.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/LED/LED.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/SysTick/SysTick.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">  UINIO_LED_GPIO_Config();  <span class="comment">// 初始化 LED 相关的 GPIO 引脚</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span>(<span class="number">1</span>) &#123;</span><br><span class="line">    gpio_bit_write(UINIO_LED_PORT, UINIO_LED_PIN, SET);      <span class="comment">// GPIOB8 输出高电平</span></span><br><span class="line">    UINIO_SysTick_Delay_ms(<span class="number">1000</span>);</span><br><span class="line"></span><br><span class="line">    gpio_bit_write(UINIO_LED_PORT, UINIO_LED_PIN, RESET);    <span class="comment">// GPIOB8 输出低电平</span></span><br><span class="line">    UINIO_SysTick_Delay_us(<span class="number">1000000</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><blockquote><p><strong>注意</strong>：本节内容涉及的全部源代码，已经保存在<strong>UINIO-MCU-GD32F350RBT6</strong> 核心板工程 <code>Examples</code>目录下的 <code>3-Systick</code>。</p></blockquote><h2 id="库函数修改-systick-的时钟源">库函数修改 SysTick 的时钟源</h2><p><strong>Keil-GD32F350RBT6</strong> 示例工程在<code>Firmware\GD32F3x0_standard_peripheral\Source\gd32f3x0_misc.c</code>源文件内提供有一个名为 <code>systick_clksource_set()</code>的库函数，可以用于修改 SysTick的时钟源，其功能与参数说明如下面表格所示：</p><p><img src="/Project/UINIO-MCU-GD32/7-SysTick/3.png"></p><p>可以看到，该库函数可以用于选择 SysTick系统滴答定时器的时钟源，可以选择的参数有如下两个：</p><ul><li><code>SYSTICK_CLKSOURCE_HCLK</code>：系统滴答定时器时钟源来自 AHB时钟；</li><li><code>SYSTICK_CLKSOURCE_HCLK_DIV8</code>: 系统滴答定时器时钟源来自AHB 时钟 8 分频（默认）；</li></ul><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*!</span></span><br><span class="line"><span class="comment">    \brief      set the systick clock source</span></span><br><span class="line"><span class="comment">    \param[in]  systick_clksource: the systick clock source needed to choose</span></span><br><span class="line"><span class="comment">                only one parameter can be selected which is shown as below:</span></span><br><span class="line"><span class="comment">      \arg        SYSTICK_CLKSOURCE_HCLK: systick clock source is from HCLK</span></span><br><span class="line"><span class="comment">      \arg        SYSTICK_CLKSOURCE_HCLK_DIV8: systick clock source is from HCLK/8</span></span><br><span class="line"><span class="comment">    \param[out] none</span></span><br><span class="line"><span class="comment">    \retval     none</span></span><br><span class="line"><span class="comment">*/</span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">systick_clksource_set</span><span class="params">(<span class="type">uint32_t</span> systick_clksource)</span> &#123;</span><br><span class="line">    <span class="keyword">if</span>(SYSTICK_CLKSOURCE_HCLK == systick_clksource) &#123;</span><br><span class="line">        <span class="comment">/* set the systick clock source from HCLK */</span></span><br><span class="line">        SysTick-&gt;CTRL |= SYSTICK_CLKSOURCE_HCLK;</span><br><span class="line">    &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">        <span class="comment">/* set the systick clock source from HCLK/8 */</span></span><br><span class="line">        SysTick-&gt;CTRL &amp;= SYSTICK_CLKSOURCE_HCLK_DIV8;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="基于位带-bit-band-执行位操作">基于位带 Bit Band 执行位操作</h1><p>嵌入式开发过程当中，经常需要进行<strong>位操作</strong>（即对一个比特位进行读写），早期的<strong>STC51</strong> 系列单片机可以通过关键字 <code>sbit</code>实现位操作，但是 <strong>ARM Cortex-M4</strong>架构的微控制器并不存在类似语法，而是通过提供<strong>位带别名区</strong>到<strong>位带区</strong>的映射来实现对<strong>比特位</strong>的操作。</p><h2 id="位带别名区-位带区">位带别名区 → 位带区</h2><p><strong>ARM Cortex-M4</strong>存储映射当中包含有<strong>位带别名区</strong>（Bit BandAlias）和<strong>位带区</strong>（Bit BandRegion）两个区域，通过将<strong>位带别名区</strong>（Bit BandAlias）当中的每 1 个 <code>Word</code><strong>字</strong>映射到<strong>位带区</strong>（Bit Band Region）里的<code>Bit</code> <strong>位</strong>（ARM 体系结构中 1个<strong>字</strong>的长度为 32<strong>位</strong>），这样操作<strong>位带别名区</strong>当中的<strong>字</strong>，就等于操作<strong>位带区</strong>相应的<strong>位</strong>，具体原理可以参照下面示意图：</p><p><img src="/Project/UINIO-MCU-GD32/8-Bit-Band/1.png"></p><p>基于 <strong>ARM Cortex-M4</strong> 架构的<strong>GD32F350RBT6</strong>微控制器，分别在两个区域实现了<strong>位带</strong>功能（即从<strong>位带别名区</strong>到<strong>位带区</strong>的映射）：</p><ol type="1"><li><strong>外设 Peripheral</strong> 的<code>0x44000000 ~ 0x42000000</code>地址范围属于<strong>位带别名区</strong>，而最低的<code>0x40100000 ~ 0x40000000</code>区别则属于<strong>位带区</strong>。</li><li><strong>静态随机存储器 SRAM</strong> 的<code>0x24000000 ~ 0x22000000</code>地址范围属于<strong>位带别名区</strong>，而最低的<code>0x20100000 ~ 0x20000000</code>区别则属于<strong>位带区</strong>。</li></ol><h2 id="建立通用的映射公式">建立通用的映射公式</h2><p>下面的公式展示了<strong>位带别名区域</strong>当中的每 1个<strong>字</strong>，如何对应到<strong>位带区域</strong>的相应<strong>位</strong>上面：</p><figure class="highlight js"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">映射到位带区目标位的别名区的字地址 = 位带别名区起始地址 + (位带区目标位所在字节的地址偏移量 × <span class="number">32</span>) + (目标位在对应字节当中的位置 × <span class="number">4</span>)</span><br></pre></td></tr></table></figure><p>根据上面的公式，位带区目标位的序号为 <code>number</code>（取值范围<code>0 &lt;= number &lt;= 31</code>，具体由待操作的目标寄存器决定），则该比特位在别名区的对应地址为：</p><figure class="highlight c"><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">目标位映射到外设别名区的地址 = <span class="number">0x42000000</span> + (位带区目标位所在字节的地址 - <span class="number">0x40000000</span>) * <span class="number">8</span> * <span class="number">4</span> + (number * <span class="number">4</span>);</span><br><span class="line">目标位映射到 SRAM 别名区的地址 = <span class="number">0x22000000</span> + (位带区目标位所在字节的地址 - <span class="number">0x20000000</span>) * <span class="number">8</span> * <span class="number">4</span> + (number * <span class="number">4</span>);</span><br></pre></td></tr></table></figure><blockquote><p><strong>注意</strong>：上述公式当中，因为 1 个字节有 8位，所以需要乘以 <code>8</code>，而 1 个位膨胀之后对应着 4个字节，所以需要再乘以 <code>4</code>。</p></blockquote><p>接下来，可以将上述的两个公式合并，成为一个用于将<strong>位带区地址</strong><code>address</code> 和<strong>位序号</strong> <code>bit_number</code>转换为<strong>位带别名区地址</strong>的 <code>BITBAND()</code>宏定义函数：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> BITBAND(address, bit_number) ((address &amp; 0xF0000000) + 0x02000000 + ((address &amp; 0x00FFFFFF) &lt;&lt; 5) + (bit_number &lt;&lt; 2)) <span class="comment">// 将位带区地址和位序号转换为位带别名区地址</span></span></span><br></pre></td></tr></table></figure><p>上述宏定义语句当中的 <code>address &amp; 0xF0000000</code> 用于取出<code>4</code> 或者 <code>2</code>，并且以此来判断当前操作的是 SRAM还是外设别名区：</p><ul><li>如果取出的是 <code>4</code>，加上 <code>0X0200 0000</code>之后等于<strong>外设别名区的起始地址</strong><code>0X4200 0000</code>;</li><li>如果取出的是 <code>2</code>，加上 <code>0X0200 0000</code> 之后等于<strong>SRAM 别名区的起始地址</strong> <code>0X2200 0000</code>；</li></ul><p>而上述宏定义语句当中 <code>address &amp; 0x00FF FFFF</code>得到的结果，与减去 <code>0X2000 0000</code> 或者<code>0X4000 0000</code> 得到的结果相同，而后续的<code>&lt;&lt; 5</code> 以及 <code>&lt;&lt; 2</code> 则分别起到了乘以<code>32</code> 和乘以 <code>4</code>的作用（即两种计算方式获得的二进制、十进制、十六进制结果完全相同）：</p><table><colgroup><col style="width: 27%"><col style="width: 23%"><col style="width: 24%"><col style="width: 24%"></colgroup><thead><tr><th style="text-align: left;">乘法与位运算的对应关系</th><th style="text-align: left;"></th><th style="text-align: left;"></th><th style="text-align: left;"></th></tr></thead><tbody><tr><td style="text-align: left;"><code>10 * 2 = 10 &lt;&lt; 1</code></td><td style="text-align: left;"><code>10 * 4 = 10 &lt;&lt; 2</code></td><td style="text-align: left;"><code>10 * 8 = 10 &lt;&lt; 3</code></td><td style="text-align: left;"><code>10 * 16 = 10 &lt;&lt; 4</code></td></tr><tr><td style="text-align: left;"><code>10 * 32 = 10 &lt;&lt; 5</code></td><td style="text-align: left;"><code>10 * 64 = 10 &lt;&lt; 6</code></td><td style="text-align: left;"><code>10 * 108 = 10 &lt;&lt; 7</code></td><td style="text-align: left;"><code>10 * 256 = 10 &lt;&lt; 8</code></td></tr></tbody></table><table><colgroup><col style="width: 27%"><col style="width: 23%"><col style="width: 24%"><col style="width: 24%"></colgroup><thead><tr><th style="text-align: left;">除法与位运算的对应关系</th><th style="text-align: left;"></th><th style="text-align: left;"></th><th style="text-align: left;"></th></tr></thead><tbody><tr><td style="text-align: left;"><code>10 / 2 = 10 &gt;&gt; 1</code></td><td style="text-align: left;"><code>10 / 4 = 10 &gt;&gt; 2</code></td><td style="text-align: left;"><code>10 / 8 = 10 &gt;&gt; 3</code></td><td style="text-align: left;"><code>10 / 16 = 10 &gt;&gt; 4</code></td></tr><tr><td style="text-align: left;"><code>10 / 32 = 10 &gt;&gt; 5</code></td><td style="text-align: left;"><code>10 / 64 = 10 &gt;&gt; 6</code></td><td style="text-align: left;"><code>10 / 108 = 10 &gt;&gt; 7</code></td><td style="text-align: left;"><code>10 / 256 = 10 &gt;&gt; 8</code></td></tr></tbody></table><p>最后，就可以通过<strong>指针</strong>操作<strong>位带别名区</strong>的地址，进而实现对于<strong>位带区</strong>相应比特位的操作：</p><figure class="highlight c"><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"><span class="meta">#<span class="keyword">define</span> ADDRESS_POINTER(address)         *((volatile unsigned long  *)(address))       <span class="comment">// 将地址转换为 unsigned long 类型指针</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> BIT_ADDRESS(address, bit_number) ADDRESS_POINTER(BITBAND(address, bit_number)) <span class="comment">// 使用前面定义的宏定义语句 BITBAND()，将位带别名区地址转换为指针</span></span></span><br></pre></td></tr></table></figure><p>由于 <strong>GD32F350RBT6</strong> 微控制器的<code>GPIOA ~ GPIOF</code> 基地址定义如下面列表所示：</p><ol type="1"><li><strong>GPIOA</strong> 基地址：<code>0x4800 0000</code>；</li><li><strong>GPIOB</strong> 基地址：<code>0x4800 0400</code>；</li><li><strong>GPIOC</strong> 基地址：<code>0x4800 0800</code>；</li><li><strong>GPIOD</strong> 基地址：<code>0x4800 0C00</code>；</li><li><strong>GPIOF</strong> 基地址：<code>0x4800 1400</code>；</li></ol><p>则可以将上述 GPIO 接口所对应的<strong>端口输出控制寄存器</strong><code>GPIOx_OCTL</code> 以及<strong>端口输入状态寄存器</strong><code>GPIOx_ISTAT</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 端口输出控制寄存器 GPIOx_OCTL 地址 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOA_OCTL_ADDRESS (GPIOA + 0x14)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOB_OCTL_ADDRESS (GPIOB + 0x14)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOC_OCTL_ADDRESS (GPIOC + 0x14)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOD_OCTL_ADDRESS (GPIOD + 0x14)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOE_OCTL_ADDRESS (GPIOE + 0x14)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOF_OCTL_ADDRESS (GPIOF + 0x14)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 端口输入状态寄存器 GPIOx_ISTAT 地址 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOA_ISTAT_ADDRESS (GPIOA + 0x10)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOB_ISTAT_ADDRESS (GPIOB + 0x10)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOC_ISTAT_ADDRESS (GPIOC + 0x10)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOD_ISTAT_ADDRESS (GPIOD + 0x10)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOE_ISTAT_ADDRESS (GPIOE + 0x10)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOF_ISTAT_ADDRESS (GPIOF + 0x10)</span></span><br></pre></td></tr></table></figure><p>上述代码当中的 <code>GPIOx</code> 已经被定义在固件库的<code>gd32f3x0_gpio.h</code> 头文件当中，编译的时候已经由 <strong>KeiluVision5</strong>自动包含相关路径。接下来的时间，就可以基于上面列出的寄存器地址，进一步将它们封装为控制GPIO 输入与输出的宏定义函数：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 控制 GPIOA 的输入与输出 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOA_Out(number) BIT_ADDRESS(GPIOA_OCTL_ADDRESS, number)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOA_In(number)  BIT_ADDRESS(GPIOA_ISTAT_ADDRESS, number)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 控制 GPIOB 的输入与输出 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOB_Out(number) BIT_ADDRESS(GPIOB_OCTL_ADDRESS, number)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOB_In(number)  BIT_ADDRESS(GPIOB_ISTAT_ADDRESS, number)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 控制 GPIOC 的输入与输出 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOC_Out(number) BIT_ADDRESS(GPIOC_OCTL_ADDRESS, number)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOC_In(number)  BIT_ADDRESS(GPIOC_ISTAT_ADDRESS, number)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 控制 GPIOD 的输入与输出 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOD_Out(number) BIT_ADDRESS(GPIOD_OCTL_ADDRESS, number)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOD_In(number)  BIT_ADDRESS(GPIOD_ISTAT_ADDRESS, number)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 控制 GPIOF 的输入与输出 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOF_Out(number) BIT_ADDRESS(GPIOF_OCTL_ADDRESS, number)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOF_In(number)  BIT_ADDRESS(GPIOF_ISTAT_ADDRESS, number)</span></span><br></pre></td></tr></table></figure><h2 id="完整-keil-µvision-工程代码-2">完整 Keil µVision 工程代码</h2><h3 id="bitband.h">BitBand.h</h3><p>把上述的宏定义代码保存至 <code>Drivers/BitBand</code> 目录下的<code>BitBand.h</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="comment">/*========== BitBand.h ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> UINIO_BitBand_H</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_BitBand_H</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> BITBAND(address, bit_number) ((address &amp; 0xF0000000) + 0x02000000 + ((address &amp; 0x00FFFFFF) &lt;&lt; 5) + (bit_number &lt;&lt; 2)) <span class="comment">// 将位带区地址和位序号转换为位带别名区地址</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ADDRESS_POINTER(address)         *((volatile unsigned long  *)(address))                                               <span class="comment">// 将地址转换为 unsigned long 类型指针</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> BIT_ADDRESS(address, bit_number) ADDRESS_POINTER(BITBAND(address, bit_number))                                         <span class="comment">// 使用前面定义的宏定义语句 BITBAND()，将位带别名区地址转换为指针</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 端口输出控制寄存器 GPIOx_OCTL 地址 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOA_OCTL_ADDRESS (GPIOA + 0x14)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOB_OCTL_ADDRESS (GPIOB + 0x14)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOC_OCTL_ADDRESS (GPIOC + 0x14)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOD_OCTL_ADDRESS (GPIOD + 0x14)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOE_OCTL_ADDRESS (GPIOE + 0x14)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOF_OCTL_ADDRESS (GPIOF + 0x14)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 端口输入状态寄存器 GPIOx_ISTAT 地址 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOA_ISTAT_ADDRESS (GPIOA + 0x10)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOB_ISTAT_ADDRESS (GPIOB + 0x10)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOC_ISTAT_ADDRESS (GPIOC + 0x10)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOD_ISTAT_ADDRESS (GPIOD + 0x10)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOE_ISTAT_ADDRESS (GPIOE + 0x10)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOF_ISTAT_ADDRESS (GPIOF + 0x10)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 控制 GPIOA 的输入与输出 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOA_Out(number) BIT_ADDRESS(GPIOA_OCTL_ADDRESS, number)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOA_In(number)  BIT_ADDRESS(GPIOA_ISTAT_ADDRESS, number)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 控制 GPIOB 的输入与输出 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOB_Out(number) BIT_ADDRESS(GPIOB_OCTL_ADDRESS, number)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOB_In(number)  BIT_ADDRESS(GPIOB_ISTAT_ADDRESS, number)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 控制 GPIOC 的输入与输出 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOC_Out(number) BIT_ADDRESS(GPIOC_OCTL_ADDRESS, number)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOC_In(number)  BIT_ADDRESS(GPIOC_ISTAT_ADDRESS, number)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 控制 GPIOD 的输入与输出 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOD_Out(number) BIT_ADDRESS(GPIOD_OCTL_ADDRESS, number)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOD_In(number)  BIT_ADDRESS(GPIOD_ISTAT_ADDRESS, number)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 控制 GPIOF 的输入与输出 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOF_Out(number) BIT_ADDRESS(GPIOF_OCTL_ADDRESS, number)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOF_In(number)  BIT_ADDRESS(GPIOF_ISTAT_ADDRESS, number)</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">/* UINIO_BitBand_H */</span></span></span><br></pre></td></tr></table></figure><h3 id="main.c">main.c</h3><p>继续修改之前的 LED 闪烁示例工程 <code>main.c</code> 源文件，在包含<code>BitBand.h</code> 头文件的同时，通过调用宏定义函数<code>GPIOB_Out(8)</code> 修改 <strong>GPIOB8</strong>引脚的电平状态：</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== main.c ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;main.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/LED/LED.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/SysTick/SysTick.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/BitBand/BitBand.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">  systick_config();  <span class="comment">// 初始化系统滴答定时器</span></span><br><span class="line">  UINIO_LED_GPIO_Config(); <span class="comment">// 初始化 LED 相关的 GPIO 引脚</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span>(<span class="number">1</span>) &#123;</span><br><span class="line">    GPIOB_Out(<span class="number">8</span>) = <span class="number">1</span>;      <span class="comment">// GPIOB8 输出高电平</span></span><br><span class="line">    UINIO_SysTick_Delay_ms(<span class="number">1000</span>);</span><br><span class="line"></span><br><span class="line">    GPIOB_Out(<span class="number">8</span>) = <span class="number">0</span>;      <span class="comment">// GPIOB8 输出低电平</span></span><br><span class="line">    UINIO_SysTick_Delay_ms(<span class="number">1000</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>除此之外，也可以将位带操作相关的宏定义代码，更加直观的声明在<code>main.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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== main.c ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;main.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/LED/LED.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/SysTick/SysTick.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 偏移量 = GPIOB 基地址 0x48000400 + GPIOx_OCTL 偏移量 0x14 - 片上外设起始地址 0x40000000 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOB_OCTL_OFFSET ((GPIOB + 0x14) - 0x40000000)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 位带别名区的字地址 = 位带别名区起始地址 + (位带区目标位所在字节的地址偏移量 × 32) + (目标位在对应字节当中的位置 × 4) */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> BIT_ADDRESS(byte_offset, bit_number) (volatile unsigned long *)(0x42000000 + (byte_offset &lt;&lt; 5) + (bit_number &lt;&lt; 2))</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 配置 GPIOB 端口指定引脚的输出状态，例如 GPIOB_OUT(8) */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GPIOB_OUT(number) *(BIT_ADDRESS(GPIOB_OCTL_OFFSET, number))</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">  UINIO_LED_GPIO_Config(); <span class="comment">// 初始化 LED 相关的 GPIO 引脚</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span>(<span class="number">1</span>) &#123;</span><br><span class="line">    GPIOB_OUT(<span class="number">8</span>) = <span class="number">1</span>;      <span class="comment">// GPIOB8 输出高电平</span></span><br><span class="line">    UINIO_SysTick_Delay_ms(<span class="number">1000</span>);</span><br><span class="line"></span><br><span class="line">    GPIOB_OUT(<span class="number">8</span>) = <span class="number">0</span>;      <span class="comment">// GPIOB8 输出低电平</span></span><br><span class="line">    UINIO_SysTick_Delay_ms(<span class="number">1000</span>);</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="gpio-输入模式与按键">GPIO 输入模式与按键</h1><h2 id="按键使用原理">按键使用原理</h2><p><strong>微动开关</strong>或者<strong>轻触按键</strong>是通过内部的<code>触点</code>与<code>弹片</code>来实现导通与截止，将其连接至<strong>GD32F350RBT6</strong> 的 GPIO 引脚，就可以通过检测其按下之后GPIO 引脚获取的电平状态，来判断当前是处于按下还是松开的情况：</p><p><img src="/Project/UINIO-MCU-GD32/9-Key/1.png"></p><p>当按键在被按下或者松开的时候，会由于触点上弹片的弹性作用，发生<code>5ms ~ 10ms</code> 机械抖动，为了避免 GPIO得到错误的状态，必须考虑采取一定的措施去消除这种抖动所带来的干扰：</p><ul><li><strong>硬件消抖</strong>：微动开关两侧并联上一枚<strong>电容</strong>，利用其充放电作用吸收抖动产生的振荡。</li><li><strong>软件消抖</strong>：当开关按下时，通过延时代码规避掉抖动发生的时间。</li></ul><p>首先，将一枚轻触按键 <code>SW1</code> 连接到<strong>UINIO-MCU-GD32F350RBT6</strong> 的 <strong>GPIOB9</strong>引脚，其中一端连接至 <code>3V3</code> 引脚，而另一端经过位号为<code>R3</code> 的 <code>10KΩ</code> <strong>下拉电阻</strong>之后连接至<code>GND</code> 引脚：</p><p><img src="/Project/UINIO-MCU-GD32/9-Key/2.png"></p><p>然后，使用固件库提供的工具函数，把 <strong>GPIOB9</strong>配置为带<strong>下拉电阻</strong>的<strong>输入模式</strong>，通过检测该引脚的电平状态，就可以判断按键<code>SW1</code>是否被按下（按键松开为<strong>低电平</strong>，按键按下为<strong>高电平</strong>）。</p><h2 id="完整-keil-µvision-工程代码-3">完整 Keil µVision 工程代码</h2><p>如前所述，使用 GPIO端口的输入输出功能，通常会需要经历下面三个步骤：</p><ol type="1"><li>通过<code>void rcu_periph_clock_enable(rcu_periph_enum periph);</code>固件库函数启用 GPIO 端口对应的<strong>外设时钟</strong>。</li><li>通过<code>void gpio_mode_set(uint32_t gpio_periph, uint32_t mode, uint32_t pull_up_down, uint32_t pin);</code>固件库函数配置 GPIO 端口的<strong>工作模式</strong>（输入模式<code>GPIO_MODE_INPUT</code>、输出模式<code>GPIO_MODE_OUTPUT</code>、备用功能模式<code>GPIO_MODE_AF</code>、模拟模式<code>GPIO_MODE_ANALOG</code>），以及设置<strong>上下拉电阻状态</strong>（悬空无上下拉<code>GPIO_PUPD_NONE</code>、带上拉电阻<code>GPIO_PUPD_PULLUP</code>、带下拉电阻<code>GPIO_PUPD_PULLDOWN</code>）。</li><li>通过<code>void gpio_bit_toggle(uint32_t gpio_periph, uint32_t pin);</code>固件库函数翻转 LED 对应 GPIO 引脚的电平状态。</li></ol><blockquote><p><strong>注意</strong>：本节内容所涉及的全部测试代码，已保存在<strong>UINIO-MCU-GD32F350RBT6</strong> 核心板开源项目<code>Examples</code> 目录下的 <strong>5-Key</strong> 工程当中。</p></blockquote><h3 id="driverskey.h">Drivers/key.h</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== Key.h ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> UINIO_KEY_H</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_KEY_H</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;systick.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_KEY_RCU  RCU_GPIOB   <span class="comment">// 宏定义按键对应的 GPIO 端口时钟</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_KEY_PORT GPIOB       <span class="comment">// 宏定义按键对应的 GPIO 端口</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_KEY_PIN  GPIO_PIN_9  <span class="comment">// 宏定义按键对应的 GPIO 引脚</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_Key_GPIO_Config</span><span class="params">(<span class="type">void</span>)</span>;  <span class="comment">// 调用开关对应 GPIO 引脚的配置函数</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_Key_Scan</span><span class="params">(<span class="type">void</span>)</span>;         <span class="comment">// 按键状态扫描函数</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">/* UINIO_KEY_H */</span></span></span><br></pre></td></tr></table></figure><h3 id="driverskey.c">Drivers/key.c</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><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="comment">/*========== Key.c ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;Key.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../LED/LED.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 按键对应 GPIO 引脚的配置函数 */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_Key_GPIO_Config</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">  rcu_periph_clock_enable(UINIO_KEY_RCU);                                            <span class="comment">// 使能外设时钟</span></span><br><span class="line">  gpio_mode_set(UINIO_KEY_PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, UINIO_KEY_PIN); <span class="comment">// 配置 GPIO 为带下拉电阻的输入模式</span></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="type">void</span> <span class="title function_">UINIO_Key_Scan</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">  <span class="comment">/* 判断按键是否被按下（高电平按下，低电平松开） */</span></span><br><span class="line">  <span class="keyword">if</span> (gpio_input_bit_get(UINIO_KEY_PORT, UINIO_KEY_PIN) == SET) &#123;</span><br><span class="line">    delay_1ms(<span class="number">20</span>);                                                       <span class="comment">// 延时 20 毫秒，规避按键弹片抖动时间</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* 再次判断按键是否被按下 */</span></span><br><span class="line">    <span class="keyword">if</span> (gpio_input_bit_get(UINIO_KEY_PORT, UINIO_KEY_PIN) == SET) &#123;</span><br><span class="line">      gpio_bit_toggle(UINIO_LED_PORT, UINIO_LED_PIN);                    <span class="comment">// 翻转 LED 对应 GPIO 引脚的电平状态</span></span><br><span class="line">      <span class="keyword">while</span> (gpio_input_bit_get(UINIO_KEY_PORT, UINIO_KEY_PIN) == SET);  <span class="comment">// 判断按键是否被松开</span></span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="sourcesmain.c-2">Sources/main.c</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><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== main.c ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;systick.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;main.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/LED/LED.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/Key/Key.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/SysTick/SysTick.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">  systick_config();         <span class="comment">// 滴答定时器初始化</span></span><br><span class="line">  UINIO_LED_GPIO_Config();  <span class="comment">// 配置 LED 相关的 GPIO 外设</span></span><br><span class="line">  UINIO_Key_GPIO_Config();  <span class="comment">// 配置按键相关的 GPIO 外设</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span> (<span class="number">1</span>) &#123;</span><br><span class="line">    UINIO_Key_Scan();       <span class="comment">// 循环扫描按键状态</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="usart-通用同步异步收发器">USART 通用同步/异步收发器</h1><h2 id="usart-串行协议分析">USART 串行协议分析</h2><p><strong>通用同步/异步收发器</strong>（USART，UniversalSynchronous/Asynchronous ReceiverTransmitter）是一种基于<strong>数据帧</strong>的串行数据通信方式，每一个数据帧都会以1 个<code>起始位</code>开始，并且以 1个<code>停止位</code>结束，其数据帧的基本格式如下面示意图所示：</p><p><img src="/Project/UINIO-MCU-GD32/10-USART/1.png"></p><ol type="1"><li><strong>起始位</strong>：首先发送一个起始位，通常为逻辑低电平<code>0</code>，用于通知接收端数据即将开始发送。</li><li><strong>数据位</strong>：紧接着是数据位，可以有 <code>5 ~ 8</code>位长度，按照由 <strong>LSB</strong>（最低有效位）到<strong>MSB</strong>（最高有效位）的顺序发送。</li><li><strong>校验位</strong>：数据位之后是可选的奇偶校验位，用于检查数据传输过程当中，是否存在错误。</li><li><strong>停止位</strong>：最后是停止位，通常为逻辑高电平<code>1</code>，用于标记数据帧传输完毕。</li></ol><blockquote><p><strong>注意</strong>：<strong>空闲帧</strong>与停止位一样均为<strong>高电平</strong>，如果USART连接断开，则下拉为<strong>低电平</strong>，从而成为<strong>断开帧</strong>。</p></blockquote><p><strong>USART</strong>串行接口可以工作在<strong>单工</strong>（单向通信）、<strong>半双工</strong>（双向分时通信）、<strong>全双工</strong>（双向通信）模式下。每个USART 通信设备之间的 <strong>波特率</strong>（单位为<code>bit/s</code>，即每秒钟传送的比特位数）、<strong>数据位</strong>、<strong>停止位</strong>、<strong>奇偶校验位</strong>必须保持一致。</p><p><img src="/Project/UINIO-MCU-GD32/10-USART/2.png"></p><p>将 <strong>UINIO-MCU-GD32F350RBT6</strong> 核心板与另一款 UINIO系列开源硬件 <a href="https://gitee.com/uinika/UINIO-USB-UART"><strong>UINIO-USB-UART</strong>串口调试器</a> ，参照下图的线路相互进行连接（即<strong>UINIO-MCU-GD32F350RBT6</strong> 核心板的 <code>GPIOA9</code> 和<code>GPIOA10</code> 分别连接至 <strong>UINIO-USB-UART</strong>串口调试器的 <code>RXD</code> 和 <code>TXD</code> 引脚），并且将后者的Type-C 接口通过 USB 线缆连接至计算机，从而建立起与串行通信上位机软件的USART 连接，进而可以查看到后续实验代码所打印出的测试数据。</p><h2 id="完整-keil-µvision-工程代码-4">完整 Keil µVision 工程代码</h2><p>使用 <strong>GD32F350RBT6</strong> 的片上 USART外设进行通信，需要经历下面六个步骤：</p><ol type="1"><li>使能 USART 和 GPIO 外设时钟<code>rcu_periph_clock_enable()</code>。</li><li>配置 GPIO 复用模式 <code>gpio_af_set()</code>。</li><li>配置 GPIO 的工作模式 <code>gpio_mode_set()</code>。</li><li>配置 GPIO 的输出模式与速度<code>gpio_output_options_set</code>。</li><li>复位 USART 外设 <code>usart_deinit()</code>，并且配置其工作参数<code>usart_deinit()</code>、<code>usart_baudrate_set()</code>、<code>usart_parity_config()</code>、<code>usart_word_length_set()</code>、<code>usart_stop_bit_set()</code>。</li><li>使能 USART 串口 <code>usart_enable()</code> 及其发送功能<code>usart_transmit_config()</code>。</li></ol><blockquote><p><strong>注意</strong>：本节内容所涉及的全部测试代码，已保存在<strong>UINIO-MCU-GD32F350RBT6</strong> 核心板开源项目<code>Examples</code> 目录下的 <strong>6-USART</strong> 工程当中。</p></blockquote><h3 id="driversusart.h">Drivers/USART.h</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><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">ifndef</span> UINIO_USART_H</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_USART_H</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;systick.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_USART USART0             <span class="comment">// 定义 USART 外设资源</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_USART_RCU RCU_USART0     <span class="comment">// 定义 USART0 的外设时钟</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_USART_AF GPIO_AF_1       <span class="comment">// 定义 GPIO 引脚的复用功能</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 定义 TX 和 RX 对应的 GPIO 外设时钟 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_USART_TX_RCU RCU_GPIOA</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_USART_RX_RCU RCU_GPIOA</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 定义 TX 和 RX 对应的 GPIO 接口*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_USART_TX_PORT GPIOA</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_USART_RX_PORT GPIOA</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 定义 TX 和 RX 对应的 GPIO 引脚*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_USART_TX_PIN GPIO_PIN_9</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_USART_RX_PIN GPIO_PIN_10</span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_USART_GPIO_Config</span><span class="params">(<span class="type">uint32_t</span> band_rate)</span>; <span class="comment">// USART 外设资源配置函数</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_USART_Send_Data</span><span class="params">(<span class="type">char</span> ucch)</span>;            <span class="comment">// 用于发送 1 个字节的函数</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_USART_Send_String</span><span class="params">(<span class="type">char</span> *ucstr)</span>;        <span class="comment">// 用于发送字符串的函数</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">/* UINIO_USART_H */</span></span></span><br></pre></td></tr></table></figure><h3 id="driversusart.c">Drivers/USART.c</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><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><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;USART.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;stdio.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/** 配置 USART 相关的 GPIO，参数 band_rate 是波特率 */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_USART_GPIO_Config</span><span class="params">(<span class="type">uint32_t</span> band_rate)</span> &#123;</span><br><span class="line">  <span class="comment">/* 开启时钟 */</span></span><br><span class="line">  rcu_periph_clock_enable(UINIO_USART_TX_RCU); <span class="comment">// 使能 TX 对应 GPIO 引脚的时钟</span></span><br><span class="line">  rcu_periph_clock_enable(UINIO_USART_RX_RCU); <span class="comment">// 使能 RX 对应 GPIO 引脚的时钟</span></span><br><span class="line">  rcu_periph_clock_enable(UINIO_USART_RCU);    <span class="comment">// 使能 USART 外设时钟</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 配置 GPIO 引脚的复用功能 */</span></span><br><span class="line">  gpio_af_set(UINIO_USART_TX_PORT, UINIO_USART_AF, UINIO_USART_TX_PIN);</span><br><span class="line">  gpio_af_set(UINIO_USART_RX_PORT, UINIO_USART_AF, UINIO_USART_RX_PIN);</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 配置 TX 和 RX 对应 GPIO 引脚的模式与速度 */</span></span><br><span class="line">  gpio_mode_set(UINIO_USART_TX_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, UINIO_USART_TX_PIN);             <span class="comment">// 配置 TX 引脚为带上拉电阻的复用模式</span></span><br><span class="line">  gpio_output_options_set(UINIO_USART_TX_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, UINIO_USART_TX_PIN); <span class="comment">// 配置 TX 引脚为推挽输出，速率为 50MHZ</span></span><br><span class="line">  gpio_mode_set(UINIO_USART_RX_PORT, GPIO_MODE_AF, GPIO_PUPD_PULLUP, UINIO_USART_RX_PIN);             <span class="comment">// 配置 RX 引脚为带上拉电阻的复用模式</span></span><br><span class="line">  gpio_output_options_set(UINIO_USART_RX_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, UINIO_USART_RX_PIN); <span class="comment">// 配置 RX 引脚为推挽输出，速率为 50MHZ</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 配置 USART 串行通信的参数 */</span></span><br><span class="line">  usart_deinit(UINIO_USART);                         <span class="comment">// 复位 USART 外设</span></span><br><span class="line">  usart_baudrate_set(UINIO_USART, band_rate);        <span class="comment">// 设置 USART 波特率</span></span><br><span class="line">  usart_parity_config(UINIO_USART, USART_PM_NONE);   <span class="comment">// 设置 USART 奇偶校验位</span></span><br><span class="line">  usart_word_length_set(UINIO_USART, USART_WL_8BIT); <span class="comment">// 设置 USART 数据位长度为 8 位</span></span><br><span class="line">  usart_stop_bit_set(UINIO_USART, USART_STB_1BIT);   <span class="comment">// 设置 USART 停止位长度为 1 位</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 使能和配置 USART串口 */</span></span><br><span class="line">  usart_transmit_config(UINIO_USART, USART_TRANSMIT_ENABLE); <span class="comment">// 使能 USART 发送功能</span></span><br><span class="line">  usart_enable(UINIO_USART);                                 <span class="comment">// 使能 USART 串口</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/** 通过 USART 发送一个字节 */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_USART_Send_Data</span><span class="params">(<span class="type">char</span> data)</span> &#123;</span><br><span class="line">  usart_data_transmit(UINIO_USART, (<span class="type">uint8_t</span>)data);              <span class="comment">// 通过 USART 发送数据</span></span><br><span class="line">  <span class="keyword">while</span> (RESET == usart_flag_get(UINIO_USART, USART_FLAG_TBE)); <span class="comment">// 通过发送数据缓冲区空标志位来判断发送是否完成</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/** 通过 USART 发送字符串 */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_USART_Send_String</span><span class="params">(<span class="type">char</span> *<span class="built_in">string</span>)</span> &#123;</span><br><span class="line">  <span class="comment">/* 开始循环发送，当字符串为空或者指针地址为空时跳出 */</span></span><br><span class="line">  <span class="keyword">while</span> (<span class="built_in">string</span> &amp;&amp; *<span class="built_in">string</span>) &#123;</span><br><span class="line">    UINIO_USART_Send_Data(*<span class="built_in">string</span>++);  <span class="comment">// 调用上面的函数，循环发送单个字符</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">/** 通过重写 C 语言 printf() 不断循环调用的 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> character, FILE *stream)</span> &#123;</span><br><span class="line">  UINIO_USART_Send_Data(character);    <span class="comment">// 调用上面的函数，发送单个字符</span></span><br><span class="line">  <span class="keyword">return</span> character;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="sourcesmain.c-3">Sources/main.c</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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== main.c ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;systick.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;main.h&quot;</span></span></span><br><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><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/USART/USART.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">  UINIO_USART_GPIO_Config(<span class="number">9600U</span>);  <span class="comment">// 配置 USART0，并将波特率设置为 9600</span></span><br><span class="line"></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">short</span> count1 = <span class="number">0</span>;       <span class="comment">// 声明短整型测试变量 count1</span></span><br><span class="line">  <span class="type">float</span> count2 = <span class="number">0.0</span>;              <span class="comment">// 声明浮点型测试变量 count2</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span> (<span class="number">1</span>) &#123;</span><br><span class="line">    <span class="comment">/* 依次发送单个字符 `H` `a` `n` `k` */</span></span><br><span class="line">    UINIO_USART_Send_Data(<span class="string">&#x27;H&#x27;</span>);</span><br><span class="line">    UINIO_USART_Send_Data(<span class="string">&#x27;a&#x27;</span>);</span><br><span class="line">    UINIO_USART_Send_Data(<span class="string">&#x27;n&#x27;</span>);</span><br><span class="line">    UINIO_USART_Send_Data(<span class="string">&#x27;k&#x27;</span>);</span><br><span class="line">    UINIO_USART_Send_Data(<span class="string">&#x27;\n&#x27;</span>);</span><br><span class="line"></span><br><span class="line">    UINIO_USART_Send_String(<span class="string">&quot;UinIO.com\n&quot;</span>);                   <span class="comment">// 发送字符串 UinIO.com</span></span><br><span class="line"></span><br><span class="line">    <span class="comment">/* 测试 printf() 串口打印重定向 */</span></span><br><span class="line">    count1++;                                                 <span class="comment">// 短整型测试变量自增 1</span></span><br><span class="line">    count2 += <span class="number">1.0F</span>;                                           <span class="comment">// 浮点型测试变量自增 1</span></span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;count1 = %d, count2 = %.2f \n&quot;</span>, count1, count2);  <span class="comment">// 向 USART 串行接口打印格式化信息</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="外部中断-exti">外部中断 EXTI</h1><h2 id="嵌套向量中断控制-nvic">嵌套向量中断控制 NVIC</h2><p><strong>GD32F350RBT6</strong> 微控制器所采用的 ARM Cortex-M4内核架构集成有<strong>嵌套式矢量型中断控制器</strong>（NVIC，NestedVectored Interrupt Controller），主要用于管理和处理中断：</p><ol type="1"><li><strong>中断管理</strong>：当中断源产生中断信号的时候，NVIC就会捕获处理这些信号。</li><li><strong>优先级处理</strong>：通过对中断优先级进行排序，NVIC会确保高优先级的中断首先得到处理。</li><li><strong>中断嵌套</strong>：如果在一个中断服务程序当中，发生了另外一个更高优先级的中断，NVIC会暂停处理当前中断，转而处理更高优先级的中断。</li><li><strong>向量中断</strong>：每一个中断都关联有一个固定地址的中断服务程序，当中断发生时NVIC 就会根据这个地址去执行相应的中断服务程序。</li><li><strong>中断屏蔽</strong>：NVIC允许通过编程来屏蔽某些中断，以防止它们被处理，该功能在特定情况下非常有用，例如需要执行关键任务而不希望被其它中断事件打断的时候。</li><li><strong>低功耗模式支持</strong>：NVIC与微控制器的低功耗模式紧密集成，休眠模式下 NVIC 可以检测外部中断并且唤醒MCU，从而实现在低功耗状态下的快速响应。</li></ol><h2 id="外部中断事件控制器-exti">外部中断/事件控制器 EXTI</h2><p><strong>外部中断/事件控制器</strong>（EXTI，External Interrupt/EventController）负责检测来自于中断源的中断请求，并且通知微控制器进行处理。其包含有24个相互独立的边沿检测电路（每个边沿检测电路都可以独立进行配置与屏蔽），能够在微控制器内核当中产生<strong>中断请求</strong>以及<strong>唤醒事件</strong>。每一个中断都拥有4 位的<strong>中断优先级配置位</strong>，可以提供 16个<strong>中断优先等级</strong>，并且这些中断都拥有着<strong>上升沿</strong>、<strong>下降沿</strong>、<strong>任意边沿</strong>三种触发方式：</p><p><img src="/Project/UINIO-MCU-GD32/11-Interrupt/1.png"></p><ol type="1"><li><strong>中断线配置</strong>：配置<strong>外部中断线</strong>（EXTILine），也就是 MCU当中用于接收中断请求的<strong>物理线路</strong>。</li><li><strong>触发条件方式</strong>：设置中断的触发方式，即<code>上升沿</code>、<code>下降沿</code>、<code>任意边沿</code>。</li><li><strong>中断优先级管理</strong>：分配不同的中断优先级，确保 MCU能够按照预期的顺序与优先级处理中断请求。</li><li><strong>中断请求生成与处理</strong>：当外部事件满足中断触发条件时，生成一个中断请求发送给<strong>NVIC</strong>（嵌套向量中断控制器），后者会根据中断的优先级来决定是否响应该中断，如果需要响应，就会暂停执行当前的程序，转而将控制权移交给指定的<strong>ISR</strong>（中断服务程序，Interrupt Service Routine）。</li><li><strong>中断服务程序执行</strong>：在 ISR中断服务程序当中，可以编写代码处理外部事件。待处理完毕之后，就会将控制权返还给刚才被中断的程序，从之前暂停的位置继续运行。</li></ol><p><strong>EXTI</strong> 中断的<strong>触发源</strong>可以来自于<code>GPIOA/B/C/F (0~15)</code> 引脚，以及<code>LVD</code>（低电压检测）、<code>RTC</code>（实时时钟）、<code>CEC</code>（HDMI的 CEC控制器）、<code>CMP</code>（比较器）、<code>USB</code>、<code>USART</code>等片上外设：</p><p><img src="/Project/UINIO-MCU-GD32/11-Interrupt/2.png"></p><blockquote><p><strong>注意</strong>：上述表格当中 <strong>EXTI中断线</strong>与<strong>触发源</strong>的对应关系非常重要。</p></blockquote><p>接下来的实验里，首先需要将一枚轻触按键 <code>SW2</code> 连接到<strong>UINIO-MCU-GD32F350RBT6</strong> 核心板的 <strong>GPIOA0</strong>引脚，其中一端连接至 <code>3V3</code>，而另外一端经过位号为<code>R5</code> 的 <code>10KΩ</code> 下拉电阻之后连接至<code>GND</code>。然后再把 <code>LED3</code> 的一端通过限流电阻<code>R4</code> 连接至 <strong>GPIOB8</strong> 引脚，另外一端连接到<code>GND</code> 引脚：</p><p><img src="/Project/UINIO-MCU-GD32/11-Interrupt/3.png"></p><p>最后，再将 <strong>UINIO-MCU-GD32F350RBT6</strong> 的<strong>GPIOA9</strong> 和 <strong>GPIOA10</strong> 分别连接至<strong>UINIO-USB-UART</strong> 串口调试器的 <code>RXD</code> 和<code>TXD</code> 引脚，以便于通过上位机软件观察 USART串口输出的调试数据。</p><h2 id="完整-keil-µvision-工程代码-5">完整 Keil µVision 工程代码</h2><p>使用 <strong>GD32F350RBT6</strong> 微控制器的 EXTI外部中断功能，通常需要经历下面一系列步骤：</p><ol type="1"><li>通过 <code>rcu_periph_clock_enable()</code> 使能 GPIO 引脚和 CGFCMP系统配置外设时钟。</li><li>调用 <code>nvic_priority_group_set()</code>配置<strong>优先级分组</strong>。</li><li>调用 <code>nvic_irq_enable()</code> 使能 NVIC中断，并且配置<strong>抢占优先级</strong>和<strong>响应优先级</strong>。</li><li>通过 <code>syscfg_exti_line_config()</code> 将中断线与 GPIO引脚进行连接。</li><li>调用 <code>exti_init()</code>设置<strong>中断线</strong>、<strong>中断模式</strong>、<strong>触发类型</strong>。</li><li>使能中断线 <code>exti_interrupt_enable()</code>，并且清除中断标志位<code>exti_interrupt_flag_clear()</code>。</li><li>编写已经在 <code>startup_gd32f3x0.s</code>启动文件当中定义好名称，且参数和返回值皆为 <code>void</code>的<strong>中断服务函数</strong>（每次中断执行完毕之后都需要清除一下中断标志位）。</li></ol><blockquote><p><strong>注意</strong>：本节内容所涉及的全部测试代码，已保存在<strong>UINIO-MCU-GD32F350RBT6</strong> 核心板开源项目<code>Examples</code> 目录下的 <strong>7-EXTI-Key</strong>工程当中。</p></blockquote><h3 id="driversexti-key.h">Drivers/EXTI-Key.h</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><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== EXTI-Key.h ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> UINIO_EXTI_KEY_H</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_EXTI_KEY_H</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_KEY_PORT GPIOA       <span class="comment">// 按键对应的 GPIO 端口</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_KEY_PIN  GPIO_PIN_0  <span class="comment">// 按键对应的 GPIO 引脚</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_KEY_RCU  RCU_GPIOA   <span class="comment">// 按键对应 GPIO 端口的外设时钟</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_KEY_EXTI_PORT_SOURCE EXTI_SOURCE_GPIOA   <span class="comment">// 定义用于 EXTI 的 GPIO 端口</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_KEY_EXTI_PIN_SOURCE  EXTI_SOURCE_PIN0    <span class="comment">// 定义用于 EXTI 的 GPIO 引脚</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_KEY_EXTI_LINE        EXTI_0              <span class="comment">// 定义 EXTI 中断线 0</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_KEY_EXTI_IRQN        EXTI0_1_IRQn        <span class="comment">// 定义 EXTI 线 0 和线 1 中断</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_KEY_EXTI_IRQ_Handler EXTI0_1_IRQHandler  <span class="comment">// 定义 EXTI 中断函数的名称</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_EXTI_Key_GPIO_Config</span><span class="params">(<span class="type">void</span>)</span>;  <span class="comment">// 按键中断配置函数</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">/* UINIO_EXTI_KEY_H */</span></span></span><br></pre></td></tr></table></figure><blockquote><p><strong>注意</strong>：上述代码当中的<strong>中断线 0 和 1</strong>的中断服务函数名称 <code>EXTI0_1_IRQHandler</code> 已经被定义在<code>startup_gd32f3x0.s</code> 启动文件当中。</p></blockquote><h3 id="driversexti-key.c">Drivers/EXTI-Key.c</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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== EXTI-Key.c ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;stdio.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../LED/LED.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../EXTI-Key/EXTI-Key.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/** 按键中断配置函数 */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_EXTI_Key_GPIO_Config</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">  rcu_periph_clock_enable(UINIO_KEY_RCU);  <span class="comment">// 使能按键对应的 GPIO 外设时钟</span></span><br><span class="line">  rcu_periph_clock_enable(RCU_CFGCMP);     <span class="comment">// 使能 CGFCMP 系统配置外设时钟</span></span><br><span class="line"></span><br><span class="line">  gpio_mode_set(UINIO_KEY_PORT, GPIO_MODE_INPUT, GPIO_PUPD_PULLDOWN, UINIO_KEY_PIN);  <span class="comment">// 配置按键对应的 GPIO 引脚为带下拉电阻的输入模式，默认为低电平</span></span><br><span class="line">  nvic_irq_enable(UINIO_KEY_EXTI_IRQN, <span class="number">3U</span>, <span class="number">3U</span>);                                       <span class="comment">// 使能 NVIC 中断，抢占优先级 1，子优先级 1</span></span><br><span class="line"></span><br><span class="line">  syscfg_exti_line_config(UINIO_KEY_EXTI_PORT_SOURCE, UINIO_KEY_EXTI_PIN_SOURCE);  <span class="comment">// 配置 GPIO 引脚作为 EXTI 外部中断</span></span><br><span class="line">  exti_init(UINIO_KEY_EXTI_LINE, EXTI_INTERRUPT, EXTI_TRIG_BOTH);                  <span class="comment">// 初始化 EXTI 外部中断线</span></span><br><span class="line">  exti_interrupt_enable(UINIO_KEY_EXTI_LINE);                                      <span class="comment">// 使能 EXTI 外部中断</span></span><br><span class="line">  exti_interrupt_flag_clear(UINIO_KEY_EXTI_LINE);                                  <span class="comment">// 清除 EXTI 外部中断标志位</span></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="type">void</span> <span class="title function_">UINIO_KEY_EXTI_IRQ_Handler</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">  <span class="comment">/* 如果中断标志位为 1，那么表示按键被按下 */</span></span><br><span class="line">  <span class="keyword">if</span> (exti_interrupt_flag_get(UINIO_KEY_EXTI_LINE) == SET) &#123;</span><br><span class="line">    <span class="comment">/* 当按键被按下时，执行的任务 */</span></span><br><span class="line">    <span class="keyword">if</span> (gpio_input_bit_get(UINIO_KEY_PORT, UINIO_KEY_PIN) == SET) &#123;</span><br><span class="line">      gpio_bit_toggle(UINIO_LED_PORT, UINIO_LED_PIN);  <span class="comment">// 翻转 LED 电平状态</span></span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;Key Press\n&quot;</span>);                           <span class="comment">// 串口打印 Key Press</span></span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">/* 当按键被松开时，执行的任务 */</span></span><br><span class="line">    <span class="keyword">else</span> &#123;</span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;Key Release\n&quot;</span>);                         <span class="comment">// 串口打印 Key Release</span></span><br><span class="line">    &#125;</span><br><span class="line">    exti_interrupt_flag_clear(UINIO_KEY_EXTI_LINE);    <span class="comment">// 清除 EXTI 外部中断标志位</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="sourcesmain.c-4">Sources/main.c</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><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== main.c ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;main.h&quot;</span></span></span><br><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><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/LED/LED.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/USART/USART.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/EXTI-Key/EXTI-Key.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">/* 配置优先级分组（2 位用于抢占优先级，2 位用于响应优先级） */</span></span><br><span class="line">  nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);</span><br><span class="line"></span><br><span class="line">  UINIO_LED_GPIO_Config();         <span class="comment">// 初始化 LED 对应的 GPIO 引脚资源</span></span><br><span class="line">  UINIO_EXTI_Key_GPIO_Config();    <span class="comment">// 初始化按键所对应 GPIO 引脚的中断配置</span></span><br><span class="line">  UINIO_USART_GPIO_Config(<span class="number">9600U</span>);  <span class="comment">// 初始化 USART 串口，设置波特率为 9600</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span> (<span class="number">1</span>) &#123;&#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="定时器-timer-概览">定时器 TIMER 概览</h1><p><strong>GD32F350RBT6</strong>微控制器的定时器是一个可编程的无符号<strong>计数器</strong>，支持<code>输入捕获</code>与<code>输出比较</code>，可以按照功能特性被划分为六种类型：</p><ol type="1"><li><strong>高级定时器</strong>（<code>TIMER0</code>）；</li><li><strong>通用定时器 L0</strong>（<code>TIMER1</code> 和<code>TIMER2</code>）；</li><li><strong>通用定时器 L2</strong>（<code>TIMER13</code>）；</li><li><strong>通用定时器 L3</strong>（<code>TIMER14</code>）；</li><li><strong>通用定时器 L4</strong>（<code>TIMER15</code> 和<code>TIMER16</code>）；</li><li><strong>基本定时器</strong>（<code>TIMER5</code>）；</li></ol><p>也就是 1 个 <strong>16位高级定时器</strong>（<code>TIMER0</code>），1 个 <strong>32位通用定时器</strong>（<code>TIMER1</code>），5 个 <strong>16位通用定时器</strong>（<code>TIMER2</code>、<code>TIMER13 ~ TIMER16</code>），1个 <strong>16 位基本定时器</strong>（<code>TIMER5</code>）。</p><h2 id="高级定时器-timer0">高级定时器 TIMER0</h2><p><strong>高级定时器（TIMER0）</strong>属于可编程的<strong>四通道定时器</strong>，包含有<strong>16 位无符号计数器</strong>，支持输入捕获与输出比较。可以用于产生PWM信号控制电机（包含有死区时间插入模块）以及进行电源管理，其主要特性如下表所示：</p><table><colgroup><col style="width: 31%"><col style="width: 68%"></colgroup><thead><tr><th style="text-align: left;">高级定时器 TIMER0 特性</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>总通道数</strong></td><td style="text-align: left;"><strong>4 通道</strong></td></tr><tr><td style="text-align: left;"><strong>计数器宽度</strong></td><td style="text-align: left;"><code>TIMER0</code> 是 <strong>16位</strong></td></tr><tr><td style="text-align: left;"><strong>时钟源可选</strong></td><td style="text-align: left;">内部时钟、内部触发、外部输入、外部触发</td></tr><tr><td style="text-align: left;"><strong>多种计数模式</strong></td><td style="text-align: left;">向上计数、向下计数、中央计数</td></tr><tr><td style="text-align: left;"><strong>正交编码器接口</strong></td><td style="text-align: left;">用于追踪运动和分辨旋转方向和位置</td></tr><tr><td style="text-align: left;"><strong>霍尔传感器接口</strong></td><td style="text-align: left;">可以用于控制三相电机</td></tr><tr><td style="text-align: left;"><strong>可编程的预分频器</strong></td><td style="text-align: left;">16 位（运行时可以被改变）</td></tr><tr><td style="text-align: left;"><strong>每个通道可配置</strong></td><td style="text-align: left;">输入捕获模式、输出比较模式、可编程的 PWM模式、单脉冲模式</td></tr><tr><td style="text-align: left;"><strong>可编程的死区时间</strong></td><td style="text-align: left;">支持</td></tr><tr><td style="text-align: left;"><strong>自动重装载功能</strong></td><td style="text-align: left;">支持</td></tr><tr><td style="text-align: left;"><strong>可编程的计数器重复功能</strong></td><td style="text-align: left;">支持</td></tr><tr><td style="text-align: left;"><strong>中止输入功能</strong></td><td style="text-align: left;">支持</td></tr><tr><td style="text-align: left;"><strong>中断输出和 DMA 请求</strong></td><td style="text-align: left;">更新事件、触发事件、比较/捕获事件、换相事件、中止事件</td></tr><tr><td style="text-align: left;"><strong>多个定时器的菊链</strong></td><td style="text-align: left;">使得一个定时器，能够同时启动多个定时器</td></tr><tr><td style="text-align: left;"><strong>定时器的同步</strong></td><td style="text-align: left;">允许被选择的定时器在同一个时钟周期开始计数</td></tr><tr><td style="text-align: left;"><strong>定时器主-从管理</strong></td><td style="text-align: left;">支持</td></tr></tbody></table><p>下面的结构框图提供了<strong>高级定时器（TIMER0）</strong>的内部配置细节：</p><p><img src="/Project/UINIO-MCU-GD32/12-Timer/1.png"></p><h2 id="通用定时器-l0---timer1-timer2">通用定时器 L0 - TIMER1,TIMER2</h2><p><strong>通用定时器 L0（TIMER1,TIMER2）</strong>同样属于可编程的<strong>四通道定时器</strong>，包含有<strong>16 位无符号计数器</strong>，支持输入捕获与输出比较。可以用于产生PWM 信号控制电机以及进行电源管理，其主要特性如下表所示：</p><table><colgroup><col style="width: 34%"><col style="width: 65%"></colgroup><thead><tr><th style="text-align: left;">高级定时器 TIMER1, TIMER2 特性</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>总通道数</strong></td><td style="text-align: left;"><strong>4 通道</strong></td></tr><tr><td style="text-align: left;"><strong>计数器宽度</strong></td><td style="text-align: left;"><code>TIMER2</code> 是 <strong>16位</strong>，<code>TIMER1</code> 是 <strong>32 位</strong></td></tr><tr><td style="text-align: left;"><strong>时钟源可选</strong></td><td style="text-align: left;">内部时钟、内部触发、外部输入、外部触发</td></tr><tr><td style="text-align: left;"><strong>多种计数模式</strong></td><td style="text-align: left;">向上计数、向下计数、中央计数</td></tr><tr><td style="text-align: left;"><strong>正交编码器接口</strong></td><td style="text-align: left;">用于追踪运动和分辨旋转方向和位置</td></tr><tr><td style="text-align: left;"><strong>霍尔传感器接口</strong></td><td style="text-align: left;">可以用于控制三相电机</td></tr><tr><td style="text-align: left;"><strong>可编程的预分频器</strong></td><td style="text-align: left;">16 位（运行时可以被改变）</td></tr><tr><td style="text-align: left;"><strong>每个通道可配置</strong></td><td style="text-align: left;">输入捕获模式、输出比较模式、可编程的 PWM模式、单脉冲模式</td></tr><tr><td style="text-align: left;"><strong>自动重装载功能</strong></td><td style="text-align: left;">支持</td></tr><tr><td style="text-align: left;"><strong>中断输出和 DMA 请求</strong></td><td style="text-align: left;">更新事件、触发事件、比较/捕获事件</td></tr><tr><td style="text-align: left;"><strong>多个定时器的菊链</strong></td><td style="text-align: left;">使得一个定时器，能够同时启动多个定时器</td></tr><tr><td style="text-align: left;"><strong>定时器的同步</strong></td><td style="text-align: left;">允许被选择的定时器在同一个时钟周期开始计数</td></tr><tr><td style="text-align: left;"><strong>定时器主-从管理</strong></td><td style="text-align: left;">支持</td></tr></tbody></table><p>下面的结构框图提供了<strong>通用定时器 L0（TIMER1,TIMER2）</strong>的内部配置细节：</p><p><img src="/Project/UINIO-MCU-GD32/12-Timer/2.png"></p><h2 id="通用定时器-l2---timer13">通用定时器 L2 - TIMER13</h2><p><strong>通用定时器L2（TIMER13）</strong>属于可编程的<strong>单通道定时器</strong>，包含有<strong>16 位无符号计数器</strong>，支持输入捕获与输出比较。可以用于产生PWM 信号控制电机以及进行电源管理，其主要特性如下表所示：</p><table><colgroup><col style="width: 33%"><col style="width: 66%"></colgroup><thead><tr><th style="text-align: left;">高级定时器 TIMER13 特性</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>总通道数</strong></td><td style="text-align: left;"><strong>1 通道</strong></td></tr><tr><td style="text-align: left;"><strong>计数器宽度</strong></td><td style="text-align: left;"><code>TIMER13</code> 是 <strong>16位</strong></td></tr><tr><td style="text-align: left;"><strong>时钟源可选</strong></td><td style="text-align: left;">内部时钟</td></tr><tr><td style="text-align: left;"><strong>计数模式</strong></td><td style="text-align: left;">向上计数</td></tr><tr><td style="text-align: left;"><strong>可编程的预分频器</strong></td><td style="text-align: left;">16 位（运行时可以被改变）</td></tr><tr><td style="text-align: left;"><strong>每个通道可配置</strong></td><td style="text-align: left;">输入捕获模式、输出比较模式、可编程的 PWM模式</td></tr><tr><td style="text-align: left;"><strong>自动重装载功能</strong></td><td style="text-align: left;">支持</td></tr><tr><td style="text-align: left;"><strong>中断输出</strong></td><td style="text-align: left;">更新事件、比较/捕获事件</td></tr></tbody></table><p>下面的结构框图提供了<strong>通用定时器L2（TIMER13）</strong>的内部配置细节：</p><p><img src="/Project/UINIO-MCU-GD32/12-Timer/3.png"></p><h2 id="通用定时器-l3---timer14">通用定时器 L3 - TIMER14</h2><p><strong>通用定时器L3（TIMER14）</strong>属于可编程的<strong>两通道定时器</strong>，包含有<strong>16 位无符号计数器</strong>，支持输入捕获与输出比较。可以用于产生PWM信号控制电机（包含有死区时间插入模块）以及进行电源管理，其主要特性如下表所示：</p><table><colgroup><col style="width: 31%"><col style="width: 68%"></colgroup><thead><tr><th style="text-align: left;">高级定时器 TIMER14 特性</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>总通道数</strong></td><td style="text-align: left;"><strong>2 通道</strong></td></tr><tr><td style="text-align: left;"><strong>计数器宽度</strong></td><td style="text-align: left;"><code>TIMER14</code> 是 <strong>16位</strong></td></tr><tr><td style="text-align: left;"><strong>时钟源可选</strong></td><td style="text-align: left;">内部时钟、内部触发、外部输入</td></tr><tr><td style="text-align: left;"><strong>计数模式</strong></td><td style="text-align: left;">向上计数</td></tr><tr><td style="text-align: left;"><strong>可编程的预分频器</strong></td><td style="text-align: left;">16 位（运行时可以被改变）</td></tr><tr><td style="text-align: left;"><strong>每个通道可配置</strong></td><td style="text-align: left;">输入捕获模式、输出比较模式、可编程的 PWM模式、单脉冲模式</td></tr><tr><td style="text-align: left;"><strong>可编程的死区时间</strong></td><td style="text-align: left;">支持</td></tr><tr><td style="text-align: left;"><strong>自动重装载功能</strong></td><td style="text-align: left;">支持</td></tr><tr><td style="text-align: left;"><strong>可编程的计数器重复功能</strong></td><td style="text-align: left;">支持</td></tr><tr><td style="text-align: left;"><strong>中止输入功能</strong></td><td style="text-align: left;">支持</td></tr><tr><td style="text-align: left;"><strong>中断输出和 DMA 请求</strong></td><td style="text-align: left;">更新事件、比较/捕获事件、换相事件、中止事件</td></tr><tr><td style="text-align: left;"><strong>多个定时器的菊链</strong></td><td style="text-align: left;">使得一个定时器，能够同时启动多个定时器</td></tr><tr><td style="text-align: left;"><strong>定时器的同步</strong></td><td style="text-align: left;">使得一个定时器，能够同时启动多个定时器</td></tr><tr><td style="text-align: left;"><strong>定时器主-从管理</strong></td><td style="text-align: left;">支持</td></tr></tbody></table><p>下面的结构框图提供了<strong>通用定时器L3（TIMER14）</strong>的内部配置细节：</p><p><img src="/Project/UINIO-MCU-GD32/12-Timer/4.png"></p><h2 id="通用定时器-l4---timer15-timer16">通用定时器 L4 - TIMER15,TIMER16</h2><p><strong>通用定时器 L4（TIMER15,TIMER16）</strong>属于可编程的<strong>单通道定时器</strong>，包含有<strong>16 位无符号计数器</strong>，支持输入捕获与输出比较。可以用于产生PWM信号控制电机（包含有死区时间插入模块）以及进行电源管理，其主要特性如下表所示：</p><table><colgroup><col style="width: 35%"><col style="width: 64%"></colgroup><thead><tr><th style="text-align: left;">高级定时器 TIMER15, TIMER16 特性</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>总通道数</strong></td><td style="text-align: left;"><strong>单通道</strong></td></tr><tr><td style="text-align: left;"><strong>计数器宽度</strong></td><td style="text-align: left;"><code>TIMER15</code> 和<code>TIMER16</code> 都是 <strong>16 位</strong></td></tr><tr><td style="text-align: left;"><strong>时钟源可选</strong></td><td style="text-align: left;">内部时钟</td></tr><tr><td style="text-align: left;"><strong>计数模式</strong></td><td style="text-align: left;">向上计数</td></tr><tr><td style="text-align: left;"><strong>可编程的预分频器</strong></td><td style="text-align: left;">16 位（运行时可以被改变）</td></tr><tr><td style="text-align: left;"><strong>每个通道可配置</strong></td><td style="text-align: left;">输入捕获模式、输出比较模式、可编程的 PWM模式、单脉冲模式</td></tr><tr><td style="text-align: left;"><strong>可编程的死区时间</strong></td><td style="text-align: left;">支持</td></tr><tr><td style="text-align: left;"><strong>自动重装载功能</strong></td><td style="text-align: left;">支持</td></tr><tr><td style="text-align: left;"><strong>可编程的计数器重复功能</strong></td><td style="text-align: left;">支持</td></tr><tr><td style="text-align: left;"><strong>中止输入功能</strong></td><td style="text-align: left;">支持</td></tr><tr><td style="text-align: left;"><strong>中断输出和 DMA 请求</strong></td><td style="text-align: left;">更新事件、比较/捕获事件、换相事件、中止事件</td></tr></tbody></table><p>下面的结构框图提供了<strong>通用定时器 L4（TIMER15,TIMER16）</strong>的内部配置细节：</p><p><img src="/Project/UINIO-MCU-GD32/12-Timer/5.png"></p><h2 id="基本定时器---timer5">基本定时器 - TIMER5</h2><p><strong>基本定时器（TIMER5）</strong>包含有 <strong>16位无符号计数器</strong>，支持输入捕获与输出比较。可以用于通用定时器，产生DMA 请求，以及为 DAC 数模转换提供时钟，其主要特性如下表所示：</p><table><thead><tr><th style="text-align: left;">基本定时器 TIMER5 特性</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>计数器宽度</strong></td><td style="text-align: left;"><code>TIMER5</code> 是 <strong>16位</strong></td></tr><tr><td style="text-align: left;"><strong>时钟源可选</strong></td><td style="text-align: left;">内部时钟</td></tr><tr><td style="text-align: left;"><strong>计数模式</strong></td><td style="text-align: left;">向上计数</td></tr><tr><td style="text-align: left;"><strong>可编程的预分频器</strong></td><td style="text-align: left;">16 位（运行时可以被改变）</td></tr><tr><td style="text-align: left;"><strong>自动重装载功能</strong></td><td style="text-align: left;">支持</td></tr><tr><td style="text-align: left;"><strong>中断输出和 DMA 请求</strong></td><td style="text-align: left;">更新事件</td></tr></tbody></table><p>下面的结构框图提供了<strong>基本定时器（TIMER5）</strong>的内部配置细节：</p><p><img src="/Project/UINIO-MCU-GD32/12-Timer/6.png"></p><h1 id="基本定时器-timer5-与中断">基本定时器 TIMER5 与中断</h1><p>本章节内容，将会利用<strong>基本定时器</strong> <code>TIMER5</code>以及其关联的定时器中断，来实现让 LED 每隔 1秒不间断进行闪烁的实验。其中，定时器<strong>时钟</strong>和<strong>运行参数</strong>的配置，是两个比较重要的知识点，需要大家在实验过程当中特别留意。</p><h2 id="定时器时钟配置">定时器时钟配置</h2><p>观察下面定时器相关的<strong>时钟树</strong>，可以发现如果 <strong>APB总线</strong>的时钟<strong>分频系数</strong>为<code>1</code>，那么<strong>定时器时钟频率</strong>就会与 <strong>AHB总线</strong>保持一致。否则，定时器的时钟频率会被设定为 <strong>APB总线</strong>频率的 <strong>2 倍</strong>：</p><p><img src="/Project/UINIO-MCU-GD32/12-Timer/7.png"></p><p>可以看到，<strong>系统时钟</strong> <code>CK_SYS</code> 在经过<strong>AHB 预分频器</strong>之后，可以得到 AHB 总线时钟<code>CK_AHB</code>。而这个 <code>CK_AHB</code> 再经过 <strong>APB1 和APB2 预分频器</strong>之后，就可以得到<strong>定时器时钟</strong><code>CK_TIMERx</code>，具体请参考下面的计算公式：</p><p><span class="math display">\[CK_{TIMERx} = \frac{CK_{AHB}}{APB_{x预分频值} \div 2}\]</span></p><p>由于固件库 <code>system_gd32f3x0.c</code> 源文件的<code>system_clock_config()</code> 函数当中，已经将<strong>APB1</strong> 和 <strong>APB2</strong> 的预分频值设定为<code>2</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/* APB2 = AHB/2 */</span></span><br><span class="line">RCU_CFG0 |= RCU_APB2_CKAHB_DIV2;</span><br><span class="line"><span class="comment">/* APB1 = AHB/2 */</span></span><br><span class="line">RCU_CFG0 |= RCU_APB1_CKAHB_DIV2;</span><br></pre></td></tr></table></figure><p>根据上面的计算公式，就可以知道<strong>定时器时钟</strong><code>CK_TIMERx</code> 与 <strong>AHB 总线时钟</strong><code>CK_AHB</code> 的时钟频率值相等：</p><p><span class="math display">\[CK_{TIMERx} = \frac{CK_{AHB}}{2 \div 2} = CK_{AHB} = 108MHz\]</span></p><h2 id="定时器工作参数配置">定时器工作参数配置</h2><p>官方固件库 <code>gd32f3x0_timer.h</code> 头文件当中定义的结构体变量<code>timer_parameter_struct</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/* constants definitions */</span></span><br><span class="line"><span class="comment">/* TIMER init parameter struct definitions*/</span></span><br><span class="line"><span class="keyword">typedef</span> <span class="class"><span class="keyword">struct</span> &#123;</span></span><br><span class="line">    <span class="type">uint16_t</span> prescaler;         <span class="comment">/*!&lt; prescaler value */</span></span><br><span class="line">    <span class="type">uint16_t</span> alignedmode;       <span class="comment">/*!&lt; aligned mode */</span></span><br><span class="line">    <span class="type">uint16_t</span> counterdirection;  <span class="comment">/*!&lt; counter direction */</span></span><br><span class="line">    <span class="type">uint16_t</span> clockdivision;     <span class="comment">/*!&lt; clock division value */</span></span><br><span class="line">    <span class="type">uint32_t</span> period;            <span class="comment">/*!&lt; period value */</span></span><br><span class="line">    <span class="type">uint8_t</span>  repetitioncounter; <span class="comment">/*!&lt; the counter repetition value */</span></span><br><span class="line">&#125; timer_parameter_struct;</span><br></pre></td></tr></table></figure><p>在下面的列表里，展示了这些参数的具体功能与用途：</p><ul><li><strong>prescaler</strong>：时钟的 16 位 预分频值，取值范围为<code>0 ~ 65535</code>。</li><li><strong>alignedmode</strong>：对齐模式，可供选取的值有<code>TIMER_COUNTER_EDGE</code>、<code>TIMER_COUNTER_CENTER_DOWN</code>、<code>TIMER_COUNTER_CENTER_UP</code>、<code>TIMER_COUNTER_CENTER_BOTH</code>。</li><li><strong>counterdirection</strong>：计数方向，可供选取的值有<code>TIMER_COUNTER_UP</code> 和 <code>TIMER_COUNTER_DOWN</code>。</li><li><strong>period</strong>：周期，取值范围为<code>0 ~ 65535</code>，当计数器达到周期值的时候，计数值将会清零，可以配合计数器时钟频率计算出中断时间。</li><li><strong>clockdivision</strong>：时钟分频因子，可供选取的值有<code>TIMER_CKDIV_DIV1</code>、<code>TIMER_CKDIV_DIV2</code>、<code>TIMER_CKDIV_DIV4</code>，主要用于输入捕获场景。</li><li><strong>repetitioncounter</strong>：重复计数器值（仅限于高级定时器），取值范围为<code>0 ~ 255</code>。</li></ul><h2 id="实验电路的搭建">实验电路的搭建</h2><p>类似于前面 <a href="#通过-gpio-寄存器控制-led">《通过 GPIO 固件库控制LED》</a> 章节的实验电路，这里同样将 <code>4.7K</code> 限流电阻<code>R1</code> 与 LED 发光二极管串联之后，再连接到<strong>UINIO-MCU-GD32F350RBT6</strong> 核心板的 <code>GPIOB8</code>引脚（高电平点亮，低电平熄灭）：</p><p><img src="/Project/UINIO-MCU-GD32/12-Timer/8.png"></p><p>除此之外，还需要再将 <strong>UINIO-MCU-GD32F350RBT6</strong> 核心板的<strong>GPIOA9</strong> 和 <strong>GPIOA10</strong> 引脚，分别连接至<strong>UINIO-USB-UART</strong> 串口调试器的 <code>RXD</code> 和<code>TXD</code> 引脚，这样就可以完成实验电路的搭建。</p><h2 id="完整-keil-µvision-工程代码-6">完整 Keil µVision 工程代码</h2><p>本节内容的实验，主要基于 16 位的<strong>基本定时器</strong><code>TIMER5</code> 来实现 LED 每间隔 1秒进行闪烁的效果，完成该功能大致需要经历下面六个步骤：</p><ol type="1"><li><strong>配置定时器时钟</strong>，由于固件库已经默认<code>CK_TIMERx = CK_AHB = 108MHz</code>，所以本示例缺省该步骤。</li><li><strong>配置并且初始化定时器</strong>，也就是设置<code>timer_parameter_struct</code> 结构体的成员属性，然后调用<code>timer_init()</code> 初始化定时器。</li><li>调用 <code>nvic_irq_enable()</code> 设置定时器中断的优先级。</li><li>调用 <code>timer_interrupt_enable()</code>使能定时器<strong>更新中断</strong>事件。</li><li>调用 <code>timer_enable()</code> 函数使能定时器自身。</li><li>自定义<strong>基本定时器 TIMER5</strong> 相关的中断服务函数<code>TIMER5_DAC_IRQHandler()</code>，该函数名称已在启动文件<code>startup_gd32f3x0.s</code> 进行过声明。</li></ol><blockquote><p><strong>注意</strong>：本节内容所涉及的全部测试代码，已保存在<strong>UINIO-MCU-GD32F350RBT6</strong> 核心板开源项目<code>Examples</code> 目录下的 <strong>8-Timer-LED</strong>工程当中。</p></blockquote><h3 id="driverstimer-led.h">Drivers/Timer-LED.h</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><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== TIMER_LED.h ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> UINIO_TIMER_LED_H</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_TIMER_LED_H</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_TIMER_RCU         RCU_TIMER5             <span class="comment">// 定时器 Timer5 时钟</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_TIMER             TIMER5                 <span class="comment">// 定时器 Timer5</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_TIMER_IRQ         TIMER5_DAC_IRQn        <span class="comment">// 定时器 Timer5 中断</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_TIMER_IRQ_Handler TIMER5_DAC_IRQHandler  <span class="comment">// 定时器 Timer5 中断服务函数</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// #define UINIO_TIMER_RCU         RCU_TIMER2           // 定时器 Timer2 时钟</span></span><br><span class="line"><span class="comment">// #define UINIO_TIMER             TIMER2               // 定时器 Timer2</span></span><br><span class="line"><span class="comment">// #define UINIO_TIMER_IRQ         TIMER2_IRQn          // 定时器 Timer2 中断</span></span><br><span class="line"><span class="comment">// #define UINIO_TIMER_IRQ_Handler TIMER2_IRQHandler    // 定时器 Timer2 中断服务函数</span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_Basic_Timer_Config</span><span class="params">(<span class="type">uint16_t</span> pre, <span class="type">uint16_t</span> per)</span>; <span class="comment">// 基本定时器配置函数</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">/* UINIO_TIMER_LED_H */</span></span></span><br></pre></td></tr></table></figure><h3 id="driverstimer-led.c">Drivers/Timer-LED.c</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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== TIMER_LED.c ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;stdio.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../LED/LED.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Timer-LED/Timer-LED.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/** 基本定时器配置，参数 UINIO_Clock_Prescale 为时钟预分频值，参数 UINIO_Clock_Period 为时钟周期 */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_Basic_Timer_Config</span><span class="params">(<span class="type">uint16_t</span> UINIO_Clock_Prescale, <span class="type">uint16_t</span> UINIO_Clock_Period)</span> &#123;</span><br><span class="line">  rcu_periph_clock_enable(UINIO_TIMER_RCU); <span class="comment">// 使能定时器外设时钟</span></span><br><span class="line">  <span class="comment">/* CK_TIMERx = CK_AHB = 108MHz */</span></span><br><span class="line">  timer_deinit(UINIO_TIMER);                <span class="comment">// 复位定时器外设</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 配置定时器参数 */</span></span><br><span class="line">  timer_parameter_struct TimerParameter;                <span class="comment">// 定义 timer_parameter_struct 定时器参数结构体</span></span><br><span class="line">  TimerParameter.prescaler = UINIO_Clock_Prescale - <span class="number">1</span>;  <span class="comment">// 预分频值，由于该值从 0 开始计数，所以这里需要减去 1</span></span><br><span class="line">  TimerParameter.alignedmode = TIMER_COUNTER_EDGE;      <span class="comment">// 对齐模式，边缘对齐</span></span><br><span class="line">  TimerParameter.counterdirection = TIMER_COUNTER_UP;   <span class="comment">// 计数方向，向上计数</span></span><br><span class="line">  TimerParameter.period = UINIO_Clock_Period - <span class="number">1</span>;       <span class="comment">// 周期，同样由于该值从 0 开始计数，这里同样需要减去 1</span></span><br><span class="line">  TimerParameter.clockdivision = TIMER_CKDIV_DIV1;      <span class="comment">// 时钟分频因子</span></span><br><span class="line">  TimerParameter.repetitioncounter = <span class="number">0</span>;                 <span class="comment">// 重复计数器值，取值范围为 0 ~ 255，配置为 x 就会重复 x+1 次进入中断</span></span><br><span class="line">  timer_init(UINIO_TIMER, &amp;TimerParameter);             <span class="comment">// 初始化定时器</span></span><br><span class="line"></span><br><span class="line">  nvic_irq_enable(UINIO_TIMER_IRQ, <span class="number">3U</span>, <span class="number">3U</span>);             <span class="comment">// 配置定时器中断优先级，抢占优先级 3，子优先级 2</span></span><br><span class="line"></span><br><span class="line">  timer_interrupt_enable(UINIO_TIMER, TIMER_INT_UP);    <span class="comment">// 使能定时器更新中断</span></span><br><span class="line">  timer_enable(UINIO_TIMER);                            <span class="comment">// 使能定时器</span></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="type">void</span> <span class="title function_">UINIO_TIMER_IRQ_Handler</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">  <span class="comment">/* 判断定时器中断标志位 TIMER_INT_FLAG_UP 是否置位 */</span></span><br><span class="line">  <span class="keyword">if</span> (timer_interrupt_flag_get(UINIO_TIMER, TIMER_INT_FLAG_UP) == SET) &#123;</span><br><span class="line">    timer_interrupt_flag_clear(UINIO_TIMER, TIMER_INT_FLAG_UP);  <span class="comment">// 清除定时器更新中断标志位</span></span><br><span class="line">    gpio_bit_toggle(UINIO_LED_Port, UINIO_LED_Pin);              <span class="comment">// 翻转 LED 对应 GPIO 引脚的电平状态</span></span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;UinIO.com\n&quot;</span>);                                       <span class="comment">// 串口打印调试信息 UinIO.com</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="sourcesmain.c-5">Sources/main.c</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><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== main.c ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;main.h&quot;</span></span></span><br><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><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/LED/LED.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/USART/USART.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/Timer-LED/Timer-LED.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">/* 配置优先级分组（2 位用于抢占优先级，2 位用于响应优先级） */</span></span><br><span class="line">  nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2);</span><br><span class="line"></span><br><span class="line">  UINIO_LED_GPIO_Config();         <span class="comment">// 初始化 LED 对应的 GPIO 引脚资源</span></span><br><span class="line">  UINIO_USART_GPIO_Config(<span class="number">9600U</span>);  <span class="comment">// 初始化 USART 串口，设置波特率为 9600</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 频率(10800/108)兆赫兹 * 周期(10000)微秒 = 闪烁间隔为 1 秒 */</span></span><br><span class="line">  UINIO_Basic_Timer_Config(<span class="number">10800</span>, <span class="number">10000</span>);    <span class="comment">// 初始化基本定时器，第 1 个参数为时钟预分频值，第 2 个参数为时钟周期</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span> (<span class="number">1</span>) &#123;&#125;;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="通用定时器-timer1-与-pwm">通用定时器 TIMER1 与 PWM</h1><h2 id="脉冲宽度调制-pwm-简介">脉冲宽度调制 PWM 简介</h2><p><strong>脉冲宽度调制</strong>（<strong>PWM</strong>，Pulse-widthmodulation）是一种通过将电平信号分散为离散形式，从而达到调整<strong>电压</strong>和<strong>频率</strong>，乃至于<strong>平均功率</strong>的目的。</p><p><img src="/Project/UINIO-MCU-GD32/12-Timer/9.png"></p><p>这项技术可以用于动态控制 LED亮度乃至于电机转速，其主要涉及到如下三个重要的参数：</p><ol type="1"><li><strong>频率</strong>（Frequency）：单位时间内周期性事件的重复次数，即PWM 在 1 秒钟之内，脉冲信号完整<strong>周期</strong>的出现次数，其值等于<span class="math inline">\(频率 f = \frac{1}{周期T}\)</span>，单位为<strong>赫兹</strong>。</li><li><strong>周期</strong>（Period）：一个完整信号<strong>周期</strong>所持续的时间，其值等于<span class="math inline">\(周期 T = \frac{1}{频率f}\)</span>，单位为<strong>秒</strong>。</li><li><strong>占空比</strong>（DutyCycle）：在一个完整的脉冲信号<strong>周期</strong>当中，<strong>高电平</strong>所占据的百分比值。</li></ol><h2 id="定时器-timer1-的-pwm-通道">定时器 TIMER1 的 PWM 通道</h2><p><strong>GD32F350RBT6</strong> 微控制器的 <code>TIMER1</code> 是一个<strong>通用定时器</strong>，拥有四路 PWM 通道，其中的每一路通道都对应着1 个 GPIO 引脚（需要进行复用设置）。通过下面的表格，可以发现<code>GPIOA5</code> 引脚的复用功能 <code>AF2</code>，对应的就是<code>TIMER1</code> 定时器的 <code>CH0</code> 通道：</p><p><img src="/Project/UINIO-MCU-GD32/12-Timer/10.png"></p><blockquote><p><strong>注意</strong>：GPIO 的复用功能可以通过固件库函数<code>void gpio_af_set(uint32_t gpio_periph, uint32_t alt_func_num, uint32_t pin)</code>进行设置。</p></blockquote><h2 id="pwm-脉冲频率的计算">PWM 脉冲频率的计算</h2><p>根据下面<strong>通用定时器</strong> <code>TIMER1</code>的结构框图，可以观察到该定时器各个通道时钟信号的来龙去脉。其中带有层叠效果的框图，表示其对应有<strong>影子寄存器</strong>：</p><p><img src="/Project/UINIO-MCU-GD32/12-Timer/11.png"></p><blockquote><p><strong>注意</strong>：<strong>影子寄存器</strong>可以让指令重复使用相同的寄存器编码，但是在不同模式下，这些编码对应的是不同的物理寄存器。</p></blockquote><p>相比于之前基本定时器的实验，本实验需要将定时器配置函数<code>UINIO_PWM_Config()</code> 的时钟分频值修改为<code>108</code>，从而使得分频后的定时器时钟频率等于：</p><p><span class="math display">\[分频后的时钟频率 PSC_{CLK} = \frac{定时器时钟频率 108MHz}{预分频值108} =1MHz\]</span></p><p>再根据下面的公式，就可以计算得到此时 PWM 脉冲宽度调制信号的输出频率为<code>100Hz</code>：</p><p><span class="math display">\[PWM 输出频率 = \frac{分频后的时钟频率 1MHz}{周期值 10000 微秒} = 100Hz\]</span></p><blockquote><p><strong>注意</strong>：该脉冲频率远高于肉眼可以鉴别出的<code>50Hz</code> <strong>临界闪烁频率</strong>，所以不会导致 LED发生明显的闪烁现象，可以呈现出比较完美的呼吸灯效果。</p></blockquote><h2 id="实验电路的搭建-1">实验电路的搭建</h2><p>类似于之前 <a href="#基本定时器-timer5-与中断">《基本定时器 TIMER5与中断》</a> 章节的实验电路，这里同样需要将 <code>4.7K</code> 限流电阻<code>R1</code> 与 LED发光二极管进行串联，有所不同之处在于这里需要将其连接至<strong>UINIO-MCU-GD32F350RBT6</strong> 核心板的 <code>GPIOA5</code>引脚，然后由<strong>通用定时器</strong> <code>TIMER1</code> 的通道<code>0</code> 输出 PWM 脉冲信号：</p><p><img src="/Project/UINIO-MCU-GD32/12-Timer/12.png"></p><p>除此之外，依然需要把 <strong>UINIO-MCU-GD32F350RBT6</strong> 核心板的<strong>GPIOA9</strong> 和 <strong>GPIOA10</strong> 引脚，分别连接至<strong>UINIO-USB-UART</strong> 串口调试器的 <code>RXD</code> 和<code>TXD</code> 引脚，从而能够使用串口上位机软件，查看到当前 LED的亮灭状态调试信息。</p><h2 id="完整-keil-µvision-工程代码-7">完整 Keil µVision 工程代码</h2><p>本实验通过 PWM 输出脉冲波来实现 LED的呼吸灯效果，大致上需要经历如下一系列的配置过程：</p><ol type="1"><li>调用 <code>gpio_af_set()</code> 配置 PWM 功能对应 GPIO引脚的复用功能。</li><li>使用 <code>timer_init()</code> 配置 PWM 定时器参数。</li><li>使用 <code>timer_channel_output_config()</code> 配置 PWM输出通道参数。</li><li>通过 <code>timer_channel_output_pulse_value_config()</code>函数将定时器 <code>TIMER1</code> 通道输出的脉冲值置为<code>0</code>。</li><li>使用 <code>timer_channel_output_mode_config()</code>配置定时器输出通道的比较模式为 PWM 模式 0。</li><li>使用 <code>timer_channel_output_shadow_config()</code>失能定时器输出通道的<strong>比较影子寄存器</strong>。</li><li>调用 <code>timer_auto_reload_shadow_enable()</code>使能定时器<strong>自动重载影子寄存器</strong>。</li><li>调用 <code>timer_enable()</code> 使能 PWM 相关的定时器。</li><li>循环调用 <code>timer_channel_output_pulse_value_config()</code>函数，通过动态设定脉冲值（介于 <code>0 ~ 65535</code> 范围）实现 LED的呼吸灯效果。</li></ol><h3 id="driverspwm-led.h">Drivers/PWM-LED.h</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><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== PWM_LED.h ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> UINIO_PWM_LED_H</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_PWM_LED_H</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_PWM_RCU  RCU_GPIOA   <span class="comment">// 定义 PWM 对应 GPIOA 端口的外设时钟</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_PWM_PORT GPIOA       <span class="comment">// 定义 PWM 对应的 GPIOA 端口</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_PWM_PIN  GPIO_PIN_5  <span class="comment">// 定义 PWM 对应的 GPIO 引脚</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_PWM_AF   GPIO_AF_2   <span class="comment">// 定义 PWM 对应 GPIO 引脚的复用功能 2</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_PWM_TIMER_RCU RCU_TIMER1  <span class="comment">// 定义通用定时器 TIMER1 的外设时钟</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_PWM_TIMER     TIMER1      <span class="comment">// 定义通用定时器 TIMER1 自身</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_PWM_CHANNEL   TIMER_CH_0  <span class="comment">// 定义定时器的通道 0</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_PWM_Config</span><span class="params">(<span class="type">uint16_t</span> UINIO_Clock_Prescale, <span class="type">uint16_t</span> UINIO_Clock_Period)</span>; <span class="comment">// 预定义 PWM 工作参数配置函数</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_PWM_LED_Breathing</span><span class="params">(<span class="type">void</span>)</span>;                                                <span class="comment">// 预定义 PWM 呼吸灯控制函数</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">/* UINIO_PWM_LED_H */</span></span></span><br></pre></td></tr></table></figure><h3 id="driverspwm-led.c">Drivers/PWM-LED.c</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><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><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== PWM_LED.h ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;stdio.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;systick.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../PWM-LED/PWM-LED.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/** 配置 PWM 功能对应的 GPIO 引脚 */</span></span><br><span class="line"><span class="type">static</span> <span class="type">void</span> <span class="title function_">UINIO_PWM_GPIO_Config</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">  rcu_periph_clock_enable(UINIO_PWM_RCU);                                                   <span class="comment">// 使能 PWM 对应 GPIO 引脚的外设时钟</span></span><br><span class="line">  gpio_mode_set(UINIO_PWM_PORT, GPIO_MODE_AF, GPIO_PUPD_NONE, UINIO_PWM_PIN);               <span class="comment">// 配置 GPIO 引脚为悬空的复用功能模式</span></span><br><span class="line">  gpio_output_options_set(UINIO_PWM_PORT, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, UINIO_PWM_PIN); <span class="comment">// 设置 GPIO 引脚的输出模式（推挽输出）与速率（50MHz）</span></span><br><span class="line">  gpio_af_set(UINIO_PWM_PORT, UINIO_PWM_AF, UINIO_PWM_PIN);                                 <span class="comment">// 设置 GPIO 引脚的复用功能</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/** 配置脉冲宽度调制 PWM 的工作参数，参数 UINIO_Clock_Prescale 为时钟预分频值，参数 UINIO_Clock_Period 为时钟周期 */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_PWM_Config</span><span class="params">(<span class="type">uint16_t</span> UINIO_Clock_Prescale, <span class="type">uint16_t</span> UINIO_Clock_Period)</span> &#123;</span><br><span class="line">  UINIO_PWM_GPIO_Config();  <span class="comment">// 调用前面已经定义的 PWM 对应 GPIO 引脚的配置函数</span></span><br><span class="line"></span><br><span class="line">  rcu_periph_clock_enable(UINIO_PWM_TIMER_RCU);  <span class="comment">// 使能定时器 TIMER1 外设时钟</span></span><br><span class="line">  <span class="comment">/* CK_TIMERx = CK_AHB = 108MHz */</span></span><br><span class="line">  timer_deinit(UINIO_PWM_TIMER);                 <span class="comment">// 复位定时器 TIMER1</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 配置 PWM 定时器参数 TimerParameter */</span></span><br><span class="line">  timer_parameter_struct TimerParameter;               <span class="comment">// 定义 timer_parameter_struct 定时器参数结构体</span></span><br><span class="line">  TimerParameter.prescaler = UINIO_Clock_Prescale - <span class="number">1</span>; <span class="comment">// 预分频值，由于该值从 0 开始计数，所以这里需要减去 1</span></span><br><span class="line">  TimerParameter.alignedmode = TIMER_COUNTER_EDGE;     <span class="comment">// 对齐模式，边缘对齐</span></span><br><span class="line">  TimerParameter.counterdirection = TIMER_COUNTER_UP;  <span class="comment">// 计数方向，向上计数</span></span><br><span class="line">  TimerParameter.period = UINIO_Clock_Period - <span class="number">1</span>;      <span class="comment">// 周期，同样由于该值从 0 开始计数，这里同样需要减去 1</span></span><br><span class="line">  TimerParameter.clockdivision = TIMER_CKDIV_DIV1;     <span class="comment">// 时钟分频因子</span></span><br><span class="line">  TimerParameter.repetitioncounter = <span class="number">0</span>;                <span class="comment">// 重复计数器值，取值范围为 0 ~ 255，配置为 x 就会重复 x+1 次进入中断</span></span><br><span class="line">  timer_init(UINIO_PWM_TIMER, &amp;TimerParameter);        <span class="comment">// 初始化 PWM 相关的定时器</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 配置 PWM 输出通道参数 TimerOutChannel */</span></span><br><span class="line">  timer_oc_parameter_struct TimerOutChannel;                                         <span class="comment">// 输出通道配置结构体 timer_oc_parameter_struct</span></span><br><span class="line">  TimerOutChannel.ocpolarity = TIMER_OC_POLARITY_HIGH;                               <span class="comment">// 设置通道输出极性为高电平有效</span></span><br><span class="line">  TimerOutChannel.outputstate = TIMER_CCX_ENABLE;                                    <span class="comment">// 使能通道输出功能</span></span><br><span class="line">  timer_channel_output_config(UINIO_PWM_TIMER, UINIO_PWM_CHANNEL, &amp;TimerOutChannel); <span class="comment">// 开始配置定时器通道的输出功能</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 配置占空比 */</span></span><br><span class="line">  timer_channel_output_pulse_value_config(UINIO_PWM_TIMER, UINIO_PWM_CHANNEL, <span class="number">0</span>);                  <span class="comment">// 配置定时器输出通道的脉冲值</span></span><br><span class="line">  timer_channel_output_mode_config(UINIO_PWM_TIMER, UINIO_PWM_CHANNEL, TIMER_OC_MODE_PWM0);        <span class="comment">// 配置定时器输出通道的比较模式为 PWM 模式 0</span></span><br><span class="line">  timer_channel_output_shadow_config(UINIO_PWM_TIMER, UINIO_PWM_CHANNEL, TIMER_OC_SHADOW_DISABLE); <span class="comment">// 失能定时器输出通道的比较影子寄存器</span></span><br><span class="line"></span><br><span class="line">  timer_auto_reload_shadow_enable(UINIO_PWM_TIMER); <span class="comment">// 使能定时器自动重载影子寄存器</span></span><br><span class="line">  timer_enable(UINIO_PWM_TIMER);                    <span class="comment">// 使能 PWM 相关的定时器</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/** PWM 呼吸灯控制函数 */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_PWM_LED_Breathing</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">  <span class="type">static</span> <span class="type">uint8_t</span> Direct = <span class="number">0</span>; <span class="comment">// 亮暗调节方向</span></span><br><span class="line">  <span class="type">static</span> <span class="type">uint16_t</span> Value = <span class="number">0</span>; <span class="comment">// 脉冲值</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 逐渐变亮 */</span></span><br><span class="line">  <span class="keyword">if</span> (Direct == <span class="number">0</span>) &#123;</span><br><span class="line">    Value += <span class="number">500</span>; <span class="comment">// 该值越大 LED 越亮</span></span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Get brighter...\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (Value &gt; <span class="number">10000</span>) &#123;</span><br><span class="line">      Direct = <span class="number">1</span>; <span class="comment">// 切换至渐暗模式</span></span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;Switch to dark...\n&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line">  <span class="comment">/* 逐渐变暗 */</span></span><br><span class="line">  <span class="keyword">else</span> &#123;</span><br><span class="line">    Value -= <span class="number">500</span>; <span class="comment">// 该值越小 LED 越暗</span></span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;Get darker...\n&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">if</span> (Value &lt;= <span class="number">0</span>) &#123;</span><br><span class="line">      Direct = <span class="number">0</span>; <span class="comment">// 切换至渐亮模式</span></span><br><span class="line">      <span class="built_in">printf</span>(<span class="string">&quot;Switch to bright...\n&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br><span class="line"></span><br><span class="line">  timer_channel_output_pulse_value_config(UINIO_PWM_TIMER, UINIO_PWM_CHANNEL, Value); <span class="comment">// 配置定时器通道输出的脉冲值</span></span><br><span class="line">  delay_1ms(<span class="number">50</span>);                                                                      <span class="comment">// 系统滴答定时器延时 50 毫秒</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="sourcesmain.c-6">Sources/main.c</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><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="comment">/*========== main.c ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;main.h&quot;</span></span></span><br><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><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/LED/LED.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/USART/USART.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/PWM-LED/PWM-LED.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">  systick_config();</span><br><span class="line"></span><br><span class="line">  nvic_priority_group_set(NVIC_PRIGROUP_PRE2_SUB2); <span class="comment">// 优先级分组</span></span><br><span class="line"></span><br><span class="line">  UINIO_USART_GPIO_Config(<span class="number">9600U</span>); <span class="comment">// 初始化 USART 串口，设置波特率为 9600</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 频率(10800/108)兆赫兹 * 周期(10000)微秒 = 亮度调整间隔为 0.01 秒 */</span></span><br><span class="line">  UINIO_PWM_Config(<span class="number">108</span>, <span class="number">10000</span>);   <span class="comment">// PWM 初始化</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span> (<span class="number">1</span>) &#123;</span><br><span class="line">    UINIO_PWM_LED_Breathing(); <span class="comment">// 调用 PWM 呼吸灯控制函数</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="直接存储器存取-dma-与中断">直接存储器存取 DMA 与中断</h1><h2 id="dma-功能简介">DMA 功能简介</h2><p><strong>直接存储器存取</strong>（DMA，Direct MemoryAccess）主要运用在不占用<strong>内核计算资源</strong>的情况下，进行数据的传递（<code>外设 → 存储器</code>、<code>存储器 → 外设</code>、<code>存储器 → 存储器</code>）。<strong>GD32F350RBT6</strong>只拥有一个 DMA 控制器，其拥有 <strong>7</strong>个通道，每个通道都用于处理各个外设的存储器访问请求，这些外设包括有<strong>ADC</strong>、<strong>SPI</strong>、<strong>I2C</strong>、<strong>USART</strong>、<strong>DAC</strong>、<strong>I2S</strong>以及<strong>定时器</strong>。</p><p><img src="/Project/UINIO-MCU-GD32/13-DMA/1.png"></p><p>观察上面的 DMA 功能结构框图，可以发现 DMA控制器主要由如下四个部分组成：</p><ol type="1"><li>通过 AHB 总线<strong>从接口</strong>进行 DMA 配置。</li><li>通过 AHB 总线<strong>主接口</strong>进行数据传输。</li><li>由<strong>仲裁器</strong>（Arbiter）对 DMA请求的优先级进行管理。</li><li>控制存储器或者外设的状态，并且管理计数器。</li></ol><h2 id="实验电路的搭建-2">实验电路的搭建</h2><p>本节内容的实验，需要通过 <strong>USART</strong> 输出 DMA传输过来的数据信息，所以依然要把 <strong>UINIO-MCU-GD32F350RBT6</strong>核心板与另外一款 UINIO 系列开源硬件 <a href="https://gitee.com/uinika/UINIO-USB-UART"><strong>UINIO-USB-UART</strong>串口调试器</a> ，参照下图的线路进行相互连接：</p><p><img src="/Project/UINIO-MCU-GD32/10-USART/2.png"></p><p>也就是把 <strong>UINIO-MCU-GD32F350RBT6</strong> 核心板的<code>GPIOA9</code> 和 <code>GPIOA10</code> 引脚，分别连接至<strong>UINIO-USB-UART</strong> 串口调试器的 <code>RXD</code> 和<code>TXD</code> 引脚，然后将后者的 Type-C 接口通过 USB线缆连接到计算机，进而可以借助 <strong>COMTransmit</strong>等串口调试助手软件，查看到 DMA 传输过来的各种数据和日志信息。</p><h2 id="完整-keil-µvision-工程代码-8">完整 Keil µVision 工程代码</h2><p>当使用 DMA进行数据传输时，会首先从<strong>源地址</strong>读取数据，然后再将读取的数据存储到<strong>目的地址</strong>，使用时通常需要遵循如下步骤：</p><ol type="1"><li>通过 <code>rcu_periph_clock_enable(RCU_DMA)</code> 使能 DMA外设时钟。</li><li>配置 DMA 参数结构体 <code>dma_parameter_struct</code>。</li><li>初始化 DMA 通道 <code>dma_init()</code>。</li><li>调用 <code>dma_circulation_enable/disable()</code> 和<code>dma_memory_to_memory_enable/disable()</code> 配置 DMA相关模式。</li><li>执行 <code>dma_interrupt_enable()</code> 使能 DMA 中断。</li><li>执行 <code>dma_channel_enable()</code> 使能 DMA 通道本身。</li></ol><h3 id="sourcesgd32f3x0_it.c">Sources/gd32f3x0_it.c</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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== gd32f3x0_it.c ==========*/</span></span><br><span class="line"><span class="comment">/* interrupt service routines */</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0_it.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;main.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;systick.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="keyword">extern</span> FlagStatus UINIO_Transfer_Complete;</span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">DMA_Channel1_2_IRQHandler</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">  <span class="comment">/* 判断 DMA 通道传输是否已经完成，参数 DMA_INT_FLAG_FTF 是传输完成中断标志位 */</span></span><br><span class="line">  <span class="keyword">if</span>(dma_interrupt_flag_get(DMA_CH1, DMA_INT_FLAG_FTF)) &#123;</span><br><span class="line">    dma_interrupt_flag_clear(DMA_CH1, DMA_INT_FLAG_G); <span class="comment">// 清除 DMA 通道全局中断标志位状态</span></span><br><span class="line">    UINIO_Transfer_Complete = SET;</span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="sourcesmain.c-7">Sources/main.c</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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== main.c ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/USART/USART.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> GetArrayNumber(arr_nanme)  (uint32_t)(sizeof(arr_nanme) / sizeof(*(arr_nanme)))</span></span><br><span class="line"></span><br><span class="line"><span class="type">uint8_t</span> UINIO_String[] = <span class="string">&quot;UinIO.com : Copy current string from RAM to USART by DMA.\n&quot;</span>; <span class="comment">// 需要通过 DMA 传输给 USART 的字符串</span></span><br><span class="line">__IO FlagStatus UINIO_Transfer_Complete = RESET;                                        <span class="comment">// 固件库中预定义的枚举类型变量，取值为 SET 或者 RESET</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">  UINIO_USART_GPIO_Config(<span class="number">9600U</span>);             <span class="comment">// 调用 USART 串口配置函数</span></span><br><span class="line"></span><br><span class="line">  rcu_periph_clock_enable(RCU_DMA);           <span class="comment">// 使能 DMA 相关的外部时钟</span></span><br><span class="line">  nvic_irq_enable(DMA_Channel1_2_IRQn, <span class="number">0</span>, <span class="number">0</span>); <span class="comment">// 配置 DMA 中断服务程序</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 初始化 DMA 通道 */</span></span><br><span class="line">  dma_deinit(DMA_CH1);</span><br><span class="line">  dma_parameter_struct DMA_Init_Struct;</span><br><span class="line">  DMA_Init_Struct.direction    = DMA_MEMORY_TO_PERIPHERAL;         <span class="comment">// 设置 DMA 通道数据传输方向为【读取存储器写入外设】</span></span><br><span class="line">  DMA_Init_Struct.memory_addr  = (<span class="type">uint32_t</span>)UINIO_String;           <span class="comment">// 设置存储器基地址为字符串首地址</span></span><br><span class="line">  DMA_Init_Struct.memory_inc   = DMA_MEMORY_INCREASE_ENABLE;       <span class="comment">// 配置外设地址生成算法模式为递增</span></span><br><span class="line">  DMA_Init_Struct.memory_width = DMA_MEMORY_WIDTH_8BIT;            <span class="comment">// 存储器数据传输宽度为 8 位（串口每次传送 1 个字节 8 位）</span></span><br><span class="line">  DMA_Init_Struct.number       = GetArrayNumber(UINIO_String);     <span class="comment">// 设置 DMA 通道数据传输量</span></span><br><span class="line">  DMA_Init_Struct.periph_addr  = (<span class="type">uint32_t</span>)(&amp;USART_TDATA(USART0)); <span class="comment">// 设置外设基地址</span></span><br><span class="line">  DMA_Init_Struct.periph_inc   = DMA_PERIPH_INCREASE_DISABLE;      <span class="comment">// 设置外设地址生成算法为固定地址模式</span></span><br><span class="line">  DMA_Init_Struct.periph_width = DMA_PERIPHERAL_WIDTH_8BIT;        <span class="comment">// 外设数据传输宽度为 8 位</span></span><br><span class="line">  DMA_Init_Struct.priority     = DMA_PRIORITY_ULTRA_HIGH;          <span class="comment">// 配置 DMA 传输通道优先级为最高</span></span><br><span class="line">  dma_init(DMA_CH1, &amp;DMA_Init_Struct);                             <span class="comment">// 开始初始化 DMA 通道 1</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 配置 DMA 模式 */</span></span><br><span class="line">  dma_circulation_disable(DMA_CH1);      <span class="comment">// 禁用 DMA 循环模式</span></span><br><span class="line">  dma_memory_to_memory_disable(DMA_CH1); <span class="comment">// 禁用存储器到存储器的 DMA 传输</span></span><br><span class="line"></span><br><span class="line">  usart_dma_transmit_config(USART0, USART_DENT_ENABLE); <span class="comment">// 使能串口 USART0 的 DMA 发送功能</span></span><br><span class="line">  dma_interrupt_enable(DMA_CH1, DMA_INT_FTF);           <span class="comment">// 使能 DMA1 通道传输完成中断</span></span><br><span class="line">  dma_channel_enable(DMA_CH1);                          <span class="comment">// 使能 DMA1 通道本身</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>(RESET == UINIO_Transfer_Complete);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="adc-模数转换器外设">ADC 模数转换器外设</h1><h2 id="adc-外设简介">ADC 外设简介</h2><p><strong>GD32F350RBT6</strong> 微控制器集成有 12位逐次逼近型<strong>模数转换器</strong>（<strong>ADC</strong>，AnalogDigital Converter），可以采集来自 <strong>16</strong>个<strong>外部通道</strong>（即 MCU 引脚）、<strong>2</strong>个<strong>内部通道</strong>，以及<strong>电池电压</strong><code>VBAT</code>通道的模拟信号。采样转换完成之后，转换结果可以按照<strong>最低/最高</strong>有效位的对齐方式，保存在相应的数据寄存器当中。</p><p><img src="/Project/UINIO-MCU-GD32/14-ADC/1.png"></p><blockquote><p><strong>注意</strong>：<strong>逐次逼近型 ADC</strong>通过产生一系列比较电压，逐次与输入的模拟电压信号进行比较，以一次一次逐步接近的方式，将模似信号转换成最接近的数字信号。</p></blockquote><table><colgroup><col style="width: 14%"><col style="width: 22%"><col style="width: 14%"><col style="width: 48%"></colgroup><thead><tr><th style="text-align: left;">ADC 内部输入信号</th><th style="text-align: left;">功能说明</th><th style="text-align: left;">ADC 输入引脚定义</th><th style="text-align: left;">功能说明</th></tr></thead><tbody><tr><td style="text-align: left;"><span class="math inline">\(V_{SENSE}\)</span></td><td style="text-align: left;">内部温度传感器输出电压。</td><td style="text-align: left;"><span class="math inline">\(VDDA\)</span></td><td style="text-align: left;">模拟电源正等于 <span class="math inline">\(V_{DD}\)</span>，<span class="math inline">\(2.6V\le VDDA \le 3.6V\)</span>。</td></tr><tr><td style="text-align: left;"><span class="math inline">\(V_{REFINT}\)</span></td><td style="text-align: left;">内部参考输出电压。</td><td style="text-align: left;"><span class="math inline">\(VSSA\)</span></td><td style="text-align: left;">模拟电源负等于 <span class="math inline">\(V_{SS}\)</span>，通过<strong>磁珠</strong>单点接入<code>GND</code>。</td></tr><tr><td style="text-align: left;"><span class="math inline">\(V_{BAT} /2\)</span></td><td style="text-align: left;">硬件输入电压除以二。</td><td style="text-align: left;"><span class="math inline">\(ADCx_IN[15:0]\)</span></td><td style="text-align: left;">多达 16 路外部通道。</td></tr></tbody></table><blockquote><p><strong>注意</strong>：<strong>UINIO-MCU-GD32F350RBT6</strong>核心板的模拟电源负引脚 <code>VSSA</code>，使用了对于 <code>100Mhz</code>高频杂散信号存在 <code>1KΩ</code>阻抗的<strong>磁珠</strong>进行单点接地；</p></blockquote><h2 id="adc-采样通道与模式">ADC 采样通道与模式</h2><p><strong>GD32F350RBT6</strong> 微控制器上的这总共 <strong>19</strong>条 ADC 采样通道，都支持如下几种运行模式：</p><ul><li><strong>单次转换模式</strong>：每进行 1 次 ADC 转换后，ADC就会自动停止，并将结果保存在 ADC 数据寄存器当中。 <img src="/Project/UINIO-MCU-GD32/14-ADC/2.png"></li><li><strong>扫描模式</strong>：用于对多个输入通道进行依次采集，ADC会根据配置的通道采集顺序，对多个通道依次进行采样转换。 <img src="/Project/UINIO-MCU-GD32/14-ADC/3.png"></li><li><strong>连续转换模式</strong>：当 ADC 完成 1次转换之后，就会启动另外 1次转换，周而复始，直至<code>外部触发</code>或者<code>软件触发</code>停止这个转换过程。<img src="/Project/UINIO-MCU-GD32/14-ADC/4.png"></li><li><strong>间断模式</strong>：用于在<strong>注入通道</strong>（即在规则通道转换时，需要强行插入的通道）和<strong>常规通道</strong>之间进行切换，ADC会优先转换注入通道，完成之后再自动切换到常规通道进行转换。 <img src="/Project/UINIO-MCU-GD32/14-ADC/5.png"></li></ul><p>ADC采样的触发方式主要有<strong>外部触发</strong>和<strong>软件触发</strong>两种：</p><ul><li><strong>外部触发</strong>：在外部输入信号的<code>上升沿</code> 或者<code>下降沿</code>，都可以触发<strong>规则组</strong>或者<strong>注入组</strong>的ADC 转换。</li><li><strong>软件触发</strong>：由软件控制在固定的时间点进行 ADC转换，通常用于采集精度要求较高的场景。</li></ul><h2 id="adc-性能参数">ADC 性能参数</h2><p>使用 ADC 模数转换器外设的时候，需要特别注意下面三个主要性能参数：</p><ol type="1"><li><strong>分辨率</strong>：表示 ADC 转换器的输出精度，单位为<code>bit</code> 位，分辨率越高，采样精度也就越高，但是 ADC所花费的采样转换时间就会越长。</li><li><strong>采样率</strong>：表示 ADC每秒对于模拟信号进行采样的次数，单位为赫兹 <code>Hz</code> 或者<code>样本数量Sample / 秒S</code>。采样率高就表示 ADC能够更快的将模拟信号转换为数字信号，从而更加准确的反映模拟信号的变化。</li><li><strong>采样范围</strong>：是指 ADC可以采集到的模拟电压输入信号范围，通常位于<strong>参考电压</strong><span class="math inline">\(V_{REF}\)</span> 范围之内，即 <span class="math inline">\(0V \le ADC \le V_{REF}\)</span>。</li></ol><h2 id="实验电路的搭建-3">实验电路的搭建</h2><p>本节的实验会将 <strong>UINIO-MCU-GD32F350RBT6</strong> 核心板的<strong>GPIOC1</strong> 作为 ADC 采样引脚，分别去获取<code>TP1</code>（连接至 <code>3V3</code>）和 <code>TP2</code>（连接至<code>GND</code>）两个测试点的电压数据，同时仍然将核心板与另外一款 UINIO系列开源硬件 <a href="https://gitee.com/uinika/UINIO-USB-UART"><strong>UINIO-USB-UART</strong>串口调试器</a> ，参照下面的示意图相互进行连接：</p><p><img src="/Project/UINIO-MCU-GD32/14-ADC/6.png"></p><p>即 <strong>UINIO-MCU-GD32F350RBT6</strong> 核心板的<code>GPIOA9</code> 和 <code>GPIOA10</code> 引脚，分别连接至<strong>UINIO-USB-UART</strong> 串口调试器的 <code>RXD</code> 和<code>TXD</code> 引脚，然后将后者的 Type-C 接口通过 USB线缆连接到计算机，从而借助串口调试助手软件 <strong>COMTransmit</strong>查看 ADC 采集到的数据信息。</p><h2 id="完整-keil-µvision-工程代码-9">完整 Keil µVision 工程代码</h2><p>本实验通过将 <strong>UINIO-MCU-GD32F350RBT6</strong> 核心板的<strong>GPIOC1</strong> 作为 ADC 采样引脚，分别去获取核心板上<code>3V3</code> 和 <code>GND</code> 引脚的电压数据，并且通过 USART串口将这些数据打印出来。实现这个功能，需要遵循如下一系列的步骤去配置 ADC外设：</p><ol type="1"><li>使用 <code>rcu_periph_clock_enable()</code> 使能 GPIO 和 ADC外设时钟。</li><li>通过 <code>rcu_adc_clock_config()</code> 配置 ADC 时钟。</li><li>通过 <code>gpio_mode_set()</code> 配置 GPIO引脚为模拟输入模式。</li><li>配置 ADC 的<strong>特殊功能</strong><code>adc_special_function_config()</code>、<strong>数据对齐方式</strong><code>adc_data_alignment_config()</code>、<strong>分辨率</strong><code>adc_resolution_config()</code>、<strong>通道长度</strong><code>adc_channel_length_config()</code>。</li><li>配置 ADC 通道的触发源<code>adc_external_trigger_source_config()</code>。</li><li>使能 ADC的触发方式是<strong>软件触发</strong>还是<strong>外部触发</strong><code>adc_external/software_trigger_config()</code>。</li><li>调用 <code>adc_enable()</code> 使能 <strong>ADC 外设</strong>以及<code>adc_calibration_enable()</code> 使能<strong>校准功能</strong>。</li><li>配置 ADC <strong>规则通道组</strong>或者<strong>插入通道组</strong><code>adc_regular/inserted_channel_config()</code>。</li><li>使能 ADC <strong>外部触发</strong>或者<strong>软件触发</strong>功能<code>adc_external/software_trigger_enable()</code>。</li><li>持续判断<strong>通道组转换结束标志位</strong><code>ADC_FLAG_EOC</code>，然后再通过<code>adc_regular_data_read()</code> 读取范围为 <code>0 ~ 4095</code> 的ADC 采样数据。</li></ol><p>在上面的配置过程当中，<code>adc_data_alignment_config()</code>函数所配置的<strong>数据对齐方式</strong>是指：</p><ul><li><strong>右对齐模式</strong>：ADC采集到的数据被右对齐到最低位，不足的位数填充<code>0</code>，该模式可以在不损失精度的前提下，获得更好的动态范围。</li><li><strong>左对齐模式</strong>：ADC采集到的数据被左对齐到最高位，不足的位数填充<code>0</code>，虽然该模式可以提高采样的分辨率，但是会降低动态范围。</li></ul><h3 id="driversadc.h">Drivers/ADC.h</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="comment">/*========== ADC.h ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> UINIO_ADC_H</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> UINIO_ADC_H</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_ADC_Config</span><span class="params">(<span class="type">void</span>)</span>;                         <span class="comment">// ADC 外设配置函数</span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> <span class="title function_">UINIO_ADC_Value</span><span class="params">(<span class="type">uint8_t</span> ADC_CHANNEL_x)</span>; <span class="comment">// 获取指定 ADC 通道的采集值</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span> <span class="comment">/* UINIO_ADC_H */</span></span></span><br></pre></td></tr></table></figure><h3 id="driversadc.c">Drivers/ADC.c</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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== ADC.c ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;stdio.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;ADC.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/** ADC 外设配置函数 */</span></span><br><span class="line"><span class="type">void</span> <span class="title function_">UINIO_ADC_Config</span><span class="params">(<span class="type">void</span>)</span> &#123;</span><br><span class="line">  rcu_periph_clock_enable(RCU_GPIOC);        <span class="comment">// 使能 GPIOC 外设时钟</span></span><br><span class="line">  rcu_periph_clock_enable(RCU_ADC);          <span class="comment">// 使能 ADC 外设时钟</span></span><br><span class="line">  rcu_adc_clock_config(RCU_ADCCK_APB2_DIV6); <span class="comment">// 选择 APB 总线频率的 6 分频作为 ADC 的时钟源</span></span><br><span class="line"></span><br><span class="line">  gpio_mode_set(GPIOC, GPIO_MODE_ANALOG, GPIO_PUPD_NONE, GPIO_PIN_1); <span class="comment">// 配置 GPIOC1 为不带上下拉电阻的模拟输入模式</span></span><br><span class="line"></span><br><span class="line">  adc_special_function_config(ADC_SCAN_MODE, ENABLE); <span class="comment">// 使能 ADC 特殊功能的扫描模式</span></span><br><span class="line">  adc_data_alignment_config(ADC_DATAALIGN_RIGHT);     <span class="comment">// 配置 ADC 数据对齐方式为右对齐</span></span><br><span class="line">  adc_resolution_config(ADC_RESOLUTION_12B);          <span class="comment">// 配置 ADC 分辨率为 12 位</span></span><br><span class="line">  adc_channel_length_config(ADC_REGULAR_CHANNEL, <span class="number">1</span>);  <span class="comment">// 配置规则通道组的通道长度为 1</span></span><br><span class="line"></span><br><span class="line">  adc_external_trigger_source_config(ADC_REGULAR_CHANNEL, ADC_EXTTRIG_REGULAR_NONE); <span class="comment">// 配置规则通道组的外部触发源为软件触发（规则组）</span></span><br><span class="line">  adc_external_trigger_config(ADC_REGULAR_CHANNEL, ENABLE);                          <span class="comment">// 使能 ADC 外部触发</span></span><br><span class="line"></span><br><span class="line">  adc_enable();             <span class="comment">// 使能 ADC 外设</span></span><br><span class="line">  adc_calibration_enable(); <span class="comment">// 使能 ADC 校准</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="comment">/** 获取 ADC 的值，参数 ADC_CHANNEL_x 用于指定采集通道 */</span></span><br><span class="line"><span class="type">unsigned</span> <span class="type">int</span> <span class="title function_">UINIO_ADC_Value</span><span class="params">(<span class="type">uint8_t</span>  ADC_CHANNEL_x)</span> &#123;</span><br><span class="line">  adc_regular_channel_config(<span class="number">0U</span>, ADC_CHANNEL_x, ADC_SAMPLETIME_55POINT5); <span class="comment">// 配置 ADC 规则通道组，选择通道 0，并且指定采样时间为 1.5 个周期</span></span><br><span class="line">  adc_software_trigger_enable(ADC_REGULAR_CHANNEL);                       <span class="comment">// 使能 ADC 软件触发功能</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 根据 ADC 状态标志位，等待 ADC 采样完成 */</span></span><br><span class="line">  <span class="keyword">while</span> ( adc_flag_get(ADC_FLAG_EOC) == RESET ) &#123;&#125;</span><br><span class="line"></span><br><span class="line">  <span class="type">unsigned</span> <span class="type">int</span> ADC_Value = adc_regular_data_read(); <span class="comment">// 读 ADC 规则组的采样数据</span></span><br><span class="line">  <span class="keyword">return</span> ADC_Value;                                 <span class="comment">// 返回 ADC 采样数据</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="sourcesmain.c-8">Sources/main.c</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><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/*========== main.c ==========*/</span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;gd32f3x0.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;stdio.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;systick.h&quot;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/ADC/ADC.h&quot;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;../Drivers/USART/USART.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">  systick_config();               <span class="comment">// 初始化系统滴答定时器</span></span><br><span class="line">  UINIO_USART_GPIO_Config(<span class="number">9600U</span>); <span class="comment">// 配置 USART0，并将波特率设置为 9600</span></span><br><span class="line">  UINIO_ADC_Config();             <span class="comment">// 配置 ADC 外设</span></span><br><span class="line"></span><br><span class="line">  <span class="type">uint16_t</span> Voltage = <span class="number">0</span>;           <span class="comment">// ADC 采集到的原始值（0 ~ 4095）</span></span><br><span class="line"></span><br><span class="line">  <span class="keyword">while</span>(<span class="number">1</span>) &#123;</span><br><span class="line">    Voltage = UINIO_ADC_Value(ADC_CHANNEL_11);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* 通过串口打印出实际电压值 */</span></span><br><span class="line">    <span class="built_in">printf</span>(<span class="string">&quot;ADC_Value = %f\n&quot;</span>,(( Voltage / <span class="number">4095.0</span> ) * <span class="number">3.3</span>) ); <span class="comment">// 接入 3.3V 采集的 ADC 值为 4095，接入 GND 采集的 ADC 值为 0</span></span><br><span class="line"></span><br><span class="line">    delay_1ms(<span class="number">1000</span>); <span class="comment">// 延时 1 秒</span></span><br><span class="line">  &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h1 id="i2c-集成电路总线">I2C 集成电路总线</h1><h1 id="spi-串行外设总线">SPI 串行外设总线</h1>]]></content>
    
    
    <summary type="html">&lt;p&gt;早在新冠疫情爆发前的 &lt;strong&gt;2019&lt;/strong&gt; 年，就曾经撰写过一篇关于
&lt;strong&gt;ARM&lt;/strong&gt; 标准库的技术长文 &lt;a href=&quot;http://uinio.com/Embedded/STM32F103/&quot;&gt;&lt;strong&gt;《意法半导体
STM32F103 标准库典型实例》&lt;/strong&gt;&lt;/a&gt;
，文章非常详尽的介绍了各种常见片上外设资源的应用。时至 4
年以后的今天，国产微控制器在工程实践领域已经得到了广泛运用，因而基于&lt;a href=&quot;https://www.gigadevice.com.cn/product/mcu&quot;&gt;&lt;strong&gt;兆易创新&lt;/strong&gt;&lt;/a&gt;
推出的国产 ARM 微控制器，设计和制作了 &lt;a href=&quot;https://github.com/uinika/UINIO-MCU-GD32F350RBT6&quot;&gt;&lt;strong&gt;UINIO-MCU-GD32F350RBT6&lt;/strong&gt;&lt;/a&gt;
这款开源核心板，同时撰写了本篇文章作为配套的资料教程，希冀为国产芯片的商业化普及尽自己一份绵薄之力。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/Project/UINIO-MCU-GD32/logo.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/uinika/UINIO-MCU-GD32F350RBT6&quot;&gt;&lt;strong&gt;UINIO-MCU-GD32F350RBT6&lt;/strong&gt;&lt;/a&gt;
是一款采用 LQFP64 封装的 &lt;strong&gt;GD32F350RBT6&lt;/strong&gt;
微控制器核心板，基于 &lt;strong&gt;ARM Cortex-M4&lt;/strong&gt; 内核架构，主频高达
&lt;code&gt;108MHz&lt;/code&gt;，拥有 &lt;code&gt;128K&lt;/code&gt; 容量 Flash，以及
&lt;code&gt;16K&lt;/code&gt; 的 SRAM。而 &lt;a href=&quot;https://github.com/uinika/UINIO-MCU-GD32F103C&quot;&gt;&lt;strong&gt;UINIO-MCU-GD32F103C&lt;/strong&gt;&lt;/a&gt;
采用 LQFP48 封装的 &lt;strong&gt;GD32F103Cxxx&lt;/strong&gt; 系列微控制器（包括
&lt;code&gt;GD32F103CBT6&lt;/code&gt;、&lt;code&gt;GD32F103C8T6&lt;/code&gt;、&lt;code&gt;GD32F103C6T6&lt;/code&gt;、&lt;code&gt;GD32F103C4T6&lt;/code&gt;），基于
&lt;strong&gt;ARM Cortex-M3&lt;/strong&gt; 内核架构，主频达到
&lt;code&gt;108MHz&lt;/code&gt;，拥有 &lt;code&gt;16K ~ 128K&lt;/code&gt; 容量 Flash，以及
&lt;code&gt;6K ~ 20K&lt;/code&gt; 的 SRAM。&lt;/p&gt;</summary>
    
    
    
    <category term="UINIO 开源项目资料" scheme="http://www.uinio.com/categories/UINIO-%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E8%B5%84%E6%96%99/"/>
    
    
    <category term="MCU" scheme="http://www.uinio.com/tags/MCU/"/>
    
  </entry>
  
  <entry>
    <title>运用 U8G2 与 TFT_eSPI 玩转 UINIO-Monitor 显示屏</title>
    <link href="http://www.uinio.com/Project/UINIO-Monitor/"/>
    <id>http://www.uinio.com/Project/UINIO-Monitor/</id>
    <published>2023-08-31T16:00:00.000Z</published>
    <updated>2025-06-25T14:52:28.332Z</updated>
    
    <content type="html"><![CDATA[<p><a href="https://github.com/uinika/UINIO-Monitor"><strong>UINIO-Monitor</strong></a>同时拼接有 <code>128×64</code> 分辨率 <strong>SSD1315</strong> 驱动的0.96 英寸 OLED 显示屏，<code>160×80</code> 分辨率<strong>ST7735</strong> 驱动的 0.96 英寸 LCD显示屏，<code>240×240</code> 分辨率 <strong>ST7789</strong> 驱动的 1.3英寸 LCD 显示屏。以及采用相同驱动芯片，但是分辨率分别为<code>240×320</code> 与 <code>240×280</code> 的 2.4 英寸以及 1.69 英寸LCD 显示屏。所有屏幕全部板载有 <code>0.5mm</code> 间距的<strong>FPC</strong> 柔性排线连接器，同时还引出 <code>2.54mm</code>间距的直插排针，便于通过杜邦线快速搭建实验电路。</p><p><img src="/Project/UINIO-Monitor/logo.png"></p><p>之前由我设计制作并且开源出来的 <a href="https://github.com/uinika/UINIO-MCU-ESP32C3"><strong>UINIO-MCU-ESP32C3</strong></a>和 <a href="https://github.com/uinika/UINIO-MCU-ESP32S3"><strong>UINIO-MCU-ESP32S3</strong></a>两款核心板，分别基于乐鑫科技的 <strong>ESP32-C3</strong> (RISC-V) 与<strong>ESP32-S3</strong> (Xtensa) 微控制器（更多玩法可以参考之前撰写的<a href="http://uinio.com/Project/Arduino-ESP32/">《基于 UINIO-MCU-ESP32的 Arduino 进阶教程》</a>一文）。而本篇文章就会采用这两款核心板，以及乐鑫官方的<strong>Arduino-ESP32</strong> 板级支持包，结合 <a href="https://github.com/olikraus/u8g2"><strong>U8G2</strong></a> 和 <a href="https://github.com/Bodmer/TFT_eSPI"><strong>TFT_eSPI</strong></a>两款开源显示库，帮助大家快速上手 <strong>UINIO-Monitor</strong> 系列里的5 款显示屏。</p><span id="more"></span><h1 id="英寸-oled-显示屏">0.96 英寸 OLED 显示屏</h1><p><strong>UINIO-Monitor</strong> 系列显示屏幕当中的 0.96 英寸OLED（有机发光二极管，Organic Light-Emitting Diode）显示屏，分辨率为<code>128 × 64</code> 像素，使用 I²C总线进行通信，驱动集成电路采用的是香港<a href="https://www.solomon-systech.com.cn/zh-hans/"><strong>晶门半导体</strong></a>（SolomonSystech）的 <strong>SSD1315</strong>（可以同时兼容<strong>SSD1306</strong>）。</p><p><img src="/Project/UINIO-Monitor/0.96-OLED-1.png"></p><blockquote><p><strong>注意</strong>：如果焊接上丝印为 <code>0x78</code> 的电阻<strong>R20</strong>，就会把 I²C 从设备的地址配置为<code>0x78</code>。相应的，如果焊接上 <code>0x7A</code> 丝印的电阻<strong>R19</strong>，则表示从设备地址为 <code>0x7A</code>。当使用<strong>Arduino-ESP32</strong> 和 <strong>U8G2</strong>库进行通信时，需要焊接上 <strong>R20</strong>，而 <strong>R19</strong>位置留空。</p></blockquote><p>该屏幕模组采用了日本<strong>特瑞仕</strong>（TOREX）的<strong>XC6206P332MR</strong> 低压差线性稳压芯片，可以同时兼容<code>3.3V</code> 与 <code>5V</code>两种工作电压。屏幕在全亮状态下的工作电流约为<code>25mA</code>，而全部熄灭黑屏状态下的待机电流约为<code>1.5mA</code>。正是由于该屏幕工作电流较小，为了防止正负极反接导致稳压芯片损坏，所以串接了一枚型号为<strong>1N5819</strong> 的肖特基二极管（额定正向电流为<code>1A</code>）作为防反接设计，具体电路设计可以参考如下的原理图（鼠标双击可以放大）：</p><p><img src="/Project/UINIO-Monitor/0.96-OLED-2.png"></p><p>开始上手实践之前，需要把 <strong>UINIO-Monitor</strong> 上 0.96 英寸OLED 显示屏的<code>SCK</code>、<code>SDA</code>、<code>GND</code>、<code>VCC</code>引脚，分别与 <strong>UINIO-MCU-ESP32S3</strong> 核心板的<code>GPIO16</code>、<code>GPIO17</code>、<code>5V</code>、<code>GND</code>引脚进行连接，后续 <strong>U8G2</strong>库相关的示例代码都将会沿用这个连接关系：</p><p><img src="/Project/UINIO-Monitor/0.96-OLED-3.png"></p><blockquote><p><strong>注意</strong>：为了文章撰写与阅读的方便直观，<strong>UINIO-Monitor</strong>当中的 0.96 英寸 OLED 显示屏，在后续 <strong>U8G2</strong>库相关章节的内容里全部直接简称为 <strong>UINIO-Monitor</strong>。</p></blockquote><h1 id="u8g2-库开发速成">U8G2 库开发速成</h1><p><a href="https://github.com/olikraus/u8g2"><strong>U8G2</strong></a>是一款运行在嵌入式设备上的 Arduino 单色显示库，可以通过 <strong>ArduinoIDE</strong> 的【库管理器】直接进行安装。<strong>U8G2</strong> 库包含有<code>文字</code>、<code>位图</code>、<code>线/框/圆</code>的绘制方法，并且可以支持多种字体，显示内容时需要使用到微控制器的 RAM作为缓冲区。除此之外，<strong>U8G2</strong> 库还内嵌有一个小巧的<strong>U8x8</strong>库，该库只能输出文本内容，并且只能显示固定像素大小的字体，不过显示内容时无需再使用微控制器的RAM 存储器作为缓冲区。关于两个库的更多介绍，可以参考 <a href="https://github.com/olikraus/u8g2/wiki/u8g2reference"><strong>《U8g2Reference Manual》</strong></a> 和 <a href="https://github.com/olikraus/u8g2/wiki/u8x8reference"><strong>《U8x8Reference Manual》</strong></a> 两份官方文档。</p><p><img src="/Project/UINIO-Monitor/U8G2-0.png"></p><h2 id="u8g2-构造函数">u8g2() 构造函数</h2><p>使用 <strong>U8G2</strong>库的第一步是要根据当前使用的屏幕规格与总线通信方式，选择对应的<code>u8g2()</code> 构造函数，从而实例化出相应的 <code>u8g2</code>对象。本文以 <strong>UINIO-Monitor</strong> 当中 0.96 英寸 OLED显示屏所需要使用到的 <code>U8G2_SSD1306_128X64_NONAME_F_HW_I2C</code>硬件 I²C 类型和 <code>U8G2_SSD1306_128X64_NONAME_F_SW_I2C</code> 软件I²C 类型为例进行讨论：</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 采用 SSD1306 驱动芯片，分辨率为 128*X*64，通信方式为软件 I²C 总线 */</span></span><br><span class="line"><span class="function">U8G2_SSD1306_128X64_NONAME_F_SW_I2C <span class="title">u8g2</span><span class="params">(U8G2_R0, <span class="comment">/* clock=*/</span> <span class="number">16</span>, <span class="comment">/* data=*/</span> <span class="number">17</span>, <span class="comment">/* reset=*/</span> U8X8_PIN_NONE)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="comment">/* 采用 SSD1306 驱动芯片，分辨率为 128*X*64，通信方式为硬件 I²C 总线 */</span></span><br><span class="line"><span class="function">U8G2_SSD1306_128X64_NONAME_F_HW_I2C <span class="title">u8g2</span><span class="params">(U8G2_R0, <span class="comment">/* reset=*/</span> U8X8_PIN_NONE, <span class="comment">/* clock=*/</span> <span class="number">16</span>, <span class="comment">/* data=*/</span> <span class="number">17</span>)</span></span>;</span><br></pre></td></tr></table></figure><blockquote><p><strong>注意</strong>：硬件 I²C 相比于软件 I²C总线的显示刷新频率更高，渲染动画效果的时候更加顺滑。</p></blockquote><p>事实上，<strong>U8G2</strong> 库的 <strong>Arduino C++</strong>构造函数 <code>u8g2()</code>，其返回值类型都遵循着统一的命名规则：</p><table><colgroup><col style="width: 10%"><col style="width: 28%"><col style="width: 14%"><col style="width: 14%"><col style="width: 17%"><col style="width: 14%"></colgroup><thead><tr><th style="text-align: center;">前缀</th><th style="text-align: center;">屏幕驱动芯片型号</th><th style="text-align: center;">分辨率</th><th style="text-align: center;">生产品牌</th><th style="text-align: center;">缓冲区大小</th><th style="text-align: center;">通信方式</th></tr></thead><tbody><tr><td style="text-align: center;"><code>U8G2</code></td><td style="text-align: center;"><code>SSD1306</code></td><td style="text-align: center;"><code>128X64</code></td><td style="text-align: center;"><code>NONAME</code></td><td style="text-align: center;"><code>F</code></td><td style="text-align: center;"><code>HW_I2C</code></td></tr><tr><td style="text-align: center;"><code>U8G2</code></td><td style="text-align: center;"><code>SSD1306</code></td><td style="text-align: center;"><code>128X64</code></td><td style="text-align: center;"><code>NONAME</code></td><td style="text-align: center;"><code>F</code></td><td style="text-align: center;"><code>SW_I2C</code></td></tr></tbody></table><p>接下来的三个表格，分别展示了上述表格当中<strong>缓冲区大小</strong>、<strong>通信方式</strong>、<strong>显示旋转方向</strong>的具体参数信息：</p><table><colgroup><col style="width: 11%"><col style="width: 88%"></colgroup><thead><tr><th style="text-align: center;">缓冲区大小</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: center;"><code>1</code></td><td style="text-align: left;">占用 1 页的微控制器 RAM 作为缓冲区。</td></tr><tr><td style="text-align: center;"><code>2</code></td><td style="text-align: left;">占用 2 页的微控制器 RAM作为缓冲区（可以获得更快的显示刷新速度）。</td></tr><tr><td style="text-align: center;"><code>F</code></td><td style="text-align: left;">在微控制器 RAM当中保存完整的显示帧（推荐在 RAM 存储空间足够大的场景下使用）。</td></tr></tbody></table><table><thead><tr><th style="text-align: left;">显示旋转方向</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>U8G2_R0</code></td><td style="text-align: left;">不旋转，横向显示。</td></tr><tr><td style="text-align: left;"><code>U8G2_R1</code></td><td style="text-align: left;">顺时针 90° 度旋转。</td></tr><tr><td style="text-align: left;"><code>U8G2_R2</code></td><td style="text-align: left;">顺时针 180° 度旋转。</td></tr><tr><td style="text-align: left;"><code>U8G2_R3</code></td><td style="text-align: left;">顺时针 270° 度旋转。</td></tr><tr><td style="text-align: left;"><code>U8G2_MIRROR</code></td><td style="text-align: left;">不旋转，横向显示，但是内容会被镜像。</td></tr></tbody></table><table><thead><tr><th style="text-align: left;">通信方式</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>4W_SW_SPI</code></td><td style="text-align: left;">四线制（<code>Clock\Data\CS\DC</code>）的软件模拟SPI。</td></tr><tr><td style="text-align: left;"><code>4W_HW_SPI</code></td><td style="text-align: left;">四线制（<code>Clock\Data\CS\DC</code>）的硬件SPI。</td></tr><tr><td style="text-align: left;"><code>2ND_4W_HW_SPI</code></td><td style="text-align: left;">第 2 个四线制的硬件 SPI。</td></tr><tr><td style="text-align: left;"><code>3W_SW_SPI</code></td><td style="text-align: left;">三线制（<code>Clock\Data\CS</code>）的软件模拟SPI。</td></tr><tr><td style="text-align: left;"><code>SW_I2C</code></td><td style="text-align: left;">软件模拟的 I²C 总线通信。</td></tr><tr><td style="text-align: left;"><code>HW_I2C</code></td><td style="text-align: left;">硬件 I²C 总线通信。</td></tr><tr><td style="text-align: left;"><code>2ND_HW_I2C</code></td><td style="text-align: left;">第 2 个硬件 I²C 通信总线。</td></tr><tr><td style="text-align: left;"><code>6800</code></td><td style="text-align: left;">采用 <strong>6800 协议</strong>的 8位并行接口。</td></tr><tr><td style="text-align: left;"><code>8080</code></td><td style="text-align: left;">采用 <strong>8080 协议</strong>的 8位并行接口。</td></tr></tbody></table><blockquote><p><strong>注意</strong>：如果当前没有连接重置输入引脚，那么就可以将构造函数中的<code>reset</code> 参数，直接填写为 <code>U8X8_PIN_NONE</code>。</p></blockquote><p>采用 <code>u8g2()</code> 构造函数创建 <code>u8g2</code>类的时候，需要传入一系列的参数，下面表格就展示了这些参数的具体信息：</p><table><colgroup><col style="width: 12%"><col style="width: 25%"><col style="width: 62%"></colgroup><thead><tr><th style="text-align: left;">引脚参数</th><th style="text-align: left;">数据手册名称</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>clock</code></td><td style="text-align: left;"><code>SCL / SCLK ...</code></td><td style="text-align: left;">SPI 或者 I²C 总线的时钟线。</td></tr><tr><td style="text-align: left;"><code>data</code></td><td style="text-align: left;"><code>SDA / MOSI / SDIN ...</code></td><td style="text-align: left;">SPI 或者 I²C 总线的数据线。</td></tr><tr><td style="text-align: left;"><code>d0 ... d7</code></td><td style="text-align: left;"><code>D0 ... D7</code></td><td style="text-align: left;">并行接口的数据线。</td></tr><tr><td style="text-align: left;"><code>cs</code></td><td style="text-align: left;"><code>CS</code></td><td style="text-align: left;">片选信号线。</td></tr><tr><td style="text-align: left;"><code>dc</code></td><td style="text-align: left;"><code>D/C / A0 / RS, ...</code></td><td style="text-align: left;">数据/命令选择线。</td></tr><tr><td style="text-align: left;"><code>enable</code></td><td style="text-align: left;"><code>8080:WR / 6800:E</code></td><td style="text-align: left;">8080 接口的 <code>Write</code>写入线，6800 接口的 <code>Enable</code> 使能线。</td></tr><tr><td style="text-align: left;"><code>reset</code></td><td style="text-align: left;">-</td><td style="text-align: left;">重置信号线。</td></tr></tbody></table><p><strong>U8G2</strong> 库默认使用 <strong>8</strong> 位显示模式（即256 色），如果需要使用 <strong>16</strong> 位显示模式，则必须在<code>u8g2.h</code> 头文件当中添加如下注释：</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> U8G2_16BIT</span></span><br></pre></td></tr></table></figure><blockquote><p><strong>注意</strong>：16 位显示模式下，保存 U8G2像素坐标的数据类型也会从 8 位变换为 16 位。</p></blockquote><p>接下来，就会通过 <strong>Arduino C++</strong> 和<strong>U8G2</strong> 库，结合 <strong>UINIO-MCU-ESP32S3</strong> 和<strong>UINIO-Monitor</strong> 实现一个显示<code>Hello UinIO.com!</code> 字符串的示例:</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;Arduino.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;SPI.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;U8g2lib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* U8G2 构造函数 */</span></span><br><span class="line"><span class="function">U8G2_SSD1306_128X64_NONAME_F_HW_I2C <span class="title">u8g2</span><span class="params">(U8G2_R0, <span class="comment">/* reset=*/</span>U8X8_PIN_NONE, <span class="comment">/* clock=*/</span><span class="number">16</span>, <span class="comment">/* data=*/</span><span class="number">17</span>)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">setup</span><span class="params">(<span class="type">void</span>)</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">begin</span>();  <span class="comment">// 设置与初始化显示</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">loop</span><span class="params">(<span class="type">void</span>)</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.f</span>irstPage();</span><br><span class="line">  <span class="keyword">do</span> &#123;</span><br><span class="line">    u8g<span class="number">2.</span><span class="built_in">setFont</span>(u8g2_font_ncenB10_tr);</span><br><span class="line">    u8g<span class="number">2.</span><span class="built_in">drawStr</span>(<span class="number">0</span>, <span class="number">20</span>, <span class="string">&quot;Hello UinIO.com!&quot;</span>);</span><br><span class="line">  &#125; <span class="keyword">while</span> (u8g<span class="number">2.</span><span class="built_in">nextPage</span>());</span><br><span class="line">  <span class="built_in">delay</span>(<span class="number">1000</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="u8x8-构造函数">u8x8() 构造函数</h2><p><strong>U8G2</strong> 所包含的 <strong>U8x8</strong>库无需占用微控制器的 RAM存储空间，可以用于直接显示一些文本信息。但是需要注意 <code>u8x8()</code>构造函数的参数构成，与 <code>u8g2()</code> 构造函数并不相同：</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function">U8X8_SSD1306_128X64_NONAME_SW_I2C <span class="title">u8x8</span><span class="params">(<span class="comment">/* clock=*/</span><span class="number">16</span>, <span class="comment">/* data=*/</span><span class="number">17</span>, <span class="comment">/* reset=*/</span>U8X8_PIN_NONE)</span></span>;</span><br></pre></td></tr></table></figure><p><strong>U8x8</strong> 库的 <strong>Arduino C++</strong> 构造函数<code>u8x8()</code>，其返回值类型都遵循着如下的命名规则：</p><table><thead><tr><th style="text-align: center;">前缀</th><th style="text-align: center;">屏幕驱动芯片型号</th><th style="text-align: center;">分辨率</th><th style="text-align: center;">生产品牌</th><th style="text-align: center;">通信方式</th></tr></thead><tbody><tr><td style="text-align: center;"><code>U8G2</code></td><td style="text-align: center;"><code>SSD1306</code></td><td style="text-align: center;"><code>128X64</code></td><td style="text-align: center;"><code>NONAME</code></td><td style="text-align: center;"><code>HW_I2C</code></td></tr><tr><td style="text-align: center;">...</td><td style="text-align: center;">... ...</td><td style="text-align: center;">... ...</td><td style="text-align: center;">... ...</td><td style="text-align: center;"><code>SW_I2C</code></td></tr></tbody></table><p>观察可以发现，除了没有缓冲区大小设置相关的参数之外，<code>u8x8()</code>构造函数的返回类型命名方式，与 <strong>U8G2</strong> 库的<code>u8g2()</code> 构造函数基本保持一致。接下来同样可以通过<strong>Arduino C++</strong> 和 <strong>U8x8</strong> 库，基于<strong>UINIO-MCU-ESP32S3</strong> 和 <strong>UINIO-Monitor</strong>实现一个 <code>Hello UinIO.com!</code> 字符串显示的示例：</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;Arduino.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;SPI.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;U8x8lib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* u8x8 构造函数 */</span></span><br><span class="line"><span class="function">U8X8_SSD1306_128X64_NONAME_SW_I2C <span class="title">u8x8</span><span class="params">(<span class="comment">/* clock=*/</span><span class="number">16</span>, <span class="comment">/* data=*/</span><span class="number">17</span>, <span class="comment">/* reset=*/</span>U8X8_PIN_NONE)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">setup</span><span class="params">(<span class="type">void</span>)</span> </span>&#123;</span><br><span class="line">  u8x<span class="number">8.</span><span class="built_in">begin</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">loop</span><span class="params">(<span class="type">void</span>)</span> </span>&#123;</span><br><span class="line">  u8x<span class="number">8.</span><span class="built_in">setFont</span>(u8x8_font_chroma48medium8_r);</span><br><span class="line">  u8x<span class="number">8.</span><span class="built_in">drawString</span>(<span class="number">0</span>, <span class="number">0</span>, <span class="string">&quot;Hello UinIO.com!&quot;</span>);</span><br><span class="line">  <span class="built_in">delay</span>(<span class="number">1000</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="初始化工作">初始化工作</h2><p><code>u8g2</code> 类的 <code>begin()</code> 函数用于简化 Arduino环境下的显示设置步骤，该函数在底层会依次调用<code>initDisplay()</code>、<code>clearDisplay()</code>、<code>setPowerSave()</code>三个函数：</p><figure class="highlight cpp"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">bool</span> <span class="title">begin</span><span class="params">(<span class="type">void</span>)</span></span></span><br></pre></td></tr></table></figure><p><code>begin()</code> 函数还可以用于绑定按键检测事件（最高可以绑定 6个按键），如果没有连接相应的按键，则对应的参数可以设置为<code>U8X8_PIN_NONE</code>：</p><figure class="highlight cpp"><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="function"><span class="type">bool</span> <span class="title">begin</span><span class="params">(</span></span></span><br><span class="line"><span class="params"><span class="function">  <span class="type">uint8_t</span> menu_select_pin,</span></span></span><br><span class="line"><span class="params"><span class="function">  <span class="type">uint8_t</span> menu_next_pin,</span></span></span><br><span class="line"><span class="params"><span class="function">  <span class="type">uint8_t</span> menu_prev_pin,</span></span></span><br><span class="line"><span class="params"><span class="function">  <span class="type">uint8_t</span> menu_up_pin = U8X8_PIN_NONE,</span></span></span><br><span class="line"><span class="params"><span class="function">  <span class="type">uint8_t</span> menu_down_pin = U8X8_PIN_NONE,</span></span></span><br><span class="line"><span class="params"><span class="function">  <span class="type">uint8_t</span> menu_home_pin = U8X8_PIN_NONE</span></span></span><br><span class="line"><span class="params"><span class="function">)</span></span></span><br></pre></td></tr></table></figure><p>除了 <code>begin()</code> 函数之外，<code>u8g2</code>类还提供有如下的屏幕显示初始化函数：</p><table><colgroup><col style="width: 27%"><col style="width: 72%"></colgroup><thead><tr><th style="text-align: left;">API 方法</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>void setBusClock(uint32_t clock_speed);</code></td><td style="text-align: left;">设置总线通信的时钟频率，I²C 总线可以尝试<code>200000</code> 或者 <code>400000</code>，SPI 总线可以尝试<code>1000000</code> 或者 <code>8000000</code>。</td></tr><tr><td style="text-align: left;"><code>void setContrast(uint8_t value)</code></td><td style="text-align: left;">设置显示对比度，取值范围从<code>0 ~ 255</code>。</td></tr></tbody></table><h2 id="字体配置">字体配置</h2><p><strong>U8G2</strong> 库使用的是<a href="https://github.com/olikraus/u8g2/wiki/fntlistall"><strong>点阵字体</strong></a>，使用时需要通过<code>setFont()</code> 函数配置当前所要显示的字体，其中字体名称<code>u8g2_font_字体类型与字符集</code>的最后两个字符定义了字体的<strong>类型</strong>和<strong>字符集</strong>：</p><table><thead><tr><th style="text-align: left;">字体名称</th><th style="text-align: left;">助记词</th><th style="text-align: left;">字体类型</th></tr></thead><tbody><tr><td style="text-align: left;"><code>u8g2_xxx_tx</code></td><td style="text-align: left;">Transparent</td><td style="text-align: left;">具有可变宽度的透明字体。</td></tr><tr><td style="text-align: left;"><code>u8g2_xxx_mx</code></td><td style="text-align: left;">Monospace</td><td style="text-align: left;">等宽字体。</td></tr><tr><td style="text-align: left;"><code>u8g2_xxx_hx</code></td><td style="text-align: left;">Height</td><td style="text-align: left;">具有可变宽度和共同高度的字体。</td></tr><tr><td style="text-align: left;"><code>u8g2_xxx_8x</code></td><td style="text-align: left;">8x8</td><td style="text-align: left;">位于 8x8 盒子当中的等宽字体。</td></tr></tbody></table><table><colgroup><col style="width: 31%"><col style="width: 14%"><col style="width: 53%"></colgroup><thead><tr><th style="text-align: left;">字体名称</th><th style="text-align: left;">助记词</th><th style="text-align: left;">字符集</th></tr></thead><tbody><tr><td style="text-align: left;"><code>u8g2_xxx_xe</code></td><td style="text-align: left;">Extended</td><td style="text-align: left;">包含 Unicode 编码 <code>32 ~ 701</code>的字符。</td></tr><tr><td style="text-align: left;"><code>u8g2_xxx_xf</code></td><td style="text-align: left;">Full</td><td style="text-align: left;">包含 Unicode 编码 <code>32 ~ 255</code>的字符。</td></tr><tr><td style="text-align: left;"><code>u8g2_xxx_xr</code></td><td style="text-align: left;">Restricted</td><td style="text-align: left;">包含 Unicode 编码 <code>32 ~ 127</code>的字符。</td></tr><tr><td style="text-align: left;"><code>u8g2_xxx_xu</code></td><td style="text-align: left;">Uppercase</td><td style="text-align: left;">只包含有数字和大写字母。</td></tr><tr><td style="text-align: left;"><code>u8g2_xxx_xn</code></td><td style="text-align: left;">Numbers</td><td style="text-align: left;">包含日期和时间表达的数值与额外字符。</td></tr><tr><td style="text-align: left;"><code>u8g2_xxx_x_something</code></td><td style="text-align: left;">-</td><td style="text-align: left;">特殊字体。</td></tr></tbody></table><blockquote><p><strong>注意</strong>：<strong>U8G2</strong>库不支持直接设置字体的大小，而是通过选用不同尺寸的字体来完成字体大小的控制。</p></blockquote><p>如果需要通过 U8G2 库显示中文，则必须在 <code>begin()</code>调用之后，<code>print()</code> 调用之前执行下面的方法，从而使能 UTF8编码字符的显示输出，具体说明请参见下表所示：</p><table><colgroup><col style="width: 33%"><col style="width: 66%"></colgroup><thead><tr><th style="text-align: left;">API 方法</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>void enableUTF8Print(void)</code></td><td style="text-align: left;">使能 UTF8 显示支持，从而可以通过<code>u8g2.print()</code> 打印中文;</td></tr><tr><td style="text-align: left;"><code>void disableUTF8Print(void)</code></td><td style="text-align: left;">失能 UTF8 显示支持，默认状态。</td></tr></tbody></table><p>目前 U8G2 库已经包含了中文的<strong>文泉驿字体</strong>，可以同时支持<code>12</code>、<code>13</code>、<code>14</code>、<code>15</code>、<code>16</code>像素大小的字体：</p><ul><li><code>u8g2_font_wqy(12~16)_t_chinese1</code>：只包含 U8G2官方提供的小字符集。</li><li><code>u8g2_font_wqy(12~16)_t_chinese2</code>：只包含 U8G2官方提供的小字符集。</li><li><code>u8g2_font_wqy(12~16)_t_chinese3</code>：只包含 U8G2官方提供的小字符集。</li><li><code>u8g2_font_wqy(12~16)_t_gb2312</code>：包含有完整的 GB2312中文简体字符集。</li><li><code>u8g2_font_wqy(12~16)_t_gb2312a</code>：仅包含 GB2312 的<code>01</code>、<code>02</code> 和 <code>16 ~ 55</code> 以及部分<code>08</code> 区编码，没有包含全角标点符号。</li><li><code>u8g2_font_wqy(12~16)_t_gb2312b</code>：仅包含 GB2312 的<code>1 ~ 55</code> 区编码，其中 <code>10 ~ 15</code> 属于空区，相比于<code>gb2312a</code> 会多出一些额外的符号。</li></ul><blockquote><p><strong>注意</strong>：使用上述字体时，只需要将 <code>(12~16)</code>部分替换为当前所需的像素大小即可。</p></blockquote><p>除此之外，U8G2 库还可以支持 GNU 的 <a href="http://unifoundry.com/unifont/index.html">Unifont</a><strong>点阵黑</strong>中文字体，不过这些字体的美观程度明显逊色于文泉驿字体：</p><ul><li><code>u8g2_font_unifont_t_chinese1</code>：包含 U8G2官方提供的小字符集。</li><li><code>u8g2_font_unifont_t_chinese2</code>：包含 U8G2官方提供的小字符集。</li><li><code>u8g2_font_unifont_t_chinese3</code>：包含 U8G2官方提供的小字符集。</li></ul><p>下面的示例代码，就将会分别使用 <code>u8g2_font_wqy16_t_gb2312</code>和 <code>u8g2_font_wqy13_t_gb2312</code> 两种字体，在<strong>UINIO-Monitor</strong> 上面显示 <code>"Hello UinIO.com!"</code>和 <code>"你好，电子技术博客！"</code> 两组字符串内容：</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;Arduino.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;U8g2lib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function">U8G2_SSD1306_128X64_NONAME_F_HW_I2C <span class="title">u8g2</span><span class="params">(U8G2_R0, <span class="comment">/* reset=*/</span>U8X8_PIN_NONE, <span class="comment">/* clock=*/</span><span class="number">16</span>, <span class="comment">/* data=*/</span><span class="number">17</span>)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">setup</span><span class="params">(<span class="type">void</span>)</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">begin</span>();</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">enableUTF8Print</span>();    <span class="comment">// 使能 UTF8 显示支持</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">loop</span><span class="params">(<span class="type">void</span>)</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">setFontDirection</span>(<span class="number">0</span>);  <span class="comment">// 从左至右进行显示</span></span><br><span class="line">  u8g<span class="number">2.f</span>irstPage();</span><br><span class="line">  <span class="keyword">do</span> &#123;</span><br><span class="line">    <span class="comment">/* 使用高度为 16 像素，包含完整 GB2312 字符集的文泉驿字体 */</span></span><br><span class="line">    u8g<span class="number">2.</span><span class="built_in">setFont</span>(u8g2_font_wqy16_t_gb2312);</span><br><span class="line">    u8g<span class="number">2.</span><span class="built_in">setCursor</span>(<span class="number">0</span>, <span class="number">16</span>);</span><br><span class="line">    u8g<span class="number">2.</span><span class="built_in">print</span>(<span class="string">&quot;Hello UinIO.com!&quot;</span>);</span><br><span class="line"></span><br><span class="line">    <span class="comment">/* 使用高度为 13 像素，包含完整 GB2312 字符集的文泉驿字体 */</span></span><br><span class="line">    u8g<span class="number">2.</span><span class="built_in">setFont</span>(u8g2_font_wqy13_t_gb2312);</span><br><span class="line">    u8g<span class="number">2.</span><span class="built_in">setCursor</span>(<span class="number">0</span>, <span class="number">36</span>);</span><br><span class="line">    u8g<span class="number">2.</span><span class="built_in">print</span>(<span class="string">&quot;你好，电子技术博客！&quot;</span>);</span><br><span class="line">  &#125; <span class="keyword">while</span> (u8g<span class="number">2.</span><span class="built_in">nextPage</span>());</span><br><span class="line">  <span class="built_in">delay</span>(<span class="number">1000</span>);</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>除了上面介绍的方法之外，<strong>U8G2</strong>库还额外提供有如下几个字体显示相关的工具函数：</p><table><colgroup><col style="width: 32%"><col style="width: 67%"></colgroup><thead><tr><th style="text-align: left;">API 方法</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>u8g2_uint_t getMaxCharHeight(void)</code></td><td style="text-align: left;">返回指定点阵字体里，最大的字体<strong>高度</strong>。</td></tr><tr><td style="text-align: left;"><code>u8g2_uint_t getMaxCharWidth(void)</code></td><td style="text-align: left;">返回指定点阵字体里，最大的字体<strong>宽度</strong>。</td></tr><tr><td style="text-align: left;"><code>void setDrawColor(uint8_t color)</code></td><td style="text-align: left;">参数 <code>color</code> 为 <code>0</code>表示字体不亮背景亮，为 <code>1</code> 表示背景不亮字体亮（默认）。</td></tr></tbody></table><h2 id="显示坐标系统">显示坐标系统</h2><p>显示坐标系统是 <strong>U8G2</strong>库当中比较重要的概念，运用显示相关的函数时，需要特别关注其显示起始的坐标。当使用<code>u8g2</code> 类的 <code>print()</code> 函数显示内容时，需要先运用<code>setCursor()</code> 函数设置显示内容在 <code>x</code> 轴与<code>y</code> 轴的起始像素坐标位置：</p><table><colgroup><col style="width: 47%"><col style="width: 52%"></colgroup><thead><tr><th style="text-align: left;">API 方法</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>void setCursor(u8g2_uint_t x, u8g2_uint_t y)</code></td><td style="text-align: left;">设置显示内容的起始像素坐标位置。</td></tr><tr><td style="text-align: left;"><code>void home(void)</code></td><td style="text-align: left;">将光标放置到屏幕的左上角。</td></tr><tr><td style="text-align: left;"><code>void clear(void)</code></td><td style="text-align: left;">清除屏幕和缓冲区上的内容，并且将光标放置到左上角。</td></tr></tbody></table><p><strong>U8G2</strong> 库将屏幕的左上角作为<strong>坐标原点</strong><code>(0, 0)</code>，显示内容将会沿着起始坐标位置分别<strong>向上</strong>和<strong>向右</strong>进行输出，例如下图左侧的代码分别将显示的起始坐标设置为<code>x = 0</code> 与<code>y = 15</code>，最终渲染显示出来的结果如下面右图所示：</p><p><img src="/Project/UINIO-Monitor/U8G2-1.png"></p><h2 id="屏幕刷新方法">屏幕刷新方法</h2><p><strong>U8G2</strong> 库提供有 <code>clearBuffer()</code> 和<code>sendBuffer()</code> 这组屏幕显示刷新的方法（刷新速度比较快，但是RAM 空间占用较大）：</p><table><colgroup><col style="width: 31%"><col style="width: 68%"></colgroup><thead><tr><th style="text-align: left;">API 方法</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>void clearBuffer(void)</code></td><td style="text-align: left;">清除微控制器 RAM帧缓冲区当中的所有内容。</td></tr><tr><td style="text-align: left;"><code>void sendBuffer(void)</code></td><td style="text-align: left;">将微控制器 RAM帧缓冲区当中的内容发送至屏幕进行显示。</td></tr></tbody></table><p>显示缓冲区操作相关的代码，都必须放置到 <code>clearBuffer()</code> 和<code>sendBuffer()</code> 函数之间的区域：</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="type">void</span> <span class="title">loop</span><span class="params">(<span class="type">void</span>)</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">clearBuffer</span>();</span><br><span class="line">  <span class="comment">/* ................................................ */</span></span><br><span class="line">  <span class="comment">/* 显示缓冲区相关的操作代码都放置到这里 */</span></span><br><span class="line">  <span class="comment">/* ................................................ */</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">sendBuffer</span>();</span><br><span class="line">  <span class="built_in">delay</span>(<span class="number">1000</span>);</span><br></pre></td></tr></table></figure><p>除此之外，<strong>U8G2</strong> 库还提供了 <code>firstPage()</code>与 <code>nextPage()</code> 来刷新屏幕显示内容（消耗的 RAM空间相对较小）：</p><table><colgroup><col style="width: 28%"><col style="width: 71%"></colgroup><thead><tr><th style="text-align: left;">API 方法</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>void firstPage(void)</code></td><td style="text-align: left;">该命令是内容渲染循环的一部分，需要与<code>nextPage()</code> 配合使用。</td></tr><tr><td style="text-align: left;"><code>uint8_t nextPage(void)</code></td><td style="text-align: left;">该命令是内容渲染循环的一部分，需要与<code>firstPage()</code> 配合使用。</td></tr></tbody></table><p>使用时即可以采用 <code>do...while()</code> 循环的方式来组合调用<code>firstPage()</code> 与 <code>nextPage()</code> 函数：</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line">u8g<span class="number">2.f</span>irstPage();</span><br><span class="line"><span class="keyword">do</span> &#123;</span><br><span class="line">  <span class="comment">/* ....................................................... */</span></span><br><span class="line">  <span class="comment">/* 所有显示内容的代码，都必须出现在该循环体内 */</span></span><br><span class="line">  <span class="comment">/* ....................................................... */</span></span><br><span class="line">&#125; <span class="keyword">while</span> (u8g<span class="number">2.</span><span class="built_in">nextPage</span>());</span><br></pre></td></tr></table></figure><p>也可以把 <code>firstPage()</code> 放置到 Arduino 草图代码的<code>setup()</code> 函数当中，而 <code>nextPage()</code> 函数放置到<code>loop()</code> 循环的内部：</p><figure class="highlight cpp"><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="function"><span class="type">void</span> <span class="title">setup</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.f</span>irstPage();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">loop</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  <span class="comment">/* ....................................................... */</span></span><br><span class="line">  <span class="comment">/* 显示内容到屏幕的相关代码都必须出现在这里 */</span></span><br><span class="line">  <span class="comment">/* ....................................................... */</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">nextPage</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="文本输出函数">文本输出函数</h2><p>除了之前示例代码当中使用过的 <code>print()</code> 和<code>drawStr()</code> 之外，<strong>U8G2</strong>库还提供有如下一系列可以用于显示内容输出的方法：</p><table><colgroup><col style="width: 35%"><col style="width: 64%"></colgroup><thead><tr><th style="text-align: left;">API 方法</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>u8g2_uint_t drawStr(u8g2_uint_t x, u8g2_uint_t y, const char *s)</code></td><td style="text-align: left;">在指定的坐标位置绘制字符串（不能绘制编码大于或等于256 的字符），使用前必须指定字体。</td></tr><tr><td style="text-align: left;"><code>u8g2_uint_t drawStrX2(u8g2_uint_t x, u8g2_uint_t y, const char *s)</code></td><td style="text-align: left;">功能同上，只是绘制的字体大小加倍。</td></tr><tr><td style="text-align: left;"><code>u8g2_uint_t drawUTF8(u8g2_uint_t x, u8g2_uint_t y, const char *s)</code></td><td style="text-align: left;">绘制一个编码为 UTF-8的字符串（中文），该函数能够绘制编码值大于 <code>127</code>的字符。</td></tr><tr><td style="text-align: left;"><code>u8g2_uint_t drawUTF8X2(u8g2_uint_t x, u8g2_uint_t y, const char *s)</code></td><td style="text-align: left;">功能同上，只是绘制的字体大小加倍。</td></tr><tr><td style="text-align: left;"><code>u8g2_uint_t drawGlyph(u8g2_uint_t x, u8g2_uint_t y, uint16_t encoding)</code></td><td style="text-align: left;">在指定的坐标位置绘制图像字符，需要配合特殊的图像字体一起使用。</td></tr><tr><td style="text-align: left;"><code>u8g2_uint_t drawGlyphX2(u8g2_uint_t x, u8g2_uint_t y, uint16_t encoding)</code></td><td style="text-align: left;">功能同上，只是绘制的字体大小加倍。</td></tr><tr><td style="text-align: left;"><code>void print(...)</code></td><td style="text-align: left;">向当前的光标位置（通过<code>setCursor()</code> 设置）写入指定字体（通过 <code>setFont()</code>设置）的文本（需要调用 <code>enableUTF8Print()</code> 使能 UTF-8编码）。</td></tr></tbody></table><p>接下来的示例代码，就会分别采用上面表格当中介绍的各种工具函数，测试输出各种显示内容：</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;Arduino.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;U8g2lib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function">U8G2_SSD1306_128X64_NONAME_F_HW_I2C <span class="title">u8g2</span><span class="params">(U8G2_R0, <span class="comment">/* reset=*/</span> U8X8_PIN_NONE, <span class="comment">/* clock=*/</span> <span class="number">16</span>, <span class="comment">/* data=*/</span> <span class="number">17</span>)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">setup</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  Serial.<span class="built_in">begin</span>(<span class="number">115200</span>);</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">setBusClock</span>(<span class="number">800000</span>);  <span class="comment">// 设置 I²C 总线时钟频率</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">begin</span>();              <span class="comment">// 初始化显示相关的一系列设置</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">enableUTF8Print</span>();    <span class="comment">// 使能 UTF8 编码支持</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">loop</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  <span class="type">static</span> <span class="type">unsigned</span> <span class="type">int</span> start = <span class="built_in">millis</span>(); <span class="comment">// 代码开始执行时候的毫秒数</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">clearBuffer</span>();</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 设置一个英文字体，并且调用 drawStr() 函数显示英文 */</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">setFont</span>(u8g2_font_adventurer_tf);</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">drawStr</span>(<span class="number">0</span>, <span class="number">13</span>, <span class="string">&quot;Hello UinIO.com!&quot;</span>);</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 设置一个中文字体，并且调用 print() 函数显示中文 */</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">setFont</span>(u8g2_font_wqy13_t_gb2312b);</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">setCursor</span>(<span class="number">0</span>, <span class="number">30</span>);</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">print</span>(<span class="string">&quot;你好，电子技术博客！&quot;</span>);</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 调用 drawUTF8() 绘制 UTF8 编码的雪人字符 */</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">setFont</span>(u8g2_font_unifont_t_symbols);</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">drawUTF8</span>(<span class="number">0</span>, <span class="number">55</span>, <span class="string">&quot;Snowman:☃&quot;</span>);</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 调用 drawGlyph() 绘制太阳图标 */</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">setFont</span>(<span class="type">u8g2_font_open_iconic_weather_2x_t</span>);</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">drawGlyph</span>(<span class="number">100</span>, <span class="number">57</span>, <span class="number">0x0045</span>);</span><br><span class="line"></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">sendBuffer</span>();</span><br><span class="line">  <span class="type">static</span> <span class="type">unsigned</span> <span class="type">int</span> end = <span class="built_in">millis</span>(); <span class="comment">// 代码结束执行时候的毫秒数</span></span><br><span class="line">  Serial.<span class="built_in">println</span>(end - start);        <span class="comment">// 向串口打印上述代码执行所花费的毫秒数</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="绘制位图">绘制位图</h2><p><strong>XBM</strong>（X-Bitmap）是一种通用的图像文件格式，可以通过一个16 进制数组来表示二进制图像。<strong>U8G2</strong> 库提供的<code>drawXBM()</code>函数，可以直接用来绘制单色位图（图片在使用之前需要进行<strong>单值化</strong>处理和<strong>取模</strong>）：</p><table><colgroup><col style="width: 42%"><col style="width: 57%"></colgroup><thead><tr><th style="text-align: left;">API 方法</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>void drawXBM(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h, const uint8_t *bitmap)</code></td><td style="text-align: left;">绘制 XBM 格式的位图，参数 <code>x</code>和 <code>y</code> 表示位图的左上角，而 <code>w</code> 与 <code>h</code>表示位图的宽高，参数 <code>bitmap</code>表示取模之后得到的单色位图数组。</td></tr></tbody></table><blockquote><p><strong>注意</strong>：通常会将 <code>bitmap</code> 数组变量定义为<code>PROGMEM</code> 类型，表示将其存储在 Flash存储器当中，便于保存一些较大的位图数据，并且节省微控制器 RAM的存储空间。</p></blockquote><h3 id="位图取模">位图取模</h3><p><code>drawXBM()</code> 中的单色位图数组参数<code>bitmap</code>，可以通过取模工具软件 <strong>PCtoLCD2002</strong>获取，具体操作步骤如下面列表所示：</p><ol type="1"><li><strong>调整分辨率</strong>：将图片转换为适配 OLED 屏幕的<code>128*64</code> 分辨率。</li><li><strong>转换单色位图</strong>：再将转换分辨率之后的图片处理为<code>.bmp</code> 单色位图格式。</li><li><strong>生成 XBM 数组</strong>：使用 <strong>PCtoLCD2002</strong>工具软件对该单色位图进行取模，得到 XBM 数组。</li><li><strong>U8G2 绘制位图</strong>：调用 <code>u8g2</code> 类的<code>drawXBM()</code> 函数显示位图。</li></ol><blockquote><p><strong>注意</strong>：可以采用更为方便的在线工具 <a href="https://arduino.me/a/image-to-bitmap-array">image-to-bitmap-array</a>进行取模操作。</p></blockquote><p>首先使用 <strong>Windows</strong>操作系统自带的画图工具打开目标图片，然后点击顶部工具栏的【重新调整大小】，在弹出的对话框中选择【像素】，再将水平和垂直高度分别设置为<code>64</code> 个像素：</p><p><img src="/Project/UINIO-Monitor/U8G2-Bitmap-1.png"></p><p>完成位图尺寸的调整之后，鼠标依次点击 <strong>Windows</strong>画图工具顶部菜单栏的【文件 → 另存为 → BMP 图片】：</p><p><img src="/Project/UINIO-Monitor/U8G2-Bitmap-2.png"></p><p>在接下来弹出的【保存为】对话框当中，选择保存类型为【单色位图】的<code>.bmp</code> 文件：</p><p><img src="/Project/UINIO-Monitor/U8G2-Bitmap-3.png"></p><p>接着打开 <strong>PCtoLCD2002</strong>取模软件，点击顶部工具栏上的【字模生成和液晶面板选项】按钮，在弹出的【字模选项】对话框当中进行如下设置：</p><p><img src="/Project/UINIO-Monitor/U8G2-Bitmap-4.png"></p><p>最后，鼠标再次点击顶部工具栏上的【打开一个 BMP图像】按钮，将刚才得到的 <code>.bmp</code>单色位图文件导入，再点击【生成字模】按钮，就会在界面的底部区域得到<strong>U8G2</strong> 库绘图所需的 XBM 数组：</p><p><img src="/Project/UINIO-Monitor/U8G2-Bitmap-5.png"></p><p>把这里得到的位图数组赋值给下面示例代码的 <code>Hank</code>变量，然后调用 <code>drawXBM()</code> 函数就可以进行位图的显示：</p><figure class="highlight cpp"><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><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;Arduino.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;U8g2lib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function">U8G2_SSD1306_128X64_NONAME_F_HW_I2C <span class="title">u8g2</span><span class="params">(U8G2_R0, <span class="comment">/* reset=*/</span>U8X8_PIN_NONE, <span class="comment">/* clock=*/</span><span class="number">16</span>, <span class="comment">/* data=*/</span><span class="number">17</span>)</span></span>;</span><br><span class="line"></span><br><span class="line">PROGMEM <span class="type">const</span> <span class="type">uint8_t</span> Hank[] = &#123;</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x1F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xFE</span>, <span class="number">0xFF</span>, <span class="number">0x03</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x80</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x0F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x1F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF8</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x3F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xFC</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x7F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x80</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x01</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x03</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x07</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x0F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF0</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x1F</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xFC</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x1F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xFE</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x1F</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xFC</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x1F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF8</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x3F</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xF8</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x3F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xFC</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x3F</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xFC</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x3F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xFC</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x3F</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xFC</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x3F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xFC</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFE</span>, <span class="number">0x3F</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xFC</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x3F</span>, <span class="number">0xFC</span>, <span class="number">0x3F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xFC</span>, <span class="number">0xBF</span>, <span class="number">0xFF</span>, <span class="number">0x07</span>, <span class="number">0xFC</span>, <span class="number">0x3F</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xFC</span>, <span class="number">0x0F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF8</span>, <span class="number">0x1F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xFC</span>, <span class="number">0x03</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF0</span>, <span class="number">0x1F</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xF8</span>, <span class="number">0x03</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0x1F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF0</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x1F</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xF0</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x80</span>, <span class="number">0x0F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF0</span>, <span class="number">0xE0</span>, <span class="number">0x03</span>, <span class="number">0xC0</span>, <span class="number">0x87</span>, <span class="number">0x0F</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xF0</span>, <span class="number">0x00</span>, <span class="number">0x06</span>, <span class="number">0x60</span>, <span class="number">0x80</span>, <span class="number">0x0F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF8</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x0F</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x88</span>, <span class="number">0x3C</span>, <span class="number">0x1F</span>, <span class="number">0xF8</span>, <span class="number">0x3C</span>, <span class="number">0x13</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x8C</span>, <span class="number">0xFB</span>, <span class="number">0xA7</span>, <span class="number">0xE5</span>, <span class="number">0xDF</span>, <span class="number">0x31</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x84</span>, <span class="number">0xCA</span>, <span class="number">0x21</span>, <span class="number">0x84</span>, <span class="number">0xD3</span>, <span class="number">0x21</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x84</span>, <span class="number">0x02</span>, <span class="number">0x20</span>, <span class="number">0x04</span>, <span class="number">0xC0</span>, <span class="number">0x21</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x84</span>, <span class="number">0x02</span>, <span class="number">0x90</span>, <span class="number">0x08</span>, <span class="number">0x80</span>, <span class="number">0x21</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x84</span>, <span class="number">0xFD</span>, <span class="number">0x8F</span>, <span class="number">0xF0</span>, <span class="number">0x9F</span>, <span class="number">0x31</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x88</span>, <span class="number">0x01</span>, <span class="number">0x80</span>, <span class="number">0x00</span>, <span class="number">0x80</span>, <span class="number">0x10</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x18</span>, <span class="number">0x01</span>, <span class="number">0x40</span>, <span class="number">0x00</span>, <span class="number">0x80</span>, <span class="number">0x18</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0x01</span>, <span class="number">0x80</span>, <span class="number">0x00</span>, <span class="number">0x80</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x03</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x02</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x40</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x06</span>, <span class="number">0x03</span>, <span class="number">0xC0</span>, <span class="number">0x60</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x0C</span>, <span class="number">0xFC</span>, <span class="number">0x3F</span>, <span class="number">0x30</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x18</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x18</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x30</span>, <span class="number">0xC0</span>, <span class="number">0x03</span>, <span class="number">0x0C</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x60</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x06</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x80</span>, <span class="number">0x01</span>, <span class="number">0x80</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x0F</span>, <span class="number">0x78</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x80</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0xF7</span>, <span class="number">0xEF</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x8F</span>, <span class="number">0xF1</span>, <span class="number">0x03</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0xDF</span>, <span class="number">0xF9</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF0</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF0</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x0F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF0</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x0F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF8</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x0F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF8</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x1F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF8</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x1F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xEC</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x17</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">setup</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">setBusClock</span>(<span class="number">800000</span>);  <span class="comment">// 设置 I²C 总线时钟频率</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">begin</span>();              <span class="comment">// 初始化显示相关的一系列设置</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">enableUTF8Print</span>();    <span class="comment">// 使能 UTF8 编码支持</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">loop</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">clearBuffer</span>();</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">drawXBM</span>(<span class="number">32</span>, <span class="number">0</span>, <span class="number">64</span>, <span class="number">64</span>, Hank); <span class="comment">// 调用 drawXBM() 函数绘制位图</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">sendBuffer</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>将上述代码下载到 <strong>UINIO-MCU-ESP32S3</strong>核心板执行之后，显示到 <strong>UINIO-Monitor</strong> 的 OLED屏幕内容如下面所示：</p><p><img src="/Project/UINIO-Monitor/U8G2-Bitmap-6.png"></p><h3 id="汉字取模">汉字取模</h3><p>除了支持把位图转换为 XBM 数组之外，<strong>PCtoLCD2002</strong>还能够把字符转换为 XBM 数组。首先在打开 <strong>PCtoLCD2002</strong>取模软件之后，选择顶部菜单栏上的【模式 → 字符模式】：</p><p><img src="/Project/UINIO-Monitor/U8G2-Bitmap-7.png"></p><p>接下来，依然需要点击顶部工具栏上的【字模生成和液晶面板选项】按钮，在弹出的【字模选项】对话框当中进行如下设置：</p><p><img src="/Project/UINIO-Monitor/U8G2-Bitmap-8.png"></p><p>然后，选择字体为 <code>楷体</code>，每一个字的宽度与高度都设置为<code>64</code> 个像素，并且在中间的输入框填写汉字<code>成都</code>，点击【生成字模】按钮：</p><p><img src="/Project/UINIO-Monitor/U8G2-Bitmap-9.png"></p><p>最后，把上述步骤得到的两个 XBM 数组，分别赋予如下示例代码当中的<code>Chengdu</code> 和 <code>Du</code> 两个变量，再分别调用<code>drawXBM()</code> 函数就可以完成显示：</p><figure class="highlight cpp"><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><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;Arduino.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;U8g2lib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function">U8G2_SSD1306_128X64_NONAME_F_HW_I2C <span class="title">u8g2</span><span class="params">(U8G2_R0, <span class="comment">/* reset=*/</span>U8X8_PIN_NONE, <span class="comment">/* clock=*/</span><span class="number">16</span>, <span class="comment">/* data=*/</span><span class="number">17</span>)</span></span>;</span><br><span class="line"></span><br><span class="line">PROGMEM <span class="type">const</span> <span class="type">uint8_t</span> Cheng[] = &#123;</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x7C</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xFC</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF8</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF8</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF0</span>, <span class="number">0x80</span>, <span class="number">0x1F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF0</span>, <span class="number">0x00</span>, <span class="number">0x3F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF0</span>, <span class="number">0x00</span>, <span class="number">0x7E</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0x00</span>, <span class="number">0x7C</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0x01</span>, <span class="number">0x70</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x03</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x80</span>, <span class="number">0xC3</span>, <span class="number">0x0F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x80</span>, <span class="number">0xFF</span>, <span class="number">0x0F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x80</span>, <span class="number">0xFF</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF0</span>, <span class="number">0x7F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xFE</span>, <span class="number">0x0F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0x7F</span>, <span class="number">0x0F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xF0</span>, <span class="number">0xFF</span>, <span class="number">0x07</span>, <span class="number">0x0E</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF0</span>, <span class="number">0x3F</span>, <span class="number">0x00</span>, <span class="number">0x0E</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x1E</span>, <span class="number">0x20</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x1C</span>, <span class="number">0xE0</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x1C</span>, <span class="number">0xE0</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x3C</span>, <span class="number">0xE0</span>, <span class="number">0x03</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x38</span>, <span class="number">0xE0</span>, <span class="number">0x03</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x78</span>, <span class="number">0xE0</span>, <span class="number">0x03</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x04</span>, <span class="number">0x70</span>, <span class="number">0xE0</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x1F</span>, <span class="number">0x70</span>, <span class="number">0xF0</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x81</span>, <span class="number">0x7F</span>, <span class="number">0xF0</span>, <span class="number">0xF0</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0xC1</span>, <span class="number">0x7F</span>, <span class="number">0xE0</span>, <span class="number">0x78</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0xF9</span>, <span class="number">0x7D</span>, <span class="number">0xE0</span>, <span class="number">0x79</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x3F</span>, <span class="number">0x3C</span>, <span class="number">0xC0</span>, <span class="number">0x3D</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x07</span>, <span class="number">0x3C</span>, <span class="number">0xC0</span>, <span class="number">0x3F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x3C</span>, <span class="number">0x80</span>, <span class="number">0x1F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0x01</span>, <span class="number">0x3C</span>, <span class="number">0x80</span>, <span class="number">0x1F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0x01</span>, <span class="number">0x3C</span>, <span class="number">0x00</span>, <span class="number">0x0F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0x01</span>, <span class="number">0x3C</span>, <span class="number">0x80</span>, <span class="number">0x0F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0x00</span>, <span class="number">0x3C</span>, <span class="number">0xC0</span>, <span class="number">0x1F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xF0</span>, <span class="number">0x00</span>, <span class="number">0x3C</span>, <span class="number">0xC0</span>, <span class="number">0x3F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x70</span>, <span class="number">0x00</span>, <span class="number">0x1C</span>, <span class="number">0xE0</span>, <span class="number">0x3D</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x78</span>, <span class="number">0x00</span>, <span class="number">0x1E</span>, <span class="number">0xF0</span>, <span class="number">0x7C</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x38</span>, <span class="number">0x00</span>, <span class="number">0x1E</span>, <span class="number">0x78</span>, <span class="number">0xF8</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x3C</span>, <span class="number">0x18</span>, <span class="number">0x1E</span>, <span class="number">0x1C</span>, <span class="number">0xF0</span>, <span class="number">0x01</span>, <span class="number">0x04</span>, <span class="number">0x00</span>, <span class="number">0x1C</span>, <span class="number">0xF0</span>, <span class="number">0x1F</span>, <span class="number">0x0E</span>, <span class="number">0xF0</span>, <span class="number">0x01</span>, <span class="number">0x06</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x0E</span>, <span class="number">0xE0</span>, <span class="number">0x0F</span>, <span class="number">0x03</span>, <span class="number">0xE0</span>, <span class="number">0x03</span>, <span class="number">0x06</span>, <span class="number">0x00</span>, <span class="number">0x07</span>, <span class="number">0xC0</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x07</span>, <span class="number">0x06</span>,</span><br><span class="line">  <span class="number">0x80</span>, <span class="number">0x03</span>, <span class="number">0xC0</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0x80</span>, <span class="number">0x1F</span>, <span class="number">0x07</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x80</span>, <span class="number">0x03</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x7F</span>, <span class="number">0x07</span>,</span><br><span class="line">  <span class="number">0x60</span>, <span class="number">0x00</span>, <span class="number">0x80</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xFE</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xFC</span>, <span class="number">0x07</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF8</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xF0</span>, <span class="number">0x07</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x07</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="comment">/*&quot;成&quot;,0*/</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line">PROGMEM <span class="type">const</span> <span class="type">uint8_t</span> Du[] = &#123;</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x60</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0x03</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x03</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x03</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x06</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x0E</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x1E</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x1E</span>, <span class="number">0x00</span>, <span class="number">0x78</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x7F</span>, <span class="number">0x1F</span>, <span class="number">0x00</span>, <span class="number">0xFC</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0x7F</span>, <span class="number">0x8F</span>, <span class="number">0x87</span>, <span class="number">0xFF</span>, <span class="number">0x03</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0xFF</span>, <span class="number">0x8F</span>, <span class="number">0x87</span>, <span class="number">0xFF</span>, <span class="number">0xFB</span>, <span class="number">0x03</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0xFF</span>, <span class="number">0x81</span>, <span class="number">0x03</span>, <span class="number">0x0F</span>, <span class="number">0xF0</span>, <span class="number">0x03</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC7</span>, <span class="number">0xC1</span>, <span class="number">0x03</span>, <span class="number">0x0F</span>, <span class="number">0xF8</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0xC1</span>, <span class="number">0x01</span>, <span class="number">0x0F</span>, <span class="number">0x78</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0xE1</span>, <span class="number">0x00</span>, <span class="number">0x0F</span>, <span class="number">0x3C</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0xE1</span>, <span class="number">0x00</span>, <span class="number">0x0F</span>, <span class="number">0x1C</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x71</span>, <span class="number">0x3C</span>, <span class="number">0x0F</span>, <span class="number">0x0E</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0xF9</span>, <span class="number">0x7F</span>, <span class="number">0x0F</span>, <span class="number">0x06</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0xFF</span>, <span class="number">0x1F</span>, <span class="number">0x0F</span>, <span class="number">0x03</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xFF</span>, <span class="number">0x1F</span>, <span class="number">0x00</span>, <span class="number">0x0F</span>, <span class="number">0x01</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0xF0</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x0E</span>, <span class="number">0x00</span>, <span class="number">0x8F</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0xF0</span>, <span class="number">0xFF</span>, <span class="number">0x07</span>, <span class="number">0x0F</span>, <span class="number">0x00</span>, <span class="number">0x0F</span>, <span class="number">0x03</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0xE0</span>, <span class="number">0x7F</span>, <span class="number">0x00</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0x0F</span>, <span class="number">0x06</span>, <span class="number">0x00</span>, <span class="number">0x80</span>, <span class="number">0x03</span>, <span class="number">0x80</span>, <span class="number">0x03</span>, <span class="number">0x00</span>, <span class="number">0x0F</span>, <span class="number">0x0C</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x0F</span>, <span class="number">0x18</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0xF0</span>, <span class="number">0x00</span>, <span class="number">0x0F</span>, <span class="number">0x30</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x73</span>, <span class="number">0xFC</span>, <span class="number">0x03</span>, <span class="number">0x0F</span>, <span class="number">0x70</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xFE</span>, <span class="number">0xFF</span>, <span class="number">0x07</span>, <span class="number">0x0F</span>, <span class="number">0xE0</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xFE</span>, <span class="number">0xE1</span>, <span class="number">0x07</span>, <span class="number">0x0F</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x0E</span>, <span class="number">0xC0</span>, <span class="number">0x03</span>, <span class="number">0x0F</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x0F</span>, <span class="number">0xC0</span>, <span class="number">0x03</span>, <span class="number">0x0F</span>, <span class="number">0xC0</span>, <span class="number">0x03</span>, <span class="number">0x00</span>, <span class="number">0x80</span>, <span class="number">0x0F</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x0F</span>, <span class="number">0xC0</span>, <span class="number">0x03</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0xC0</span>, <span class="number">0x0D</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x0F</span>, <span class="number">0x80</span>, <span class="number">0x03</span>, <span class="number">0x00</span>, <span class="number">0xE0</span>, <span class="number">0x0C</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x8F</span>, <span class="number">0x87</span>, <span class="number">0x07</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x70</span>, <span class="number">0x8C</span>, <span class="number">0xC7</span>, <span class="number">0x01</span>, <span class="number">0x0F</span>, <span class="number">0xFF</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0x38</span>, <span class="number">0xFC</span>, <span class="number">0xC7</span>, <span class="number">0x01</span>, <span class="number">0x0F</span>, <span class="number">0xFC</span>, <span class="number">0x07</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x1E</span>, <span class="number">0xFC</span>, <span class="number">0xC3</span>, <span class="number">0x01</span>, <span class="number">0x0F</span>, <span class="number">0xF8</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0x0F</span>, <span class="number">0x0C</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x0F</span>, <span class="number">0xF0</span>, <span class="number">0x03</span>,</span><br><span class="line">  <span class="number">0x80</span>, <span class="number">0x03</span>, <span class="number">0x0C</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x0F</span>, <span class="number">0xE0</span>, <span class="number">0x03</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x0C</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x0F</span>, <span class="number">0xE0</span>, <span class="number">0x01</span>,</span><br><span class="line">  <span class="number">0x60</span>, <span class="number">0x00</span>, <span class="number">0x0C</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x0F</span>, <span class="number">0xC0</span>, <span class="number">0x00</span>, <span class="number">0x10</span>, <span class="number">0x00</span>, <span class="number">0x0C</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x0F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x0E</span>, <span class="number">0xEF</span>, <span class="number">0x01</span>, <span class="number">0x0F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xFE</span>, <span class="number">0xFF</span>, <span class="number">0x01</span>, <span class="number">0x0F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xFE</span>, <span class="number">0xFF</span>, <span class="number">0x01</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x0E</span>, <span class="number">0xE0</span>, <span class="number">0x01</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x0C</span>, <span class="number">0xE0</span>, <span class="number">0x01</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x0C</span>, <span class="number">0xC0</span>, <span class="number">0x01</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x04</span>, <span class="number">0xC0</span>, <span class="number">0x00</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x07</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x03</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x02</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="comment">/*&quot;都&quot;,1*/</span></span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">setup</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">setBusClock</span>(<span class="number">800000</span>);  <span class="comment">// 设置 I²C 总线时钟频率</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">begin</span>();              <span class="comment">// 初始化显示相关的一系列设置</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">enableUTF8Print</span>();    <span class="comment">// 使能 UTF8 编码支持</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">loop</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">clearBuffer</span>();</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">drawXBM</span>(<span class="number">0</span>, <span class="number">0</span>, <span class="number">64</span>, <span class="number">64</span>, Cheng);  <span class="comment">// 调用 drawXBM() 函数绘制 &quot;成&quot; 字</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">drawXBM</span>(<span class="number">64</span>, <span class="number">0</span>, <span class="number">64</span>, <span class="number">64</span>, Du);    <span class="comment">// 调用 drawXBM() 函数绘制 &quot;都&quot; 字</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">sendBuffer</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这里同样将上述代码下载到 <strong>UINIO-MCU-ESP32S3</strong>核心板运行，此时 <strong>UINIO-Monitor</strong> 的 OLED屏幕显示结果如下面所示：</p><p><img src="/Project/UINIO-Monitor/U8G2-Bitmap-10.png"></p><h2 id="绘制基本图形">绘制基本图形</h2><h3 id="矩形绘制">矩形绘制</h3><p><strong>U8G2</strong> 库提供了 <code>drawBox()</code> 和<code>drawFrame()</code> 两个函数用于矩形的绘制：</p><table><colgroup><col style="width: 41%"><col style="width: 58%"></colgroup><thead><tr><th style="text-align: left;">矩形绘制 API</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>void drawBox(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h)</code></td><td style="text-align: left;">绘制一个<strong>实心</strong>的矩形，参数<code>x</code> 和 <code>y</code>表示矩形<strong>左上角</strong>的起始位置，而 <code>w</code> 和<code>h</code> 分别表示其宽度与高度。</td></tr><tr><td style="text-align: left;"><code>void drawFrame(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h)</code></td><td style="text-align: left;">绘制一个<strong>空心</strong>的矩形，参数<code>x</code> 和 <code>y</code>表示矩形<strong>左上角</strong>的起始位置，而 <code>w</code> 和<code>h</code> 分别表示其宽度与高度。</td></tr></tbody></table><p>下面的示例代码会在 <strong>UINIO-Monitor</strong>屏幕的左右两侧，分别绘制一个实心矩形和一个空心矩形：</p><figure class="highlight cpp"><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="meta">#<span class="keyword">include</span> <span class="string">&lt;Arduino.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;U8g2lib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function">U8G2_SSD1306_128X64_NONAME_F_HW_I2C <span class="title">u8g2</span><span class="params">(U8G2_R0, <span class="comment">/* reset=*/</span>U8X8_PIN_NONE, <span class="comment">/* clock=*/</span><span class="number">16</span>, <span class="comment">/* data=*/</span><span class="number">17</span>)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">setup</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">begin</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">loop</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">clearBuffer</span>();</span><br><span class="line"></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">drawBox</span>(<span class="number">16</span>, <span class="number">16</span>, <span class="number">32</span>, <span class="number">32</span>);    <span class="comment">// 绘制实心矩形</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">drawFrame</span>(<span class="number">80</span>, <span class="number">16</span>, <span class="number">32</span>, <span class="number">32</span>);  <span class="comment">// 绘制空心矩形</span></span><br><span class="line"></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">sendBuffer</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="圆形绘制">圆形绘制</h3><p><strong>U8G2</strong> 库提供了 <code>drawCircle()</code> 和<code>drawDisc()</code> 两个函数用于圆形的绘制：</p><table><colgroup><col style="width: 48%"><col style="width: 51%"></colgroup><thead><tr><th style="text-align: left;">圆形绘制 API</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>void drawCircle(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rad, uint8_t opt = U8G2_DRAW_ALL)</code></td><td style="text-align: left;">以 <code>(x0, y0)</code>位置为圆心，绘制一个半径为 <code>rad</code>的<strong>空心</strong>圆，参数 <code>opt</code>用于指定只绘制圆形的哪些部分。</td></tr><tr><td style="text-align: left;"><code>void drawDisc(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rad, uint8_t opt = U8G2_DRAW_ALL)</code></td><td style="text-align: left;">以 <code>(x0, y0)</code>位置为圆心，绘制一个半径为 <code>rad</code>的<strong>实心</strong>圆，参数 <code>opt</code>用于指定只绘制圆形的哪些部分。</td></tr></tbody></table><p>下面的示例代码会在 <strong>UINIO-Monitor</strong>屏幕的左右两侧，分别绘制一个实心圆形和一个空心圆形：</p><figure class="highlight cpp"><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="meta">#<span class="keyword">include</span> <span class="string">&lt;Arduino.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;U8g2lib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function">U8G2_SSD1306_128X64_NONAME_F_HW_I2C <span class="title">u8g2</span><span class="params">(U8G2_R0, <span class="comment">/* reset=*/</span>U8X8_PIN_NONE, <span class="comment">/* clock=*/</span><span class="number">16</span>, <span class="comment">/* data=*/</span><span class="number">17</span>)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">setup</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">begin</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">loop</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">clearBuffer</span>();</span><br><span class="line"></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">drawCircle</span>(<span class="number">32</span>, <span class="number">32</span>, <span class="number">16</span>);  <span class="comment">// 绘制实心圆形</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">drawDisc</span>(<span class="number">96</span>, <span class="number">32</span>, <span class="number">16</span>);    <span class="comment">// 绘制空心圆形</span></span><br><span class="line"></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">sendBuffer</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="椭圆形绘制">椭圆形绘制</h3><p><strong>U8G2</strong> 库提供了 <code>drawEllipse()</code> 和<code>drawFilledEllipse()</code> 两个函数用于椭圆形的绘制：</p><table><colgroup><col style="width: 45%"><col style="width: 54%"></colgroup><thead><tr><th style="text-align: left;">椭圆形绘制 API</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>void drawEllipse(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rx, u8g2_uint_t ry, uint8_t opt)</code></td><td style="text-align: left;">以 <code>(x0, y0)</code>作为圆心，位置绘制水平半径为 <code>rx</code>，垂直半径为 <code>ry</code>的<strong>空心</strong>椭圆（8 位显示模式下，两者取值必须小于512）。</td></tr><tr><td style="text-align: left;"><code>void drawFilledEllipse(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rx, u8g2_uint_t ry, uint8_t opt)</code></td><td style="text-align: left;">以 <code>(x0, y0)</code>作为圆心，位置绘制水平半径为 <code>rx</code>，垂直半径为 <code>ry</code>的<strong>实心</strong>椭圆（8 位显示模式下，两者取值必须小于512）。</td></tr></tbody></table><p>下面的示例代码会在 <strong>UINIO-Monitor</strong>屏幕的左右两侧，分别绘制一个实心椭圆形和一个空心椭圆形：</p><figure class="highlight cpp"><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="meta">#<span class="keyword">include</span> <span class="string">&lt;Arduino.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;U8g2lib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function">U8G2_SSD1306_128X64_NONAME_F_HW_I2C <span class="title">u8g2</span><span class="params">(U8G2_R0, <span class="comment">/* reset=*/</span>U8X8_PIN_NONE, <span class="comment">/* clock=*/</span><span class="number">16</span>, <span class="comment">/* data=*/</span><span class="number">17</span>)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">setup</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">begin</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">loop</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">clearBuffer</span>();</span><br><span class="line"></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">drawEllipse</span>(<span class="number">32</span>, <span class="number">30</span>, <span class="number">30</span>, <span class="number">16</span>);        <span class="comment">// 绘制实心椭圆形</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">drawFilledEllipse</span>(<span class="number">96</span>, <span class="number">30</span>, <span class="number">30</span>, <span class="number">16</span>);  <span class="comment">// 绘制空心椭圆形</span></span><br><span class="line"></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">sendBuffer</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="直线绘制">直线绘制</h3><p><strong>U8G2</strong> 库提供了 <code>drawHLine()</code> 和<code>drawVLine()</code> 以及 <code>drawLine()</code>三个函数来绘制直线：</p><table><colgroup><col style="width: 43%"><col style="width: 56%"></colgroup><thead><tr><th style="text-align: left;">直线绘制 API</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>void drawHLine(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w)</code></td><td style="text-align: left;">基于 <code>(x, y)</code>位置<strong>从左至右</strong>绘制一条长度为 <code>w</code>像素的<strong>水平</strong>直线。</td></tr><tr><td style="text-align: left;"><code>void drawVLine(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t h)</code></td><td style="text-align: left;">基于 <code>(x, y)</code>位置<strong>从下至上</strong>绘制一条长度为 <code>w</code>像素的<strong>垂直</strong>直线。</td></tr><tr><td style="text-align: left;"><code>void drawLine(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t x1, u8g2_uint_t y1)</code></td><td style="text-align: left;">基于两个像素点的位置绘制一条直线，参数<code>(x0, y0)</code> 是第 1 个点的坐标，而 <code>(x1, y1)</code> 则是第2 个点的坐标。</td></tr></tbody></table><p>下面的示例代码会在 <strong>UINIO-Monitor</strong>屏幕上面，绘制呈现<strong>米</strong>字形交错的 1 条水平直线和 1条垂直直线，以及 2 条斜线（类似于英国国旗的图案）：</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;Arduino.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;U8g2lib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function">U8G2_SSD1306_128X64_NONAME_F_HW_I2C <span class="title">u8g2</span><span class="params">(U8G2_R0, <span class="comment">/* reset=*/</span>U8X8_PIN_NONE, <span class="comment">/* clock=*/</span><span class="number">16</span>, <span class="comment">/* data=*/</span><span class="number">17</span>)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">setup</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">begin</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">loop</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">clearBuffer</span>();</span><br><span class="line"></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">drawLine</span>(<span class="number">0</span>, <span class="number">0</span>, <span class="number">128</span>, <span class="number">64</span>);  <span class="comment">// 绘制一条从屏幕左上角到右下角的斜线</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">drawLine</span>(<span class="number">128</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">64</span>);  <span class="comment">// 绘制一条从屏幕右上角到左下角的斜线</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">drawHLine</span>(<span class="number">0</span>, <span class="number">32</span>, <span class="number">128</span>);    <span class="comment">// 绘制一条水平直线</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">drawVLine</span>(<span class="number">64</span>, <span class="number">0</span>, <span class="number">64</span>);     <span class="comment">// 绘制一条垂直直线</span></span><br><span class="line"></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">sendBuffer</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="像素点绘制">像素点绘制</h3><p><strong>U8G2</strong> 库提供了 <code>drawPixel()</code>函数来绘制一个像素点：</p><table><colgroup><col style="width: 58%"><col style="width: 41%"></colgroup><thead><tr><th style="text-align: left;">像素点绘制 API</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>void drawPixel(u8g2_uint_t x, u8g2_uint_t y)</code></td><td style="text-align: left;">在 <code>(x, y)</code>位置绘制一个像素点。</td></tr></tbody></table><p>下面的示例代码会在 <strong>UINIO-Monitor</strong> 屏幕当中，每间隔 8个像素绘制一个点，最终形成一条水平的虚线效果：</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;Arduino.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;U8g2lib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function">U8G2_SSD1306_128X64_NONAME_F_HW_I2C <span class="title">u8g2</span><span class="params">(U8G2_R0, <span class="comment">/* reset=*/</span>U8X8_PIN_NONE, <span class="comment">/* clock=*/</span><span class="number">16</span>, <span class="comment">/* data=*/</span><span class="number">17</span>)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">setup</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">begin</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">loop</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">clearBuffer</span>();</span><br><span class="line"></span><br><span class="line">  <span class="comment">/* 从左侧第 8 个像素位置开始，每间隔 8 个像素绘制出一个点 */</span></span><br><span class="line">  <span class="keyword">for</span> (<span class="type">int</span> index = <span class="number">8</span>; index &lt;= <span class="number">128</span>; index += <span class="number">8</span>) &#123;</span><br><span class="line">    u8g<span class="number">2.</span><span class="built_in">drawPixel</span>(index, <span class="number">32</span>);  <span class="comment">// 绘制一条由像素点组成的虚线</span></span><br><span class="line">  &#125;;</span><br><span class="line"></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">sendBuffer</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h3 id="圆角矩形绘制">圆角矩形绘制</h3><p><strong>U8G2</strong> 库提供了 <code>drawRBox()</code> 和<code>drawRFrame()</code> 两个函数用于圆角矩形的绘制：</p><table><colgroup><col style="width: 48%"><col style="width: 51%"></colgroup><thead><tr><th style="text-align: left;">直线绘制 API</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>void drawRBox(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h, u8g2_uint_t r)</code></td><td style="text-align: left;">以 <code>(x, y)</code>位置作为左上角，绘制一个宽高度分别为 <code>w</code> 和 <code>h</code>的圆角<strong>实心</strong>矩形，圆角的半径为 <code>r</code>。</td></tr><tr><td style="text-align: left;"><code>void drawRFrame(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h, u8g2_uint_t r)</code></td><td style="text-align: left;">以 <code>(x, y)</code>位置作为左上角，绘制一个宽高度分别为 <code>w</code> 和 <code>h</code>的圆角<strong>空心</strong>矩形，圆角的半径为 <code>r</code>。</td></tr></tbody></table><p>下面的示例代码会在 <strong>UINIO-Monitor</strong>屏幕的左右两侧，分别绘制一个实心和一个空心的圆角矩形：</p><figure class="highlight cpp"><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="meta">#<span class="keyword">include</span> <span class="string">&lt;Arduino.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;U8g2lib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function">U8G2_SSD1306_128X64_NONAME_F_HW_I2C <span class="title">u8g2</span><span class="params">(U8G2_R0, <span class="comment">/* reset=*/</span>U8X8_PIN_NONE, <span class="comment">/* clock=*/</span><span class="number">16</span>, <span class="comment">/* data=*/</span><span class="number">17</span>)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">setup</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">begin</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">loop</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">clearBuffer</span>();</span><br><span class="line"></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">drawRBox</span>(<span class="number">30</span>, <span class="number">16</span>, <span class="number">32</span>, <span class="number">32</span>, <span class="number">8</span>);    <span class="comment">// 绘制实心圆角矩形</span></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">drawRFrame</span>(<span class="number">66</span>, <span class="number">16</span>, <span class="number">32</span>, <span class="number">32</span>, <span class="number">8</span>);  <span class="comment">// 绘制空心圆角矩形</span></span><br><span class="line"></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">sendBuffer</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="绘制三角形">绘制三角形</h2><p><strong>U8G2</strong> 库提供了 <code>drawTriangle()</code>函数用于绘制实心的三角形：</p><table><colgroup><col style="width: 54%"><col style="width: 45%"></colgroup><thead><tr><th style="text-align: left;">直线绘制 API</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2)</code></td><td style="text-align: left;">分别以<code>(x0, y0)</code>、<code>(x1, y1)</code>、<code>(x2, y2)</code>作为顶点绘制一个<strong>实心</strong>的三角形。</td></tr></tbody></table><p>下面的示例代码，分别以屏幕顶部中间点 <code>(64, 0)</code>、屏幕左下角<code>(0, 64)</code>、屏幕右下角 <code>(128, 64)</code>作为顶点，绘制出了一个实心的三角形：</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;Arduino.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;U8g2lib.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="function">U8G2_SSD1306_128X64_NONAME_F_HW_I2C <span class="title">u8g2</span><span class="params">(U8G2_R0, <span class="comment">/* reset=*/</span>U8X8_PIN_NONE, <span class="comment">/* clock=*/</span><span class="number">16</span>, <span class="comment">/* data=*/</span><span class="number">17</span>)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">setup</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">begin</span>();</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">loop</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">clearBuffer</span>();</span><br><span class="line"></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">drawTriangle</span>(<span class="number">64</span>, <span class="number">0</span>, <span class="number">0</span>, <span class="number">64</span>, <span class="number">128</span>, <span class="number">64</span>);  <span class="comment">// 绘制实心三角形</span></span><br><span class="line"></span><br><span class="line">  u8g<span class="number">2.</span><span class="built_in">sendBuffer</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="mui-图形界面库">MUI 图形界面库</h2><p><strong>MUI</strong> 是一款基于 <strong>U8G2</strong>库的单色图形用户界面库，提供了诸如<code>事件处理</code>、<code>用户界面绘图</code>、<code>丰富的预定义用户元素</code>、<code>静态菜单定义</code>等特性。详细信息可以参考 <strong>U8G2</strong> 库作者提供的 <a href="https://github.com/olikraus/u8g2/wiki/muimanual">《MUI手册》</a>和 <a href="https://github.com/olikraus/u8g2/wiki/muiref">《MUI 参考》</a>两份文档。</p><h1 id="英寸-lcd-显示屏">0.96/1.3/1.69/2.4 英寸 LCD 显示屏</h1><p><strong>UINIO-Monitor</strong> 里的 <strong>2.4</strong>英寸显示屏幕，采用了 <code>320 × 240</code>分辨率的<strong>薄膜晶体管</strong>（TFT，Thin FilmTransistor）屏幕材质，总线通信方式为<strong>SPI</strong>，驱动芯片型号是<a href="https://www.sitronix.com.tw/cn/index-cn/">台湾矽创电子（Sitronix）</a>的<strong>ST7789</strong>，属于本系列当中显示尺寸最大的屏幕：</p><p><img src="/Project/UINIO-Monitor/LCD-2.4.png"></p><p><strong>UINIO-Monitor</strong> 里的 <strong>1.3</strong>英寸显示屏幕，采用了 <code>240 × 240</code>分辨率的<strong>薄膜晶体管</strong>（TFT，Thin FilmTransistor）屏幕材质，总线通信方式为<strong>SPI</strong>，驱动芯片型号是<a href="https://www.sitronix.com.tw/cn/index-cn/">台湾矽创电子（Sitronix）</a>的<strong>ST7789</strong>：</p><p><img src="/Project/UINIO-Monitor/LCD-1.3.png"></p><p><strong>UINIO-Monitor</strong> 里的 <strong>1.69</strong>英寸圆角显示屏幕，采用了 <code>280 × 240</code>分辨率的<strong>薄膜晶体管</strong>（TFT，Thin FilmTransistor）屏幕材质，总线通信方式为<strong>SPI</strong>，驱动芯片型号是<a href="https://www.sitronix.com.tw/cn/index-cn/">台湾矽创电子（Sitronix）</a>的<strong>ST7789</strong>：</p><p><img src="/Project/UINIO-Monitor/LCD-1.69.png"></p><p><strong>UINIO-Monitor</strong> 里的 <strong>0.96</strong>英寸显示屏幕，采用了 <code>160 × 80</code>分辨率的<strong>薄膜晶体管</strong>（TFT，Thin FilmTransistor）屏幕材质，总线通信方式为<strong>SPI</strong>，驱动芯片型号是<a href="https://www.sitronix.com.tw/cn/index-cn/">台湾矽创电子（Sitronix）</a>的<strong>ST7735</strong>：</p><p><img src="/Project/UINIO-Monitor/LCD-0.96.png"></p><p>由于 <strong>UINIO-Monitor</strong> 系列的 TFT屏幕都采用了台湾矽创电子（Sitronix）的主控方案，因而原理图设计方面基本上大同小异，不过建议线性稳压芯片采用带<strong>反接保护</strong>的德州仪器<a href="https://www.ti.com/lit/ds/symlink/lp2992.pdf">LP2992IM5-3.3</a>，虽然价格相对于国产微盟的ME6211C33M5G 更贵，不过一分钱一分货，总比烧坏了成本更高的 TFT屏幕要强：</p><p><img src="/Project/UINIO-Monitor/LCD-Schematic.png"></p><p>同样在开始上手实践之前，需要把 <strong>UINIO-Monitor</strong> 当中TFT 显示屏的<code>BLK</code>、<code>CS</code>、<code>D/C</code>、<code>RST</code>、<code>SCL</code>、<code>SDA</code>、<code>GND</code>、<code>VCC</code>引脚，分别与 <strong>UINIO-MCU-ESP32S3</strong> 核心板的<code>3V3</code>、<code>GPIO15</code>、<code>GPIO16</code>、<code>GPIO17</code>、<code>GPIO18</code>、<code>GPIO19</code>、<code>GND</code>、<code>5V</code>引脚进行连接，后续 <strong>TFT_eSPI</strong>库相关的示例代码都将会沿用这个连接关系，下面的连接示意图以<code>280 × 240</code> 分辨率的 <strong>1.69</strong>英寸圆角显示屏幕为例：</p><p><img src="/Project/UINIO-Monitor/LCD-ESP32S3.png"></p><h1 id="tft_espi-库开发速成">TFT_eSPI 库开发速成</h1><p><a href="https://github.com/Bodmer/TFT_eSPI">TFT_eSPI</a>是一款可以运行在 32 位微控制器上的 TFT屏幕图形与字体显示库，本文撰写时的最新版本为 <code>v2.5.0</code>，相关的API 函数可以参考 <a href="https://github.com/Bodmer/User_Manual_TFT_eSPI">《TFT_eSPI库用户手册》</a>，该库对于如下一系列微控制器进行了专门的性能优化：</p><ul><li><strong>树莓派 Pico</strong> 上的 <code>RP2040</code>微控制器。</li><li><strong>乐鑫科技</strong>的<code>ESP8266</code>、<code>ESP32</code>、<code>ESP32-S2</code>、<code>ESP32-C3</code>、<code>ESP32-S3</code>微控制器。</li><li><strong>意法半导体</strong>的<code>STM32F1xx</code>、<code>STM32F2xx</code>、<code>STM32F4xx</code>、<code>STM32F767</code>微控制器（推荐采用 RAM 空间较大的型号）。</li></ul><p>上述的微控制器在 <strong>TFT_eSPI</strong>库当中，可以支持如下表格当中的接口类型：</p><table><colgroup><col style="width: 22%"><col style="width: 16%"><col style="width: 20%"><col style="width: 22%"><col style="width: 18%"></colgroup><thead><tr><th style="text-align: left;">微控制器</th><th style="text-align: center;">4 线制 SPI</th><th style="text-align: center;">8 位并行总线</th><th style="text-align: center;">16 位并行总线</th><th style="text-align: left;">DMA 支持</th></tr></thead><tbody><tr><td style="text-align: left;"><strong>ESP32 C3</strong></td><td style="text-align: center;">是</td><td style="text-align: center;">否</td><td style="text-align: center;">否</td><td style="text-align: left;">否</td></tr><tr><td style="text-align: left;"><strong>ESP32 S3</strong></td><td style="text-align: center;">是</td><td style="text-align: center;">是</td><td style="text-align: center;">否</td><td style="text-align: left;">是 (仅 SPI)</td></tr><tr><td style="text-align: left;"><strong>ESP32 S2</strong></td><td style="text-align: center;">是</td><td style="text-align: center;">否</td><td style="text-align: center;">否</td><td style="text-align: left;">否</td></tr><tr><td style="text-align: left;"><strong>ESP32</strong></td><td style="text-align: center;">是</td><td style="text-align: center;">是</td><td style="text-align: center;">否</td><td style="text-align: left;">是 (仅 SPI)</td></tr><tr><td style="text-align: left;"><strong>RP2040</strong></td><td style="text-align: center;">是</td><td style="text-align: center;">是</td><td style="text-align: center;">是</td><td style="text-align: left;">是 (全部)</td></tr><tr><td style="text-align: left;"><strong>ESP8266</strong></td><td style="text-align: center;">是</td><td style="text-align: center;">否</td><td style="text-align: center;">否</td><td style="text-align: left;">否</td></tr><tr><td style="text-align: left;"><strong>STM32Fxxx</strong></td><td style="text-align: center;">是</td><td style="text-align: center;">是</td><td style="text-align: center;">否</td><td style="text-align: left;">是 (仅 SPI)</td></tr><tr><td style="text-align: left;">其它</td><td style="text-align: center;">是</td><td style="text-align: center;">否</td><td style="text-align: center;">否</td><td style="text-align: left;">否</td></tr></tbody></table><p><strong>TFT_eSPI</strong> 库能够支持如下一系列 TFT液晶显示屏驱动芯片（官方推荐使用内置有 <code>ILI9341</code> 和<code>ST7796</code> 两款驱动芯片的 SPI 屏幕）：</p><table><thead><tr><th style="text-align: left;">型号</th><th style="text-align: left;">型号</th><th style="text-align: left;">型号</th><th style="text-align: left;">型号</th><th style="text-align: left;">型号</th></tr></thead><tbody><tr><td style="text-align: left;">ILI9163</td><td style="text-align: left;">ILI9225</td><td style="text-align: left;">ILI9341</td><td style="text-align: left;">ILI9342</td><td style="text-align: left;">ILI9481</td></tr><tr><td style="text-align: left;">ILI9486</td><td style="text-align: left;">ILI9488</td><td style="text-align: left;">HX8357B</td><td style="text-align: left;">HX8357C</td><td style="text-align: left;">HX8357D</td></tr><tr><td style="text-align: left;">GC9A01</td><td style="text-align: left;">R61581</td><td style="text-align: left;">RM68120</td><td style="text-align: left;">RM68140</td><td style="text-align: left;">S6D02A1</td></tr><tr><td style="text-align: left;">SSD1351</td><td style="text-align: left;">SSD1963</td><td style="text-align: left;">ST7735</td><td style="text-align: left;">ST7789</td><td style="text-align: left;">ST7796</td></tr></tbody></table><h2 id="配置-user_setup.h">配置 User_Setup.h</h2><p>通过 <strong>Arduino IDE</strong> 的【库管理器】安装完成<strong>TFT_eSPI</strong> 库之后，还需要对<code>D:\Workspace\Workspace_Arduino\libraries\TFT_eSPI</code>路径下面的 <code>User_Setup.h</code> 头文件进行相应的编辑：</p><figure class="highlight cpp"><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">define</span> USER_SETUP_INFO <span class="string">&quot;UINIO_Monitor_Setup&quot;</span> <span class="comment">// 用于测试和诊断的用户自定义信息</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 配置 TFT 液晶屏驱动芯片型号，只能预定义一个驱动芯片型号 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ST7735_DRIVER     <span class="comment">// ST7735 的配置选项</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ST7789_DRIVER     <span class="comment">// ST7789 的完整配置选项</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ST7789_2_DRIVER   <span class="comment">// ST7789 的最小配置选项</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 以纵向排列的方式（高度大于宽度），配置 TFT 屏幕的像素高度与宽度 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_WIDTH  240    <span class="comment">// 2.4 英寸 ST7789 屏幕的宽度</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_HEIGHT 320    <span class="comment">// 2.4 英寸 ST7789 屏幕的高度</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_WIDTH  240    <span class="comment">// 1.3 英寸 ST7789 屏幕的宽度</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_HEIGHT 240    <span class="comment">// 1.3 英寸 ST7789 屏幕的宽度</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_WIDTH  240    <span class="comment">// 1.69 英寸 ST7789 屏幕的宽度</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_HEIGHT 280    <span class="comment">// 1.69 英寸 ST7789 屏幕的宽度</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_WIDTH  80     <span class="comment">// 0.96 英寸 ST7735 屏幕的宽度</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_HEIGHT 160    <span class="comment">// 0.96 英寸 ST7735 屏幕的宽度</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 配置 TFT 液晶屏当前所使用的 SPI 通信总线 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_MOSI 19       <span class="comment">// 从机输出/主机输入，即 UINIO-Monitor 上丝印为 SDA 的引脚</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_SCLK 18       <span class="comment">// 时钟引脚，即 UINIO-Monitor 上丝印为 SCL 的引脚</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_RST  17       <span class="comment">// 重置引脚，如果已经连接至 UINIO-MCU-EESP32 的 RST 引脚，那么可以将其配置为 -1</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_DC   16       <span class="comment">// 数据/命令控制引脚</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_CS   15       <span class="comment">// 片选引脚</span></span></span><br><span class="line"><span class="comment">// #define TFT_BL            // LED 背光控制引脚，可以接入 UINIO-MCU-ESP32S3 的 3V3 输出</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* TFT_eSPI 库自带的字体（非中文），加载全部字体会消耗约 17kb 的 Flash 存储空间，可以按需进行启用（ESP32-C3 和 ESP32-S3 的存储空间足够保存所有字体） */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> LOAD_GLCD         <span class="comment">// 8 像素字体，占用约 1820 bytes 的 Flash 存储空间</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> LOAD_FONT2        <span class="comment">// 16 像素字体，占用约 3534 bytes 的 Flash 存储空间</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> LOAD_FONT4        <span class="comment">// 16 像素字体，占用约 5848 bytes 的 Flash 存储空间</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> LOAD_FONT6        <span class="comment">// 48 像素字体，占用约 2666 bytes 的 Flash 存储空间，仅包含字符 1234567890:-.apm</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> LOAD_FONT7        <span class="comment">// 7 段 48 像素字体，占用约 2438 bytes 的 Flash 存储空间，仅包含字符 1234567890:-.</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> LOAD_FONT8        <span class="comment">// 75 像素字体，占用约 3256 bytes 的 Flash 存储空间，仅包含字符 1234567890:-.</span></span></span><br><span class="line"><span class="comment">// #define LOAD_FONT8N       // 用于代替上面的 LOAD_FONT8 字体，稍微窄一点，适合 3 个数字 160 像素的 TFT 屏幕</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> LOAD_GFXFF        <span class="comment">// 免费字体，包括 Adafruit_GFX 免费字体，以及 FF1 至 FF48 的自定义字体</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 用于停止加载 SPIFFS 文件系统和平滑字体代码，这样会节省约 20 kbytes 的 Flash 存储空间 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> SMOOTH_FONT</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 定义 SPI 总线时钟频率，该参数会影响到图形的渲染速度，超过 27MHz 会导致使用 ST7735 驱动芯片的屏幕显示异常 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> SPI_FREQUENCY  27000000         <span class="comment">// 可以选择的参数有 1000000、5000000、10000000、20000000、40000000、55000000、80000000</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> SPI_READ_FREQUENCY  20000000    <span class="comment">// 定义 SPI 读取 TFT 屏幕的频率</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> SPI_TOUCH_FREQUENCY  2500000    <span class="comment">// 触摸信号的 SPI 通信频率（触摸芯片 XPT2046 需要使用 2.5MHz 的时钟信号频率）</span></span></span><br></pre></td></tr></table></figure><p>如果 <strong>UINIO-Monitor</strong>屏幕显示出现异常，可以尝试通过调整如下的选项进行修复：</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">/* 只针对 ST7735、ST7789、ILI9341 有效，如果显示屏上红色与蓝色发生互换，那么可以重新调整其颜色顺序（只能启用一个选项）*/</span></span><br><span class="line"> <span class="meta">#<span class="keyword">define</span> TFT_RGB_ORDER TFT_RGB     <span class="comment">// 颜色顺序 Red-Green-Blue</span></span></span><br><span class="line"> <span class="meta">#<span class="keyword">define</span> TFT_RGB_ORDER TFT_BGR     <span class="comment">// 颜色顺序 Blue-Green-Red</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 如果显示的颜色发生反转（白色显示为黑色），可以尝试注释下面当中的其中一项 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_INVERSION_ON</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_INVERSION_OFF</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 定义显示类型（仅针对 ST7735 有效），如果屏幕不能正确显示图形（例如颜色错误、镜像、边缘杂散像素），那么可以尝试下面这些选项 */</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ST7735_INITB</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ST7735_GREENTAB</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ST7735_GREENTAB2</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ST7735_GREENTAB3</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ST7735_GREENTAB128        <span class="comment">// 仅 128 x 128 分辨率显示有效</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ST7735_GREENTAB160x80     <span class="comment">// 仅 160 x 80 分辨率显示有效</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ST7735_ROBOTLCD           <span class="comment">// 只针对某些 RobotLCD 开发板</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ST7735_REDTAB</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ST7735_BLACKTAB</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ST7735_REDTAB160x80       <span class="comment">// 用于 24 像素偏移的 160 × 80 分辨率显示屏</span></span></span><br></pre></td></tr></table></figure><h2 id="开始上手">开始上手</h2><p><strong>Arduino IDE</strong> 的【库管理器】可以直接安装<strong>TFT_eSPI</strong> 库，安装完成之后就可以在 Arduino草图代码当中包含 <code>#include &lt;TFT_eSPI.h&gt;</code>头文件，下面代码展示了 <strong>TFT_eSPI</strong> 库的基本使用方式：</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;SPI.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;TFT_eSPI.h&gt;</span></span></span><br><span class="line"></span><br><span class="line">TFT_eSPI tft = <span class="built_in">TFT_eSPI</span>();                 <span class="comment">// 创建 TFT_eSPI 对象</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">setup</span><span class="params">(<span class="type">void</span>)</span> </span>&#123;</span><br><span class="line">  tft.<span class="built_in">init</span>();                              <span class="comment">// 重置然后初始化 TFT 显示相关的寄存器</span></span><br><span class="line">  tft.<span class="built_in">setRotation</span>(<span class="number">0</span>);                      <span class="comment">// 调整屏幕方向，参数为 1 表示旋转 90° 度，为 2 表示旋转 180° 度，为 3 表示旋转 270° 度</span></span><br><span class="line">  tft.<span class="built_in">fillScreen</span>(TFT_BLACK);               <span class="comment">// 设置 TFT 屏幕的背景颜色</span></span><br><span class="line">  tft.<span class="built_in">setTextColor</span>(TFT_WHITE, TFT_BLACK);  <span class="comment">// 设置 TFT 屏幕显示文本字体的颜色以及显示背景色</span></span><br><span class="line">  <span class="comment">/* ... 其它 TFT_eSPI 配置代码 ... */</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">loop</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  <span class="comment">/* ... 需要循环执行的 TFT_eSPI 显示控制代码 ... */</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="颜色模式">颜色模式</h2><p><strong>TFT_eSPI</strong> 库所采用的颜色模式为<strong>RGB565</strong>，即每一个像素占据着 <code>2 Byte</code>个字节的数据量（即 2 个字节的无符号整型数据），其中红色占据<code>5 bit</code> 位，绿色占据 <code>6 bit</code> 位，蓝色占据<code>5 bit</code> 位。<strong>TFT_eSPI</strong> 库提供了一个便捷的<code>color565()</code> 方法，可以将普通的 RGB 颜色转换为 RGB565模式的颜色：</p><table><colgroup><col style="width: 19%"><col style="width: 39%"><col style="width: 41%"></colgroup><thead><tr><th style="text-align: center;">归属类与返回值</th><th style="text-align: center;">API 函数</th><th style="text-align: center;">功能描述</th></tr></thead><tbody><tr><td style="text-align: center;"><code>uint16_t TFT_eSPI::</code></td><td style="text-align: center;"><code>color565(uint8_t r, uint8_t g, uint8_t b)</code></td><td style="text-align: center;">用于将普通 RGB 颜色转换为 RGB565模式的颜色。</td></tr></tbody></table><p>下面的示例代码，通过 <code>color565()</code>函数将<strong>红</strong>、<strong>黄</strong>、<strong>蓝</strong>、<strong>绿</strong>4 种 RGB 颜色，分别转换为了 RGB565 模式的颜色值：</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line"><span class="type">uint16_t</span> RGB_Red = tft.<span class="built_in">color565</span>(<span class="number">255</span>, <span class="number">0</span>, <span class="number">0</span>);</span><br><span class="line"><span class="type">uint16_t</span> RGB_Yellow = tft.<span class="built_in">color565</span>(<span class="number">255</span>, <span class="number">255</span>, <span class="number">0</span>);</span><br><span class="line"><span class="type">uint16_t</span> RGB_Blue = tft.<span class="built_in">color565</span>(<span class="number">0</span>, <span class="number">0</span>, <span class="number">255</span>);</span><br><span class="line"><span class="type">uint16_t</span> RGB_Green = tft.<span class="built_in">color565</span>(<span class="number">0</span>, <span class="number">255</span>, <span class="number">0</span>);</span><br></pre></td></tr></table></figure><p>在 <strong>TFT_eSPI</strong> 库安装目录下的 <code>TFT_eSPI.h</code>源文件里，已经预定义了如下一系列的默认颜色，代码当中可以直接进行使用：</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_BLACK       0x0000      <span class="comment">/*   0,   0,   0 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_NAVY        0x000F      <span class="comment">/*   0,   0, 128 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_DARKGREEN   0x03E0      <span class="comment">/*   0, 128,   0 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_DARKCYAN    0x03EF      <span class="comment">/*   0, 128, 128 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_MAROON      0x7800      <span class="comment">/* 128,   0,   0 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_PURPLE      0x780F      <span class="comment">/* 128,   0, 128 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_OLIVE       0x7BE0      <span class="comment">/* 128, 128,   0 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_LIGHTGREY   0xD69A      <span class="comment">/* 211, 211, 211 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_DARKGREY    0x7BEF      <span class="comment">/* 128, 128, 128 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_BLUE        0x001F      <span class="comment">/*   0,   0, 255 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_GREEN       0x07E0      <span class="comment">/*   0, 255,   0 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_CYAN        0x07FF      <span class="comment">/*   0, 255, 255 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_RED         0xF800      <span class="comment">/* 255,   0,   0 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_MAGENTA     0xF81F      <span class="comment">/* 255,   0, 255 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_YELLOW      0xFFE0      <span class="comment">/* 255, 255,   0 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_WHITE       0xFFFF      <span class="comment">/* 255, 255, 255 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_ORANGE      0xFDA0      <span class="comment">/* 255, 180,   0 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_GREENYELLOW 0xB7E0      <span class="comment">/* 180, 255,   0 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_PINK        0xFE19      <span class="comment">/* 255, 192, 203 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_BROWN       0x9A60      <span class="comment">/* 150,  75,   0 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_GOLD        0xFEA0      <span class="comment">/* 255, 215,   0 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_SILVER      0xC618      <span class="comment">/* 192, 192, 192 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_SKYBLUE     0x867D      <span class="comment">/* 135, 206, 235 */</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TFT_VIOLET      0x915C      <span class="comment">/* 180,  46, 226 */</span></span></span><br></pre></td></tr></table></figure><h2 id="文本显示">文本显示</h2><p>下面表格当中的函数用于控制<code>TFT_eSP::print/printf/println()</code>系列文本输出函数（可以自动换行）的坐标系统：</p><table><colgroup><col style="width: 47%"><col style="width: 52%"></colgroup><thead><tr><th style="text-align: left;">API 方法</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>void setCursor(int16_t x, int16_t y)</code></td><td style="text-align: left;">为 <code>tft.print()</code> 设置文本光标的<code>(x, y)</code> 坐标位置。</td></tr><tr><td style="text-align: left;"><code>void setCursor(int16_t x, int16_t y, uint8_t font)</code></td><td style="text-align: left;">为 <code>tft.print()</code> 设置文本光标的<code>(x, y)</code> 坐标位置和字体。</td></tr><tr><td style="text-align: left;"><code>int16_t getCursorX(void)</code></td><td style="text-align: left;">获取当前 <code>tft.print()</code>文本光标在 <code>x</code> 轴的坐标位置。</td></tr><tr><td style="text-align: left;"><code>int16_t getCursorY(void)</code></td><td style="text-align: left;">获取当前 <code>tft.print()</code>文本光标在 <code>y</code> 轴的坐标位置。</td></tr></tbody></table><p>而接下来表格当中的这些方法，则用于控制<code>TFT_eSP::drawXxx()</code>系列文本输出函数（无法自动换行）的参考基准点：</p><table><thead><tr><th style="text-align: left;">API 方法</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>uint8_t getTextDatum(void)</code></td><td style="text-align: left;">获取文本输出基准点。</td></tr><tr><td style="text-align: left;"><code>void setTextDatum(uint8_t d)</code></td><td style="text-align: left;">设置文本输出基准点。</td></tr></tbody></table><p>上面表格当中的 <code>setTextDatum(uint8_t d)</code> 函数的参数<code>d</code> 表示基准点的位置，可供选择的枚举参数有如下这些：</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">define</span> TL_DATUM    0  <span class="comment">// 基准点位于输出文本的左上角（Top left）位置，默认参数</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TC_DATUM    1  <span class="comment">// 基准点位于输出文本的中间顶部（Top Centre）位置</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> TR_DATUM    2  <span class="comment">// 基准点位于输出文本的右侧顶部（Top Right）位置</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> ML_DATUM    3  <span class="comment">// 基准点位于输出文本的左侧中间（Middle Left）位置</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> CL_DATUM    3  <span class="comment">// 同上</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> MC_DATUM    4  <span class="comment">// 基准点位于输出文本横向与纵向的中间（Middle Centre）位置</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> CC_DATUM    4  <span class="comment">// 同上</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> MR_DATUM    5  <span class="comment">// 基准点位于输出文本的右侧中间（Middle Right）位置</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> CR_DATUM    5  <span class="comment">// 同上</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> BL_DATUM    6  <span class="comment">// 基准点位于输出文本的底部左侧（Bottom Left）位置</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> BC_DATUM    7  <span class="comment">// 基准点位于输出文本的底部中间（Bottom Centre）位置</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> BR_DATUM    8  <span class="comment">// 基准点位于输出文本的底部右侧（Bottom Right）位置</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> L_BASELINE  9  <span class="comment">// 左侧字符基准线（Left Character Baseline）</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> C_BASELINE 10  <span class="comment">// 中间字符基准线（Centre Character Baseline）</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> R_BASELINE 11  <span class="comment">// 右侧字符基准线（Right Character Baseline）</span></span></span><br></pre></td></tr></table></figure><p>除此之外，<strong>TFT_eSPI</strong>库还提供了如下一系列文本输出相关的辅助函数：</p><table><colgroup><col style="width: 37%"><col style="width: 62%"></colgroup><thead><tr><th style="text-align: left;">API 方法</th><th style="text-align: left;">功能描述</th></tr></thead><tbody><tr><td style="text-align: left;"><code>void setTextFont(uint8_t f)</code></td><td style="text-align: left;">设置当前所要显示文本的字体。</td></tr><tr><td style="text-align: left;"><code>void setTextSize(uint8_t s)</code></td><td style="text-align: left;">设置文本放大倍数（自定义字体无效），参数<code>s</code> 的取值范围介于 1 ~ 7 之间。</td></tr><tr><td style="text-align: left;"><code>void setTextColor(uint16_t c)</code></td><td style="text-align: left;">设置字体颜色（背景为透明）。</td></tr><tr><td style="text-align: left;"><code>void setTextColor(uint16_t c, uint16_t b)</code></td><td style="text-align: left;">设置字体的颜色以及其背景色。</td></tr><tr><td style="text-align: left;"><code>void setTextWrap(bool wrapX, bool wrapY)</code></td><td style="text-align: left;">设置文本是否自动换行。</td></tr><tr><td style="text-align: left;"><code>void setTextPadding(uint16_t x_width)</code></td><td style="text-align: left;">设置填充宽度（以像素为单位），将会擦除之前的文本内容。</td></tr><tr><td style="text-align: left;"><code>void getTextPadding(void)</code></td><td style="text-align: left;">获取填充宽度（以像素为单位）。</td></tr></tbody></table><p>下面的示例代码，会向 <strong>UINIO-Monitor</strong>屏幕<strong>从上至下</strong>依次打印 <code>Hello UinIO.com</code>字符串内容：</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;SPI.h&gt;</span></span></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;TFT_eSPI.h&gt;</span></span></span><br><span class="line"></span><br><span class="line">TFT_eSPI tft = <span class="built_in">TFT_eSPI</span>();  <span class="comment">// 创建 TFT_eSPI 对象</span></span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">setup</span><span class="params">(<span class="type">void</span>)</span> </span>&#123;</span><br><span class="line">  tft.<span class="built_in">init</span>();                              <span class="comment">// 重置然后初始化 TFT 显示相关的寄存器</span></span><br><span class="line">  tft.<span class="built_in">setRotation</span>(<span class="number">0</span>);                      <span class="comment">// 调整屏幕方向，参数为 1 表示旋转 90° 度，为 2 表示旋转 180° 度，为 3 表示旋转 270° 度</span></span><br><span class="line">  tft.<span class="built_in">fillScreen</span>(TFT_BLACK);               <span class="comment">// 设置 TFT 屏幕的背景颜色</span></span><br><span class="line">  tft.<span class="built_in">setTextColor</span>(TFT_WHITE, TFT_BLACK);  <span class="comment">// 设置 TFT 屏幕显示文本字体的颜色以及显示背景色</span></span><br><span class="line">  tft.<span class="built_in">setTextSize</span>(<span class="number">2</span>);                      <span class="comment">// 设置文本字体的放大倍数</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* print/f/ln 系列文本打印函数 ... */</span></span><br><span class="line">  tft.<span class="built_in">println</span>(<span class="string">&quot;Hello UinIO.com&quot;</span>);                <span class="comment">// 换行打印字符串</span></span><br><span class="line">  tft.<span class="built_in">printf</span>(<span class="string">&quot;Hello UinIO.com\n&quot;</span>);               <span class="comment">// 格式化打印字符串</span></span><br><span class="line">  tft.<span class="built_in">print</span>(<span class="string">&quot;Hello UinIO.com&quot;</span>);                  <span class="comment">// 直接打印字符串</span></span><br><span class="line"></span><br><span class="line">  <span class="comment">/* drawXxx() 系列文本绘制函数 */</span></span><br><span class="line">  tft.<span class="built_in">drawString</span>(<span class="string">&quot;Hello UinIO.com&quot;</span>, <span class="number">0</span>, <span class="number">50</span>, <span class="number">2</span>);   <span class="comment">// 绘制字符串</span></span><br><span class="line">  tft.<span class="built_in">drawFloat</span>(<span class="number">2023.12</span>, <span class="number">2</span>, <span class="number">0</span>, <span class="number">90</span>);              <span class="comment">// 绘制符点数</span></span><br><span class="line">  tft.<span class="built_in">drawNumber</span>(<span class="number">610000</span>, <span class="number">0</span>, <span class="number">115</span>);                <span class="comment">// 绘制数字</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">loop</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  <span class="comment">/* ... 需要循环执行的 TFT_eSPI 显示控制代码 ... */</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><h2 id="自定义字体">自定义字体</h2><p><strong>TFT_eSPI</strong> 库在其安装目录<code>TFT_eSPI\Tools\Create_Smooth_Font\Create_font</code>下面提供了处理自定义字体的 <strong>Create_font</strong>工具，其中包含有如下源文件和目录：</p><ul><li><code>data</code> 目录：用于存放 <code>.ttf</code> 以及<code>.otf</code> 字体文件。</li><li><code>FontFiles</code> 目录：保存的是转换处理之后所获得的<code>.vlw</code> 字体文件。</li><li><code>Create_font.pde</code> 工程文件：用于将自定义字体，从 Unicode编码转换为 <code>.vlw</code> 格式的字体文件（后续需要再进一步转换为<code>.h</code> 文件）。</li></ul><h3 id="processing-生成-.vlw-字体文件">Processing 生成 .vlw字体文件</h3><p><a href="https://processing.org/download"><strong>Processing</strong></a>是一款用于图像处理的开源编程语言与开发环境，通过其可以打开位于<strong>TFT_eSPI</strong> 库安装目录<code>TFT_eSPI\Tools\Create_Smooth_Font\Create_font</code>下面，用于制作<strong>自定义字体</strong>的 Processing 工程文件<code>Create_font.pde</code>：</p><p><img src="/Project/UINIO-Monitor/Processing-1.png"></p><p>将下面的代码复制到 <code>Create_font.pde</code> 的用户配置参数注释<code>USER CONFIGURED PARAMETERS</code>所在的位置，并且替换掉原来的内容：</p><figure class="highlight java"><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></pre></td><td class="code"><pre><span class="line"><span class="comment">//                       &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; USER CONFIGURED PARAMETERS START HERE &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;</span></span><br><span class="line"><span class="type">int</span> <span class="variable">fontNumber</span> <span class="operator">=</span> -<span class="number">1</span>; <span class="comment">// 字体编号，值为 -1 表示使用下面的 fontName 设置，&gt;=0 则表示使用系统字体编号</span></span><br><span class="line"></span><br><span class="line"><span class="type">String</span> <span class="variable">fontName</span> <span class="operator">=</span> <span class="string">&quot;SourceHanSansSC-Bold&quot;</span>;  <span class="comment">// 自定义字体文件的名称</span></span><br><span class="line"><span class="comment">// String fontType = &quot;.ttf&quot;;</span></span><br><span class="line"><span class="type">String</span> <span class="variable">fontType</span> <span class="operator">=</span> <span class="string">&quot;.otf&quot;</span>;   <span class="comment">// 自定义字体文件的后缀</span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span>  <span class="variable">fontSize</span> <span class="operator">=</span> <span class="number">14</span>;        <span class="comment">// 字体的像素大小</span></span><br><span class="line"></span><br><span class="line"><span class="type">int</span> <span class="variable">displayFontSize</span> <span class="operator">=</span> <span class="number">14</span>;  <span class="comment">// Processing 草图弹出窗口的字体大小（可以和上面的 fontSize 不同）</span></span><br><span class="line"></span><br><span class="line"><span class="comment">/* 当前所使用 Unicode 编码的起始码与结束码（适用于字符较少的英文或拉丁字体）*/</span></span><br><span class="line"><span class="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span>[] unicodeBlocks = &#123;</span><br><span class="line">  <span class="number">0x0021</span>, <span class="number">0x007E</span>, <span class="comment">// 该 Unicode 块包含了常见的符号与所有的大小写英文字母</span></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="keyword">static</span> <span class="keyword">final</span> <span class="type">int</span>[] specificUnicodes = &#123;</span><br><span class="line">  <span class="number">0x6210</span>, <span class="number">0x90fd</span>, <span class="comment">// 中文汉字 &quot;成都&quot; 的 Unicode 编码</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="comment">//                       &gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt;&gt; USER CONFIGURED PARAMETERS END HERE &lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;&lt;</span></span><br></pre></td></tr></table></figure><p>接下来，就可以根据下面列出的步骤，依次进行相关的处理和操作：</p><ol type="1"><li>使用<a href="http://www.jsons.cn/unicode">在线中文转 Uinicode工具</a>，获得当前所需中文汉字的 Unicode 编码，然后将转换结果当中的<code>\u</code> 替换为 <code>0x</code>，最后将结果填写到<code>Create_font.pde</code> 工程源文件的<code>specificUnicodes()</code> 函数里。</li><li>紧接着把<strong>思源黑体</strong>的字体文件<code>SourceHanSansSC-Bold.otf</code> 复制到<code>TFT_eSPI\Tools\Create_Smooth_Font\Create_font</code> 路径下面的<code>data</code> 目录，同时把 <code>Create_font.pde</code> 里的<code>fontName</code> 变量修改为字体的文件名称<code>SourceHanSansSC-Bold</code>，而 <code>fontType</code> 变量修改为<code>.otf</code>。</li><li>完成上述步骤之后，点击 <strong>Processing</strong>工具顶部的【运行】按钮，就会弹出下面的提示框，展示当前生成完毕的字体内容。</li></ol><p><img src="/Project/UINIO-Monitor/Processing-2.png"></p><p>与此同时，就会在<code>TFT_eSPI\Tools\Create_Smooth_Font\Create_font</code> 路径下面的<code>FontFiles</code> 目录里，发现刚才已经转换完成了的<code>SourceHanSansSC-Bold14.vlw</code> 文件：</p><figure class="highlight bash"><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></pre></td><td class="code"><pre><span class="line">D:\Workspace\Workspace_Arduino\libraries\TFT_eSPI\Tools\Create_Smooth_Font\Create_font\FontFiles</span><br><span class="line">λ <span class="built_in">ls</span></span><br><span class="line"></span><br><span class="line">SourceHanSansSC-Bold14.vlw  System_Font_List.txt</span><br></pre></td></tr></table></figure><h3 id="将-.vlw-转换为-.h-头文件">将 .vlw 转换为 .h 头文件</h3><p>接下来，继续通过<a href="https://tomeko.net/online_tools/file_to_hex.php?lang=zh">在线文件十六进制转换器</a>,或者该网站上提供的 <code>bin2hex.exe</code> 程序，把前面生成的<code>SourceHanSansSC-Bold14.vlw</code>文件转换为<strong>十六进制</strong>的格式：</p><p><img src="/Project/UINIO-Monitor/Processing-3.png"></p><p>此时可以打开 <strong>Arduino IDE</strong>新建一个草图工程，接着在工程文件的根目录再新建一个<code>font_chengdu.h</code>头文件（用于保存上述十六进制编码），把上面获得的十六进制编码拷贝到下面的<code>font_chengdu</code> 数组变量当中，就成功创建出了可供<strong>TFT_eSPI</strong> 库使用的 <code>font_chengdu.h</code>字体头文件：</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;pgmspace.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="type">const</span> <span class="type">uint8_t</span> font_chengdu[] PROGMEM = &#123;</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x02</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x0B</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x0E</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x0C</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x03</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x62</span>, <span class="number">0x10</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x10</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x0E</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x0E</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x0D</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x90</span>, <span class="number">0xFD</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x0E</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x0E</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x0E</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x0C</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x03</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xBF</span>, <span class="number">0xE9</span>, <span class="number">0x3E</span>, <span class="number">0xE3</span>, <span class="number">0x57</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC2</span>, <span class="number">0xF8</span>, <span class="number">0x2C</span>, <span class="number">0xD7</span>, <span class="number">0xFF</span>, <span class="number">0x5A</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x4A</span>, <span class="number">0xA3</span>, <span class="number">0xA3</span>, <span class="number">0xA3</span>, <span class="number">0xA3</span>,</span><br><span class="line">  <span class="number">0xA3</span>, <span class="number">0xE8</span>, <span class="number">0xFE</span>, <span class="number">0xA3</span>, <span class="number">0xAF</span>, <span class="number">0xFE</span>, <span class="number">0xAD</span>, <span class="number">0x42</span>, <span class="number">0x00</span>, <span class="number">0x73</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>,</span><br><span class="line">  <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x67</span>, <span class="number">0x00</span>, <span class="number">0x73</span>, <span class="number">0xFF</span>, <span class="number">0x4B</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x95</span>, <span class="number">0xFF</span>, <span class="number">0x25</span>,</span><br><span class="line">  <span class="number">0x05</span>, <span class="number">0x27</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x73</span>, <span class="number">0xFF</span>, <span class="number">0xA8</span>, <span class="number">0x83</span>, <span class="number">0x83</span>, <span class="number">0x63</span>, <span class="number">0x76</span>, <span class="number">0xFF</span>, <span class="number">0x4A</span>, <span class="number">0x58</span>, <span class="number">0xFF</span>,</span><br><span class="line">  <span class="number">0x79</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x76</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xBD</span>, <span class="number">0x57</span>, <span class="number">0xFF</span>, <span class="number">0x6F</span>, <span class="number">0xC4</span>, <span class="number">0xFD</span>, <span class="number">0x20</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x82</span>, <span class="number">0xFF</span>, <span class="number">0x3F</span>, <span class="number">0x00</span>, <span class="number">0xE4</span>, <span class="number">0xB7</span>, <span class="number">0x2E</span>, <span class="number">0xFF</span>, <span class="number">0xC4</span>, <span class="number">0xFF</span>, <span class="number">0xB8</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x8F</span>,</span><br><span class="line">  <span class="number">0xFF</span>, <span class="number">0x29</span>, <span class="number">0x00</span>, <span class="number">0xEB</span>, <span class="number">0xB1</span>, <span class="number">0x03</span>, <span class="number">0xF5</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x38</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x9D</span>, <span class="number">0xFF</span>, <span class="number">0x13</span>,</span><br><span class="line">  <span class="number">0x01</span>, <span class="number">0xFA</span>, <span class="number">0xA5</span>, <span class="number">0x00</span>, <span class="number">0xC3</span>, <span class="number">0xFF</span>, <span class="number">0xA8</span>, <span class="number">0x00</span>, <span class="number">0x59</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xC1</span>, <span class="number">0xFC</span>, <span class="number">0x5B</span>, <span class="number">0x95</span>, <span class="number">0xFF</span>,</span><br><span class="line">  <span class="number">0x8B</span>, <span class="number">0x44</span>, <span class="number">0xF8</span>, <span class="number">0xFF</span>, <span class="number">0x67</span>, <span class="number">0x00</span>, <span class="number">0xF5</span>, <span class="number">0x6C</span>, <span class="number">0x06</span>, <span class="number">0xF3</span>, <span class="number">0xCF</span>, <span class="number">0x6E</span>, <span class="number">0xFF</span>, <span class="number">0xE4</span>, <span class="number">0x89</span>, <span class="number">0xF5</span>,</span><br><span class="line">  <span class="number">0xFD</span>, <span class="number">0xFC</span>, <span class="number">0xDB</span>, <span class="number">0x3D</span>, <span class="number">0xFF</span>, <span class="number">0x58</span>, <span class="number">0x5D</span>, <span class="number">0xFF</span>, <span class="number">0x8D</span>, <span class="number">0x00</span>, <span class="number">0x01</span>, <span class="number">0x43</span>, <span class="number">0xFF</span>, <span class="number">0xF1</span>, <span class="number">0x4C</span>, <span class="number">0x74</span>,</span><br><span class="line">  <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFB</span>, <span class="number">0x19</span>, <span class="number">0x2C</span>, <span class="number">0xD8</span>, <span class="number">0x26</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x7A</span>, <span class="number">0x29</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x5C</span>, <span class="number">0xA4</span>,</span><br><span class="line">  <span class="number">0x56</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x09</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x03</span>, <span class="number">0xDB</span>, <span class="number">0x74</span>, <span class="number">0x00</span>, <span class="number">0x1E</span>, <span class="number">0x15</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x02</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x5B</span>,</span><br><span class="line">  <span class="number">0x6E</span>, <span class="number">0xFF</span>, <span class="number">0xBA</span>, <span class="number">0x68</span>, <span class="number">0xB1</span>, <span class="number">0xE2</span>, <span class="number">0xE1</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xED</span>, <span class="number">0x4A</span>, <span class="number">0x00</span>, <span class="number">0xD7</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>,</span><br><span class="line">  <span class="number">0xFF</span>, <span class="number">0xFD</span>, <span class="number">0xFD</span>, <span class="number">0x7C</span>, <span class="number">0xDF</span>, <span class="number">0xE6</span>, <span class="number">0x93</span>, <span class="number">0xCD</span>, <span class="number">0xFF</span>, <span class="number">0x55</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x03</span>, <span class="number">0xFF</span>, <span class="number">0x87</span>, <span class="number">0xAB</span>,</span><br><span class="line">  <span class="number">0xF9</span>, <span class="number">0x17</span>, <span class="number">0xDF</span>, <span class="number">0xC3</span>, <span class="number">0x00</span>, <span class="number">0xBD</span>, <span class="number">0xF1</span>, <span class="number">0x08</span>, <span class="number">0x34</span>, <span class="number">0x73</span>, <span class="number">0x76</span>, <span class="number">0xFF</span>, <span class="number">0xC7</span>, <span class="number">0xFE</span>, <span class="number">0xDB</span>, <span class="number">0x4D</span>,</span><br><span class="line">  <span class="number">0xDF</span>, <span class="number">0xC3</span>, <span class="number">0x10</span>, <span class="number">0xFA</span>, <span class="number">0x95</span>, <span class="number">0x00</span>, <span class="number">0x73</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xAB</span>, <span class="number">0xDF</span>, <span class="number">0xC3</span>,</span><br><span class="line">  <span class="number">0x66</span>, <span class="number">0xFF</span>, <span class="number">0x2C</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x4A</span>, <span class="number">0xE7</span>, <span class="number">0xF2</span>, <span class="number">0x2F</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0xDF</span>, <span class="number">0xC3</span>, <span class="number">0x7B</span>, <span class="number">0xFD</span>,</span><br><span class="line">  <span class="number">0x40</span>, <span class="number">0x00</span>, <span class="number">0x0C</span>, <span class="number">0x99</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x33</span>, <span class="number">0xDF</span>, <span class="number">0xC3</span>, <span class="number">0x01</span>, <span class="number">0xC4</span>, <span class="number">0xE0</span>, <span class="number">0x05</span>,</span><br><span class="line">  <span class="number">0x9F</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x94</span>, <span class="number">0x53</span>, <span class="number">0x94</span>, <span class="number">0xFF</span>, <span class="number">0x33</span>, <span class="number">0xDF</span>, <span class="number">0xC3</span>, <span class="number">0x00</span>, <span class="number">0x67</span>, <span class="number">0xFF</span>, <span class="number">0x31</span>, <span class="number">0x33</span>, <span class="number">0xF6</span>,</span><br><span class="line">  <span class="number">0xFF</span>, <span class="number">0x87</span>, <span class="number">0x3F</span>, <span class="number">0x87</span>, <span class="number">0xFF</span>, <span class="number">0x33</span>, <span class="number">0xDF</span>, <span class="number">0xC3</span>, <span class="number">0x00</span>, <span class="number">0x48</span>, <span class="number">0xFF</span>, <span class="number">0x51</span>, <span class="number">0x00</span>, <span class="number">0x31</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>,</span><br><span class="line">  <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x33</span>, <span class="number">0xDF</span>, <span class="number">0xC5</span>, <span class="number">0x91</span>, <span class="number">0xD7</span>, <span class="number">0xFF</span>, <span class="number">0x33</span>, <span class="number">0x00</span>, <span class="number">0x23</span>, <span class="number">0xFF</span>, <span class="number">0x94</span>, <span class="number">0x53</span>, <span class="number">0x94</span>,</span><br><span class="line">  <span class="number">0xFF</span>, <span class="number">0x33</span>, <span class="number">0xDF</span>, <span class="number">0xC3</span>, <span class="number">0xC1</span>, <span class="number">0xF7</span>, <span class="number">0x8E</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x23</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0xFF</span>, <span class="number">0x33</span>,</span><br><span class="line">  <span class="number">0xDF</span>, <span class="number">0xC3</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x20</span>, <span class="number">0xE3</span>, <span class="number">0x55</span>, <span class="number">0x00</span>, <span class="number">0x3E</span>, <span class="number">0xA7</span>, <span class="number">0x22</span>, <span class="number">0xCE</span>, <span class="number">0xB4</span>,</span><br><span class="line">  <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x00</span>, <span class="number">0x11</span>, <span class="number">0xE6</span>, <span class="number">0x80</span>, <span class="number">0x9D</span>, <span class="number">0xE6</span>, <span class="number">0xBA</span>, <span class="number">0x90</span>, <span class="number">0xE9</span>, <span class="number">0xBB</span>, <span class="number">0x91</span>, <span class="number">0xE4</span>,</span><br><span class="line">  <span class="number">0xBD</span>, <span class="number">0x93</span>, <span class="number">0x20</span>, <span class="number">0x42</span>, <span class="number">0x6F</span>, <span class="number">0x6C</span>, <span class="number">0x64</span>, <span class="number">0x00</span>, <span class="number">0x14</span>, <span class="number">0x53</span>, <span class="number">0x6F</span>, <span class="number">0x75</span>, <span class="number">0x72</span>, <span class="number">0x63</span>, <span class="number">0x65</span>, <span class="number">0x48</span>,</span><br><span class="line">  <span class="number">0x61</span>, <span class="number">0x6E</span>, <span class="number">0x53</span>, <span class="number">0x61</span>, <span class="number">0x6E</span>, <span class="number">0x73</span>, <span class="number">0x53</span>, <span class="number">0x43</span>, <span class="number">0x2D</span>, <span class="number">0x42</span>, <span class="number">0x6F</span>, <span class="number">0x6C</span>, <span class="number">0x64</span>, <span class="number">0x01</span></span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><h3 id="显示自定义字体">显示自定义字体</h3><p>在刚才新建的 Arduino 草图工程源代码里边，通过预处理命令<code>#include</code> 包含上面建立的 <code>font_chengdu.h</code>字体头文件，然后使用 <code>loadFont()</code> 函数加载字体，再分别通过<code>print()</code> 和 <code>drawString()</code>函数向屏幕输出思源黑体的<strong>成都</strong>，最后在使用完成之后调用<code>unloadFont()</code> 函数卸载字体：</p><figure class="highlight cpp"><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></pre></td><td class="code"><pre><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&lt;TFT_eSPI.h&gt;</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">include</span> <span class="string">&quot;font_chengdu.h&quot;</span>  <span class="comment">// 包含自定义字库头文件</span></span></span><br><span class="line"></span><br><span class="line">TFT_eSPI tft = <span class="built_in">TFT_eSPI</span>();</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">setup</span><span class="params">()</span> </span>&#123;</span><br><span class="line">  <span class="comment">/* 初始化 TFT_eSPI 设置 */</span></span><br><span class="line">  tft.<span class="built_in">init</span>();</span><br><span class="line">  tft.<span class="built_in">setRotation</span>(<span class="number">0</span>);</span><br><span class="line">  tft.<span class="built_in">fillScreen</span>(TFT_BLACK);</span><br><span class="line">  tft.<span class="built_in">setTextColor</span>(TFT_WHITE);</span><br><span class="line"></span><br><span class="line">  tft.<span class="built_in">loadFont</span>(font_chengdu);     <span class="comment">// 加载 font_chengdu 字库</span></span><br><span class="line"></span><br><span class="line">  tft.<span class="built_in">print</span>(<span class="string">&quot;成都&quot;</span>);               <span class="comment">// 第 1 行输出汉字</span></span><br><span class="line">  tft.<span class="built_in">drawString</span>(<span class="string">&quot;成都&quot;</span>, <span class="number">0</span>, <span class="number">16</span>);   <span class="comment">// 第 2 行输出汉字</span></span><br><span class="line">  tft.<span class="built_in">unloadFont</span>();               <span class="comment">// 卸载字库资源</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"><span class="function"><span class="type">void</span> <span class="title">loop</span><span class="params">()</span> </span>&#123;&#125;</span><br></pre></td></tr></table></figure><h2 id="tft_ewidget-图形界面库">TFT_eWidget 图形界面库</h2><p><strong>TFT_eSPI</strong> 库的作者还提供了一个简单小巧的 <a href="https://github.com/Bodmer/TFT_eWidget">TFT_eWidget</a>图形界面库，不过 Arduino 当中通常使用 <strong>LVGL</strong> 结合<strong>TFT_eSPI</strong>来绘制图形界面，所以该库的运用并不广泛，本文就不再赘述，有需要的朋友可以直接参考开源项目当中的说明文档。</p>]]></content>
    
    
    <summary type="html">&lt;p&gt;&lt;a href=&quot;https://github.com/uinika/UINIO-Monitor&quot;&gt;&lt;strong&gt;UINIO-Monitor&lt;/strong&gt;&lt;/a&gt;
同时拼接有 &lt;code&gt;128×64&lt;/code&gt; 分辨率 &lt;strong&gt;SSD1315&lt;/strong&gt; 驱动的
0.96 英寸 OLED 显示屏，&lt;code&gt;160×80&lt;/code&gt; 分辨率
&lt;strong&gt;ST7735&lt;/strong&gt; 驱动的 0.96 英寸 LCD
显示屏，&lt;code&gt;240×240&lt;/code&gt; 分辨率 &lt;strong&gt;ST7789&lt;/strong&gt; 驱动的 1.3
英寸 LCD 显示屏。以及采用相同驱动芯片，但是分辨率分别为
&lt;code&gt;240×320&lt;/code&gt; 与 &lt;code&gt;240×280&lt;/code&gt; 的 2.4 英寸以及 1.69 英寸
LCD 显示屏。所有屏幕全部板载有 &lt;code&gt;0.5mm&lt;/code&gt; 间距的
&lt;strong&gt;FPC&lt;/strong&gt; 柔性排线连接器，同时还引出 &lt;code&gt;2.54mm&lt;/code&gt;
间距的直插排针，便于通过杜邦线快速搭建实验电路。&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/Project/UINIO-Monitor/logo.png&quot;&gt;&lt;/p&gt;
&lt;p&gt;之前由我设计制作并且开源出来的 &lt;a href=&quot;https://github.com/uinika/UINIO-MCU-ESP32C3&quot;&gt;&lt;strong&gt;UINIO-MCU-ESP32C3&lt;/strong&gt;&lt;/a&gt;
和 &lt;a href=&quot;https://github.com/uinika/UINIO-MCU-ESP32S3&quot;&gt;&lt;strong&gt;UINIO-MCU-ESP32S3&lt;/strong&gt;&lt;/a&gt;
两款核心板，分别基于乐鑫科技的 &lt;strong&gt;ESP32-C3&lt;/strong&gt; (RISC-V) 与
&lt;strong&gt;ESP32-S3&lt;/strong&gt; (Xtensa) 微控制器（更多玩法可以参考之前撰写的
&lt;a href=&quot;http://uinio.com/Project/Arduino-ESP32/&quot;&gt;《基于 UINIO-MCU-ESP32
的 Arduino 进阶教程》&lt;/a&gt;
一文）。而本篇文章就会采用这两款核心板，以及乐鑫官方的
&lt;strong&gt;Arduino-ESP32&lt;/strong&gt; 板级支持包，结合 &lt;a href=&quot;https://github.com/olikraus/u8g2&quot;&gt;&lt;strong&gt;U8G2&lt;/strong&gt;&lt;/a&gt; 和 &lt;a href=&quot;https://github.com/Bodmer/TFT_eSPI&quot;&gt;&lt;strong&gt;TFT_eSPI&lt;/strong&gt;&lt;/a&gt;
两款开源显示库，帮助大家快速上手 &lt;strong&gt;UINIO-Monitor&lt;/strong&gt; 系列里的
5 款显示屏。&lt;/p&gt;</summary>
    
    
    
    <category term="UINIO 开源项目资料" scheme="http://www.uinio.com/categories/UINIO-%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE%E8%B5%84%E6%96%99/"/>
    
    
    <category term="Arduino" scheme="http://www.uinio.com/tags/Arduino/"/>
    
  </entry>
  
</feed>
