<?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://www.729dhs.site</link><item><title>校区2 录取名单多维度分析报告</title><link>https://www.729dhs.site/post/note/campus2_analysis</link><guid isPermaLink="false">note/campus2_analysis</guid><description>2个专业 · 37名报考考生 · 32名录取 · 初试四科拆解 + 复试综合分析</description><pubDate>Sun, 21 Jun 2026 16:40:00 GMT</pubDate><content:encoded>&lt;h1&gt;校区 2 录取名单多维度分析报告&lt;a href=&quot;#校区-2-录取名单多维度分析报告&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;2 个专业 · 37 名报考考生 · 32 名录取 · 初试四科拆解 + 复试综合分析&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;p&gt;&lt;strong&gt;光电信息工程：&lt;/strong&gt; 报考 19 人，录取 17 人，初试名单中有复试成绩的 17 人与录取名单 17 人&lt;strong&gt;完全匹配&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;仪器仪表工程：&lt;/strong&gt; 报考 18 人，录取 15 人。初试名单中有复试成绩的 15 人中，有一位考生的复试总分存在微小差异（a.xlsx 记录为 364.72，ss.xlsx 记录为 394.72），可能是数据录入笔误，建议核实。其余 14 人完全匹配。&lt;/p&gt;
&lt;p&gt;未录取考生共 5 人（仪器仪表 3 人、光电信息 2 人），均为初试名单中有记录但无复试总分。&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;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;th&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;/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;/td&gt;&lt;td&gt;18&lt;/td&gt;&lt;td&gt;15&lt;/td&gt;&lt;td&gt;83.3%&lt;/td&gt;&lt;td&gt;56.9&lt;/td&gt;&lt;td&gt;78.2&lt;/td&gt;&lt;td&gt;120.0&lt;/td&gt;&lt;td&gt;117.8&lt;/td&gt;&lt;td&gt;372.9&lt;/td&gt;&lt;td&gt;25.7&lt;/td&gt;&lt;td&gt;424&lt;/td&gt;&lt;td&gt;344&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;光电信息工程&lt;/td&gt;&lt;td&gt;19&lt;/td&gt;&lt;td&gt;17&lt;/td&gt;&lt;td&gt;89.5%&lt;/td&gt;&lt;td&gt;54.8&lt;/td&gt;&lt;td&gt;74.2&lt;/td&gt;&lt;td&gt;110.9&lt;/td&gt;&lt;td&gt;120.4&lt;/td&gt;&lt;td&gt;360.3&lt;/td&gt;&lt;td&gt;27.8&lt;/td&gt;&lt;td&gt;404&lt;/td&gt;&lt;td&gt;320&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/BIT/campus2_chart_1.png&quot; alt=&quot;图表1&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&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;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/BIT/campus2_chart_2.png&quot; alt=&quot;图表2&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;要点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;仪器仪表工程的数学中位数明显高于光电信息工程（约 125 vs 110），但离散度也更大&lt;/li&gt;
&lt;li&gt;光电信息工程的专业课整体偏高，中位数约 125 分&lt;/li&gt;
&lt;li&gt;两个专业的政治和英语分布较为接近&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;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/BIT/campus2_chart_3.png&quot; alt=&quot;图表3&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;要点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;仪器仪表工程的数学均分（120.0）比光电信息工程（110.9）高出近 10 分&lt;/li&gt;
&lt;li&gt;光电信息工程的专业课均分（120.4）略高于仪器仪表工程（117.8）&lt;/li&gt;
&lt;li&gt;政治和英语两科差异不大，政治仪器仪表略高、英语仪器仪表也略高&lt;/li&gt;
&lt;li&gt;总体来看，仪器仪表工程初试均分更高（372.9 vs 360.3），主要由数学拉开差距&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;将各维度归一化后对比，面积越大代表综合实力越强。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/BIT/campus2_chart_4.png&quot; alt=&quot;图表4&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&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;li&gt;两者政治水平接近&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;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/BIT/campus2_chart_5.png&quot; alt=&quot;图表5&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;要点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;政治成绩两个专业都集中在 50-65 分区间&lt;/li&gt;
&lt;li&gt;英语集中在 70-85 分&lt;/li&gt;
&lt;li&gt;数学分布范围最广（74-145），是拉开差距的关键科目&lt;/li&gt;
&lt;li&gt;专业课集中在 105-135 区间&lt;/li&gt;
&lt;li&gt;数学的标准差最大，是区分考生水平的核心科目&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;每位考生的四科成绩堆叠展示，按初试总分降序排列，× 标记未录取考生。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/BIT/campus2_chart_6.png&quot; alt=&quot;图表6&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&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;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;figure&gt;&lt;img src=&quot;/img/Note/BIT/campus2_chart_7.png&quot; alt=&quot;图表7&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;要点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;两个专业的科目占比结构非常相似——数学和专业课各占约 31-32%，是初试的两大支柱&lt;/li&gt;
&lt;li&gt;英语占约 20-21%&lt;/li&gt;
&lt;li&gt;政治占比最小，仅约 15%&lt;/li&gt;
&lt;li&gt;这意味着&lt;strong&gt;数学和专业课是决定初试排名最重要的科目&lt;/strong&gt;&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;颜色越绿表示正相关越强，越红表示负相关越强。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/BIT/campus2_chart_8.png&quot; alt=&quot;图表8&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;要点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;数学与初试总分的相关性最高（约 0.78），再次印证数学是拉分关键&lt;/li&gt;
&lt;li&gt;专业课与总分的相关性也较强（约 0.69）&lt;/li&gt;
&lt;li&gt;政治和英语与总分的相关性较弱&lt;/li&gt;
&lt;li&gt;值得注意的是，数学与专业课呈中等正相关（约 0.3），说明数学好的考生专业课往往也不差&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;九、初试总分 vs 复试总分散点图&lt;a href=&quot;#九初试总分-vs-复试总分散点图&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;figure&gt;&lt;img src=&quot;/img/Note/BIT/campus2_chart_9.png&quot; alt=&quot;图表9&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&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;li&gt;光电信息工程中出现了一些初试分不高但复试总分较高的案例（逆袭者）&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;浅色柱表示所有报考考生，深色柱表示最终录取考生。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/BIT/campus2_chart_10.png&quot; alt=&quot;图表10&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;要点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;仪器仪表工程在 390-410 高分段录取率 100%&lt;/li&gt;
&lt;li&gt;370-390 分段是竞争最激烈的区间&lt;/li&gt;
&lt;li&gt;光电信息工程的分布更加均匀，从 320 到 404 都有录取，低分段（320-330）也有考生成功录取（可能复试逆袭）&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;基于公式 &lt;code&gt;总成绩 ≈ 初试×0.5 + 复试×2.5&lt;/code&gt; 推算。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/BIT/campus2_chart_11.png&quot; alt=&quot;图表11&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;要点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;两个专业的初试和复试贡献占比非常接近（初试约 48-50%，复试约 50-52%），复试权重略高&lt;/li&gt;
&lt;li&gt;说明在这个校区，&lt;strong&gt;复试表现对最终录取的影响与初试几乎同等重要，甚至略占上风&lt;/strong&gt;&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;绿色=复试后排名提升，红色=复试后排名下降。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/BIT/campus2_chart_12.png&quot; alt=&quot;图表12&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;要点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;仪器仪表工程中有考生排名变化幅度达 5 位以上，复试逆袭空间较大&lt;/li&gt;
&lt;li&gt;光电信息工程的排名变化相对温和，多数在±3 名以内，初试高分的”护城河”更稳固&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;假设 &lt;code&gt;总成绩 = 初试×0.5 + 复试×2.5&lt;/code&gt;，反推复试面试得分。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/BIT/campus2_chart_13.png&quot; alt=&quot;图表13&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;要点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;推算的复试成绩集中在 78-90 分区间&lt;/li&gt;
&lt;li&gt;仪器仪表工程复试均值约 84 分，光电信息工程复试均值约 84 分，两者非常接近&lt;/li&gt;
&lt;li&gt;复试分数分布相对集中，区分度不如初试大&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;十四、录取 vs 未录取考生各科对比&lt;a href=&quot;#十四录取-vs-未录取考生各科对比&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/BIT/campus2_chart_14.png&quot; alt=&quot;图表14&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;要点：&lt;/strong&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;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;a href=&quot;#1-数学是拉分之王&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;数学与初试总分相关性最高（~0.78），标准差最大，是决定初试排名的核心科目。仪器仪表工程数学均分（120.0）显著高于光电信息（110.9），直接拉开了初试差距。&lt;/p&gt;
&lt;h3&gt;2. 专业课紧随其后&lt;a href=&quot;#2-专业课紧随其后&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;专业课与总分相关性约 0.69，是第二大拉分科目。光电信息工程的专业课均分（120.4）略高于仪器仪表（117.8）。&lt;/p&gt;
&lt;h3&gt;3. 政治英语是”稳定器”&lt;a href=&quot;#3-政治英语是稳定器&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;政治和英语的分数区间窄、标准差小，很难靠这两科拉开差距，但如果严重偏低会成为短板。&lt;/p&gt;
&lt;h3&gt;4. 复试权重与初试相当甚至略高&lt;a href=&quot;#4-复试权重与初试相当甚至略高&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;复试对总成绩的贡献约 50-52%，说明复试表现至关重要。仪器仪表工程的复试逆袭空间更大，排名变动幅度可达 5 位以上。&lt;/p&gt;
&lt;h3&gt;5. 录取率较高&lt;a href=&quot;#5-录取率较高&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;仪器仪表工程录取率 83.3%（15/18），光电信息工程录取率 89.5%（17/19），整体录取率较高，竞争烈度中等。&lt;/p&gt;
&lt;h3&gt;6. 备考建议&lt;a href=&quot;#6-备考建议&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;，应重点攻克数学（拉开差距）同时保证专业课不拖后腿&lt;/li&gt;
&lt;li&gt;如果目标是&lt;strong&gt;光电信息工程&lt;/strong&gt;，数学同样是关键，但专业课也很重要，需要均衡发展&lt;/li&gt;
&lt;li&gt;复试准备不可忽视，尤其是仪器仪表工程方向&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;7. 与另一校区对比&lt;a href=&quot;#7-与另一校区对比&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;该校区仅有 2 个专业（vs 另一校区 4 个专业），招生规模更小（32 人 vs 94 人），但数据结构相似——复试占比均在 50%以上，体现了统一的录取评价体系。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;本报告由 Python + matplotlib 自动生成&lt;/em&gt;&lt;/p&gt;</content:encoded><category>category:笔记</category><category>tag:数据分析</category><category>tag:考研</category><category>tag:录取分析</category></item><item><title>录取名单多维度分析报告</title><link>https://www.729dhs.site/post/note/admission_analysis</link><guid isPermaLink="false">note/admission_analysis</guid><description>4个专业 · 94名录取考生 · 初试/复试/总成绩全面拆解</description><pubDate>Sun, 21 Jun 2026 07:30: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;blockquote&gt;
&lt;p&gt;4 个专业 · 94 名录取考生 · 初试/复试/总成绩全面拆解&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;p&gt;本报告基于录取名单中 4 个专业的 94 名考生数据（已排除 1 名强军计划考生）进行分析。&lt;/p&gt;
&lt;p&gt;经回归验证，总成绩计算公式为：&lt;strong&gt;总成绩 = 初试 × 0.5 + 复试 × 2.5&lt;/strong&gt;，即初试和复试各占总成绩的 50%。&lt;/p&gt;
&lt;p&gt;“仪器科学技术”（1 人）已合并入”仪器科学与技术”（16 人），共 17 人。&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;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;/td&gt;&lt;td&gt;30&lt;/td&gt;&lt;td&gt;376.7&lt;/td&gt;&lt;td&gt;81.7&lt;/td&gt;&lt;td&gt;392.6&lt;/td&gt;&lt;td&gt;48.0%&lt;/td&gt;&lt;td&gt;52.0%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;光电信息工程&lt;/td&gt;&lt;td&gt;31&lt;/td&gt;&lt;td&gt;400.5&lt;/td&gt;&lt;td&gt;81.0&lt;/td&gt;&lt;td&gt;402.8&lt;/td&gt;&lt;td&gt;49.7%&lt;/td&gt;&lt;td&gt;50.3%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;仪器科学与技术&lt;/td&gt;&lt;td&gt;17&lt;/td&gt;&lt;td&gt;353.6&lt;/td&gt;&lt;td&gt;78.2&lt;/td&gt;&lt;td&gt;372.4&lt;/td&gt;&lt;td&gt;47.5%&lt;/td&gt;&lt;td&gt;52.5%&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;仪器仪表工程&lt;/td&gt;&lt;td&gt;15&lt;/td&gt;&lt;td&gt;382.9&lt;/td&gt;&lt;td&gt;81.1&lt;/td&gt;&lt;td&gt;394.3&lt;/td&gt;&lt;td&gt;48.6%&lt;/td&gt;&lt;td&gt;51.4%&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&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;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/BIT/chart_1.png&quot; alt=&quot;图表1&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;要点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;光电信息工程初试分数跨度最大（372~439），复试分布也最分散&lt;/li&gt;
&lt;li&gt;光学工程和仪器仪表工程的初试和复试分布都相对集中&lt;/li&gt;
&lt;li&gt;仪器科学与技术的初试标准差最大（24.4 分），说明该专业录取考生的初试水平差异最为悬殊&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;二、成绩密度分布曲线（KDE）&lt;a href=&quot;#二成绩密度分布曲线kde&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;figure&gt;&lt;img src=&quot;/img/Note/BIT/chart_2.png&quot; alt=&quot;图表2&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;要点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;光电信息工程的初试成绩明显偏向高分段（集中在 390~410），形成了”高分密集”的特征&lt;/li&gt;
&lt;li&gt;仪器科学与技术的初试密度曲线偏向低分段（340~360 区间），峰值明显左移&lt;/li&gt;
&lt;li&gt;复试方面各专业分布较为接近，但仪器科学与技术的复试密度峰值也略低于其他专业&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;三、初试 vs 复试散点图&lt;a href=&quot;#三初试-vs-复试散点图&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;figure&gt;&lt;img src=&quot;/img/Note/BIT/chart_3.png&quot; alt=&quot;图表3&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;要点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;光电信息工程的考生散布在更高初试分数段（右侧），其中一位初试 439 分的考生极为突出&lt;/li&gt;
&lt;li&gt;仪器科学与技术则集中在左下方（初试相对较低）&lt;/li&gt;
&lt;li&gt;各专业的星号（均值点）显示初试和复试成绩之间并没有强烈的线性关系，说明复试成绩并非初试的简单”复制”&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;由于公式是 &lt;code&gt;初试×0.5 + 复试×2.5&lt;/code&gt;，初试满分 250、复试满分 250，权重相等。但实际录取考生的初试/复试比例因人而异。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/BIT/chart_4.png&quot; alt=&quot;图表4&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;要点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;所有专业的初试占比在 47.5%~49.7% 之间，复试占比 50.3%~52.5%，差异非常小&lt;/li&gt;
&lt;li&gt;仪器科学与技术的复试占比最高（52.5%），说明该专业录取考生的复试表现在总成绩中贡献更大——如果复试发挥好，在总排名中更有优势&lt;/li&gt;
&lt;li&gt;光电信息工程初试占比最高（49.7%），初试高分考生更占优势&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;将复试成绩×5 对齐到初试的 500 分制进行对比。虚线为各专业均值。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/BIT/chart_5.png&quot; alt=&quot;图表5&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;要点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;光学工程的初试分布呈近似正态，集中在 365~385 区间&lt;/li&gt;
&lt;li&gt;光电信息工程则明显右偏，高分考生占比大&lt;/li&gt;
&lt;li&gt;仪器科学与技术的初试分布最”扁平”，低分段和高分段都有人&lt;/li&gt;
&lt;li&gt;仪器仪表工程虽然人数最少，但初试集中在 370~400 区间，较为均匀&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;将初试成绩分段，对比各专业在不同分数段的人数分布。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/BIT/chart_6.png&quot; alt=&quot;图表6&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;要点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;390~410 分段是”黄金区间”，光电信息工程在此段人数最多&lt;/li&gt;
&lt;li&gt;410+高分段几乎只有光电信息工程&lt;/li&gt;
&lt;li&gt;仪器科学与技术主要集中在 330~370 的中低分段&lt;/li&gt;
&lt;li&gt;光学工程则均匀分布在 350~410 区间&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;综合初试均分、复试均分、总均分、成绩集中度、录取规模等维度进行归一化对比。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/BIT/chart_7.png&quot; alt=&quot;图表7&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&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;li&gt;仪器科学与技术各维度均处于较低水平，但录取人数（17 人）在四个专业中排第三&lt;/li&gt;
&lt;li&gt;仪器仪表工程的各项指标处于中间水平&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;横向条形图展示每位考生因复试表现导致的排名变化。绿色=复试后排名提升，红色=排名下降。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/BIT/chart_8.png&quot; alt=&quot;图表8&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;要点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;仪器科学与技术的排名变化幅度最大，有考生的排名提升或下降了 7-8 位，说明复试对该专业的最终录取排名影响最大&lt;/li&gt;
&lt;li&gt;光电信息工程的排名变化相对小，初试高分考生的”护城河”更深&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;九、初试排名 vs 最终排名变化&lt;a href=&quot;#九初试排名-vs-最终排名变化&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;figure&gt;&lt;img src=&quot;/img/Note/BIT/chart_9.png&quot; alt=&quot;图表9&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&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;h2&gt;十、复试翻盘率&lt;a href=&quot;#十复试翻盘率&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;定义”翻盘”为最终排名比初试排名提升 ≥ 3 名。翻盘率越高，说明复试对最终结果的影响越大。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/BIT/chart_10.png&quot; alt=&quot;图表10&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&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;h2&gt;十一、成绩离散度与竞争强度&lt;a href=&quot;#十一成绩离散度与竞争强度&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;变异系数(CV)衡量分数的相对分散程度；极差(最高-最低)反映录取考生的分差。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/BIT/chart_11.png&quot; alt=&quot;图表11&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;要点：&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;仪器科学与技术的初试变异系数和极差都最大（初试极差达 88 分），说明该专业录取门槛相对灵活，高低分差距大&lt;/li&gt;
&lt;li&gt;光电信息工程的复试极差较小（14.7 分），复试打分相对集中、区分度有限&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;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/BIT/chart_12.png&quot; alt=&quot;图表12&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&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;h3&gt;1. 初试与复试权重&lt;a href=&quot;#1-初试与复试权重&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;从公式上看，初试和复试各占 50%，但实际效果因专业而异：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;光电信息工程的初试均分最高（400.5），初试优势更难被复试翻盘&lt;/li&gt;
&lt;li&gt;仪器科学与技术初试均分最低（353.6），复试对排名的影响最大&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2. 光电信息工程：“初试为王”&lt;a href=&quot;#2-光电信息工程初试为王&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;该专业录取考生的初试分数段极高（均分 400.5），初试占比也最大（49.7%），且翻盘率最低。&lt;strong&gt;如果你初试能拿到 400+，在该专业的优势非常稳固。&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;3. 仪器科学与技术：“复试决胜”&lt;a href=&quot;#3-仪器科学与技术复试决胜&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;该专业初试均分最低但复试翻盘率最高，成绩分布最分散，说明复试发挥对最终录取至关重要。&lt;strong&gt;初试不理想但复试出色的考生有机会逆袭。&lt;/strong&gt;&lt;/p&gt;
&lt;h3&gt;4. 光学工程：“均衡稳定”&lt;a href=&quot;#4-光学工程均衡稳定&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;初试和复试分布都较为集中和均匀，没有明显的偏科特征，竞争相对公平和可预测。&lt;/p&gt;
&lt;h3&gt;5. 仪器仪表工程：“中间路线”&lt;a href=&quot;#5-仪器仪表工程中间路线&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;各项指标处于中等水平，初试集中度高（标准差 14.6），复试表现中等，整体波动较小。&lt;/p&gt;
&lt;h3&gt;6. 整体趋势&lt;a href=&quot;#6-整体趋势&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;四个专业的复试占比均在 50%~52.5%之间，说明复试成绩在实际录取中的权重略高于初试（因为复试满分 100×2.5=250，而大多数考生初试在 350-410 之间，×0.5 后只有 175-205 分，复试的边际影响力更大）。&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;本报告由 Python + matplotlib 自动生成&lt;/em&gt;&lt;/p&gt;</content:encoded><category>category:笔记</category><category>tag:数据分析</category><category>tag:考研</category><category>tag:录取分析</category></item><item><title>STM32N657X0H3Q Nucleo VSCode 调试配置记录</title><link>https://www.729dhs.site/post/stm32n657-nucleo-dev-log2</link><guid isPermaLink="false">stm32n657-nucleo-dev-log2</guid><description>STM32N657X0H3Q Nucleo 开发板 VSCode 调试配置记录，解决 LRUN 模式下无法调试的问题，包含 launch.json 正确配置方案及常见踩坑总结。</description><pubDate>Mon, 08 Jun 2026 03:39:51 GMT</pubDate><content:encoded>&lt;h1&gt;STM32N657X0H3Q Nucleo VSCode 调试配置记录&lt;a href=&quot;#stm32n657x0h3q-nucleo-vscode-调试配置记录&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;在前一篇文章中，我已经完成了程序的编译、签名以及使用 STM32 Programmer 下载的完整流程。LRUN 模式下可以分别单独下载 FSBL 和 Application，且均能正常运行。但有一个关键问题未能解决——&lt;strong&gt;无法在 VSCode 中进行源码级调试&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;调试时，程序自动断点停在一个库函数内部，位置在 &lt;code&gt;RETR=Map Memory&lt;/code&gt; 附近。按照 ST 社区论坛的教程，此处应该能够正常停在断点处并进入单步调试模式。但实际情况并非如此：断点命中后不久，调试器便与板子断开连接，调试会话自动退出。&lt;/p&gt;
&lt;p&gt;起初怀疑是安全域（TrustZone）配置导致的问题——是否因为 RIF 资源隔离配置不当，导致调试器无法在安全状态下进行调试？但后来逐步排查后排除了这个可能性。&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;launch.json&lt;/code&gt; 后发现，&lt;strong&gt;stldr 文件配置错误&lt;/strong&gt;是导致无法调试的根本原因。&lt;/p&gt;
&lt;p&gt;当前使用的是 &lt;strong&gt;New Clone 板（NUCLEO-N657X0-Q）&lt;/strong&gt;，但配置文件中误写为 DK 开发板（STM32N6570-DK）的对应设置。stldr（External Loader）文件是调试器与外部 Flash 通信的桥梁，加载器不匹配时调试器无法正确访问外部存储，导致连接失败。&lt;/p&gt;
&lt;h3&gt;launch.json 配置详解&lt;a href=&quot;#launchjson-配置详解&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;修正 stldr 配置后，又对整体配置进行了调整。以下是最终的完整配置及各字段说明：&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;    &quot;version&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;0.2.0&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &quot;configurations&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;            &quot;type&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;stlinkgdbtarget&quot;&lt;/span&gt;&lt;span&gt;,          &lt;/span&gt;&lt;span&gt;// 调试器类型：ST-Link GDB 目标&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            &quot;request&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;launch&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            &quot;name&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;NUCLEO-N657X0-Q Debug (FSBL + Appli)&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            &quot;origin&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;snippet&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            &quot;cwd&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;${workspaceFolder}&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            &quot;preBuild&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;${command:st-stm32-ide-debug-launch.build}&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;            &quot;runEntry&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;BOOT_Application&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;            // SVD 文件路径（请将路径前缀替换为 STM32CubeProgrammer 实际安装目录）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            &quot;svdPath&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;...&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;STM32CubeProgrammer&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;SVD&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;STM32N657.svd&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            &quot;imagesAndSymbols&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;                    // Application 镜像：symbol 用于源码映射，image 用于烧录&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                    &quot;symbolFileName&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;${workspaceFolder}/Appli/build/Template_FSBL_LRUN_Appli.elf&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                    &quot;imageFileName&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;${workspaceFolder}/Appli/build/Appli-trusted.elf&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;
&lt;span&gt;&lt;span&gt;                    // FSBL 镜像：两者都指向同一 ELF（FSBL 无需 separate trusted 文件）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                    &quot;symbolFileName&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;${workspaceFolder}/FSBL/build/Template_FSBL_LRUN_FSBL.elf&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                    &quot;imageFileName&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;${workspaceFolder}/FSBL/build/Template_FSBL_LRUN_FSBL.elf&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;
&lt;span&gt;&lt;span&gt;            &quot;serverExtLoader&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;                    // External Loader：NUCLEO-N657X0-Q 对应的 stldr 文件（New Clone 板，非 DK 板）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                    &quot;loader&quot;&lt;/span&gt;&lt;span&gt;: &lt;/span&gt;&lt;span&gt;&quot;...&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;STM32CubeProgrammer&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;bin&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;ExternalLoader&lt;/span&gt;&lt;span&gt;\\&lt;/span&gt;&lt;span&gt;MX25UM51245G_STM32N6570-NUCLEO.stldr&quot;&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                    &quot;initialize&quot;&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;span&gt;&lt;span&gt;            ]&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;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;blockquote&gt;
&lt;p&gt;&lt;strong&gt;路径说明&lt;/strong&gt;：上文中 &lt;code&gt;...\\STM32CubeProgrammer\\&lt;/code&gt; 表示 STM32CubeProgrammer 的安装目录，请替换为你电脑上的实际路径，例如 &lt;code&gt;C:\\Program Files\\STMicroelectronics\\STM32Cube\\STM32CubeProgrammer\\&lt;/code&gt; 或自行指定的目录。&lt;/p&gt;
&lt;/blockquote&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;&lt;code&gt;runEntry&lt;/code&gt;&lt;/td&gt;&lt;td&gt;指定调试器入口函数&lt;/td&gt;&lt;td&gt;NUCLEO-N657X0-Q 的 LRUN 模式需设为 &lt;code&gt;BOOT_Application&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;svdPath&lt;/code&gt;&lt;/td&gt;&lt;td&gt;SVD 文件路径，提供外设寄存器描述&lt;/td&gt;&lt;td&gt;路径指向 STM32CubeProgrammer 安装目录下的 SVD 文件夹&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;symbolFileName&lt;/code&gt;&lt;/td&gt;&lt;td&gt;ELF 符号文件，用于源码级调试&lt;/td&gt;&lt;td&gt;需与编译产物路径一致&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;imageFileName&lt;/code&gt;&lt;/td&gt;&lt;td&gt;烧录镜像文件&lt;/td&gt;&lt;td&gt;Appli 用 &lt;code&gt;Appli-trusted.elf&lt;/code&gt;（已签名），FSBL 直接用编译生成的 &lt;code&gt;.elf&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;serverExtLoader&lt;/code&gt;&lt;/td&gt;&lt;td&gt;外部 Flash 加载器配置&lt;/td&gt;&lt;td&gt;&lt;strong&gt;务必选择与板子匹配的 stldr 文件&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&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;FSBL 与 Appli 的 ELF 配置差异&lt;a href=&quot;#fsbl-与-appli-的-elf-配置差异&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FSBL 和 Application 的镜像配置有一个值得注意的区别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;FSBL&lt;/strong&gt;：&lt;code&gt;symbolFileName&lt;/code&gt; 和 &lt;code&gt;imageFileName&lt;/code&gt; 都指向同一个 &lt;code&gt;.elf&lt;/code&gt; 文件，因为 FSBL 直接使用编译生成的 ELF 进行签名和调试&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Application&lt;/strong&gt;：&lt;code&gt;symbolFileName&lt;/code&gt; 指向编译生成的 ELF（含调试符号），而 &lt;code&gt;imageFileName&lt;/code&gt; 指向 &lt;code&gt;Appli-trusted.elf&lt;/code&gt;（签名后的镜像）&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这是因为 Application 需要经过签名（添加 V2.3 Header）才能被 Boot ROM 或 FSBL 识别，而调试时需要的是符号未剥离的原始 ELF 文件来映射源码位置。&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;code&gt;.elf&lt;/code&gt; — 编译器直接生成的 ELF 文件，含调试符号&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-trusted.elf&lt;/code&gt; — 经签名工具处理后添加了 Header 的镜像文件&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-trusted.bin&lt;/code&gt; — 经签名工具处理后添加了 Header 的纯二进制文件&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Application 使用 &lt;code&gt;Appli-trusted.elf&lt;/code&gt; 作为镜像文件，而 FSBL 不需要单独生成 trusted 版本。&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;修正配置后，完整的 VSCode 调试流程如下：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;确保 BOOT1 = 2-3&lt;/strong&gt;（DEV 模式）&lt;/li&gt;
&lt;li&gt;在 VSCode 中选择 &lt;code&gt;NUCLEO-N657X0-Q Debug (FSBL + Appli)&lt;/code&gt; 配置&lt;/li&gt;
&lt;li&gt;在 Application 代码中设置断点&lt;/li&gt;
&lt;li&gt;按 F5 启动调试&lt;/li&gt;
&lt;li&gt;FSBL 自动运行 → 加载 Appli 到 SRAM → 跳转执行 → 断点命中&lt;/li&gt;
&lt;/ol&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;stldr 文件不匹配（DK 板 vs New Clone 板）&lt;/td&gt;&lt;td&gt;检查并修正 &lt;code&gt;serverExtLoader&lt;/code&gt; 中的 stldr 路径&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;断点停在库函数中后退出&lt;/td&gt;&lt;td&gt;安全域配置导致调试器被阻断&lt;/td&gt;&lt;td&gt;检查 RIF 配置中调试相关权限&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Appli-trusted.elf&lt;/code&gt; 找不到&lt;/td&gt;&lt;td&gt;编译后未正确生成签名镜像&lt;/td&gt;&lt;td&gt;检查 CMake POST_BUILD 签名脚本&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;symbolFileName&lt;/code&gt; 指向正确的 &lt;code&gt;.elf&lt;/code&gt; 文件&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;</content:encoded><category>category:笔记</category><category>category:STM32</category><category>tag:STM32</category><category>tag:STM32N6</category><category>tag:嵌入式</category></item><item><title>STM32N657X0H3Q Nucleo 开发板开发记录</title><link>https://www.729dhs.site/post/stm32n657-nucleo-dev-log</link><guid isPermaLink="false">stm32n657-nucleo-dev-log</guid><description>STM32N657X0H3Q Nucleo 开发板调试记录，涵盖 SRAM 调试、XSPI XIP 模式、FSBL Load &amp; Run 模式配置与签名烧录流程。</description><pubDate>Sat, 06 Jun 2026 16:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;STM32N657X0H3Q Nucleo 开发板开发记录&lt;a href=&quot;#stm32n657x0h3q-nucleo-开发板开发记录&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;这破板子真服了——又是什么 TrustZone、又是 FSBL、又是 OTP，怎么这么难……&lt;/p&gt;
&lt;/blockquote&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;第一次调试：SRAM 模式&lt;a href=&quot;#第一次调试sram-模式&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;第一次当然顺其自然，想着按照以往 F1 跟 F4 的经验，直接在 CubeMX 里面配置项目，然后加载到 VS Code 进行调试。不过神奇的是，&lt;strong&gt;其实是可以调试的&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;但是它运行不了，Reset 之后代码直接消失不见了。从现在来看应该是在调试的时候用的是 SRAM 模式，直接加载到 SRAM 之后进行的运行。好处是能直接看到结果，可以调试，但问题就是它其实完全没有记住代码。记住代码这个过程其实是需要让它记到 Flash 里面去配置这个 XSPI 的。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;踩坑&lt;/strong&gt;：NUCLEO-N657X0-Q &lt;strong&gt;没有内部 Flash&lt;/strong&gt;，代码必须存放在外部 XSPI Flash 中。调试模式下加载到 SRAM 后，Reset 一旦断电代码就没了，这就是为什么 Reset 后代码”消失”了。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;XSPI + XIP 模式尝试&lt;a href=&quot;#xspi--xip-模式尝试&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;XIP 模式意思就是 Execute In Place，直接在外部 Nor Flash 里面进行运行程序，也就是说 SRAM 其实是没有进行任何工作的。XSPI 的意思是这个板子、这个芯片它的一个特殊的 SPI 协议，它用于和外部这个 Nor Flash 进行通信，配置过程还挺复杂的。&lt;/p&gt;
&lt;p&gt;然后进行了 XSPI 的尝试，但是完全不能做，不知道是哪里出问题了，有源源不断的问题，下载代码和调试全都是报错。而且官方论坛这个帖子是根据 DK 版进行配置的，我不太清楚 DK 版跟 New Clone 板子是否有什么区别，所以还是放弃了。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;踩坑&lt;/strong&gt;：XIP 模式配置极其复杂，需要：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;配置 Memory-Mapped Mode，让 CPU 能直接总线访问外部 Flash&lt;/li&gt;
&lt;li&gt;外部 Flash 的 .stldr 加载器文件（STM32CubeProgrammer 需要加载正确的 External Loader）&lt;/li&gt;
&lt;li&gt;正确的 linker 脚本（&lt;code&gt;STM32N657XX_ROMxspi*.ld&lt;/code&gt;）&lt;/li&gt;
&lt;li&gt;签名时需要加上 &lt;code&gt;-align&lt;/code&gt; 参数&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;DK 版（开发套件）和 NUCLEO 板的配置可能有差异，官方教程按照 DK 版来，很多配置在 NUCLEO 板上不适用。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;LRUN 模式：成功&lt;a href=&quot;#lrun-模式成功&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;LRUN 模式就是 Load and Run，它是通过 FSBL 以及 Application 进行配合。FSBL 进行初始化，并把 Application 的代码转移到 SRAM。我的理解是，把 PC 指针最后在进入死循环之前就转移到了 Application。所以需要注意的是，&lt;strong&gt;死循环是不会执行的&lt;/strong&gt;。我把亮灯放到了死循环之前，进入 Application 之前。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/STM32/NucleoN657_1_1.png&quot; alt=&quot;alt text&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;然后倒是挺顺利的，直接编译烧录。编译完之后给它加签名，加签名之后直接各自烧录就可以了。理论上来说应该是先去烧录 FSBL，再去烧录 Application 的。不过实际上它板载的程序应该是 LRUN 模式，所以不管烧哪个进行替换其实都完全可以的。因为这只不过是 FSBL 的指针问题，Application 是各自的程序，其实没有什么区别。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/STM32/NucleoN657_1_2.png&quot; alt=&quot;alt text&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;还有需要注意的是，在烧录的时候需要选择外部存储设置，也就是那个 STLDR 文件，选择它这个板子对应的设置，然后才能进行烧录。我在烧录的时候它最后弹出来了内核被锁定，之前以及会弹出一个写入保护 PROTECTION，不太清楚是为什么。&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/STM32/NucleoN657_1_3.png&quot; alt=&quot;alt text&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;踩坑&lt;/strong&gt;：烧录时弹出”内核被锁定”（Core locked）或者”写入保护 PROTECTION”，通常是 Option Bytes 配置问题。可以尝试：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;按住 Reset 再烧录&lt;/li&gt;
&lt;li&gt;使用 Mass Erase 擦除整片芯片&lt;/li&gt;
&lt;li&gt;检查 BOOT 跳线是否正确设置（DEV 模式下 BOOT1 = 2-3）&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;另外，烧录前需要在 CubeProgrammer 中加载正确的 External Loader（.stldr 文件），否则无法识别外部 Flash。&lt;/p&gt;
&lt;/blockquote&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;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;：STM32N657X0H3QU&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;开发板&lt;/strong&gt;：NUCLEO-N657X0-Q (MB1940)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;架构&lt;/strong&gt;：ARM Cortex-M55 with Helium (MVE) + TrustZone&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;主频&lt;/strong&gt;：600 MHz&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flash&lt;/strong&gt;：&lt;strong&gt;无内部 Flash&lt;/strong&gt;，依赖外部 XSPI Nor Flash&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;RAM&lt;/strong&gt;：2MB AXISRAM (0x3400_0000 ~ 0x3420_0000)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;STM32N6 与以往 F1/F4 系列最大的区别在于：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;无内部 Flash&lt;/strong&gt;：代码必须存放在外部 XSPI Flash 中&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TrustZone&lt;/strong&gt;：安全世界与非安全世界隔离，需要正确配置 RIF&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;双域架构&lt;/strong&gt;：Secure 域和 Non-Secure 域分离&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OTP Fuses&lt;/strong&gt;：一次性可编程熔丝，用于配置高速模式&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FSBL 机制&lt;/strong&gt;：First Stage Boot Loader&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;2.2 LED 引脚&lt;a href=&quot;#22-led-引脚&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;LED 颜色&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;绿色 LED&lt;/td&gt;&lt;td&gt;PG.00 (LED_GREEN)&lt;/td&gt;&lt;td&gt;Appli 主循环控制&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;蓝色 LED&lt;/td&gt;&lt;td&gt;PG.08 (LED_BLUE)&lt;/td&gt;&lt;td&gt;Appli 主循环控制&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;红色 LED&lt;/td&gt;&lt;td&gt;PG.10 (LED_RED)&lt;/td&gt;&lt;td&gt;FSBL 调试指示&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;勘误&lt;/strong&gt;：之前笔记把 PG.08 写成黄色，实际是蓝色（LED_BLUE）。NUCLEO-N657X0-Q 板上丝印标注的颜色和 BSP 定义一致。 |&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;2.3 启动模式（Boot Pin）&lt;a href=&quot;#23-启动模式boot-pin&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;板上 Boot 引脚有 3 个位置（排针 1、2、3），通过跳线帽选择：&lt;/p&gt;
&lt;h4&gt;Boot 引脚配置&lt;a href=&quot;#boot-引脚配置&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;




















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;引脚&lt;/th&gt;&lt;th&gt;排针 1-2 短路&lt;/th&gt;&lt;th&gt;排针 2-3 短路&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;BOOT0&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;0（低电平）&lt;/td&gt;&lt;td&gt;1（高电平）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;BOOT1&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;0（低电平）&lt;/td&gt;&lt;td&gt;1（高电平）&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h4&gt;启动模式&lt;a href=&quot;#启动模式&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h4&gt;



































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;模式&lt;/th&gt;&lt;th&gt;BOOT0&lt;/th&gt;&lt;th&gt;BOOT1&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;DEV（调试）&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;任意&lt;/strong&gt;（0 或 1 都可以）&lt;/td&gt;&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt;（排针 2-3 短路）&lt;/td&gt;&lt;td&gt;IDE 加载程序到 RAM，可源码调试&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Boot from Flash&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;（排针 1-2 短路）&lt;/td&gt;&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt;（排针 1-2 短路）&lt;/td&gt;&lt;td&gt;从外部 XSPI Flash 启动，独立运行&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Reserved&lt;/strong&gt;&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;&lt;strong&gt;System ROM&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;0&lt;/td&gt;&lt;td&gt;芯片内置 ROM（一般不用）&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：DEV 模式下 BOOT0 任意，&lt;strong&gt;只要求 BOOT1 = 1&lt;/strong&gt;（跳线帽接 2-3）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;2.4 Boot ROM 启动顺序&lt;a href=&quot;#24-boot-rom-启动顺序&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;STM32N6 芯片上电后，Boot ROM 按以下顺序查找可启动代码：&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;1&lt;/td&gt;&lt;td&gt;&lt;code&gt;0x7000 0000&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;首选&lt;/strong&gt;：外部 XSPI Flash（FSBL 或带 header 的程序）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;内部 ROM&lt;/td&gt;&lt;td&gt;芯片出厂自带的 BootLoader（如有）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;RAM&lt;/td&gt;&lt;td&gt;如果其他地方都没有，尝试从 RAM 启动&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;注意&lt;/strong&gt;：地址 &lt;code&gt;0x7000 0000&lt;/code&gt; 是外部 Flash 的&lt;strong&gt;镜像起始地址&lt;/strong&gt;，实际物理 Flash 通过 XSPI 接口访问。带签名的程序放在这里，Boot ROM 才能识别并加载。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;2.5 名词解释&lt;a href=&quot;#25-名词解释&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;LRUN&lt;/td&gt;&lt;td&gt;Load &amp;amp; Run&lt;/td&gt;&lt;td&gt;代码从外部 Flash 复制到内部 RAM 后执行&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;XIP&lt;/td&gt;&lt;td&gt;eXecute In Place&lt;/td&gt;&lt;td&gt;代码直接在外部 Flash 原地执行，不复制到 RAM&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;XSPI&lt;/td&gt;&lt;td&gt;eXtended SPI&lt;/td&gt;&lt;td&gt;ST 的串行外设接口协议，用于与外部 Flash 通信&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;FSBL&lt;/td&gt;&lt;td&gt;First Stage Boot Loader&lt;/td&gt;&lt;td&gt;第一阶段引导加载程序&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;OTP&lt;/td&gt;&lt;td&gt;One-Time Programmable&lt;/td&gt;&lt;td&gt;一次性可编程熔丝&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;2.6 链接文件命名规则&lt;a href=&quot;#26-链接文件命名规则&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;格式：&lt;code&gt;ROM在哪里_RUN_RAM在哪里&lt;/code&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;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;STM32N657XX_LRUN&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Appli 放在内部 RAM（由 FSBL 加载）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;STM32N657XX_ROMxspi1&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Appli 在外部 XSPI1 Flash，原地执行&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;STM32N657XX_ROMxspi2&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Appli 在外部 XSPI2 Flash，原地执行&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;STM32N657XX_LRUN_RAMxspi2&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Appli 放 RAM，但从 XSPI2 的 Flash 加载&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;STM32N657XX_ROMxspi1_RAMxspi3&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Appli 在 XSPI1，RAM 用 XSPI3&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;三、FSBL Load &amp;amp; Run 模式&lt;a href=&quot;#三fsbl-load--run-模式&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;p&gt;FSBL LRUN 模式将系统分为两个独立的子项目：&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;strong&gt;FSBL&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;初始化 OTP、配置 XSPI2、读取并复制 Appli、跳转执行&lt;/td&gt;&lt;td&gt;内部 RAM (0x3400_0000)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Appli&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;用户应用程序，控制 LED 等外设&lt;/td&gt;&lt;td&gt;内部 RAM (0x3400_0400)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;3.2 FSBL 代码分析&lt;a href=&quot;#32-fsbl-代码分析&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FSBL 的核心代码在 &lt;code&gt;FSBL/Src/main.c&lt;/code&gt;：&lt;/p&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;    SCB_EnableICache&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    SCB_EnableDCache&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;  // 配置 600MHz 系统时钟&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // OTP 配置（第一次必须）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#ifndef&lt;/span&gt;&lt;span&gt; NO_OTP_FUSE&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;OTP_Config&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;        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;#endif&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; // 初始化 LED (PG.10)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    MX_XSPI2_Init&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span&gt; // 初始化 XSPI2 接口&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    MX_EXTMEM_Init&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    BOOT_Application&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span&gt;   // 复制 Appli 到 RAM 并跳转&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;__NOP&lt;/span&gt;&lt;span&gt;(); }&lt;/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;FSBL 执行流程&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;使能缓存&lt;/strong&gt;：ICache + DCache&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;配置时钟&lt;/strong&gt;：600MHz 主频&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OTP 配置&lt;/strong&gt;：设置 VDDIO3_HSLV 等熔丝（仅第一次需要）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;初始化 GPIO&lt;/strong&gt;：配置 LED 引脚 PG.10（调试用）&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;初始化 XSPI2&lt;/strong&gt;：与外部 Flash 通信&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;初始化外部存储&lt;/strong&gt;：&lt;code&gt;MX_EXTMEM_Init()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;跳转执行&lt;/strong&gt;：&lt;code&gt;BOOT_Application()&lt;/code&gt; 复制 Appli 到 RAM 并跳转&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;3.3 OTP 配置详解&lt;a href=&quot;#33-otp-配置详解&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;OTP_Config()&lt;/code&gt; 函数配置 VDDIO3_HSLV 熔丝位：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;#define&lt;/span&gt;&lt;span&gt; BSEC_HW_CONFIG_ID&lt;/span&gt;&lt;span&gt;    124&lt;/span&gt;&lt;span&gt;U&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;#define&lt;/span&gt;&lt;span&gt; BSEC_HWS_HSLV_VDDIO3&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;U&amp;lt;&amp;lt;&lt;/span&gt;&lt;span&gt;15&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;  // VDDIO3 高速模式使能&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;注意&lt;/strong&gt;：OTP 熔丝&lt;strong&gt;一次写入，不可逆&lt;/strong&gt;，配置前请确认。第一次烧录时需要禁用 &lt;code&gt;NO_OTP_FUSE&lt;/code&gt; 宏。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;3.4 Appli 代码分析&lt;a href=&quot;#34-appli-代码分析&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Appli 的代码在 &lt;code&gt;Appli/Src/main.c&lt;/code&gt;：&lt;/p&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;    SystemCoreClockUpdate&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    MPU_Config&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    SCB_EnableICache&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    SCB_EnableDCache&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;    BSP_LED_Init&lt;/span&gt;&lt;span&gt;(LED_GREEN);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    SystemIsolation_Config&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span&gt;  // 配置 RIF 资源隔离&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;
&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;        HAL_GPIO_TogglePin&lt;/span&gt;&lt;span&gt;(GPIOG, GPIO_PIN_0);&lt;/span&gt;&lt;span&gt;  // 绿色 LED&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        HAL_GPIO_TogglePin&lt;/span&gt;&lt;span&gt;(GPIOG, GPIO_PIN_8);&lt;/span&gt;&lt;span&gt;  // 蓝色 LED&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        HAL_Delay&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;750&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;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;Appli 中的 &lt;code&gt;SystemIsolation_Config()&lt;/code&gt; 配置 TrustZone 资源隔离：&lt;/p&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; SystemIsolation_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;    __HAL_RCC_RIFSC_CLK_ENABLE&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    HAL_GPIO_ConfigPinAttributes&lt;/span&gt;&lt;span&gt;(GPIOG, GPIO_PIN_0, GPIO_PIN_SEC&lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt;GPIO_PIN_NPRIV);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    HAL_GPIO_ConfigPinAttributes&lt;/span&gt;&lt;span&gt;(GPIOG, GPIO_PIN_8, GPIO_PIN_SEC&lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt;GPIO_PIN_NPRIV);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    HAL_GPIO_ConfigPinAttributes&lt;/span&gt;&lt;span&gt;(GPIOG, GPIO_PIN_10, GPIO_PIN_SEC&lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt;GPIO_PIN_NPRIV);&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.5 跳过 FSBL 直接运行 Appli&lt;a href=&quot;#35-跳过-fsbl-直接运行-appli&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;如果满足以下条件之一，可以&lt;strong&gt;跳过 FSBL 直接烧录 Appli&lt;/strong&gt;：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OTP 已经配置好（VDDIO3_HSLV 已设置）&lt;/li&gt;
&lt;li&gt;芯片出厂自带 FSBL 在 &lt;code&gt;0x7000 0000&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Boot ROM 支持直接从 &lt;code&gt;0x7010 0000&lt;/code&gt; 加载&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;操作步骤&lt;/strong&gt;：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;签名 Appli：&lt;code&gt;Appli-trusted.bin&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;烧录到 &lt;code&gt;0x7010 0000&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Reset，芯片会从外部 Flash 启动&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;踩坑&lt;/strong&gt;：如果芯片没有自带 FSBL 且 Boot ROM 不支持直接加载，跳过 FSBL 会导致芯片找不到可执行代码而停住。&lt;/p&gt;
&lt;/blockquote&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;4.1 工具链&lt;a href=&quot;#41-工具链&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;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;GCC ARM Compiler&lt;/td&gt;&lt;td&gt;&lt;code&gt;C:\Users\Q\AppData\Local\stm32cube\bundles\gnu-tools-for-stm32\14.3.1+st.2&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;STM32Cube Firmware&lt;/td&gt;&lt;td&gt;&lt;code&gt;C:\Users\Q\STM32Cube\Repository\STM32Cube_FW_N6_V1.3.0\&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Signing Tool&lt;/td&gt;&lt;td&gt;&lt;code&gt;C:\APPS\Programmer\bin\STM32_SigningTool_CLI.exe&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&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;cd&lt;/span&gt;&lt;span&gt; build/Debug&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;cube-cmake&lt;/span&gt;&lt;span&gt; --build&lt;/span&gt;&lt;span&gt; .&lt;/span&gt;&lt;span&gt; --target&lt;/span&gt;&lt;span&gt; clean&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;cube-cmake&lt;/span&gt;&lt;span&gt; --build&lt;/span&gt;&lt;span&gt; .&lt;/span&gt;&lt;span&gt; --target&lt;/span&gt;&lt;span&gt; all&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4.3 CMake POST_BUILD 配置（自动签名）&lt;a href=&quot;#43-cmake-post_build-配置自动签名&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;find_program&lt;/span&gt;&lt;span&gt;(OBJCOPY arm-none-eabi-objcopy &lt;/span&gt;&lt;span&gt;PATHS&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    C:/Users/Q/AppData/Local/stm32cube/bundles/gnu-tools-for-stm32/14.3.1+st.2/bin&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    NO_DEFAULT_PATH&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;add_custom_command&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;TARGET&lt;/span&gt;&lt;span&gt; ${CMAKE_PROJECT_NAME}&lt;/span&gt;&lt;span&gt; POST_BUILD&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    COMMAND&lt;/span&gt;&lt;span&gt; ${OBJCOPY}&lt;/span&gt;&lt;span&gt; -O binary $&amp;lt;TARGET_FILE:&lt;/span&gt;&lt;span&gt;${CMAKE_PROJECT_NAME}&lt;/span&gt;&lt;span&gt;&amp;gt; &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            ${CMAKE_BINARY_DIR}&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;${CMAKE_PROJECT_NAME}&lt;/span&gt;&lt;span&gt;.bin&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    COMMENT&lt;/span&gt;&lt;span&gt; &quot;Generating binary&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;add_custom_command&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;TARGET&lt;/span&gt;&lt;span&gt; ${CMAKE_PROJECT_NAME}&lt;/span&gt;&lt;span&gt; POST_BUILD&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    COMMAND&lt;/span&gt;&lt;span&gt; ${OBJCOPY}&lt;/span&gt;&lt;span&gt; -O ihex $&amp;lt;TARGET_FILE:&lt;/span&gt;&lt;span&gt;${CMAKE_PROJECT_NAME}&lt;/span&gt;&lt;span&gt;&amp;gt; &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            ${CMAKE_BINARY_DIR}&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;${CMAKE_PROJECT_NAME}&lt;/span&gt;&lt;span&gt;.hex&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    COMMENT&lt;/span&gt;&lt;span&gt; &quot;Generating HEX&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;# 自动签名（编译后自动执行，无需手动签名）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;find_program&lt;/span&gt;&lt;span&gt;(SIGNING_TOOL C:/APPS/Programmer/bin/STM32_SigningTool_CLI.exe)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;add_custom_command&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;TARGET&lt;/span&gt;&lt;span&gt; ${CMAKE_PROJECT_NAME}&lt;/span&gt;&lt;span&gt; POST_BUILD&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    COMMAND&lt;/span&gt;&lt;span&gt; ${SIGNING_TOOL}&lt;/span&gt;&lt;span&gt; -bin &lt;/span&gt;&lt;span&gt;${CMAKE_BINARY_DIR}&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;${CMAKE_PROJECT_NAME}&lt;/span&gt;&lt;span&gt;.bin &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            -nk -of 0x80000000 -t fsbl&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            -o &lt;/span&gt;&lt;span&gt;${CMAKE_BINARY_DIR}&lt;/span&gt;&lt;span&gt;/&lt;/span&gt;&lt;span&gt;${CMAKE_PROJECT_NAME}&lt;/span&gt;&lt;span&gt;-trusted.bin &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            -hv 2.3 -align -s&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    COMMENT&lt;/span&gt;&lt;span&gt; &quot;Signing ${CMAKE_PROJECT_NAME}.bin&quot;&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;4.4 NO_OTP_FUSE 宏配置&lt;a href=&quot;#44-no_otp_fuse-宏配置&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FSBL 的编译宏在 &lt;code&gt;FSBL/mx-generated.cmake&lt;/code&gt; 中定义：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;set&lt;/span&gt;&lt;span&gt;(MX_Defines_Syms &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    USE_HAL_DRIVER &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    STM32N657xx &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    NO_OTP_FUSE &lt;/span&gt;&lt;span&gt;# 注释掉此行以启用 OTP 配置&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;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;code&gt;NO_OTP_FUSE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;第一次烧录时必须，FSBL 会自动配置 OTP 熔丝&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;启用 &lt;code&gt;NO_OTP_FUSE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;后续开发使用，跳过 OTP 配置步骤&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;4.5 编译产物&lt;a href=&quot;#45-编译产物&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;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;FSBL.elf / .bin / .hex&lt;/td&gt;&lt;td&gt;&lt;code&gt;FSBL/build/Template_FSBL_LRUN_FSBL.*&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Appli.elf / .bin / .hex&lt;/td&gt;&lt;td&gt;&lt;code&gt;Appli/build/Template_FSBL_LRUN_Appli.*&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;FSBL-trusted.bin&lt;/td&gt;&lt;td&gt;&lt;code&gt;FSBL/build/Template_FSBL_LRUN_FSBL-trusted.bin&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Appli-trusted.bin&lt;/td&gt;&lt;td&gt;&lt;code&gt;Appli/build/Template_FSBL_LRUN_Appli-trusted.bin&lt;/code&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;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;STM32N6 的外部 Flash 存储了关键固件，芯片的 Boot ROM 只会加载&lt;strong&gt;带有正确签名 Header&lt;/strong&gt; 的镜像。签名工具为 .bin 文件添加一个 V2.3 格式的头部。&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;# Appli 签名&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt; &quot;C:\APPS\Programmer\bin\STM32_SigningTool_CLI.exe&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;bin &lt;/span&gt;&lt;span&gt;&quot;C:\APPS\COPRO\MCU\CUBEMX\N6_MX\Template_FSBL_LRUN\Appli\build\Template_FSBL_LRUN_Appli.bin&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;nk &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;of &lt;/span&gt;&lt;span&gt;0x80000000&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;span&gt;t fsbl &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    -&lt;/span&gt;&lt;span&gt;o &lt;/span&gt;&lt;span&gt;&quot;C:\APPS\COPRO\MCU\CUBEMX\N6_MX\Template_FSBL_LRUN\Appli\build\Template_FSBL_LRUN_Appli-trusted.bin&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;hv &lt;/span&gt;&lt;span&gt;2.3&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;span&gt;align &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;# FSBL 签名&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt; &quot;C:\APPS\Programmer\bin\STM32_SigningTool_CLI.exe&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;bin &lt;/span&gt;&lt;span&gt;&quot;C:\APPS\COPRO\MCU\CUBEMX\N6_MX\Template_FSBL_LRUN\FSBL\build\Template_FSBL_LRUN_FSBL.bin&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;nk &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;of &lt;/span&gt;&lt;span&gt;0x80000000&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;span&gt;t fsbl &lt;/span&gt;&lt;span&gt;`&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    -&lt;/span&gt;&lt;span&gt;o &lt;/span&gt;&lt;span&gt;&quot;C:\APPS\COPRO\MCU\CUBEMX\N6_MX\Template_FSBL_LRUN\FSBL\build\Template_FSBL_LRUN_FSBL-trusted.bin&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;hv &lt;/span&gt;&lt;span&gt;2.3&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;span&gt;align &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt;s&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&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;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;code&gt;-bin&lt;/code&gt;&lt;/td&gt;&lt;td&gt;输入的 .bin 文件路径&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-nk&lt;/code&gt;&lt;/td&gt;&lt;td&gt;No Key，开发模式，不做真正签名验证&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-of 0x80000000&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Option flags 地址偏移&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-t fsbl&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Binary type：FSBL 类型&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-hv 2.3&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Header version（N6 必须用 2.3）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-align&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;必须加&lt;/strong&gt;，payload 对齐到 0x400&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;-s&lt;/code&gt;&lt;/td&gt;&lt;td&gt;静默模式，不弹出覆盖确认提示&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&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;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;code&gt;Appli-trusted.bin&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;0x7010_0000&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;FSBL-trusted.bin&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;0x7000_0000&lt;/code&gt;（可选）&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&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;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;FSBL 初始化&lt;/td&gt;&lt;td&gt;红灯（PG.10）闪烁 3 次&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;跳转 Appli&lt;/td&gt;&lt;td&gt;绿灯（PG.00）和蓝灯（PG.08）交替闪烁&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;5.6 External Loader (.stldr)&lt;a href=&quot;#56-external-loader-stldr&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;烧录外部 XSPI Flash 时，CubeProgrammer 需要加载对应的 External Loader 文件：&lt;/p&gt;













&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;开发板&lt;/th&gt;&lt;th&gt;Loader 文件&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;NUCLEO-N657X0-Q&lt;/td&gt;&lt;td&gt;&lt;code&gt;NUCLEO_N657X0_Q.stldr&lt;/code&gt;（通常在 CubeProgrammer 安装目录下）&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;位置&lt;/strong&gt;：通常在 &lt;code&gt;C:\Program Files\STMicroelectronics\STM32Cube\STM32CubeProgrammer\ExternalLoader\&lt;/code&gt; 下。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;踩坑&lt;/strong&gt;：如果不加载正确的 .stldr 文件，CubeProgrammer 无法识别外部 Flash，烧录时会报错或无法写入。&lt;/p&gt;
&lt;/blockquote&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;6.1 DEV 模式调试（推荐）&lt;a href=&quot;#61-dev-模式调试推荐&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;设置 BOOT1 = 2-3（DEV 模式）&lt;/li&gt;
&lt;li&gt;IDE 加载 &lt;code&gt;FSBL/build/Template_FSBL_LRUN_FSBL.elf&lt;/code&gt; 到 RAM&lt;/li&gt;
&lt;li&gt;在 Appli 代码打断点&lt;/li&gt;
&lt;li&gt;Debug/Run&lt;/li&gt;
&lt;li&gt;FSBL 运行 → 加载 Appli → 断点生效&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;6.2 Flash 模式&lt;a href=&quot;#62-flash-模式&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;无法源码调试，只能靠 LED / UART / ITM。&lt;/p&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;Template_FSBL_LRUN/&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── CLAUDE.md              # 项目说明文档&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── SKILL.md              # 技能文档&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── README.md              # 官方说明&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── Template_FSBL_LRUN.ioc # CubeMX 配置文件&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── FSBL/                  # FSBL 子项目&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         # FSBL 主程序&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   │   ├── extmem.c       # 外部存储初始化&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;│   │   └── extmem.h&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── mx-generated.cmake # 编译宏定义&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── CMakeLists.txt&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   └── STM32N657XX_LRUN.ld&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── Appli/                 # Appli 子项目&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 # Appli 主程序&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;│   │   └── stm32n6xx_nucleo_conf.h&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── mx-generated.cmake&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── CMakeLists.txt&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   └── STM32N657XX_LRUN.ld&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── Drivers/               # HAL 驱动（项目内）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── Secure_nsclib/          # 安全非安全调用库&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── gcc-arm-none-eabi.cmake # 工具链配置&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;└── mx-generated.cmake       # 主 CMake 配置&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;ST 官方社区帖子&lt;a href=&quot;#st-官方社区帖子&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://community.st.com/t5/stm32-mcus/how-to-create-an-stm32n6-fsbl-load-and-run/ta-p/768206&quot;&gt;How to create an STM32N6 FSBL Load and Run&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://community.st.com/t5/stm32cubeide-mcus/nucleo-n657x0-q-unable-to-upload-code/m-p/876582&quot;&gt;Nucleo-N657X0-Q unable to upload code&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://community.st.com/t5/stm32cubeide-mcus/debugging-program-in-external-flash-xip-mode-stm32n6/m-p/794285&quot;&gt;Debugging program in external flash XIP mode STM32N6&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://community.st.com/t5/stm32-mcus/how-to-debug-stm32n6-using-stm32cubeide/tac-p/898644&quot;&gt;How to debug STM32N6 using STM32CubeIDE&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://community.st.com/t5/stm32-mcus/how-to-execute-code-from-the-external-serial-nor-using-the/ta-p/771048&quot;&gt;How to execute code from external serial NOR&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://community.st.com/t5/stm32-mcus/how-to-build-an-ai-application-from-scratch-on-the-nucleo-n657x0/ta-p/828502&quot;&gt;How to build an AI application from scratch on the Nucleo-N657X0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://community.st.com/t5/stm32-mcus-embedded-software/stm32n6570-dk-lrun-project-does-not-boot/m-p/874078&quot;&gt;STM32N6570-DK LRUN project does not boot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://community.st.com/t5/stm32-mcus/how-to-build-an-ai-application-from-scratch-on-the-stm32n6570-dk/ta-p/825591&quot;&gt;How to build an AI application from scratch on the STM32N6570-DK&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;ST 官方 PDF&lt;a href=&quot;#st-官方-pdf&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;rm0486 — STM32N657xx ARM-based 32-bit MCUs&lt;/li&gt;
&lt;li&gt;um3234 — How to proceed with Boot ROM on STM32N6 MCUs&lt;/li&gt;
&lt;li&gt;an6265 — Getting started with STM32N6 MCUs in STM32CubeIDE&lt;/li&gt;
&lt;li&gt;an5967 — Getting started with hardware development for STM32N6 MCUs&lt;/li&gt;
&lt;li&gt;um3249 — Getting started with STM32CubeN6 for STM32N6 series&lt;/li&gt;
&lt;li&gt;pm0273 — STM32 Cortex-M55 MCUs Programming Manual&lt;/li&gt;
&lt;li&gt;Nucleo-N657X0-Q 原理图 (en.mb1940-n657x0q-c02-schematic)&lt;/li&gt;
&lt;li&gt;um3417 — STM32N6 Nucleo144 board MB1940&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;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;Option Bytes 锁定&lt;/td&gt;&lt;td&gt;按住 Reset 再烧录，或 Mass Erase&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;烧录报错”写入保护”&lt;/td&gt;&lt;td&gt;读保护 RDP 开启&lt;/td&gt;&lt;td&gt;使用 Mass Erase 擦除&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Flash 模式不运行&lt;/td&gt;&lt;td&gt;没有 &lt;code&gt;-align&lt;/code&gt; 签名&lt;/td&gt;&lt;td&gt;重新签名，加 &lt;code&gt;-align&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Flash 模式不运行&lt;/td&gt;&lt;td&gt;OTP 未配置&lt;/td&gt;&lt;td&gt;第一次禁用 NO_OTP_FUSE，让 FSBL 配置 OTP&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;芯片无响应&lt;/td&gt;&lt;td&gt;调试器断开&lt;/td&gt;&lt;td&gt;按 Reset，重新连接&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;调试时断点不生效&lt;/td&gt;&lt;td&gt;用了 Flash 模式&lt;/td&gt;&lt;td&gt;切回 DEV 模式，BOOT1=2-3&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;编译后无 .bin 文件&lt;/td&gt;&lt;td&gt;CMakeLists.txt 缺少 post-build&lt;/td&gt;&lt;td&gt;添加 objcopy 命令&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;签名报”binary not found”&lt;/td&gt;&lt;td&gt;PowerShell 引号问题&lt;/td&gt;&lt;td&gt;用 &lt;code&gt;&amp;amp; &quot;...&quot;&lt;/code&gt; 或在 CMD 里运行&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;</content:encoded><category>category:笔记</category><category>category:STM32</category><category>tag:STM32</category><category>tag:STM32N6</category><category>tag:嵌入式</category><category>tag:调试</category></item><item><title>STM32 SimpleFOC 位置伺服：从零到稳，2个Hard Bug的排查与修复全记录</title><link>https://www.729dhs.site/post/stm32-simplefoc-debug-journal</link><guid isPermaLink="false">stm32-simplefoc-debug-journal</guid><description>STM32F103 + SimpleFOC Mini + AS5600 构建位置伺服系统的完整过程。从 uint16_t 整型溢出到 PID Reset 瞬态冲击，逐个记录排查过程与修复方案。</description><pubDate>Mon, 01 Jun 2026 02:30:00 GMT</pubDate><content:encoded>&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;用 STM32F103C8T6 (Blue Pill) 从零搭建一个 FOC 位置伺服系统，驱动 2804 云台电机。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;这套系统的”从零”不是从 SimpleFOC 库开始——而是从 CubeMX 生成的 HAL 代码开始，手写 FOC 核心算法、PID 控制器、编码器驱动、串口命令解析。整个开发周期约两周，其中&lt;strong&gt;调试占了 80% 的时间&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;最终效果：电机锁位稳如磐石，推两圈松手原路倒两圈回来，PID 参数可在线调节无瞬态冲击。而这背后，是 2 个真实 bug 的定位与修复——以及几个”以为是根因”的误报记录。&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;STM32F103C8T6 (72MHz)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── TIM1 CH1/CH2/CH3 (PA8/PA9/PA10) → SimpleFOC Mini IN1/IN2/IN3&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── PA11 GPIO OUT → SimpleFOC Mini ENABLE&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── I2C1 PB8(SCL) / PB9(SDA) → AS5600 磁编码器 (0x36)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── USART1 PB6(TX) / PB7(RX) → USB-TTL (115200 8N1)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;└── TIM2 (1098Hz 中断) → 控制循环节拍&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MCU&lt;/strong&gt;: STM32F103C8T6, 72MHz, 64KB Flash, 20KB RAM&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;驱动板&lt;/strong&gt;: SimpleFOC Mini (3 路半桥)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;编码器&lt;/strong&gt;: AS5600 12-bit 磁编码器 (I2C 接口)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;电机&lt;/strong&gt;: 2804 云台电机, 12 槽 14 极 (7 极对), 低内阻&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;main loop (110Hz)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  ├─ TIM2 中断 → foc_tick 标志&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  ├─ 传感器读取 → AS5600 (软 I2C)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  ├─ 角度展开 → 单圈绝对值 → 累计角度&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  ├─ PID 控制 → D-on-measurement + 低通滤波&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  ├─ SVPWM → 三相正弦波 (中心对齐 PWM)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  └─ UART 命令解析 → ? T90 Kp0.1 ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;二、误报：硬件 I2C 卡死？&lt;a href=&quot;#二误报硬件-i2c-卡死&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;p&gt;电机正常运行 30~60 秒后突然”失力”——编码器读数冻结在某一个值，用手转电机完全无回正力矩，串口自动打印也停了。断电重插恢复，运行一段时间又复现。&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;code&gt;D&lt;/code&gt; 命令（编码器诊断）在某次故障中读出了和 &lt;code&gt;?&lt;/code&gt; 状态命令&lt;strong&gt;不同的值&lt;/strong&gt;——&lt;code&gt;?&lt;/code&gt; 报 Raw=1445, &lt;code&gt;D&lt;/code&gt; 报 Raw=4030。排除编码器硬件故障。&lt;/li&gt;
&lt;li&gt;I2C Err 始终为 0——HAL 没有报错，但返回的是旧寄存器值，说明 I2C 外设可能进入了”假成功”状态。&lt;/li&gt;
&lt;li&gt;查阅 STM32F103 Errata：&lt;strong&gt;I2C 外设在特定总线时序下会卡死在 BUSY 状态&lt;/strong&gt;，软件无法通过正常方式恢复，只能复位外设。&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// 检测到读数连续 100 次不变时，尝试复位 I2C 外设&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;__HAL_RCC_I2C1_FORCE_RESET&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;__HAL_RCC_I2C1_RELEASE_RESET&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;HAL_I2C_Init&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;hi2c1&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;p&gt;改完软 I2C 之后，问题依然存在。后续发现真正的根因是 &lt;strong&gt;uint16_t tick 溢出&lt;/strong&gt;，改了之后就稳定了。软件 I2C 的改动留下了（更可靠），但 I2C 本身&lt;strong&gt;不是这个症状的根因&lt;/strong&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;教训&lt;/strong&gt;: 一个症状可能有多个”嫌疑人”，改了 A 不代表修好了。当无法确认根因时，先找最直接的可重现线索（时间规律）。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;三、误报：PID 正反馈？&lt;a href=&quot;#三误报pid-正反馈&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;现象&lt;a href=&quot;#现象-1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;上电后电机不锁位，持续旋转。发 &lt;code&gt;T90&lt;/code&gt; 后电机加速跑而不是停下来。&lt;/p&gt;
&lt;h3&gt;排查过程&lt;a href=&quot;#排查过程-1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;检查 PID 的 setpoint/measurement 传参——逻辑看起来可能有问题。&lt;/p&gt;
&lt;h3&gt;结果&lt;a href=&quot;#结果-1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;实际检查代码后发现 &lt;strong&gt;PID 符号传参本身没有反转&lt;/strong&gt;，这并不是真正的 bug。症状的真正原因同样是 uint16_t tick 溢出——控制循环根本没在跑。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;教训&lt;/strong&gt;: 在没有 trace 工具的情况下，容易把”没跑”当成”跑错了”。先确认代码是否真的在运行，再分析运行时的行为。&lt;/p&gt;
&lt;/blockquote&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;现象&lt;a href=&quot;#现象-2&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;电机每隔几十秒”突然死机”——自动打印停，电机吸附在磁极位，串口命令也没反应。&lt;/p&gt;
&lt;h3&gt;排查过程&lt;a href=&quot;#排查过程-2&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;检查栈大小：&lt;code&gt;STM32F103XX_FLASH.ld&lt;/code&gt; 中 &lt;code&gt;_Min_Stack_Size = 0x400&lt;/code&gt;（仅 1KB）&lt;/li&gt;
&lt;li&gt;&lt;code&gt;snprintf&lt;/code&gt; + &lt;code&gt;%f&lt;/code&gt; 会拉入 &lt;code&gt;_printf_float&lt;/code&gt;，单条调用链栈消耗 &amp;gt;700 字节&lt;/li&gt;
&lt;li&gt;尝试扩栈到 2KB + 大 buf 改 static&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;结果&lt;a href=&quot;#结果-2&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;改了之后问题依然存在。真正的根因依然是 uint16_t tick 溢出。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;教训&lt;/strong&gt;: 嵌入式里 &lt;code&gt;snprintf&lt;/code&gt; + &lt;code&gt;%f&lt;/code&gt; 确实吃栈，但这题里不是它干的。猜测 + 修 + 验证，而不是修完没效果还接着信。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;五、Bug #1 — uint16_t Tick 溢出 + C 整型提升陷阱&lt;a href=&quot;#五bug-1--uint16_t-tick-溢出--c-整型提升陷阱&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;这是真正解决问题的那个 bug。改了之后系统稳定运行。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;现象&lt;a href=&quot;#现象-3&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;电机每隔约 60 秒就”卡死”——自动打印停，电机不响应，但串口命令&lt;strong&gt;还能处理&lt;/strong&gt;。观察到 tick_count 从 65535 跳回 0（uint16_t 溢出），和故障时间点完全吻合。&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;strong&gt;C 语言的整型提升规则（Integer Promotion）&lt;/strong&gt; 导致的隐蔽 bug：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;volatile&lt;/span&gt;&lt;span&gt; uint16_t&lt;/span&gt;&lt;span&gt; tick_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; last_ctrl_tick &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 65530&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&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; (tick_count &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; last_ctrl_tick &lt;/span&gt;&lt;span&gt;&amp;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;// uint16_t - uint16_t → 提升为 signed int (32-bit)&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;int&lt;/span&gt;&lt;span&gt;)tick_count &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;)last_ctrl_tick &lt;/span&gt;&lt;span&gt;&amp;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;//  当 tick_count 溢出归零时:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;//  (int)0 - (int)65530 = -65530&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;//  -65530 &amp;gt;= 10 ? → false → 控制更新不再触发！&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;C11 标准 §6.3.1.1：当 &lt;code&gt;uint16_t&lt;/code&gt;（比 &lt;code&gt;int&lt;/code&gt; 窄）参与算术运算时，先提升为 &lt;code&gt;int&lt;/code&gt;（有符号）。&lt;strong&gt;无符号环绕特性在提升过程中被破坏了&lt;/strong&gt;。&lt;/p&gt;
&lt;p&gt;这是一个非常隐蔽的 bug——代码逻辑看起来正确（无符号减法天然支持环绕），但编译器把它变成了有符号运算，溢出时得到负数，比较永远不成立。&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;tick_count&lt;/code&gt; 和相关变量改为 &lt;code&gt;uint32_t&lt;/code&gt;：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;volatile&lt;/span&gt;&lt;span&gt; uint32_t&lt;/span&gt;&lt;span&gt; tick_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;       // 49 天溢出, 不再在运行时触发&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; last_ctrl_tick &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; print_tick &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;p&gt;在 32 位 ARM 上, &lt;code&gt;uint32_t&lt;/code&gt; = &lt;code&gt;unsigned int&lt;/code&gt;, 与 &lt;code&gt;signed int&lt;/code&gt; 同级。C 标准的 “usual arithmetic conversions” 规定&lt;strong&gt;同级时 unsigned 优先&lt;/strong&gt;，所以 &lt;code&gt;uint32_t - uint32_t&lt;/code&gt; 保持在无符号域。这才是&lt;strong&gt;原理修复&lt;/strong&gt;——不是推迟溢出，而是保证减法永远在无符号域完成。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;教训&lt;/strong&gt;: 嵌入式 C 中, &lt;code&gt;uint8_t&lt;/code&gt; 和 &lt;code&gt;uint16_t&lt;/code&gt; 的减法&lt;strong&gt;不可信&lt;/strong&gt;——要么强转 &lt;code&gt;(uint16_t)(a - b)&lt;/code&gt;, 要么直接用 &lt;code&gt;uint32_t&lt;/code&gt;。这个 bug 花了两天才定位到编译器层面。&lt;strong&gt;确认有效的修复：把 uint16_t 改成 uint32_t&lt;/strong&gt;。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;六、Bug #2 — PID_Reset 后 D 项速度尖峰&lt;a href=&quot;#六bug-2--pid_reset-后-d-项速度尖峰&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;这个 bug 也是真实存在的，调 PID 参数时会触发瞬态冲击。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;现象&lt;a href=&quot;#现象-4&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;串口发 &lt;code&gt;kp0&lt;/code&gt;（把 Kp 设为 0），电机突然猛踹一脚飞出去。之后即使恢复 Kp，电机已漂到未知位置。&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;PID_Reset&lt;/code&gt; 将 &lt;code&gt;prev_measurement&lt;/code&gt; 清零。下一个控制周期：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;velocity = (measurement - 0) / 0.009s&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;         = (155° - 0°) / 0.009s&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;         = 17,200°/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;D_out = -Kd × 300 → 瞬间饱和 → 电机被 40% 占空比猛踹一脚&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;#define&lt;/span&gt;&lt;span&gt; PID_MEAS_UNINIT&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;e&lt;/span&gt;&lt;span&gt;10&lt;/span&gt;&lt;span&gt;f&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;  // 合法角度 0~2π 不可能在此&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; PID_Init&lt;/span&gt;&lt;span&gt;(...) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    pid&lt;/span&gt;&lt;span&gt;-&amp;gt;&lt;/span&gt;&lt;span&gt;prev_measurement &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; PID_MEAS_UNINIT;&lt;/span&gt;&lt;/span&gt;
&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; PID_Reset&lt;/span&gt;&lt;span&gt;(...) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    pid-&amp;gt;integral &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0.0&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;    pid-&amp;gt;prev_measurement &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; PID_MEAS_UNINIT;&lt;/span&gt;&lt;span&gt;  // 哨兵&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // deriv_filtered 不清零, 首帧 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;float&lt;/span&gt;&lt;span&gt; PID_Update&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; (pid-&amp;gt;prev_measurement &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; -&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;e&lt;/span&gt;&lt;span&gt;9&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;        // 首帧 → 跳过 D, 仅记录当前值&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        pid-&amp;gt;prev_measurement &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; measurement;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        D_out &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 0.0&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;else&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;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;效果：调 PID 参数不再产生瞬态冲击&lt;/strong&gt;。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;教训&lt;/strong&gt;: Reset 函数不能盲清零。任何有记忆性的状态量在 Reset 时都要用哨兵值标记”未初始化”状态。&lt;/p&gt;
&lt;/blockquote&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;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;1&lt;/td&gt;&lt;td&gt;I2C BUSY&lt;/td&gt;&lt;td&gt;误报&lt;/td&gt;&lt;td&gt;改了软 I2C，但症状的根因是 uint16_t 溢出&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;PID 符号&lt;/td&gt;&lt;td&gt;误报&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;栈溢出&lt;/td&gt;&lt;td&gt;误报&lt;/td&gt;&lt;td&gt;改了大 buf/扩了栈，但根因还是 uint16_t 溢出&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;&lt;strong&gt;uint16_t 整型提升&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;真实 bug&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;确认有效修复：改为 uint32_t&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;5&lt;/td&gt;&lt;td&gt;&lt;strong&gt;PID Reset D 尖峰&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;真实 bug&lt;/strong&gt;&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;p&gt;两个真实 bug 都定位到了根因并修复。三个”嫌疑人”其实是&lt;strong&gt;症状的副产品&lt;/strong&gt;而非根因——当 uint16_t 溢出导致控制循环停止时，所有”控制不工作”的表现都会被误认为各自有独立的根因。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;不找到根因就不算修好。&lt;/strong&gt; 同一个症状可能有多个人在喊，但你只能信第一个（最准时）的线索——时间规律是最好的 debug 信息。&lt;/p&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;完整源码：&lt;a href=&quot;https://github.com/729DHS/simplefoc_mini_STM32_demo&quot;&gt;GitHub - simpleFOC_1&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;</content:encoded><category>category:笔记</category><category>category:STM32</category><category>tag:STM32</category><category>tag:FOC</category><category>tag:电机控制</category><category>tag:PID</category><category>tag:嵌入式</category><category>tag:调试</category><category>tag:AS5600</category></item><item><title>Delta 并联机器人 — 从零搭建运动学库</title><link>https://www.729dhs.site/post/delta-robot-kinematics-library</link><guid isPermaLink="false">delta-robot-kinematics-library</guid><description>记录 Delta 并联机器人的运动学推导、MATLAB 验证和 C++ 库实现过程。静平台半径 115mm，驱动臂 125mm，从动臂 338mm，动平台直径 150mm。</description><pubDate>Thu, 14 May 2026 23:00:00 GMT</pubDate><content:encoded>&lt;p&gt;最近把 Delta 并联机器人的运动学库写完了，记录一下过程和关键数据。&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;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;Rb&lt;/td&gt;&lt;td&gt;115 mm&lt;/td&gt;&lt;td&gt;静平台半径（中心到电机轴）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Re&lt;/td&gt;&lt;td&gt;75 mm&lt;/td&gt;&lt;td&gt;动平台半径（中心到球铰，150/2）&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;L1&lt;/td&gt;&lt;td&gt;125 mm&lt;/td&gt;&lt;td&gt;驱动臂（大臂）长度&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;L2&lt;/td&gt;&lt;td&gt;338 mm&lt;/td&gt;&lt;td&gt;从动臂（小臂/拉杆）长度&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&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;逆解 (IK)&lt;a href=&quot;#逆解-ik&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;给定末端位置 &lt;code&gt;(x, y, z)&lt;/code&gt;，求三个电机角度 &lt;code&gt;θ₁, θ₂, θ₃&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;对每个支链，将问题转换到局部坐标系，简化为平面 2R 连杆逆运动学：&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;x_local·sin(θ) - z_local·cos(θ) = (d² + L1² - L2²) / (2·L1)&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;θ = φ + π/2 + α&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;其中 &lt;code&gt;φ = atan2(z_local, x_local)&lt;/code&gt;，&lt;code&gt;α = acos((L1² + d² - L2²) / (2·L1·d))&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;关键细节：从动臂在旋转平面外的投影要处理为有效长度 &lt;code&gt;L2_eff = sqrt(L2² - y_local²)&lt;/code&gt;。&lt;/p&gt;
&lt;h3&gt;正解 (FK)&lt;a href=&quot;#正解-fk&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;给定 &lt;code&gt;θ₁, θ₂, θ₃&lt;/code&gt;，求末端位置。用牛顿迭代法求解三球交汇点，收敛到误差 &amp;lt; 1e-6 mm。&lt;/p&gt;
&lt;h2&gt;MATLAB 验证结果&lt;a href=&quot;#matlab-验证结果&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;用 MATLAB 验证 IK→FK 一致性，&lt;strong&gt;在所有测试点误差均为 0.0000 mm&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;p&gt;扫描范围 20mm 网格，共 5928 个可达点：&lt;/p&gt;

































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Z (mm)&lt;/th&gt;&lt;th&gt;最大半径 (mm)&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;-460&lt;/td&gt;&lt;td&gt;14&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-440&lt;/td&gt;&lt;td&gt;103&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-400&lt;/td&gt;&lt;td&gt;192&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-360&lt;/td&gt;&lt;td&gt;247&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-300 ~ -200&lt;/td&gt;&lt;td&gt;247&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;-100&lt;/td&gt;&lt;td&gt;247&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;工作空间呈穹顶形，Z 范围约 -460 ~ -100 mm，最大水平半径约 250mm。&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;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;deltarobot/&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;│   ├── delta_common.h        → 向量、角度、工具&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── delta_param.h         → 机械参数结构体&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── delta_kinematics.h    → IK/FK/雅可比&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── delta_trajectory.h    → 轨迹规划（插补+S曲线）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   └── delta_control.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;│   ├── delta_kinematics.cpp&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── delta_trajectory.cpp&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   └── delta_control.cpp&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── scripts/&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── verify_delta.m         → 运动学验证 + 工作空间计算&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   └── workspace.m            → 工作空间可视化&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;下一步&lt;a href=&quot;#下一步&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;在 STM32F407 上跑通 IK 计算&lt;/li&gt;
&lt;li&gt;配合步进电机 DRV8825/TMC2209 做开环位置控制&lt;/li&gt;
&lt;li&gt;后来再加编码器闭环&lt;/li&gt;
&lt;/ul&gt;</content:encoded><category>category:笔记</category><category>category:Kinematics</category><category>tag:robot</category><category>tag:STM32</category><category>tag:kinematics</category><category>tag:Delta</category></item><item><title>STM32 库设计笔记2</title><link>https://www.729dhs.site/post/stm32-library-design2</link><guid isPermaLink="false">stm32-library-design2</guid><description>STM32 驱动库面向对象程序设计,从硬编码到多态的演化之路</description><pubDate>Wed, 13 May 2026 16:05:13 GMT</pubDate><content:encoded>&lt;h2&gt;第一阶段：新手村——硬编码&lt;a href=&quot;#第一阶段新手村硬编码&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;p&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;pre&gt;&lt;code&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; 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_GPIO_WritePin&lt;/span&gt;&lt;span&gt;(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);&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;htim2, TIM_CHANNEL_1, &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;    HAL_Delay&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;    HAL_GPIO_WritePin&lt;/span&gt;&lt;span&gt;(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);&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;htim3, TIM_CHANNEL_1, &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;    HAL_Delay&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;    HAL_GPIO_WritePin&lt;/span&gt;&lt;span&gt;(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);&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;htim2, TIM_CHANNEL_1, &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;    HAL_GPIO_WritePin&lt;/span&gt;&lt;span&gt;(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);&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;htim3, TIM_CHANNEL_1, &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;/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;ol&gt;
&lt;li&gt;&lt;strong&gt;代码重复&lt;/strong&gt;：每个操作都要写一堆寄存器/库函数&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不可移植&lt;/strong&gt;：换 MCU 要改所有文件&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不可读&lt;/strong&gt;：看代码不知道是在“控制电机”，只知道在“操作 GPIO 和 PWM”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;不可维护&lt;/strong&gt;：要改电机逻辑，需要找遍所有调用的地方&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;核心痛点&lt;a href=&quot;#核心痛点&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;业务逻辑（让车前进）和硬件操作（拉高 GPIO、写 PWM）混在一起&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&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;思路&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;h3&gt;代码&lt;a href=&quot;#代码-1&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;// motor_hw.c - 硬件操作封装&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;void&lt;/span&gt;&lt;span&gt; motor_left_forward&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; speed&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;(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);&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;htim2, TIM_CHANNEL_1, speed);&lt;/span&gt;&lt;/span&gt;
&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; motor_left_stop&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;    HAL_GPIO_WritePin&lt;/span&gt;&lt;span&gt;(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);&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;htim2, TIM_CHANNEL_1, &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;void&lt;/span&gt;&lt;span&gt; motor_right_forward&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;uint16_t&lt;/span&gt;&lt;span&gt; speed&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;(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);&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;htim3, TIM_CHANNEL_1, speed);&lt;/span&gt;&lt;/span&gt;
&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; motor_right_stop&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;    HAL_GPIO_WritePin&lt;/span&gt;&lt;span&gt;(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);&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;htim3, TIM_CHANNEL_1, &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;// main.c - 业务逻辑变清晰了&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;void&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;    motor_left_forward&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;    motor_right_forward&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;    HAL_Delay&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;    motor_left_stop&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    motor_right_stop&lt;/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;ul&gt;
&lt;li&gt;代码可读性提升&lt;/li&gt;
&lt;li&gt;硬件操作集中在一个文件，换 MCU 只改这个文件&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;ol&gt;
&lt;li&gt;&lt;strong&gt;函数泛滥&lt;/strong&gt;：每个动作一个函数（左转、右转、前进、后退、带加速度…），函数数量爆炸&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;参数不统一&lt;/strong&gt;：有的函数用 &lt;code&gt;uint16_t speed&lt;/code&gt;，有的用 &lt;code&gt;float duty&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;扩展性差&lt;/strong&gt;：增加新电机需要写 4 个新函数&lt;/li&gt;
&lt;/ol&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;思路&lt;a href=&quot;#思路-1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;不要为每个动作单独写函数，而是写一个“通用函数”，用参数区分动作。&lt;/p&gt;
&lt;h3&gt;代码&lt;a href=&quot;#代码-2&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;void&lt;/span&gt;&lt;span&gt; motor_control&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;uint8_t&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;uint8_t&lt;/span&gt;&lt;span&gt; action&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;int16_t&lt;/span&gt;&lt;span&gt; speed&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    switch&lt;/span&gt;&lt;span&gt;(id) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        case&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;            if&lt;/span&gt;&lt;span&gt; (action &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; FORWARD) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                HAL_GPIO_WritePin&lt;/span&gt;&lt;span&gt;(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);&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;htim2, TIM_CHANNEL_1, speed);&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; (action &lt;/span&gt;&lt;span&gt;==&lt;/span&gt;&lt;span&gt; STOP) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;                HAL_GPIO_WritePin&lt;/span&gt;&lt;span&gt;(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);&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;htim2, TIM_CHANNEL_1, &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;            break&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        case&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;            break&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 使用&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;motor_control&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, FORWARD, &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;motor_control&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, FORWARD, &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;HAL_Delay&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;motor_control&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, STOP, &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;motor_control&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;, STOP, &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;优点&lt;a href=&quot;#优点-1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;函数数量从 &lt;code&gt;电机数 × 动作数&lt;/code&gt; 减少到 1 个&lt;/li&gt;
&lt;li&gt;新增动作只需加 &lt;code&gt;case&lt;/code&gt;，不用加函数&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;新问题&lt;a href=&quot;#新问题-1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;参数越来越多&lt;/strong&gt;：要支持加速度？加参数 &lt;code&gt;uint8_t accel&lt;/code&gt;；要支持方向？加参数 &lt;code&gt;uint8_t dir&lt;/code&gt;… 参数列表越来越长&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;类型不安全&lt;/strong&gt;：&lt;code&gt;action&lt;/code&gt; 参数传错值（传了 255 而不是 FORWARD），编译器不报错&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;可读性变差&lt;/strong&gt;：&lt;code&gt;motor_control(0, 1, 500)&lt;/code&gt; 是什么意思？要看文档或函数定义&lt;/li&gt;
&lt;/ol&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;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;    uint8_t&lt;/span&gt;&lt;span&gt; motor_id;&lt;/span&gt;&lt;span&gt;      // 0=左轮, 1=右轮&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    uint8_t&lt;/span&gt;&lt;span&gt; action;&lt;/span&gt;&lt;span&gt;        // FORWARD, BACKWARD, STOP&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    int16_t&lt;/span&gt;&lt;span&gt; speed;&lt;/span&gt;&lt;span&gt;         // -1000 ~ 1000&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    uint8_t&lt;/span&gt;&lt;span&gt; accel_rate;&lt;/span&gt;&lt;span&gt;    // 0-10&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    uint32_t&lt;/span&gt;&lt;span&gt; duration_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;MotorCommand_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;void&lt;/span&gt;&lt;span&gt; motor_control&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;MotorCommand_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; cmd&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 根据 cmd 里的字段执行&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 使用&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;MotorCommand_t&lt;/span&gt;&lt;span&gt; cmd &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {.motor_id&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;, .action&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;FORWARD, .speed&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;500&lt;/span&gt;&lt;span&gt;, .accel_rate&lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt;5&lt;/span&gt;&lt;span&gt;, .duration_ms&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;motor_control&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;cmd&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;#优点-2&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;hr /&gt;
&lt;h2&gt;第四阶段：状态机 + 非阻塞（让 CPU 能干别的事）&lt;a href=&quot;#第四阶段状态机--非阻塞让-cpu-能干别的事&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;问题&lt;a href=&quot;#问题-1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;前面的写法都是&lt;strong&gt;阻塞&lt;/strong&gt;的：&lt;code&gt;HAL_Delay(1000)&lt;/code&gt; 会让 CPU 傻等 1 秒，啥也不能做。&lt;/p&gt;
&lt;h3&gt;思路&lt;a href=&quot;#思路-2&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;把“等待”变成“周期性检查”：每次调用只做一小步，然后返回。主循环不断调用，直到完成。&lt;/p&gt;
&lt;h3&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;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;    int16_t&lt;/span&gt;&lt;span&gt; target_speed;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    int16_t&lt;/span&gt;&lt;span&gt; current_speed;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    uint32_t&lt;/span&gt;&lt;span&gt; start_time;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    uint32_t&lt;/span&gt;&lt;span&gt; duration;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    uint8_t&lt;/span&gt;&lt;span&gt; is_active;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;MotorState_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;MotorState_t&lt;/span&gt;&lt;span&gt; motors&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;void&lt;/span&gt;&lt;span&gt; motor_start&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;uint8_t&lt;/span&gt;&lt;span&gt; id&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;int16_t&lt;/span&gt;&lt;span&gt; speed&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;uint32_t&lt;/span&gt;&lt;span&gt; ms&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    motors&lt;/span&gt;&lt;span&gt;[id].target_speed &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;    motors&lt;/span&gt;&lt;span&gt;[id].duration &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ms;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    motors&lt;/span&gt;&lt;span&gt;[id].start_time &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; get_tick_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;    motors&lt;/span&gt;&lt;span&gt;[id].is_active &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;void&lt;/span&gt;&lt;span&gt; motor_update&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;    for&lt;/span&gt;&lt;span&gt; (&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; 0&lt;/span&gt;&lt;span&gt;; i &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; 2&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;        if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;!&lt;/span&gt;&lt;span&gt;motors&lt;/span&gt;&lt;span&gt;[i].is_active) &lt;/span&gt;&lt;span&gt;continue&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&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; elapsed &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; get_tick_ms&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; motors&lt;/span&gt;&lt;span&gt;[i].start_time;&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; (elapsed &lt;/span&gt;&lt;span&gt;&amp;gt;=&lt;/span&gt;&lt;span&gt; motors&lt;/span&gt;&lt;span&gt;[i].duration) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            // 时间到，停止&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            motors&lt;/span&gt;&lt;span&gt;[i].is_active &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;            set_pwm&lt;/span&gt;&lt;span&gt;(i, &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;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;
&lt;span&gt;&lt;span&gt;            set_pwm&lt;/span&gt;&lt;span&gt;(i, &lt;/span&gt;&lt;span&gt;motors&lt;/span&gt;&lt;span&gt;[i].target_speed);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&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; 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;    motor_start&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;500&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;  // 左轮转1秒&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    motor_start&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;500&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;  // 右轮转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;    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;        motor_update&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;span&gt;  // 每10ms调用一次&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        // 这10ms间隙可以做其他事&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        read_sensors&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        check_emergency&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        delay_ms&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;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;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;HAL_Delay(1000)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;&lt;code&gt;motor_start(..., 1000)&lt;/code&gt; + 主循环轮询&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CPU 空转 1 秒&lt;/td&gt;&lt;td&gt;CPU 每 10ms 检查一次，其他时间干活&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&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;h3&gt;问题&lt;a href=&quot;#问题-2&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;目前每个电机是全局状态，要加新电机需要手动复制粘贴代码。&lt;/p&gt;
&lt;h3&gt;思路&lt;a href=&quot;#思路-3&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;把电机相关的数据和方法打包成一个结构体，用指针操作。&lt;/p&gt;
&lt;h3&gt;代码&lt;a href=&quot;#代码-4&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;// 电机&quot;类&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;typedef&lt;/span&gt;&lt;span&gt; struct&lt;/span&gt;&lt;span&gt; Motor_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;    int16_t&lt;/span&gt;&lt;span&gt; target_speed;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    int16_t&lt;/span&gt;&lt;span&gt; current_speed;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    uint32_t&lt;/span&gt;&lt;span&gt; start_time;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    uint32_t&lt;/span&gt;&lt;span&gt; duration;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    uint8_t&lt;/span&gt;&lt;span&gt; is_active;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    uint8_t&lt;/span&gt;&lt;span&gt; id;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &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; (&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;start)(&lt;/span&gt;&lt;span&gt;struct&lt;/span&gt;&lt;span&gt; Motor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; self, &lt;/span&gt;&lt;span&gt;int16_t&lt;/span&gt;&lt;span&gt; speed, &lt;/span&gt;&lt;span&gt;uint32_t&lt;/span&gt;&lt;span&gt; ms);&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;update)(&lt;/span&gt;&lt;span&gt;struct&lt;/span&gt;&lt;span&gt; Motor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; self);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;Motor_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;void&lt;/span&gt;&lt;span&gt; motor_start_impl&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Motor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; self&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;int16_t&lt;/span&gt;&lt;span&gt; speed&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;uint32_t&lt;/span&gt;&lt;span&gt; ms&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    self-&amp;gt;target_speed &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;    self-&amp;gt;duration &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; ms;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    self-&amp;gt;start_time &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; get_tick_ms&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    self-&amp;gt;is_active &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;void&lt;/span&gt;&lt;span&gt; motor_update_impl&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Motor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; self&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;!&lt;/span&gt;&lt;span&gt;self-&amp;gt;is_active) &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;    if&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;get_tick_ms&lt;/span&gt;&lt;span&gt;() &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; self-&amp;gt;start_time &lt;/span&gt;&lt;span&gt;&amp;gt;=&lt;/span&gt;&lt;span&gt; self-&amp;gt;duration) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        self-&amp;gt;is_active &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;        set_pwm&lt;/span&gt;&lt;span&gt;(self-&amp;gt;id, &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;else&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        set_pwm&lt;/span&gt;&lt;span&gt;(self-&amp;gt;id, self-&amp;gt;target_speed);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// 创建实例&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Motor_t&lt;/span&gt;&lt;span&gt; left_motor &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    .id &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;    .start &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; motor_start_impl,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    .update &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; motor_update_impl,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Motor_t&lt;/span&gt;&lt;span&gt; right_motor &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    .id &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;    .start &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; motor_start_impl,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    .update &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; motor_update_impl,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&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; 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;    left_motor.&lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;left_motor, &lt;/span&gt;&lt;span&gt;500&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;    right_motor.&lt;/span&gt;&lt;span&gt;start&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;right_motor, &lt;/span&gt;&lt;span&gt;500&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;    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;        left_motor.&lt;/span&gt;&lt;span&gt;update&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;left_motor);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        right_motor.&lt;/span&gt;&lt;span&gt;update&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;right_motor);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        delay_ms&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;h3&gt;关键点：&lt;code&gt;self&lt;/code&gt; 指针&lt;a href=&quot;#关键点self-指针&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;每个方法第一个参数都是 &lt;code&gt;self&lt;/code&gt;，指向调用它的实例。这样同一个 &lt;code&gt;motor_update_impl&lt;/code&gt; 函数可以操作不同的电机数据。&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;第六阶段：硬件抽象（换 MCU 不改上层代码）&lt;a href=&quot;#第六阶段硬件抽象换-mcu-不改上层代码&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;问题&lt;a href=&quot;#问题-3&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;目前 &lt;code&gt;set_pwm()&lt;/code&gt; 函数里还是直接调用 HAL 库，换 MCU 需要改这个函数内部。&lt;/p&gt;
&lt;h3&gt;思路&lt;a href=&quot;#思路-4&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;把硬件操作也抽象成操作表（函数指针集合），上层只调用操作表，不直接调用 HAL。&lt;/p&gt;
&lt;h3&gt;代码&lt;a href=&quot;#代码-5&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;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;    void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;pwm_set)(&lt;/span&gt;&lt;span&gt;uint8_t&lt;/span&gt;&lt;span&gt; channel, &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;    uint32_t&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;get_tick)(&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;    void&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;delay_ms)(&lt;/span&gt;&lt;span&gt;uint32_t&lt;/span&gt;&lt;span&gt; ms);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;Hardware_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;// STM32 实现&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; stm32_pwm_set&lt;/span&gt;&lt;span&gt;(&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;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;    __HAL_TIM_SET_COMPARE&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;htim2, TIM_CHANNEL_1 &lt;/span&gt;&lt;span&gt;+&lt;/span&gt;&lt;span&gt; ch, 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;static&lt;/span&gt;&lt;span&gt; uint32_t&lt;/span&gt;&lt;span&gt; stm32_get_tick&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;    return&lt;/span&gt;&lt;span&gt; HAL_GetTick&lt;/span&gt;&lt;span&gt;();&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Hardware_t&lt;/span&gt;&lt;span&gt; STM32_Hardware &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_set &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; stm32_pwm_set,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    .get_tick &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; stm32_get_tick,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    .delay_ms &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; HAL_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;// 上层代码依赖抽象，不依赖具体&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;Hardware_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; HW &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;STM32_Hardware;&lt;/span&gt;&lt;span&gt;  // 换平台只改这一行&lt;/span&gt;&lt;/span&gt;
&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; motor_update_impl&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Motor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; self&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // ...&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    HW-&amp;gt;&lt;/span&gt;&lt;span&gt;pwm_set&lt;/span&gt;&lt;span&gt;(self-&amp;gt;id, self-&amp;gt;target_speed);&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;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;STM32&lt;/td&gt;&lt;td&gt;&lt;code&gt;stm32_pwm_set&lt;/code&gt; 等函数的实现&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ESP32&lt;/td&gt;&lt;td&gt;写一套 &lt;code&gt;esp32_pwm_set&lt;/code&gt; 等函数，然后 &lt;code&gt;HW = &amp;amp;ESP32_Hardware&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;模拟测试&lt;/td&gt;&lt;td&gt;写一套 mock 函数，在 PC 上跑&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;上层业务逻辑（电机控制、底盘控制）一行代码都不用改！&lt;/strong&gt;&lt;/p&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;场景&lt;a href=&quot;#场景-1&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;：需要 PID 闭环控制&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;步进电机&lt;/strong&gt;：需要发脉冲控制&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;问题&lt;a href=&quot;#问题-4&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;它们的行为完全不同，但我们希望上层能用统一的接口：&lt;code&gt;motor_update()&lt;/code&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;pre&gt;&lt;code&gt;&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; struct&lt;/span&gt;&lt;span&gt; Motor_t&lt;/span&gt;&lt;span&gt; Motor_t&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; struct&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;update)(&lt;/span&gt;&lt;span&gt;Motor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; self);&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;set_speed)(&lt;/span&gt;&lt;span&gt;Motor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; self, &lt;/span&gt;&lt;span&gt;int16_t&lt;/span&gt;&lt;span&gt; speed);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;MotorOps_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;struct&lt;/span&gt;&lt;span&gt; Motor_t&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    MotorOps_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; ops;&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; id;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // 其他通用属性...&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&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; struct&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    Motor_t&lt;/span&gt;&lt;span&gt; base;&lt;/span&gt;&lt;span&gt;           // 继承通用部分&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    int16_t&lt;/span&gt;&lt;span&gt; target_speed;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    int16_t&lt;/span&gt;&lt;span&gt; current_speed;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    float&lt;/span&gt;&lt;span&gt; kp, ki, kd;&lt;/span&gt;&lt;span&gt;       // PID参数&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;DCMotor_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;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; dc_update&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Motor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; self&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    DCMotor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; dc &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;DCMotor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;)self;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // PID 计算&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    int16_t&lt;/span&gt;&lt;span&gt; error &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; dc-&amp;gt;target_speed &lt;/span&gt;&lt;span&gt;-&lt;/span&gt;&lt;span&gt; dc-&amp;gt;current_speed;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    int16_t&lt;/span&gt;&lt;span&gt; output &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; error &lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; dc-&amp;gt;kp;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    HW-&amp;gt;&lt;/span&gt;&lt;span&gt;pwm_set&lt;/span&gt;&lt;span&gt;(self-&amp;gt;id, output);&lt;/span&gt;&lt;/span&gt;
&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; dc_set_speed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Motor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; self&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;int16_t&lt;/span&gt;&lt;span&gt; speed&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    DCMotor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; dc &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;DCMotor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;)self;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    dc-&amp;gt;target_speed &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;}&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; MotorOps_t&lt;/span&gt;&lt;span&gt; dc_ops &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    .update &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; dc_update,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    .set_speed &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; dc_set_speed,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&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; struct&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    Motor_t&lt;/span&gt;&lt;span&gt; base;&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; target_steps;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    int32_t&lt;/span&gt;&lt;span&gt; current_steps;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;} &lt;/span&gt;&lt;span&gt;StepperMotor_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;static&lt;/span&gt;&lt;span&gt; void&lt;/span&gt;&lt;span&gt; stepper_update&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Motor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; self&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    StepperMotor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; stepper &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;StepperMotor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;)self;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    if&lt;/span&gt;&lt;span&gt; (stepper-&amp;gt;current_steps &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; stepper-&amp;gt;target_steps) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        // 发一个脉冲&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        HW-&amp;gt;&lt;/span&gt;&lt;span&gt;gpio_toggle&lt;/span&gt;&lt;span&gt;(self-&amp;gt;id);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        stepper-&amp;gt;current_steps&lt;/span&gt;&lt;span&gt;++&lt;/span&gt;&lt;span&gt;;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&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; stepper_set_speed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;Motor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; self&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;int16_t&lt;/span&gt;&lt;span&gt; speed&lt;/span&gt;&lt;span&gt;) {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    StepperMotor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; stepper &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;StepperMotor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;)self;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    stepper-&amp;gt;target_steps &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;}&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; MotorOps_t&lt;/span&gt;&lt;span&gt; stepper_ops &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    .update &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; stepper_update,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    .set_speed &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; stepper_set_speed,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// ========== 第四步：创建对象 ==========&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;DCMotor_t&lt;/span&gt;&lt;span&gt; dc_motor_obj &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    .base &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { .ops &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;dc_ops, .id &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;    .target_speed &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;    .kp &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 1.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;StepperMotor_t&lt;/span&gt;&lt;span&gt; stepper_obj &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; {&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    .base &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; { .ops &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; &amp;amp;&lt;/span&gt;&lt;span&gt;stepper_ops, .id &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;    .target_steps &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;Motor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt; motors&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;Motor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;dc_motor_obj,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    (&lt;/span&gt;&lt;span&gt;Motor_t&lt;/span&gt;&lt;span&gt;*&lt;/span&gt;&lt;span&gt;)&lt;/span&gt;&lt;span&gt;&amp;amp;&lt;/span&gt;&lt;span&gt;stepper_obj,&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&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; 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;    motors&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;0&lt;/span&gt;&lt;span&gt;]-&amp;gt;ops-&amp;gt;&lt;/span&gt;&lt;span&gt;set_speed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;motors&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;500&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    motors&lt;/span&gt;&lt;span&gt;[&lt;/span&gt;&lt;span&gt;1&lt;/span&gt;&lt;span&gt;]-&amp;gt;ops-&amp;gt;&lt;/span&gt;&lt;span&gt;set_speed&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;motors&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;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;    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;        for&lt;/span&gt;&lt;span&gt; (&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; 0&lt;/span&gt;&lt;span&gt;; i &lt;/span&gt;&lt;span&gt;&amp;lt;&lt;/span&gt;&lt;span&gt; 2&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;            motors&lt;/span&gt;&lt;span&gt;[i]-&amp;gt;ops-&amp;gt;&lt;/span&gt;&lt;span&gt;update&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;motors&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;
&lt;span&gt;&lt;span&gt;        delay_ms&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;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;motors[0]（直流电机）:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    motors[0]-&amp;gt;ops-&amp;gt;update → 执行 dc_update() → PID 计算 → 设 PWM&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;motors[1]（步进电机）:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    motors[1]-&amp;gt;ops-&amp;gt;update → 执行 stepper_update() → 发脉冲 → 走一步&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;同样的代码 &lt;code&gt;motors[i]-&amp;gt;ops-&amp;gt;update(motors[i])&lt;/code&gt;，做的是完全不同的事情！&lt;/strong&gt;&lt;/p&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;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;1. 硬编码&lt;/td&gt;&lt;td&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;2. 函数封装&lt;/td&gt;&lt;td&gt;硬件操作打包&lt;/td&gt;&lt;td&gt;&lt;code&gt;motor_left_forward()&lt;/code&gt;&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;用参数区分行为&lt;/td&gt;&lt;td&gt;&lt;code&gt;motor_control(id, action, speed)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;减少函数数量&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;4. 非阻塞&lt;/td&gt;&lt;td&gt;状态机 + 轮询&lt;/td&gt;&lt;td&gt;&lt;code&gt;motor_start()&lt;/code&gt; + &lt;code&gt;motor_update()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;CPU 不空转&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;5. 多实例&lt;/td&gt;&lt;td&gt;结构体封装&lt;/td&gt;&lt;td&gt;&lt;code&gt;Motor_t&lt;/code&gt; + &lt;code&gt;self&lt;/code&gt; 指针&lt;/td&gt;&lt;td&gt;支持多个对象&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;6. 硬件抽象&lt;/td&gt;&lt;td&gt;操作表&lt;/td&gt;&lt;td&gt;&lt;code&gt;Hardware_t&lt;/code&gt; + 函数指针&lt;/td&gt;&lt;td&gt;跨平台移植&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;7. 多态&lt;/td&gt;&lt;td&gt;每个对象有自己的操作表&lt;/td&gt;&lt;td&gt;&lt;code&gt;MotorOps_t&lt;/code&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;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;1-2 个文件，个人玩具&lt;/td&gt;&lt;td&gt;阶段 2-3&lt;/td&gt;&lt;td&gt;够用，不折腾&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;多个模块，团队开发&lt;/td&gt;&lt;td&gt;阶段 4-5&lt;/td&gt;&lt;td&gt;可维护性重要&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;需要换平台的产品&lt;/td&gt;&lt;td&gt;阶段 6&lt;/td&gt;&lt;td&gt;硬件抽象是刚需&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;有多种设备类型（电机、灯、传感器）&lt;/td&gt;&lt;td&gt;阶段 7&lt;/td&gt;&lt;td&gt;多态让扩展变得简单&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;hr /&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>轮腿机器人二自由度闭式连杆机构正逆运动学推导</title><link>https://www.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;br /&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;/div&gt;
        &lt;div&gt;
          &lt;div&gt;GitHub - 729DHS/linkage-2dof&lt;/div&gt;
          &lt;div&gt;https://github.com/729DHS/linkage-2dof&lt;/div&gt;
        &lt;/div&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://www.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://www.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://www.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://www.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://www.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://www.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://www.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://www.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 &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;__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;GPIO_InitStruct.Mode &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_MODE_INPUT;&lt;/span&gt;&lt;span&gt;   // 或 GPIO_MODE_OUTPUT_PP 等&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_NOPULL;&lt;/span&gt;&lt;span&gt;       // 视外部电路选择 PULLUP/PULLDOWN&lt;/span&gt;&lt;/span&gt;
&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_15;&lt;/span&gt;&lt;span&gt;        // PA15: JTDI（SWD 模式下可用作普通 GPIO）&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;HAL_GPIO_Init&lt;/span&gt;&lt;span&gt;(GPIOA, &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;span&gt;&lt;span&gt;GPIO_InitStruct.Pin &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; GPIO_PIN_3 &lt;/span&gt;&lt;span&gt;|&lt;/span&gt;&lt;span&gt; GPIO_PIN_4;&lt;/span&gt;&lt;span&gt; // PB3: JTDO/SWO, PB4: NJTRST&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;HAL_GPIO_Init&lt;/span&gt;&lt;span&gt;(GPIOB, &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;/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://www.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://www.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&lt;/span&gt;&lt;span&gt; _ &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; 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&lt;/span&gt;&lt;span&gt; _ &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; get_thing&lt;/span&gt;&lt;span&gt;();&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&lt;/span&gt;&lt;span&gt; pair &lt;/span&gt;&lt;span&gt;=&lt;/span&gt;&lt;span&gt; (&lt;/span&gt;&lt;span&gt;&apos;a&apos;&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;17&lt;/span&gt;&lt;span&gt;);&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;pair&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;// this is &apos;a&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;pair&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;// this is 17&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;let&lt;/span&gt;&lt;span&gt; pairs&lt;/span&gt;&lt;span&gt;:&lt;/span&gt;&lt;span&gt;(&lt;/span&gt;&lt;span&gt;i32&lt;/span&gt;&lt;span&gt;, &lt;/span&gt;&lt;span&gt;i32&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;char&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;2&lt;/span&gt;&lt;span&gt;,&lt;/span&gt;&lt;span&gt;&apos;a&apos;&lt;/span&gt;&lt;span&gt;);&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://www.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://www.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></channel></rss>