<?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><language>en</language><item><title>校区2 录取名单多维度分析报告</title><link>https://www.729dhs.site/en/post/note/campus2_analysis</link><guid isPermaLink="false">en: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/en/post/note/admission_analysis</link><guid isPermaLink="false">en: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 Debug Configuration Guide</title><link>https://www.729dhs.site/en/post/stm32n657-nucleo-dev-log2</link><guid isPermaLink="false">en:stm32n657-nucleo-dev-log2</guid><description>STM32N657X0H3Q Nucleo development board VSCode debug configuration guide, resolving LRUN mode debugging issues, with correct launch.json setup and common pitfalls.</description><pubDate>Mon, 08 Jun 2026 03:39:51 GMT</pubDate><content:encoded>&lt;h1&gt;STM32N657X0H3Q Nucleo VSCode Debug Configuration Guide&lt;a href=&quot;#stm32n657x0h3q-nucleo-vscode-debug-configuration-guide&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;hr /&gt;
&lt;h2&gt;Problem Recap&lt;a href=&quot;#problem-recap&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In the previous article, I covered the complete workflow of compiling, signing, and flashing via STM32 Programmer. In LRUN mode, both FSBL and Application can be flashed independently and run correctly. However, one critical issue remained — &lt;strong&gt;source-level debugging in VSCode was not working&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;When starting a debug session, the program would break at a library function around &lt;code&gt;RETR=Map Memory&lt;/code&gt;. According to ST Community forum tutorials, this breakpoint should allow single-step debugging as usual — but in practice, the debugger disconnected from the board shortly after hitting the break, and the session terminated.&lt;/p&gt;
&lt;p&gt;Initially, I suspected TrustZone security domain configuration — perhaps RIF resource isolation was preventing the debugger from accessing the secure state. After systematic troubleshooting, this possibility was ruled out.&lt;/p&gt;
&lt;h2&gt;Root Cause Analysis&lt;a href=&quot;#root-cause-analysis&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;A careful inspection of &lt;code&gt;launch.json&lt;/code&gt; revealed the root cause: &lt;strong&gt;the stldr file configuration was wrong&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;I’m using the &lt;strong&gt;New Clone board (NUCLEO-N657X0-Q)&lt;/strong&gt;, but the configuration mistakenly referenced settings for the DK board (STM32N6570-DK). The stldr (External Loader) file acts as the bridge between the debugger and external Flash. An incorrect loader means the debugger can’t properly access external memory, causing the connection to fail.&lt;/p&gt;
&lt;h3&gt;launch.json Configuration Breakdown&lt;a href=&quot;#launchjson-configuration-breakdown&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After fixing the stldr configuration, other settings were also adjusted. Here’s the complete configuration with field explanations:&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;// Debugger type: ST-Link GDB target&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;// Build command&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;// Entry function name&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            // SVD file path (replace the path prefix with your actual STM32CubeProgrammer installation directory)&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 image: symbol for source mapping, image for flashing&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 image: both point to the same ELF (FSBL doesn&apos;t need a separate trusted file)&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 file (New Clone board, NOT DK board)&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;Path Note&lt;/strong&gt;: The &lt;code&gt;...\\STM32CubeProgrammer\\&lt;/code&gt; prefix above represents STM32CubeProgrammer’s installation directory. Replace it with your actual path, such as &lt;code&gt;C:\\Program Files\\STMicroelectronics\\STM32Cube\\STM32CubeProgrammer\\&lt;/code&gt; or your custom directory.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Key Configuration Fields&lt;a href=&quot;#key-configuration-fields&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;Field&lt;/th&gt;&lt;th&gt;Purpose&lt;/th&gt;&lt;th&gt;Notes&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;Debugger entry function&lt;/td&gt;&lt;td&gt;LRUN mode on NUCLEO-N657X0-Q must be &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 file path providing peripheral register descriptions&lt;/td&gt;&lt;td&gt;Point to the SVD folder under STM32CubeProgrammer&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 symbol file for source-level debugging&lt;/td&gt;&lt;td&gt;Must match compiled binary path&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;Flash image&lt;/td&gt;&lt;td&gt;Appli uses &lt;code&gt;Appli-trusted.elf&lt;/code&gt; (signed), FSBL uses the compiled &lt;code&gt;.elf&lt;/code&gt; directly&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;External Flash loader configuration&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Make sure to select the stldr matching your board&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Configuration Insights&lt;a href=&quot;#configuration-insights&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;FSBL vs Appli ELF Configuration&lt;a href=&quot;#fsbl-vs-appli-elf-configuration&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;There’s an important distinction between FSBL and Application image configuration:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;FSBL&lt;/strong&gt;: Both &lt;code&gt;symbolFileName&lt;/code&gt; and &lt;code&gt;imageFileName&lt;/code&gt; point to the same &lt;code&gt;.elf&lt;/code&gt; file, because FSBL uses the compiled ELF directly for both debugging and signing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Application&lt;/strong&gt;: &lt;code&gt;symbolFileName&lt;/code&gt; points to the compiled ELF (with debug symbols), while &lt;code&gt;imageFileName&lt;/code&gt; points to &lt;code&gt;Appli-trusted.elf&lt;/code&gt; (the signed image)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is because the Application needs to be signed (with a V2.3 Header) to be recognized by Boot ROM or FSBL, while debugging requires the original unstripped ELF for source-code mapping.&lt;/p&gt;
&lt;h3&gt;Signing File Notes&lt;a href=&quot;#signing-file-notes&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The naming convention for signing artifacts was also somewhat confusing in the original configuration. Key distinction:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;.elf&lt;/code&gt; — Compiler-generated ELF with debug symbols&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-trusted.elf&lt;/code&gt; — Image file post-signing, with Header added&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-trusted.bin&lt;/code&gt; — Pure binary post-signing, with Header added&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Application uses &lt;code&gt;Appli-trusted.elf&lt;/code&gt; as its image file, while FSBL doesn’t require a separate trusted version.&lt;/p&gt;
&lt;h2&gt;Debug Workflow Summary&lt;a href=&quot;#debug-workflow-summary&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;With the corrected configuration, the complete VSCode debug workflow is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Ensure BOOT1 = 2-3&lt;/strong&gt; (DEV mode)&lt;/li&gt;
&lt;li&gt;In VSCode, select the &lt;code&gt;NUCLEO-N657X0-Q Debug (FSBL + Appli)&lt;/code&gt; configuration&lt;/li&gt;
&lt;li&gt;Set breakpoints in Application code&lt;/li&gt;
&lt;li&gt;Press F5 to start debugging&lt;/li&gt;
&lt;li&gt;FSBL runs automatically → loads Appli into SRAM → jumps to execution → breakpoints hit&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Pitfall Summary&lt;a href=&quot;#pitfall-summary&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;Symptom&lt;/th&gt;&lt;th&gt;Possible Cause&lt;/th&gt;&lt;th&gt;Solution&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Debug connection drops immediately&lt;/td&gt;&lt;td&gt;stldr mismatch (DK vs New Clone board)&lt;/td&gt;&lt;td&gt;Check and fix &lt;code&gt;serverExtLoader&lt;/code&gt; stldr path&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Breakpoint hits library function then exits&lt;/td&gt;&lt;td&gt;Security domain blocking debugger&lt;/td&gt;&lt;td&gt;Check RIF configuration for debug permissions&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;code&gt;Appli-trusted.elf&lt;/code&gt; not found&lt;/td&gt;&lt;td&gt;Signed image not generated post-build&lt;/td&gt;&lt;td&gt;Verify CMake POST_BUILD signing script&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Can’t single-step in debug&lt;/td&gt;&lt;td&gt;Symbol file path incorrect&lt;/td&gt;&lt;td&gt;Confirm &lt;code&gt;symbolFileName&lt;/code&gt; points to the correct &lt;code&gt;.elf&lt;/code&gt; file&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:Embedded</category></item><item><title>STM32N657X0H3Q Nucleo Development Board Debug Log</title><link>https://www.729dhs.site/en/post/stm32n657-nucleo-dev-log</link><guid isPermaLink="false">en:stm32n657-nucleo-dev-log</guid><description>STM32N657X0H3Q Nucleo development board debugging journal, covering SRAM debugging, XSPI XIP mode, FSBL Load &amp; Run configuration, and signing/flash procedures.</description><pubDate>Sat, 06 Jun 2026 16:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;STM32N657X0H3Q Nucleo Development Board Debug Log&lt;a href=&quot;#stm32n657x0h3q-nucleo-development-board-debug-log&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;This board is ridiculous — TrustZone, FSBL, OTP… why is everything so complicated?&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;1. Debugging Journey&lt;a href=&quot;#1-debugging-journey&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;First Attempt: SRAM Mode&lt;a href=&quot;#first-attempt-sram-mode&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Following the familiar F1 and F4 workflow, I configured the project in CubeMX and loaded it into VS Code for debugging. Surprisingly, &lt;strong&gt;debugging actually worked&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;But it wouldn’t run standalone — after a Reset, the code just disappeared. Looking back, this was because I was using SRAM mode: the code was loaded directly into SRAM for debugging. The benefit was being able to see results and debug in real-time, but the problem was that &lt;strong&gt;the code wasn’t actually being stored anywhere&lt;/strong&gt;. Storing code requires writing it to Flash, which means configuring the XSPI interface.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall&lt;/strong&gt;: The NUCLEO-N657X0-Q &lt;strong&gt;has no internal Flash&lt;/strong&gt;. Code must be stored in external XSPI Flash. When debugging in SRAM mode, power loss means code loss — this explains why the code “disappeared” after Reset.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;XSPI + XIP Mode Attempt&lt;a href=&quot;#xspi--xip-mode-attempt&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;XIP stands for Execute In Place — the program runs directly from external Nor Flash without copying to SRAM. XSPI (eXtended SPI) is ST’s serial peripheral interface protocol for communicating with external Flash. The configuration process is quite involved.&lt;/p&gt;
&lt;p&gt;I attempted the XSPI approach but got nowhere. Problems kept piling up — flashing and debugging both threw errors. The official forum post was configured for the DK board, and I’m not sure if there are differences between DK and the NUCLEO board, so I gave up.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall&lt;/strong&gt;: XIP mode configuration is extremely complex, requiring:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Memory-Mapped Mode configuration so the CPU can access external Flash via bus&lt;/li&gt;
&lt;li&gt;External Flash .stldr loader file (STM32CubeProgrammer needs the correct External Loader)&lt;/li&gt;
&lt;li&gt;Correct linker script (&lt;code&gt;STM32N657XX_ROMxspi*.ld&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-align&lt;/code&gt; parameter when signing&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The DK board (Development Kit) and NUCLEO board may have different configurations. Official tutorials target the DK board, so many settings don’t apply to NUCLEO.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;LRUN Mode: Success&lt;a href=&quot;#lrun-mode-success&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;LRUN (Load and Run) uses FSBL + Application working together. FSBL initializes the system and copies the Application code to SRAM. My understanding: the PC pointer is transferred to Application just before entering the infinite loop. So the &lt;strong&gt;infinite loop never executes&lt;/strong&gt;. I placed the LED blink before the infinite loop, before entering 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;FSBL Flow&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;Then things went smoothly — compile and flash. After compilation, sign the binaries, then flash each one separately. Theoretically you should flash FSBL first, then Application. But in practice, the onboard program should already be in LRUN mode, so flashing either one works fine. It’s just a matter of FSBL pointers — Application is its own program, no real difference.&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;Flash Configuration&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;p&gt;One important note: when flashing, you need to select the external memory settings — that .stldr file. Select the one matching this board, then proceed. When flashing, I got a “Core locked” popup. Previously it showed “Write Protection PROTECTION” — not sure why.&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;Core Locked Error&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall&lt;/strong&gt;: “Core locked” or “Write Protection PROTECTION” during flashing is usually an Option Bytes issue. Try:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Hold Reset while flashing&lt;/li&gt;
&lt;li&gt;Use Mass Erase to erase the entire chip&lt;/li&gt;
&lt;li&gt;Check BOOT jumpers are correctly set (DEV mode: BOOT1 = 2-3)&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Also, you need to load the correct External Loader (.stldr file) in CubeProgrammer before flashing, otherwise external Flash won’t be recognized.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;2. Hardware Platform &amp;amp; Key Concepts&lt;a href=&quot;#2-hardware-platform--key-concepts&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;2.1 Chip &amp;amp; Development Board&lt;a href=&quot;#21-chip--development-board&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Chip&lt;/strong&gt;: STM32N657X0H3QU&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Board&lt;/strong&gt;: NUCLEO-N657X0-Q (MB1940)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Architecture&lt;/strong&gt;: ARM Cortex-M55 with Helium (MVE) + TrustZone&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clock&lt;/strong&gt;: 600 MHz&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Flash&lt;/strong&gt;: &lt;strong&gt;No internal Flash&lt;/strong&gt;, relies on external 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 differs from F1/F4 series in several key ways:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;No internal Flash&lt;/strong&gt;: Code must be stored in external XSPI Flash&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;TrustZone&lt;/strong&gt;: Secure and Non-Secure worlds are isolated, requiring proper RIF configuration&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dual-domain architecture&lt;/strong&gt;: Secure and Non-Secure domains are separate&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OTP Fuses&lt;/strong&gt;: One-time programmable fuses for high-speed mode configuration&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;FSBL mechanism&lt;/strong&gt;: First Stage Boot Loader&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;2.2 LED Pins&lt;a href=&quot;#22-led-pins&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;Color&lt;/th&gt;&lt;th&gt;Pin&lt;/th&gt;&lt;th&gt;Note&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Green LED&lt;/td&gt;&lt;td&gt;PG.00 (LED_GREEN)&lt;/td&gt;&lt;td&gt;Appli main loop control&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Blue LED&lt;/td&gt;&lt;td&gt;PG.08 (LED_BLUE)&lt;/td&gt;&lt;td&gt;Appli main loop control&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Red LED&lt;/td&gt;&lt;td&gt;PG.10 (LED_RED)&lt;/td&gt;&lt;td&gt;FSBL debug indicator&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Correction&lt;/strong&gt;: Previous notes listed PG.08 as yellow, but it’s actually blue (LED_BLUE). The silkscreen on NUCLEO-N657X0-Q matches the BSP definition.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;2.3 Boot Mode (Boot Pin)&lt;a href=&quot;#23-boot-mode-boot-pin&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The board has 3 Boot pin positions (headers 1, 2, 3), selected via jumpers:&lt;/p&gt;
&lt;h4&gt;Boot Pin Configuration&lt;a href=&quot;#boot-pin-configuration&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;Pin&lt;/th&gt;&lt;th&gt;Headers 1-2 Short&lt;/th&gt;&lt;th&gt;Headers 2-3 Short&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 (Low)&lt;/td&gt;&lt;td&gt;1 (High)&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 (Low)&lt;/td&gt;&lt;td&gt;1 (High)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h4&gt;Boot Modes&lt;a href=&quot;#boot-modes&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;Mode&lt;/th&gt;&lt;th&gt;BOOT0&lt;/th&gt;&lt;th&gt;BOOT1&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;DEV (Debug)&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Any&lt;/strong&gt; (0 or 1)&lt;/td&gt;&lt;td&gt;&lt;strong&gt;1&lt;/strong&gt; (Headers 2-3)&lt;/td&gt;&lt;td&gt;IDE loads program to RAM, source-level debugging&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; (Headers 1-2)&lt;/td&gt;&lt;td&gt;&lt;strong&gt;0&lt;/strong&gt; (Headers 1-2)&lt;/td&gt;&lt;td&gt;Boot from external XSPI Flash, standalone&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;Reserved&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;Built-in chip ROM (rarely used)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: In DEV mode, BOOT0 can be anything, &lt;strong&gt;only BOOT1 = 1 is required&lt;/strong&gt; (jumper on 2-3).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;2.4 Boot ROM Startup Sequence&lt;a href=&quot;#24-boot-rom-startup-sequence&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After power-on, the STM32N6 Boot ROM searches for bootable code in this order:&lt;/p&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Order&lt;/th&gt;&lt;th&gt;Address&lt;/th&gt;&lt;th&gt;Description&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;Primary&lt;/strong&gt;: External XSPI Flash (FSBL or headered program)&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;Internal ROM&lt;/td&gt;&lt;td&gt;Factory-installed BootLoader (if any)&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;If nothing else found, try booting from RAM&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note&lt;/strong&gt;: Address &lt;code&gt;0x7000 0000&lt;/code&gt; is the &lt;strong&gt;mirror start address&lt;/strong&gt; of external Flash. Physical Flash is accessed via XSPI interface. Only signed programs at this address are recognized by Boot ROM.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;2.5 Glossary&lt;a href=&quot;#25-glossary&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;Abbr.&lt;/th&gt;&lt;th&gt;Full Name&lt;/th&gt;&lt;th&gt;Meaning&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;Code copied from external Flash to internal RAM for execution&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;Code executes directly from external Flash, no RAM copy&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’s serial peripheral interface protocol for external Flash communication&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;First-stage bootloader&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;One-time programmable fuses&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;2.6 Linker Script Naming Convention&lt;a href=&quot;#26-linker-script-naming-convention&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Format: &lt;code&gt;ROM_location_RUN_RAM_location&lt;/code&gt;&lt;/p&gt;





























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Linker Script&lt;/th&gt;&lt;th&gt;Meaning&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 in internal RAM (loaded by 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 in external XSPI1 Flash, execute in place&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 in external XSPI2 Flash, execute in place&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 in RAM, loaded from 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 in XSPI1, RAM in XSPI3&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;3. FSBL Load &amp;amp; Run Mode&lt;a href=&quot;#3-fsbl-load--run-mode&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;3.1 Architecture Overview&lt;a href=&quot;#31-architecture-overview&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FSBL LRUN mode divides the system into two independent subprojects:&lt;/p&gt;




















&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Subproject&lt;/th&gt;&lt;th&gt;Responsibility&lt;/th&gt;&lt;th&gt;Execution Location&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;Initialize OTP, configure XSPI2, read/copy Appli, jump&lt;/td&gt;&lt;td&gt;Internal 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;User application, controls LEDs and peripherals&lt;/td&gt;&lt;td&gt;Internal RAM (0x3400_0400)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;3.2 FSBL Code Analysis&lt;a href=&quot;#32-fsbl-code-analysis&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FSBL core code in &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;  // Configure 600MHz system clock&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // OTP configuration (required on first flash)&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; // Initialize 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; // Initialize XSPI2 interface&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;   // Copy Appli to RAM and jump&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;  // Never reaches here&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 execution flow&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Enable caches&lt;/strong&gt;: ICache + DCache&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Configure clock&lt;/strong&gt;: 600MHz&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;OTP configuration&lt;/strong&gt;: Set VDDIO3_HSLV fuse (only needed on first flash)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Initialize GPIO&lt;/strong&gt;: Configure LED pin PG.10 (debug)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Initialize XSPI2&lt;/strong&gt;: Communicate with external Flash&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Initialize external memory&lt;/strong&gt;: &lt;code&gt;MX_EXTMEM_Init()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Jump to execution&lt;/strong&gt;: &lt;code&gt;BOOT_Application()&lt;/code&gt; copies Appli to RAM and jumps&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;3.3 OTP Configuration Details&lt;a href=&quot;#33-otp-configuration-details&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; configures VDDIO3_HSLV fuse bits:&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 high-speed mode enable&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;blockquote&gt;
&lt;p&gt;⚠️ &lt;strong&gt;Warning&lt;/strong&gt;: OTP fuses are &lt;strong&gt;one-time write, irreversible&lt;/strong&gt;. Confirm before configuring. Disable &lt;code&gt;NO_OTP_FUSE&lt;/code&gt; macro on first flash.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;3.4 Appli Code Analysis&lt;a href=&quot;#34-appli-code-analysis&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Appli code in &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;  // Configure RIF resource isolation&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;  // Green 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;  // Blue 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;&lt;code&gt;SystemIsolation_Config()&lt;/code&gt; configures TrustZone resource isolation:&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 Skip FSBL and Run Appli Directly&lt;a href=&quot;#35-skip-fsbl-and-run-appli-directly&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;You can &lt;strong&gt;skip FSBL and flash Appli directly&lt;/strong&gt; if any of these conditions are met:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;OTP already configured (VDDIO3_HSLV set)&lt;/li&gt;
&lt;li&gt;Chip has built-in FSBL at &lt;code&gt;0x7000 0000&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Boot ROM supports direct loading from &lt;code&gt;0x7010 0000&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Steps&lt;/strong&gt;:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Sign Appli: &lt;code&gt;Appli-trusted.bin&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Flash to &lt;code&gt;0x7010 0000&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Reset, chip boots from external Flash&lt;/li&gt;
&lt;/ol&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Pitfall&lt;/strong&gt;: If the chip has no built-in FSBL and Boot ROM doesn’t support direct loading, skipping FSBL will cause the chip to not find executable code and hang.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;4. Build Configuration&lt;a href=&quot;#4-build-configuration&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;4.1 Toolchain&lt;a href=&quot;#41-toolchain&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;Tool&lt;/th&gt;&lt;th&gt;Path&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 Build Commands&lt;a href=&quot;#42-build-commands&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 Configuration (Auto-Signing)&lt;a href=&quot;#43-cmake-post_build-configuration-auto-signing&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;# Auto-signing (runs automatically after build, no manual signing needed)&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 Macro Configuration&lt;a href=&quot;#44-no_otp_fuse-macro-configuration&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FSBL build macros in &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;# Comment this out to enable OTP configuration&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;Configuration&lt;/th&gt;&lt;th&gt;Description&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Disable &lt;code&gt;NO_OTP_FUSE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Required on first flash, FSBL will auto-configure OTP fuses&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Enable &lt;code&gt;NO_OTP_FUSE&lt;/code&gt;&lt;/td&gt;&lt;td&gt;For development, skip OTP configuration&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;4.5 Build Outputs&lt;a href=&quot;#45-build-outputs&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;File&lt;/th&gt;&lt;th&gt;Location&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;5. Signing &amp;amp; Flashing&lt;a href=&quot;#5-signing--flashing&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;5.1 Why Signing is Required&lt;a href=&quot;#51-why-signing-is-required&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;STM32N6’s external Flash stores critical firmware. The chip’s Boot ROM only loads images with &lt;strong&gt;correctly signed Headers&lt;/strong&gt;. The signing tool adds a V2.3 format header to the .bin file.&lt;/p&gt;
&lt;h3&gt;5.2 Manual Signing Commands&lt;a href=&quot;#52-manual-signing-commands&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 signing&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 signing&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 Signing Parameter Reference&lt;a href=&quot;#53-signing-parameter-reference&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;Parameter&lt;/th&gt;&lt;th&gt;Description&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;Input .bin file path&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, development mode, no actual signature verification&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 address offset&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 type&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 requires 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;Required&lt;/strong&gt;, payload aligned to 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;Silent mode, no overwrite confirmation popup&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;5.4 Flash Addresses&lt;a href=&quot;#54-flash-addresses&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;File&lt;/th&gt;&lt;th&gt;Address&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; (optional)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h3&gt;5.5 Post-Flash Behavior&lt;a href=&quot;#55-post-flash-behavior&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;Stage&lt;/th&gt;&lt;th&gt;Behavior&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;FSBL initialization&lt;/td&gt;&lt;td&gt;Red LED (PG.10) blinks 3 times&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Jump to Appli&lt;/td&gt;&lt;td&gt;Green (PG.00) and Blue (PG.08) LEDs blink alternately&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;When flashing external XSPI Flash, CubeProgrammer needs the corresponding External Loader file:&lt;/p&gt;













&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Board&lt;/th&gt;&lt;th&gt;Loader File&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; (usually in CubeProgrammer installation directory)&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Location&lt;/strong&gt;: Usually at &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;Pitfall&lt;/strong&gt;: Without loading the correct .stldr file, CubeProgrammer cannot recognize external Flash, causing errors or failure to write during flashing.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;6. Debugging Methods&lt;a href=&quot;#6-debugging-methods&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;6.1 DEV Mode Debugging (Recommended)&lt;a href=&quot;#61-dev-mode-debugging-recommended&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Set BOOT1 = 2-3 (DEV mode)&lt;/li&gt;
&lt;li&gt;IDE loads &lt;code&gt;FSBL/build/Template_FSBL_LRUN_FSBL.elf&lt;/code&gt; to RAM&lt;/li&gt;
&lt;li&gt;Set breakpoints in Appli code&lt;/li&gt;
&lt;li&gt;Debug/Run&lt;/li&gt;
&lt;li&gt;FSBL runs → loads Appli → breakpoints hit&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;6.2 Flash Mode&lt;a href=&quot;#62-flash-mode&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;No source-level debugging possible. Rely on LED / UART / ITM.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;7. Project File Structure&lt;a href=&quot;#7-project-file-structure&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              # Project documentation&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── SKILL.md              # Skill documentation&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── README.md              # Official documentation&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── Template_FSBL_LRUN.ioc # CubeMX configuration&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 subproject&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 main program&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   │   ├── extmem.c       # External memory initialization&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 # Build macros&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 subproject&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 main program&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 drivers (in-project)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── Secure_nsclib/          # Secure/non-secure call library&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;├── gcc-arm-none-eabi.cmake # Toolchain configuration&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;└── mx-generated.cmake       # Main CMake configuration&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;8. References&lt;a href=&quot;#8-references&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;ST Official Community Posts&lt;a href=&quot;#st-official-community-posts&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 Official PDFs&lt;a href=&quot;#st-official-pdfs&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 Schematic (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;9. Quick Troubleshooting Guide&lt;a href=&quot;#9-quick-troubleshooting-guide&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;Symptom&lt;/th&gt;&lt;th&gt;Possible Cause&lt;/th&gt;&lt;th&gt;Solution&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;Flash error “Core locked”&lt;/td&gt;&lt;td&gt;Option Bytes locked&lt;/td&gt;&lt;td&gt;Hold Reset while flashing, or Mass Erase&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Flash error “Write protection”&lt;/td&gt;&lt;td&gt;Read protection RDP enabled&lt;/td&gt;&lt;td&gt;Use Mass Erase&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Flash mode not running&lt;/td&gt;&lt;td&gt;Missing &lt;code&gt;-align&lt;/code&gt; in signature&lt;/td&gt;&lt;td&gt;Re-sign with &lt;code&gt;-align&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Flash mode not running&lt;/td&gt;&lt;td&gt;OTP not configured&lt;/td&gt;&lt;td&gt;On first flash, disable NO_OTP_FUSE so FSBL configures OTP&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Chip unresponsive&lt;/td&gt;&lt;td&gt;Debugger disconnected&lt;/td&gt;&lt;td&gt;Press Reset, reconnect&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Breakpoints not hitting in debug&lt;/td&gt;&lt;td&gt;Using Flash mode&lt;/td&gt;&lt;td&gt;Switch to DEV mode, BOOT1=2-3&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;No .bin file after build&lt;/td&gt;&lt;td&gt;CMakeLists.txt missing post-build&lt;/td&gt;&lt;td&gt;Add objcopy commands&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Signing “binary not found”&lt;/td&gt;&lt;td&gt;PowerShell quoting issue&lt;/td&gt;&lt;td&gt;Use &lt;code&gt;&amp;amp; &quot;...&quot;&lt;/code&gt; or run in 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:Embedded</category><category>tag:Debug</category></item><item><title>STM32 SimpleFOC Position Servo: From Zero to Stable, Full Record of 2 Hard Bug Fixes</title><link>https://www.729dhs.site/en/post/stm32-simplefoc-debug-journal</link><guid isPermaLink="false">en:stm32-simplefoc-debug-journal</guid><description>Complete process of building a position servo system with STM32F103 + SimpleFOC Mini + AS5600. From uint16_t integer overflow to PID Reset transient spike, each bug&apos;s investigation and fix is documented.</description><pubDate>Mon, 01 Jun 2026 02:30:00 GMT</pubDate><content:encoded>&lt;h2&gt;1. Project Background&lt;a href=&quot;#1-project-background&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Building a FOC position servo system from scratch using STM32F103C8T6 (Blue Pill) to drive a 2804 gimbal motor.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The “from scratch” here doesn’t start from the SimpleFOC library — it starts from CubeMX-generated HAL code, with hand-written FOC core algorithm, PID controller, encoder driver, and serial command parsing. The entire development cycle took about two weeks, with &lt;strong&gt;debugging taking 80% of the time&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;End result: motor holds position rock-solid, pushed two turns and released, it returns along the same path. PID parameters adjustable online with no transient spikes. Behind this: 2 real bug localizations and fixes — plus records of several “thought this was the root cause” false leads.&lt;/p&gt;
&lt;h3&gt;Hardware Architecture&lt;a href=&quot;#hardware-architecture&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 magnetic encoder (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 interrupt) → Control loop tick&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;Driver&lt;/strong&gt;: SimpleFOC Mini (3-phase half-bridge)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Encoder&lt;/strong&gt;: AS5600 12-bit magnetic encoder (I2C interface)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Motor&lt;/strong&gt;: 2804 gimbal motor, 12-slot 14-pole (7 pole pairs), low resistance&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Software Architecture&lt;a href=&quot;#software-architecture&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 interrupt → foc_tick flag&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  ├─ Sensor read → AS5600 (software I2C)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  ├─ Angle unwrapping → single-turn absolute → cumulative angle&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  ├─ PID control → D-on-measurement + low-pass filter&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  ├─ SVPWM → three-phase sine wave (center-aligned PWM)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  └─ UART command parsing → ? T90 Kp0.1 ...&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;2. False Lead: Hardware I2C Freeze?&lt;a href=&quot;#2-false-lead-hardware-i2c-freeze&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;Symptom&lt;a href=&quot;#symptom&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Motor runs normally for 30~60 seconds, then suddenly “loses power” — encoder reading freezes at a certain value, rotating the motor by hand produces no corrective torque, and auto-print stops. Recovery after power cycle, repeats after running for a while.&lt;/p&gt;
&lt;h3&gt;Investigation&lt;a href=&quot;#investigation&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; command (encoder diagnostics) showed a &lt;strong&gt;different value&lt;/strong&gt; than the &lt;code&gt;?&lt;/code&gt; status command during one failure — &lt;code&gt;?&lt;/code&gt; reported Raw=1445, &lt;code&gt;D&lt;/code&gt; reported Raw=4030. Ruled out encoder hardware fault.&lt;/li&gt;
&lt;li&gt;I2C error count stayed at 0 — HAL didn’t report errors, but returned stale register values, suggesting the I2C peripheral may have entered a “fake success” state.&lt;/li&gt;
&lt;li&gt;Checking STM32F103 Errata: &lt;strong&gt;I2C peripheral can freeze in BUSY state under specific bus timing conditions&lt;/strong&gt;, software cannot recover via normal means, only peripheral reset works.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Attempted Fix&lt;a href=&quot;#attempted-fix&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;// When readings stay unchanged for 100 consecutive times, try resetting I2C peripheral&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;Result&lt;a href=&quot;#result&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After switching to software I2C, the problem persisted. The real root cause was later found to be &lt;strong&gt;uint16_t tick overflow&lt;/strong&gt; — after fixing that, everything stabilized. The software I2C changes were kept (more reliable), but I2C itself &lt;strong&gt;was not the root cause of this symptom&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lesson&lt;/strong&gt;: One symptom can have multiple “suspects.” Fixing A doesn’t mean you fixed it. When you can’t confirm the root cause, look for the most directly reproducible clue first (time pattern).&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;3. False Lead: PID Positive Feedback?&lt;a href=&quot;#3-false-lead-pid-positive-feedback&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;Symptom&lt;a href=&quot;#symptom-1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After power-on, motor doesn’t hold position, rotates continuously. Sending &lt;code&gt;T90&lt;/code&gt; causes motor to accelerate instead of stopping.&lt;/p&gt;
&lt;h3&gt;Investigation&lt;a href=&quot;#investigation-1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Checked PID setpoint/measurement parameter passing — logic seemed possibly wrong.&lt;/p&gt;
&lt;h3&gt;Result&lt;a href=&quot;#result-1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Actual code inspection revealed &lt;strong&gt;PID sign parameters were not inverted&lt;/strong&gt; — this wasn’t a real bug. The real cause of the symptom was also uint16_t tick overflow — the control loop wasn’t running at all.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lesson&lt;/strong&gt;: Without trace tools, it’s easy to interpret “not running” as “running wrong.” First confirm whether code is actually executing, then analyze runtime behavior.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;4. False Lead: Stack Overflow?&lt;a href=&quot;#4-false-lead-stack-overflow&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;Symptom&lt;a href=&quot;#symptom-2&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Motor “dies” every few tens of seconds — auto-print stops, motor 吸附在磁极位 (stuck at magnetic pole position), serial commands unresponsive.&lt;/p&gt;
&lt;h3&gt;Investigation&lt;a href=&quot;#investigation-2&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Checked stack size: &lt;code&gt;_Min_Stack_Size = 0x400&lt;/code&gt; (only 1KB) in &lt;code&gt;STM32F103XX_FLASH.ld&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;snprintf&lt;/code&gt; + &lt;code&gt;%f&lt;/code&gt; pulls in &lt;code&gt;_printf_float&lt;/code&gt;, single call chain stack consumption &amp;gt;700 bytes&lt;/li&gt;
&lt;li&gt;Tried expanding stack to 2KB + changing large buffers to static&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Result&lt;a href=&quot;#result-2&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Problem persisted after changes. Real root cause was still uint16_t tick overflow.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lesson&lt;/strong&gt;: In embedded, &lt;code&gt;snprintf&lt;/code&gt; + &lt;code&gt;%f&lt;/code&gt; does eat stack, but that wasn’t the issue here. Hypothesis + fix + verify — don’t keep trusting a fix that isn’t working.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;5. Bug #1 — uint16_t Tick Overflow + C Integer Promotion Trap&lt;a href=&quot;#5-bug-1--uint16_t-tick-overflow--c-integer-promotion-trap&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;This is the bug that actually solved the problem. After fixing it, the system ran stably.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Symptom&lt;a href=&quot;#symptom-3&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Motor “freezes” every ~60 seconds — auto-print stops, motor unresponsive, but serial commands &lt;strong&gt;still work&lt;/strong&gt;. Observed tick_count wrapping from 65535 back to 0 (uint16_t overflow), exactly matching the failure timestamps.&lt;/p&gt;
&lt;h3&gt;Root Cause Analysis&lt;a href=&quot;#root-cause-analysis&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is an obscure bug caused by &lt;strong&gt;C language Integer Promotion rules&lt;/strong&gt;:&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;// What you see:&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;// What the compiler actually generates:&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// uint16_t - uint16_t → promoted to 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;//  When tick_count wraps to 0:&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 → control update never fires!&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;C11 Standard §6.3.1.1: when &lt;code&gt;uint16_t&lt;/code&gt; (narrower than &lt;code&gt;int&lt;/code&gt;) participates in arithmetic, it’s first promoted to &lt;code&gt;int&lt;/code&gt; (signed). &lt;strong&gt;The unsigned wrap-around behavior is destroyed during promotion&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;This is a very subtle bug — the code logic looks correct (unsigned subtraction naturally wraps), but the compiler turns it into signed arithmetic, producing a negative number on overflow, making the comparison 永远不成立 (never true).&lt;/p&gt;
&lt;h3&gt;Fix&lt;a href=&quot;#fix&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Change &lt;code&gt;tick_count&lt;/code&gt; and related variables to &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;       // Overflows in 49 days, won&apos;t trigger during runtime&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;On 32-bit ARM, &lt;code&gt;uint32_t&lt;/code&gt; = &lt;code&gt;unsigned int&lt;/code&gt;, same rank as &lt;code&gt;signed int&lt;/code&gt;. C standard’s “usual arithmetic conversions” specify &lt;strong&gt;unsigned wins when ranks are equal&lt;/strong&gt;, so &lt;code&gt;uint32_t - uint32_t&lt;/code&gt; stays in unsigned domain. This is the &lt;strong&gt;principle fix&lt;/strong&gt; — not just delaying overflow, but ensuring subtraction always happens in unsigned domain.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lesson&lt;/strong&gt;: In embedded C, subtraction of &lt;code&gt;uint8_t&lt;/code&gt; and &lt;code&gt;uint16_t&lt;/code&gt; is &lt;strong&gt;unreliable&lt;/strong&gt; — either cast strongly &lt;code&gt;(uint16_t)(a - b)&lt;/code&gt;, or use &lt;code&gt;uint32_t&lt;/code&gt; directly. This bug took two days to locate at the compiler level. &lt;strong&gt;Confirmed effective fix: change uint16_t to uint32_t&lt;/strong&gt;.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;6. Bug #2 — PID_Reset D Term Velocity Spike&lt;a href=&quot;#6-bug-2--pid_reset-d-term-velocity-spike&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;This bug is real too — it causes transient shock when adjusting PID parameters.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Symptom&lt;a href=&quot;#symptom-4&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Sending &lt;code&gt;kp0&lt;/code&gt; (set Kp to 0) via serial, motor suddenly kicks hard and flies out. After that, even restoring Kp, the motor has drifted to an unknown position.&lt;/p&gt;
&lt;h3&gt;Root Cause&lt;a href=&quot;#root-cause&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; clears &lt;code&gt;prev_measurement&lt;/code&gt; to zero. In the next control cycle:&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 →瞬间饱和 → motor gets kicked by 40% duty cycle&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Fix: Sentinel Value&lt;a href=&quot;#fix-sentinel-value&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;  // Legal angle 0~2π can never be here&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;  // Sentinel&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // deriv_filtered not cleared, first frame D skipped, re-accumulate from zero&lt;/span&gt;&lt;/span&gt;
&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;        // First frame → skip D, just record current value&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;        // Normal D calculation&lt;/span&gt;&lt;/span&gt;
&lt;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;Effect: No transient shock when adjusting PID parameters&lt;/strong&gt;.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Lesson&lt;/strong&gt;: Reset functions cannot blindly zero everything. Any stateful variable must use a sentinel value to mark “uninitialized” state during Reset.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;7. Lessons Summary&lt;a href=&quot;#7-lessons-summary&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;Issue&lt;/th&gt;&lt;th&gt;Category&lt;/th&gt;&lt;th&gt;Conclusion&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;False lead&lt;/td&gt;&lt;td&gt;Changed to software I2C, but root cause was uint16_t overflow&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2&lt;/td&gt;&lt;td&gt;PID sign&lt;/td&gt;&lt;td&gt;False lead&lt;/td&gt;&lt;td&gt;Parameters actually not inverted; real cause was control loop not running&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3&lt;/td&gt;&lt;td&gt;Stack overflow&lt;/td&gt;&lt;td&gt;False lead&lt;/td&gt;&lt;td&gt;Expanded stack, but root cause was still uint16_t overflow&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;4&lt;/td&gt;&lt;td&gt;&lt;strong&gt;uint16_t integer promotion&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Real bug&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Confirmed fix: change to 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 spike&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Real bug&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;&lt;strong&gt;Confirmed fix: sentinel value&lt;/strong&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Both real bugs were traced to root cause and fixed. The three “suspects” were actually &lt;strong&gt;symptoms’ side effects rather than root causes&lt;/strong&gt; — when uint16_t overflow caused the control loop to stop, all “control not working” manifestations were mistakenly thought to have independent root causes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Not finding the root cause means not truly fixed.&lt;/strong&gt; The same symptom may have multiple people shouting about it, but you can only trust the first (most timely) clue — time patterns are the best debug information.&lt;/p&gt;
&lt;hr /&gt;
&lt;blockquote&gt;
&lt;p&gt;Full source code: &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>tag:STM32</category><category>tag:FOC</category><category>tag:Motor Control</category><category>tag:PID</category><category>tag:Embedded</category><category>tag:Debug</category><category>tag:AS5600</category></item><item><title>Delta Parallel Robot — Building a Kinematics Library from Scratch</title><link>https://www.729dhs.site/en/post/delta-robot-kinematics-library</link><guid isPermaLink="false">en:delta-robot-kinematics-library</guid><description>Recording the kinematics derivation, MATLAB verification, and C++ library implementation process for a Delta parallel robot. Static platform radius 115mm, driving arm 125mm, passive arm 338mm, moving platform diameter 150mm.</description><pubDate>Thu, 14 May 2026 23:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently I finished writing the kinematics library for a Delta parallel robot. Let me record the process and key data.&lt;/p&gt;
&lt;h2&gt;Mechanical Parameters&lt;a href=&quot;#mechanical-parameters&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;Parameter&lt;/th&gt;&lt;th&gt;Value&lt;/th&gt;&lt;th&gt;Description&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;Static platform radius (center to motor shaft)&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;Moving platform radius (center to ball joint, 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;Driving arm (big arm) length&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;Passive arm (small arm/rod) length&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;h2&gt;Core Kinematics&lt;a href=&quot;#core-kinematics&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;Inverse Kinematics (IK)&lt;a href=&quot;#inverse-kinematics-ik&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Given end-effector position &lt;code&gt;(x, y, z)&lt;/code&gt;, find three motor angles &lt;code&gt;θ₁, θ₂, θ₃&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For each leg, transform the problem to a local coordinate system, simplifying to planar 2R linkage inverse kinematics:&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;Solution:&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;where &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;Key detail: The projection of the passive arm outside the rotation plane needs to be processed as effective length &lt;code&gt;L2_eff = sqrt(L2² - y_local²)&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Forward Kinematics (FK)&lt;a href=&quot;#forward-kinematics-fk&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Given &lt;code&gt;θ₁, θ₂, θ₃&lt;/code&gt;, find end-effector position. Use Newton iteration to solve for the three-sphere intersection point, converging to error &amp;lt; 1e-6 mm.&lt;/p&gt;
&lt;h2&gt;MATLAB Verification Results&lt;a href=&quot;#matlab-verification-results&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Verified IK→FK consistency in MATLAB, &lt;strong&gt;error is 0.0000 mm at all test points&lt;/strong&gt;.&lt;/p&gt;
&lt;h3&gt;Workspace&lt;a href=&quot;#workspace&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Scanned with 20mm grid, total 5928 reachable points:&lt;/p&gt;

































&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Z (mm)&lt;/th&gt;&lt;th&gt;Max Radius (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;The workspace is dome-shaped, Z range approximately -460 ~ -100 mm, maximum horizontal radius approximately 250mm.&lt;/p&gt;
&lt;h2&gt;Code Organization&lt;a href=&quot;#code-organization&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        → vectors, angles, utilities&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── delta_param.h         → mechanical parameter struct&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── delta_kinematics.h    → IK/FK/Jacobian&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   ├── delta_trajectory.h    → trajectory planning (interpolation + S-curve)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   └── delta_control.h       → three-axis coordinated control interface&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         → kinematics verification + workspace calculation&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;│   └── workspace.m            → workspace visualization&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;Next Steps&lt;a href=&quot;#next-steps&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Run IK calculation on STM32F407&lt;/li&gt;
&lt;li&gt;Cooperate with stepper motors DRV8825/TMC2209 for open-loop position control&lt;/li&gt;
&lt;li&gt;Later add encoder for closed-loop&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 Library Design Notes 2</title><link>https://www.729dhs.site/en/post/stm32-library-design2-note</link><guid isPermaLink="false">en:stm32-library-design2-note</guid><description>STM32 driver library object-oriented programming design, the evolution from hardcoding to polymorphism.</description><pubDate>Wed, 13 May 2026 16:05:13 GMT</pubDate><content:encoded>&lt;h2&gt;Stage 1: Newbie Village - Hardcoding&lt;a href=&quot;#stage-1-newbie-village---hardcoding&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;Scenario&lt;a href=&quot;#scenario&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;We have a small car chassis control program that needs to control two DC motors.&lt;/p&gt;
&lt;h3&gt;Code&lt;a href=&quot;#code&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;// Beginner approach: write specific operations each time&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 wheel 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, &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;    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;    // Right wheel 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_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;    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;    // Stop left wheel&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;    // Stop right wheel&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;Problems&lt;a href=&quot;#problems&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Code duplication&lt;/strong&gt;: Each operation requires writing a bunch of register/library function calls&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Not portable&lt;/strong&gt;: Changing MCU requires modifying all files&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unreadable&lt;/strong&gt;: Looking at the code, you can’t tell it’s “controlling motors”, only that it’s “operating GPIO and PWM”&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Hard to maintain&lt;/strong&gt;: To change motor logic, you need to find all the places it’s called&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Core Pain Point&lt;a href=&quot;#core-pain-point&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Business logic (making the car go forward) is mixed with hardware operations (pulling GPIO high, writing PWM)&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;Stage 2: Function Encapsulation (Gathering Repeated Code)&lt;a href=&quot;#stage-2-function-encapsulation-gathering-repeated-code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;Concept&lt;a href=&quot;#concept&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Package hardware operations into functions; upper layers call function names without looking at internal implementation.&lt;/p&gt;
&lt;h3&gt;Code&lt;a href=&quot;#code-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 - Hardware operation encapsulation&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 - Business logic becomes clearer&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;Advantages&lt;a href=&quot;#advantages&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Improved code readability&lt;/li&gt;
&lt;li&gt;Hardware operations concentrated in one file, changing MCU only requires modifying this file&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;New Problems&lt;a href=&quot;#new-problems&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Function proliferation&lt;/strong&gt;: Each action gets its own function (turn left, turn right, forward, backward, with acceleration…), function count explodes&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Inconsistent parameters&lt;/strong&gt;: Some functions use &lt;code&gt;uint16_t speed&lt;/code&gt;, others use &lt;code&gt;float duty&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Poor extensibility&lt;/strong&gt;: Adding a new motor requires writing 4 new functions&lt;/li&gt;
&lt;/ol&gt;
&lt;hr /&gt;
&lt;h2&gt;Stage 3: Parameter-Driven (Using Parameters Instead of Function Names)&lt;a href=&quot;#stage-3-parameter-driven-using-parameters-instead-of-function-names&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;Concept&lt;a href=&quot;#concept-1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Don’t write separate functions for each action; instead, write one “generic function” and use parameters to distinguish actions.&lt;/p&gt;
&lt;h3&gt;Code&lt;a href=&quot;#code-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;// Use one function instead of multiple&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;  // Left wheel&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;  // Right wheel&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;            // Similar...&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;// Usage&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;Advantages&lt;a href=&quot;#advantages-1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Function count reduced from &lt;code&gt;motor_count × action_count&lt;/code&gt; to 1&lt;/li&gt;
&lt;li&gt;Adding new actions only requires adding &lt;code&gt;case&lt;/code&gt;, no new functions needed&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;New Problems&lt;a href=&quot;#new-problems-1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Too many parameters&lt;/strong&gt;: Want to support acceleration? Add parameter &lt;code&gt;uint8_t accel&lt;/code&gt;; want to support direction? Add parameter &lt;code&gt;uint8_t dir&lt;/code&gt;… parameter list keeps growing&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Type unsafe&lt;/strong&gt;: Passing wrong value for &lt;code&gt;action&lt;/code&gt; parameter (passing 255 instead of FORWARD), compiler doesn’t complain&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Poor readability&lt;/strong&gt;: What does &lt;code&gt;motor_control(0, 1, 500)&lt;/code&gt; mean? Need to check documentation or function definition&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Evolution: Using Struct for Parameter Passing&lt;a href=&quot;#evolution-using-struct-for-parameter-passing&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;// Pack multiple parameters into one struct&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=left wheel, 1=right wheel&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;  // Duration&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;    // Execute based on fields in 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;// Usage&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;Advantages&lt;a href=&quot;#advantages-2&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Clear parameters with field names&lt;/li&gt;
&lt;li&gt;Adding parameters only requires modifying the struct, not the function signature&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Stage 4: State Machine + Non-Blocking (Letting the CPU Do Other Things)&lt;a href=&quot;#stage-4-state-machine--non-blocking-letting-the-cpu-do-other-things&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;Problem&lt;a href=&quot;#problem&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Previous approaches are all &lt;strong&gt;blocking&lt;/strong&gt;: &lt;code&gt;HAL_Delay(1000)&lt;/code&gt; makes the CPU wait idly for 1 second, doing nothing.&lt;/p&gt;
&lt;h3&gt;Concept&lt;a href=&quot;#concept-2&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Turn “waiting” into “periodic checking”: each call does only a small step, then returns. Main loop continuously calls until complete.&lt;/p&gt;
&lt;h3&gt;Code&lt;a href=&quot;#code-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;  // Get current time&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;        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;        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;            // Time&apos;s up, stop&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;            // Still running&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;// Main loop (non-blocking)&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;  // Left wheel runs for 1 second&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;  // Right wheel runs for 1 second&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;  // Call every 10ms&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        // During these 10ms间隙, can do other things&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;        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;Core Changes&lt;a href=&quot;#core-changes&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;Blocking&lt;/th&gt;&lt;th&gt;Non-Blocking&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; + main loop polling&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;CPU idles for 1 second&lt;/td&gt;&lt;td&gt;CPU checks every 10ms, works on other things the rest of the time&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Can only execute actions sequentially&lt;/td&gt;&lt;td&gt;Can handle multiple tasks simultaneously&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;Stage 5: Struct Encapsulation for Multiple Instances (Preparing for Polymorphism)&lt;a href=&quot;#stage-5-struct-encapsulation-for-multiple-instances-preparing-for-polymorphism&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;Problem&lt;a href=&quot;#problem-1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Currently each motor is global state; adding a new motor requires manual copy-paste of code.&lt;/p&gt;
&lt;h3&gt;Concept&lt;a href=&quot;#concept-3&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Package motor-related data and methods into a struct, operate via pointers.&lt;/p&gt;
&lt;h3&gt;Code&lt;a href=&quot;#code-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;// Motor &quot;class&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;    // Properties (data)&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;    // Methods (function pointers)&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;// Method implementations&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;    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;// Create instances&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;// Usage&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;    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;Key Point: &lt;code&gt;self&lt;/code&gt; Pointer&lt;a href=&quot;#key-point-self-pointer&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Each method’s first parameter is &lt;code&gt;self&lt;/code&gt;, pointing to the instance that called it. This allows the same &lt;code&gt;motor_update_impl&lt;/code&gt; function to operate on different motor data.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Stage 6: Hardware Abstraction (Changing MCU Without Modifying Upper Layer Code)&lt;a href=&quot;#stage-6-hardware-abstraction-changing-mcu-without-modifying-upper-layer-code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;Problem&lt;a href=&quot;#problem-2&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Currently &lt;code&gt;set_pwm()&lt;/code&gt; function still directly calls HAL library; changing MCU requires modifying this function’s internals.&lt;/p&gt;
&lt;h3&gt;Concept&lt;a href=&quot;#concept-4&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Abstract hardware operations into an operations table (function pointer collection); upper layers only call the operations table, not HAL directly.&lt;/p&gt;
&lt;h3&gt;Code&lt;a href=&quot;#code-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;// Hardware operations table (abstraction layer)&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 implementation&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;// Upper layer code depends on abstraction, not concrete implementation&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;  // Change platform by modifying only this line&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// Motor control code changed to&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;Effect&lt;a href=&quot;#effect&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;Platform&lt;/th&gt;&lt;th&gt;Code that needs to change&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;Implementations of &lt;code&gt;stm32_pwm_set&lt;/code&gt; and similar functions&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;ESP32&lt;/td&gt;&lt;td&gt;Write a set of &lt;code&gt;esp32_pwm_set&lt;/code&gt; and similar functions, then &lt;code&gt;HW = &amp;amp;ESP32_Hardware&lt;/code&gt;&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Simulation testing&lt;/td&gt;&lt;td&gt;Write a set of mock functions, run on PC&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Upper layer business logic (motor control, chassis control) doesn’t need a single line of code change!&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Stage 7: Polymorphism (Same Interface, Different Behaviors)&lt;a href=&quot;#stage-7-polymorphism-same-interface-different-behaviors&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;Scenario&lt;a href=&quot;#scenario-1&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Now we have two types of motors:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;DC motor&lt;/strong&gt;: Needs PID closed-loop control&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stepper motor&lt;/strong&gt;: Needs pulse signaling control&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Problem&lt;a href=&quot;#problem-3&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Their behaviors are completely different, but we want the upper layer to use a unified interface: &lt;code&gt;motor_update()&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;Solution: Operations Table + Derived Structs&lt;a href=&quot;#solution-operations-table--derived-structs&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;// ========== Step 1: Define common interface ==========&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;  // Operations table (tells how to operate)&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;    // Other common properties...&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;};&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// ========== Step 2: Implement DC motor ==========&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;           // Inherit common part&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 parameters&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 calculation&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;// ========== Step 3: Implement stepper motor ==========&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;           // Inherit common part&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;        // Send one pulse&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;  // Here speed actually represents 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;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;// ========== Step 4: Create objects ==========&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;// ========== Step 5: Unified calling ==========&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;    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;  // Same call, different behavior!&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;The Magic of Polymorphism&lt;a href=&quot;#the-magic-of-polymorphism&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] (DC motor):&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    motors[0]-&amp;gt;ops-&amp;gt;update → executes dc_update() → PID calculation → set 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] (stepper motor):&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    motors[1]-&amp;gt;ops-&amp;gt;update → executes stepper_update() → send pulse → take one step&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;The same code &lt;code&gt;motors[i]-&amp;gt;ops-&amp;gt;update(motors[i])&lt;/code&gt;, but does completely different things!&lt;/strong&gt;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Summary: Architecture Evolution Roadmap&lt;a href=&quot;#summary-architecture-evolution-roadmap&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;Stage&lt;/th&gt;&lt;th&gt;Core Concept&lt;/th&gt;&lt;th&gt;Key Code Characteristics&lt;/th&gt;&lt;th&gt;Problem Solved&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;1. Hardcoding&lt;/td&gt;&lt;td&gt;Write wherever needed&lt;/td&gt;&lt;td&gt;Register operations scattered everywhere&lt;/td&gt;&lt;td&gt;None&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;2. Function encapsulation&lt;/td&gt;&lt;td&gt;Package hardware operations&lt;/td&gt;&lt;td&gt;&lt;code&gt;motor_left_forward()&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Readability, centralized modification&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;3. Parameter-driven&lt;/td&gt;&lt;td&gt;Use parameters to distinguish behavior&lt;/td&gt;&lt;td&gt;&lt;code&gt;motor_control(id, action, speed)&lt;/code&gt;&lt;/td&gt;&lt;td&gt;Reduce function count&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;4. Non-blocking&lt;/td&gt;&lt;td&gt;State machine + polling&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 not idle&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;5. Multiple instances&lt;/td&gt;&lt;td&gt;Struct encapsulation&lt;/td&gt;&lt;td&gt;&lt;code&gt;Motor_t&lt;/code&gt; + &lt;code&gt;self&lt;/code&gt; pointer&lt;/td&gt;&lt;td&gt;Support multiple objects&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;6. Hardware abstraction&lt;/td&gt;&lt;td&gt;Operations table&lt;/td&gt;&lt;td&gt;&lt;code&gt;Hardware_t&lt;/code&gt; + function pointers&lt;/td&gt;&lt;td&gt;Cross-platform portability&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;7. Polymorphism&lt;/td&gt;&lt;td&gt;Each object has its own operations table&lt;/td&gt;&lt;td&gt;&lt;code&gt;MotorOps_t&lt;/code&gt; + derived structs&lt;/td&gt;&lt;td&gt;Same interface, different behaviors&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;Finally: When to Use Which?&lt;a href=&quot;#finally-when-to-use-which&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;Project Scale&lt;/th&gt;&lt;th&gt;Recommended Stage&lt;/th&gt;&lt;th&gt;Reason&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;1-2 files, personal toy&lt;/td&gt;&lt;td&gt;Stage 2-3&lt;/td&gt;&lt;td&gt;Sufficient, no over-engineering&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Multiple modules, team development&lt;/td&gt;&lt;td&gt;Stage 4-5&lt;/td&gt;&lt;td&gt;Maintainability matters&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Platform-switching product&lt;/td&gt;&lt;td&gt;Stage 6&lt;/td&gt;&lt;td&gt;Hardware abstraction is essential&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;Multiple device types (motors, lights, sensors)&lt;/td&gt;&lt;td&gt;Stage 7&lt;/td&gt;&lt;td&gt;Polymorphism makes extension simple&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:Library Design</category><category>tag:HAL</category><category>tag:Embedded</category></item><item><title>STM32 库设计笔记2</title><link>https://www.729dhs.site/en/post/stm32-library-design2</link><guid isPermaLink="false">en: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>Wheel-Legged Robot 2-DOF Closed-Loop Linkage Forward and Inverse Kinematics Derivation</title><link>https://www.729dhs.site/en/post/2dof-linkage-forward-inverse-kinematics</link><guid isPermaLink="false">en:2dof-linkage-forward-inverse-kinematics</guid><description>Forward and inverse kinematics analytical derivation for a wheel-legged robot leg with 2-DOF double parallelogram linkage mechanism, plus Python numerical implementation. The mechanism is ultimately equivalent to a standard 2R robotic arm.</description><pubDate>Mon, 04 May 2026 06:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;1. Problem Background&lt;a href=&quot;#1-problem-background&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Each leg of a wheel-legged robot needs both &lt;strong&gt;wheel rolling&lt;/strong&gt; and &lt;strong&gt;leg obstacle-crossing&lt;/strong&gt; capabilities. The mechanism design discussed here uses two coaxial motors, transmitting power to the wheel through a figure-8 shaped double parallelogram linkage, achieving decoupled control of leg swinging and wheel steering.&lt;/p&gt;
&lt;p&gt;Compared to traditional belt drive or gear drive solutions, this all-linkage mechanism has advantages of &lt;strong&gt;zero backlash, high structural stiffness, no wearing parts&lt;/strong&gt;, making it especially suitable for wheel-legged robot applications requiring high-precision end-effector position control.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/Kinematics/p2.png&quot; alt=&quot;Wheel-leg physical photo&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;
&lt;figure&gt;&lt;img src=&quot;/img/Note/Kinematics/p1.png&quot; alt=&quot;Simulation diagram&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;pre&gt;flowchart TD
  M[&quot;Motor A (θa)&quot;] --&amp;gt; A[&quot;bar_a (three-arm杆 O-P1-P2)&quot;]
  M2[&quot;Motor B (θb)&quot;] --&amp;gt; B[&quot;bar_b (two-arm杆 O-P3)&quot;]
  A --&amp;gt; D[&quot;bar_d (three-arm直杆 P1-P4-P5)&quot;]
  B --&amp;gt; C[&quot;bar_c (two-arm杆 P3-P4)&quot;]
  C --&amp;gt; D
  D --&amp;gt; E[&quot;bar_e (two-arm杆 P5-P6)&quot;]
  A --&amp;gt; F[&quot;bar_f (three-arm直杆 P2-P6-P7)&quot;]
  E --&amp;gt; F
  F --&amp;gt; W[&quot;P7 — Hub motor (end-effector)&quot;]&lt;/pre&gt;
&lt;p&gt;Two parallelograms nested in a figure-8 shape:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Parallelogram 1&lt;/strong&gt;: O – P1 – P4 – P3, side lengths 48.4 × 57.3 mm&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parallelogram 2&lt;/strong&gt;: P1 – P2 – P6 – P5, side lengths 59 × 32.4 mm&lt;/li&gt;
&lt;/ul&gt;
&lt;div&gt;
&lt;p&gt;The key point is: all three-arm bars (bar_a, bar_d, bar_f) are &lt;strong&gt;straight bars&lt;/strong&gt; (three points collinear). This geometric constraint is the core prerequisite for subsequent analytical simplification.&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;2. Forward Kinematics Derivation&lt;a href=&quot;#2-forward-kinematics-derivation&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The goal of forward kinematics is: given motor angles &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;, find the position of end-effector &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 Point Coordinates Step-by-Step Solution&lt;a href=&quot;#21-point-coordinates-step-by-step-solution&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Step 1 — P1, P2 on bar_a&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Using O as origin, rotated by &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;Here &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;, because bar_a is a straight bar, P1 lies on the O–P2 line.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2 — P3 on bar_b&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 — P4 on bar_d (intersection of two circles)&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;From parallelogram 1, we know &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; are fixed values, so P4 is the intersection of two circles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Circle center &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;, radius &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;Circle center &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;, radius &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;The analytical solution process for intersection of two circles is as follows. Let vector &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;, distance between centers &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;, then:&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;Where &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; is the &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; rotation matrix, the &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; sign corresponds to two assembly modes, denoted as &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 Core Simplification: Straight Bar Constraint&lt;a href=&quot;#22-core-simplification-straight-bar-constraint&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;After obtaining P4, the direction angle of bar_d is:&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;Because bar_d is a &lt;strong&gt;straight bar&lt;/strong&gt;, P5 is collinear with P1, P4, and &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;, so:&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;Substituting the relationship of parallelogram 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;, eliminating 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;Note that the direction of &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; is the same as &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; (opposite sides of parallelogram are parallel), and &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;, so:&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 is also a straight bar, P7 is in the opposite extension direction of 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 Final Analytical Expression&lt;a href=&quot;#23-final-analytical-expression&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Substituting &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 Physical Meaning&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  desc The mechanism is equivalent to a standard 2R planar robotic arm&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 First Link&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      desc O → P₂, length L₁ = 107.4 mm, angle θ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 Second Link&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      desc P₂ → P₇, length L₂ = 128 mm, angle θ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 End-effector&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      desc Hub motor position 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;This conclusion is very elegant: &lt;strong&gt;Regardless of how the double parallelogram bends, the position of end-effector P₇ depends only on the rotation angles of the two motors&lt;/strong&gt;, and has nothing to do with the posture of all intermediate links. This is thanks to the straight bar constraint and the geometric properties of nested parallelograms — the kinematics of intermediate joints are completely &quot;absorbed&quot;.&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;3. Inverse Kinematics Derivation&lt;a href=&quot;#3-inverse-kinematics-derivation&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Inverse kinematics: Given end-effector position &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;, find &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 Cosine Law&lt;a href=&quot;#31-cosine-law&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Let &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; (distance from P7 to origin), &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;From the geometric relationship of a 2R robotic arm:&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 Two Solutions&lt;a href=&quot;#32-two-solutions&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;The positive sign corresponds to &lt;strong&gt;elbow-down&lt;/strong&gt;, the negative sign corresponds to &lt;strong&gt;elbow-up&lt;/strong&gt; (two arm configurations).&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 Workspace and Singular Configurations&lt;a href=&quot;#33-workspace-and-singular-configurations&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The workspace is an annular region:&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;That is &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;Three singular configurations:&lt;/p&gt;

























&lt;table&gt;&lt;thead&gt;&lt;tr&gt;&lt;th&gt;Condition&lt;/th&gt;&lt;th&gt;Meaning&lt;/th&gt;&lt;th&gt;Solution Situation&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;Fully extended&lt;/td&gt;&lt;td&gt;Single solution (&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;$r =&lt;/td&gt;&lt;td&gt;L_1 - L_2&lt;/td&gt;&lt;td&gt;= 20.6$&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;End-effector coincides with origin&lt;/td&gt;&lt;td&gt;Infinitely many solutions&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;p&gt;Near singular configurations, the mechanism&apos;s force transmission performance degrades sharply — a small end-effector force may produce large torques at the joints. This is also an inherent problem of 2R robotic arms, and singular regions should be avoided during trajectory planning.&lt;/p&gt;
&lt;p&gt;&lt;/p&gt;&lt;figure&gt;&lt;img src=&quot;/img/Note/Kinematics/p3.jpg&quot; alt=&quot;Modeling&quot; loading=&quot;lazy&quot; /&gt;&lt;/figure&gt;&lt;p&gt;&lt;/p&gt;
&lt;h2&gt;4. Code Implementation&lt;a href=&quot;#4-code-implementation&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;4.1 Intersection of Two Circles&lt;a href=&quot;#41-intersection-of-two-circles&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This is the geometric foundation for the entire numerical solution — given two circle centers and radii, find the intersection points.&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;Returns (p_left, p_right), returns (None, None) when no solution.&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;# Concentric circles&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;  # No intersection&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;# Tangent&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;The positive/negative sign of the &lt;code&gt;perp&lt;/code&gt; vector distinguishes the two solutions — corresponding to two assembly modes.&lt;/p&gt;
&lt;h3&gt;4.2 Forward Kinematics Solver&lt;a href=&quot;#42-forward-kinematics-solver&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. P1, P2 on bar_a&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. P3 on bar_b&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. Find P4 via circle intersection&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 used for branch continuity in trajectory tracking&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    # 4. bar_d direction → 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. Find P6 via circle intersection&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 direction → P7 (end-effector)&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;The entire solution process is completed entirely with trigonometric functions and square roots, &lt;strong&gt;without any iteration&lt;/strong&gt;, making it a pure analytical forward solution.&lt;/p&gt;
&lt;h3&gt;4.3 Inverse Kinematics&lt;a href=&quot;#43-inverse-kinematics&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;# Outside workspace&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;The &lt;code&gt;elbow&lt;/code&gt; parameter controls which inverse solution is returned: &lt;code&gt;+1&lt;/code&gt; elbow up, &lt;code&gt;-1&lt;/code&gt; elbow down, &lt;code&gt;0&lt;/code&gt; returns both solutions.&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;5. Four Assembly Modes&lt;a href=&quot;#5-four-assembly-modes&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The &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; choice in circle intersection brings &lt;strong&gt;four assembly modes&lt;/strong&gt; (branch_d × branch_f), corresponding to different assembly methods of the actual mechanism:&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 Four Assembly Modes&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;  desc Combination of ± solutions from two circle intersections → Four assembly modes&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;Convex-Convex (−1, −1)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      desc P₄ is to the left of P₁→P₃, P₆ is to the left of P₂→P₅&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - label &quot;Convex-Concave (−1, +1)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      desc P₄ is to the left of P₁→P₃, P₆ is to the right of P₂→P₅&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - label &quot;Concave-Convex (+1, −1)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      desc P₄ is to the right of P₁→P₃, P₆ is to the left of P₂→P₅ (★ default mode)&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    - label &quot;Concave-Concave (+1, +1)&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;      desc P₄ is to the right of P₁→P₃, P₆ is to the right of P₂→P₅&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Among them, &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; (concave-convex) corresponds to the case where both parallelograms are convex quadrilaterals, which is also the default mode where the 2R simplification holds.&lt;/p&gt;
&lt;p&gt;In the other three modes, the parallelograms will have different degrees of concavity, but the analytical derivation framework for forward and inverse kinematics remains the same — just select the corresponding &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; branch during solving. However, note that in non-default modes, the relative orientation between end-effector P₇ and motor shaft changes, and trajectory planning should distinguish from the default mode.&lt;/p&gt;
&lt;h3&gt;5.1 Branch Keeping in Trajectory Tracking&lt;a href=&quot;#51-branch-keeping-in-trajectory-tracking&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;During trajectory tracking, each frame&apos;s &lt;code&gt;solve_linkage&lt;/code&gt; passes in the previous frame&apos;s &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;, and selects the solution closer to the previous frame among the two circle intersection solutions. This maintains the same assembly mode during continuous motion, avoiding jumps.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;# Select P4 closer to previous frame (maintain branch_d continuity)&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;Similarly, P6&apos;s branch selection uses the same nearest-neighbor decision strategy. The complete branch-keeping logic is as follows:&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;Select the intersection point closer to the previous frame from the two&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;# First frame, default to first&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;These two branch selection algorithms together ensure that both parallelograms maintain continuous assembly state during trajectory tracking, avoiding motion discontinuities or mechanism jamming caused by &quot;frame skipping&quot;.&lt;/p&gt;
&lt;h3&gt;5.2 Assembly Mode Selection Basis&lt;a href=&quot;#52-assembly-mode-selection-basis&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The default mode (concave-convex, +1, −1) is the most natural scheme for physical assembly — both parallelograms remain convex externally, the mechanism&apos;s force condition is optimal, and it directly corresponds to the 2R simplified model, facilitating kinematics planning.&lt;/p&gt;
&lt;p&gt;Under certain special motion requirements (such as needing to avoid obstacles, change end-effector pose range, or optimize force transmission angle), other assembly modes can be selected. Assembly mode switching needs to transition naturally when the mechanism passes through singular configurations (two circles tangent, &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;) — at this point the two solutions coincide, and the branch can be safely switched.&lt;/p&gt;
&lt;h2&gt;6. Verification&lt;a href=&quot;#6-verification&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; (Analytical)&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; (Numerical)&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;The above verification shows that the analytical derivation and numerical solution are completely consistent, and the forward and inverse kinematics solvers are correct and reliable.&lt;/p&gt;
&lt;h2&gt;7. Summary&lt;a href=&quot;#7-summary&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This figure-8 shaped double parallelogram mechanism cleverly utilizes the &lt;strong&gt;straight bar collinearity&lt;/strong&gt; constraint, making the seemingly complex linkage transmission chain ultimately simplify to a 2R planar robotic arm. Both forward and inverse kinematics have closed-form analytical solutions, requiring no numerical iteration, making it very suitable for embedded real-time control scenarios.&lt;/p&gt;
&lt;p&gt;If you&apos;re interested in the complete code, the project is open source on 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;# Quick try&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;   # Interactive sliders&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;          # Generate animation&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;            # Inverse kinematics demo&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>This World is Both Cruel and Gentle - Reflections</title><link>https://www.729dhs.site/en/post/sunyuchen</link><guid isPermaLink="false">en:sunyuchen</guid><description>Notes from Sun Ge&apos;s book</description><pubDate>Tue, 21 Apr 2026 06:52:26 GMT</pubDate><content:encoded>&lt;h1&gt;Notes on “This World is Both Cruel and Gentle”&lt;a href=&quot;#notes-on-this-world-is-both-cruel-and-gentle&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;I had long heard about Sun Ge’s book, and read it recently. It did leave me with some reflections.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;People nowadays always talk about stability, but stability is the biggest lie of all, and extremely hard to find. From my observation, only those earning a hundred thousand or two hundred thousand per year in the public sector could demand this, but clearly this requirement is extremely high.&lt;/p&gt;
&lt;p&gt;People fear uncertainty. Bill Gates called Hewlett-Packard when he was twelve years old. The first step is extremely difficult to take; people are afraid of rejection, afraid of embarrassment, failure, afraid things won’t develop as expected.&lt;/p&gt;
&lt;h2&gt;Why I’ve Never Looked for a Stable Job&lt;a href=&quot;#why-ive-never-looked-for-a-stable-job&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;But who cares? Payment is by the word. The faster you translate and the more words you produce, the more money you can earn. And translators don&apos;t know their readers. Most people&apos;s attitude is to muddle through, speed up and finish the manuscript, and couldn&apos;t care less about publishing quality or the troubles, misleadings, and deviations they cause to readers. Very few people care about the dignity of the translation profession, or about your struggles and pains during translation. You gradually discover that a good translation and a bad translation are treated the same, with absolutely no difference; no one values diligence, effort, or talent. A conscientious person feels awkward in such an environment, while a loafer who loves stability finds it like discovering their own organization. At that time, I was immersed in translation. I overheard discussions among these veteran office workers mentioned in &quot;Ode to Joy.&quot; All day they discussed their dream: when they could infiltrate an even more stable industry, one with lower quality requirements and even less regard for professional dignity; all day they thought most about how to cut corners, reduce materials, and make it even easier on this basis—there&apos;s no laziest, only lazier; their biggest daily hobby is to discourage newcomers who believe they can change something, achieve something, or take their work seriously.&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;The so-called “stability” is more like the soldiers in “Soldier Assault” who slack off in the grassland fifth squad, doing nothing, getting a paycheck and idling—that’s the so-called stability. When they see Xu Sanuo persisting day after day, they feel uneasy. It’s like a dorm full of people gaming, where the person who studies seriously is the odd one, because they disrupt the group’s stability.&lt;/p&gt;
&lt;p&gt;Especially now with the sluggish social environment, people are more inclined to lie flat. As if you, as a striver, are the odd one. Not only do they want to slack off, they want to drag you down. As a striver, you’re called an idiot, but clearly, success still belongs to a minority. Those who lie flat will never succeed.&lt;/p&gt;
&lt;p&gt;Ninety percent of people make ninety-nine percent of the choices, yet want one percent of the results—that clearly won’t work. Those who study seriously day after day, why shouldn’t success belong to them?&lt;/p&gt;
&lt;p&gt;In my view, Sun Ge is more of a typical example—persisting at all costs for one thing. I always think I’m unlucky, that what I do doesn’t yield good results. But thinking about it carefully, I still haven’t truly put in genuine effort. Maybe I’ve only put in half an effort.&lt;/p&gt;
&lt;h2&gt;Do What Is Correct When Viewed from the Future&lt;a href=&quot;#do-what-is-correct-when-viewed-from-the-future&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Courage and vision are essential prerequisites for success.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;If an entrepreneur has met Bill Gates and Musk, they will no longer be satisfied with being merely an outstanding county-level entrepreneur. The sense of deserving is very important. Some people feel they don’t deserve it, or subconsciously think they don’t deserve it. All people are born equal, with two arms and two legs. We’re no different. The conveniences of birth are not reasons to divide people into classes or levels.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Focus on increments rather than stock&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Don’t limit your gaze to immediate interests. Long-term investment, even if at a loss, if it can exchange for greater returns in the future, then it is worth it.&lt;/p&gt;
&lt;h2&gt;ALL IN to a Magnificent Cause&lt;a href=&quot;#all-in-to-a-magnificent-cause&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The internet has opened a new era, where connections between people have become unprecedentedly convenient. It has also opened a virtual parallel space.&lt;/p&gt;
&lt;p&gt;When deciding to undertake a great cause, you must have the determination to ALL IN.&lt;/p&gt;
&lt;p&gt;ALL IN doesn’t mean having no retreat, nor is it blind impulse. It requires keen judgment and perception of the future, having seventy to eighty percent certainty, and believing in your own judgment.
Especially when changing careers, starting a business, or starting from scratch.&lt;/p&gt;</content:encoded><category>category:notes</category><category>tag:This World is Both Cruel and Gentle</category></item><item><title>JLC FreeRTOS LED Demo</title><link>https://www.729dhs.site/en/post/jlc-freertos-led-demo</link><guid isPermaLink="false">en:jlc-freertos-led-demo</guid><description>JLC Foundation Board FreeRTOS LED demo, using the onboard PB8 LED and PB2 LED.</description><pubDate>Thu, 02 Apr 2026 14:48:50 GMT</pubDate><content:encoded>&lt;h1&gt;Tutorial: FreeRTOS Multi-Task Basics and GPIO Control&lt;a href=&quot;#tutorial-freertos-multi-task-basics-and-gpio-control&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2&gt;0. Experiment Overview&lt;a href=&quot;#0-experiment-overview&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This experiment is a mandatory introduction to Embedded Real-Time Operating Systems (RTOS). By creating two tasks with different priorities to control two LEDs blinking at different frequencies, it visually demonstrates FreeRTOS’s &lt;strong&gt;multi-task scheduling&lt;/strong&gt;, &lt;strong&gt;priority preemption&lt;/strong&gt;, and &lt;strong&gt;time management&lt;/strong&gt; mechanisms.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Learning Objectives&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Understand the concept of a FreeRTOS “Task” and how it differs from bare-metal &lt;code&gt;while(1)&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Master the method of configuring FreeRTOS tasks using STM32CubeMX.&lt;/li&gt;
&lt;li&gt;Deeply understand the meaning of each parameter in &lt;code&gt;osThreadNew&lt;/code&gt; when creating a task.&lt;/li&gt;
&lt;li&gt;Learn to analyze the scheduling behavior of tasks with different priorities.&lt;/li&gt;
&lt;/ol&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;1. Prerequisites&lt;a href=&quot;#1-prerequisites&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1.1 What is a FreeRTOS Task?&lt;a href=&quot;#11-what-is-a-freertos-task&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In a bare-metal program, we typically execute code sequentially within a dead loop &lt;code&gt;while(1)&lt;/code&gt;. In an RTOS, the program is split into multiple independent “tasks”. Each task appears to 独占 CPU, but the OS kernel (Scheduler) rapidly switches between tasks based on &lt;strong&gt;priority&lt;/strong&gt; and &lt;strong&gt;time slice&lt;/strong&gt;, achieving macroscopic “parallelism”.&lt;/p&gt;
&lt;h3&gt;1.2 Hardware Basics&lt;a href=&quot;#12-hardware-basics&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;MCU&lt;/strong&gt;: STM32F407 (Cortex-M4)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LED Connections&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; (Push-Pull Output)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LED2&lt;/strong&gt; -&amp;gt; &lt;strong&gt;PB8&lt;/strong&gt; (Push-Pull Output)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Clock&lt;/strong&gt;: System main frequency 168MHz, SysTick or TIM14 provides the heartbeat tick.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;2. Principle Analysis&lt;a href=&quot;#2-principle-analysis&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;2.1 Task Priority and Scheduling&lt;a href=&quot;#21-task-priority-and-scheduling&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This experiment creates two tasks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Task PB2&lt;/strong&gt;: Priority &lt;code&gt;Normal&lt;/code&gt; (higher)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Task PB8&lt;/strong&gt;: Priority &lt;code&gt;Low&lt;/code&gt; (lower)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Scheduling Rules&lt;/strong&gt;:
FreeRTOS uses &lt;strong&gt;priority-based preemptive scheduling&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When a higher-priority task is ready, the CPU immediately executes it.&lt;/li&gt;
&lt;li&gt;Only when the higher-priority task enters &lt;strong&gt;blocking state&lt;/strong&gt; (e.g., calling &lt;code&gt;osDelay&lt;/code&gt;) does the lower-priority task get a chance to run.&lt;/li&gt;
&lt;li&gt;In this experiment, both tasks spend most of their time in &lt;code&gt;osDelay&lt;/code&gt; blocking, so they alternate execution without interfering with each other.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.2 Time Delay (&lt;code&gt;osDelay&lt;/code&gt;)&lt;a href=&quot;#22-time-delay-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;: Means the task is suspended for 1000 system ticks.&lt;/li&gt;
&lt;li&gt;Assuming the system tick frequency is 1000Hz (1ms), the delay time is 1 second.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Key Point&lt;/strong&gt;: During the delay, this task does not consume CPU resources; the CPU can execute other ready lower-priority tasks. This is the core of efficient multi-tasking.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;3. In-Depth Code Analysis&lt;a href=&quot;#3-in-depth-code-analysis&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The following teaching breakdown is based on &lt;code&gt;Core/Src/main.c&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;3.1 Task Attribute Definitions&lt;a href=&quot;#31-task-attribute-definitions&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;In the global variable section of &lt;code&gt;main.c&lt;/code&gt;, the task’s “ID card” is defined.&lt;/p&gt;</content:encoded><category>category:笔记</category><category>category:STM32</category><category>tag:STM32</category><category>tag:Embedded</category><category>tag:Foundation Board</category></item><item><title>JLC FreeRTOS Encoder + PWM + LED</title><link>https://www.729dhs.site/en/post/jlc-freertos-encoder-led-demo</link><guid isPermaLink="false">en:jlc-freertos-encoder-led-demo</guid><description>JLC Foundation Board FreeRTOS demo using an encoder and LED, with the onboard PB8 LED and EC11 encoder.</description><pubDate>Thu, 02 Apr 2026 14:48:50 GMT</pubDate><content:encoded>&lt;h1&gt;EC11 Encoder LED Brightness Control Project&lt;a href=&quot;#ec11-encoder-led-brightness-control-project&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2&gt;1. Project Overview&lt;a href=&quot;#1-project-overview&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This project is based on the STM32F407 microcontroller and FreeRTOS operating system, implementing the function of controlling LED brightness using an EC11 encoder. The project uses three tasks (threads) working together to achieve non-blocking encoder reading, button detection, and LED brightness control.&lt;/p&gt;
&lt;h2&gt;2. Technical Framework&lt;a href=&quot;#2-technical-framework&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;2.1 Hardware Platform&lt;a href=&quot;#21-hardware-platform&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Microcontroller&lt;/strong&gt;: STM32F407&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Encoder&lt;/strong&gt;: EC11 rotary encoder (connected to PD12 and PD13)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Button&lt;/strong&gt;: PC13 (encoder’s built-in press function)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LED&lt;/strong&gt;: PB8 (brightness controlled via PWM)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Timer&lt;/strong&gt;: TIM10 (for PWM output)&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.2 Software Architecture&lt;a href=&quot;#22-software-architecture&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Development Environment&lt;/strong&gt;: STM32CubeMX + VScode&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Operating System&lt;/strong&gt;: FreeRTOS&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Library&lt;/strong&gt;: STM32 HAL library&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code Structure&lt;/strong&gt;: Standard STM32 HAL project structure + FreeRTOS task management&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3. Code Structure Analysis&lt;a href=&quot;#3-code-structure-analysis&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;3.1 Header Files&lt;a href=&quot;#31-header-files&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;Includes the main header file and CMSIS-OS header file, which define the basic configuration of the STM32 HAL library and FreeRTOS-related functions.&lt;/p&gt;
&lt;h3&gt;3.2 Global Variable Definitions&lt;a href=&quot;#32-global-variable-definitions&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 enable state (1=on, 0=off)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pwm_duty&lt;/code&gt;: PWM duty cycle (0-65535)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pwm_arr&lt;/code&gt;: PWM auto-reload value (timer period)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;pwm_step&lt;/code&gt;: PWM change step per encoder rotation&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.3 Task Handle Definitions&lt;a href=&quot;#33-task-handle-definitions&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;Defines handles for three tasks, used for task management.&lt;/p&gt;
&lt;h3&gt;3.4 Task Function Prototypes&lt;a href=&quot;#34-task-function-prototypes&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 Encoder State Table&lt;a href=&quot;#35-encoder-state-table&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;The state table for encoder rotation direction detection, used for table-lookup calculation of rotation direction.&lt;/p&gt;
&lt;h2&gt;4. Main Function Implementation&lt;a href=&quot;#4-main-function-implementation&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;4.1 Main Function&lt;a href=&quot;#41-main-function&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;  /* System Initialization */&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;  /* Start PWM Output */&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;  /* Start Task Scheduler */&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;  /* Will never execute here */&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;The main function first performs system initialization, then configures GPIO, TIM10 timer, and FreeRTOS, and starts PWM output and the task scheduler.&lt;/p&gt;
&lt;h3&gt;4.2 Task Initialization&lt;a href=&quot;#42-task-initialization&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;  /* Create Tasks */&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;Uses the &lt;code&gt;osThreadNew&lt;/code&gt; function to create three tasks and set task attributes.&lt;/p&gt;
&lt;h3&gt;4.3 Encoder Task&lt;a href=&quot;#43-encoder-task&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;    /* Read encoder state */&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;    /* Calculate rotation direction */&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;    /* Adjust PWM duty cycle based on direction */&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; // Prevent overflow&lt;/span&gt;&lt;/span&gt;
&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;The Encoder task uses a lookup table to detect encoder rotation direction and adjusts the PWM duty cycle accordingly.&lt;/p&gt;
&lt;h3&gt;4.4 KEY Task&lt;a href=&quot;#44-key-task&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;    /* Button debounce processing */&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;          /* Toggle LED enable state */&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;    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;The KEY task implements button debounce processing. When a button press is detected, it toggles the LED enable state.&lt;/p&gt;
&lt;h3&gt;4.5 LED Task&lt;a href=&quot;#45-led-task&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;    /* Control LED brightness based on PWM duty cycle and LED enable state */&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;    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;The LED task controls LED brightness via TIM10 PWM output. Since PB8 is active-low, the PWM duty cycle needs to be inverted.&lt;/p&gt;
&lt;h3&gt;4.6 TIM10 Timer Initialization&lt;a href=&quot;#46-tim10-timer-initialization&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;The TIM10 timer initialization function configures the timer’s basic parameters and PWM output channel.&lt;/p&gt;
&lt;h3&gt;4.7 GPIO Initialization&lt;a href=&quot;#47-gpio-initialization&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;  /* Configure PC13 as input */&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;  /* Configure PD12 and PD13 as input */&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;The GPIO initialization function configures input pins for the button and encoder.&lt;/p&gt;
&lt;h2&gt;5. Technical Details&lt;a href=&quot;#5-technical-details&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;5.1 Encoder Working Principle&lt;a href=&quot;#51-encoder-working-principle&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The EC11 encoder is a rotary position sensor that detects rotation direction through the phase difference between two output signals (Phase A and Phase B). When the encoder rotates clockwise, Phase A leads Phase B; when rotating counterclockwise, Phase B leads Phase A.&lt;/p&gt;
&lt;p&gt;This project uses a lookup table to detect rotation direction. By reading the states of Phase A and Phase B, it calculates the current state code, then looks up the rotation direction based on the previous state code and current state code.&lt;/p&gt;
&lt;h3&gt;5.2 PWM Control Principle&lt;a href=&quot;#52-pwm-control-principle&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;PWM (Pulse Width Modulation) is a technique that controls a signal by changing the pulse width. In LED control, the PWM duty cycle (ratio of high-level time to the entire period) determines the LED’s average brightness. Higher duty cycle means brighter LED; lower duty cycle means dimmer LED.&lt;/p&gt;
&lt;p&gt;This project uses the TIM10 timer to generate a PWM signal. The timer clock is 84MHz (APB2 bus clock), prescaler is 0, and auto-reload value is 65535, so the PWM frequency is:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;PWM frequency = Timer clock / (Prescaler + 1) / (Auto-reload value + 1) = 84MHz / 1 / 65536 ≈ 1281Hz&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;5.3 FreeRTOS Task Management&lt;a href=&quot;#53-freertos-task-management&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;FreeRTOS is an open-source real-time operating system that provides task management, queues, semaphores, and other features. This project uses FreeRTOS task management to create three tasks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Encoder Task&lt;/strong&gt;: Normal priority, responsible for reading encoder state and calculating rotation direction&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;KEY Task&lt;/strong&gt;: Low priority, responsible for detecting button state&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LED Task&lt;/strong&gt;: Low priority, responsible for controlling LED brightness&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The task scheduler determines which task gets CPU control based on task priority and state.&lt;/p&gt;
&lt;h3&gt;5.4 Button Debounce Processing&lt;a href=&quot;#54-button-debounce-processing&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Buttons generate mechanical bouncing when pressed and released, causing multiple triggers. This project implements software debounce by detecting the sustained duration of the button state to determine whether the button is truly pressed. When the button state is sustained for more than 50ms, the button is considered pressed.&lt;/p&gt;
&lt;h3&gt;5.5 Inter-Task Communication&lt;a href=&quot;#55-inter-task-communication&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The current project uses global variables for inter-task communication. The Encoder task updates the &lt;code&gt;pwm_duty&lt;/code&gt; variable, the KEY task updates the &lt;code&gt;led_enabled&lt;/code&gt; variable, and the LED task reads these variables to control LED brightness.&lt;/p&gt;
&lt;h2&gt;6. Workflow&lt;a href=&quot;#6-workflow&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;System Initialization&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Configure system clock&lt;/li&gt;
&lt;li&gt;Initialize GPIO&lt;/li&gt;
&lt;li&gt;Initialize TIM10 timer&lt;/li&gt;
&lt;li&gt;Initialize FreeRTOS&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Task Creation&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Create Encoder task&lt;/li&gt;
&lt;li&gt;Create KEY task&lt;/li&gt;
&lt;li&gt;Create LED task&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Task Execution&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Encoder Task&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;Read encoder state&lt;/li&gt;
&lt;li&gt;Calculate rotation direction&lt;/li&gt;
&lt;li&gt;Adjust PWM duty cycle based on direction&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;KEY Task&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;Detect button state (with debounce)&lt;/li&gt;
&lt;li&gt;Toggle LED enable state when button is pressed&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;LED Task&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;Control LED brightness based on PWM duty cycle and LED enable state&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;7. Code Optimization Suggestions&lt;a href=&quot;#7-code-optimization-suggestions&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;7.1 Use Queues Instead of Global Variables&lt;a href=&quot;#71-use-queues-instead-of-global-variables&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The current code uses global variables to pass data. It is recommended to use FreeRTOS queues for inter-task communication to improve code reliability and maintainability. For example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// Create queue&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;// Send message&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;// Receive message&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 Add Parameter Configuration&lt;a href=&quot;#72-add-parameter-configuration&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Parameters like PWM step size and button debounce time can be defined as configurable macros for easy adjustment:&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 change step&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;      // Button debounce time&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;      // Encoder detection delay&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 update delay&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;7.3 Add Error Handling&lt;a href=&quot;#73-add-error-handling&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Add error handling at critical operations to improve system stability:&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 Optimize Task Priority&lt;a href=&quot;#74-optimize-task-priority&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Adjust task priority according to actual requirements to ensure critical tasks respond in a timely manner:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Encoder Task: Higher priority to ensure timely response to encoder input&lt;/li&gt;
&lt;li&gt;KEY Task: Medium priority&lt;/li&gt;
&lt;li&gt;LED Task: Lower priority because brightness updates do not require real-time response&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;7.5 Add Status Indicator&lt;a href=&quot;#75-add-status-indicator&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;A LED status indicator can be added. For example, when the LED is on, use another LED to indicate the status:&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. Testing Methods&lt;a href=&quot;#8-testing-methods&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;Basic Function Test&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rotate the encoder and observe LED brightness changes&lt;/li&gt;
&lt;li&gt;Press the encoder’s button and observe the LED on/off state&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Performance Test&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Quickly rotate the encoder to test system response speed&lt;/li&gt;
&lt;li&gt;Press the button multiple times to test the debounce function&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Boundary Test&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rotate the encoder to minimum brightness and test whether it stops correctly&lt;/li&gt;
&lt;li&gt;Rotate the encoder to maximum brightness and test whether it stops correctly&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Stability Test&lt;/strong&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Run for a long time to test system stability&lt;/li&gt;
&lt;li&gt;Perform repeated operations to test system reliability&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;9. Project Structure&lt;a href=&quot;#9-project-structure&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. Key Technical Points&lt;a href=&quot;#10-key-technical-points&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 Task Creation and Management&lt;/strong&gt;: Use &lt;code&gt;osThreadNew&lt;/code&gt; to create tasks and set task priority and stack size.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Encoder Reading Algorithm&lt;/strong&gt;: Use a lookup table to implement encoder rotation direction detection, improving detection speed and accuracy.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;PWM Control&lt;/strong&gt;: Use TIM10 PWM mode to control LED brightness, achieving smooth brightness adjustment.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Button Debounce&lt;/strong&gt;: Implement software debounce to improve button detection reliability.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Inter-Task Communication&lt;/strong&gt;: Currently uses global variables. It is recommended to use queues for inter-task communication.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;STM32 HAL Library Usage&lt;/strong&gt;: Use HAL library functions to configure GPIO, timers, and other peripherals.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Code Standards&lt;/strong&gt;: Follow STM32 HAL library code standards and comment style.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;11. Project Features&lt;a href=&quot;#11-project-features&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;Modular Design&lt;/strong&gt;: Functions are divided into three independent tasks, making it easy to maintain and extend.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Real-time Response&lt;/strong&gt;: FreeRTOS achieves real-time task scheduling, ensuring encoder input and button operations respond promptly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Smooth Control&lt;/strong&gt;: PWM technology achieves smooth LED brightness adjustment, avoiding sudden brightness changes.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Reliability&lt;/strong&gt;: Button debounce is implemented, improving system reliability.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: The code structure is clear, making it easy to add new features or modify existing ones.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;12. Application Scenarios&lt;a href=&quot;#12-application-scenarios&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The EC11 encoder-controlled LED brightness technology implemented in this project can be applied to various scenarios:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Lighting Control&lt;/strong&gt;: Adjust indoor lighting brightness&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Device Parameter Adjustment&lt;/strong&gt;: Adjust various device parameters such as volume and speed&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Dashboard Control&lt;/strong&gt;: Control dashboard display brightness&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Smart Home&lt;/strong&gt;: Adjust smart lamp brightness&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Industrial Control&lt;/strong&gt;: Adjust device output power&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;13. Summary&lt;a href=&quot;#13-summary&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This project successfully implements EC11 encoder-controlled LED brightness functionality, achieving non-blocking operation through FreeRTOS task management. The project structure is clear, the code is concise, and the functionality is complete. It can serve as a reference example for learning FreeRTOS and STM32 PWM control.&lt;/p&gt;
&lt;p&gt;Through this project, you can master the following technologies:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;GPIO and timer configuration for STM32 microcontrollers&lt;/li&gt;
&lt;li&gt;FreeRTOS task creation and management&lt;/li&gt;
&lt;li&gt;Encoder reading and rotation direction detection&lt;/li&gt;
&lt;li&gt;PWM control technology&lt;/li&gt;
&lt;li&gt;Button debounce processing&lt;/li&gt;
&lt;li&gt;Inter-task communication methods&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;These technologies are very practical in embedded system development and can be applied to various scenarios requiring user input and output control.&lt;/p&gt;</content:encoded><category>category:笔记</category><category>category:STM32</category><category>tag:STM32</category><category>tag:Embedded</category><category>tag:Foundation Board</category></item><item><title>嘉立创筑基派FreeRTOS编码器+PWM+LED</title><link>https://www.729dhs.site/en/post/jlc-freertos-endoer-led-demo</link><guid isPermaLink="false">en: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>JLC Foundation Board PWM LED Demo</title><link>https://www.729dhs.site/en/post/jlc-pwm-led-demo</link><guid isPermaLink="false">en:jlc-pwm-led-demo</guid><description>JLC Foundation Board PWM LED demo, using the onboard PB8 LED.</description><pubDate>Thu, 02 Apr 2026 14:38:52 GMT</pubDate><content:encoded>&lt;h1&gt;PWM LED Control Project Documentation&lt;a href=&quot;#pwm-led-control-project-documentation&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2&gt;1. Project Overview&lt;a href=&quot;#1-project-overview&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This project is an LED brightness control example based on the STM32F407 microcontroller. It uses PWM (Pulse Width Modulation) technology to achieve dynamic LED brightness adjustment. The project is developed using the STM32 HAL library, uses the TIM10 timer to generate PWM signals, controls LED brightness by changing the duty cycle, and implements an LED breathing light effect.&lt;/p&gt;
&lt;h2&gt;2. Technical Framework&lt;a href=&quot;#2-technical-framework&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;2.1 Hardware Platform&lt;a href=&quot;#21-hardware-platform&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Microcontroller: STM32F407&lt;/li&gt;
&lt;li&gt;Timer: TIM10&lt;/li&gt;
&lt;li&gt;PWM Output Pin: TIM10_CH1&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;2.2 Software Architecture&lt;a href=&quot;#22-software-architecture&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Development Environment: STM32CubeMX + VScode&lt;/li&gt;
&lt;li&gt;Library: STM32 HAL library&lt;/li&gt;
&lt;li&gt;Code Structure: Standard STM32 HAL project structure&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;3. Code Structure Analysis&lt;a href=&quot;#3-code-structure-analysis&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;3.1 Header Files&lt;a href=&quot;#31-header-files&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;Includes the main header file, which defines the basic configuration and function declarations of the STM32 HAL library.&lt;/p&gt;
&lt;h3&gt;3.2 Variable Definitions&lt;a href=&quot;#32-variable-definitions&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;Defines the handle for the TIM10 timer, used for timer operations.&lt;/p&gt;
&lt;h3&gt;3.3 Constant Definitions&lt;a href=&quot;#33-constant-definitions&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 maximum duty cycle value&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 minimum duty cycle value&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;        // Breathing light fade steps&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;        // Delay time per step (milliseconds)&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;     // Maximum brightness hold time (milliseconds)&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;   // Minimum brightness hold time (milliseconds)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;These constants define various parameters for the LED breathing light effect, including PWM duty cycle range, fade steps, and timing parameters.&lt;/p&gt;
&lt;h3&gt;3.4 Function Prototypes&lt;a href=&quot;#34-function-prototypes&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;              // System clock configuration&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 initialization&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 timer initialization&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;      // Set LED brightness&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 fade effect&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;4. Main Function Implementation&lt;a href=&quot;#4-main-function-implementation&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;4.1 Main Function&lt;a href=&quot;#41-main-function&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;  // System initialization&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;  // Peripheral initialization&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;  // Start PWM output&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;  // Main loop&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;The main function first performs system initialization, then configures GPIO and TIM10 timer, and starts PWM output. In the main loop, the LED breathing light mode is achieved through the LED_GentleFade function to create smooth brightness transitions.&lt;/p&gt;
&lt;h3&gt;4.2 System Clock Configuration&lt;a href=&quot;#42-system-clock-configuration&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;  // Configure main internal regulator output voltage&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;  // Initialize RCC oscillator&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;  // Initialize CPU, AHB, and APB bus clocks&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;The system clock configuration function uses HSE (external high-speed clock) as the PLL clock source and generates a 168MHz system clock through PLL multiplication. It configures clock dividers for CPU, AHB, and APB buses, achieving clock distribution for the entire system.&lt;/p&gt;
&lt;h3&gt;4.3 TIM10 Timer Initialization&lt;a href=&quot;#43-tim10-timer-initialization&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;The TIM10 timer initialization function configures the timer’s basic parameters and PWM output channel. Key parameters include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Prescaler: 0&lt;/li&gt;
&lt;li&gt;Counter Mode: Up counting&lt;/li&gt;
&lt;li&gt;Auto-reload Value (Period): 65535&lt;/li&gt;
&lt;li&gt;PWM Mode: PWM1 mode&lt;/li&gt;
&lt;li&gt;Output Polarity: Active high&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4.4 GPIO Initialization&lt;a href=&quot;#44-gpio-initialization&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;The GPIO initialization function enables GPIO port clocks to provide clock support for the PWM output pin.&lt;/p&gt;
&lt;h3&gt;4.5 LED Brightness Setting Function&lt;a href=&quot;#45-led-brightness-setting-function&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;The LED_SetBrightness function changes the PWM duty cycle by setting the comparison register (CCR) value of TIM10 channel 1, thereby controlling LED brightness. Higher duty cycle means brighter LED; lower duty cycle means dimmer LED.&lt;/p&gt;
&lt;h3&gt;4.6 LED Fade Effect Function&lt;a href=&quot;#46-led-fade-effect-function&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;The LED_GentleFade function implements smooth LED brightness fading. It starts from the initial duty cycle value and gradually changes to the target duty cycle value, with brief delays between each step. By adjusting LED_FADE_STEPS and LED_FADE_STEP_MS parameters, the speed and smoothness of the fade can be changed.&lt;/p&gt;
&lt;h3&gt;4.7 Error Handler Function&lt;a href=&quot;#47-error-handler-function&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;The error handler function is called when an error occurs. It disables interrupts and enters an infinite loop to prevent the system from continuing to run.&lt;/p&gt;
&lt;h2&gt;5. Technical Details&lt;a href=&quot;#5-technical-details&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;5.1 PWM Principle&lt;a href=&quot;#51-pwm-principle&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;PWM (Pulse Width Modulation) is a technique that controls a signal by changing the pulse width. In LED control, the PWM duty cycle (ratio of high-level time to the entire period) determines the LED’s average brightness. Higher duty cycle means brighter LED; lower duty cycle means dimmer LED.&lt;/p&gt;
&lt;h3&gt;5.2 TIM10 Timer Configuration&lt;a href=&quot;#52-tim10-timer-configuration&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;TIM10 is a 16-bit timer on the STM32F407 with the following features:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;16-bit auto-reload counter&lt;/li&gt;
&lt;li&gt;Up to 4 independent channels (IC, OC, or PWM)&lt;/li&gt;
&lt;li&gt;Programmable prescaler&lt;/li&gt;
&lt;li&gt;Repetition counter&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this project, TIM10 is configured in PWM mode using channel 1 for PWM output. The timer clock is 84MHz (APB2 bus clock), prescaler is 0, and auto-reload value is 65535, so the PWM frequency is:
PWM frequency = Timer clock / (Prescaler + 1) / (Auto-reload value + 1) = 84MHz / 1 / 65536 ≈ 1281Hz&lt;/p&gt;
&lt;h3&gt;5.3 Breathing Light Effect Implementation&lt;a href=&quot;#53-breathing-light-effect-implementation&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;The breathing light effect is achieved through the LED_GentleFade function, which fades LED brightness from minimum to maximum and back from maximum to minimum. The fade process is divided into multiple steps with brief delays between each step, creating a smooth brightness change effect.&lt;/p&gt;
&lt;p&gt;The number of fade steps and the delay time per step determine the speed and smoothness of the breathing light. More steps and longer delay per step result in a smoother but slower breathing light effect; fewer steps and shorter delays result in a more pronounced but faster effect.&lt;/p&gt;
&lt;h3&gt;5.4 STM32 HAL Library Usage&lt;a href=&quot;#54-stm32-hal-library-usage&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This project is developed using the STM32 HAL library, which provides rich functions and structures that simplify peripheral configuration and usage. For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HAL_Init(): Initialize the HAL library&lt;/li&gt;
&lt;li&gt;HAL_RCC_OscConfig(): Configure system clock source&lt;/li&gt;
&lt;li&gt;HAL_RCC_ClockConfig(): Configure system clocks&lt;/li&gt;
&lt;li&gt;HAL_TIM_Base_Init(): Initialize timer basic functions&lt;/li&gt;
&lt;li&gt;HAL_TIM_PWM_Init(): Initialize timer PWM functions&lt;/li&gt;
&lt;li&gt;HAL_TIM_PWM_Start(): Start PWM output&lt;/li&gt;
&lt;li&gt;__HAL_TIM_SET_COMPARE(): Set timer comparison value&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;5.5 Code Structure and Comment Standards&lt;a href=&quot;#55-code-structure-and-comment-standards&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;This project follows the code structure generated by STM32CubeMX, using specific comment markers for user code areas, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;/* USER CODE BEGIN Header &lt;em&gt;/ and /&lt;/em&gt; USER CODE END Header */&lt;/li&gt;
&lt;li&gt;/* USER CODE BEGIN Includes &lt;em&gt;/ and /&lt;/em&gt; USER CODE END Includes */&lt;/li&gt;
&lt;li&gt;/* USER CODE BEGIN 2 &lt;em&gt;/ and /&lt;/em&gt; USER CODE END 2 */&lt;/li&gt;
&lt;li&gt;/* USER CODE BEGIN 3 &lt;em&gt;/ and /&lt;/em&gt; USER CODE END 3 */&lt;/li&gt;
&lt;li&gt;/* USER CODE BEGIN 4 &lt;em&gt;/ and /&lt;/em&gt; USER CODE END 4 */&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This structure ensures that user code is not overwritten when regenerating code, improving code maintainability.&lt;/p&gt;
&lt;h2&gt;6. Project Features&lt;a href=&quot;#6-project-features&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Modular Design&lt;/strong&gt;: LED control functionality is encapsulated in independent functions, making it easy to maintain and extend.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Parameterized Configuration&lt;/strong&gt;: Constants are used to define breathing light effect parameters for easy adjustment.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Error Handling&lt;/strong&gt;: Basic error handling mechanism is implemented.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Code Standards&lt;/strong&gt;: Follows STM32 HAL library code standards and comment style.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: The code structure is clear, making it easy to add new features or modify existing ones.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;7. Application Scenarios&lt;a href=&quot;#7-application-scenarios&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The PWM LED control technology implemented in this project can be applied to various scenarios:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LED lighting control&lt;/li&gt;
&lt;li&gt;Indicator brightness adjustment&lt;/li&gt;
&lt;li&gt;Decorative lighting effects&lt;/li&gt;
&lt;li&gt;Backlight brightness adjustment&lt;/li&gt;
&lt;li&gt;Signal light control&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;8. Summary&lt;a href=&quot;#8-summary&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;This project demonstrates how to use the STM32F407 timer’s PWM function to achieve LED brightness control and breathing light effects. Through reasonable timer parameter configuration and writing control functions, smooth LED brightness adjustment is achieved. The code structure is clear, follows STM32 HAL library standards, and has good maintainability and scalability. This example can serve as a reference for learning STM32 timer PWM functions and LED control technology.&lt;/p&gt;</content:encoded><category>category:笔记</category><category>category:STM32</category><category>tag:STM32</category><category>tag:Embedded</category><category>tag:Foundation Board</category></item><item><title>Integer Overflow</title><link>https://www.729dhs.site/en/post/int-overflow</link><guid isPermaLink="false">en:int-overflow</guid><description>Integer overflow is a common programming error, especially prevalent in resource-constrained embedded scenarios. This article discusses solutions.</description><pubDate>Thu, 02 Apr 2026 13:02:17 GMT</pubDate><content:encoded>&lt;h1&gt;Integer Overflow Technical Notes&lt;a href=&quot;#integer-overflow-technical-notes&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2&gt;Core Concepts&lt;a href=&quot;#core-concepts&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Integer overflow&lt;/strong&gt; occurs when the result of an arithmetic operation exceeds the representable range of the data type.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Unsigned integer overflow&lt;/strong&gt;: In C/C++ standards, this is &lt;strong&gt;legal&lt;/strong&gt;, and the result undergoes &lt;strong&gt;wrap-around&lt;/strong&gt; — jumping from the maximum value to the minimum (or vice versa), causing logical errors.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Signed integer overflow&lt;/strong&gt;: This is &lt;strong&gt;undefined behavior (UB)&lt;/strong&gt;, which may cause program crashes, calculation errors, or security vulnerabilities.&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Example type ranges&lt;/strong&gt;: The range of &lt;code&gt;uint16_t&lt;/code&gt; (16-bit unsigned integer) is &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;Typical Scenario Analysis: PWM Duty Cycle Gradient&lt;a href=&quot;#typical-scenario-analysis-pwm-duty-cycle-gradient&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;In embedded development, calculating the difference between two unsigned integers (such as PWM duty cycle variation) is a common scenario. If handled improperly, overflow is highly likely to occur.&lt;/p&gt;
&lt;h3&gt;Incorrect Approach: Direct Subtraction&lt;a href=&quot;#incorrect-approach-direct-subtraction&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;When &lt;code&gt;end_duty &amp;lt; start_duty&lt;/code&gt;, unsigned subtraction causes underflow.&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;// Incorrect approach&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;// But uint16_t cannot store negative numbers, it wraps automatically: 65536 - 500 = 65036 (completely wrong)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is a &lt;strong&gt;typical unsigned integer overflow&lt;/strong&gt;.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// Correct approach&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;// First cast end to 32-bit signed integer, the result is also signed&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// Can now store negative numbers, result = -500 (correct)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h2&gt;Common Overflow Prevention Techniques&lt;a href=&quot;#common-overflow-prevention-techniques&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;1. Type Promotion&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;// Addition overflow protection&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;  // Promote to 32-bit before adding&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;    // Handle overflow&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;}&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;// Multiplication overflow protection&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 won&apos;t overflow 32-bit&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;2. Pre-check&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;        // Will overflow, return max value or throw error&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;// Multiplication pre-check&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;  // Overflow&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. Use Larger Intermediate Types&lt;a href=&quot;#3-use-larger-intermediate-types&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;// Example from your code&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;// Subsequent calculation&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;//                   ^^^^^ Convert back to uint16_t in the end&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;//                   delta * step max approx 60000 * 70 = 4.2M&amp;lt; 2^31, safe&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;4. Saturation Arithmetic&lt;a href=&quot;#4-saturation-arithmetic&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;// For PWM duty cycle limiting&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. Compiler Built-in Overflow Checks (GCC/Clang)&lt;a href=&quot;#5-compiler-built-in-overflow-checks-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;        // Overflow occurred&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;// Check addition&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. Special Techniques for Timer Scenarios&lt;a href=&quot;#6-special-techniques-for-timer-scenarios&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;// Handling timer counter overflow (common in encoders, input capture)&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;    // Detect underflow (decrementing count)&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;  // Handle overflow&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    &lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    // Calculate actual 32-bit count value&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;Complete Overflow Prevention Analysis of Your Code&lt;a href=&quot;#complete-overflow-prevention-analysis-of-your-code&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;  // Prevent subtraction overflow&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;        // Dangerous calculation: (delta * step) / LED_FADE_STEPS&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        // delta max 60000, step max 70 → product 4.2M&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;        // int32_t max 2.1B, so it&apos;s safe&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;        //            ^^^^^ Final result range 0~60000, converting back to uint16_t is safe&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;Potential risks (already avoided):&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If &lt;code&gt;LED_FADE_STEPS&lt;/code&gt; is changed to 1000, &lt;code&gt;delta * step&lt;/code&gt; max is 60M, still safe&lt;/li&gt;
&lt;li&gt;If &lt;code&gt;LED_PWM_DUTY_MAX&lt;/code&gt; is changed to 600000 (exceeding uint16_t), the code will have problems&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Best Practices Summary&lt;a href=&quot;#best-practices-summary&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;Scenario&lt;/th&gt;&lt;th&gt;Recommended Technique&lt;/th&gt;&lt;/tr&gt;&lt;/thead&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Subtraction may result in negative&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Promote to signed type &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;Adding two small integers&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Promote to larger type &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;Multiplication may overflow&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Pre-check &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;Loop accumulation&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Use larger type for accumulation, truncate at the end&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Time difference calculation&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Use unsigned subtraction (leveraging wrap-around) with overflow flag&lt;/td&gt;&lt;/tr&gt;&lt;tr&gt;&lt;td&gt;&lt;strong&gt;PID/filter calculation&lt;/strong&gt;&lt;/td&gt;&lt;td&gt;Use floating point or fixed point with saturation&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;hr /&gt;
&lt;h2&gt;Utility Macros&lt;a href=&quot;#utility-macros&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;// Safe addition macro (saturation)&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;// Safe subtraction (with type promotion)&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;// Check if addition overflows&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;// Usage example&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;  // Saturate to max value&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 language</category><category>tag:STM32</category></item><item><title>整形溢出_IntegerOverflow</title><link>https://www.729dhs.site/en/post/int_overflow</link><guid isPermaLink="false">en: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>JLC Foundation Board LED Demo</title><link>https://www.729dhs.site/en/post/jlc-blink-demo-1</link><guid isPermaLink="false">en:jlc-blink-demo-1</guid><description>JLC Foundation Board LED demo, using the onboard PC13 LED.</description><pubDate>Thu, 02 Apr 2026 02:56:51 GMT</pubDate><content:encoded>&lt;h1&gt;JLC Foundation Board LED Demo_1&lt;a href=&quot;#jlc-foundation-board-led-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:Embedded</category><category>tag:Foundation Board</category></item><item><title>FreeRTOS Basics and API Guide for STM32 Beginners</title><link>https://www.729dhs.site/en/post/freertos-basics-api-stm32</link><guid isPermaLink="false">en:freertos-basics-api-stm32</guid><description>This guide is for STM32 beginners, systematically covering FreeRTOS core concepts, task states, key APIs, and common development pitfalls, with a minimal project template and visual state diagrams.</description><pubDate>Tue, 31 Mar 2026 04:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;FreeRTOS Basics and API Guide for STM32 Beginners&lt;a href=&quot;#freertos-basics-and-api-guide-for-stm32-beginners&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;Goal: After reading this guide, you can independently set up a minimal FreeRTOS project with “2 tasks + 1 queue + 1 semaphore”.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Table of Contents&lt;a href=&quot;#table-of-contents&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;Establish overall understanding first&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ol&gt;
&lt;li&gt;Task execution states (core)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ol&gt;
&lt;li&gt;Key concepts: scheduling, Tick, critical section, heap and stack&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ol&gt;
&lt;li&gt;Core API quick reference (native FreeRTOS)&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ol&gt;
&lt;li&gt;From 0 to 1: minimal project mental model&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ol&gt;
&lt;li&gt;Common beginner pitfalls and troubleshooting&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ol&gt;
&lt;li&gt;5-day beginner practice checklist&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;ol&gt;
&lt;li&gt;Native API vs CMSIS-RTOS v2 comparison&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;1. Establish Overall Understanding First&lt;a href=&quot;#1-establish-overall-understanding-first&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;FreeRTOS is essentially a kernel that does three things for you:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Manage multiple tasks.&lt;/li&gt;
&lt;li&gt;Schedule tasks to run based on priority and timing.&lt;/li&gt;
&lt;li&gt;Provide inter-task communication mechanisms (queues, semaphores, event groups, etc.).&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can think of it as “a micro operating system kernel on a microcontroller”:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;main()&lt;/code&gt; does hardware initialization.&lt;/li&gt;
&lt;li&gt;Create tasks.&lt;/li&gt;
&lt;li&gt;Start the scheduler.&lt;/li&gt;
&lt;li&gt;From then on, the kernel takes over CPU allocation.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;2. Task Execution States (Core)&lt;a href=&quot;#2-task-execution-states-core&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;2.2 Task State Flow (Visualization)&lt;a href=&quot;#22-task-state-flow-visualization&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 Most Common Confusion for Beginners&lt;a href=&quot;#23-most-common-confusion-for-beginners&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; is “passively waiting for a condition”, it automatically returns to &lt;code&gt;Ready&lt;/code&gt; when the condition is met.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Suspended&lt;/code&gt; is “manual freezing”, it does not automatically recover.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;3. Key Concepts: Scheduling, Tick, Critical Section, Heap and Stack&lt;a href=&quot;#3-key-concepts-scheduling-tick-critical-section-heap-and-stack&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;3.1 Priority and Preemption&lt;a href=&quot;#31-priority-and-preemption&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;FreeRTOS typically uses “highest priority runs first”.&lt;/li&gt;
&lt;li&gt;When preemption is enabled (&lt;code&gt;configUSE_PREEMPTION=1&lt;/code&gt;), a higher priority task becoming ready will preempt a lower priority task.&lt;/li&gt;
&lt;li&gt;Whether same-priority time slicing occurs depends on &lt;code&gt;configUSE_TIME_SLICING&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Recommendations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Start by dividing task priorities into 2-3 levels, don’t spread them out initially.&lt;/li&gt;
&lt;li&gt;Only put “short, urgent, critical” tasks in high priority.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.2 Tick and Delay&lt;a href=&quot;#32-tick-and-delay&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Tick is the kernel’s periodic interrupt (e.g., 1ms once, depends on &lt;code&gt;configTICK_RATE_HZ&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;The parameter unit for &lt;code&gt;vTaskDelay()&lt;/code&gt; is Tick, not ms.&lt;/li&gt;
&lt;li&gt;It is recommended to use &lt;code&gt;pdMS_TO_TICKS(ms)&lt;/code&gt; for conversion.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example:&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;: Relative delay, will accumulate drift in loops.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vTaskDelayUntil()&lt;/code&gt;: Absolute periodicity, more suitable for periodic tasks.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.3 Critical Section&lt;a href=&quot;#33-critical-section&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Used to protect shared resources, preventing concurrent access from corrupting data.&lt;/p&gt;
&lt;p&gt;Common in task context:&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;Principles:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Keep critical sections short.&lt;/li&gt;
&lt;li&gt;Do not perform blocking operations (such as queue blocking wait) inside critical sections.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.4 Idle Task and Tick Hook&lt;a href=&quot;#34-idle-task-and-tick-hook&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Idle Task runs when “no task is runnable”.&lt;/li&gt;
&lt;li&gt;You can use Idle Hook/Tick Hook for lightweight background work (must be very short).&lt;/li&gt;
&lt;li&gt;It is not recommended to write complex logic in Hooks.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3.5 Heap and Stack (Must Be Distinguished)&lt;a href=&quot;#35-heap-and-stack-must-be-distinguished&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Stack: Each task is independent, stores function local variables/call context.&lt;/li&gt;
&lt;li&gt;Heap: System dynamic allocation area, task control blocks, queues, etc. are often allocated from heap.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Common problems:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Task stack too small → stack overflow.&lt;/li&gt;
&lt;li&gt;Improper &lt;code&gt;heap_x.c&lt;/code&gt; selection or heap too small → object creation failure.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;4. Core API Quick Reference (Native FreeRTOS)&lt;a href=&quot;#4-core-api-quick-reference-native-freertos&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Note: The following focuses on native APIs; for CMSIS comparison, see Section 8.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;4.1 Task Management&lt;a href=&quot;#41-task-management&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;: Create a task.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vTaskDelete()&lt;/code&gt;: Delete a task.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vTaskDelay()&lt;/code&gt;: Relative delay.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vTaskDelayUntil()&lt;/code&gt;: Fixed period delay.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vTaskSuspend()&lt;/code&gt; / &lt;code&gt;vTaskResume()&lt;/code&gt;: Suspend/resume tasks.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Minimal example:&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;Purpose: Pass data between tasks (most commonly used).&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;Example:&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;Note:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;item_size&lt;/code&gt; must match the send/receive data type.&lt;/li&gt;
&lt;li&gt;The timeout parameter unit for send/receive is Tick.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;4.3 Semaphore and Mutex&lt;a href=&quot;#43-semaphore-and-mutex&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Binary semaphore: Event synchronization.&lt;/li&gt;
&lt;li&gt;Counting semaphore: Resource counting.&lt;/li&gt;
&lt;li&gt;Mutex: Shared resource mutual exclusion, with priority inheritance.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Common APIs:&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;Recommendations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mutex is preferred for protecting shared peripherals (such as UART).&lt;/li&gt;
&lt;li&gt;Binary semaphore or task notification is commonly used for ISR-to-task synchronization.&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;Purpose: Combined judgment of multiple event bits (e.g., “network ready + sensor ready”).&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;Purpose: Execute lightweight callbacks periodically.&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;Avoid time-consuming and blocking operations in callback functions.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;4.6 Interrupt Cooperation (ISR and Task)&lt;a href=&quot;#46-interrupt-cooperation-isr-and-task&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Rules:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Must use &lt;code&gt;FromISR&lt;/code&gt; version API in ISR.&lt;/li&gt;
&lt;li&gt;When a task switch may be triggered, call &lt;code&gt;portYIELD_FROM_ISR()&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example:&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;Interrupt priority note:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;On Cortex-M, ensure the interrupt priority configuration allows FreeRTOS API calls.&lt;/li&gt;
&lt;li&gt;Focus on &lt;code&gt;configMAX_SYSCALL_INTERRUPT_PRIORITY&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;5. From 0 to 1: Minimal Project Mental Model&lt;a href=&quot;#5-from-0-to-1-minimal-project-mental-model&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;5.1 Recommended &lt;code&gt;main()&lt;/code&gt; Order&lt;a href=&quot;#51-recommended-main-order&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Clock/interrupt group initialization.&lt;/li&gt;
&lt;li&gt;Peripheral initialization (GPIO/UART, etc.).&lt;/li&gt;
&lt;li&gt;Create communication objects (Queue/Semaphore).&lt;/li&gt;
&lt;li&gt;Create tasks.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;vTaskStartScheduler()&lt;/code&gt; to start the scheduler.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;5.2 Task Division Recommendations (Beginner Version)&lt;a href=&quot;#52-task-division-recommendations-beginner-version&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Acquisition task: Read sensors, send to queue.&lt;/li&gt;
&lt;li&gt;Processing task: Receive from queue, calculate.&lt;/li&gt;
&lt;li&gt;Output task: UART/screen output.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Avoid:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One task doing everything.&lt;/li&gt;
&lt;li&gt;Multiple tasks directly operating the same peripheral without mutual exclusion.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;5.3 Typical Dual-Task Flow (LED + UART)&lt;a href=&quot;#53-typical-dual-task-flow-led--uart&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Task A (LED): Toggles every 500ms to prove scheduling is running.&lt;/li&gt;
&lt;li&gt;Task B (UART): Prints count every 1s.&lt;/li&gt;
&lt;li&gt;Set both tasks to the same priority initially, then optimize after confirming stability.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Success criteria:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LED blinks regularly.&lt;/li&gt;
&lt;li&gt;UART prints stably, system does not freeze or produce garbled output.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;6. Common Beginner Pitfalls and Troubleshooting&lt;a href=&quot;#6-common-beginner-pitfalls-and-troubleshooting&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;6.1 Stack Overflow&lt;a href=&quot;#61-stack-overflow&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;p&gt;Symptoms: Unexplained HardFault, random freezes.&lt;/p&gt;
&lt;p&gt;Troubleshooting:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Enable stack overflow detection (&lt;code&gt;configCHECK_FOR_STACK_OVERFLOW&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Increase the stack of suspicious tasks.&lt;/li&gt;
&lt;li&gt;Avoid putting large arrays on stack, use static or heap instead.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;6.2 Wrong Blocking Time Unit&lt;a href=&quot;#62-wrong-blocking-time-unit&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Treating Tick as ms will cause timing chaos.&lt;/li&gt;
&lt;li&gt;Use &lt;code&gt;pdMS_TO_TICKS()&lt;/code&gt; uniformly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;6.3 Using Wrong API in ISR&lt;a href=&quot;#63-using-wrong-api-in-isr&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Using &lt;code&gt;xQueueSend()&lt;/code&gt; instead of &lt;code&gt;xQueueSendFromISR()&lt;/code&gt; in ISR.&lt;/li&gt;
&lt;li&gt;The result may be assertion failure or abnormal behavior.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;6.4 Queue Length or Element Size Mismatch&lt;a href=&quot;#64-queue-length-or-element-size-mismatch&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Mismatch between queue element definition and actual send/receive type will cause “seems to run but data garbled”.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;6.5 Deadlock&lt;a href=&quot;#65-deadlock&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Task A waits for Task B’s lock, Task B waits for Task A’s lock.&lt;/li&gt;
&lt;li&gt;Keep lock ordering consistent, reduce nested locks.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;6.6 Priority Inversion&lt;a href=&quot;#66-priority-inversion&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Low priority holding mutex resource causes high priority to be indirectly blocked.&lt;/li&gt;
&lt;li&gt;Use mutexes for shared resources (has priority inheritance).&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;6.7 &lt;code&gt;printf&lt;/code&gt; Risks&lt;a href=&quot;#67-printf-risks&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Large stack usage, time-consuming, reentrancy risks.&lt;/li&gt;
&lt;li&gt;Recommendations:
&lt;ul&gt;
&lt;li&gt;Reduce print frequency.&lt;/li&gt;
&lt;li&gt;Avoid printing in ISR.&lt;/li&gt;
&lt;li&gt;Use lightweight logging on critical paths.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;7. 5-Day Beginner Practice Checklist&lt;a href=&quot;#7-5-day-beginner-practice-checklist&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;h3&gt;Day 1: Get a Minimal Dual-Task Running&lt;a href=&quot;#day-1-get-a-minimal-dual-task-running&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Goal: LED task + UART task running concurrently.&lt;/li&gt;
&lt;li&gt;Verify: LED blinks steadily, UART outputs once per second.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Day 2: Queue Communication&lt;a href=&quot;#day-2-queue-communication&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Goal: TaskA sends count to queue, TaskB receives and prints.&lt;/li&gt;
&lt;li&gt;Verify: Printed values are continuous with no loss.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Day 3: Semaphore Synchronization&lt;a href=&quot;#day-3-semaphore-synchronization&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Goal: Button interrupt releases semaphore, task is awakened to handle.&lt;/li&gt;
&lt;li&gt;Verify: Task blocks without button press, responds immediately after press.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Day 4: Software Timer&lt;a href=&quot;#day-4-software-timer&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Goal: Software timer periodically triggers status reporting.&lt;/li&gt;
&lt;li&gt;Verify: Callback executes at fixed period.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Day 5: ISR to Task Notification&lt;a href=&quot;#day-5-isr-to-task-notification&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Goal: Interrupt uses &lt;code&gt;FromISR&lt;/code&gt; API to awaken task.&lt;/li&gt;
&lt;li&gt;Verify: Task runs quickly after interrupt response, system is stable.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;8. Native API vs CMSIS-RTOS v2 Comparison&lt;a href=&quot;#8-native-api-vs-cmsis-rtos-v2-comparison&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Only the most common mappings are listed for quick switching when reading different tutorials:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Task creation: &lt;code&gt;xTaskCreate&lt;/code&gt; &amp;lt;-&amp;gt; &lt;code&gt;osThreadNew&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Delay: &lt;code&gt;vTaskDelay&lt;/code&gt; &amp;lt;-&amp;gt; &lt;code&gt;osDelay&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Start scheduler: &lt;code&gt;vTaskStartScheduler&lt;/code&gt; &amp;lt;-&amp;gt; &lt;code&gt;osKernelStart&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Queue send/receive: &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;Semaphore take/give: &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;Conclusion:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Beginners are recommended to master native FreeRTOS APIs first, then look at CMSIS wrappers.&lt;/li&gt;
&lt;li&gt;The concepts are the same, main differences are in naming and wrapper layer.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Final Checklist (Review Before Writing Code)&lt;a href=&quot;#final-checklist-review-before-writing-code&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Have you used &lt;code&gt;pdMS_TO_TICKS()&lt;/code&gt; uniformly for Tick and ms?&lt;/li&gt;
&lt;li&gt;Are all ISRs using &lt;code&gt;FromISR&lt;/code&gt; API?&lt;/li&gt;
&lt;li&gt;Are shared peripherals protected with mutual exclusion?&lt;/li&gt;
&lt;li&gt;Do task stack sizes have margin?&lt;/li&gt;
&lt;li&gt;Are blocking waits all set with reasonable timeouts?&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;9. Directly Runnable Minimal Project Template (Can Be Copied to STM32 Project)&lt;a href=&quot;#9-directly-runnable-minimal-project-template-can-be-copied-to-stm32-project&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The following example is a minimal FreeRTOS skeleton that can be directly copied to your project: two tasks (LED, UART), one queue and one mutex. Note: Peripheral initialization (UART/GPIO) should be replaced according to your HAL/LL implementation.&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;/* Global objects */&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 state&lt;/span&gt;&lt;/span&gt;
&lt;span&gt;&lt;span&gt;    }&lt;/span&gt;&lt;/span&gt;
&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; // Will not return, FreeRTOS takes over&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. Common FreeRTOSConfig Macros and Behavior Mapping (Quick Reference)&lt;a href=&quot;#10-common-freertosconfig-macros-and-behavior-mapping-quick-reference&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;: Enable preemption, higher priority task becoming ready will immediately switch to CPU.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;configUSE_TIME_SLICING = 1&lt;/code&gt;: Enable time slicing between same priority tasks (if 0, same priority may not slice).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;configTICK_RATE_HZ&lt;/code&gt;: Tick frequency (e.g., 1000 -&amp;gt; 1 tick = 1 ms), affects vTaskDelay, etc.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;configMINIMAL_STACK_SIZE&lt;/code&gt;: Default minimal task stack size, estimate reasonably when creating tasks.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;configMAX_PRIORITIES&lt;/code&gt;: Maximum number of priority levels allowed.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;configCHECK_FOR_STACK_OVERFLOW&lt;/code&gt;: Enable stack overflow detection (recommend setting to 1 or 2 and implement vApplicationStackOverflowHook).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;configUSE_MUTEXES&lt;/code&gt;: Enable mutexes (priority inheritance), recommended for shared peripheral protection.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;configMAX_SYSCALL_INTERRUPT_PRIORITY&lt;/code&gt; / Cortex-M interrupt priority configuration: Ensure interrupt priority using FreeRTOS API is not higher than this threshold.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Documentation should explain that these macros are typically modified in &lt;code&gt;FreeRTOSConfig.h&lt;/code&gt;, and provide recommended values or ranges for common projects.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;11. Common Incorrect vs Correct 写法对照 (Training Style Examples)&lt;a href=&quot;#11-common-incorrect-vs-correct-写法对照-training-style-examples&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Incorrect: Calling &lt;code&gt;xQueueSend()&lt;/code&gt; in ISR (will cause unpredictable behavior or assertion)
Correct: Call &lt;code&gt;xQueueSendFromISR()&lt;/code&gt; in ISR and call &lt;code&gt;portYIELD_FROM_ISR()&lt;/code&gt; when needed.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Incorrect: Multiple tasks directly calling &lt;code&gt;HAL_UART_Transmit()&lt;/code&gt; (not thread-safe, data may be interleaved)
Correct: Create a mutex for UART, all tasks &lt;code&gt;xSemaphoreTake()&lt;/code&gt; before sending, &lt;code&gt;xSemaphoreGive()&lt;/code&gt; after.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Incorrect: Queue creation &lt;code&gt;item_size&lt;/code&gt; does not match passed type (e.g., sizeof(uint32_t) but passing struct pointer)
Correct: Queue element size should exactly match the actual passed data type, or send pointer and ensure lifecycle.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Incorrect: Making blocking calls in critical section (e.g., calling xQueueReceive(portMAX_DELAY) after taskENTER_CRITICAL())
Correct: Only perform short, small, and non-blocking operations in critical sections, blocking operations should be outside critical sections.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;12. Debugging and Observation: How to Diagnose Stack/Queue/Scheduling Problems&lt;a href=&quot;#12-debugging-and-observation-how-to-diagnose-stackqueuescheduling-problems&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;View task stack high water mark: &lt;code&gt;uxTaskGetStackHighWaterMark()&lt;/code&gt; returns the minimum remaining stack value used by a task (unit platform dependent), used to evaluate whether stack needs to be increased.&lt;/li&gt;
&lt;li&gt;Implement hooks: Implement &lt;code&gt;vApplicationStackOverflowHook()&lt;/code&gt; and &lt;code&gt;vApplicationMallocFailedHook()&lt;/code&gt;, record information when problems occur and safely restart or enter safe state.&lt;/li&gt;
&lt;li&gt;Use assertions: Enable &lt;code&gt;configASSERT()&lt;/code&gt;, and output key information in assertion callback (such as current task name, register snapshot) for troubleshooting.&lt;/li&gt;
&lt;li&gt;Statistics and events: Use &lt;code&gt;vTaskList()&lt;/code&gt; / &lt;code&gt;vTaskGetRunTimeStats()&lt;/code&gt; (if runtime stats are enabled) to observe task running conditions and CPU usage.&lt;/li&gt;
&lt;li&gt;Fault injection: As an exercise, intentionally shrink queue length or set a task’s stack too small, observe system behavior and use above tools to locate problems.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Quick Reference Checklist (Newly Added)&lt;a href=&quot;#quick-reference-checklist-newly-added&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Runnable minimal project template see Section 9.&lt;/li&gt;
&lt;li&gt;Common errors and correct approaches see Section 11, debugging methods see Section 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:Embedded</category></item><item><title>FreeRTOS 基础概念与 API 入门（STM32 新手向）</title><link>https://www.729dhs.site/en/post/freertos-basic-api-stm32</link><guid isPermaLink="false">en: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 Notes</title><link>https://www.729dhs.site/en/post/stm32-gpio-note</link><guid isPermaLink="false">en:stm32-gpio-note</guid><description>STM32 GPIO configuration, modes, HAL functions, and low-power practices notes.</description><pubDate>Wed, 25 Mar 2026 07:00:00 GMT</pubDate><content:encoded>&lt;h1&gt;STM32 GPIO Notes&lt;a href=&quot;#stm32-gpio-notes&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h1&gt;
&lt;h2&gt;GPIO Configuration Options in CubeMX&lt;a href=&quot;#gpio-configuration-options-in-cubemx&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;When configuring GPIO in STM32CubeMX, the main options include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Pin Mode&lt;/strong&gt;: Select the pin’s function, such as Input, Output, Analog, or Alternate Function.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPIO output level&lt;/strong&gt;: Set the initial output level, High or Low.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPIO mode&lt;/strong&gt;: Select the output type, Push-Pull or Open-Drain.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GPIO Pull-up/Pull-down&lt;/strong&gt;: No pull-up and no pull-down, Pull-up, or Pull-down.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Maximum output speed&lt;/strong&gt;: Low, Medium, High, or Very High.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User Label&lt;/strong&gt;: Add a custom name to the pin for easy reference in code.&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 has multiple modes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Input Floating&lt;/strong&gt;: Pin floating input without internal pull-up or pull-down.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Input Pull-up&lt;/strong&gt;: Pin input pulled up to VCC.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Input Pull-down&lt;/strong&gt;: Pin input pulled down to GND.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Output Push-Pull&lt;/strong&gt;: Output mode that can drive both high and low levels.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Output Open-Drain&lt;/strong&gt;: Output mode that can only pull low; requires external pull-up.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alternate Function Push-Pull&lt;/strong&gt;: Alternate function such as UART, SPI, etc., push-pull output.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Alternate Function Open-Drain&lt;/strong&gt;: Alternate function, open-drain output.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Analog&lt;/strong&gt;: Used for ADC/DAC with no digital functionality.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;HAL Library Function Usage&lt;a href=&quot;#hal-library-function-usage&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The STM32 HAL library provides simplified GPIO operation functions:&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;: Reads the specified GPIO pin state, returns GPIO_PIN_SET or GPIO_PIN_RESET.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Example: &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;: Sets the output level of a GPIO pin.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Example: &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;: Toggles the output level of a GPIO pin.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Example: &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;Comparison with Standard Peripheral Library&lt;a href=&quot;#comparison-with-standard-peripheral-library&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;The HAL library is an abstraction of the Standard Peripheral Library, providing a more user-friendly interface. Here is the comparison:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;HAL_GPIO_ReadPin&lt;/strong&gt; corresponds to Standard Library’s &lt;strong&gt;GPIO_ReadInputDataBit&lt;/strong&gt; or &lt;strong&gt;GPIO_ReadOutputDataBit&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Standard Library: &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; corresponds to Standard Library’s &lt;strong&gt;GPIO_SetBits&lt;/strong&gt; and &lt;strong&gt;GPIO_ResetBits&lt;/strong&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Standard Library: &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; requires manual implementation in the Standard Library, or use bit manipulation.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;No direct equivalent in Standard Library; commonly used: &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;The HAL library is more abstract and more compatible, while the Standard Library is more low-level and more efficient but more complex.&lt;/p&gt;
&lt;h2&gt;Detailed GPIO Mode Functions&lt;a href=&quot;#detailed-gpio-mode-functions&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 Mode&lt;/strong&gt;: Used to connect analog peripherals such as ADC (Analog-to-Digital Converter) or DAC (Digital-to-Analog Converter). In this mode, the pin does not perform digital input/output but directly passes analog signals to the internal ADC/DAC module for voltage measurement or analog voltage output. Commonly used for sensor input or audio output.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Alternate Function Mode&lt;/strong&gt;: Allows GPIO pins to be multiplexed by other peripherals such as UART, SPI, I2C, PWM, and other communication or timer functions. At this time, the pin is no longer used as a general GPIO but is controlled by the corresponding peripheral for data transmission, clock signals, etc. Whether to choose Push-Pull or Open-Drain depends on the peripheral requirements; for example, I2C often uses Open-Drain.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;GPIO Power Saving&lt;a href=&quot;#gpio-power-saving&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;If an IO is not in use, it can be configured to analog mode, so the pin will not consume current, thereby reducing power consumption.&lt;/p&gt;
&lt;h2&gt;JTAG/SWD Pin Considerations&lt;a href=&quot;#jtagswd-pin-considerations&quot;&gt;&lt;span&gt;&lt;/span&gt;&lt;/a&gt;&lt;/h2&gt;
&lt;p&gt;Early in the power-on/reset phase, the SWJ (SWD+JTAG) interface is enabled by default, and related pins may exhibit brief transients. These pins should not directly drive sensitive loads before system initialization.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;When using only SWD: The JTAG can be disabled early in initialization to release additional pins (such as JTDI/TDI, JTDO/TDO, JTMS/TMS, NJTRST). After release, these pins can be configured as regular GPIO input, output, or alternate function.&lt;/li&gt;
&lt;li&gt;Practical advice: Before disabling/remapping, configure these pins as input with appropriate pull-up/pull-down; only set the target mode and initial output level after release is complete to avoid misoperation at power-on.&lt;/li&gt;
&lt;li&gt;Trace/ITM: If serial debug output (SWO/JTDO) is not used, it is recommended to keep it disabled or configure it as input to avoid external triggering.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Examples (F1 series):&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;HAL: Keep SWD, disable JTAG: &lt;code&gt;__HAL_AFIO_REMAP_SWJ_NOJTAG();&lt;/code&gt;; Fully disable SWJ: &lt;code&gt;__HAL_AFIO_REMAP_SWJ_DISABLE();&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Standard Library: Keep SWD, disable JTAG: &lt;code&gt;GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable, ENABLE);&lt;/code&gt;; Fully disable SWJ: &lt;code&gt;GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable, ENABLE);&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The specific disable/remap methods may differ for different series chips. Please refer to the series reference manual and HAL/LL macro documentation.&lt;/p&gt;
&lt;h2&gt;Series Differences Summary&lt;a href=&quot;#series-differences-summary&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;Configuration location: AFIO remap.&lt;/li&gt;
&lt;li&gt;Keep SWD, disable JTAG: &lt;code&gt;__HAL_AFIO_REMAP_SWJ_NOJTAG();&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;Standard Library: &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;Fully disable SWJ: &lt;code&gt;__HAL_AFIO_REMAP_SWJ_DISABLE();&lt;/code&gt;
&lt;ul&gt;
&lt;li&gt;Standard Library: &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;After release: Configure &lt;code&gt;PA15/PB3/PB4&lt;/code&gt; as GPIO input/output/alternate function as needed.&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;Configuration location: In CubeMX &lt;code&gt;System Core -&amp;gt; SYS -&amp;gt; Debug&lt;/code&gt; selection; no AFIO macros at code level.&lt;/li&gt;
&lt;li&gt;Recommended: Select &lt;code&gt;Serial Wire&lt;/code&gt; (keep SWD, release JTAG-only pins); &lt;code&gt;No Debug&lt;/code&gt; releases all debug pins including &lt;code&gt;PA13/PA14&lt;/code&gt;. Use with caution.&lt;/li&gt;
&lt;li&gt;Common pins: SWDIO &lt;code&gt;PA13&lt;/code&gt;, SWCLK &lt;code&gt;PA14&lt;/code&gt;; JTAG-only: &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;After release example (applicable to F4/L4/H7, for reference only):&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;pre&gt;&lt;code&gt;&lt;span&gt;&lt;span&gt;// In early initialization phase, set JTAG-only pins to safe mode (input) or target mode&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;   // or GPIO_MODE_OUTPUT_PP, etc.&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;       // choose PULLUP/PULLDOWN based on external circuit&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 (can be used as regular GPIO in SWD mode)&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;Configuration location similar to F4: Via CubeMX &lt;code&gt;SYS -&amp;gt; Debug&lt;/code&gt; select SWD/JTAG/disable.&lt;/li&gt;
&lt;li&gt;Pin assignment basically consistent with F4 (specific models may vary slightly), SWD: &lt;code&gt;PA13/PA14&lt;/code&gt;; JTAG-only: &lt;code&gt;PA15/PB3/PB4&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;If Trace/ITM is enabled, &lt;code&gt;PB3 (SWO)&lt;/code&gt; will be occupied; when not in use, set to input or disable.&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;Configuration location similar to F4/L4: CubeMX &lt;code&gt;SYS -&amp;gt; Debug&lt;/code&gt;; some dual-core devices (M7+M4) have independent debug ports. Confirm according to device manual.&lt;/li&gt;
&lt;li&gt;Pins: SWD keeps &lt;code&gt;PA13/PA14&lt;/code&gt;; JTAG-only common &lt;code&gt;PA15/PB3/PB4&lt;/code&gt;; Trace/SWO uses &lt;code&gt;PB3&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Disable or release strategy same as F4/L4: When Trace is not used, keep &lt;code&gt;PB3&lt;/code&gt; disabled or input to avoid accidental triggering.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Note: The above pins are common mappings. For specific pin assignments, refer to the device datasheet/CubeMX pin view. Releasing debug pins will affect online debugging capability. Please handle with caution when in mass production or having strict pin requirements.&lt;/p&gt;</content:encoded><category>category:笔记</category><category>category:STM32</category><category>tag:STM32</category><category>tag:Embedded</category></item></channel></rss>