<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/rss/feed.xsl" type="text/xsl"?><rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>氵工的博客</title><description>ヾ(≧▽≦*)o</description><link>https://729dhs.site</link><item><title>轮腿机器人二自由度闭式连杆机构正逆运动学推导</title><link>https://729dhs.site/post/2dof-linkage-forward-inverse-kinematics</link><guid isPermaLink="false">2dof-linkage-forward-inverse-kinematics</guid><description>轮腿机器人腿部 2-DOF 双平行四边形连杆机构的正逆运动学解析推导，以及 Python 数值实现。机构最终等价于标准 2R 机械臂。</description><pubDate>Mon, 04 May 2026 06:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;1. 问题背景&lt;a href=&quot;#1-问题背景&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;轮腿式机器人（wheel-legged robot）的每条腿需要同时具备 &lt;strong&gt;轮式滚动&lt;/strong&gt; 和 &lt;strong&gt;腿部越障&lt;/strong&gt; 两种能力。本文讨论的机构设计采用两个同轴电机，通过一套 8 字形双平行四边形连杆将动力传递到轮端，实现腿部摆动与轮子转向的解耦控制。&lt;/p&gt;
&lt;p&gt;与传统带传动或齿轮传动方案相比，这种全连杆机构具有 &lt;strong&gt;零回程差、结构刚度高、无磨损件&lt;/strong&gt; 等优点，特别适合需要高精度末端位置控制的轮腿机器人应用。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/Kinematics/p2.png&quot; alt=&quot;轮腿实物图&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img src=&quot;/img/Note/Kinematics/p1.png&quot; alt=&quot;仿真图&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;pre&gt;flowchart TD
  M[&quot;电机 A (θa)&quot;] --&amp;gt; A[&quot;bar_a（三副杆 O-P1-P2）&quot;]
  M2[&quot;电机 B (θb)&quot;] --&amp;gt; B[&quot;bar_b（二副杆 O-P3）&quot;]
  A --&amp;gt; D[&quot;bar_d（三副直杆 P1-P4-P5）&quot;]
  B --&amp;gt; C[&quot;bar_c（二副杆 P3-P4）&quot;]
  C --&amp;gt; D
  D --&amp;gt; E[&quot;bar_e（二副杆 P5-P6）&quot;]
  A --&amp;gt; F[&quot;bar_f（三副直杆 P2-P6-P7）&quot;]
  E --&amp;gt; F
  F --&amp;gt; W[&quot;P7 — 轮毂电机（末端）&quot;]&lt;/pre&gt;
&lt;p&gt;两个平行四边形嵌套成 8 字形：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;平行四边形 1&lt;/strong&gt;：O – P1 – P4 – P3，边长 48.4 × 57.3 mm&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;平行四边形 2&lt;/strong&gt;：P1 – P2 – P6 – P5，边长 59 × 32.4 mm&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;p&gt;关键之处在于：所有三副杆（bar_a、bar_d、bar_f）都是 &lt;strong&gt;直杆&lt;/strong&gt;（三点共线）。这个几何约束是后续解析简化的核心前提。&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;2. 正运动学推导&lt;a href=&quot;#2-正运动学推导&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;正运动学的目标是：给定电机转角 &lt;span&gt;&lt;span&gt;θa,θb\theta_a, \theta_b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，求末端 &lt;span&gt;&lt;span&gt;P7P_7&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的位置。&lt;/p&gt;
&lt;h3&gt;2.1 点坐标逐步求解&lt;a href=&quot;#21-点坐标逐步求解&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Step 1 — bar_a 上的 P1、P2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;以 O 为原点，绕 &lt;span&gt;&lt;span&gt;θa\theta_a&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 旋转：&lt;/p&gt;
&lt;span&gt;&lt;span&gt;&lt;span&gt;P1=LOP1[cos⁡θasin⁡θa]=48.4[cos⁡θasin⁡θa]P2=LOP2[cos⁡θasin⁡θa]=107.4[cos⁡θasin⁡θa]\begin{aligned}
P_1 &amp;amp;= L_{OP1} \begin{bmatrix}\cos\theta_a \\ \sin\theta_a\end{bmatrix}
      = 48.4 \begin{bmatrix}\cos\theta_a \\ \sin\theta_a\end{bmatrix} \\[6pt]
P_2 &amp;amp;= L_{OP2} \begin{bmatrix}\cos\theta_a \\ \sin\theta_a\end{bmatrix}
      = 107.4 \begin{bmatrix}\cos\theta_a \\ \sin\theta_a\end{bmatrix}
\end{aligned}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;OP&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;cos&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;sin&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;48.4&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;cos&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;sin&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;OP&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;cos&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;sin&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;107.4&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;cos&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;sin&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;这里 &lt;span&gt;&lt;span&gt;LOP2=48.4+59=107.4L_{OP2} = 48.4 + 59 = 107.4&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;OP&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;48.4&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;59&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;107.4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，因为 bar_a 是直杆，P1 在 O–P2 连线上。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2 — bar_b 上的 P3&lt;/strong&gt;&lt;/p&gt;
&lt;span&gt;&lt;span&gt;&lt;span&gt;P3=Lb[cos⁡θbsin⁡θb]=57.3[cos⁡θbsin⁡θb]P_3 = L_b \begin{bmatrix}\cos\theta_b \\ \sin\theta_b\end{bmatrix}
     = 57.3 \begin{bmatrix}\cos\theta_b \\ \sin\theta_b\end{bmatrix}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;cos&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;sin&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;57.3&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;cos&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;sin&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;&lt;strong&gt;Step 3 — bar_d 上的 P4（两圆相交）&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;由平行四边形 1 可知 &lt;span&gt;&lt;span&gt;∣P1P4∣|P_1P_4|&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∣&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;∣&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;、&lt;span&gt;&lt;span&gt;∣P3P4∣|P_3P_4|&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∣&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;∣&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 为固定值，故 P4 是两圆的交点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;圆心 &lt;span&gt;&lt;span&gt;P1P_1&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，半径 &lt;span&gt;&lt;span&gt;LP1P4=57.3L_{P1P4} = 57.3&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;57.3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;圆心 &lt;span&gt;&lt;span&gt;P3P_3&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，半径 &lt;span&gt;&lt;span&gt;Lc=48.4L_c = 48.4&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;48.4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;两圆相交的解析求解过程如下。令向量 &lt;span&gt;&lt;span&gt;v=P3−P1\mathbf{v} = P_3 - P_1&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，两圆心距离 &lt;span&gt;&lt;span&gt;d=∥v∥d = \|\mathbf{v}\|&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∥&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;∥&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，则：&lt;/p&gt;
&lt;span&gt;&lt;span&gt;&lt;span&gt;a=LP1P42−Lc2+d22dh=LP1P42−a2P4=P1+adv±hdRv\begin{aligned}
a &amp;amp;= \frac{L_{P1P4}^2 - L_c^2 + d^2}{2d} \\[4pt]
h &amp;amp;= \sqrt{L_{P1P4}^2 - a^2} \\[4pt]
P_4 &amp;amp;= P_1 + \frac{a}{d}\mathbf{v} \pm \frac{h}{d}\mathbf{R}\mathbf{v}
\end{aligned}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;c&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;±&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;h&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;Rv&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;其中 &lt;span&gt;&lt;span&gt;R=[0−110]\mathbf{R} = \begin{bmatrix}0 &amp;amp; -1 \\ 1 &amp;amp; 0\end{bmatrix}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;R&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 为 &lt;span&gt;&lt;span&gt;90∘90^\circ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;9&lt;/span&gt;&lt;span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;∘&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 旋转矩阵，&lt;span&gt;&lt;span&gt;±\pm&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;±&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 号的选择对应两种装配模式，记作 &lt;span&gt;&lt;span&gt;branch_d=±1\mathrm{branch}\_d = \pm 1&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;branch&lt;/span&gt;&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;±&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。&lt;/p&gt;
&lt;h3&gt;2.2 核心简化：直杆约束&lt;a href=&quot;#22-核心简化直杆约束&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;得到 P4 后，bar_d 的方向角为：&lt;/p&gt;
&lt;span&gt;&lt;span&gt;&lt;span&gt;θd=atan2(P4−P1)\theta_d = \text{atan2}(P_4 - P_1)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;atan2&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;因为 bar_d 是 &lt;strong&gt;直杆&lt;/strong&gt;，P5 与 P1、P4 共线，且 &lt;span&gt;&lt;span&gt;∣P1P5∣=32.4|P_1P_5| = 32.4&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∣&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;∣&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;32.4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，所以：&lt;/p&gt;
&lt;span&gt;&lt;span&gt;&lt;span&gt;P5=P1+32.457.3(P4−P1)P_5 = P_1 + \frac{32.4}{57.3} (P_4 - P_1)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;57.3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;32.4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;代入平行四边形 2 的关系 &lt;span&gt;&lt;span&gt;P6=P2+P5−P1P_6 = P_2 + P_5 - P_1&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;6&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;5&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，消去 P5：&lt;/p&gt;
&lt;span&gt;&lt;span&gt;&lt;span&gt;P6=P2−32.457.3(P4−P1)P_6 = P_2 - \frac{32.4}{57.3} (P_4 - P_1)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;6&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;57.3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;32.4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;注意 &lt;span&gt;&lt;span&gt;P4−P1P_4 - P_1&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 的方向与 &lt;span&gt;&lt;span&gt;P3P_3&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 相同（平行四边形对边平行），而 &lt;span&gt;&lt;span&gt;P3=Lb[cos⁡θb,sin⁡θb]TP_3 = L_b[\cos\theta_b, \sin\theta_b]^T&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;3&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;cos&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;sin&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，于是：&lt;/p&gt;
&lt;span&gt;&lt;span&gt;&lt;span&gt;P6=P2−32.4[cos⁡θbsin⁡θb]P_6 = P_2 - 32.4 \begin{bmatrix}\cos\theta_b \\ \sin\theta_b\end{bmatrix}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;6&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;32.4&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;cos&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;sin&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;bar_f 同样是直杆，P7 在 P2→P6 的反方向延长线上，&lt;span&gt;&lt;span&gt;∣P2P7∣=128|P_2P_7| = 128&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∣&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;∣&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;128&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;：&lt;/p&gt;
&lt;span&gt;&lt;span&gt;&lt;span&gt;P7=P2+128[cos⁡θbsin⁡θb]P_7 = P_2 + 128 \begin{bmatrix}\cos\theta_b \\ \sin\theta_b\end{bmatrix}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;128&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;cos&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;sin&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;h3&gt;2.3 最终解析式&lt;a href=&quot;#23-最终解析式&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;将 &lt;span&gt;&lt;span&gt;P2=107.4[cos⁡θa,sin⁡θa]TP_2 = 107.4[\cos\theta_a, \sin\theta_a]^T&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;107.4&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;cos&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;sin&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;T&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 代入，得：&lt;/p&gt;
&lt;span&gt;&lt;span&gt;&lt;span&gt;P7=[107.4cos⁡θa+128cos⁡θb107.4sin⁡θa+128sin⁡θb]\boxed{P_7 = \begin{bmatrix}
107.4\cos\theta_a + 128\cos\theta_b \\
107.4\sin\theta_a + 128\sin\theta_b
\end{bmatrix}}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;[&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;107.4&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;cos&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;128&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;cos&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;107.4&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;sin&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;128&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;sin&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;infographic list-grid-badge-card&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;data&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  title 物理意义&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  desc 机构等价于一个标准 2R 平面机械臂&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  items&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - label 第一连杆&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      desc O → P₂，长 L₁ = 107.4 mm，角度 θa&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      icon mdi/link-variant&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - label 第二连杆&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      desc P₂ → P₇，长 L₂ = 128 mm，角度 θb&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      icon mdi/link-variant&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - label 末端&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      desc 轮毂电机位置 P₇&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      icon mdi/wheel&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;p&gt;这个结论非常优雅：&lt;strong&gt;无论双平行四边形如何弯折，末端 P₇ 的位置始终只依赖于两个电机的转角&lt;/strong&gt;，与中间所有连杆的姿态无关。这得益于直杆约束和嵌套平行四边形的几何特性——中间关节的运动学被完全&quot;消化&quot;掉了。&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;3. 逆运动学推导&lt;a href=&quot;#3-逆运动学推导&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;逆运动学：给定末端位置 &lt;span&gt;&lt;span&gt;P7=(x,y)P_7 = (x, y)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，求 &lt;span&gt;&lt;span&gt;θa,θb\theta_a, \theta_b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。&lt;/p&gt;
&lt;h3&gt;3.1 余弦定理&lt;a href=&quot;#31-余弦定理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;令 &lt;span&gt;&lt;span&gt;r=x2+y2r = \sqrt{x^2 + y^2}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;（P7 到原点的距离），&lt;span&gt;&lt;span&gt;ϕ=atan2(y,x)\phi = \text{atan2}(y, x)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;ϕ&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;atan2&lt;/span&gt;&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;由 2R 机械臂的几何关系：&lt;/p&gt;
&lt;span&gt;&lt;span&gt;&lt;span&gt;cos⁡α=r2+L12−L222L1r\cos\alpha = \frac{r^2 + L_1^2 - L_2^2}{2 L_1 r}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;cos&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;α&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;r&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;span&gt;α=arccos⁡(r2+107.42−12822×107.4×r)\alpha = \arccos\left(\frac{r^2 + 107.4^2 - 128^2}{2 \times 107.4 \times r}\right)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;α&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;arccos&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;107.4&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;×&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;r&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;107.&lt;/span&gt;&lt;span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;12&lt;/span&gt;&lt;span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;h3&gt;3.2 两个解&lt;a href=&quot;#32-两个解&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;span&gt;&lt;span&gt;&lt;span&gt;θa=ϕ±α\theta_a = \phi \pm \alpha&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;ϕ&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;±&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;α&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;正号对应 &lt;strong&gt;elbow-down&lt;/strong&gt;，负号对应 &lt;strong&gt;elbow-up&lt;/strong&gt;（两种臂型）。&lt;/p&gt;
&lt;span&gt;&lt;span&gt;&lt;span&gt;θb=atan2(y−L1sin⁡θa,  x−L1cos⁡θa)\theta_b = \text{atan2}\left(
  y - L_1\sin\theta_a,\;
  x - L_1\cos\theta_a
\right)&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;atan2&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;y&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;sin&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;cos&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;h3&gt;3.3 工作空间与奇异位形&lt;a href=&quot;#33-工作空间与奇异位形&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;工作空间是一个圆环：&lt;/p&gt;
&lt;span&gt;&lt;span&gt;&lt;span&gt;∣L1−L2∣≤r≤L1+L2|L_1 - L_2| \leq r \leq L_1 + L_2&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∣&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;∣&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≤&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≤&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;即 &lt;span&gt;&lt;span&gt;20.6 mm≤r≤235.4 mm20.6 \text{ mm} \leq r \leq 235.4 \text{ mm}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;20.6&lt;/span&gt;&lt;span&gt;&lt;span&gt; mm&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≤&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;≤&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;235.4&lt;/span&gt;&lt;span&gt;&lt;span&gt; mm&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;。&lt;/p&gt;
&lt;p&gt;三种奇异位形：&lt;/p&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;条件&lt;/th&gt;&lt;th&gt;含义&lt;/th&gt;&lt;th&gt;解的情况&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;span&gt;&lt;span&gt;r=L1+L2=235.4r = L_1 + L_2 = 235.4&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;235.4&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;完全伸展&lt;/td&gt;&lt;td&gt;单解（&lt;span&gt;&lt;span&gt;θa=θb\theta_a = \theta_b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span&gt;&lt;span&gt;r=∥L1−L2∥=20.6r = \|L_1 - L_2\| = 20.6&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;∥&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;L&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;∥&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;20.6&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;完全收缩&lt;/td&gt;&lt;td&gt;单解&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;span&gt;&lt;span&gt;r=0r = 0&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;r&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/td&gt;&lt;td&gt;末端与原点重合&lt;/td&gt;&lt;td&gt;无穷多解&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;在奇异位形附近，机构的传力性能会急剧下降——微小的末端力就可能在关节处产生很大的力矩。这也是 2R 机械臂的固有问题，在轨迹规划时需要避开奇异区域。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/Kinematics/p3.jpg&quot; alt=&quot;建模&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;h2&gt;4. 代码实现&lt;a href=&quot;#4-代码实现&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;4.1 两圆相交&lt;a href=&quot;#41-两圆相交&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;这是整个数值求解的几何基础——给定两个圆心和半径，求交点。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; circle_intersection&lt;/span&gt;&lt;span&gt;(c1, r1, c2, r2):&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &quot;&quot;&quot;返回 (p_left, p_right)，无解时返回 (None, None)。&quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    v &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; c2 &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; c1&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    d &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; np.linalg.norm(v)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; d &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; 1e-12&lt;/span&gt;&lt;span&gt;:          &lt;/span&gt;&lt;span&gt;# 同心圆&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        return&lt;/span&gt;&lt;span&gt; None&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;None&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; d &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; r1 &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; r2 &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 1e-10&lt;/span&gt;&lt;span&gt; or&lt;/span&gt;&lt;span&gt; d &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; abs&lt;/span&gt;&lt;span&gt;(r1 &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; r2) &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; 1e-10&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        return&lt;/span&gt;&lt;span&gt; None&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;None&lt;/span&gt;&lt;span&gt;  # 无交点&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    a &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (r1&lt;/span&gt;&lt;span&gt;**&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;span&gt; r2&lt;/span&gt;&lt;span&gt;**&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt; +&lt;/span&gt;&lt;span&gt; d&lt;/span&gt;&lt;span&gt;**&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;2.0&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; d)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    h &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; np.sqrt(&lt;/span&gt;&lt;span&gt;max&lt;/span&gt;&lt;span&gt;(r1&lt;/span&gt;&lt;span&gt;**&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;**&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0.0&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    p_mid &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; c1 &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; (a &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; d) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; v&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; h &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; 1e-10&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        return&lt;/span&gt;&lt;span&gt; p_mid.copy(), p_mid.copy()  &lt;/span&gt;&lt;span&gt;# 相切&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    perp &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; np.array([&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;v[&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;], v[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;]]) &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; d&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; p_mid &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; h &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; perp, p_mid &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; h &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; perp&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;通过 &lt;code&gt;perp&lt;/code&gt; 向量的正负号区分两个解——对应两种装配模式。&lt;/p&gt;
&lt;h3&gt;4.2 正运动学求解器&lt;a href=&quot;#42-正运动学求解器&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; solve_linkage&lt;/span&gt;&lt;span&gt;(theta_a, theta_b, params, prev_theta_d&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;None&lt;/span&gt;&lt;span&gt;, prev_theta_f&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;None&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    # 1. bar_a 上的 P1, P2&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    P1 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; rotate_vec(np.array([params.&lt;/span&gt;&lt;span&gt;L_OP1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0.0&lt;/span&gt;&lt;span&gt;]), theta_a)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    P2 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; rotate_vec(params._a2_local, theta_a)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    # 2. bar_b 上的 P3&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    P3 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; params.L_b &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; np.array([np.cos(theta_b), np.sin(theta_b)])&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    # 3. 两圆相交求 P4&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    p4_left, p4_right &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; circle_intersection(P1, params.&lt;/span&gt;&lt;span&gt;L_P1P4&lt;/span&gt;&lt;span&gt;, P3, params.L_c)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    # prev_theta_d 用于轨迹跟踪时保持分支连续性&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    # 4. bar_d 方向 → P5&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    theta_d &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; np.arctan2((P4 &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; P1)[&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;], (P4 &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; P1)[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    P5 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; P1 &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; rotate_vec(params._d5_local, theta_d)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    # 5. 两圆相交求 P6&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    p6_left, p6_right &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; circle_intersection(P2, params.&lt;/span&gt;&lt;span&gt;L_P2P6&lt;/span&gt;&lt;span&gt;, P5, params.L_e)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    # 6. bar_f 方向 → P7（末端）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    theta_f &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; np.arctan2((P6 &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; P2)[&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;], (P6 &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; P2)[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    P7 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; P2 &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; rotate_vec(params._f7_local, theta_f)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span&gt;&apos;P7&apos;&lt;/span&gt;&lt;span&gt;: P7, &lt;/span&gt;&lt;span&gt;&apos;theta_d&apos;&lt;/span&gt;&lt;span&gt;: theta_d, &lt;/span&gt;&lt;span&gt;&apos;theta_f&apos;&lt;/span&gt;&lt;span&gt;: theta_f, &lt;/span&gt;&lt;span&gt;...&lt;/span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;整个求解过程全部由三角函数和开方完成，&lt;strong&gt;无需任何迭代&lt;/strong&gt;，属于纯解析正解。&lt;/p&gt;
&lt;h3&gt;4.3 逆运动学&lt;a href=&quot;#43-逆运动学&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; solve_inverse&lt;/span&gt;&lt;span&gt;(P7_target, params, elbow&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    L1, L2 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; params.&lt;/span&gt;&lt;span&gt;L_OP2&lt;/span&gt;&lt;span&gt;, params.&lt;/span&gt;&lt;span&gt;L_P2P7&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    x, y &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; P7_target&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    r &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; np.hypot(x, y)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; r &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; L1 &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; L2 &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 1e-6&lt;/span&gt;&lt;span&gt; or&lt;/span&gt;&lt;span&gt; r &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; abs&lt;/span&gt;&lt;span&gt;(L1 &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; L2) &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; 1e-6&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        return&lt;/span&gt;&lt;span&gt; []  &lt;/span&gt;&lt;span&gt;# 超出工作空间&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    cos_alpha &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (r&lt;/span&gt;&lt;span&gt;**&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt; +&lt;/span&gt;&lt;span&gt; L1&lt;/span&gt;&lt;span&gt;**&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;span&gt; L2&lt;/span&gt;&lt;span&gt;**&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;2.0&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt; L1 &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; r)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    alpha &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; np.arccos(np.clip(cos_alpha, &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1.0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1.0&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    phi &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; np.arctan2(y, x)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    solutions &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; []&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    for&lt;/span&gt;&lt;span&gt; sgn &lt;/span&gt;&lt;span&gt;in&lt;/span&gt;&lt;span&gt; ([&lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; elbow &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; else&lt;/span&gt;&lt;span&gt; [elbow]):&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        theta_a &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; phi &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; sgn &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; alpha&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        theta_b &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; np.arctan2(&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            y &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; L1 &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; np.sin(theta_a),&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            x &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; L1 &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; np.cos(theta_a),&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        )&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        solutions.append({&lt;/span&gt;&lt;span&gt;&apos;theta_a&apos;&lt;/span&gt;&lt;span&gt;: theta_a, &lt;/span&gt;&lt;span&gt;&apos;theta_b&apos;&lt;/span&gt;&lt;span&gt;: theta_b})&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; solutions&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;p&gt;&lt;code&gt;elbow&lt;/code&gt; 参数控制返回哪个逆解：&lt;code&gt;+1&lt;/code&gt; 肘向上、&lt;code&gt;-1&lt;/code&gt; 肘向下、&lt;code&gt;0&lt;/code&gt; 返回全部两个解。&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;5. 四种装配模式&lt;a href=&quot;#5-四种装配模式&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;两圆相交的 &lt;span&gt;&lt;span&gt;±\pm&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;±&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 选择带来了 &lt;strong&gt;四种装配模式&lt;/strong&gt;（branch_d × branch_f），对应实际机构的不同组装方式：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;infographic list-grid-badge-card&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;data&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  title 四种装配模式&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  desc 两圆相交 ± 解的组合 → 四种装配模式&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  items&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - label &quot;凸凸 (−1, −1)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      desc P₄ 在 P₁→P₃ 左侧，P₆ 在 P₂→P₅ 左侧&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - label &quot;凸凹 (−1, +1)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      desc P₄ 在 P₁→P₃ 左侧，P₆ 在 P₂→P₅ 右侧&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - label &quot;凹凸 (+1, −1)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      desc P₄ 在 P₁→P₃ 右侧，P₆ 在 P₂→P₅ 左侧（★ 默认模式）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - label &quot;凹凹 (+1, +1)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      desc P₄ 在 P₁→P₃ 右侧，P₆ 在 P₂→P₅ 右侧&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中 &lt;span&gt;&lt;span&gt;branch_d=+1, branch_f=−1\mathrm{branch}\_d = +1,\ \mathrm{branch}\_f = -1&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;branch&lt;/span&gt;&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;branch&lt;/span&gt;&lt;/span&gt;&lt;span&gt;_&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;（凹凸）对应两个平行四边形均为凸四边形的情况，这也是 2R 简化成立的默认模式。&lt;/p&gt;
&lt;p&gt;其余三种模式中平行四边形会出现不同程度的凹陷，但正逆运动学的解析推导框架仍然相同——仅在求解时选择对应的 &lt;span&gt;&lt;span&gt;±\pm&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;±&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt; 分支即可。不过需要注意，非默认模式下的末端 P₇ 与电机轴的相对方位会发生变化，在轨迹规划时应与默认模式区分对待。&lt;/p&gt;
&lt;h3&gt;5.1 轨迹跟踪中的分支保持&lt;a href=&quot;#51-轨迹跟踪中的分支保持&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;轨迹跟踪时，每一帧的 &lt;code&gt;solve_linkage&lt;/code&gt; 会传入上一帧的 &lt;span&gt;&lt;span&gt;θd,θf\theta_d, \theta_f&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;d&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;f&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;，在两圆相交的两个解中选取与上一帧更接近的那个。这样就能在连续运动中保持同一装配模式，避免跳跃。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;# 选取与上一帧更接近的 P4（保持 branch_d 连续性）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;P4 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; p4_left &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; norm(p4_left &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; P4_prev) &lt;/span&gt;&lt;span&gt;&amp;lt;=&lt;/span&gt;&lt;span&gt; norm(p4_right &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; P4_prev) &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; p4_right&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;同理，P6 的分支选择也采用相同的近邻判定策略。完整的分支保持逻辑如下：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;def&lt;/span&gt;&lt;span&gt; select_branch&lt;/span&gt;&lt;span&gt;(p_left, p_right, p_prev):&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &quot;&quot;&quot;从两个交点中选取与上一帧更接近的那个&quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; p_prev &lt;/span&gt;&lt;span&gt;is&lt;/span&gt;&lt;span&gt; None&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        return&lt;/span&gt;&lt;span&gt; p_left  &lt;/span&gt;&lt;span&gt;# 首帧，默认取第一个&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    d_left &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; norm(p_left &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; p_prev)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    d_right &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; norm(p_right &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; p_prev)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; p_left &lt;/span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; d_left &lt;/span&gt;&lt;span&gt;&amp;lt;=&lt;/span&gt;&lt;span&gt; d_right &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; p_right&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这两个分支选择算法共同保证了轨迹跟踪过程中两个平行四边形都能保持连续的装配状态，不会出现&quot;跳帧&quot;导致的运动不连续或机构卡死。&lt;/p&gt;
&lt;h3&gt;5.2 装配模式的选择依据&lt;a href=&quot;#52-装配模式的选择依据&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;默认模式（凹凸, +1, −1）是物理装配最自然的方案——两个平行四边形均保持外凸，机构受力状态最佳，且与 2R 简化模型直接对应，便于运动学规划。&lt;/p&gt;
&lt;p&gt;在某些特殊运动需求下（如需要避开障碍物、改变末端姿态范围或优化传力角度），可以选择其他装配模式。装配模式的切换需要在机构经过奇异位形（两圆相切，&lt;span&gt;&lt;span&gt;h=0h = 0&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;h&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;）时自然过渡——此时两个解重合，分支可以安全切换。&lt;/p&gt;
&lt;h2&gt;6. 验证&lt;a href=&quot;#6-验证&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;&lt;span&gt;&lt;span&gt;θa\theta_a&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/th&gt;&lt;th&gt;&lt;span&gt;&lt;span&gt;θb\theta_b&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;θ&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/th&gt;&lt;th&gt;&lt;span&gt;&lt;span&gt;P7P_7&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;（解析）&lt;/th&gt;&lt;th&gt;&lt;span&gt;&lt;span&gt;P7P_7&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;P&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;7&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;（数值）&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;0°&lt;/td&gt;&lt;td&gt;90°&lt;/td&gt;&lt;td&gt;(107.4, 128.0)&lt;/td&gt;&lt;td&gt;(107.4, 128.0) ✓&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;30°&lt;/td&gt;&lt;td&gt;120°&lt;/td&gt;&lt;td&gt;(29.0, 164.6)&lt;/td&gt;&lt;td&gt;(29.0, 164.6) ✓&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;0°&lt;/td&gt;&lt;td&gt;0°&lt;/td&gt;&lt;td&gt;(235.4, 0.0)&lt;/td&gt;&lt;td&gt;(235.4, 0.0) ✓&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;−30°&lt;/td&gt;&lt;td&gt;45°&lt;/td&gt;&lt;td&gt;(183.5, 36.8)&lt;/td&gt;&lt;td&gt;(183.5, 36.8) ✓&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;以上验证表明，解析推导与数值求解完全一致，正逆运动学求解器正确可靠。&lt;/p&gt;
&lt;h2&gt;7. 总结&lt;a href=&quot;#7-总结&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;这套 8 字形双平行四边形机构巧妙地利用了 &lt;strong&gt;直杆共线&lt;/strong&gt; 约束，使得看似复杂的连杆传动链最终简化为一个 2R 平面机械臂。正逆运动学均有闭式解析解，无需数值迭代，非常适合嵌入式实时控制场景。&lt;/p&gt;
&lt;p&gt;如果你对完整代码感兴趣，项目在 GitHub 上开源：&lt;/p&gt;
&lt;div&gt;
  &lt;a href=&quot;https://github.com/729DHS/linkage-2dof&quot; target=&quot;_blank&quot;&gt;
    &lt;div&gt;
      &lt;div&gt;
        &lt;div&gt;
          &lt;img src=&quot;https://github.com/fluidicon.png&quot; alt=&quot;&quot; loading=&quot;lazy&quot; /&gt;
          &lt;span&gt;github.com&lt;/span&gt;
        &lt;/div&gt;
        &lt;h3&gt;GitHub - 729DHS/linkage-2dof: 2-DOF wheel-legged robot linkage mechanism simulation with interactive visualization&lt;/h3&gt;
        &lt;p&gt;2-DOF wheel-legged robot linkage mechanism simulation with interactive visualization - 729DHS/linkage-2dof&lt;/p&gt;
        &lt;div&gt;
          &lt;span&gt;https://github.com/729DHS/linkage-2dof&lt;/span&gt;
           
        &lt;/div&gt;
      &lt;/div&gt;
      &lt;div&gt;&lt;img src=&quot;https://opengraph.githubassets.com/786cca54bd404d3517f203e8254c2c17a1b76e262e62439368d0daad2027a820/729DHS/linkage-2dof&quot; alt=&quot;GitHub - 729DHS/linkage-2dof: 2-DOF wheel-legged robot linkage mechanism simulation with interactive visualization&quot; loading=&quot;lazy&quot; /&gt;&lt;/div&gt;
    &lt;/div&gt;
  &lt;/a&gt;
&lt;/div&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;# 快速体验&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;git&lt;/span&gt;&lt;span&gt; clone&lt;/span&gt;&lt;span&gt; https://github.com/729DHS/linkage-2dof.git&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;cd&lt;/span&gt;&lt;span&gt; linkage-2dof&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;uv&lt;/span&gt;&lt;span&gt; sync&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;python&lt;/span&gt;&lt;span&gt; main.py&lt;/span&gt;&lt;span&gt; interactive&lt;/span&gt;&lt;span&gt;   # 交互式滑块&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;python&lt;/span&gt;&lt;span&gt; main.py&lt;/span&gt;&lt;span&gt; anim&lt;/span&gt;&lt;span&gt;          # 生成动画&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;python&lt;/span&gt;&lt;span&gt; main.py&lt;/span&gt;&lt;span&gt; ik&lt;/span&gt;&lt;span&gt;            # 逆运动学演示&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;</content:encoded><category>category:笔记</category><category>category:机器人</category><category>tag:robot</category><category>tag:kinematics</category><category>tag:Python</category></item><item><title>这世界即残酷也温柔-感触</title><link>https://729dhs.site/post/sunyuchen</link><guid isPermaLink="false">sunyuchen</guid><description>孙割的书笔记</description><pubDate>Tue, 21 Apr 2026 06:52:26 GMT</pubDate><content:encoded>&lt;h1&gt;这世界既残酷也温柔笔记&lt;a href=&quot;#这世界既残酷也温柔笔记&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;对于孙割这本书早有耳闻，最近些天看了看，确实有点感触&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;现在人们总是说什么稳定，稳定反而是最大的谎言，及其难得。依我的观察，也就只有说那种十几二十万年薪的体制内才算这要求，但是显然这要求是极其的高。&lt;/p&gt;
&lt;p&gt;人们畏惧不确定性，比尔盖茨十二岁就打电话给惠普公司，第一步极其难以迈出，人们害怕被拒绝，害怕丢脸，失败，害怕事情不向自己预期发展。&lt;/p&gt;
&lt;h2&gt;我为什么从不找一份稳定的工作&lt;a href=&quot;#我为什么从不找一份稳定的工作&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;但是谁在意呢？报酬按字数给钱，翻译得越快、字数越多，便能拿到更多的钱。而且翻译者也不认识他们的读者，绝大多数人的态度就是敷衍过关，加快速度交稿了事，根本不在意出版质量，不在意给读者带来的麻烦、误导、偏差。很少有人理会翻译的职业尊严，理会你在翻译时的纠结痛苦。你渐渐发现译好译坏一个样，完全没有任何差别；也没人理会认真、努力、天赋的价值。一个认真的人待在这个环境里会觉得尴尬，而一个混吃等死、喜欢稳定的人则如同找到了组织。 当时，我埋头翻译。听到《欢乐颂》里提到过的这类职场老油条们的讨论，他们成天讨论的梦想就是何时能够混入一个更稳定、对工作质量要求更低、对行业尊严更不在乎的行业；他们成天想得最多的事情就是如何能在此基础上，再偷一点工再减一点料再轻松一点，没有最懒，只有更懒；他们成天最大的爱好就是打击那些认为自己能够改变什么、能够有所作为、能够认真对待工作的新人。&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;所谓的“稳定”，更像是士兵突击里，草原五班那群混日子的兵，无所事事，拿点工资混，就是所谓的稳定，当看到许三多日复一日坚持，他们会感到不安。就像宿舍一群人打游戏，认真学习的人就是异类，因为他打破了群体的稳定。&lt;/p&gt;
&lt;p&gt;尤其是现在这低迷的社会环境，人们更倾向于躺平，似乎你作为奋斗者就是异类。他们不仅想混吃等死，还想拉你下水，作为奋斗者，会被称为傻逼，但是显然，成功仍然是属于少数人的，那些躺平的人永远无法成功&lt;/p&gt;
&lt;p&gt;90%的人做出 99%的选择，却想要那 1%的结果，显然不行的。那些日复一日认真学习的人，凭什么成功不属于他们呢？&lt;/p&gt;
&lt;p&gt;在我看来孙割更是一种典型，为了一件事可以不顾一切坚持下去，我总认为我运气不好，做的事情没有好的结果，不过细想一下，还是没有真正的认真，也许只是做了五分工而已。&lt;/p&gt;
&lt;h2&gt;做从未来看正确的事&lt;a href=&quot;#做从未来看正确的事&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;勇气和格局是成功必备的前置条件&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;如果一个企业家见过了比尔盖茨 马斯克，将不再满足于仅仅是一个县里的优秀企业家。配得感十分重要，有些人会觉得自己不配，或者下意识认为不配。人人生而平等，都是两条胳膊两条腿，没有什么不同，出生所带来的便利不是把人分类分级的理由&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;关注增量而非存量&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;目光不只局限于眼下的利益，长期投入即使亏损，如果能够换来未来更大回报，那它就是值得的。&lt;/p&gt;
&lt;h2&gt;ALL IN 一个波澜壮阔的事业&lt;a href=&quot;#all-in-一个波澜壮阔的事业&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;互联网开启了一个新的时代，人与人的联系变得前所未有便捷。同时也开启了一个虚拟的平行空间。&lt;/p&gt;
&lt;p&gt;当要决定做一番大事业时，一定要有 ALL IN 的决心&lt;/p&gt;
&lt;p&gt;ALL IN，不是没有退路，也不是盲目冲动，要对未来有敏锐的判断力和感受，有七八成把握，并且要相信自己的判断。
尤其是当转行，创业，从零开始的时候。&lt;/p&gt;</content:encoded><category>category:笔记</category><category>tag:这世界即残酷也温柔</category></item><item><title>嘉立创筑基派FreeRTOS 点灯demo</title><link>https://729dhs.site/post/jlc-freertos-led-demo</link><guid isPermaLink="false">jlc-freertos-led-demo</guid><description>嘉立创筑基派FreeRTOS点灯DEMO,使用筑基板自带PB8 LED,板载PB2 LED</description><pubDate>Thu, 02 Apr 2026 14:48:50 GMT</pubDate><content:encoded>&lt;h1&gt;实验教程：FreeRTOS 多任务基础与 GPIO 控制&lt;a href=&quot;#实验教程freertos-多任务基础与-gpio-控制&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2&gt;0. 实验概述&lt;a href=&quot;#0-实验概述&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;本实验是嵌入式实时操作系统 (RTOS) 的入门必修课。通过构建两个不同优先级的任务，控制两颗 LED 以不同频率闪烁，直观地展示 FreeRTOS 的&lt;strong&gt;多任务调度&lt;/strong&gt;、&lt;strong&gt;优先级抢占&lt;/strong&gt;以及&lt;strong&gt;时间管理&lt;/strong&gt;机制。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt; 学习目标&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;理解 FreeRTOS 中“任务 (Task)“的概念及其与裸机 &lt;code&gt;while(1)&lt;/code&gt; 的区别。&lt;/li&gt;
&lt;li&gt;掌握使用 STM32CubeMX 配置 FreeRTOS 任务的方法。&lt;/li&gt;
&lt;li&gt;深入理解 &lt;code&gt;osThreadNew&lt;/code&gt; 创建任务时各参数的含义。&lt;/li&gt;
&lt;li&gt;学会分析不同优先级任务的调度行为。&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;1. 预备知识&lt;a href=&quot;#1-预备知识&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1.1 什么是 FreeRTOS 任务？&lt;a href=&quot;#11-什么是-freertos-任务&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在裸机程序中，我们通常在一个死循环 &lt;code&gt;while(1)&lt;/code&gt; 中顺序执行代码。而在 RTOS 中，程序被拆分为多个独立的“任务”。每个任务看起来像是在独占 CPU，但实际上操作系统内核（Scheduler）会根据&lt;strong&gt;优先级&lt;/strong&gt;和&lt;strong&gt;时间片&lt;/strong&gt;快速切换任务，实现宏观上的“并行”。&lt;/p&gt;
&lt;h3&gt;1.2 硬件基础&lt;a href=&quot;#12-硬件基础&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;主控&lt;/strong&gt;: STM32F407 (Cortex-M4)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LED 连接&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;LED1&lt;/strong&gt; -&amp;gt; &lt;strong&gt;PB2&lt;/strong&gt; (推挽输出)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LED2&lt;/strong&gt; -&amp;gt; &lt;strong&gt;PB8&lt;/strong&gt; (推挽输出)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;时钟&lt;/strong&gt;: 系统主频 168MHz，SysTick 或 TIM14 提供心跳节拍。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;2. 原理解析&lt;a href=&quot;#2-原理解析&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;2.1 任务优先级与调度&lt;a href=&quot;#21-任务优先级与调度&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;本实验创建了兩個任务：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task PB2&lt;/strong&gt;: 优先级 &lt;code&gt;Normal&lt;/code&gt; (较高)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Task PB8&lt;/strong&gt;: 优先级 &lt;code&gt;Low&lt;/code&gt; (较低)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;调度规则&lt;/strong&gt;：
FreeRTOS 采用&lt;strong&gt;基于优先级的抢占式调度&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;当高优先级任务就绪时，CPU 会立即执行高优先级任务。&lt;/li&gt;
&lt;li&gt;只有当高优先级任务进入&lt;strong&gt;阻塞状态&lt;/strong&gt;（如调用 &lt;code&gt;osDelay&lt;/code&gt;）时，低优先级任务才有机会运行。&lt;/li&gt;
&lt;li&gt;在本实验中，两个任务大部分时间都在 &lt;code&gt;osDelay&lt;/code&gt; 阻塞中，因此它们会交替运行，互不干扰。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.2 时间延迟 (&lt;code&gt;osDelay&lt;/code&gt;)&lt;a href=&quot;#22-时间延迟-osdelay&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;osDelay(1000)&lt;/code&gt;：表示任务挂起 1000 个系统节拍（Tick）。&lt;/li&gt;
&lt;li&gt;假设系统节拍频率为 1000Hz (1ms)，则延迟时间为 1 秒。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;关键点&lt;/strong&gt;：在延迟期间，该任务不占用 CPU 资源，CPU 可以去执行其他就绪的低优先级任务。这是多任务高效运行的核心。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;3. 代码深度解析&lt;a href=&quot;#3-代码深度解析&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;以下基于 &lt;code&gt;Core/Src/main.c&lt;/code&gt; 进行教学拆解。&lt;/p&gt;
&lt;h3&gt;3.1 任务属性定义&lt;a href=&quot;#31-任务属性定义&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在 &lt;code&gt;main.c&lt;/code&gt; 全局变量区，定义了任务的“身份证”&lt;/p&gt;</content:encoded><category>category:笔记</category><category>category:STM32</category><category>tag:STM32</category><category>tag:嵌入式</category><category>tag:筑基派</category></item><item><title>嘉立创筑基派FreeRTOS编码器+PWM+LED</title><link>https://729dhs.site/post/jlc-freertos-endoer-led-demo</link><guid isPermaLink="false">jlc-freertos-endoer-led-demo</guid><description>嘉立创筑基派FreeRTOS,使用编码器以及LED,使用筑基板自带PB8 LED,EC11编码器</description><pubDate>Thu, 02 Apr 2026 14:48:50 GMT</pubDate><content:encoded>&lt;h1&gt;EC11 编码器控制 LED 亮度项目&lt;a href=&quot;#ec11-编码器控制-led-亮度项目&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2&gt;1. 项目概述&lt;a href=&quot;#1-项目概述&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;本项目基于 STM32F407 微控制器和 FreeRTOS 操作系统，实现了使用 EC11 编码器控制 LED 亮度的功能。项目通过三个任务（线程）协同工作，实现了无阻塞的编码器读取、按键检测和 LED 亮度控制。&lt;/p&gt;
&lt;h2&gt;2. 技术框架&lt;a href=&quot;#2-技术框架&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;2.1 硬件平台&lt;a href=&quot;#21-硬件平台&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;微控制器&lt;/strong&gt;：STM32F407&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;编码器&lt;/strong&gt;：EC11 旋转编码器（连接到 PD12 和 PD13）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;按键&lt;/strong&gt;：PC13（编码器自带的按下功能）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LED&lt;/strong&gt;：PB8（通过 PWM 控制亮度）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;定时器&lt;/strong&gt;：TIM10（用于 PWM 输出）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.2 软件架构&lt;a href=&quot;#22-软件架构&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;开发环境&lt;/strong&gt;：STM32CubeMX + VScode&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;操作系统&lt;/strong&gt;：FreeRTOS&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;库函数&lt;/strong&gt;：STM32 HAL 库&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;代码结构&lt;/strong&gt;：标准 STM32 HAL 项目结构 + FreeRTOS 任务管理&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3. 代码结构分析&lt;a href=&quot;#3-代码结构分析&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;3.1 头文件和包含部分&lt;a href=&quot;#31-头文件和包含部分&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;#include&lt;/span&gt;&lt;span&gt; &quot;main.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#include&lt;/span&gt;&lt;span&gt; &quot;cmsis_os.h&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;包含了主头文件和 CMSIS-OS 头文件，其中定义了 STM32 HAL 库的基本配置和 FreeRTOS 的相关函数。&lt;/p&gt;
&lt;h3&gt;3.2 全局变量定义&lt;a href=&quot;#32-全局变量定义&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;/* USER CODE BEGIN PV */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;uint8_t&lt;/span&gt;&lt;span&gt; led_enabled &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; pwm_duty &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; uint16_t&lt;/span&gt;&lt;span&gt; pwm_arr &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 65535&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; uint16_t&lt;/span&gt;&lt;span&gt; pwm_step &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 1000&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;/* USER CODE END PV */&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;led_enabled&lt;/code&gt;：LED 使能状态（1=开启，0=关闭）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pwm_duty&lt;/code&gt;：PWM 占空比（0-65535）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pwm_arr&lt;/code&gt;：PWM 自动重载值（定时器周期）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pwm_step&lt;/code&gt;：每次旋转编码器的 PWM 变化步长&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.3 任务句柄定义&lt;a href=&quot;#33-任务句柄定义&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;/* USER CODE BEGIN EV */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;osThreadId_t&lt;/span&gt;&lt;span&gt; EncoderTaskHandle;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;osThreadId_t&lt;/span&gt;&lt;span&gt; KEYTaskHandle;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;osThreadId_t&lt;/span&gt;&lt;span&gt; LEDTaskHandle;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;/* USER CODE END EV */&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;定义了三个任务的句柄，用于任务管理。&lt;/p&gt;
&lt;h3&gt;3.4 任务函数原型&lt;a href=&quot;#34-任务函数原型&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;/* USER CODE BEGIN FunctionPrototypes */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; EncoderTask&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt;argument&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; KEYTask&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt;argument&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; LEDTask&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt;argument&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;/* USER CODE END FunctionPrototypes */&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3.5 编码器状态表&lt;a href=&quot;#35-编码器状态表&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; int8_t&lt;/span&gt;&lt;span&gt; enc_table&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;16&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,  &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,  &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    1&lt;/span&gt;&lt;span&gt;,  &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,  &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;   -&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,  &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,  &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,  &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    0&lt;/span&gt;&lt;span&gt;,  &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;,  &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;编码器旋转方向检测的状态表，用于查表法计算旋转方向。&lt;/p&gt;
&lt;h2&gt;4. 主要功能实现&lt;a href=&quot;#4-主要功能实现&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;4.1 主函数&lt;a href=&quot;#41-主函数&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  /* 系统初始化 */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  HAL_Init&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  SystemClock_Config&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  MX_GPIO_Init&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  MX_TIM10_Init&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  MX_FREERTOS_Init&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  /* 启动PWM输出 */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;HAL_TIM_PWM_Start&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;htim10, TIM_CHANNEL_1) &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; HAL_OK)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    Error_Handler&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  /* 启动任务调度器 */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  osKernelStart&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  /* 永远不会执行到这里 */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  while&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;主函数首先进行系统初始化，然后配置 GPIO、TIM10 定时器和 FreeRTOS，启动 PWM 输出和任务调度器。&lt;/p&gt;
&lt;h3&gt;4.2 任务初始化&lt;a href=&quot;#42-任务初始化&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; MX_FREERTOS_Init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  /* 创建任务 */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  EncoderTaskHandle &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; osThreadNew&lt;/span&gt;&lt;span&gt;(EncoderTask, &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;EncoderTask_attributes);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  KEYTaskHandle &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; osThreadNew&lt;/span&gt;&lt;span&gt;(KEYTask, &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;KEYTask_attributes);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  LEDTaskHandle &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; osThreadNew&lt;/span&gt;&lt;span&gt;(LEDTask, &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;LEDTask_attributes);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;使用&lt;code&gt;osThreadNew&lt;/code&gt;函数创建三个任务，并设置任务属性。&lt;/p&gt;
&lt;h3&gt;4.3 Encoder 任务&lt;a href=&quot;#43-encoder-任务&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; EncoderTask&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt;argument&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  static&lt;/span&gt;&lt;span&gt; uint8_t&lt;/span&gt;&lt;span&gt; enc_last &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  uint8_t&lt;/span&gt;&lt;span&gt; enc_current;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  int8_t&lt;/span&gt;&lt;span&gt; enc_dir;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  for&lt;/span&gt;&lt;span&gt; (;;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    /* 读取编码器状态 */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    enc_current &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ((GPIOE-&amp;gt;IDR &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt; GPIO_PIN_12) &lt;/span&gt;&lt;span&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span&gt; 12&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; ((GPIOE-&amp;gt;IDR &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt; GPIO_PIN_13) &lt;/span&gt;&lt;span&gt;&amp;gt;&amp;gt;&lt;/span&gt;&lt;span&gt; 12&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    /* 计算旋转方向 */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    enc_dir &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; enc_table&lt;/span&gt;&lt;span&gt;[(enc_last &lt;/span&gt;&lt;span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; enc_current];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    enc_last &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; enc_current;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    /* 根据方向调整PWM占空比 */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (enc_dir &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; pwm_duty &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; pwm_arr)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      pwm_duty &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; pwm_step;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      if&lt;/span&gt;&lt;span&gt; (pwm_duty &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; pwm_arr) pwm_duty &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; pwm_arr;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    else&lt;/span&gt;&lt;span&gt; if&lt;/span&gt;&lt;span&gt; (enc_dir &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; pwm_duty &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      pwm_duty &lt;/span&gt;&lt;span&gt;-=&lt;/span&gt;&lt;span&gt; pwm_step;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      if&lt;/span&gt;&lt;span&gt; (pwm_duty &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; pwm_arr) pwm_duty &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt; // 防止溢出&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    osDelay&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Encoder 任务使用查表法检测编码器旋转方向，并根据方向调整 PWM 占空比。&lt;/p&gt;
&lt;h3&gt;4.4 KEY 任务&lt;a href=&quot;#44-key-任务&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; KEYTask&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt;argument&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  static&lt;/span&gt;&lt;span&gt; uint8_t&lt;/span&gt;&lt;span&gt; key_state &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  static&lt;/span&gt;&lt;span&gt; uint32_t&lt;/span&gt;&lt;span&gt; key_time &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  for&lt;/span&gt;&lt;span&gt; (;;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    /* 按键防抖处理 */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;HAL_GPIO_ReadPin&lt;/span&gt;&lt;span&gt;(GPIOC, GPIO_PIN_13) &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; GPIO_PIN_RESET)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      if&lt;/span&gt;&lt;span&gt; (key_state &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        key_state &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        key_time &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; osKernelGetTickCount&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      else&lt;/span&gt;&lt;span&gt; if&lt;/span&gt;&lt;span&gt; (key_state &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;osKernelGetTickCount&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; key_time &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; 50&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;          key_state &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 2&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;          /* 切换LED使能状态 */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;          led_enabled &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; !&lt;/span&gt;&lt;span&gt;led_enabled;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    else&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      key_state &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    osDelay&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;KEY 任务实现了按键的防抖处理，当检测到按键按下时，切换 LED 的使能状态。&lt;/p&gt;
&lt;h3&gt;4.5 LED 任务&lt;a href=&quot;#45-led-任务&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; LEDTask&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt;argument&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  for&lt;/span&gt;&lt;span&gt; (;;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    /* 根据PWM占空比和LED使能状态控制LED亮度 */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    uint16_t&lt;/span&gt;&lt;span&gt; out &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; led_enabled &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt;)(pwm_arr &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; pwm_duty) &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; pwm_arr;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    __HAL_TIM_SET_COMPARE&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;htim10, TIM_CHANNEL_1, out);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    osDelay&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;50&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;LED 任务通过 TIM10 的 PWM 输出控制 LED 亮度。由于 PB8 是低电平有效，所以需要将 PWM 占空比取反。&lt;/p&gt;
&lt;h3&gt;4.6 TIM10 定时器初始化&lt;a href=&quot;#46-tim10-定时器初始化&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; MX_TIM10_Init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  TIM_OC_InitTypeDef sConfigOC &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  htim10.Instance &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; TIM10;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  htim10.Init.Prescaler &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  htim10.Init.CounterMode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; TIM_COUNTERMODE_UP;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  htim10.Init.Period &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 65535&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  htim10.Init.ClockDivision &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; TIM_CLOCKDIVISION_DIV1;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  htim10.Init.AutoReloadPreload &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; TIM_AUTORELOAD_PRELOAD_DISABLE;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;HAL_TIM_Base_Init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;htim10) &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; HAL_OK)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    Error_Handler&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;HAL_TIM_PWM_Init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;htim10) &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; HAL_OK)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    Error_Handler&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  sConfigOC.OCMode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; TIM_OCMODE_PWM1;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  sConfigOC.Pulse &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  sConfigOC.OCPolarity &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; TIM_OCPOLARITY_HIGH;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  sConfigOC.OCFastMode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; TIM_OCFAST_DISABLE;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;HAL_TIM_PWM_ConfigChannel&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;htim10, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;sConfigOC, TIM_CHANNEL_1) &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; HAL_OK)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    Error_Handler&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  HAL_TIM_MspPostInit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;htim10);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;TIM10 定时器初始化函数配置了定时器的基本参数和 PWM 输出通道。&lt;/p&gt;
&lt;h3&gt;4.7 GPIO 初始化&lt;a href=&quot;#47-gpio-初始化&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; MX_GPIO_Init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  GPIO_InitTypeDef GPIO_InitStruct &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  /* GPIO Ports Clock Enable */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  __HAL_RCC_GPIOC_CLK_ENABLE&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  __HAL_RCC_GPIOD_CLK_ENABLE&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  __HAL_RCC_GPIOB_CLK_ENABLE&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  /* 配置PC13为输入 */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  GPIO_InitStruct.Pin &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_PIN_13;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  GPIO_InitStruct.Mode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_MODE_INPUT;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  GPIO_InitStruct.Pull &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_PULLUP;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  HAL_GPIO_Init&lt;/span&gt;&lt;span&gt;(GPIOC, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;GPIO_InitStruct);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  /* 配置PD12和PD13为输入 */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  GPIO_InitStruct.Pin &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_PIN_12&lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt;GPIO_PIN_13;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  GPIO_InitStruct.Mode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_MODE_INPUT;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  GPIO_InitStruct.Pull &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_PULLUP;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  HAL_GPIO_Init&lt;/span&gt;&lt;span&gt;(GPIOD, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;GPIO_InitStruct);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;GPIO 初始化函数配置了按键和编码器的输入引脚。&lt;/p&gt;
&lt;h2&gt;5. 技术细节&lt;a href=&quot;#5-技术细节&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;5.1 编码器工作原理&lt;a href=&quot;#51-编码器工作原理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;EC11 编码器是一种旋转式位置传感器，通过两个输出信号（A 相和 B 相）的相位差来检测旋转方向。当编码器顺时针旋转时，A 相领先 B 相；当编码器逆时针旋转时，B 相领先 A 相。&lt;/p&gt;
&lt;p&gt;本项目使用查表法检测旋转方向，通过读取 A 相和 B 相的状态，计算出当前状态码，然后根据上一次的状态码和当前状态码查表得到旋转方向。&lt;/p&gt;
&lt;h3&gt;5.2 PWM 控制原理&lt;a href=&quot;#52-pwm-控制原理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;PWM（脉冲宽度调制）是一种通过改变脉冲宽度来控制信号的技术。在 LED 控制中，PWM 的占空比（高电平时间与整个周期的比值）决定了 LED 的平均亮度。占空比越高，LED 越亮；占空比越低，LED 越暗。&lt;/p&gt;
&lt;p&gt;本项目使用 TIM10 定时器生成 PWM 信号，定时器时钟为 84MHz（APB2 总线时钟），预分频器为 0，自动重装载值为 65535，因此 PWM 频率为：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;PWM频率 = 定时器时钟 / (预分频器+1) / (自动重装载值+1) = 84MHz / 1 / 65536 ≈ 1281Hz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5.3 FreeRTOS 任务管理&lt;a href=&quot;#53-freertos-任务管理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FreeRTOS 是一个开源的实时操作系统，提供了任务管理、队列、信号量等功能。本项目使用 FreeRTOS 的任务管理功能，创建了三个任务：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Encoder 任务&lt;/strong&gt;：优先级正常，负责读取编码器状态并计算旋转方向&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;KEY 任务&lt;/strong&gt;：优先级低，负责检测按键状态&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LED 任务&lt;/strong&gt;：优先级低，负责控制 LED 亮度&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;任务调度器根据任务优先级和状态，决定哪个任务获得 CPU 控制权。&lt;/p&gt;
&lt;h3&gt;5.4 按键防抖处理&lt;a href=&quot;#54-按键防抖处理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;按键在按下和释放时会产生机械抖动，导致多次触发。本项目实现了软件防抖，通过检测按键状态的持续时间来判断按键是否真正被按下。当按键状态持续 50ms 以上时，才认为按键被按下。&lt;/p&gt;
&lt;h3&gt;5.5 任务间通信&lt;a href=&quot;#55-任务间通信&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;当前项目使用全局变量进行任务间通信，Encoder 任务更新&lt;code&gt;pwm_duty&lt;/code&gt;变量，KEY 任务更新&lt;code&gt;led_enabled&lt;/code&gt;变量，LED 任务读取这些变量并控制 LED 亮度。&lt;/p&gt;
&lt;h2&gt;6. 工作流程&lt;a href=&quot;#6-工作流程&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;系统初始化&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;配置系统时钟&lt;/li&gt;
&lt;li&gt;初始化 GPIO&lt;/li&gt;
&lt;li&gt;初始化 TIM10 定时器&lt;/li&gt;
&lt;li&gt;初始化 FreeRTOS&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;任务创建&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;创建 Encoder 任务&lt;/li&gt;
&lt;li&gt;创建 KEY 任务&lt;/li&gt;
&lt;li&gt;创建 LED 任务&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;任务执行&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Encoder 任务&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;读取编码器状态&lt;/li&gt;
&lt;li&gt;计算旋转方向&lt;/li&gt;
&lt;li&gt;根据方向调整 PWM 占空比&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;KEY 任务&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;检测按键状态（带防抖）&lt;/li&gt;
&lt;li&gt;当按键按下时，切换 LED 使能状态&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LED 任务&lt;/strong&gt;：
&lt;ul&gt;
&lt;li&gt;根据 PWM 占空比和 LED 使能状态控制 LED 亮度&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;7. 代码优化建议&lt;a href=&quot;#7-代码优化建议&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;7.1 使用队列替代全局变量&lt;a href=&quot;#71-使用队列替代全局变量&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;当前代码使用全局变量传递数据，建议使用 FreeRTOS 的队列进行任务间通信，提高代码的可靠性和可维护性。例如：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 创建队列&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;osMessageQueueId_t&lt;/span&gt;&lt;span&gt; pwmQueue &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; osMessageQueueNew&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;sizeof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt;), &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 发送消息&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;osMessageQueuePut&lt;/span&gt;&lt;span&gt;(pwmQueue, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;pwm_duty&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 接收消息&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;osMessageQueueGet&lt;/span&gt;&lt;span&gt;(pwmQueue, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;pwm_duty&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;7.2 增加参数配置&lt;a href=&quot;#72-增加参数配置&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;可以将 PWM 的步长、按键防抖时间等参数定义为可配置的宏，方便调整：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;#define&lt;/span&gt;&lt;span&gt; PWM_STEP&lt;/span&gt;&lt;span&gt;        1000&lt;/span&gt;&lt;span&gt;    // PWM变化步长&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#define&lt;/span&gt;&lt;span&gt; KEY_DEBOUNCE_MS&lt;/span&gt;&lt;span&gt; 50&lt;/span&gt;&lt;span&gt;      // 按键防抖时间&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#define&lt;/span&gt;&lt;span&gt; ENCODER_DELAY&lt;/span&gt;&lt;span&gt;   10&lt;/span&gt;&lt;span&gt;      // 编码器检测延迟&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#define&lt;/span&gt;&lt;span&gt; LED_UPDATE_DELAY&lt;/span&gt;&lt;span&gt; 50&lt;/span&gt;&lt;span&gt;     // LED更新延迟&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;7.3 增加错误处理&lt;a href=&quot;#73-增加错误处理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;在关键操作处增加错误处理，提高系统的稳定性：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;HAL_TIM_PWM_Start&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;htim10&lt;/span&gt;&lt;span&gt;, TIM_CHANNEL_1) &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; HAL_OK)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  Error_Handler&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;7.4 优化任务优先级&lt;a href=&quot;#74-优化任务优先级&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;根据实际需求调整任务优先级，确保关键任务能够及时响应：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Encoder 任务：优先级较高，确保及时响应编码器输入&lt;/li&gt;
&lt;li&gt;KEY 任务：优先级中等&lt;/li&gt;
&lt;li&gt;LED 任务：优先级较低，因为亮度更新不需要实时响应&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;7.5 增加状态指示&lt;a href=&quot;#75-增加状态指示&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;可以增加 LED 状态指示，例如当 LED 开启时，使用另一个 LED 指示状态：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (led_enabled)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  HAL_GPIO_WritePin&lt;/span&gt;&lt;span&gt;(GPIOB, GPIO_PIN_9, GPIO_PIN_SET);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  HAL_GPIO_WritePin&lt;/span&gt;&lt;span&gt;(GPIOB, GPIO_PIN_9, GPIO_PIN_RESET);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;8. 测试方法&lt;a href=&quot;#8-测试方法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;基本功能测试&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;旋转编码器，观察 LED 亮度变化&lt;/li&gt;
&lt;li&gt;按下编码器的按键，观察 LED 的开关状态&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;性能测试&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;快速旋转编码器，测试系统的响应速度&lt;/li&gt;
&lt;li&gt;多次按下按键，测试防抖功能&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;边界测试&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;旋转编码器到最小亮度，测试是否能正确停止&lt;/li&gt;
&lt;li&gt;旋转编码器到最大亮度，测试是否能正确停止&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;稳定性测试&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;长时间运行，测试系统的稳定性&lt;/li&gt;
&lt;li&gt;重复操作，测试系统的可靠性&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;9. 项目结构&lt;a href=&quot;#9-项目结构&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;FreeRTOS\F02_Encoder_PWM_LED_1\&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── Core\&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── Inc\&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   │   ├── main.h&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   │   └── stm32f4xx_hal_conf.h&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   └── Src\&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│       ├── main.c&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│       ├── stm32f4xx_hal_msp.c&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│       ├── stm32f4xx_it.c&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│       └── sysmem.c&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── Drivers\&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── CMSIS\&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   │   ├── Device\&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   │   └── Include\&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   └── STM32F4xx_HAL_Driver\&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│       ├── Inc\&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│       └── Src\&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── FreeRTOS\&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── CMSIS_RTOS_V2\&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   └── Source\&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;└── README.md&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;10. 技术要点&lt;a href=&quot;#10-技术要点&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;FreeRTOS 任务创建与管理&lt;/strong&gt;：使用&lt;code&gt;osThreadNew&lt;/code&gt;创建任务，设置任务优先级和栈大小。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;编码器读取算法&lt;/strong&gt;：使用查表法实现编码器旋转方向的检测，提高检测速度和准确性。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PWM 控制&lt;/strong&gt;：使用 TIM10 的 PWM 模式控制 LED 亮度，实现平滑的亮度调节。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;按键防抖&lt;/strong&gt;：实现软件防抖，提高按键检测的可靠性。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;任务间通信&lt;/strong&gt;：当前使用全局变量，建议使用队列进行任务间通信。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;STM32 HAL 库使用&lt;/strong&gt;：使用 HAL 库函数配置 GPIO、定时器等外设。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;代码规范&lt;/strong&gt;：遵循 STM32 HAL 库的代码规范和注释风格。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;11. 项目特点&lt;a href=&quot;#11-项目特点&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;模块化设计&lt;/strong&gt;：将功能分为三个独立的任务，便于维护和扩展。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;实时响应&lt;/strong&gt;：使用 FreeRTOS 实现实时任务调度，确保编码器输入和按键操作能够及时响应。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;平滑控制&lt;/strong&gt;：通过 PWM 技术实现 LED 亮度的平滑调节，避免亮度突变。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;可靠性&lt;/strong&gt;：实现了按键防抖，提高了系统的可靠性。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;可扩展性&lt;/strong&gt;：代码结构清晰，便于添加新的功能或修改现有功能。&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;12. 应用场景&lt;a href=&quot;#12-应用场景&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;本项目实现的 EC11 编码器控制 LED 亮度技术可以应用于多种场景：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;照明控制&lt;/strong&gt;：调节室内灯光亮度&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;设备参数调节&lt;/strong&gt;：调节设备的各种参数，如音量、速度等&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;仪表盘控制&lt;/strong&gt;：控制仪表盘的显示亮度&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;智能家居&lt;/strong&gt;：调节智能灯具的亮度&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;工业控制&lt;/strong&gt;：调节设备的输出功率&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;13. 总结&lt;a href=&quot;#13-总结&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;本项目成功实现了使用 EC11 编码器控制 LED 亮度的功能，通过 FreeRTOS 的任务管理实现了无阻塞的操作。项目结构清晰，代码简洁，功能完整，可以作为学习 FreeRTOS 和 STM32 PWM 控制的参考示例。&lt;/p&gt;
&lt;p&gt;通过本项目的学习，可以掌握以下技术：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;STM32 微控制器的 GPIO 和定时器配置&lt;/li&gt;
&lt;li&gt;FreeRTOS 任务创建和管理&lt;/li&gt;
&lt;li&gt;编码器读取和旋转方向检测&lt;/li&gt;
&lt;li&gt;PWM 控制技术&lt;/li&gt;
&lt;li&gt;按键防抖处理&lt;/li&gt;
&lt;li&gt;任务间通信方法&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这些技术在嵌入式系统开发中非常实用，可以应用于各种需要用户输入和输出控制的场景。&lt;/p&gt;</content:encoded><category>category:笔记</category><category>category:STM32</category><category>tag:STM32</category><category>tag:嵌入式</category><category>tag:筑基派</category></item><item><title>嘉立创筑基派PWM_LED_demo</title><link>https://729dhs.site/post/jlc-pwm-led-demo</link><guid isPermaLink="false">jlc-pwm-led-demo</guid><description>嘉立创筑基派PWM点灯DEMO,使用筑基板自带PB8 LED</description><pubDate>Thu, 02 Apr 2026 14:38:52 GMT</pubDate><content:encoded>&lt;h1&gt;PWM LED 控制项目文档&lt;a href=&quot;#pwm-led-控制项目文档&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2&gt;1. 项目概述&lt;a href=&quot;#1-项目概述&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;本项目是一个基于 STM32F407 微控制器的 LED 亮度控制示例，通过 PWM(脉冲宽度调制)技术实现 LED 亮度的动态调节。项目采用 STM32 HAL 库开发，使用 TIM10 定时器生成 PWM 信号，通过改变占空比来控制 LED 的亮度，并实现 LED 呼吸灯效果。&lt;/p&gt;
&lt;h2&gt;2. 技术框架&lt;a href=&quot;#2-技术框架&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;2.1 硬件平台&lt;a href=&quot;#21-硬件平台&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;微控制器: STM32F407&lt;/li&gt;
&lt;li&gt;定时器: TIM10&lt;/li&gt;
&lt;li&gt;PWM 输出引脚: TIM10_CH1&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.2 软件架构&lt;a href=&quot;#22-软件架构&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;开发环境: STM32CubeMX + VScode&lt;/li&gt;
&lt;li&gt;库函数: STM32 HAL 库&lt;/li&gt;
&lt;li&gt;代码结构: 标准 STM32 HAL 项目结构&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3. 代码结构分析&lt;a href=&quot;#3-代码结构分析&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;3.1 头文件和包含部分&lt;a href=&quot;#31-头文件和包含部分&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;#include&lt;/span&gt;&lt;span&gt; &quot;main.h&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;包含了主头文件，其中定义了 STM32 HAL 库的基本配置和函数声明。&lt;/p&gt;
&lt;h3&gt;3.2 变量定义&lt;a href=&quot;#32-变量定义&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;TIM_HandleTypeDef htim10;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;定义了 TIM10 定时器的句柄，用于定时器操作。&lt;/p&gt;
&lt;h3&gt;3.3 常量定义&lt;a href=&quot;#33-常量定义&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; uint16_t&lt;/span&gt;&lt;span&gt; LED_PWM_DUTY_MAX &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 60000&lt;/span&gt;&lt;span&gt;U&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;   // PWM最大占空比值&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; uint16_t&lt;/span&gt;&lt;span&gt; LED_PWM_DUTY_MIN &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;U&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;       // PWM最小占空比值&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; uint16_t&lt;/span&gt;&lt;span&gt; LED_FADE_STEPS &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 70&lt;/span&gt;&lt;span&gt;U&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;        // 呼吸灯渐变步数&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; uint32_t&lt;/span&gt;&lt;span&gt; LED_FADE_STEP_MS &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 8&lt;/span&gt;&lt;span&gt;U&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;        // 每步延迟时间(毫秒)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; uint32_t&lt;/span&gt;&lt;span&gt; LED_PEAK_HOLD_MS &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 160&lt;/span&gt;&lt;span&gt;U&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;     // 最亮保持时间(毫秒)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; const&lt;/span&gt;&lt;span&gt; uint32_t&lt;/span&gt;&lt;span&gt; LED_VALLEY_HOLD_MS &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 120&lt;/span&gt;&lt;span&gt;U&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;   // 最暗保持时间(毫秒)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这些常量定义了 LED 呼吸灯效果的各种参数，包括 PWM 占空比范围、渐变步数和时间参数。&lt;/p&gt;
&lt;h3&gt;3.4 函数原型&lt;a href=&quot;#34-函数原型&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; SystemClock_Config&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;span&gt;              // 系统时钟配置&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; MX_GPIO_Init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;span&gt;             // GPIO初始化&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; MX_TIM10_Init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;span&gt;            // TIM10定时器初始化&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; LED_SetBrightness&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; duty&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;span&gt;      // 设置LED亮度&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; LED_GentleFade&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; start_duty&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; end_duty&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;span&gt;  // LED渐变效果&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4. 主要功能实现&lt;a href=&quot;#4-主要功能实现&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;4.1 主函数&lt;a href=&quot;#41-主函数&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 系统初始化&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  HAL_Init&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  SystemClock_Config&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 外设初始化&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  MX_GPIO_Init&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  MX_TIM10_Init&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 启动PWM输出&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;HAL_TIM_PWM_Start&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;htim10, TIM_CHANNEL_1) &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; HAL_OK)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    Error_Handler&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  LED_SetBrightness&lt;/span&gt;&lt;span&gt;(LED_PWM_DUTY_MIN);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 主循环&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  while&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    LED_GentleFade&lt;/span&gt;&lt;span&gt;(LED_PWM_DUTY_MIN, LED_PWM_DUTY_MAX);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    HAL_Delay&lt;/span&gt;&lt;span&gt;(LED_PEAK_HOLD_MS);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    LED_GentleFade&lt;/span&gt;&lt;span&gt;(LED_PWM_DUTY_MAX, LED_PWM_DUTY_MIN);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    HAL_Delay&lt;/span&gt;&lt;span&gt;(LED_VALLEY_HOLD_MS);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;主函数首先进行系统初始化，然后配置 GPIO 和 TIM10 定时器，启动 PWM 输出。在主循环中，通过 LED_GentleFade 函数实现 LED 亮度的渐变效果，形成呼吸灯模式。&lt;/p&gt;
&lt;h3&gt;4.2 系统时钟配置&lt;a href=&quot;#42-系统时钟配置&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; SystemClock_Config&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  RCC_OscInitTypeDef RCC_OscInitStruct &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  RCC_ClkInitTypeDef RCC_ClkInitStruct &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 配置主内部稳压器输出电压&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  __HAL_RCC_PWR_CLK_ENABLE&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  __HAL_PWR_VOLTAGESCALING_CONFIG&lt;/span&gt;&lt;span&gt;(PWR_REGULATOR_VOLTAGE_SCALE1);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 初始化RCC振荡器&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  RCC_OscInitStruct.OscillatorType &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; RCC_OSCILLATORTYPE_HSE;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  RCC_OscInitStruct.HSEState &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; RCC_HSE_ON;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  RCC_OscInitStruct.PLL.PLLState &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; RCC_PLL_ON;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  RCC_OscInitStruct.PLL.PLLSource &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; RCC_PLLSOURCE_HSE;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  RCC_OscInitStruct.PLL.PLLM &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 4&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  RCC_OscInitStruct.PLL.PLLN &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 168&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  RCC_OscInitStruct.PLL.PLLP &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; RCC_PLLP_DIV2;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  RCC_OscInitStruct.PLL.PLLQ &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 4&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;HAL_RCC_OscConfig&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;RCC_OscInitStruct) &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; HAL_OK)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    Error_Handler&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  // 初始化CPU、AHB和APB总线时钟&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  RCC_ClkInitStruct.ClockType &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; RCC_CLOCKTYPE_HCLK&lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt;RCC_CLOCKTYPE_SYSCLK&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                              |&lt;/span&gt;&lt;span&gt;RCC_CLOCKTYPE_PCLK1&lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt;RCC_CLOCKTYPE_PCLK2;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  RCC_ClkInitStruct.SYSCLKSource &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; RCC_SYSCLKSOURCE_PLLCLK;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  RCC_ClkInitStruct.AHBCLKDivider &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; RCC_SYSCLK_DIV1;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  RCC_ClkInitStruct.APB1CLKDivider &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; RCC_HCLK_DIV4;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  RCC_ClkInitStruct.APB2CLKDivider &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; RCC_HCLK_DIV2;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;HAL_RCC_ClockConfig&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;RCC_ClkInitStruct, FLASH_LATENCY_5) &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; HAL_OK)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    Error_Handler&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;系统时钟配置函数使用 HSE(外部高速时钟)作为 PLL 时钟源，通过 PLL 倍频生成 168MHz 的系统时钟。配置了 CPU、AHB 和 APB 总线的时钟分频系数，实现了整个系统的时钟分配。&lt;/p&gt;
&lt;h3&gt;4.3 TIM10 定时器初始化&lt;a href=&quot;#43-tim10-定时器初始化&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; MX_TIM10_Init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  TIM_OC_InitTypeDef sConfigOC &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  htim10.Instance &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; TIM10;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  htim10.Init.Prescaler &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  htim10.Init.CounterMode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; TIM_COUNTERMODE_UP;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  htim10.Init.Period &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 65535&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  htim10.Init.ClockDivision &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; TIM_CLOCKDIVISION_DIV1;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  htim10.Init.AutoReloadPreload &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; TIM_AUTORELOAD_PRELOAD_DISABLE;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;HAL_TIM_Base_Init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;htim10) &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; HAL_OK)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    Error_Handler&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;HAL_TIM_PWM_Init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;htim10) &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; HAL_OK)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    Error_Handler&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  sConfigOC.OCMode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; TIM_OCMODE_PWM1;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  sConfigOC.Pulse &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; LED_PWM_DUTY_MAX;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  sConfigOC.OCPolarity &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; TIM_OCPOLARITY_HIGH;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  sConfigOC.OCFastMode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; TIM_OCFAST_DISABLE;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;HAL_TIM_PWM_ConfigChannel&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;htim10, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;sConfigOC, TIM_CHANNEL_1) &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; HAL_OK)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    Error_Handler&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  HAL_TIM_MspPostInit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;htim10);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;TIM10 定时器初始化函数配置了定时器的基本参数和 PWM 输出通道。关键参数包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;预分频器(Prescaler): 0&lt;/li&gt;
&lt;li&gt;计数模式: 向上计数&lt;/li&gt;
&lt;li&gt;自动重装载值(Period): 65535&lt;/li&gt;
&lt;li&gt;PWM 模式: PWM1 模式&lt;/li&gt;
&lt;li&gt;输出极性: 高电平有效&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4.4 GPIO 初始化&lt;a href=&quot;#44-gpio-初始化&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; MX_GPIO_Init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  /* GPIO Ports Clock Enable */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  __HAL_RCC_GPIOH_CLK_ENABLE&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  __HAL_RCC_GPIOA_CLK_ENABLE&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  __HAL_RCC_GPIOB_CLK_ENABLE&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;GPIO 初始化函数使能了 GPIO 端口时钟，为 PWM 输出引脚提供时钟支持。&lt;/p&gt;
&lt;h3&gt;4.5 LED 亮度设置函数&lt;a href=&quot;#45-led-亮度设置函数&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; LED_SetBrightness&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; duty&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  __HAL_TIM_SET_COMPARE&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;htim10, TIM_CHANNEL_1, duty);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;LED_SetBrightness 函数通过设置 TIM10 通道 1 的比较寄存器(CCR)值来改变 PWM 占空比，从而控制 LED 亮度。占空比越大，LED 越亮；占空比越小，LED 越暗。&lt;/p&gt;
&lt;h3&gt;4.6 LED 渐变效果函数&lt;a href=&quot;#46-led-渐变效果函数&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; LED_GentleFade&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; start_duty&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; end_duty&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; int32_t&lt;/span&gt;&lt;span&gt; delta &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;int32_t&lt;/span&gt;&lt;span&gt;)end_duty &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; start_duty;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; step &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;; step &lt;/span&gt;&lt;span&gt;&amp;lt;=&lt;/span&gt;&lt;span&gt; LED_FADE_STEPS; &lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;step)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; uint16_t&lt;/span&gt;&lt;span&gt; duty &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt;)(start_duty &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; (delta &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; step) &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; LED_FADE_STEPS);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    LED_SetBrightness&lt;/span&gt;&lt;span&gt;(duty);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    HAL_Delay&lt;/span&gt;&lt;span&gt;(LED_FADE_STEP_MS);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;LED_GentleFade 函数实现了 LED 亮度的平滑渐变效果。它从起始占空比值开始，逐步改变到目标占空比值，每步之间有短暂的延迟。通过调整 LED_FADE_STEPS 和 LED_FADE_STEP_MS 参数，可以改变渐变的速度和平滑度。&lt;/p&gt;
&lt;h3&gt;4.7 错误处理函数&lt;a href=&quot;#47-错误处理函数&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; Error_Handler&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  /* User can add his own implementation to report the HAL error return state */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  __disable_irq&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  while&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;错误处理函数在发生错误时被调用，它会禁用中断并进入无限循环，防止系统继续运行。&lt;/p&gt;
&lt;h2&gt;5. 技术细节&lt;a href=&quot;#5-技术细节&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;5.1 PWM 原理&lt;a href=&quot;#51-pwm-原理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;PWM(Pulse Width Modulation，脉冲宽度调制)是一种通过改变脉冲宽度来控制信号的技术。在 LED 控制中，PWM 的占空比(高电平时间与整个周期的比值)决定了 LED 的平均亮度。占空比越高，LED 越亮；占空比越低，LED 越暗。&lt;/p&gt;
&lt;h3&gt;5.2 TIM10 定时器配置&lt;a href=&quot;#52-tim10-定时器配置&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;TIM10 是 STM32F407 上的一个 16 位定时器，具有以下特点：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;16 位自动重装载计数器&lt;/li&gt;
&lt;li&gt;多达 4 个独立通道(IC、OC 或 PWM)&lt;/li&gt;
&lt;li&gt;可编程预分频器&lt;/li&gt;
&lt;li&gt;重复计数器&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在本项目中，TIM10 配置为 PWM 模式，使用通道 1 输出 PWM 信号。定时器时钟为 84MHz(APB2 总线时钟)，预分频器为 0，自动重装载值为 65535，因此 PWM 频率为：
PWM 频率 = 定时器时钟 / (预分频器+1) / (自动重装载值+1) = 84MHz / 1 / 65536 ≈ 1281Hz&lt;/p&gt;
&lt;h3&gt;5.3 呼吸灯效果实现&lt;a href=&quot;#53-呼吸灯效果实现&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;呼吸灯效果是通过 LED_GentleFade 函数实现的，它将 LED 亮度从最小值渐变到最大值，再从最大值渐变回最小值。渐变过程分为多个步骤，每步之间有短暂的延迟，形成平滑的亮度变化效果。&lt;/p&gt;
&lt;p&gt;渐变步数和每步延迟时间决定了呼吸灯的速度和平滑度。步数越多，每步延迟时间越长，呼吸灯效果越平滑但速度越慢；反之则效果越明显但速度越快。&lt;/p&gt;
&lt;h3&gt;5.4 STM32 HAL 库使用&lt;a href=&quot;#54-stm32-hal-库使用&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;本项目使用 STM32 HAL 库进行开发，HAL 库提供了丰富的函数和结构体，简化了外设的配置和使用。例如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HAL_Init(): 初始化 HAL 库&lt;/li&gt;
&lt;li&gt;HAL_RCC_OscConfig(): 配置系统时钟源&lt;/li&gt;
&lt;li&gt;HAL_RCC_ClockConfig(): 配置系统时钟&lt;/li&gt;
&lt;li&gt;HAL_TIM_Base_Init(): 初始化定时器基本功能&lt;/li&gt;
&lt;li&gt;HAL_TIM_PWM_Init(): 初始化定时器 PWM 功能&lt;/li&gt;
&lt;li&gt;HAL_TIM_PWM_Start(): 启动 PWM 输出&lt;/li&gt;
&lt;li&gt;__HAL_TIM_SET_COMPARE(): 设置定时器比较值&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;5.5 代码结构和注释规范&lt;a href=&quot;#55-代码结构和注释规范&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;本项目遵循 STM32CubeMX 生成的代码结构，使用特定的注释标记用户代码区域，如：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;/* USER CODE BEGIN Header &lt;em&gt;/ 和 /&lt;/em&gt; USER CODE END Header */&lt;/li&gt;
&lt;li&gt;/* USER CODE BEGIN Includes &lt;em&gt;/ 和 /&lt;/em&gt; USER CODE END Includes */&lt;/li&gt;
&lt;li&gt;/* USER CODE BEGIN 2 &lt;em&gt;/ 和 /&lt;/em&gt; USER CODE END 2 */&lt;/li&gt;
&lt;li&gt;/* USER CODE BEGIN 3 &lt;em&gt;/ 和 /&lt;/em&gt; USER CODE END 3 */&lt;/li&gt;
&lt;li&gt;/* USER CODE BEGIN 4 &lt;em&gt;/ 和 /&lt;/em&gt; USER CODE END 4 */&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这种结构使得在重新生成代码时，用户代码不会被覆盖，提高了代码的可维护性。&lt;/p&gt;
&lt;h2&gt;6. 项目特点&lt;a href=&quot;#6-项目特点&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;模块化设计&lt;/strong&gt;: 将 LED 控制功能封装为独立函数，便于维护和扩展。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数化配置&lt;/strong&gt;: 使用常量定义呼吸灯效果参数，便于调整。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;错误处理&lt;/strong&gt;: 实现了基本的错误处理机制。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;代码规范&lt;/strong&gt;: 遵循 STM32 HAL 库的代码规范和注释风格。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可扩展性&lt;/strong&gt;: 代码结构清晰，便于添加新的功能或修改现有功能。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;7. 应用场景&lt;a href=&quot;#7-应用场景&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;本项目实现的 PWM LED 控制技术可以应用于多种场景：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LED 照明控制&lt;/li&gt;
&lt;li&gt;指示灯亮度调节&lt;/li&gt;
&lt;li&gt;装饰灯效果&lt;/li&gt;
&lt;li&gt;背光亮度调节&lt;/li&gt;
&lt;li&gt;信号灯控制&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;8. 总结&lt;a href=&quot;#8-总结&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;本项目展示了如何使用 STM32F407 的定时器 PWM 功能实现 LED 亮度控制和呼吸灯效果。通过合理配置定时器参数和编写控制函数，实现了 LED 亮度的平滑调节。代码结构清晰，遵循 STM32 HAL 库的规范，具有良好的可维护性和可扩展性。该示例可以作为学习 STM32 定时器 PWM 功能和 LED 控制技术的参考。&lt;/p&gt;</content:encoded><category>category:笔记</category><category>category:STM32</category><category>tag:STM32</category><category>tag:嵌入式</category><category>tag:筑基派</category></item><item><title>整形溢出_IntegerOverflow</title><link>https://729dhs.site/post/int_overflow</link><guid isPermaLink="false">int_overflow</guid><description>整形溢出是常见的编程错误,在嵌入式这种资源受限场景尤其常见,本文讲述解决方式</description><pubDate>Thu, 02 Apr 2026 13:02:17 GMT</pubDate><content:encoded>&lt;h1&gt;整数溢出 (Integer Overflow) 技术笔记&lt;a href=&quot;#整数溢出-integer-overflow-技术笔记&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2&gt; 核心概念&lt;a href=&quot;#-核心概念&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;整数溢出&lt;/strong&gt;是指算术运算的结果超出了数据类型所能表示的数值范围。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;无符号整数溢出&lt;/strong&gt;：在 C/C++ 标准中是&lt;strong&gt;合法&lt;/strong&gt;的，结果会发生&lt;strong&gt;回绕 (Wrap-around)&lt;/strong&gt;，即从最大值跳变到最小值（或反之），导致逻辑错误。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;有符号整数溢出&lt;/strong&gt;：属于&lt;strong&gt;未定义行为 (Undefined Behavior)&lt;/strong&gt;，可能导致程序崩溃、计算错误或安全漏洞。&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;示例类型范围&lt;/strong&gt;：&lt;code&gt;uint16_t&lt;/code&gt; (16 位无符号整数) 的取值范围为 &lt;code&gt;0 ~ 65535&lt;/code&gt; (&lt;span&gt;&lt;span&gt;216−12^{16} - 1&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;16&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;−&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;)。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt; 典型场景分析：PWM 占空比渐变&lt;a href=&quot;#-典型场景分析pwm-占空比渐变&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;在嵌入式开发中，计算两个无符号整数的差值（如 PWM 占空比的变化量）是常见场景。若处理不当，极易引发溢出。&lt;/p&gt;
&lt;h3&gt;❌ 错误做法：直接相减&lt;a href=&quot;#-错误做法直接相减&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;当 &lt;code&gt;end_duty &amp;lt; start_duty&lt;/code&gt; 时，无符号减法会导致向下溢出。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; start &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 1000&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; end &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 500&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 错误做法&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; delta1 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; end &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; start; &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 500 - 1000 = -500&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 但 uint16_t 不能存负数，会自动回绕：65536 - 500 = 65036（完全错误）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这就是&lt;strong&gt;典型的无符号整数溢出&lt;/strong&gt;。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 正确做法&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;int32_t&lt;/span&gt;&lt;span&gt; delta2 &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;int32_t&lt;/span&gt;&lt;span&gt;)end &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; start; &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 先把 end 强转为 32位有符号整数，运算结果也是有符号数&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 可以正常存储负数，结果 = -500（正确）&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;️ 常见防溢出技巧&lt;a href=&quot;#️-常见防溢出技巧&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. &lt;strong&gt;类型提升（Type Promotion）&lt;/strong&gt;&lt;a href=&quot;#1-类型提升type-promotion&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 加法溢出防护&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; a &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 60000&lt;/span&gt;&lt;span&gt;, b &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 60000&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;uint32_t&lt;/span&gt;&lt;span&gt; sum &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;uint32_t&lt;/span&gt;&lt;span&gt;)a &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; b;&lt;/span&gt;&lt;span&gt;  // 提升到32位再相加&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (sum &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; 65535&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 处理溢出&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 乘法溢出防护&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; x &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 1000&lt;/span&gt;&lt;span&gt;, y &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 1000&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;uint32_t&lt;/span&gt;&lt;span&gt; product &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;uint32_t&lt;/span&gt;&lt;span&gt;)x &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; y;&lt;/span&gt;&lt;span&gt;  // 1,000,000 不会溢出32位&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. &lt;strong&gt;预检查（Pre-check）&lt;/strong&gt;&lt;a href=&quot;#2-预检查pre-check&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; add_with_check&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; b&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (a &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; UINT16_MAX &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; b) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        // 会溢出，返回最大值或报错&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        return&lt;/span&gt;&lt;span&gt; UINT16_MAX;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; a &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; b;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 乘法预检查&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; mul_with_check&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; b&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (a &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt; &amp;amp;&amp;amp;&lt;/span&gt;&lt;span&gt; b &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; UINT16_MAX &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; a) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        return&lt;/span&gt;&lt;span&gt; UINT16_MAX;&lt;/span&gt;&lt;span&gt;  // 溢出&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; a &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; b;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;3. &lt;strong&gt;使用更大的中间类型&lt;/strong&gt;&lt;a href=&quot;#3-使用更大的中间类型&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 你的代码中的例子&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; int32_t&lt;/span&gt;&lt;span&gt; delta &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;int32_t&lt;/span&gt;&lt;span&gt;)end_duty &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; start_duty;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 后续计算&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; duty &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt;)(start_duty &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; (delta &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; step) &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; LED_FADE_STEPS);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;//                   ^^^^^ 最终转回 uint16_t&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;//                   delta * step 最大约 60000 * 70 = 4.2M &amp;lt; 2^31，安全&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. &lt;strong&gt;饱和运算（Saturation）&lt;/strong&gt;&lt;a href=&quot;#4-饱和运算saturation&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; saturated_add&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; b&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    uint32_t&lt;/span&gt;&lt;span&gt; result &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;uint32_t&lt;/span&gt;&lt;span&gt;)a &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; b;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; (result &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; UINT16_MAX) &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; UINT16_MAX &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt;)result;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 用于PWM占空比限制&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; duty &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; saturated_add&lt;/span&gt;&lt;span&gt;(current_duty, increment);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5. &lt;strong&gt;使用编译器内置溢出检查（GCC/Clang）&lt;/strong&gt;&lt;a href=&quot;#5-使用编译器内置溢出检查gccclang&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;#include&lt;/span&gt;&lt;span&gt; &amp;lt;stdint.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;int32_t&lt;/span&gt;&lt;span&gt; multiply_with_overflow_check&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;int32_t&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;int32_t&lt;/span&gt;&lt;span&gt; b&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    int32_t&lt;/span&gt;&lt;span&gt; result;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;__builtin_mul_overflow&lt;/span&gt;&lt;span&gt;(a, b, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;result)) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        // 溢出发生了&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        return&lt;/span&gt;&lt;span&gt; INT32_MAX;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; result;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 检查加法&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;int32_t&lt;/span&gt;&lt;span&gt; add_with_overflow_check&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;int32_t&lt;/span&gt;&lt;span&gt; a&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;int32_t&lt;/span&gt;&lt;span&gt; b&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    int32_t&lt;/span&gt;&lt;span&gt; result;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;__builtin_add_overflow&lt;/span&gt;&lt;span&gt;(a, b, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;result)) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        return&lt;/span&gt;&lt;span&gt; INT32_MAX;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; result;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;6. &lt;strong&gt;定时器场景的特殊技巧&lt;/strong&gt;&lt;a href=&quot;#6-定时器场景的特殊技巧&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 处理定时器计数器溢出（常见于编码器、输入捕获）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; uint16_t&lt;/span&gt;&lt;span&gt; last_count &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; uint16_t&lt;/span&gt;&lt;span&gt; overflow_count &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; timer_irq_handler&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    uint16_t&lt;/span&gt;&lt;span&gt; current_count &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; TIM2-&amp;gt;CNT;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 检测向下溢出（递减计数）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (current_count &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; last_count) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        overflow_count&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;  // 处理溢出&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 计算实际32位计数值&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    uint32_t&lt;/span&gt;&lt;span&gt; real_count &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (overflow_count &lt;/span&gt;&lt;span&gt;&amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt; 16&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; current_count;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    last_count &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; current_count;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt; 你的代码中的完整防溢出分析&lt;a href=&quot;#-你的代码中的完整防溢出分析&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; LED_GentleFade&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; start_duty&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; end_duty&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    const&lt;/span&gt;&lt;span&gt; int32_t&lt;/span&gt;&lt;span&gt; delta &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;int32_t&lt;/span&gt;&lt;span&gt;)end_duty &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; start_duty;&lt;/span&gt;&lt;span&gt;  // ✅ 防止减法溢出&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    for&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; step &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;; step &lt;/span&gt;&lt;span&gt;&amp;lt;=&lt;/span&gt;&lt;span&gt; LED_FADE_STEPS; &lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;step)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        // 危险计算：(delta * step) / LED_FADE_STEPS&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        // delta 最大 60000, step 最大 70 → 乘积 4.2M&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        // int32_t 最大 2.1B，所以安全&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        const&lt;/span&gt;&lt;span&gt; uint16_t&lt;/span&gt;&lt;span&gt; duty &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt;)(start_duty &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; (delta &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; step) &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; LED_FADE_STEPS);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        //            ^^^^^ 最终结果范围 0~60000，转回 uint16_t 安全&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        LED_SetBrightness&lt;/span&gt;&lt;span&gt;(duty);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        HAL_Delay&lt;/span&gt;&lt;span&gt;(LED_FADE_STEP_MS);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;潜在风险（已避免）：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;如果 &lt;code&gt;LED_FADE_STEPS&lt;/code&gt; 改成 1000，&lt;code&gt;delta * step&lt;/code&gt; 最大 60M，仍然安全&lt;/li&gt;
&lt;li&gt;如果 &lt;code&gt;LED_PWM_DUTY_MAX&lt;/code&gt; 改成 600000（超过 uint16_t），代码会出问题&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt; 最佳实践总结&lt;a href=&quot;#-最佳实践总结&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;

































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;场景&lt;/th&gt;&lt;th&gt;推荐技巧&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;减法可能导致负数&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;提升到有符号类型 &lt;code&gt;(int32_t)a - b&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;两个小整数相加&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;提升到更大类型 &lt;code&gt;(uint32_t)a + b&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;乘法可能溢出&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;预检查 &lt;code&gt;if (a &amp;gt; MAX / b)&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;循环累加&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;使用更大类型累加，最后再截断&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;时间差值计算&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;使用无符号减法（利用回绕特性）配合溢出标志&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;PID/滤波计算&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;使用浮点或定点数并做饱和处理&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt; 实用工具宏&lt;a href=&quot;#-实用工具宏&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 安全加法宏（饱和）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#define&lt;/span&gt;&lt;span&gt; SAFE_ADD_U16&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;) ((&lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt;)(((&lt;/span&gt;&lt;span&gt;uint32_t&lt;/span&gt;&lt;span&gt;)(a) &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; (b)) &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; UINT16_MAX &lt;/span&gt;&lt;span&gt;?&lt;/span&gt;&lt;span&gt; UINT16_MAX &lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt; ((a) &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; (b))))&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 安全减法（带符号提升）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#define&lt;/span&gt;&lt;span&gt; SAFE_SUB_U16&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;) ((&lt;/span&gt;&lt;span&gt;int32_t&lt;/span&gt;&lt;span&gt;)(a) &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;int32_t&lt;/span&gt;&lt;span&gt;)(b))&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 检查加法是否溢出&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#define&lt;/span&gt;&lt;span&gt; ADD_OVERFLOW_U16&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;b&lt;/span&gt;&lt;span&gt;) (((&lt;/span&gt;&lt;span&gt;uint32_t&lt;/span&gt;&lt;span&gt;)(a) &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; (b)) &lt;/span&gt;&lt;span&gt;&amp;gt;&lt;/span&gt;&lt;span&gt; UINT16_MAX)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 使用示例&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; pwm &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 60000&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; inc &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 10000&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;ADD_OVERFLOW_U16&lt;/span&gt;&lt;span&gt;(pwm, inc)) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    pwm &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; UINT16_MAX;&lt;/span&gt;&lt;span&gt;  // 饱和到最大值&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    pwm &lt;/span&gt;&lt;span&gt;+=&lt;/span&gt;&lt;span&gt; inc;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded><category>category:笔记</category><category>category:C语言</category><category>tag:C语言</category><category>tag:STM32</category></item><item><title>嘉立创筑基派点灯DEMO</title><link>https://729dhs.site/post/jlc-blink-demo-1</link><guid isPermaLink="false">jlc-blink-demo-1</guid><description>嘉立创筑基派点灯DEMO,使用自带PC13LED</description><pubDate>Thu, 02 Apr 2026 02:56:51 GMT</pubDate><content:encoded>&lt;h1&gt;嘉立创筑基派点灯 DEMO_1&lt;a href=&quot;#嘉立创筑基派点灯-demo_1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;</content:encoded><category>category:笔记</category><category>category:STM32</category><category>tag:STM32</category><category>tag:嵌入式</category><category>tag:筑基派</category></item><item><title>FreeRTOS 基础概念与 API 入门（STM32 新手向）</title><link>https://729dhs.site/post/freertos-basic-api-stm32</link><guid isPermaLink="false">freertos-basic-api-stm32</guid><description>本文面向 STM32 新手，系统梳理 FreeRTOS 的核心概念、任务状态、关键 API 及常见开发陷阱，配套最小工程模板与可视化状态图。</description><pubDate>Tue, 31 Mar 2026 04:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;FreeRTOS 基础概念与 API 入门（STM32 新手向）&lt;a href=&quot;#freertos-基础概念与-api-入门stm32-新手向&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;目标：看完这份笔记，你可以独立搭出一个“2 任务 + 1 队列 + 1 信号量”的最小 FreeRTOS 工程。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;目录&lt;a href=&quot;#目录&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;ol&gt;
&lt;li&gt;先建立整体认知&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ol&gt;
&lt;li&gt;任务运行状态（核心）&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ol&gt;
&lt;li&gt;关键概念：调度、Tick、临界区、堆与栈&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ol&gt;
&lt;li&gt;核心 API 速查（原生 FreeRTOS）&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ol&gt;
&lt;li&gt;从 0 到 1 最小工程心智模型&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ol&gt;
&lt;li&gt;新手高频坑与排查&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ol&gt;
&lt;li&gt;5 天入门练习清单&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ol&gt;
&lt;li&gt;原生 API 与 CMSIS-RTOS v2 对照&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;1. 先建立整体认知&lt;a href=&quot;#1-先建立整体认知&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FreeRTOS 本质是一个内核，它帮你做三件事：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;管理多个任务（Task）。&lt;/li&gt;
&lt;li&gt;按优先级和时机调度任务运行。&lt;/li&gt;
&lt;li&gt;提供任务间通信手段（队列、信号量、事件组等）。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;你可以把它理解为“单片机上的微型操作系统内核”：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;main()&lt;/code&gt; 里做硬件初始化。&lt;/li&gt;
&lt;li&gt;创建任务。&lt;/li&gt;
&lt;li&gt;启动调度器。&lt;/li&gt;
&lt;li&gt;从此由内核接管 CPU 分配。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;2. 任务运行状态（核心）&lt;a href=&quot;#2-任务运行状态核心&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;2.2 任务状态流（可视化）&lt;a href=&quot;#22-任务状态流可视化&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;stateDiagram-v2
    [*] --&amp;gt; Ready
    Ready --&amp;gt; Running: 获得CPU
    Running --&amp;gt; Blocked: 等待事件
    Blocked --&amp;gt; Ready: 事件发生
    Running --&amp;gt; Ready: 时间片用尽
    Running --&amp;gt; Suspended: 挂起
    Suspended --&amp;gt; Ready: 恢复&lt;/pre&gt;
&lt;h3&gt;2.3 新手最容易混淆&lt;a href=&quot;#23-新手最容易混淆&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Blocked&lt;/code&gt; 是“被动等待条件”，条件满足会自动回到 &lt;code&gt;Ready&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Suspended&lt;/code&gt; 是“人为冻结”，不会自动恢复。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;3. 关键概念：调度、Tick、临界区、堆与栈&lt;a href=&quot;#3-关键概念调度tick临界区堆与栈&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;3.1 优先级与抢占&lt;a href=&quot;#31-优先级与抢占&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;FreeRTOS 通常是“高优先级优先运行”。&lt;/li&gt;
&lt;li&gt;抢占开启时（&lt;code&gt;configUSE_PREEMPTION=1&lt;/code&gt;），更高优先级就绪会打断低优先级任务。&lt;/li&gt;
&lt;li&gt;同优先级是否时间片轮转取决于 &lt;code&gt;configUSE_TIME_SLICING&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;建议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;先把任务优先级分成 2~3 档，不要一开始全拉开。&lt;/li&gt;
&lt;li&gt;高优先级只放“短、急、关键”任务。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.2 Tick 与延时&lt;a href=&quot;#32-tick-与延时&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Tick 是内核时基中断（例如 1ms 一次，取决于 &lt;code&gt;configTICK_RATE_HZ&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vTaskDelay()&lt;/code&gt; 的参数单位是 Tick，不是 ms。&lt;/li&gt;
&lt;li&gt;推荐用 &lt;code&gt;pdMS_TO_TICKS(ms)&lt;/code&gt; 做转换。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;vTaskDelay&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;pdMS_TO_TICKS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;500&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;vTaskDelay()&lt;/code&gt; vs &lt;code&gt;vTaskDelayUntil()&lt;/code&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;vTaskDelay()&lt;/code&gt;：相对延时，循环中会累积漂移。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vTaskDelayUntil()&lt;/code&gt;：绝对周期，更适合周期任务。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.3 临界区&lt;a href=&quot;#33-临界区&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;用于保护共享资源，防止并发访问破坏数据。&lt;/p&gt;
&lt;p&gt;任务上下文常用：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;taskENTER_CRITICAL&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;/* critical section */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;taskEXIT_CRITICAL&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;原则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;临界区要短。&lt;/li&gt;
&lt;li&gt;临界区内不要做阻塞操作（如队列阻塞等待）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.4 空闲任务与 Tick Hook&lt;a href=&quot;#34-空闲任务与-tick-hook&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;空闲任务（Idle Task）在“无任务可运行”时执行。&lt;/li&gt;
&lt;li&gt;可用 Idle Hook/Tick Hook 做轻量背景工作（必须非常短）。&lt;/li&gt;
&lt;li&gt;不建议在 Hook 里写复杂逻辑。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.5 堆与栈（必须分清）&lt;a href=&quot;#35-堆与栈必须分清&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;栈（Stack）：每个任务独立，存函数局部变量/调用现场。&lt;/li&gt;
&lt;li&gt;堆（Heap）：系统动态分配区，任务控制块、队列等常从堆申请。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;常见问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;任务栈太小 -&amp;gt; 栈溢出。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;heap_x.c&lt;/code&gt; 选型不当或堆太小 -&amp;gt; 创建对象失败。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;4. 核心 API 速查（原生 FreeRTOS）&lt;a href=&quot;#4-核心-api-速查原生-freertos&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;说明：以下以原生 API 为主，CMSIS 对照见第 8 节。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;4.1 任务管理&lt;a href=&quot;#41-任务管理&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;xTaskCreate()&lt;/code&gt;：创建任务。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vTaskDelete()&lt;/code&gt;：删除任务。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vTaskDelay()&lt;/code&gt;：相对延时。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vTaskDelayUntil()&lt;/code&gt;：固定周期延时。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vTaskSuspend()&lt;/code&gt; / &lt;code&gt;vTaskResume()&lt;/code&gt;：挂起/恢复任务。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;最小示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;xTaskCreate&lt;/span&gt;&lt;span&gt;(TaskA, &lt;/span&gt;&lt;span&gt;&quot;A&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;256&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;xTaskCreate&lt;/span&gt;&lt;span&gt;(TaskB, &lt;/span&gt;&lt;span&gt;&quot;B&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;256&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;vTaskStartScheduler&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.2 队列（Queue）&lt;a href=&quot;#42-队列queue&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;用途：任务间传数据（最常用）。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;xQueueCreate(len, item_size)&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xQueueSend()&lt;/code&gt; / &lt;code&gt;xQueueReceive()&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;QueueHandle_t&lt;/span&gt;&lt;span&gt; q &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; xQueueCreate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;sizeof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;uint32_t&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;uint32_t&lt;/span&gt;&lt;span&gt; v &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 123&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;xQueueSend&lt;/span&gt;&lt;span&gt;(q, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;pdMS_TO_TICKS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;xQueueReceive&lt;/span&gt;&lt;span&gt;(q, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;v&lt;/span&gt;&lt;span&gt;, portMAX_DELAY);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;item_size&lt;/code&gt; 要和收发数据类型一致。&lt;/li&gt;
&lt;li&gt;发送接收的超时参数单位是 Tick。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4.3 信号量与互斥量&lt;a href=&quot;#43-信号量与互斥量&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;二值信号量：事件同步。&lt;/li&gt;
&lt;li&gt;计数信号量：资源计数。&lt;/li&gt;
&lt;li&gt;互斥量：共享资源互斥，带优先级继承。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;常用 API：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;xSemaphoreCreateBinary()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xSemaphoreCreateCounting()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xSemaphoreCreateMutex()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xSemaphoreTake()&lt;/code&gt; / &lt;code&gt;xSemaphoreGive()&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;建议：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;保护共享外设（如串口）优先用互斥量。&lt;/li&gt;
&lt;li&gt;ISR 到任务同步常用二值信号量或任务通知。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4.4 事件组（Event Group）&lt;a href=&quot;#44-事件组event-group&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;用途：多个事件位组合判断（如“网络就绪 + 传感器就绪”）。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;xEventGroupCreate()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xEventGroupSetBits()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xEventGroupWaitBits()&lt;/code&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;4.5 软件定时器（Software Timer）&lt;a href=&quot;#45-软件定时器software-timer&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;用途：定时执行轻量回调。&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;xTimerCreate()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;xTimerStart()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;回调函数中避免耗时和阻塞。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;4.6 中断协作（ISR 与任务）&lt;a href=&quot;#46-中断协作isr-与任务&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;规则：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ISR 里必须用 &lt;code&gt;FromISR&lt;/code&gt; 版本 API。&lt;/li&gt;
&lt;li&gt;可能触发任务切换时，调用 &lt;code&gt;portYIELD_FROM_ISR()&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;BaseType_t&lt;/span&gt;&lt;span&gt; hpw &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; pdFALSE;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;xQueueSendFromISR&lt;/span&gt;&lt;span&gt;(q, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;data&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;hpw&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;portYIELD_FROM_ISR&lt;/span&gt;&lt;span&gt;(hpw);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;中断优先级注意：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cortex-M 下要确保可调用 FreeRTOS API 的中断优先级配置正确。&lt;/li&gt;
&lt;li&gt;重点关注 &lt;code&gt;configMAX_SYSCALL_INTERRUPT_PRIORITY&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;5. 从 0 到 1 最小工程心智模型&lt;a href=&quot;#5-从-0-到-1-最小工程心智模型&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;5.1 &lt;code&gt;main()&lt;/code&gt; 推荐顺序&lt;a href=&quot;#51-main-推荐顺序&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;时钟/中断分组初始化。&lt;/li&gt;
&lt;li&gt;外设初始化（GPIO/UART 等）。&lt;/li&gt;
&lt;li&gt;创建通信对象（Queue/Semaphore）。&lt;/li&gt;
&lt;li&gt;创建任务。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vTaskStartScheduler()&lt;/code&gt; 启动调度器。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;5.2 任务划分建议（新手版）&lt;a href=&quot;#52-任务划分建议新手版&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;采集任务：读传感器，发队列。&lt;/li&gt;
&lt;li&gt;处理任务：收队列，计算。&lt;/li&gt;
&lt;li&gt;输出任务：串口/屏幕输出。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;避免：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;一个任务里什么都干。&lt;/li&gt;
&lt;li&gt;多个任务同时直接操作同一外设且无互斥。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;5.3 典型双任务流程（LED + 串口）&lt;a href=&quot;#53-典型双任务流程led--串口&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;任务 A（LED）：500ms 翻转一次，证明调度在跑。&lt;/li&gt;
&lt;li&gt;任务 B（UART）：每 1s 打印计数。&lt;/li&gt;
&lt;li&gt;两任务优先级先设相同，确认稳定后再调优。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;达标标准：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LED 按周期闪烁。&lt;/li&gt;
&lt;li&gt;串口稳定打印，系统不死机、不乱序。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;6. 新手高频坑与排查&lt;a href=&quot;#6-新手高频坑与排查&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;6.1 栈溢出&lt;a href=&quot;#61-栈溢出&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;现象：莫名 HardFault、随机死机。&lt;/p&gt;
&lt;p&gt;排查：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;开启栈溢出检测（&lt;code&gt;configCHECK_FOR_STACK_OVERFLOW&lt;/code&gt;）。&lt;/li&gt;
&lt;li&gt;增大可疑任务栈。&lt;/li&gt;
&lt;li&gt;避免大数组放栈上，改静态或堆。&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;6.2 阻塞时间单位写错&lt;a href=&quot;#62-阻塞时间单位写错&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;把 Tick 当 ms 会导致节奏错乱。&lt;/li&gt;
&lt;li&gt;统一使用 &lt;code&gt;pdMS_TO_TICKS()&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;6.3 ISR 调错 API&lt;a href=&quot;#63-isr-调错-api&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;ISR 中误用 &lt;code&gt;xQueueSend()&lt;/code&gt; 而不是 &lt;code&gt;xQueueSendFromISR()&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;结果可能是断言失败或异常行为。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;6.4 队列长度或元素大小不匹配&lt;a href=&quot;#64-队列长度或元素大小不匹配&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;队列元素定义和实际收发类型不一致会导致“看似能跑但数据错乱”。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;6.5 死锁&lt;a href=&quot;#65-死锁&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;任务 A 等 B 的锁，B 又等 A 的锁。&lt;/li&gt;
&lt;li&gt;保持锁顺序一致，减少嵌套锁。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;6.6 优先级反转&lt;a href=&quot;#66-优先级反转&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;低优先级占互斥资源导致高优先级被间接阻塞。&lt;/li&gt;
&lt;li&gt;共享资源优先用互斥量（有优先级继承）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;6.7 &lt;code&gt;printf&lt;/code&gt; 风险&lt;a href=&quot;#67-printf-风险&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;栈占用大、耗时长、重入性风险。&lt;/li&gt;
&lt;li&gt;建议：
&lt;ul&gt;
&lt;li&gt;降低打印频率。&lt;/li&gt;
&lt;li&gt;避免在 ISR 内打印。&lt;/li&gt;
&lt;li&gt;关键路径用轻量日志。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;7. 5 天入门练习清单&lt;a href=&quot;#7-5-天入门练习清单&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;Day 1：跑通最小双任务&lt;a href=&quot;#day-1跑通最小双任务&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;目标：LED 任务 + UART 任务并发运行。&lt;/li&gt;
&lt;li&gt;验证：LED 稳定闪烁，串口 1s 输出一次。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Day 2：队列通信&lt;a href=&quot;#day-2队列通信&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;目标：TaskA 发送计数到队列，TaskB 接收并打印。&lt;/li&gt;
&lt;li&gt;验证：打印值连续且无丢失。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Day 3：信号量同步&lt;a href=&quot;#day-3信号量同步&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;目标：按键中断释放信号量，任务被唤醒处理。&lt;/li&gt;
&lt;li&gt;验证：无按键时任务阻塞，按下后立即响应。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Day 4：软件定时器&lt;a href=&quot;#day-4软件定时器&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;目标：用软件定时器周期触发状态上报。&lt;/li&gt;
&lt;li&gt;验证：回调按固定周期执行。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Day 5：ISR 到任务通知&lt;a href=&quot;#day-5isr-到任务通知&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;目标：中断使用 &lt;code&gt;FromISR&lt;/code&gt; API 唤醒任务。&lt;/li&gt;
&lt;li&gt;验证：中断响应后任务快速运行，系统稳定。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;8. 原生 API 与 CMSIS-RTOS v2 对照&lt;a href=&quot;#8-原生-api-与-cmsis-rtos-v2-对照&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;仅列最常用映射，便于读不同教程时快速切换：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;任务创建：&lt;code&gt;xTaskCreate&lt;/code&gt; &amp;lt;-&amp;gt; &lt;code&gt;osThreadNew&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;延时：&lt;code&gt;vTaskDelay&lt;/code&gt; &amp;lt;-&amp;gt; &lt;code&gt;osDelay&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;启动调度：&lt;code&gt;vTaskStartScheduler&lt;/code&gt; &amp;lt;-&amp;gt; &lt;code&gt;osKernelStart&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;队列发送/接收：&lt;code&gt;xQueueSend/xQueueReceive&lt;/code&gt; &amp;lt;-&amp;gt; &lt;code&gt;osMessageQueuePut/osMessageQueueGet&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;信号量获取/释放：&lt;code&gt;xSemaphoreTake/xSemaphoreGive&lt;/code&gt; &amp;lt;-&amp;gt; &lt;code&gt;osSemaphoreAcquire/osSemaphoreRelease&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;结论：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;新手建议先掌握原生 FreeRTOS API，再看 CMSIS 封装。&lt;/li&gt;
&lt;li&gt;两者思路一致，主要差在命名和包装层。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;最后检查清单（写代码前看一遍）&lt;a href=&quot;#最后检查清单写代码前看一遍&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Tick 与 ms 是否都用 &lt;code&gt;pdMS_TO_TICKS()&lt;/code&gt; 统一转换？&lt;/li&gt;
&lt;li&gt;ISR 是否全部使用 &lt;code&gt;FromISR&lt;/code&gt; API？&lt;/li&gt;
&lt;li&gt;共享外设是否有互斥保护？&lt;/li&gt;
&lt;li&gt;各任务栈大小是否留有余量？&lt;/li&gt;
&lt;li&gt;阻塞等待是否都设置了合理超时？&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;9. 可直接运行的最小工程模板（可复制到 STM32 工程）&lt;a href=&quot;#9-可直接运行的最小工程模板可复制到-stm32-工程&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;下面示例是一个可直接拷贝到用户工程的最小 FreeRTOS 骨架：两个任务（LED、UART），一个队列和一个互斥量。注：外设初始化（UART/GPIO）请按你的 HAL/LL 实现替换。&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;/* 全局对象 */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;QueueHandle_t&lt;/span&gt;&lt;span&gt; g_queue;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;SemaphoreHandle_t&lt;/span&gt;&lt;span&gt; g_uartMutex;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; LedTask&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt;pvParameters&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    (&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;) pvParameters;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    for&lt;/span&gt;&lt;span&gt; (;;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        HAL_GPIO_TogglePin&lt;/span&gt;&lt;span&gt;(LED_GPIO_Port, LED_Pin);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        vTaskDelay&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;pdMS_TO_TICKS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;500&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;span&gt; // Blocked 状态&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; UartTask&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt;pvParameters&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    (&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;) pvParameters;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    uint32_t&lt;/span&gt;&lt;span&gt; cnt &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    char&lt;/span&gt;&lt;span&gt; buf&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;64&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    for&lt;/span&gt;&lt;span&gt; (;;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;xSemaphoreTake&lt;/span&gt;&lt;span&gt;(g_uartMutex, &lt;/span&gt;&lt;span&gt;pdMS_TO_TICKS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;50&lt;/span&gt;&lt;span&gt;)) &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; pdPASS)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            int&lt;/span&gt;&lt;span&gt; n &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; snprintf&lt;/span&gt;&lt;span&gt;(buf, &lt;/span&gt;&lt;span&gt;sizeof&lt;/span&gt;&lt;span&gt;(buf), &lt;/span&gt;&lt;span&gt;&quot;cnt=&lt;/span&gt;&lt;span&gt;%lu\r\n&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;, (&lt;/span&gt;&lt;span&gt;unsigned&lt;/span&gt;&lt;span&gt; long&lt;/span&gt;&lt;span&gt;)cnt&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            HAL_UART_Transmit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;huart1, (&lt;/span&gt;&lt;span&gt;uint8_t*&lt;/span&gt;&lt;span&gt;)buf, n, HAL_MAX_DELAY);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            xSemaphoreGive&lt;/span&gt;&lt;span&gt;(g_uartMutex);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        vTaskDelay&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;pdMS_TO_TICKS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1000&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    HAL_Init&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    SystemClock_Config&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    MX_GPIO_Init&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    MX_USART1_UART_Init&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    g_queue &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; xQueueCreate&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;sizeof&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;uint32_t&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    g_uartMutex &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; xSemaphoreCreateMutex&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (g_queue &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; NULL&lt;/span&gt;&lt;span&gt; ||&lt;/span&gt;&lt;span&gt; g_uartMutex &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; NULL&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        Error_Handler&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    xTaskCreate&lt;/span&gt;&lt;span&gt;(LedTask, &lt;/span&gt;&lt;span&gt;&quot;LED&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;128&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    xTaskCreate&lt;/span&gt;&lt;span&gt;(UartTask, &lt;/span&gt;&lt;span&gt;&quot;UART&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;256&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    vTaskStartScheduler&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span&gt; // 不会返回，FreeRTOS 接管&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    for&lt;/span&gt;&lt;span&gt; (;;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;10. 常用 FreeRTOSConfig 宏与行为映射（快速参考）&lt;a href=&quot;#10-常用-freertosconfig-宏与行为映射快速参考&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;configUSE_PREEMPTION = 1&lt;/code&gt; : 启用抢占，优先级高的任务就绪会立即切换上 CPU。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;configUSE_TIME_SLICING = 1&lt;/code&gt; : 同优先级任务之间启用时间片轮转（若为 0 则同优先级可能不轮转）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;configTICK_RATE_HZ&lt;/code&gt; : tick 频率（例如 1000 -&amp;gt; 1 tick = 1 ms），影响 vTaskDelay 等。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;configMINIMAL_STACK_SIZE&lt;/code&gt; : 默认任务最小栈大小，创建任务时要基于此合理估算。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;configMAX_PRIORITIES&lt;/code&gt; : 允许的最大优先级数量。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;configCHECK_FOR_STACK_OVERFLOW&lt;/code&gt; : 启用栈溢出检测（建议设 1 或 2 并实现 vApplicationStackOverflowHook）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;configUSE_MUTEXES&lt;/code&gt; : 使能互斥量（优先级继承），建议用于共享外设保护。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;configMAX_SYSCALL_INTERRUPT_PRIORITY&lt;/code&gt; / Cortex-M 中断优先级配置：确保使用 FreeRTOS API 的中断优先级不高于此阈值。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;在文档中应说明这些宏通常在 &lt;code&gt;FreeRTOSConfig.h&lt;/code&gt; 中修改，并给出常见工程的推荐值或范围。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;11. 常见错误写法与正确写法对照（训练式示例）&lt;a href=&quot;#11-常见错误写法与正确写法对照训练式示例&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;错误：在 ISR 中调用 &lt;code&gt;xQueueSend()&lt;/code&gt;（会导致不可预测行为或断言）
正确：在 ISR 中调用 &lt;code&gt;xQueueSendFromISR()&lt;/code&gt; 并在需要时调用 &lt;code&gt;portYIELD_FROM_ISR()&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;错误：多个任务直接调用 &lt;code&gt;HAL_UART_Transmit()&lt;/code&gt;（非线程安全，可能数据交错）
正确：为串口创建一个互斥量，所有任务在发送前 &lt;code&gt;xSemaphoreTake()&lt;/code&gt;，发送后 &lt;code&gt;xSemaphoreGive()&lt;/code&gt;。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;错误：队列创建时 &lt;code&gt;item_size&lt;/code&gt; 与传入类型不匹配（例如 sizeof(uint32_t) 但传入结构体指针）
正确：队列元素大小应与实际传入的数据类型完全一致，或发送指针并确保生命周期。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;错误：在临界区中做阻塞调用（例如在 taskENTER_CRITICAL() 后调用 xQueueReceive(portMAX_DELAY)）
正确：临界区内仅做短、小且非阻塞的操作，阻塞操作应在临界区外执行。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;12. 调试与观测：如何判断栈/队列/调度问题&lt;a href=&quot;#12-调试与观测如何判断栈队列调度问题&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;查看任务栈水位：&lt;code&gt;uxTaskGetStackHighWaterMark()&lt;/code&gt; 可以返回任务已使用栈的最小剩余值（单位平台相关），用于评估是否需要增大栈。&lt;/li&gt;
&lt;li&gt;实现钩子：实现 &lt;code&gt;vApplicationStackOverflowHook()&lt;/code&gt; 与 &lt;code&gt;vApplicationMallocFailedHook()&lt;/code&gt;，在发生问题时记录信息并安全重启或进入安全状态。&lt;/li&gt;
&lt;li&gt;使用断言：启用 &lt;code&gt;configASSERT()&lt;/code&gt;，并在断言回调中输出关键信息（例如当前任务名、寄存器快照）以便排查。&lt;/li&gt;
&lt;li&gt;统计与事件：使用 &lt;code&gt;vTaskList()&lt;/code&gt; / &lt;code&gt;vTaskGetRunTimeStats()&lt;/code&gt;（如果配置启用 run-time stats）来观察任务运行情况与 CPU 占用。&lt;/li&gt;
&lt;li&gt;故障注入：作为练习，有意识地缩小队列长度或把某任务栈设置偏小，观察系统表现并用以上工具定位问题。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;参考快速清单（新增后）&lt;a href=&quot;#参考快速清单新增后&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;可复制的最小工程模板见本节第 9 节。&lt;/li&gt;
&lt;li&gt;常见错误与正确写法见第 11 节，调试方法见第 12 节。&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>category:笔记</category><category>category:FreeRTOS</category><category>tag:FreeRTOS</category><category>tag:STM32</category><category>tag:嵌入式</category></item><item><title>STM32 GPIO 笔记</title><link>https://729dhs.site/post/stm32-gpio-note</link><guid isPermaLink="false">stm32-gpio-note</guid><description>STM32 GPIO 配置、模式、HAL 函数与低功耗实践笔记。</description><pubDate>Wed, 25 Mar 2026 07:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;STM32 GPIO 笔记&lt;a href=&quot;#stm32-gpio-笔记&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2&gt;CubeMX 中的 GPIO 配置选项&lt;a href=&quot;#cubemx-中的-gpio-配置选项&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;在 STM32CubeMX 中配置 GPIO 时，主要选项包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pin Mode (引脚模式)&lt;/strong&gt;: 选择引脚的功能，如 Input (输入), Output (输出), Analog (模拟), Alternate Function (复用功能)。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPIO output level (GPIO 输出电平)&lt;/strong&gt;: 设置初始输出电平，High (高) 或 Low (低)。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPIO mode (GPIO 模式)&lt;/strong&gt;: 选择输出类型，Push-Pull (推挽) 或 Open-Drain (开漏)。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPIO Pull-up/Pull-down (GPIO 上拉/下拉)&lt;/strong&gt;: No pull-up and no pull-down (无上拉下拉), Pull-up (上拉), Pull-down (下拉)。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maximum output speed (最大输出速度)&lt;/strong&gt;: Low (低), Medium (中), High (高), Very High (很高)。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User Label (用户标签)&lt;/strong&gt;: 为引脚添加自定义名称，便于代码中引用。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;GPIO 模式 (Modes)&lt;a href=&quot;#gpio-模式-modes&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;GPIO 有多种模式，以下是中英文对照：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Input Floating (输入浮空)&lt;/strong&gt;: 引脚浮空输入，无内部上拉或下拉。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Input Pull-up (输入上拉)&lt;/strong&gt;: 引脚输入，上拉到 VCC。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Input Pull-down (输入下拉)&lt;/strong&gt;: 引脚输入，下拉到 GND。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Output Push-Pull (输出推挽)&lt;/strong&gt;: 输出模式，能驱动高低电平。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Output Open-Drain (输出开漏)&lt;/strong&gt;: 输出模式，只能拉低电平，需要外部上拉。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alternate Function Push-Pull (复用推挽)&lt;/strong&gt;: 复用功能，如 UART、SPI 等，推挽输出。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alternate Function Open-Drain (复用开漏)&lt;/strong&gt;: 复用功能，开漏输出。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Analog (模拟)&lt;/strong&gt;: 用于 ADC/DAC，无数字功能。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;HAL 库函数用法&lt;a href=&quot;#hal-库函数用法&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;STM32 HAL 库提供了简化的 GPIO 操作函数：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;HAL_GPIO_ReadPin(GPIOx, GPIO_PIN_x)&lt;/strong&gt;: 读取指定 GPIO 引脚的状态，返回 GPIO_PIN_SET 或 GPIO_PIN_RESET。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;示例: &lt;code&gt;if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET)&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;HAL_GPIO_WritePin(GPIOx, GPIO_PIN_x, GPIO_PIN_SET/RESET)&lt;/strong&gt;: 设置 GPIO 引脚的输出电平。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;示例: &lt;code&gt;HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;HAL_GPIO_TogglePin(GPIOx, GPIO_PIN_x)&lt;/strong&gt;: 翻转 GPIO 引脚的输出电平。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;示例: &lt;code&gt;HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_2);&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;对照标准库 (Standard Peripheral Library)&lt;a href=&quot;#对照标准库-standard-peripheral-library&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;HAL 库是对标准库的封装，提供了更易用的接口。以下是对照：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;HAL_GPIO_ReadPin&lt;/strong&gt; 对应标准库的 &lt;strong&gt;GPIO_ReadInputDataBit&lt;/strong&gt; 或 &lt;strong&gt;GPIO_ReadOutputDataBit&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;标准库: &lt;code&gt;uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;HAL_GPIO_WritePin&lt;/strong&gt; 对应标准库的 &lt;strong&gt;GPIO_SetBits&lt;/strong&gt; 和 &lt;strong&gt;GPIO_ResetBits&lt;/strong&gt;。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;标准库: &lt;code&gt;void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;HAL_GPIO_TogglePin&lt;/strong&gt; 在标准库中需要手动实现，或使用位操作。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;标准库无直接对应，通常用: &lt;code&gt;GPIOx-&amp;gt;ODR ^= GPIO_Pin;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;HAL 库更抽象，兼容性更好，而标准库更底层，效率更高但复杂。&lt;/p&gt;
&lt;h2&gt;GPIO 模式详细作用&lt;a href=&quot;#gpio-模式详细作用&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Analog (模拟) 模式&lt;/strong&gt;: 用于连接模拟外设，如 ADC (模数转换器) 或 DAC (数模转换器)。在该模式下，引脚不进行数字输入/输出，而是直接传递模拟信号到内部 ADC/DAC 模块，用于测量电压或输出模拟电压。常用于传感器输入或音频输出。&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Alternate Function (复用功能) 模式&lt;/strong&gt;: 允许 GPIO 引脚被其他外设复用，如 UART、SPI、I2C、PWM 等通信或定时器功能。此时，引脚不再作为通用 GPIO 使用，而是由相应外设控制，用于数据传输、时钟信号等。选择 Push-Pull 或 Open-Drain 取决于外设需求，例如 I2C 常使用 Open-Drain。&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;GPIO 省电&lt;a href=&quot;#gpio-省电&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;如果 IO 不使用,可以配置为模拟模式(analog mode),这样引脚就不会产生电流消耗,从而降低功耗。&lt;/p&gt;
&lt;h2&gt;JTAG/SWD 引脚注意事项&lt;a href=&quot;#jtagswd-引脚注意事项&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;上电/复位早期 SWJ（SWD+JTAG）接口默认启用，相关管脚可能出现短暂跳变；不应在系统初始化前让这些引脚直接驱动敏感负载。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;仅使用 SWD 时：可在初始化早期禁用 JTAG，释放额外管脚（如 JTDI/TDI、JTDO/TDO、JTMS/TMS、NJTRST）。释放后，这些引脚可以像普通 GPIO 一样配置为输入、输出或复用。&lt;/li&gt;
&lt;li&gt;实务建议：在禁用/重映射前，先将这些引脚配置为输入并配合合适的上拉/下拉；完成释放后再统一设置目标模式和初始输出电平，避免上电瞬间的误动作。&lt;/li&gt;
&lt;li&gt;Trace/ITM：若未使用串行调试输出（SWO/JTDO），建议保持禁用或配置为输入，避免外部误触发。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;示例（F1 系）：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HAL：保留 SWD、禁用 JTAG：&lt;code&gt;__HAL_AFIO_REMAP_SWJ_NOJTAG();&lt;/code&gt;；完全禁用 SWJ：&lt;code&gt;__HAL_AFIO_REMAP_SWJ_DISABLE();&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;标准库：保留 SWD、禁用 JTAG：&lt;code&gt;GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);&lt;/code&gt;；完全禁用 SWJ：&lt;code&gt;GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;不同系列芯片的具体禁用/重映射方法可能不同，请参考该系列的参考手册与 HAL/LL 宏说明。&lt;/p&gt;
&lt;h2&gt;各系列差异简表&lt;a href=&quot;#各系列差异简表&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;F1（STM32F1）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;配置位置：AFIO 重映射。&lt;/li&gt;
&lt;li&gt;保留 SWD、禁用 JTAG：&lt;code&gt;__HAL_AFIO_REMAP_SWJ_NOJTAG();&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;标准库：&lt;code&gt;GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;完全禁用 SWJ：&lt;code&gt;__HAL_AFIO_REMAP_SWJ_DISABLE();&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;标准库：&lt;code&gt;GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;释放后：将 &lt;code&gt;PA15/PB3/PB4&lt;/code&gt; 等按需配置为 GPIO 输入/输出/复用。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;F4（STM32F4）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;配置位置：CubeMX 中 &lt;code&gt;System Core -&amp;gt; SYS -&amp;gt; Debug&lt;/code&gt; 选择；代码层无 AFIO 宏。&lt;/li&gt;
&lt;li&gt;推荐：选择 &lt;code&gt;Serial Wire&lt;/code&gt;（保留 SWD，释放 JTAG 仅用的管脚）；&lt;code&gt;No Debug&lt;/code&gt; 会释放包括 &lt;code&gt;PA13/PA14&lt;/code&gt; 在内的所有调试引脚，慎用。&lt;/li&gt;
&lt;li&gt;常见管脚：SWDIO &lt;code&gt;PA13&lt;/code&gt;、SWCLK &lt;code&gt;PA14&lt;/code&gt;；JTAG 仅用：&lt;code&gt;PA15 (JTDI)&lt;/code&gt;、&lt;code&gt;PB3 (JTDO/SWO)&lt;/code&gt;、&lt;code&gt;PB4 (NJTRST)&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;释放后示例（适用于 F4/L4/H7，仅示意）：&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 在早期初始化阶段，将 JTAG 仅用的管脚设为安全模式（输入）或目标模式&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;GPIO_InitTypeDef GPIO_InitStruct = {0};&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;__HAL_RCC_GPIOA_CLK_ENABLE();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;__HAL_RCC_GPIOB_CLK_ENABLE();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;   // 或 GPIO_MODE_OUTPUT_PP 等&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;GPIO_InitStruct.Pull = GPIO_NOPULL;       // 视外部电路选择 PULLUP/PULLDOWN&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;GPIO_InitStruct.Pin = GPIO_PIN_15;        // PA15: JTDI（SWD 模式下可用作普通 GPIO）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;HAL_GPIO_Init(GPIOA, &amp;amp;GPIO_InitStruct);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;GPIO_InitStruct.Pin = GPIO_PIN_3 | GPIO_PIN_4; // PB3: JTDO/SWO, PB4: NJTRST&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;HAL_GPIO_Init(GPIOB, &amp;amp;GPIO_InitStruct);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;L4（STM32L4）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;配置位置与 F4 类似：通过 CubeMX &lt;code&gt;SYS -&amp;gt; Debug&lt;/code&gt; 选择 SWD/JTAG/禁用。&lt;/li&gt;
&lt;li&gt;管脚分配基本与 F4 一致（具体型号可能略有差异），SWD：&lt;code&gt;PA13/PA14&lt;/code&gt;；JTAG 仅用：&lt;code&gt;PA15/PB3/PB4&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;若启用 Trace/ITM，&lt;code&gt;PB3 (SWO)&lt;/code&gt; 会被占用；未使用时建议设为输入或禁用。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;H7（STM32H7）&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;配置位置与 F4/L4 类似：CubeMX &lt;code&gt;SYS -&amp;gt; Debug&lt;/code&gt;；部分双核器件（M7+M4）有独立调试端口，需按器件手册确认。&lt;/li&gt;
&lt;li&gt;管脚：SWD 保留 &lt;code&gt;PA13/PA14&lt;/code&gt;；JTAG 仅用常见 &lt;code&gt;PA15/PB3/PB4&lt;/code&gt;；Trace/SWO 使用 &lt;code&gt;PB3&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;禁用或释放策略与 F4/L4 相同：未用 Trace 时保持 &lt;code&gt;PB3&lt;/code&gt; 禁用或输入，避免误触发。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;备注：以上管脚为常见映射，具体以器件数据手册/CubeMX 引脚视图为准；释放调试引脚会影响在线调试能力，请在量产或对引脚有严格需求时谨慎处理。&lt;/p&gt;</content:encoded><category>category:笔记</category><category>category:STM32</category><category>tag:STM32</category><category>tag:嵌入式</category></item><item><title>STM32 SPI 笔记</title><link>https://729dhs.site/post/stm32-spi-note</link><guid isPermaLink="false">stm32-spi-note</guid><description>STM32 SPI 通信基础与实践笔记。</description><pubDate>Wed, 25 Mar 2026 07:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;STM32 SPI 笔记&lt;a href=&quot;#stm32-spi-笔记&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2&gt;SPI 简介&lt;a href=&quot;#spi-简介&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;SPI（Serial Peripheral Interface）是一种&lt;strong&gt;同步串行通信接口&lt;/strong&gt;，由摩托罗拉公司提出。&lt;/p&gt;
&lt;h3&gt;特点&lt;a href=&quot;#特点&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;全双工通信&lt;/li&gt;
&lt;li&gt;主从模式（Master/Slave）&lt;/li&gt;
&lt;li&gt;同步时钟（SCK）&lt;/li&gt;
&lt;li&gt;高速传输（可达数十 Mbps）&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;信号线&lt;a href=&quot;#信号线&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;信号&lt;/th&gt;&lt;th&gt;全称&lt;/th&gt;&lt;th&gt;说明&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;SCK&lt;/td&gt;&lt;td&gt;Serial Clock&lt;/td&gt;&lt;td&gt;时钟信号，由主机产生&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;MOSI&lt;/td&gt;&lt;td&gt;Master Out Slave In&lt;/td&gt;&lt;td&gt;主机输出/从机输入&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;MISO&lt;/td&gt;&lt;td&gt;Master In Slave Out&lt;/td&gt;&lt;td&gt;主机输入/从机输出&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;NSS/CS&lt;/td&gt;&lt;td&gt;Chip Select&lt;/td&gt;&lt;td&gt;片选信号，低电平有效&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;2. STM32 SPI 工作模式&lt;a href=&quot;#2-stm32-spi-工作模式&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;SPI 工作模式&lt;a href=&quot;#spi-工作模式&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;模式&lt;/th&gt;&lt;th&gt;CPOL&lt;/th&gt;&lt;th&gt;CPHA&lt;/th&gt;&lt;th&gt;采样边沿&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;第一个上升沿&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;第一个下降沿&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;第二个上升沿&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;1&lt;/td&gt;&lt;td&gt;第二个下降沿&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;CPOL&lt;/strong&gt;：时钟极性（空闲时电平）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CPHA&lt;/strong&gt;：时钟相位（采样时刻）&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;HAL 库配置示例&lt;a href=&quot;#hal-库配置示例&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;初始化代码&lt;a href=&quot;#初始化代码&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// SPI 句柄定义&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;SPI_HandleTypeDef hspi1;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// SPI 初始化配置&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; MX_SPI1_Init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    hspi1.Instance &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; SPI1;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    hspi1.Init.Mode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; SPI_MODE_MASTER;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    hspi1.Init.Direction &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; SPI_DIRECTION_2LINES;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    hspi1.Init.DataSize &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; SPI_DATASIZE_8BIT;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    hspi1.Init.CLKPolarity &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; SPI_POLARITY_LOW;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    hspi1.Init.CLKPhase &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; SPI_PHASE_1EDGE;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    hspi1.Init.NSS &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; SPI_NSS_SOFT;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    hspi1.Init.BaudRatePrescaler &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; SPI_BAUDRATEPRESCALER_16;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    hspi1.Init.FirstBit &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; SPI_FIRSTBIT_MSB;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    hspi1.Init.TIMode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; SPI_TIMODE_DISABLE;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    hspi1.Init.CRCCalculation &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; SPI_CRCCALCULATION_DISABLE;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    hspi1.Init.CRCPolynomial &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 10&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;HAL_SPI_Init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;hspi1) &lt;/span&gt;&lt;span&gt;!=&lt;/span&gt;&lt;span&gt; HAL_OK)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        // 初始化错误处理&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        Error_Handler&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;数据收发函数&lt;a href=&quot;#数据收发函数&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 单字节发送&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;HAL_SPI_Transmit&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;hspi1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;txData&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, HAL_MAX_DELAY);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 单字节接收&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;HAL_SPI_Receive&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;hspi1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;rxData&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, HAL_MAX_DELAY);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 全双工收发&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;HAL_SPI_TransmitReceive&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;hspi1&lt;/span&gt;&lt;span&gt;, txBuffer, rxBuffer, size, HAL_MAX_DELAY);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 中断方式发送&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;HAL_SPI_Transmit_IT&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;hspi1&lt;/span&gt;&lt;span&gt;, txBuffer, size);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// DMA 方式发送&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;HAL_SPI_Transmit_DMA&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;hspi1&lt;/span&gt;&lt;span&gt;, txBuffer, size);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;常见问题&lt;a href=&quot;#常见问题&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;






























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;问题&lt;/th&gt;&lt;th&gt;可能原因&lt;/th&gt;&lt;th&gt;解决方案&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;通信无数据&lt;/td&gt;&lt;td&gt;片选未拉低&lt;/td&gt;&lt;td&gt;检查 &lt;code&gt;NSS&lt;/code&gt; 引脚配置&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;数据错位&lt;/td&gt;&lt;td&gt;时钟模式不匹配&lt;/td&gt;&lt;td&gt;确认主从 &lt;code&gt;CPOL/CPHA&lt;/code&gt; 一致&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;速率过低&lt;/td&gt;&lt;td&gt;分频系数过大&lt;/td&gt;&lt;td&gt;调整 &lt;code&gt;BaudRatePrescaler&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;接收数据固定&lt;/td&gt;&lt;td&gt;未先发送时钟&lt;/td&gt;&lt;td&gt;SPI 需先发数据产生时钟&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;// TODO :&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt; 补充示波器波形图&lt;/li&gt;
&lt;li&gt; 添加实际项目应用场景&lt;/li&gt;
&lt;li&gt; 记录调试过程中遇到的问题及解决方案&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>category:笔记</category><category>category:STM32</category><category>tag:STM32</category><category>tag:SPI</category><category>tag:嵌入式</category></item><item><title>RUST in an hour</title><link>https://729dhs.site/post/rust-in-an-hour</link><guid isPermaLink="false">rust-in-an-hour</guid><description>RUST in an hour 阅读</description><pubDate>Wed, 25 Mar 2026 06:47:59 GMT</pubDate><content:encoded>&lt;h1&gt;RUST in an hour&lt;a href=&quot;#rust-in-an-hour&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2&gt;Delete element&lt;a href=&quot;#delete-element&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The underscore is a special name - or rather, a “lack of name”. It basically means to throw away something:_&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// this does *nothing* because 42 is a constant&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;let _ = 42;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// this calls `get_thing` but throws away its result&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;let _ = get_thing();&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Tuples&lt;a href=&quot;#tuples&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;the format of tuples is “(a,b,c…)” , the most usage are similar to tuples in Python:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;let pair = (&apos;a&apos;, 17);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;pair.0; // this is &apos;a&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;pair.1; // this is 17&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;//you can define their type&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;let pairs:(i32, i32,char) = (1,2,&apos;a&apos;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;the content of tuples are static&lt;/p&gt;
&lt;h3&gt;Distructuring tuples&lt;a href=&quot;#distructuring-tuples&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; (x, y, z) &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Statements&lt;a href=&quot;#statements&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;let&lt;/span&gt;&lt;span&gt; x &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; vec!&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;3&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;4&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;6&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;7&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;8&lt;/span&gt;&lt;span&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    .&lt;/span&gt;&lt;span&gt;iter&lt;/span&gt;&lt;span&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    .&lt;/span&gt;&lt;span&gt;map&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; x &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 3&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    .&lt;/span&gt;&lt;span&gt;fold&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt;x, y&lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; x &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; y);&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Declare function&lt;a href=&quot;#declare-function&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;</content:encoded><category>category:笔记</category><category>category:RUST</category><category>tag:RUST</category></item><item><title>R语言常用函数</title><link>https://729dhs.site/post/R_functions</link><guid isPermaLink="false">R_functions</guid><description>R语言常用函数</description><pubDate>Wed, 25 Mar 2026 06:17:26 GMT</pubDate><content:encoded>&lt;h1&gt;Functionsk&lt;a href=&quot;#functionsk&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2&gt;runif&lt;a href=&quot;#runif&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;runif(n,min,max)
n is the number.&lt;/p&gt;
&lt;h2&gt;sample&lt;a href=&quot;#sample&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;sample(x,n,replace)
x is the range
n is the number
when n is bigger than the length of x, you should set replace = T.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;x &amp;lt;- sample(2:10,100,replace = T)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;# the length is bigger,use repalce = T&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;rnorm&lt;a href=&quot;#rnorm&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;dnorm(x, mean = 0, sd = 1, log = FALSE)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;pnorm(q, mean = 0, sd = 1, lower.tail = TRUE, log.p = FALSE)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;qnorm(p, mean = 0, sd = 1, lower.tail = TRUE, log.p = FALSE)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;rnorm(n, mean = 0, sd = 1)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;rnorm: normal distribution
n: number
mean: the center of the distribution
sd: the range near the center&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;for example: rnorm(10,100,20) it means we select ten numbers between 80 and 120, the min is 100-20, max is 100+20.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;set seed()&lt;a href=&quot;#set-seed&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;设定随机数种子，便于复现&lt;/p&gt;
&lt;h2&gt;hist() 频率直方图&lt;a href=&quot;#hist-频率直方图&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;hist receive a vector
it will draw a histogram to show the frequency of the data&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;hist&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;freq&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; probability&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; !&lt;/span&gt;&lt;span&gt;freq&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    right&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; TRUE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;density&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; angle&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; 45&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; col&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;lightgray&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    main&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;Histogram of&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    xlim&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; range&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;breaks&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; ylim&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    xlab&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; xname&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;axes&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; TRUE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; plot&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; TRUE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; labels&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; FALSE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;freq: if T, display every values frequency, default is T,show the frequency instead of the density.&lt;/li&gt;
&lt;li&gt;probability: an alias for !freq, for S compatibility.&lt;/li&gt;
&lt;li&gt;right: if the data equal to the right side of range, it will beongs to this rnage.&lt;/li&gt;
&lt;li&gt;density: draw shading lines&lt;/li&gt;
&lt;li&gt;angle: the angle of the density&lt;/li&gt;
&lt;li&gt;col: the color of the histogram&lt;/li&gt;
&lt;li&gt;main: the title of the histogram&lt;/li&gt;
&lt;li&gt;xlim: the range of the x axis, when value = range(breaks),it will draw all the range of data, but if not, it will default to chose the range.&lt;/li&gt;
&lt;li&gt;ylim: the range of the y axis&lt;/li&gt;
&lt;li&gt;xlab: the label of the x axis&lt;/li&gt;
&lt;li&gt;ylab: the label of the y axis&lt;/li&gt;
&lt;li&gt;axes: if T, draw the x and y axis,default is T&lt;/li&gt;
&lt;li&gt;labels: default is F, show the value of the data on the histogram&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;plot 散点图&lt;a href=&quot;#plot-散点图&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;plot function need two parameters as x,y , this function defualt draw points on the graph&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;plot&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;x&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; y&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; type&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;p&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; xlim&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; ylim&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; log&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    main&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; sub&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; xlab&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; ylab&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ann&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; par&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;ann&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; axes&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; TRUE&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; frame.plot&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; axes&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; panel.first&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    panel.last&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; NULL&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; bty&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; &quot;o&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; ...&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;type:
“p” for points,
“l” for lines,
“b” for both(lines and points),
“c” for the lines part alone of “b”,
“o” for both ‘overplotted’,
“h” for ‘histogram’ like (or ‘high-density’) vertical lines,
“s” for stair steps,
“S” for other steps, see ‘Details’ below,&lt;/li&gt;
&lt;li&gt;cex: size of the points&lt;/li&gt;
&lt;li&gt;col: color&lt;/li&gt;
&lt;li&gt;pch: the shape of the points,19 is full&lt;/li&gt;
&lt;li&gt;xlim/ylim: xlim = c(min_x, max_x), decide the range of x/y&lt;/li&gt;
&lt;li&gt;log: log”x”/“xy”: use log on x,y&lt;/li&gt;
&lt;li&gt;main: tittle&lt;/li&gt;
&lt;li&gt;sub: subtitle, down the pic&lt;/li&gt;
&lt;li&gt;bty: the type of the frame, “o” is the default line, “l” is no frame, “c” means double line&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;text&lt;a href=&quot;#text&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;用于给点或者决策树等添加文字&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;text(x, y, label, pos = 3, offset = 0.5， cex = 1.5, srt = 45)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;label: the label vector&lt;/li&gt;
&lt;li&gt;cex: size of the label, default is 1&lt;/li&gt;
&lt;li&gt;pos: the position of the label&lt;/li&gt;
&lt;li&gt;offset: the distance between the label and the point&lt;/li&gt;
&lt;li&gt;srt: the angle of the label&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;qq 图（Quantile-Quantile Plot）&lt;a href=&quot;#qq-图quantile-quantile-plot&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;geom_qq
qqplot
qqnrom
这三个方式做出来类似&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;qqnorm(All$mark)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;qqline(All$mark, col = 2)  # 添加一条理论正态分布的参考线，颜色设为红色&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;abline&lt;a href=&quot;#abline&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;abline(a = NULL, b = NULL, h = NULL, v = NULL, reg = NULL, coef = NULL,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    untf = FALSE, lty = 1, lwd = 1, col = &quot;black&quot;, ...)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;a,b: a*x+b&lt;/li&gt;
&lt;li&gt;h,v: horizontal and vertical lines&lt;/li&gt;
&lt;li&gt;reg: regression line&lt;/li&gt;
&lt;li&gt;lty: line type&lt;/li&gt;
&lt;li&gt;lwd: line width&lt;/li&gt;
&lt;li&gt;col: colour&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;拟合示例：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;   data &amp;lt;- data.frame(x = 1:10, y = 2 * (1:10) + rnorm(10))&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;   plot(data$x, data$y)  # 绘制数据点&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;   model &amp;lt;- lm(y ~ x, data)  # 对数据进行线性拟合&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;   abline(model, col = &quot;blue&quot;)  # 添加拟合线&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;as.factor&lt;a href=&quot;#asfactor&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;usage: xxx &amp;lt;- as.factor(xxx)
use: change vector to factor
&lt;strong&gt;what is factor?&lt;/strong&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;# 创建一个简单的因子&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;fruit&lt;/span&gt;&lt;span&gt; &amp;lt;-&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;apple&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;banana&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;apple&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;orange&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;banana&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;apple&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;fruit_factor&lt;/span&gt;&lt;span&gt; &amp;lt;-&lt;/span&gt;&lt;span&gt; factor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;fruit&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;# 显示因子结构&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;fruit_factor&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;# 指定水平和标签&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;fruit_factor_labeled&lt;/span&gt;&lt;span&gt; &amp;lt;-&lt;/span&gt;&lt;span&gt; factor&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;fruit&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; levels&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;apple&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;banana&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;orange&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                               labels&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;Apple&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;Banana&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;Orange&quot;&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;fruit_factor_labeled&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;summary&lt;a href=&quot;#summary&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;得到拟合模型的参数&lt;/p&gt;
&lt;h2&gt;colMeans&lt;a href=&quot;#colmeans&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;average_marks &amp;lt;- colMeans(df2, na.rm = TRUE)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;colSums&lt;a href=&quot;#colsums&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;sum_marks &amp;lt;- colSums(df2, na.rm = TRUE)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;apply()&lt;a href=&quot;#apply&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;median_marks &amp;lt;- apply(df2, 2, median, na.rm = TRUE)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#计算中位数&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;row_sums &amp;lt;- apply(mat, 1, sum)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#计算矩阵每一行的和&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;max_marks &amp;lt;- apply(df2, 2, max, na.rm = TRUE)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;min_marks &amp;lt;- apply(df2, 2, min, na.rm = TRUE)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#计算最大最小&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;tapply&lt;a href=&quot;#tapply&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt; &amp;lt;-&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; 4&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; 7&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; 6&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; 8&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; 3&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; 4&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt; &amp;lt;-&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;A&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;A&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;B&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;B&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;A&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;A&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;B&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;B&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt; &amp;lt;-&lt;/span&gt;&lt;span&gt; tapply&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; mean&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt; &amp;lt;-&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;X&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;Y&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;X&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;Y&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;X&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;Y&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;X&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; &quot;Y&quot;&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;result&lt;/span&gt;&lt;span&gt; &amp;lt;-&lt;/span&gt;&lt;span&gt; tapply&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; list&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; d&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; mean&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;tapply&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;vector&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; index&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; FUN&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; ...&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; default&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; NA&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; simplify&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; TRUE&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;in the first example, variable in c vector defines which group the variable in a vector belongs to.
it will calculate the mean of each group such as A,B&lt;/p&gt;
&lt;h2&gt;rep&lt;a href=&quot;#rep&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;rep(x, times = NULL, each = NULL, length.out = NULL, along = NULL)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;rep(1, times = 5) &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;# 重复数字1，共5次&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;lm&lt;a href=&quot;#lm&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;线性模型（lm()）、广义线性模型（glm()）、混合效应模型（lme()）
线性拟合
lm(y~x)&lt;/p&gt;
&lt;h2&gt;lme&lt;a href=&quot;#lme&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;glm&lt;a href=&quot;#glm&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;服从指数组分布&lt;/p&gt;
&lt;h2&gt;gam&lt;a href=&quot;#gam&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;cooks.distance&lt;a href=&quot;#cooksdistance&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;boxplot  箱线图&lt;a href=&quot;#boxplot--箱线图&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;x 和 y&lt;/strong&gt;：这是箱线图的基本数据，可以是向量、矩阵、数据框或列表。如果 x 是一个向量，那么 y 可以省略，此时 x 表示类别，y 表示对应的数值。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;names.arg&lt;/strong&gt;：如果 x 是一个向量，可以使用 names.arg 来提供类别名称。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;main&lt;/strong&gt;：设置图形的主标题。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;xlab 和 ylab&lt;/strong&gt;：分别设置 X 轴和 Y 轴的标签。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;las&lt;/strong&gt;：控制轴标签的方向，0 表示水平，1 表示垂直，2 表示旋转 45 度。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;col 和 fill&lt;/strong&gt;：设置箱线的颜色和填充色。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;border&lt;/strong&gt;：设置箱线边框的颜色。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;outlier.col&lt;/strong&gt; 和 &lt;strong&gt;outlier.pch&lt;/strong&gt;：设置异常值的点颜色和形状。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;horizontal&lt;/strong&gt;：如果设为 TRUE，则绘制水平箱线图。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;varwidth&lt;/strong&gt;：如果设为 TRUE，箱线的宽度将根据数据的样本量变化，否则所有箱线宽度相同。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;notch&lt;/strong&gt;：如果设为 TRUE，箱线会有一个切口，表示 95%的置信区间，可用于比较中位数的显著性。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;range&lt;/strong&gt;：控制须的长度，通常默认为 1.5 倍的四分位距（IQR）。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;par&lt;/strong&gt;：可以传递图形参数，如 mar（边距）、 oma（外边距）等。
怎么看箱线图，箱线图主要用于描述数据的分布情况，其关键元素包括：&lt;/li&gt;
&lt;li&gt;箱子（Box）：表示数据的下四分位数（Q1）和上四分位数（Q3），也就是数据的中间 50%。&lt;/li&gt;
&lt;li&gt;中位数线（Median Line）：位于箱子内部的线，表示数据的中位数。&lt;/li&gt;
&lt;li&gt;须（Whiskers）：从箱子两端延伸出去的线，通常表示数据的最小值（不包括异常值）和最大值，但不超过 Q1 减去 1.5 倍 IQR 和 Q3 加上 1.5 倍 IQR。&lt;/li&gt;
&lt;li&gt;异常值（Outliers）：落在须之外的数据点，表示远离主要数据集的值。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;bwplot&lt;a href=&quot;#bwplot&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;AIC&lt;a href=&quot;#aic&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;fligner.test&lt;a href=&quot;#flignertest&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;检验方差齐性，得到 p-value，如果小于 0.05，拒绝原假设&lt;/p&gt;
&lt;h2&gt;shapiro.test&lt;a href=&quot;#shapirotest&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;检验数据是否遵循正态分布，得到值大于 0.05，则认为遵循正态分布&lt;/p&gt;
&lt;h2&gt;cor.test&lt;a href=&quot;#cortest&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;durbinWatsonTest&lt;a href=&quot;#durbinwatsontest&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Durbin-Watson 统计量是一个在 0 到 4 之间的数，用于评估模型的残差序列是否具有自相关性。数值接近 2 通常表示残差之间没有明显的自相关，而远离 2 则可能表明存在自相关&lt;/p&gt;
&lt;h2&gt;dwtest()&lt;a href=&quot;#dwtest&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;dwtest(object, alternative = c(&quot;two.sided&quot;, &quot;less&quot;, &quot;greater&quot;), lag.max = NULL)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;输出将包括 Durbin-Watson 统计量、对应的 p 值和检验结论。如果 p 值大于显著性水平（通常为 0.05），则不能拒绝原假设，即残差没有自相关性。反之，如果 p 值小于显著性水平，则可能需要对模型进行调整，以消除残差的自相关性。&lt;/p&gt;
&lt;h2&gt;kruskal.test&lt;a href=&quot;#kruskaltest&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;aov&lt;a href=&quot;#aov&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;anova&lt;a href=&quot;#anova&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;par(mfrow=c(x,y),cor = (1,1,2,2))&lt;a href=&quot;#parmfrowcxycor--1122&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;mfrow 定义图的阵列
cor 定义上下左右边框&lt;/p&gt;
&lt;h2&gt;dotchart()&lt;a href=&quot;#dotchart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;pairs()&lt;a href=&quot;#pairs&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;panel.cor()&lt;a href=&quot;#panelcor&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h2&gt;tree()&lt;a href=&quot;#tree&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;library&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;tree&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;my_tree&lt;/span&gt;&lt;span&gt; &amp;lt;-&lt;/span&gt;&lt;span&gt; tree&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;response&lt;/span&gt;&lt;span&gt; ~&lt;/span&gt;&lt;span&gt; .&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; data&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; dataset&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt; control&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; tree.control&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;nnode&lt;/span&gt;&lt;span&gt; =&lt;/span&gt;&lt;span&gt; n&lt;/span&gt;&lt;span&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;plot&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;my_tree&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;text&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;my_tree&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;response: 分类或回归问题的响应变量，对于分类问题，它应该是一个因子；对于回归问题，它应该是一个数值向量。&lt;/li&gt;
&lt;li&gt;.: 代表所有其他变量，即用所有的自变量来预测响应变量。&lt;/li&gt;
&lt;li&gt;data: 包含响应变量和自变量的数据框。&lt;/li&gt;
&lt;li&gt;control: 一个 tree.control 对象，用于设置构建决策树时的参数，如最大树深度 nnode 等。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;参数检验&lt;a href=&quot;#参数检验&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;T 检验：&lt;/p&gt;
&lt;p&gt;单样本 T 检验：检验一个样本的均值是否与已知总体均值有显著差异。
独立样本 T 检验（两样本 T 检验）：比较两个独立样本的均值差异是否显著。
配对样本 T 检验：比较配对数据（如同一对象处理前后的测量）的均值差异是否显著。
ANOVA（方差分析）：&lt;/p&gt;
&lt;p&gt;一元方差分析：用于比较三个或以上独立样本的均值是否存在显著差异。
多元方差分析（MANOVA）：当因变量不止一个时，用于同时分析多个因变量的均值差异。
卡方检验（χ²检验）：&lt;/p&gt;
&lt;p&gt;拟合优度检验：检验观察频数与期望频数之间是否存在显著差异。
独立性检验：分析两个分类变量是否独立。
同质性检验：检验多个样本的频率分布是否相同。
F 检验：&lt;/p&gt;
&lt;p&gt;方差齐性检验：在进行 ANOVA 之前，检验各组方差是否相等。
方差分析中的 F 检验：ANOVA 中用于确定组间差异是否显著。&lt;/p&gt;
&lt;h2&gt;interaction.plot&lt;a href=&quot;#interactionplot&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;interaction.plot(x.factor = mydata$Age.Group, &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                 trace.factor = mydata$Gender, &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                 response = mydata$Salary, &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                 type = &quot;b&quot;, &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                 col = c(&quot;red&quot;, &quot;blue&quot;), &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                 leg.legend = c(&quot;Female&quot;, &quot;Male&quot;))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;x.factor：X 轴的因子变量，可以是一个因子变量或一个数值向量。&lt;/li&gt;
&lt;li&gt;trace.factor：Y 轴的因子变量，可以是一个因子变量或一个数值向量。&lt;/li&gt;
&lt;li&gt;response：响应变量，可以是一个数值向量。&lt;/li&gt;
&lt;li&gt;data: 数据框&lt;/li&gt;
&lt;li&gt;type: 类型&lt;/li&gt;
&lt;/ul&gt;
&lt;ol&gt;
&lt;li&gt;“l” 线型图&lt;/li&gt;
&lt;li&gt;“b” 线型图和点型图&lt;/li&gt;
&lt;li&gt;“p” 点型图&lt;/li&gt;
&lt;li&gt;“o” 超越线图的点图。&lt;/li&gt;
&lt;li&gt;“c” 直方图风格的线图&lt;/li&gt;
&lt;li&gt;legend: 图例&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;groupedData()&lt;a href=&quot;#groupeddata&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;处理重复测量数据&lt;/p&gt;
&lt;h2&gt;radarplot() 雷达图&lt;a href=&quot;#radarplot-雷达图&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;radarchart/radarchartcirc(df, axistype, seg, pty, pcol, plty, plwd, pdensity, pangle, pfcol,cglty, cglwd, cglcol, axislabcol, title, maxmin, na.itp, centerzero, vlabels, vlcex, caxislabels, calcex, paxislabels, palcex, ...)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;axislabcol: 轴标签的颜色。轴标签和数字的颜色，默认是”blue&lt;/li&gt;
&lt;li&gt;axistype&lt;div&gt;&lt;/div&gt;，可以是 0 到 5 之间的数值。0 表示无轴标签，1 表示中心轴标签，2 表示围绕图表的轴标签，3 表示同时有中心和周边轴标签，4 是 1 的星号格式，5 是 3 的星号格式。默认是 0&lt;/li&gt;
&lt;li&gt;seg: 分段数，决定轴上的分割数量。&lt;/li&gt;
&lt;li&gt;pty: 多边形的类型（线型）,指定点符号的向量，默认是 16（闭合的圆圈）。如果不绘制数据点，应设置为 32。&lt;/li&gt;
&lt;li&gt;pcol: 多边形边缘的颜色,绘制数据的颜色代码向量，默认是 1&lt;div&gt;&lt;/div&gt;，会重复使用&lt;/li&gt;
&lt;li&gt;plty: 多边形边缘的线型。绘制数据的线型向量，默认是 1&lt;div&gt;&lt;/div&gt;，会重复使用&lt;/li&gt;
&lt;li&gt;plwd: 多边形边缘的线宽。&lt;/li&gt;
&lt;li&gt;pdensity: 可能用于控制点的密度，如果 pcol 用于点而不是线条。&lt;/li&gt;
&lt;li&gt;pangle: 可能用于控制点的角度分布，如果 pcol 用于点。&lt;/li&gt;
&lt;li&gt;pfcol: 多边形内部的填充颜色。pfcol = scales::alpha(“#00AFBB”, 0.5)；alpha() 函数的第二个参数是一个介于 0 和 1 之间的数值，表示颜色的透明度。0 表示完全透明，1 表示完全不透明。在这个例子中，0.5 表示半透明，所以最终的 pfcol 颜色是 50%透明的蓝色&lt;/li&gt;
&lt;li&gt;cglty: 网格线的线型。雷达网格的线型，默认是 3（虚线）。对于 radarchartcirc()，默认是 1（实线）&lt;/li&gt;
&lt;li&gt;cglwd: 网格线的线宽。雷达网格的线宽，默认是 1，表示最细的线宽&lt;/li&gt;
&lt;li&gt;cglcol: 网格线的颜色。雷达网格的颜色，默认是”navy”&lt;/li&gt;
&lt;li&gt;title: 图表的标题。maxmin: 可能用于控制最大最小值的显示。&lt;/li&gt;
&lt;li&gt;na.itp: 如何处理 NA 值。&lt;/li&gt;
&lt;li&gt;centerzero: 是否将图表中心设为 0。&lt;/li&gt;
&lt;li&gt;vlabels: 变量的标签，通常对应数据框的列名。&lt;/li&gt;
&lt;li&gt;vlcex: 变量标签的字体大小。&lt;/li&gt;
&lt;li&gt;caxislabels: 轴刻度标签。&lt;/li&gt;
&lt;li&gt;calcex: 刻度标签的字体大小。&lt;/li&gt;
&lt;li&gt;paxislabels: 多边形轴的标签。&lt;/li&gt;
&lt;li&gt;palcex: 多边形轴标签的字体大小。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;legend 图例&lt;a href=&quot;#legend-图例&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;legend(x, y, legend, fill = NULL, col = &quot;black&quot;, bg = &quot;white&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;       lty = 1, lwd = 1, pch = 1, angle = 45, density = NULL, bty = &quot;o&quot;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;       box.lwd = 1, box.col = &quot;black&quot;, text.col = &quot;black&quot;, &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;       title = NULL, cex = 1, pt.bg = NA, pt.cex = 1, &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;       xjust = 0, yjust = 1, xpd = NA, &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;       ncol = 1, horiz = FALSE, title.adj = c(0.5, 0.5), ...)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content:encoded><category>category:笔记</category><category>category:R</category><category>tag:R</category></item><item><title>STM32 定时器笔记</title><link>https://729dhs.site/post/stm32-timer-note</link><guid isPermaLink="false">stm32-timer-note</guid><description>STM32 定时器基础、CubeMX 配置与常见模式实践记录。</description><pubDate>Tue, 30 Dec 2025 16:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;定时器&lt;a href=&quot;#定时器&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;hr /&gt;
&lt;h2&gt;定时器基础知识&lt;a href=&quot;#定时器基础知识&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;基础构成&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;时钟来源: 内部 APB 时钟/ETR 外部时钟/内部触发 ITR；定时器时钟频率 = 定时器输入时钟 ÷ (PSC+1)。&lt;/li&gt;
&lt;li&gt;计数器 CNT: 16/32 位向上、向下或中心对齐计数模式；溢出或到达 ARR 触发更新事件。&lt;/li&gt;
&lt;li&gt;预分频 PSC: 将输入时钟再分频，减少计数速度；更新事件才会装载新 PSC。&lt;/li&gt;
&lt;li&gt;自动重装载 ARR: 计数上限或下限，决定周期；开启预装载时（ARPE）在更新事件同步装载。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;关键模式&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;单脉冲模式(One Pulse): 响应一次触发产生有限脉冲，常用于测距等。&lt;/li&gt;
&lt;li&gt;输出比较/定时输出: CCRx 与 CNT 比较，匹配时产生事件，可配置翻转/置位/清零。&lt;/li&gt;
&lt;li&gt;PWM: 由 ARR 设周期，CCR 设占空比；上升沿/下降沿对齐或中心对齐可减小谐波。&lt;/li&gt;
&lt;li&gt;输入捕获: 捕获外部边沿时间戳到 CCR，结合 PSC/ARR 可测频率或脉宽。&lt;/li&gt;
&lt;li&gt;编码器模式: 两路正交输入解码位移/速度；选择 TI1/TI2 极性、滤波。&lt;/li&gt;
&lt;li&gt;基础定时: 部分定时器（如 TIM6/7）仅生成更新事件驱动 DAC 或触发。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;事件与中断/DMA&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;更新事件 UEV: CNT 到 ARR 或方向翻转时触发；可触发中断或 DMA，常用来做“心跳”。&lt;/li&gt;
&lt;li&gt;触发输出 TRGO: 可配置为 UEV/OCxREF/OCxREF 清零，用于驱动 ADC、DAC、另一个定时器。&lt;/li&gt;
&lt;li&gt;中断: 更新 UIE、捕获比较 CCxIE、触发 TIE、突破 BDTR 故障；注意在 NVIC 和寄存器同时开启。&lt;/li&gt;
&lt;li&gt;DMA: 可把更新或捕获比较事件搬运 ARR/CCR 数据，适合连续波形更新。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;输出相关细节&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CCR 预装载: PWM 时建议开 OCxPE，避免更新窗口撕裂；在更新事件同步写入。&lt;/li&gt;
&lt;li&gt;极性: 可配置 CHx 极性高/低，PWM 互补输出(CHxN)需高级定时器并设置死区时间 BDTR.DTG。&lt;/li&gt;
&lt;li&gt;刹车/死区: 高级定时器支持刹车输入 BKIN、死区插入、输出使能 MOE，保障功率驱动安全。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;输入滤波与时序&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数字滤波: ICF 位可设采样次数与分频，滤除毛刺；过强滤波会增加响应延迟。&lt;/li&gt;
&lt;li&gt;边沿选择: CCxP/CCxNP 选择上升/下降/双边沿；双边沿测频时需注意计数翻倍。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;常用公式&lt;/p&gt;
&lt;span&gt;&lt;span&gt;&lt;span&gt;fcnt=ftimPSC+1f_{cnt} = \frac{f_{tim}}{PSC+1}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;PSC&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;im&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;span&gt;fupdate=fcntARR+1f_{update} = \frac{f_{cnt}}{ARR+1}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;u&lt;/span&gt;&lt;span&gt;p&lt;/span&gt;&lt;span&gt;d&lt;/span&gt;&lt;span&gt;a&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;RR&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;c&lt;/span&gt;&lt;span&gt;n&lt;/span&gt;&lt;span&gt;t&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;span&gt;fpwm=ftim(PSC+1)(ARR+1)f_{pwm} = \frac{f_{tim}}{(PSC+1)(ARR+1)}&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;pw&lt;/span&gt;&lt;span&gt;m&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;PSC&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;A&lt;/span&gt;&lt;span&gt;RR&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;t&lt;/span&gt;&lt;span&gt;im&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;​&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;p&gt;实用小贴士&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;修改 PSC/ARR/CCR 后若开预装载，需等待一次更新事件才生效，可手动 UG 产生。&lt;/li&gt;
&lt;li&gt;中心对齐模式下计数往返一次算一个周期，实际频率为对齐模式的 2 倍计数范围。&lt;/li&gt;
&lt;li&gt;多定时器级联时，用 TRGO/ITR 做主从同步，避免相位漂移。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;CubeMX 配置&lt;a href=&quot;#cubemx-配置&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;CubeMX 配置 STM32F103C8 定时器界面:&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/STM32/N5_TIM_1.webp&quot; alt=&quot;TIM_1&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;选项卡:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Slave mode:
&lt;ul&gt;
&lt;li&gt;Disable&lt;/li&gt;
&lt;li&gt;External Clock Mode 1&lt;/li&gt;
&lt;li&gt;Reset Mode&lt;/li&gt;
&lt;li&gt;Gate Mode&lt;/li&gt;
&lt;li&gt;Trigger Mode&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Tigger Source:
&lt;ul&gt;
&lt;li&gt;Disable&lt;/li&gt;
&lt;li&gt;ITR0&lt;/li&gt;
&lt;li&gt;ITR1&lt;/li&gt;
&lt;li&gt;ITR2&lt;/li&gt;
&lt;li&gt;ITR3&lt;/li&gt;
&lt;li&gt;ETR1&lt;/li&gt;
&lt;li&gt;Tl1_ED&lt;/li&gt;
&lt;li&gt;Tl1FP1&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Clock Source:
&lt;ul&gt;
&lt;li&gt;Disable&lt;/li&gt;
&lt;li&gt;Internal Clock&lt;/li&gt;
&lt;li&gt;ETR2&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Channel1/2/3/4:
&lt;ul&gt;
&lt;li&gt;Disable&lt;/li&gt;
&lt;li&gt;Input Capture direct mode&lt;/li&gt;
&lt;li&gt;Input Capture indirect mode&lt;/li&gt;
&lt;li&gt;Input Capture tiggered by TRC&lt;/li&gt;
&lt;li&gt;Output Compare No Output&lt;/li&gt;
&lt;li&gt;Output Compare CH1/2/3/4&lt;/li&gt;
&lt;li&gt;PWM Generation No Output&lt;/li&gt;
&lt;li&gt;PWM Generation CH1/2/3/4&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Combine Channels:
&lt;ul&gt;
&lt;li&gt;Disable&lt;/li&gt;
&lt;li&gt;Encoder Mode&lt;/li&gt;
&lt;li&gt;PWM Input on CH1&lt;/li&gt;
&lt;li&gt;PWM Input on CH2&lt;/li&gt;
&lt;li&gt;XOR ON/HALL Sensor Mode&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt; Use ETR as Clearing Source&lt;/li&gt;
&lt;li&gt; XOR activation&lt;/li&gt;
&lt;li&gt; One Pulse Mode&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;CubeMX 配置选项解读&lt;a href=&quot;#cubemx-配置选项解读&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;Slave Mode (从模式选择)&lt;a href=&quot;#slave-mode-从模式选择&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;用于设定当前定时器如何响应来自其他定时器或外部引脚的触发信号。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Disable&lt;/code&gt;: &lt;strong&gt;禁用从模式&lt;/strong&gt;。定时器独立运行，仅受自身控制寄存器支配。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;External Clock Mode 1&lt;/code&gt;: &lt;strong&gt;外部时钟模式 1&lt;/strong&gt;。计数器 CNT 不再由内部时钟驱动，而是由选定的触发源（如 TIx 或 ETR）的边沿驱动。常用于“外部脉冲计数”。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Reset Mode&lt;/code&gt;: &lt;strong&gt;复位模式&lt;/strong&gt;。当选定的触发信号出现上升沿时，CNT 计数器立即清零并重新开始计数。常用于“清除计数器”或“同步相位”。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Gate Mode&lt;/code&gt;: &lt;strong&gt;门控模式&lt;/strong&gt;。触发信号为高电平时，CNT 正常计数；信号为低电平时，CNT 停止计数。常用于“测量高电平持续时间”。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Trigger Mode&lt;/code&gt;: &lt;strong&gt;触发模式&lt;/strong&gt;。在触发信号的上升沿启动计数器运行。注意：启动后，计数器会一直运行，直到手动停止。常用于“延迟启动”。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Trigger Source (触发源选择)&lt;a href=&quot;#trigger-source-触发源选择&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;决定谁来触发上述的“从模式”动作。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;ITR0/1/2/3&lt;/code&gt;: &lt;strong&gt;内部触发输入&lt;/strong&gt;。来源于其他定时器的 TRGO 输出。具体对应关系需查阅芯片手册的 &lt;em&gt;TIMx internal trigger connection&lt;/em&gt; 表。常用于“定时器级联（主从模式）”。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ETR1&lt;/code&gt;: &lt;strong&gt;外部触发输入&lt;/strong&gt;。信号通过外部引脚 ETR 进入，经过极性、预分频和滤波后作为触发源。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TI1_ED&lt;/code&gt;: &lt;strong&gt;通道 1 边沿检测&lt;/strong&gt;（Edge Detector）。TI1 的上升沿和下降沿都会产生触发。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;TI1FP1 / TI2FP2&lt;/code&gt;: &lt;strong&gt;滤波后的通道信号&lt;/strong&gt;。即来自输入引脚 CH1/CH2 且经过滤波和极性选择后的信号。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Clock Source (时钟源)&lt;a href=&quot;#clock-source-时钟源&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;决定计数器 CNT 计数的脉冲来源。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Internal Clock&lt;/code&gt;: &lt;strong&gt;内部时钟&lt;/strong&gt;。默认选项，使用来自 APB 预分频器处理后的内部时钟信号。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ETR2&lt;/code&gt;: &lt;strong&gt;外部时钟模式 2&lt;/strong&gt;。使用 ETR 引脚作为时钟源。与 External Clock Mode 1 的区别在于 ETR2 使用专用路径，不占用从模式控制器。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Channel 1/2/3/4 (通道模式)&lt;a href=&quot;#channel-1234-通道模式&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Input Capture direct mode&lt;/code&gt;: &lt;strong&gt;直接输入捕获&lt;/strong&gt;。物理引脚 CHx 的信号连接到对应的 CCRx 寄存器。用于“测频”或“测脉宽”。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Input Capture indirect mode&lt;/code&gt;: &lt;strong&gt;间接输入捕获&lt;/strong&gt;。物理引脚 CHx 的信号连接到&lt;strong&gt;相邻&lt;/strong&gt;的 CCRy 寄存器（如 CH1 连接到 CCR2）。常用于“PWM 输入模式”，即一个引脚信号同时测量周期和占空比。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Output Compare No Output&lt;/code&gt;: &lt;strong&gt;输出比较（无输出）&lt;/strong&gt;。CNT 与 CCR 匹配时产生中断或事件，但不翻转物理引脚电平。常用于“软件定时执行任务”。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Output Compare CHx&lt;/code&gt;: &lt;strong&gt;输出比较&lt;/strong&gt;。匹配时翻转物理引脚电平。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PWM Generation CHx&lt;/code&gt;: &lt;strong&gt;PWM 输出&lt;/strong&gt;。根据 ARR 和 CCR 的值在引脚上生成脉冲宽度调制信号。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Combine Channels (组合通道)&lt;a href=&quot;#combine-channels-组合通道&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Encoder Mode&lt;/code&gt;: &lt;strong&gt;编码器模式&lt;/strong&gt;。利用 TI1 和 TI2 两个通道的正交信号自动增减 CNT。用于“电机测速”或“旋钮位置检测”。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PWM Input on CH1/2&lt;/code&gt;: &lt;strong&gt;PWM 输入模式&lt;/strong&gt;。自动占用两个捕获寄存器，一个测周期，一个测占空比。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;XOR ON/HALL Sensor Mode&lt;/code&gt;: &lt;strong&gt;异或/霍尔传感器模式&lt;/strong&gt;。将 CH1/2/3 的输入进行异或运算后再接入触发控制器。常用于“直流无刷电机（BLDC）的换向控制”。&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;其他勾选项&lt;a href=&quot;#其他勾选项&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Use ETR as Clearing Source&lt;/code&gt;: &lt;strong&gt;使用 ETR 作为清除源&lt;/strong&gt;。当 ETR 信号为高时，强制清零输出参考信号（OCxREF）。常用于“过流保护”。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;XOR activation&lt;/code&gt;: &lt;strong&gt;异或激活&lt;/strong&gt;。开启通道间的异或逻辑。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;One Pulse Mode&lt;/code&gt;: &lt;strong&gt;单脉冲模式&lt;/strong&gt;。计数器在发生一次溢出（Update 事件）后自动停止（设置 CR1 寄存器的 OPM 位）。&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;PWM Generation 选项解读&lt;a href=&quot;#pwm-generation-选项解读&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/STM32/N5_TIM_2.webp&quot; alt=&quot;&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;一、时钟与计数基准（决定 PWM 频率）&lt;/strong&gt;&lt;a href=&quot;#一时钟与计数基准决定-pwm-频率&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;









































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;配置项&lt;/th&gt;&lt;th&gt;作用&lt;/th&gt;&lt;th&gt;关键公式/逻辑&lt;/th&gt;&lt;th&gt;典型设置&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;TIMx_CLK&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;定时器内核时钟源&lt;/td&gt;&lt;td&gt;&lt;code&gt;TIMx_CLK = APBx_CLK × (APB预分频≠1 ? 2 : 1)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;查时钟树，F103 通常 72MHz&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Prescaler (PSC)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;分频计数器时钟&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;计数频率 = TIMx_CLK / (PSC+1)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;设 PSC 使计数频率≈1MHz（精度与范围平衡）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Counter Period (ARR)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;决定 PWM 周期（频率）&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;PWM频率 = 计数频率 / (ARR+1)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;根据目标频率计算：&lt;code&gt;ARR = (计数频率/目标频率) - 1&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Counter Mode&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;计数方向&lt;/td&gt;&lt;td&gt;&lt;code&gt;Up&lt;/code&gt;（0→ARR）、&lt;code&gt;Down&lt;/code&gt;（ARR→0）、&lt;code&gt;Center&lt;/code&gt;&lt;/td&gt;&lt;td&gt;电机控制常用&lt;code&gt;Up&lt;/code&gt;，三相驱动用&lt;code&gt;Center&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;auto-reload preload&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;ARR 更新方式&lt;/td&gt;&lt;td&gt;&lt;code&gt;Enable&lt;/code&gt;：修改 ARR 后需更新事件才生效；&lt;code&gt;Disable&lt;/code&gt;：立即生效&lt;/td&gt;&lt;td&gt;&lt;strong&gt;建议 Enable&lt;/strong&gt;，避免调频时波形突变&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;&lt;strong&gt;二、PWM 输出控制（决定波形形状）&lt;/strong&gt;&lt;a href=&quot;#二pwm-输出控制决定波形形状&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;









































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;配置项&lt;/th&gt;&lt;th&gt;作用&lt;/th&gt;&lt;th&gt;关键逻辑&lt;/th&gt;&lt;th&gt;典型设置&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Pulse (CCR)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;决定 PWM 占空比&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;占空比 = CCR / (ARR+1)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;动态调占空比时直接改此值&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Mode&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;PWM 工作模式&lt;/td&gt;&lt;td&gt;&lt;code&gt;PWM mode 1&lt;/code&gt;：CNT&amp;lt;CCR 有效；&lt;code&gt;PWM mode 2&lt;/code&gt;：CNT≥CCR 有效&lt;/td&gt;&lt;td&gt;根据硬件“有效电平”选，常用模式 1&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;CH Polarity&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;通道极性&lt;/td&gt;&lt;td&gt;&lt;code&gt;High&lt;/code&gt;：有效电平为高；&lt;code&gt;Low&lt;/code&gt;：有效电平为低&lt;/td&gt;&lt;td&gt;匹配驱动电路（如高电平驱动电机选&lt;code&gt;High&lt;/code&gt;）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Output compare preload&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;CCR 更新方式&lt;/td&gt;&lt;td&gt;&lt;code&gt;Enable&lt;/code&gt;：修改 CCR 后需更新事件才生效；&lt;code&gt;Disable&lt;/code&gt;：立即生效&lt;/td&gt;&lt;td&gt;&lt;strong&gt;建议 Enable&lt;/strong&gt;，避免调占空比时跳变&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Fast Mode&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;快速响应模式&lt;/td&gt;&lt;td&gt;绕过影子寄存器，强制立即更新输出&lt;/td&gt;&lt;td&gt;默认&lt;code&gt;Disable&lt;/code&gt;，仅需极快响应时启用&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;&lt;strong&gt;三、高级定时器特有（驱动 H 桥电机必须）&lt;/strong&gt;&lt;a href=&quot;#三高级定时器特有驱动-h-桥电机必须&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;配置项&lt;/th&gt;&lt;th&gt;作用&lt;/th&gt;&lt;th&gt;关键逻辑&lt;/th&gt;&lt;th&gt;典型设置&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Break Input&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;刹车信号输入&lt;/td&gt;&lt;td&gt;外部刹车信号有效时，强制关闭 PWM 输出&lt;/td&gt;&lt;td&gt;接硬件保护电路（如过流检测）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Dead Time&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;死区时间&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;防止 H 桥上下管同时导通，设置互补输出的延迟&lt;/td&gt;&lt;td&gt;根据 MOS 管开关时间计算，通常 1~10μs&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Complementary Output&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;互补输出通道&lt;/td&gt;&lt;td&gt;与主通道反相，用于驱动 H 桥的另一个管子&lt;/td&gt;&lt;td&gt;必须与主通道配合使用&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;&lt;strong&gt;四、动态调频关键操作流程&lt;/strong&gt;&lt;a href=&quot;#四动态调频关键操作流程&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;当需要&lt;strong&gt;实时改变 PWM 频率&lt;/strong&gt;（如步进电机加减速）时，必须按此顺序操作：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;1.&lt;/span&gt;&lt;span&gt; HAL_TIM_PWM_Stop&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;htim&lt;/span&gt;&lt;span&gt;, TIM_CHANNEL_1);&lt;/span&gt;&lt;span&gt;  // ① 先停止PWM输出&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;2.&lt;/span&gt;&lt;span&gt; htim.Instance&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;ARR &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; new_arr;&lt;/span&gt;&lt;span&gt;            // ② 更新ARR（新频率）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;3.&lt;/span&gt;&lt;span&gt; // ③ 按比例更新CCR，保持占空比不变：&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;   new_ccr &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (new_arr &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; old_ccr &lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt; (old_arr &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;   __HAL_TIM_SET_COMPARE&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;htim&lt;/span&gt;&lt;span&gt;, TIM_CHANNEL_1, new_ccr);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;4.&lt;/span&gt;&lt;span&gt; HAL_TIM_PWM_Start&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;htim&lt;/span&gt;&lt;span&gt;, TIM_CHANNEL_1);&lt;/span&gt;&lt;span&gt; // ④ 重新启动PWM&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;核心原则&lt;/strong&gt;：改频率时&lt;strong&gt;必须同步调整 CCR&lt;/strong&gt;，否则占空比会突变，导致电机扭矩波动甚至失步。&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;&lt;strong&gt;五、速查：不同定时器选型&lt;/strong&gt;&lt;a href=&quot;#五速查不同定时器选型&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;类型&lt;/th&gt;&lt;th&gt;代表&lt;/th&gt;&lt;th&gt;适合场景&lt;/th&gt;&lt;th&gt;注意&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;基本定时器&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;TIM6, TIM7&lt;/td&gt;&lt;td&gt;纯时基（如 DAC 触发、简单延时）&lt;/td&gt;&lt;td&gt;&lt;strong&gt;无输出引脚&lt;/strong&gt;，不能直接输出 PWM&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;通用定时器&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;TIM2~TIM5&lt;/td&gt;&lt;td&gt;普通 PWM 输出、输入捕获、编码器&lt;/td&gt;&lt;td&gt;步进电机驱动常用，但&lt;strong&gt;无死区功能&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;高级定时器&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;TIM1, TIM8&lt;/td&gt;&lt;td&gt;三相电机驱动、H 桥控制&lt;/td&gt;&lt;td&gt;&lt;strong&gt;必须配置死区时间&lt;/strong&gt;，防止烧管&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;hr /&gt;
&lt;h3&gt;&lt;strong&gt;一句话总结&lt;/strong&gt;&lt;a href=&quot;#一句话总结&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;PSC + ARR = 频率&lt;/strong&gt;（PSC 定内部时钟，ARR 定周期）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;CCR = 占空比&lt;/strong&gt;（占空比 = CCR/(ARR+1)）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Polarity + Mode = 有效电平逻辑&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;动态调频时：停 PWM → 改 ARR → 按比例改 CCR → 启 PWM&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;驱动 H 桥必选高级定时器 + 配置死区&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;提示：在 STM32CubeMX 中配置时，&lt;strong&gt;先设 PSC 和 ARR 得到目标频率，再设 CCR 得到占空比，最后根据硬件电路选择极性和模式&lt;/strong&gt;。高级定时器务必在“Break and Dead Time”选项卡中设置死区时间。&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><category>category:笔记</category><category>category:STM32</category><category>tag:STM32</category><category>tag:TIM</category><category>tag:定时器</category><category>tag:嵌入式</category></item><item><title>STM32 库设计笔记</title><link>https://729dhs.site/post/stm32-library-design</link><guid isPermaLink="false">stm32-library-design</guid><description>STM32 驱动库与抽象层设计、句柄封装与条件编译实践。</description><pubDate>Mon, 29 Dec 2025 16:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;库设计&lt;a href=&quot;#库设计&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;一般而言,库的易用性和复杂度负相关,在设计&lt;strong&gt;高度抽象的易用性库&lt;/strong&gt;时,需要考虑设计模式和三层架构封装&lt;/p&gt;
&lt;h2&gt;句柄化与对象封装&lt;a href=&quot;#句柄化与对象封装&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;在面对对象编程中,我们用类或结构体来完成定义我们所操作的对象
以下是 STM32 HAL 库的一段 SPI 代码&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;typedef&lt;/span&gt;&lt;span&gt; struct&lt;/span&gt;&lt;span&gt; __SPI_HandleTypeDef&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  SPI_TypeDef                &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;Instance;&lt;/span&gt;&lt;span&gt;      /*!&amp;lt; SPI registers base address               */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  SPI_InitTypeDef            Init;&lt;/span&gt;&lt;span&gt;           /*!&amp;lt; SPI communication parameters             */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  const&lt;/span&gt;&lt;span&gt; uint8_t&lt;/span&gt;&lt;span&gt;              *&lt;/span&gt;&lt;span&gt;pTxBuffPtr;&lt;/span&gt;&lt;span&gt;    /*!&amp;lt; Pointer to SPI Tx transfer Buffer        */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  uint16_t&lt;/span&gt;&lt;span&gt;                   TxXferSize;&lt;/span&gt;&lt;span&gt;     /*!&amp;lt; SPI Tx Transfer size                     */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  __IO &lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt;              TxXferCount;&lt;/span&gt;&lt;span&gt;    /*!&amp;lt; SPI Tx Transfer Counter                  */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  uint8_t&lt;/span&gt;&lt;span&gt;                    *&lt;/span&gt;&lt;span&gt;pRxBuffPtr;&lt;/span&gt;&lt;span&gt;    /*!&amp;lt; Pointer to SPI Rx transfer Buffer        */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  uint16_t&lt;/span&gt;&lt;span&gt;                   RxXferSize;&lt;/span&gt;&lt;span&gt;     /*!&amp;lt; SPI Rx Transfer size                     */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  __IO &lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt;              RxXferCount;&lt;/span&gt;&lt;span&gt;    /*!&amp;lt; SPI Rx Transfer Counter                  */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;RxISR)(&lt;/span&gt;&lt;span&gt;struct&lt;/span&gt;&lt;span&gt; __SPI_HandleTypeDef &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;hspi);&lt;/span&gt;&lt;span&gt;   /*!&amp;lt; function pointer on Rx ISR       */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;TxISR)(&lt;/span&gt;&lt;span&gt;struct&lt;/span&gt;&lt;span&gt; __SPI_HandleTypeDef &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;hspi);&lt;/span&gt;&lt;span&gt;   /*!&amp;lt; function pointer on Tx ISR       */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  DMA_HandleTypeDef          &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;hdmatx;&lt;/span&gt;&lt;span&gt;        /*!&amp;lt; SPI Tx DMA Handle parameters             */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  DMA_HandleTypeDef          &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;hdmarx;&lt;/span&gt;&lt;span&gt;        /*!&amp;lt; SPI Rx DMA Handle parameters             */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  HAL_LockTypeDef            Lock;&lt;/span&gt;&lt;span&gt;           /*!&amp;lt; Locking object                           */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  __IO HAL_SPI_StateTypeDef  State;&lt;/span&gt;&lt;span&gt;          /*!&amp;lt; SPI communication state                  */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  __IO &lt;/span&gt;&lt;span&gt;uint32_t&lt;/span&gt;&lt;span&gt;              ErrorCode;&lt;/span&gt;&lt;span&gt;      /*!&amp;lt; SPI Error code                           */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;USE_HAL_SPI_REGISTER_CALLBACKS&lt;/span&gt;&lt;span&gt; ==&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;U&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; TxCpltCallback)(&lt;/span&gt;&lt;span&gt;struct&lt;/span&gt;&lt;span&gt; __SPI_HandleTypeDef &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;hspi);&lt;/span&gt;&lt;span&gt;             /*!&amp;lt; SPI Tx Completed callback          */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; RxCpltCallback)(&lt;/span&gt;&lt;span&gt;struct&lt;/span&gt;&lt;span&gt; __SPI_HandleTypeDef &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;hspi);&lt;/span&gt;&lt;span&gt;             /*!&amp;lt; SPI Rx Completed callback          */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; TxRxCpltCallback)(&lt;/span&gt;&lt;span&gt;struct&lt;/span&gt;&lt;span&gt; __SPI_HandleTypeDef &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;hspi);&lt;/span&gt;&lt;span&gt;           /*!&amp;lt; SPI TxRx Completed callback        */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; TxHalfCpltCallback)(&lt;/span&gt;&lt;span&gt;struct&lt;/span&gt;&lt;span&gt; __SPI_HandleTypeDef &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;hspi);&lt;/span&gt;&lt;span&gt;         /*!&amp;lt; SPI Tx Half Completed callback     */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; RxHalfCpltCallback)(&lt;/span&gt;&lt;span&gt;struct&lt;/span&gt;&lt;span&gt; __SPI_HandleTypeDef &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;hspi);&lt;/span&gt;&lt;span&gt;         /*!&amp;lt; SPI Rx Half Completed callback     */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; TxRxHalfCpltCallback)(&lt;/span&gt;&lt;span&gt;struct&lt;/span&gt;&lt;span&gt; __SPI_HandleTypeDef &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;hspi);&lt;/span&gt;&lt;span&gt;       /*!&amp;lt; SPI TxRx Half Completed callback   */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; ErrorCallback)(&lt;/span&gt;&lt;span&gt;struct&lt;/span&gt;&lt;span&gt; __SPI_HandleTypeDef &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;hspi);&lt;/span&gt;&lt;span&gt;              /*!&amp;lt; SPI Error callback                 */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; AbortCpltCallback)(&lt;/span&gt;&lt;span&gt;struct&lt;/span&gt;&lt;span&gt; __SPI_HandleTypeDef &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;hspi);&lt;/span&gt;&lt;span&gt;          /*!&amp;lt; SPI Abort callback                 */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; MspInitCallback)(&lt;/span&gt;&lt;span&gt;struct&lt;/span&gt;&lt;span&gt; __SPI_HandleTypeDef &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;hspi);&lt;/span&gt;&lt;span&gt;            /*!&amp;lt; SPI Msp Init callback              */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; MspDeInitCallback)(&lt;/span&gt;&lt;span&gt;struct&lt;/span&gt;&lt;span&gt; __SPI_HandleTypeDef &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;hspi);&lt;/span&gt;&lt;span&gt;          /*!&amp;lt; SPI Msp DeInit callback            */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#endif&lt;/span&gt;&lt;span&gt;  /* USE_HAL_SPI_REGISTER_CALLBACKS */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;} SPI_HandleTypeDef;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;从上代码中可见,HAL 库为了封装 SPI,用这个 SPI__HandleType 结构体把所需全部参数封装&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;再比如标准库的 GPIO 初始化结构体&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;typedef&lt;/span&gt;&lt;span&gt; struct&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  uint16_t&lt;/span&gt;&lt;span&gt; GPIO_Pin;             &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  GPIOSpeed_TypeDef GPIO_Speed;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  GPIOMode_TypeDef GPIO_Mode;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}GPIO_InitTypeDef;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;typedef&lt;/span&gt;&lt;span&gt; enum&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{ &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  GPIO_Speed_10MHz &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 1&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  GPIO_Speed_2MHz, &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  GPIO_Speed_50MHz&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}GPIOSpeed_TypeDef;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#define&lt;/span&gt;&lt;span&gt; IS_GPIO_SPEED&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;SPEED&lt;/span&gt;&lt;span&gt;) (((SPEED) &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; GPIO_Speed_10MHz) &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; ((SPEED) &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; GPIO_Speed_2MHz) &lt;/span&gt;&lt;span&gt;||&lt;/span&gt;&lt;span&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                              ((SPEED) &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; GPIO_Speed_50MHz))&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;typedef&lt;/span&gt;&lt;span&gt; enum&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{ GPIO_Mode_AIN &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0x&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  GPIO_Mode_IN_FLOATING &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0x&lt;/span&gt;&lt;span&gt;04&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  GPIO_Mode_IPD &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0x&lt;/span&gt;&lt;span&gt;28&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  GPIO_Mode_IPU &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0x&lt;/span&gt;&lt;span&gt;48&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  GPIO_Mode_Out_OD &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0x&lt;/span&gt;&lt;span&gt;14&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  GPIO_Mode_Out_PP &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0x&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  GPIO_Mode_AF_OD &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0x&lt;/span&gt;&lt;span&gt;1C&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  GPIO_Mode_AF_PP &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0x&lt;/span&gt;&lt;span&gt;18&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}GPIOMode_TypeDef;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以上是对对象的封装,常见还是用到结构体跟 enum 枚举,但是对于非嵌入式尤其是现代 C++而言,不使用 typedef 结构体,一般使用类和类枚举&lt;/p&gt;
&lt;h2&gt;HAL 设计与条件编译&lt;a href=&quot;#hal-设计与条件编译&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;来看一段标准库代码&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;#ifdef&lt;/span&gt;&lt;span&gt; CMSIS_NVIC_VIRTUAL&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  #ifndef&lt;/span&gt;&lt;span&gt; CMSIS_NVIC_VIRTUAL_HEADER_FILE&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    #define&lt;/span&gt;&lt;span&gt; CMSIS_NVIC_VIRTUAL_HEADER_FILE&lt;/span&gt;&lt;span&gt; &quot;cmsis_nvic_virtual.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  #endif&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  #include&lt;/span&gt;&lt;span&gt; CMSIS_NVIC_VIRTUAL_HEADER_FILE&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#else&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  #define&lt;/span&gt;&lt;span&gt; NVIC_SetPriorityGrouping&lt;/span&gt;&lt;span&gt;    __NVIC_SetPriorityGrouping&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  #define&lt;/span&gt;&lt;span&gt; NVIC_GetPriorityGrouping&lt;/span&gt;&lt;span&gt;    __NVIC_GetPriorityGrouping&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  #define&lt;/span&gt;&lt;span&gt; NVIC_EnableIRQ&lt;/span&gt;&lt;span&gt;              __NVIC_EnableIRQ&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  #define&lt;/span&gt;&lt;span&gt; NVIC_GetEnableIRQ&lt;/span&gt;&lt;span&gt;           __NVIC_GetEnableIRQ&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  #define&lt;/span&gt;&lt;span&gt; NVIC_DisableIRQ&lt;/span&gt;&lt;span&gt;             __NVIC_DisableIRQ&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  #define&lt;/span&gt;&lt;span&gt; NVIC_GetPendingIRQ&lt;/span&gt;&lt;span&gt;          __NVIC_GetPendingIRQ&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  #define&lt;/span&gt;&lt;span&gt; NVIC_SetPendingIRQ&lt;/span&gt;&lt;span&gt;          __NVIC_SetPendingIRQ&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  #define&lt;/span&gt;&lt;span&gt; NVIC_ClearPendingIRQ&lt;/span&gt;&lt;span&gt;        __NVIC_ClearPendingIRQ&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  #define&lt;/span&gt;&lt;span&gt; NVIC_GetActive&lt;/span&gt;&lt;span&gt;              __NVIC_GetActive&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  #define&lt;/span&gt;&lt;span&gt; NVIC_SetPriority&lt;/span&gt;&lt;span&gt;            __NVIC_SetPriority&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  #define&lt;/span&gt;&lt;span&gt; NVIC_GetPriority&lt;/span&gt;&lt;span&gt;            __NVIC_GetPriority&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  #define&lt;/span&gt;&lt;span&gt; NVIC_SystemReset&lt;/span&gt;&lt;span&gt;            __NVIC_SystemReset&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#endif&lt;/span&gt;&lt;span&gt; /* CMSIS_NVIC_VIRTUAL */&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;再比如&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;#ifdef&lt;/span&gt;&lt;span&gt; SYSCLK_FREQ_HSE&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; SetSysClockToHSE&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#elif&lt;/span&gt;&lt;span&gt; defined&lt;/span&gt;&lt;span&gt; SYSCLK_FREQ_24MHz&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; SetSysClockTo24&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#elif&lt;/span&gt;&lt;span&gt; defined&lt;/span&gt;&lt;span&gt; SYSCLK_FREQ_36MHz&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; SetSysClockTo36&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#elif&lt;/span&gt;&lt;span&gt; defined&lt;/span&gt;&lt;span&gt; SYSCLK_FREQ_48MHz&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; SetSysClockTo48&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#elif&lt;/span&gt;&lt;span&gt; defined&lt;/span&gt;&lt;span&gt; SYSCLK_FREQ_56MHz&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; SetSysClockTo56&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;);  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#elif&lt;/span&gt;&lt;span&gt; defined&lt;/span&gt;&lt;span&gt; SYSCLK_FREQ_72MHz&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; SetSysClockTo72&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#endif&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这种条件编译和检测宏定义然后看人下菜的模式,经常用于 HAL 设计,好处就是,可以灵活配置,已经对接好了各种可以快速移植的平台,你只需要选择你需要的宏定义甚至可以自动识别宏定义,然后条件编译&lt;/p&gt;
&lt;p&gt;当然,我们这种模式是为了实现后续的黑盒化,统一我们的库函数什么的,虽然前期写的痛苦代码较多,但是后期使用方便.&lt;/p&gt;
&lt;h2&gt;高度抽象带来的额外代码和防御性编程&lt;a href=&quot;#高度抽象带来的额外代码和防御性编程&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;当我们代码高度封装,就会出现我们为了实现这些本需要我们自己操作的内容,需要额外写自动化配置的多余代码,甚至还需要为了预留更高级的操作,我们还需要保留自己的一份原始底层操作函数代码
假设我们用自己的库实现了高度封装高度智能自动化的 GPIO 配置,但是这样的代价就是有些操作我们不能做,比如让 IO 口频率很高,或者因为外设原因,原本库中配置好的一套初始化就不能用了,我们只能自己配置,但是这个时候我们用的是自己的库,所以还是需要预留底层操作&lt;/p&gt;
&lt;h3&gt;防御性编程&lt;a href=&quot;#防御性编程&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;仍然是标准库的案例:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; GPIO_SetBits&lt;/span&gt;&lt;span&gt;(GPIO_TypeDef&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; GPIOx&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; GPIO_Pin&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;{&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  /* Check the parameters */&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  assert_param&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IS_GPIO_ALL_PERIPH&lt;/span&gt;&lt;span&gt;(GPIOx));&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  assert_param&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;IS_GPIO_PIN&lt;/span&gt;&lt;span&gt;(GPIO_Pin));&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  GPIOx-&amp;gt;BSRR &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_Pin;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;这个 assert_param 宏就是防御性编程,这是一个检验的函数用于检验传入参数是否合法,否则直接进入 hardfault,在这里即使是最简单的 Set 操作,也检验了 IO 端口号的合法性
再比如说互斥锁和原子操作,就是典型的防御性编程,保证程序运行时至少是完全在运行的,保证运行环境安全性.&lt;/p&gt;
&lt;h3&gt;回调函数与解耦&lt;a href=&quot;#回调函数与解耦&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;为什么抽象库函数需要回调?
首先我们理解这个问题是什么意思
简单说,抽象库需要在不同层间传递“当事件发生时要做什么”的可变逻辑,但库本身又不想也不应关心具体业务,于是提供一个“挂钩点”(回调)让上层注入行为。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;解耦职责&lt;/strong&gt;: 底层库只负责检测事件、调度流程,上层注入的回调负责业务决策,两者互不依赖,降低耦合。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;消除主动轮询&lt;/strong&gt;: 没有回调时,上层只能轮询查询外设状态;有了回调,库在中断/任务切换点被动触发,既省 CPU 又降低延迟。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;复用与可测试性&lt;/strong&gt;: 同一套库代码可以被不同项目/模块复用,只需更换回调实现即可;测试时也能用假回调注入,隔离硬件依赖。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;状态机闭环&lt;/strong&gt;: HAL 里常见的“配置-&amp;gt;启动-&amp;gt;事件回调-&amp;gt;收尾”模式,回调为状态机提供了出口,让框架能够正确结束或继续下一步。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;扩展性&lt;/strong&gt;: 当需要额外处理(统计、日志、安全检查)时,增加或替换回调就能完成,无需修改库本体。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;回调的使用注意点:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;回调应尽量短小可重入,避免在中断上下文里做耗时或阻塞操作。&lt;/li&gt;
&lt;li&gt;明确回调的调用时机与线程/中断上下文,否则容易出现竞态。&lt;/li&gt;
&lt;li&gt;对回调错误要有兜底策略(返回码或错误钩子),避免隐藏故障。&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>category:笔记</category><category>category:STM32</category><category>tag:STM32</category><category>tag:库设计</category><category>tag:HAL</category><category>tag:嵌入式</category></item><item><title>STM32 Keil RTE 与 RTOS 笔记</title><link>https://729dhs.site/post/stm32-keil-rte-rtos</link><guid isPermaLink="false">stm32-keil-rte-rtos</guid><description>STM32 在 Keil RTE 环境下的项目创建与 FreeRTOS API 基础记录。</description><pubDate>Sat, 27 Dec 2025 16:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;Keil+RTE 环境创建&lt;a href=&quot;#keilrte-环境创建&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;打开 Keil,New uVision Project,选择芯片 STM32f103C8T6,默认弹出 RTE 窗口&lt;/p&gt;
&lt;p&gt;如图,进行 Std 标准库创建时,选择以下基础内容:
CMSIS —&amp;gt; CORE 这是链接 ARM 芯片的核心
Device —&amp;gt; Startup 这是芯片启动必须链接的
其他可以不需要
但是使用标准库操作 STM32 时,还需要
Device —&amp;gt; StdPeriph Drivers 下的内容
如 RCC,GPIO,I2C 等,选择后出现黄色报错,点击界面最左下角的 Resolve 即可,会自动寻找依赖项选择,如 Framework&lt;/p&gt;
&lt;p&gt;这样最基础的 Std 库项目创建完成,其他跟普通的创建项目没有区别
创建主函数,写个简单 demo,点击 Options for Target,也就是常说的魔术棒
点击 C/C++(AC6)进行宏定义设置
对于 103C8 需要写 STM32F10X_MD
对于标准库需要写 USD_STDPERIPH_DRIVER
以及对于 AC6+CMSIS 6.X 版本,需要加入 IP=IPR
对 CMSIS 5.X 则不需要&lt;/p&gt;
&lt;p&gt;想知道自己库的版本,或者对版本和库进行管理,点击 RTE 图标旁边的 Pack Installer 即可&lt;/p&gt;
&lt;h1&gt;对于 FreeRTOS 的一些知识&lt;a href=&quot;#对于-freertos-的一些知识&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;FreeRTOS 的 API 分为两个版本,一个是原生,一个是 CMSIS 版 API,CMSIS 对原生函数名等进行改写&lt;/p&gt;
&lt;h2&gt;原生 API&lt;a href=&quot;#原生-api&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;遵循一套独特的命名约定，函数名通常包含返回类型。&lt;/p&gt;
&lt;p&gt;以下是原生例程&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;#include&lt;/span&gt;&lt;span&gt; &quot;stm32f10x.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#include&lt;/span&gt;&lt;span&gt; &quot;stm32f10x_conf.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#include&lt;/span&gt;&lt;span&gt; &amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#include&lt;/span&gt;&lt;span&gt; &quot;FreeRTOS.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#include&lt;/span&gt;&lt;span&gt; &quot;task.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;volatile&lt;/span&gt;&lt;span&gt; uint32_t&lt;/span&gt;&lt;span&gt; g_counter &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;  // 简单计数器，LED和UART共享&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; LED_Init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    GPIO_InitTypeDef gpio;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    RCC_APB2PeriphClockCmd&lt;/span&gt;&lt;span&gt;(RCC_APB2Periph_GPIOC, ENABLE);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    gpio.GPIO_Pin &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_Pin_13;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    gpio.GPIO_Mode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_Mode_Out_PP;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    gpio.GPIO_Speed &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_Speed_2MHz;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    GPIO_Init&lt;/span&gt;&lt;span&gt;(GPIOC, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;gpio);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; USART1_Init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    GPIO_InitTypeDef gpio; USART_InitTypeDef usart;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    RCC_APB2PeriphClockCmd&lt;/span&gt;&lt;span&gt;(RCC_APB2Periph_GPIOA &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; RCC_APB2Periph_USART1, ENABLE);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    gpio.GPIO_Pin &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_Pin_9;  gpio.GPIO_Mode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_Mode_AF_PP;      gpio.GPIO_Speed &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_Speed_50MHz; &lt;/span&gt;&lt;span&gt;GPIO_Init&lt;/span&gt;&lt;span&gt;(GPIOA, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;gpio);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    gpio.GPIO_Pin &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_Pin_10; gpio.GPIO_Mode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_Mode_IN_FLOATING;                               &lt;/span&gt;&lt;span&gt;GPIO_Init&lt;/span&gt;&lt;span&gt;(GPIOA, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;gpio);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    usart.USART_BaudRate &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 115200&lt;/span&gt;&lt;span&gt;; usart.USART_WordLength &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; USART_WordLength_8b; usart.USART_StopBits &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; USART_StopBits_1;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    usart.USART_Parity &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; USART_Parity_No; usart.USART_HardwareFlowControl &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; USART_HardwareFlowControl_None; usart.USART_Mode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; USART_Mode_Tx &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; USART_Mode_Rx;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    USART_Init&lt;/span&gt;&lt;span&gt;(USART1, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;usart); &lt;/span&gt;&lt;span&gt;USART_Cmd&lt;/span&gt;&lt;span&gt;(USART1, ENABLE);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; fputc&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; ch&lt;/span&gt;&lt;span&gt;, FILE &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    USART_SendData&lt;/span&gt;&lt;span&gt;(USART1, (&lt;/span&gt;&lt;span&gt;uint8_t&lt;/span&gt;&lt;span&gt;)ch);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    while&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;USART_GetFlagStatus&lt;/span&gt;&lt;span&gt;(USART1, USART_FLAG_TXE) &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; RESET);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    return&lt;/span&gt;&lt;span&gt; ch;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; USART1_SendChar&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;char&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    USART_SendData&lt;/span&gt;&lt;span&gt;(USART1, c);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    while&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;USART_GetFlagStatus&lt;/span&gt;&lt;span&gt;(USART1, USART_FLAG_TXE) &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; RESET);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; USART1_SendString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; char&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    while&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;s) &lt;/span&gt;&lt;span&gt;USART1_SendChar&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;span&gt;  // 简单同步发送，不做缓冲&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; LedTask&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt;param&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    while&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        GPIO_ResetBits&lt;/span&gt;&lt;span&gt;(GPIOC, GPIO_Pin_13);&lt;/span&gt;&lt;span&gt;  // LED on&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        vTaskDelay&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;pdMS_TO_TICKS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;500&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        GPIO_SetBits&lt;/span&gt;&lt;span&gt;(GPIOC, GPIO_Pin_13);&lt;/span&gt;&lt;span&gt;    // LED off&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        vTaskDelay&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;pdMS_TO_TICKS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;500&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; UartTask&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt;param&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    char&lt;/span&gt;&lt;span&gt; buf&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;16&lt;/span&gt;&lt;span&gt;]; &lt;/span&gt;&lt;span&gt;uint32_t&lt;/span&gt;&lt;span&gt; val; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; i;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    while&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        g_counter&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;; val &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; g_counter; i &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        if&lt;/span&gt;&lt;span&gt; (val &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;) { &lt;/span&gt;&lt;span&gt;buf&lt;/span&gt;&lt;span&gt;[i&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;0&apos;&lt;/span&gt;&lt;span&gt;; }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            char&lt;/span&gt;&lt;span&gt; tmp&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;]; &lt;/span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; j &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            while&lt;/span&gt;&lt;span&gt; (val) { &lt;/span&gt;&lt;span&gt;tmp&lt;/span&gt;&lt;span&gt;[j&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (val &lt;/span&gt;&lt;span&gt;%&lt;/span&gt;&lt;span&gt; 10&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; &apos;0&apos;&lt;/span&gt;&lt;span&gt;; val &lt;/span&gt;&lt;span&gt;/=&lt;/span&gt;&lt;span&gt; 10&lt;/span&gt;&lt;span&gt;; }&lt;/span&gt;&lt;span&gt; // 反转收集数字&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            while&lt;/span&gt;&lt;span&gt; (j&lt;/span&gt;&lt;span&gt;--&lt;/span&gt;&lt;span&gt;) &lt;/span&gt;&lt;span&gt;buf&lt;/span&gt;&lt;span&gt;[i&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; tmp&lt;/span&gt;&lt;span&gt;[j];&lt;/span&gt;&lt;span&gt;                         // 再反转得到正序&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        buf&lt;/span&gt;&lt;span&gt;[i] &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &apos;&lt;/span&gt;&lt;span&gt;\0&lt;/span&gt;&lt;span&gt;&apos;&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        USART1_SendString&lt;/span&gt;&lt;span&gt;(buf); &lt;/span&gt;&lt;span&gt;USART1_SendString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;\r\n&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;span&gt;      // 发送计数值&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        vTaskDelay&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;pdMS_TO_TICKS&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1000&lt;/span&gt;&lt;span&gt;));&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    SystemInit&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span&gt;                 // HAL/CMSIS 启动&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    LED_Init&lt;/span&gt;&lt;span&gt;(); &lt;/span&gt;&lt;span&gt;USART1_Init&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span&gt;    // 硬件初始化&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    xTaskCreate&lt;/span&gt;&lt;span&gt;(LedTask, &lt;/span&gt;&lt;span&gt;&quot;LED&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;128&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;span&gt;   // 低栈闪灯&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    xTaskCreate&lt;/span&gt;&lt;span&gt;(UartTask, &lt;/span&gt;&lt;span&gt;&quot;UART&quot;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;512&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;span&gt; // 串口打印任务&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    vTaskStartScheduler&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span&gt;        // 启动调度&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    while&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;span&gt; /* should never reach */&lt;/span&gt;&lt;span&gt; }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;以下是 CMSIS V2 例程&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;#include&lt;/span&gt;&lt;span&gt; &quot;stm32f10x.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#include&lt;/span&gt;&lt;span&gt; &quot;cmsis_os2.h&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#include&lt;/span&gt;&lt;span&gt; &amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;volatile&lt;/span&gt;&lt;span&gt; uint32_t&lt;/span&gt;&lt;span&gt; g_counter &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;span&gt;    // LED 线程自增计数，UART读取&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;osThreadId_t&lt;/span&gt;&lt;span&gt; ledTaskHandle;&lt;/span&gt;&lt;span&gt;         // LED 线程句柄&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;osThreadId_t&lt;/span&gt;&lt;span&gt; uartTaskHandle;&lt;/span&gt;&lt;span&gt;        // UART 线程句柄&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; LED_Task&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt;argument&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;span&gt;   // 闪灯任务&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; UART_Task&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt;argument&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;span&gt;  // 串口打印任务&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; USART1_Init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; USART1_SendChar&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;char&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; USART1_SendString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; char&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; LED_Task&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt;argument&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    GPIO_InitTypeDef gpio;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    RCC_APB2PeriphClockCmd&lt;/span&gt;&lt;span&gt;(RCC_APB2Periph_GPIOC, ENABLE);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    gpio.GPIO_Pin &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_Pin_13; gpio.GPIO_Mode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_Mode_Out_PP; gpio.GPIO_Speed &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_Speed_50MHz; &lt;/span&gt;&lt;span&gt;GPIO_Init&lt;/span&gt;&lt;span&gt;(GPIOC, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;gpio);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    GPIO_SetBits&lt;/span&gt;&lt;span&gt;(GPIOC, GPIO_Pin_13);&lt;/span&gt;&lt;span&gt;  // 默认灭&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    for&lt;/span&gt;&lt;span&gt; (;;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        GPIO_ResetBits&lt;/span&gt;&lt;span&gt;(GPIOC, GPIO_Pin_13); g_counter&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;; &lt;/span&gt;&lt;span&gt;osDelay&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;500&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        GPIO_SetBits&lt;/span&gt;&lt;span&gt;(GPIOC, GPIO_Pin_13);    &lt;/span&gt;&lt;span&gt;osDelay&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;500&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; UART_Task&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt;argument&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    char&lt;/span&gt;&lt;span&gt; buf&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;64&lt;/span&gt;&lt;span&gt;];&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    USART1_Init&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span&gt;  // 独立初始化串口&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    for&lt;/span&gt;&lt;span&gt; (;;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        snprintf&lt;/span&gt;&lt;span&gt;(buf, &lt;/span&gt;&lt;span&gt;sizeof&lt;/span&gt;&lt;span&gt;(buf), &lt;/span&gt;&lt;span&gt;&quot;Hello RTOS, g_counter = &lt;/span&gt;&lt;span&gt;%lu\r\n&lt;/span&gt;&lt;span&gt;&quot;&lt;/span&gt;&lt;span&gt;, g_counter);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        USART1_SendString&lt;/span&gt;&lt;span&gt;(buf);&lt;/span&gt;&lt;span&gt;  // 直接同步发送&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        osDelay&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1000&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; USART1_Init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    GPIO_InitTypeDef gpio; USART_InitTypeDef usart;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    RCC_APB2PeriphClockCmd&lt;/span&gt;&lt;span&gt;(RCC_APB2Periph_GPIOA &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; RCC_APB2Periph_USART1, ENABLE);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    gpio.GPIO_Pin &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_Pin_9;  gpio.GPIO_Mode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_Mode_AF_PP;      gpio.GPIO_Speed &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_Speed_50MHz; &lt;/span&gt;&lt;span&gt;GPIO_Init&lt;/span&gt;&lt;span&gt;(GPIOA, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;gpio);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    gpio.GPIO_Pin &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_Pin_10; gpio.GPIO_Mode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_Mode_IN_FLOATING;                               &lt;/span&gt;&lt;span&gt;GPIO_Init&lt;/span&gt;&lt;span&gt;(GPIOA, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;gpio);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    usart.USART_BaudRate &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 115200&lt;/span&gt;&lt;span&gt;; usart.USART_WordLength &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; USART_WordLength_8b; usart.USART_StopBits &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; USART_StopBits_1;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    usart.USART_Parity &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; USART_Parity_No; usart.USART_Mode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; USART_Mode_Tx; usart.USART_HardwareFlowControl &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; USART_HardwareFlowControl_None;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    USART_Init&lt;/span&gt;&lt;span&gt;(USART1, &lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;usart); &lt;/span&gt;&lt;span&gt;USART_Cmd&lt;/span&gt;&lt;span&gt;(USART1, ENABLE);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; USART1_SendChar&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;char&lt;/span&gt;&lt;span&gt; c&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    USART_SendData&lt;/span&gt;&lt;span&gt;(USART1, c);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    while&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;USART_GetFlagStatus&lt;/span&gt;&lt;span&gt;(USART1, USART_FLAG_TXE) &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; RESET);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; USART1_SendString&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;const&lt;/span&gt;&lt;span&gt; char&lt;/span&gt;&lt;span&gt; *&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    while&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;s) &lt;/span&gt;&lt;span&gt;USART1_SendChar&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;span&gt;  // 简单轮询方式&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;int&lt;/span&gt;&lt;span&gt; main&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    NVIC_PriorityGroupConfig&lt;/span&gt;&lt;span&gt;(NVIC_PriorityGroup_4);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    osKernelInitialize&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    ledTaskHandle &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; osThreadNew&lt;/span&gt;&lt;span&gt;(LED_Task, &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;span&gt;   // 创建闪灯线程&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    uartTaskHandle &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; osThreadNew&lt;/span&gt;&lt;span&gt;(UART_Task, &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;NULL&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;span&gt; // 创建串口线程&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    osKernelStart&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span&gt;                                    // 启动调度器&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    while&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;) {}&lt;/span&gt;&lt;span&gt;                                        // 不应返回&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h1&gt;杂谈&lt;a href=&quot;#杂谈&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;p&gt;需要注意的是在 RTOS 里要避免 newLib,比如 Stdio.h,printf,这些函数库对于 RTOS 并不友好&lt;/p&gt;
&lt;h2&gt;为什么 Newlib 对 RTOS “不友好”？&lt;a href=&quot;#为什么-newlib-对-rtos-不友好&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A. 重入性 (Reentrancy) 风险
这是最致命的问题。printf、malloc、strtok 等函数通常使用全局变量或静态缓冲区。
冲突： 如果任务 A 正在调用 printf 打印一半，此时更高优先级的任务 B 抢占了 CPU 也调用 printf，全局缓冲区的数据就会被污染，甚至导致硬件异常。
Newlib 的补救： Newlib 提供了一个 struct _reent 结构体，但 RTOS 必须为每个任务都分配一个这样的结构体并在任务切换时进行切换，这会极大增加内存开销。&lt;/p&gt;
&lt;p&gt;B. 栈空间的“大胃王”
printf 是一个非常复杂的函数，它需要处理各种格式化、浮动溢出和内部缓存。
内存占用： 调用一次标准 printf 可能会瞬间消耗几百甚至上千字节的栈空间。
后果： 在 RTOS 中，每个任务的栈大小是有限的（通常设为 128 或 256 字），直接调用 printf 极易引发 Stack Overflow。&lt;/p&gt;
&lt;p&gt;C. 线程安全与 Lock
Newlib 的某些函数内部会尝试调用 __malloc_lock 和 __malloc_unlock。如果这些底层的锁函数没有被正确映射到 RTOS 的信号量或互斥量上，系统就会死锁或产生竞态。&lt;/p&gt;
&lt;p&gt;总结：RTOS 的“避坑手册”&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;禁止在中断 (ISR) 中调用 printf： 这几乎 100% 会导致系统挂死。&lt;/li&gt;
&lt;li&gt;谨慎对待浮点数： %f 格式化极其消耗性能和栈空间。&lt;/li&gt;
&lt;li&gt;检查栈大小： 如果必须用标准库，请务必调大任务栈（Stack Size）。&lt;/li&gt;
&lt;li&gt;配置 Newlib-nano： 在 STM32CubeIDE 等编译器中，勾选 —specs=nano.specs，它可以大幅缩减标准库体积，但依然不能完全解决线程安全问题。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Cortex-M 上的原子操作小结&lt;a href=&quot;#cortex-m-上的原子操作小结&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;8/16/32 位对齐的读写在 Cortex-M3/M4 上天然原子（单总线周期），但非对齐或跨字宽访问就不原子。&lt;/li&gt;
&lt;li&gt;禁中断法：短临界区可用 &lt;code&gt;__disable_irq()&lt;/code&gt; / &lt;code&gt;__enable_irq()&lt;/code&gt; 包裹，或 FreeRTOS 的 &lt;code&gt;taskENTER_CRITICAL&lt;/code&gt;/&lt;code&gt;taskEXIT_CRITICAL&lt;/code&gt;；注意临界区越短越好。&lt;/li&gt;
&lt;li&gt;自旋原子指令：Cortex-M3+ 支持 &lt;code&gt;LDREX&lt;/code&gt;/&lt;code&gt;STREX&lt;/code&gt; 形成原子操作，CMSIS 提供封装：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;__LDREXW&lt;/code&gt; / &lt;code&gt;__STREXW&lt;/code&gt;：32 位独占读写，用于自定义无锁结构。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;__CLREX&lt;/code&gt;：清除独占标记，避免意外占用。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;内存屏障：
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;__DMB()&lt;/code&gt; 数据内存屏障，保证访存顺序（典型用在共享变量标志位前后）。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;__DSB()&lt;/code&gt; 数据同步屏障，确保之前的访存完成后才继续；常见于外设寄存器配置完成后。&lt;/li&gt;
&lt;li&gt;&lt;code&gt;__ISB()&lt;/code&gt; 指令同步屏障，刷新流水线，常用于切换栈/向量表后。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;原子加减建议：
&lt;ul&gt;
&lt;li&gt;C11 &lt;code&gt;stdatomic&lt;/code&gt; 若编译器/库支持，可用 &lt;code&gt;atomic_fetch_add&lt;/code&gt; 等，底层会用 LDREX/STREX。&lt;/li&gt;
&lt;li&gt;否则用禁中断或基于 &lt;code&gt;__LDREXW&lt;/code&gt;/&lt;code&gt;__STREXW&lt;/code&gt; 的循环实现 &lt;code&gt;atomic_inc&lt;/code&gt;/&lt;code&gt;atomic_dec&lt;/code&gt;。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;FreeRTOS 场景：
&lt;ul&gt;
&lt;li&gt;任务间优先用队列/信号量/互斥量；ISR 到任务用中断安全 API（以 &lt;code&gt;FromISR&lt;/code&gt; 结尾）。&lt;/li&gt;
&lt;li&gt;若仅是简单计数且在任务上下文，可用 &lt;code&gt;taskENTER_CRITICAL&lt;/code&gt; 包裹；在 ISR 中则禁用更低优先级中断或用 &lt;code&gt;ulPortSetInterruptMask&lt;/code&gt;/&lt;code&gt;vPortClearInterruptMask&lt;/code&gt;（端口相关）。&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>category:笔记</category><category>category:STM32</category><category>tag:STM32</category><category>tag:RTOS</category><category>tag:FreeRTOS</category><category>tag:Keil</category></item></channel></rss>