<?xml version="1.0" encoding="utf-8"?><?xml-stylesheet type="text/xsl" href="rss.xsl"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>WheelsLab Blog</title>
        <link>https://WheelsLab.github.io/sites/blog</link>
        <description>WheelsLab Blog</description>
        <lastBuildDate>Wed, 21 Jan 2026 12:15:01 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <item>
            <title><![CDATA[Docusaurus 博客支持]]></title>
            <link>https://WheelsLab.github.io/sites/blog/get-started-with-docusaurus-blog</link>
            <guid>https://WheelsLab.github.io/sites/blog/get-started-with-docusaurus-blog</guid>
            <pubDate>Wed, 21 Jan 2026 12:15:01 GMT</pubDate>
            <description><![CDATA[Docusaurus 使用 @docusaurus/plugin-content-blog 插件提供博客功能，classic 预设包含此插件，无须手动安装。]]></description>
            <content:encoded><![CDATA[<p>Docusaurus 使用 <a href="https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-content-blog" target="_blank" rel="noopener noreferrer" class=""><code>@docusaurus/plugin-content-blog</code></a> 插件提供<a href="https://docusaurus.io/docs/blog" target="_blank" rel="noopener noreferrer" class="">博客功能</a>，<code>classic</code> 预设包含此插件，无须手动安装。</p>
<p>首先需要添加作者和文章的标签信息，用于在每篇博客的 Front Matter 中使用。
添加全局作者信息</p>
<ul>
<li class=""><code>autherKey</code>：键名，用于在博客的 Front Matter 引用作者<!-- -->
<ul>
<li class=""><code>name</code>：姓名</li>
<li class=""><code>title</code>：职位/头衔</li>
<li class=""><code>url</code>：个人网址</li>
<li class=""><code>social</code>：社交账号<!-- -->
<ul>
<li class=""><code>github</code></li>
<li class=""><code>x</code></li>
</ul>
</li>
</ul>
</li>
</ul>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">website/blog/authors.yml</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">jmarcey</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Joel Marcey</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">title</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Co</span><span class="token punctuation" style="color:#393A34">-</span><span class="token plain">creator of Docusaurus 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">url</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> https</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//github.com/JoelMarcey</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">image_url</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> https</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//github.com/JoelMarcey.png</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">email</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> jimarcey@gmail.com</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">socials</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">x</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> joelmarcey</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">github</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> JoelMarcey</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">slorber</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">name</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Sébastien Lorber</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">title</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> Docusaurus maintainer</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">url</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> https</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//sebastienlorber.com</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">image_url</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> https</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain">//github.com/slorber.png</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">socials</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">x</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> sebastienlorber</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">github</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> slorber</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token key atrule" style="color:#00a4db">email</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> seb@example.com</span><br></span></code></pre></div></div>
<p>添加全局标签文件</p>
<div class="language-yaml codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">blog/tags.yml</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-yaml codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token key atrule" style="color:#00a4db">releases</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">label</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Product releases'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">permalink</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'/product-releases'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">description</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Content related to product releases.'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># A partial tag definition is also valid</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token key atrule" style="color:#00a4db">announcements</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">  </span><span class="token key atrule" style="color:#00a4db">label</span><span class="token punctuation" style="color:#393A34">:</span><span class="token plain"> </span><span class="token string" style="color:#e3116c">'Announcements'</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># An empty tag definition is also valid</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic"># Other attributes will be inferred from the key</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">emptyTag</span><span class="token punctuation" style="color:#393A34">:</span><br></span></code></pre></div></div>
<p>博客的 Front Matter，可以引用上面定义的作者和标签</p>
<div class="language-markdown codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-markdown codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token front-matter-block punctuation" style="color:#393A34">---</span><span class="token front-matter-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token front-matter-block"></span><span class="token front-matter-block front-matter yaml language-yaml key atrule" style="color:#00a4db">title</span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">:</span><span class="token front-matter-block front-matter yaml language-yaml"> Welcome Docusaurus</span><br></span><span class="token-line" style="color:#393A34"><span class="token front-matter-block front-matter yaml language-yaml"></span><span class="token front-matter-block front-matter yaml language-yaml key atrule" style="color:#00a4db">authors</span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">:</span><span class="token front-matter-block front-matter yaml language-yaml"></span><br></span><span class="token-line" style="color:#393A34"><span class="token front-matter-block front-matter yaml language-yaml">  </span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">-</span><span class="token front-matter-block front-matter yaml language-yaml"> slorber</span><br></span><span class="token-line" style="color:#393A34"><span class="token front-matter-block front-matter yaml language-yaml">  </span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">-</span><span class="token front-matter-block front-matter yaml language-yaml"> yangshun</span><br></span><span class="token-line" style="color:#393A34"><span class="token front-matter-block front-matter yaml language-yaml">  </span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">-</span><span class="token front-matter-block front-matter yaml language-yaml"> </span><span class="token front-matter-block front-matter yaml language-yaml key atrule" style="color:#00a4db">name</span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">:</span><span class="token front-matter-block front-matter yaml language-yaml"> Joel Marcey</span><br></span><span class="token-line" style="color:#393A34"><span class="token front-matter-block front-matter yaml language-yaml">    </span><span class="token front-matter-block front-matter yaml language-yaml key atrule" style="color:#00a4db">title</span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">:</span><span class="token front-matter-block front-matter yaml language-yaml"> Co</span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">-</span><span class="token front-matter-block front-matter yaml language-yaml">creator of Docusaurus 1</span><br></span><span class="token-line" style="color:#393A34"><span class="token front-matter-block front-matter yaml language-yaml">    </span><span class="token front-matter-block front-matter yaml language-yaml key atrule" style="color:#00a4db">url</span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">:</span><span class="token front-matter-block front-matter yaml language-yaml"> https</span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">:</span><span class="token front-matter-block front-matter yaml language-yaml">//github.com/JoelMarcey</span><br></span><span class="token-line" style="color:#393A34"><span class="token front-matter-block front-matter yaml language-yaml">    </span><span class="token front-matter-block front-matter yaml language-yaml key atrule" style="color:#00a4db">image_url</span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">:</span><span class="token front-matter-block front-matter yaml language-yaml"> https</span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">:</span><span class="token front-matter-block front-matter yaml language-yaml">//github.com/JoelMarcey.png</span><br></span><span class="token-line" style="color:#393A34"><span class="token front-matter-block front-matter yaml language-yaml">    </span><span class="token front-matter-block front-matter yaml language-yaml key atrule" style="color:#00a4db">socials</span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">:</span><span class="token front-matter-block front-matter yaml language-yaml"></span><br></span><span class="token-line" style="color:#393A34"><span class="token front-matter-block front-matter yaml language-yaml">      </span><span class="token front-matter-block front-matter yaml language-yaml key atrule" style="color:#00a4db">x</span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">:</span><span class="token front-matter-block front-matter yaml language-yaml"> joelmarcey</span><br></span><span class="token-line" style="color:#393A34"><span class="token front-matter-block front-matter yaml language-yaml">      </span><span class="token front-matter-block front-matter yaml language-yaml key atrule" style="color:#00a4db">github</span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">:</span><span class="token front-matter-block front-matter yaml language-yaml"> JoelMarcey</span><br></span><span class="token-line" style="color:#393A34"><span class="token front-matter-block front-matter yaml language-yaml"></span><span class="token front-matter-block front-matter yaml language-yaml key atrule" style="color:#00a4db">tags</span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">:</span><span class="token front-matter-block front-matter yaml language-yaml"> </span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">[</span><span class="token front-matter-block front-matter yaml language-yaml">docusaurus</span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">]</span><span class="token front-matter-block front-matter yaml language-yaml"></span><br></span><span class="token-line" style="color:#393A34"><span class="token front-matter-block front-matter yaml language-yaml"></span><span class="token front-matter-block front-matter yaml language-yaml key atrule" style="color:#00a4db">description</span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">:</span><span class="token front-matter-block front-matter yaml language-yaml"> This is my first post on Docusaurus.</span><br></span><span class="token-line" style="color:#393A34"><span class="token front-matter-block front-matter yaml language-yaml"></span><span class="token front-matter-block front-matter yaml language-yaml key atrule" style="color:#00a4db">image</span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">:</span><span class="token front-matter-block front-matter yaml language-yaml"> https</span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">:</span><span class="token front-matter-block front-matter yaml language-yaml">//i.imgur.com/mErPwqL.png</span><br></span><span class="token-line" style="color:#393A34"><span class="token front-matter-block front-matter yaml language-yaml"></span><span class="token front-matter-block front-matter yaml language-yaml key atrule" style="color:#00a4db">hide_table_of_contents</span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">:</span><span class="token front-matter-block front-matter yaml language-yaml"> </span><span class="token front-matter-block front-matter yaml language-yaml boolean important" style="color:#36acaa">false</span><span class="token front-matter-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token front-matter-block"></span><span class="token front-matter-block punctuation" style="color:#393A34">---</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">A Markdown blog post</span><br></span></code></pre></div></div>
<p>博客列表页可以控制要显示的内容摘要，在文章中使用 <code>&lt;!--truncate--&gt;</code> 标记内容摘要，标记以上的内容将成为摘要</p>
<div class="language-markdown codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">website/blog/my-post.md</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-markdown codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token front-matter-block punctuation" style="color:#393A34">---</span><span class="token front-matter-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token front-matter-block"></span><span class="token front-matter-block front-matter yaml language-yaml key atrule" style="color:#00a4db">title</span><span class="token front-matter-block front-matter yaml language-yaml punctuation" style="color:#393A34">:</span><span class="token front-matter-block front-matter yaml language-yaml"> Markdown blog truncation example</span><span class="token front-matter-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token front-matter-block"></span><span class="token front-matter-block punctuation" style="color:#393A34">---</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">All these will be part of the blog post summary.</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain"></span><span class="token comment" style="color:#999988;font-style:italic">&lt;!-- truncate --&gt;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">But anything from here on down will not be.</span><br></span></code></pre></div></div>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p><code>mdx</code> 使用 <code>{/* truncate */}</code></p></div></div>]]></content:encoded>
            <author>iclhchc@gmail.com (WheelsLab)</author>
            <category>Docusaurus</category>
        </item>
        <item>
            <title><![CDATA[学习 STM32]]></title>
            <link>https://WheelsLab.github.io/sites/blog/learn-stm32</link>
            <guid>https://WheelsLab.github.io/sites/blog/learn-stm32</guid>
            <pubDate>Wed, 21 Jan 2026 12:15:01 GMT</pubDate>
            <description><![CDATA[STM32 学习笔记整理]]></description>
            <content:encoded><![CDATA[<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="stm32-学习笔记整理">STM32 学习笔记整理<a href="https://wheelslab.github.io/sites/blog/learn-stm32#stm32-%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0%E6%95%B4%E7%90%86" class="hash-link" aria-label="Direct link to STM32 学习笔记整理" title="Direct link to STM32 学习笔记整理" translate="no">​</a></h2>
<p>最近几个月系统性地学习了 STM32 编程，计划将零散的学习笔记整理成一系列结构化文档。本篇文章作为整体概览，用于说明后续的创作计划，并对 STM32 编程涉及的核心内容做一个初步梳理。</p>
<p>整体上，我打算将内容拆分为两个系列，并最终整理成较为完整的文档：</p>
<ul>
<li class="">
<p><strong>STM32 基础</strong><br>
<!-- -->这一部分主要跟随江协科技（购买了其 STM32 套件）以及铁头山羊的 STM32 教程进行学习。在此之前曾简单接触过 51 单片机，但学习到一半后选择中止。对已经具备一定编程基础的学习者而言，直接从 STM32 入手在效率和实用性上都更合适。</p>
</li>
<li class="">
<p><strong>STM32 平衡车项目</strong><br>
<!-- -->该系列基于铁头山羊的平衡车套件，是对前述 STM32 基础知识的一次综合实践，同时也会引入一定的自动控制原理。</p>
</li>
</ul>
<p>从更高层次来看，嵌入式系统通常可以分为两大方向：<strong>嵌入式 MCU</strong> 与 <strong>嵌入式 Linux</strong>。两者在硬件形态、开发方式以及所需技术栈上均有明显差异。目前我主要关注的是 MCU 方向，而 STM32 则是其中应用最为广泛的一类芯片。</p>
<p>STM32 的入门，本质上是学习其片上外设（即 STM32 内部功能模块）的编程接口。但在真正开始写代码之前，有必要先对单片机的概念以及其与“常规应用程序开发”的差异建立基本认知。</p>
<p>常规应用程序开发依赖于操作系统所提供的各类功能，以及构建在其之上的生态库。应用程序本质上是由操作系统管理的一个或多个进程，其运行环境、资源分配以及调度行为均由操作系统负责。与之相对，单片机开发通常属于裸机开发（Bare-metal）：系统中不存在通用意义上的操作系统，也很少引入复杂的第三方库。开发者编写的程序几乎就是芯片上运行的全部软件逻辑，代码直接与硬件打交道，负责从上电启动到外设控制的完整流程。</p>
<p>当然，也可以在单片机上引入 RTOS 来提供任务调度等操作系统级能力，但这属于更高一层的抽象，将在后续内容中再展开讨论。</p>
<p><a href="https://zh.wikipedia.org/wiki/%E5%8D%95%E7%89%87%E6%9C%BA" target="_blank" rel="noopener noreferrer" class="">单片机（Single-chip microcomputer）</a>可以被视为一台高度集成的“迷你计算机”。如果有 DIY 电脑的经验，就会知道一台完整的 PC 由 CPU / GPU / 主板 / 内存 / 存储等多个部件构成，不同外设通过各类总线（如南北桥、USB、PCIe）进行连接与通信。单片机在架构上与之类似，其片上外设同样通过内部总线（如 AHB、APB1、APB2）连接到 CPU，只是外设类型更加聚焦于嵌入式场景，例如 USART、I2C、定时器等。从这一角度看，MCU 更接近于手机中的 <strong>SoC（System on a Chip）</strong>。</p>
<p><img decoding="async" loading="lazy" alt="img" src="https://wheelslab.github.io/sites/assets/images/250px-Motherboard_diagram.svg-50c21047780f553559a0811bdec92976.png" width="250" height="386" class="img_ev3q"></p>
<div class="theme-admonition theme-admonition-note admonition_xJq3 alert alert--secondary"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 14 16"><path fill-rule="evenodd" d="M6.3 5.69a.942.942 0 0 1-.28-.7c0-.28.09-.52.28-.7.19-.18.42-.28.7-.28.28 0 .52.09.7.28.18.19.28.42.28.7 0 .28-.09.52-.28.7a1 1 0 0 1-.7.3c-.28 0-.52-.11-.7-.3zM8 7.99c-.02-.25-.11-.48-.31-.69-.2-.19-.42-.3-.69-.31H6c-.27.02-.48.13-.69.31-.2.2-.3.44-.31.69h1v3c.02.27.11.5.31.69.2.2.42.31.69.31h1c.27 0 .48-.11.69-.31.2-.19.3-.42.31-.69H8V7.98v.01zM7 2.3c-3.14 0-5.7 2.54-5.7 5.68 0 3.14 2.56 5.7 5.7 5.7s5.7-2.55 5.7-5.7c0-3.15-2.56-5.69-5.7-5.69v.01zM7 .98c3.86 0 7 3.14 7 7s-3.14 7-7 7-7-3.12-7-7 3.14-7 7-7z"></path></svg></span>note</div><div class="admonitionContent_BuS1"><p><strong><a href="https://zh.wikipedia.org/wiki/%E5%8D%95%E7%89%87%E6%9C%BA" target="_blank" rel="noopener noreferrer" class="">单片机</a></strong>（英语：Single-chip microcomputer，台湾作<strong>单晶片</strong>，全称<strong>单芯片微型计算机</strong>），是把<a href="https://zh.wikipedia.org/wiki/%E4%B8%AD%E5%A4%AE%E8%99%95%E7%90%86%E5%99%A8" target="_blank" rel="noopener noreferrer" class="">中央处理器</a>、<a href="https://zh.wikipedia.org/wiki/%E9%9B%BB%E8%85%A6%E8%A8%98%E6%86%B6%E9%AB%94" target="_blank" rel="noopener noreferrer" class="">存储器</a>、定时/计数器（timer/counter）、各种<a href="https://zh.wikipedia.org/wiki/I/O" target="_blank" rel="noopener noreferrer" class="">输入输出接口</a>等都集成在一块<a href="https://zh.wikipedia.org/wiki/%E9%9B%86%E6%88%90%E9%9B%BB%E8%B7%AF" target="_blank" rel="noopener noreferrer" class="">集成电路</a><a href="https://zh.wikipedia.org/wiki/%E8%8A%AF%E7%89%87" target="_blank" rel="noopener noreferrer" class="">芯片</a>上的<a href="https://zh.wikipedia.org/wiki/%E5%BE%AE%E5%9E%8B%E8%AE%A1%E7%AE%97%E6%9C%BA" target="_blank" rel="noopener noreferrer" class="">微型计算机</a>。</p></div></div>
<p>在实际的软件开发中，很少会完全从零开始编写所有内容，而是依赖框架或库来屏蔽底层细节。例如前端开发中的 React、Java 后端中的 Spring Boot，或 Linux 驱动开发中的 POSIX API。嵌入式开发同样如此。</p>
<p>对于 STM32 而言，芯片原厂（microcontroller vendor）提供了用于简化开发的基础库，主要包括 <strong>SPL（Standard Peripheral Library，已停止维护）</strong> 和 <strong>HAL（Hardware Abstraction Layer，官方主推）</strong>。这些库对寄存器级操作进行了封装，使开发者可以通过更高层次的 API 来配置和使用外设。而 51 单片机编程往往需要直接查阅 Datasheet 并操作寄存器，而STM32 的入门过程，本质上是理解并正确使用这些外设 API。不过，即便是 API 级别的开发，也需要对 STM32 的硬件结构和外设原理有基本认识。</p>
<p><img decoding="async" loading="lazy" alt="Inside the STM32Cube ecosystem" src="https://wheelslab.github.io/sites/assets/images/stm32diagram-549ae2b099d85be81750fe67ebb27b38.png" width="880" height="880" class="img_ev3q"></p>
<p>在后续的文档中，我将以 <strong>SPL 库</strong>为基础，系统性地整理各个模块的工作原理与编程方法。</p>
<table><thead><tr><th>文档：STM32 入门</th><th>描述</th></tr></thead><tbody><tr><td><code>00 STM32</code></td><td>STM32 系列单片机整体概述，包括芯片架构、存储器映射、总线体系（AHB / APB）以及基本开发流程</td></tr><tr><td><code>01 GPIO</code></td><td>通用输入输出接口，介绍引脚复用、工作模式配置及基本的数字输入输出操作</td></tr><tr><td><code>02 UART</code></td><td>串口通信原理与使用方法，包括波特率配置、中断方式收发以及常见调试场景</td></tr><tr><td><code>03 I2C</code></td><td>I2C 总线通信机制，主从模式、时序特性及 STM32 中 I2C 外设的配置与使用</td></tr><tr><td><code>04 SPI</code></td><td>SPI 通信协议原理，多种工作模式及其在 STM32 中的配置与数据传输流程</td></tr><tr><td><code>05 Interrupt</code></td><td>STM32 中断体系概述，包括 NVIC、中断优先级以及中断服务函数的基本结构</td></tr><tr><td><code>06 EXTI</code></td><td>外部中断与事件控制器，介绍引脚中断触发方式及其与 NVIC 的配合使用</td></tr><tr><td><code>07 Clock</code></td><td>时钟系统原理，包括内部 / 外部时钟源、PLL 配置及系统时钟树</td></tr><tr><td><code>08 Timer</code></td><td>定时器工作原理，基础定时、输入捕获、输出比较及 PWM 生成</td></tr><tr><td><code>09 ADC</code></td><td>模数转换原理，采样与量化过程，以及 STM32 ADC 外设的配置与使用</td></tr></tbody></table>
<p>在此基础上，将展开 <strong>STM32 平衡车项目</strong>。该项目不仅是对前述基础知识的综合应用，还会引入控制系统相关的概念。文档同样按照模块进行拆分，并继续使用 SPL 进行开发。</p>
<table><thead><tr><th>文档：STM32 平衡车项目</th><th>描述</th></tr></thead><tbody><tr><td><code>01 项目概述</code></td><td>项目整体介绍与效果演示，说明系统组成、硬件结构以及功能目标</td></tr><tr><td><code>02 Battery</code></td><td>电池电压采集与电量估算，介绍电源管理及 ADC 在项目中的实际应用</td></tr><tr><td><code>03 Motor</code></td><td>电机驱动与调速控制，包括 PWM 输出及电机控制基本原理</td></tr><tr><td><code>04 Encoder</code></td><td>编码器接口与速度测量方法，用于获取电机转速等反馈信息</td></tr><tr><td><code>05 MPU6050</code></td><td>IMU 传感器使用，姿态数据采集与欧拉角解算过程</td></tr><tr><td><code>06 PID</code></td><td>PID 控制算法原理及其在电机转速控制中的实现</td></tr><tr><td><code>07 Inverted-pendulum</code></td><td>倒立摆模型建立，用于描述平衡车系统的动力学特性</td></tr><tr><td><code>08 SpeedLoop</code></td><td>速度环控制设计，将速度反馈引入整体控制系统</td></tr><tr><td><code>09 RemoteControl</code></td><td>蓝牙通信实现，用于远程控制与参数调节</td></tr></tbody></table>
<p>最后，我计划使用 <strong>HAL 库</strong> 对平衡车项目进行重构，并将其整理为对比性的文档，以加深对 STM32 不同开发方式的理解。</p>
<p>下面将对各个部分做进一步的简要概述。</p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="stm32-基础">STM32 基础<a href="https://wheelslab.github.io/sites/blog/learn-stm32#stm32-%E5%9F%BA%E7%A1%80" class="hash-link" aria-label="Direct link to STM32 基础" title="Direct link to STM32 基础" translate="no">​</a></h2>
<p>STM32 是<a href="https://www.st.com.cn/content/st_com/zh.html" target="_blank" rel="noopener noreferrer" class="">意法半导体（STMicroelectronics）</a> 基于<a href="https://www.st.com/content/st_com/en/arm-32-bit-microcontrollers.html" target="_blank" rel="noopener noreferrer" class="">ARM Cortex-M 内核</a>推出的一系列 <a href="https://en.wikipedia.org/wiki/32-bit_computing" target="_blank" rel="noopener noreferrer" class="">32 位</a><a href="https://en.wikipedia.org/wiki/Microcontroller" target="_blank" rel="noopener noreferrer" class="">微控制器（MCU）</a>。根据性能、功耗以及应用场景的不同，ST 将 STM32 划分为多个产品系列，例如主流型、高性能型、低功耗型以及无线系列等。</p>
<p>下图为 STM32 系列芯片的命名规则</p>
<p><img decoding="async" loading="lazy" alt="https://www.stmcu.com.cn/upload/Selection_Guide.pdf" src="https://wheelslab.github.io/sites/assets/images/STM32_MCU_Selection_Guide-b86b3e6fd8318d6ab2eaf0d191231899.png" width="1895" height="1089" class="img_ev3q"></p>
<p>出于学习和理解的目的，选用入门级的 <code>STM32F103C8T6</code> 已经足够，也就是常见的 <a href="https://stm32-base.org/boards/STM32F103C8T6-Blue-Pill.html" target="_blank" rel="noopener noreferrer" class=""><strong>Blue Pill</strong></a> 蓝色开发板。</p>
<table><thead><tr><th>STM32F103C8T6 基本参数</th><th>含义</th></tr></thead><tbody><tr><td><code>STM32</code></td><td>ST 公司推出的 32 位 MCU 系列</td></tr><tr><td><code>F103</code></td><td>F1 系列，主流入门级产品线</td></tr><tr><td><code>C</code></td><td>48 引脚封装</td></tr><tr><td><code>8</code></td><td>64 KB 片上 Flash 存储</td></tr><tr><td><code>T</code></td><td>LQFP 封装形式</td></tr><tr><td><code>6</code></td><td>工作温度范围 −40°C ~ 85°C</td></tr></tbody></table>
<p><img decoding="async" loading="lazy" alt="Blue Pill: Perspective view" src="https://wheelslab.github.io/sites/assets/images/STM32F103C8T6_Blue_Pill-1-0f1e7c48eb045b0123728f1375c4af43.jpg" width="1920" height="1280" class="img_ev3q"><img decoding="async" loading="lazy" alt="Blue Pill: Bottom view" src="https://wheelslab.github.io/sites/assets/images/STM32F103C8T6_Blue_Pill-3-6e423e3152b221d67b58b2e4f6e4f8a6.jpg" width="1920" height="1280" class="img_ev3q"></p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="stm32-整体结构概述和一般开发流程">STM32 整体结构概述和一般开发流程<a href="https://wheelslab.github.io/sites/blog/learn-stm32#stm32-%E6%95%B4%E4%BD%93%E7%BB%93%E6%9E%84%E6%A6%82%E8%BF%B0%E5%92%8C%E4%B8%80%E8%88%AC%E5%BC%80%E5%8F%91%E6%B5%81%E7%A8%8B" class="hash-link" aria-label="Direct link to STM32 整体结构概述和一般开发流程" title="Direct link to STM32 整体结构概述和一般开发流程" translate="no">​</a></h2>
<p>本文中的教程与示例代码均基于 <strong>STM32 最小系统板 + 面包板</strong>展开。</p>
<p>最小系统板上已经集成并焊接了维持 MCU 正常运行所必需的基础硬件电路，包括电源、复位以及时钟等相关电路。</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>关于最小系统板可以看以下视频</div><div class="admonitionContent_BuS1"><ul>
<li class="">Bilibili@洋桃电子<!-- -->
<ul>
<li class=""><a href="https://www.bilibili.com/video/BV1MW411q7Jn/?p=19&amp;share_source=copy_web&amp;vd_source=dfd0807ec9090236e4eccd0cc696b85b" target="_blank" rel="noopener noreferrer" class="">STM32入门100步 第 17 步 最小系统电路</a></li>
<li class=""><a href="https://www.bilibili.com/video/BV1LZ421x75m/" target="_blank" rel="noopener noreferrer" class="">如何看懂电路图？如何画原理图？</a></li>
<li class=""><a href="https://www.bilibili.com/video/BV1ct4y1o738/" target="_blank" rel="noopener noreferrer" class="">五花八门的电源标号该怎么看 VCC VEE VDD VSS GND的含义</a></li>
</ul>
</li>
</ul></div></div>
<p><img decoding="async" loading="lazy" alt="image-20260121155806858" src="https://wheelslab.github.io/sites/assets/images/image-20260121155806858-c8039fa3d1571442270eaaa7ffed0582.png" width="1882" height="1250" class="img_ev3q"></p>
<p>而面包板则用于通过飞线连接各类外部模块，方便进行实验和扩展。</p>
<p><img decoding="async" loading="lazy" alt="Front and back, medium breadboard with power rails exposed" src="https://wheelslab.github.io/sites/assets/images/bread-board-a21385daaa79853bb5cd963ca5dcc4ff.jpg" width="600" height="401" class="img_ev3q"></p>
<p>从整体上看，一块 STM32 开发板可以拆分为两个部分：</p>
<ol>
<li class="">STM32 MCU 芯片本身</li>
<li class="">围绕芯片工作的外部元件</li>
</ol>
<p>STM32 芯片就是蓝色开发板中央那个方形的黑色芯片：</p>
<p><img decoding="async" loading="lazy" alt="img" src="https://wheelslab.github.io/sites/assets/images/250px-STM32H7B0-5376feb5619b641dd0e21bebf284fd48.jpg" width="250" height="247" class="img_ev3q"><img decoding="async" loading="lazy" alt="img" src="https://wheelslab.github.io/sites/assets/images/250px-PIC12C508-HD-4c910ae75a8866e2ab2909c0eea519fe.jpg" width="250" height="242" class="img_ev3q"></p>
<p>STM32 芯片内部实际上是一个完整的微型计算机系统，其核心是 ARM 公司设计的 Cortex-M 系列内核（可类比为 CPU），周围通过多种总线连接了由 ST 公司设计的<strong>片上外设（Peripheral）</strong></p>
<p>这些片上外设包括但不限于：GPIO、USART、I2C、SPI、定时器（TIM）、ADC 等。可以将 STM32 理解为，一个将 CPU、内存和大量外设集成在单一芯片中的嵌入式计算平台。</p>
<p><img decoding="async" loading="lazy" alt="image-20260120214716773" src="https://wheelslab.github.io/sites/assets/images/image-20260120214716773-522c9ae40a3dbb6be204419303cb1c4f.png" width="1422" height="912" class="img_ev3q"></p>
<p><img decoding="async" loading="lazy" alt="image-20260120141322784" src="https://wheelslab.github.io/sites/assets/images/image-20260120141322784-e46b9ae5d9246bb5dad7d3e199832a4c.png" width="1034" height="797" class="img_ev3q"></p>
<p>STM32 芯片四周分布着一圈银白色的引脚，这些引脚对应的正是 <strong>GPIO 模块</strong>所管理的物理接口。STM32 正是通过这些引脚与外部世界进行交互。在开发板上，部分引脚会被进一步引出到两排针脚，方便通过面包板连接 LED、按键、传感器等外部元件。这些引脚除了最基础的输出高/低电平之外，更重要的是，这些引脚可以被复用，由 STM32 内部的不同<strong>外设模块接管</strong>。</p>
<blockquote>
<p>例如：</p>
<ul>
<li class="">USART 模块 → 通过引脚向 PC 发送调试信息</li>
<li class="">I2C 模块 → 通过引脚控制 OLED 屏幕</li>
<li class="">SPI 模块 → 驱动 Flash 或其他高速外设</li>
</ul>
</blockquote>
<p>STM32 的学习核心，本质上就是<strong>学会如何配置和使用这些内部模块</strong>。</p>
<p><img decoding="async" loading="lazy" alt="The-Generic-STM32F103-Pinout-Diagram.jpg" src="https://wheelslab.github.io/sites/assets/images/The-Generic-STM32F103-Pinout-Diagram-bc167a1950790d6db7fbd09d53ac1927.jpg" width="1912" height="1294" class="img_ev3q"></p>
<p>GPIO 模块是 STM32 与外部设备之间的接口，可以类比为“硬件层面的 API”。STM32 通常包含多个 GPIO 模块（GPIOA/GPIOB/GPIOC/GPIOD），每个 GPIO 模块会引出若干引脚，例如：</p>
<ul>
<li class=""><code>PA0 ~ PA15</code> → GPIOA</li>
<li class=""><code>PC13</code> → GPIOC 的第 13 号引脚</li>
</ul>
<p>程序中对某个引脚的控制，本质上就是在操作对应 GPIO 模块的寄存器。从宏观上看，STM32 的外设编程几乎都遵循同一套流程：</p>
<ol>
<li class="">开启模块时钟</li>
<li class="">初始化模块参数</li>
<li class="">使用模块功能</li>
</ol>
<p>STM32 的时钟系统（Clock Tree）本身较为复杂，完整展开需要相当多的篇幅。对于初学阶段，可以先建立一个直观认识：</p>
<div class="theme-admonition theme-admonition-tip admonition_xJq3 alert alert--success"><div class="admonitionHeading_Gvgb"><span class="admonitionIcon_Rf37"><svg viewBox="0 0 12 16"><path fill-rule="evenodd" d="M6.5 0C3.48 0 1 2.19 1 5c0 .92.55 2.25 1 3 1.34 2.25 1.78 2.78 2 4v1h5v-1c.22-1.22.66-1.75 2-4 .45-.75 1-2.08 1-3 0-2.81-2.48-5-5.5-5zm3.64 7.48c-.25.44-.47.8-.67 1.11-.86 1.41-1.25 2.06-1.45 3.23-.02.05-.02.11-.02.17H5c0-.06 0-.13-.02-.17-.2-1.17-.59-1.83-1.45-3.23-.2-.31-.42-.67-.67-1.11C2.44 6.78 2 5.65 2 5c0-2.2 2.02-4 4.5-4 1.22 0 2.36.42 3.22 1.19C10.55 2.94 11 3.94 11 5c0 .66-.44 1.78-.86 2.48zM4 14h5c-.23 1.14-1.3 2-2.5 2s-2.27-.86-2.5-2z"></path></svg></span>tip</div><div class="admonitionContent_BuS1"><p>时钟是驱动整个芯片运行的“心跳”。如果不理解可以看下科普视频</p><ul>
<li class="">Bilibili@<a href="https://space.bilibili.com/392208938/?spm_id_from=333.788.upinfo.detail.click" target="_blank" rel="noopener noreferrer" class="">技术Flow</a>：<a href="https://www.bilibili.com/video/BV121SnYiE7E/?share_source=copy_web&amp;vd_source=dfd0807ec9090236e4eccd0cc696b85b" target="_blank" rel="noopener noreferrer" class="">计算的心跳：时钟如何推动 CPU 前进?</a></li>
<li class="">Bilibili@<a href="https://space.bilibili.com/6110244/?spm_id_from=333.788.upinfo.detail.click" target="_blank" rel="noopener noreferrer" class="">六六学得很6</a>：<a href="https://www.bilibili.com/video/BV1yeKxz2E29/?share_source=copy_web&amp;vd_source=dfd0807ec9090236e4eccd0cc696b85b" target="_blank" rel="noopener noreferrer" class="">从零搭建计算机保姆级教程08——时钟原理</a></li>
<li class="">Bilibili@<a href="https://space.bilibili.com/395188578/?spm_id_from=333.788.upinfo.detail.click" target="_blank" rel="noopener noreferrer" class="">爱上半导体</a>：<a href="https://www.bilibili.com/video/BV1L29yYZEp4/?share_source=copy_web&amp;vd_source=dfd0807ec9090236e4eccd0cc696b85b" target="_blank" rel="noopener noreferrer" class="">全球销量第一的芯片!50年设计没变过！不到一块钱！包含23个晶体管！</a></li>
</ul></div></div>
<p><img decoding="async" loading="lazy" alt="img" src="https://wheelslab.github.io/sites/assets/images/stm32-clock-tree-stm32cubemx-config-b005a462e9ece05229190903dd59a83b.png" width="976" height="671" class="img_ev3q"></p>
<p>每一次时钟跳动，ARM Cortex 内核都会向前执行一步指令。这与 PC CPU 的主频概念类似——主频越高，每秒能执行的指令就越多。</p>
<p>在 STM32 内部，不同外设工作在不同的时钟频率下，它们通过不同的总线连接到系统中</p>
<ul>
<li class="">
<p>高速外设：AHB</p>
</li>
<li class="">
<p>低速外设：APB1 / APB2</p>
</li>
</ul>
<p>在实际开发中，只需要记住两点：</p>
<ol>
<li class=""><strong>任何外设在使用前都必须开启时钟</strong></li>
<li class="">初学阶段，时钟通常配置为较高频率即可</li>
</ol>
<p>时钟开启后，电路才具备工作条件，接下来就是<strong>配置模块参数</strong>。以 GPIO 为例，初始化时通常需要指定：使用的引脚号、输入 / 输出模式、是否开启上拉 / 下拉、输出速度。在库函数中，这些参数通常被封装在一个<strong>结构体</strong>中，我们只需要填充结构体成员，然后将结构体传给对应的初始化函数，即可配置好模块。几乎所有 STM32 外设的初始化流程都遵循这一模式。</p>
<p>初始化完成后，就可以通过库函数来使用模块功能了。下面是一个经典的<strong>点灯程序</strong>，可以视为嵌入式开发中的 “Hello World”：</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockTitle_OeMC">BlinkLED.c</div><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">"stm32f10x.h"</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property comment" style="color:#999988;font-style:italic">// 引入 SPL 库的头文件</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">"Delay.h"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">void</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 1. 开启模块时钟</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token comment" style="color:#999988;font-style:italic">// 所有外设的运行都依赖时钟</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token comment" style="color:#999988;font-style:italic">// PC13 属于 GPIOC，因此需要开启 GPIOC 的时钟</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">RCC_APB2PeriphClockCmd</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">RCC_APB2Periph_GPIOC</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> ENABLE</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 开启 GPIOC 时钟</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    </span><span class="token comment" style="color:#999988;font-style:italic">// 2. 配置模块参数</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">    GPIO_InitTypeDef GPIO_InitStructure </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token number" style="color:#36acaa">0</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">			  </span><span class="token comment" style="color:#999988;font-style:italic">// 包含 GPIO 配置信息的结构体</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	GPIO_InitStructure</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">GPIO_Mode </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> GPIO_Mode_Out_OD</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">	  </span><span class="token comment" style="color:#999988;font-style:italic">// 开漏输出模式</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	GPIO_InitStructure</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">GPIO_Pin </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> GPIO_Pin_13</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">			  </span><span class="token comment" style="color:#999988;font-style:italic">// PC13 引脚</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	GPIO_InitStructure</span><span class="token punctuation" style="color:#393A34">.</span><span class="token plain">GPIO_Speed </span><span class="token operator" style="color:#393A34">=</span><span class="token plain"> GPIO_Speed_2MHz</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain">	  </span><span class="token comment" style="color:#999988;font-style:italic">// IO 最大输出速度</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">GPIO_Init</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">GPIOC</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> </span><span class="token operator" style="color:#393A34">&amp;</span><span class="token plain">GPIO_InitStructure</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token keyword" style="color:#00009f">while</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		</span><span class="token comment" style="color:#999988;font-style:italic">// 3. 使用模块</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		</span><span class="token function" style="color:#d73a49">GPIO_WriteBit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">GPIOC</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> GPIO_Pin_13</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Bit_RESET</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 亮</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		</span><span class="token function" style="color:#d73a49">Delay_ms</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		</span><span class="token function" style="color:#d73a49">GPIO_WriteBit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">GPIOC</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> GPIO_Pin_13</span><span class="token punctuation" style="color:#393A34">,</span><span class="token plain"> Bit_SET</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 灭</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		</span><span class="token function" style="color:#d73a49">Delay_ms</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1000</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>从 C 源码到单片机上实际运行的程序，还需要经历以下步骤：</p>
<ol>
<li class="">
<p><strong>编译（Compile）</strong></p>
</li>
<li class="">
<p><strong>汇编（Assemble）</strong></p>
</li>
<li class="">
<p><strong>链接（Link）</strong></p>
</li>
</ol>
<p>生成的最终产物（如 ELF / HEX / BIN）会被烧录到 STM32 的 Flash 中。</p>
<p><img decoding="async" loading="lazy" alt="The Definitive Guide to ARM® Cortex®-M3 and Cortex®-M4 Processors 3rd Edition" src="https://wheelslab.github.io/sites/assets/images/common-software-compilation-flow-ed3168acff7e6ff872555c08f6726b1e.png" width="1492" height="730" class="img_ev3q"></p>
<p>程序烧录和调试通常通过 <strong>调试器（如 ST-Link V2）</strong> 完成。除了烧录代码外，调试器的作用还包括：设置断点、单步执行、查看寄存器和内存。</p>
<p><img decoding="async" loading="lazy" alt="The Definitive Guide to ARM® Cortex®-M3 and Cortex®-M4 Processors 3rd Edition" src="https://wheelslab.github.io/sites/assets/images/A-simplified-software-development-flow-d0b3377566afc8025b154c5298715ad2.png" width="2129" height="1063" class="img_ev3q"></p>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="stm32-平衡车项目概览">STM32 平衡车项目概览<a href="https://wheelslab.github.io/sites/blog/learn-stm32#stm32-%E5%B9%B3%E8%A1%A1%E8%BD%A6%E9%A1%B9%E7%9B%AE%E6%A6%82%E8%A7%88" class="hash-link" aria-label="Direct link to STM32 平衡车项目概览" title="Direct link to STM32 平衡车项目概览" translate="no">​</a></h2>
<p><a href="https://zh.moegirl.org.cn/%E8%BF%99%E6%98%AFooo%EF%BC%8C%E4%BD%A0%E5%B7%B2%E7%BB%8F%E5%AD%A6%E4%BC%9A%E4%BA%86%EF%BC%8C%E7%8E%B0%E5%9C%A8%E5%8E%BBxxx%E5%90%A7%EF%BC%81" target="_blank" rel="noopener noreferrer" class="">你已经会点灯了，现在我们来做一个平衡车吧（笑）.jpg</a></p>
<p><img decoding="async" loading="lazy" alt="这是ooo，你已经学会了，现在去xxx吧！" src="https://wheelslab.github.io/sites/assets/images/from-one-plus-one-to-calculus-7418525ee4a29a4d5e5abbb47d39cb89.jpeg" width="280" height="602" class="img_ev3q"></p>
<p>整个项目中最具挑战、也是最核心的部分，无疑是 PID 控制算法——它直接决定了小车是否能够稳定站立。</p>
<p>下面将从硬件组成、软件结构以及整体控制逻辑三个层面，对该 STM32 平衡车项目进行一个整体概览。</p>
<p>本项目依然基于 STM32F103C8T6（最小系统板）进行开发，整体硬件由以下模块构成：</p>
<ul>
<li class="">
<p>两个直流减速电机</p>
</li>
<li class="">
<p>TB6612 电机驱动芯片（可同时驱动两路直流电机）</p>
</li>
<li class="">
<p>3 颗 LED，用于电量指示</p>
</li>
<li class="">
<p>ADC1，用于采集电池电压</p>
</li>
<li class="">
<p>USART3，连接蓝牙遥控模块</p>
</li>
<li class="">
<p>I2C1，连接姿态传感器 MPU6050</p>
</li>
<li class="">
<p>一个按键，用于控制电机启停</p>
</li>
</ul>
<p>下面是原理图，已经标注了各个模块及其对应的引脚连接方式：</p>
<p><img decoding="async" loading="lazy" alt="平衡车原理图" src="https://wheelslab.github.io/sites/assets/images/balance-car-schematic-495cc89d9cf822fee62c00dcdf3d31fb.png" width="2263" height="1600" class="img_ev3q"></p>
<p>从软件结构上看，该项目依然沿用了 STM32 裸机开发中非常典型的一种组织方式：<strong>“先初始化所有模块，再在主循环中周期性调用各模块的处理函数。”</strong></p>
<p>下面是程序的 <code>main</code> 函数主体：</p>
<div class="language-c codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-c codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">/*</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * ************************************************</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * </span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * @author ICLHC</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * @date 2025/10/15</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * @brief 平衡车项目（bilibili@铁头山羊 的 STM32 标准库平衡车课程）</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * </span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * CPU:     STM32F103C8</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * </span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic"> * ************************************************</span><br></span><span class="token-line" style="color:#393A34"><span class="token comment" style="color:#999988;font-style:italic">*/</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">"stm32f10x.h"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">"app_bat.h"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">"app_button.h"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">"app_pwm.h"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">"app_encoder.h"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">"app_mpu6050.h"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">"app_motor.h"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">"delay.h"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">"app_usart2.h"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">"task.h"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">"app_control.h"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token macro property directive-hash" style="color:#36acaa">#</span><span class="token macro property directive keyword" style="color:#00009f">include</span><span class="token macro property" style="color:#36acaa"> </span><span class="token macro property string" style="color:#e3116c">"app_rc.h"</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token keyword" style="color:#00009f">int</span><span class="token plain"> </span><span class="token function" style="color:#d73a49">main</span><span class="token punctuation" style="color:#393A34">(</span><span class="token keyword" style="color:#00009f">void</span><span class="token punctuation" style="color:#393A34">)</span><span class="token plain"> </span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token comment" style="color:#999988;font-style:italic">// 配置中断优先级分组</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">NVIC_PriorityGroupConfig</span><span class="token punctuation" style="color:#393A34">(</span><span class="token plain">NVIC_PriorityGroup_0</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 没有抢占优先级</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">App_Bat_Init</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> 	</span><span class="token comment" style="color:#999988;font-style:italic">// 电池监控</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">App_Button_Init</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> 	</span><span class="token comment" style="color:#999988;font-style:italic">// 电机开关</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">App_PWM_Init</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> 	</span><span class="token comment" style="color:#999988;font-style:italic">// TB6612</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">App_Encoder_Init</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 编码器测速</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">App_MotorInit</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> 	</span><span class="token comment" style="color:#999988;font-style:italic">// 电机调速系统</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">App_USART2_Init</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> 	</span><span class="token comment" style="color:#999988;font-style:italic">// 串口 2 初始化</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">App_MPU6050_Init</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// MPU6050 初始化（姿态传感器）</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">App_Control_Init</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> </span><span class="token comment" style="color:#999988;font-style:italic">// 平衡车控制系统（速度环/角度环/转速环）</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token function" style="color:#d73a49">App_RC_Init</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"> 		</span><span class="token comment" style="color:#999988;font-style:italic">// 蓝牙遥控器模块</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token keyword" style="color:#00009f">while</span><span class="token punctuation" style="color:#393A34">(</span><span class="token number" style="color:#36acaa">1</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">{</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain" style="display:inline-block"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		</span><span class="token function" style="color:#d73a49">App_Bat_Proc</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		</span><span class="token function" style="color:#d73a49">App_Button_Proc</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		</span><span class="token function" style="color:#d73a49">App_Motor_Proc</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		</span><span class="token function" style="color:#d73a49">App_MPU6050_Proc</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		</span><span class="token function" style="color:#d73a49">App_Control_Proc</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		</span><span class="token function" style="color:#d73a49">App_RC_Proc</span><span class="token punctuation" style="color:#393A34">(</span><span class="token punctuation" style="color:#393A34">)</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	</span><span class="token punctuation" style="color:#393A34">}</span><span class="token punctuation" style="color:#393A34">;</span><span class="token plain"></span><br></span><span class="token-line" style="color:#393A34"><span class="token plain"></span><span class="token punctuation" style="color:#393A34">}</span><br></span></code></pre></div></div>
<p>尽管相较于“点灯程序”复杂了不少，但整体框架其实并没有发生本质变化。</p>
<p>下面按照初始化顺序，简要说明各模块在系统中的角色。</p>
<table><thead><tr><th>模块名</th><th>模块类型</th><th>主要功能</th><th>关键接口 / 信号</th></tr></thead><tbody><tr><td><code>app_bat</code></td><td>电池监控</td><td>通过 ADC 周期性采集电池电压，并用 LED 显示电量状态，为系统提供电源状态反馈，辅助电压补偿与安全运行</td><td><code>VBAT_SENSE</code> → <code>ADC1_CH8``App_Bat_Proc()</code></td></tr><tr><td><code>app_button</code></td><td>按键输入</td><td>控制 TB6612 电机驱动的使能状态，实现电机启停的本地用户控制</td><td>GPIO 输入<code>App_Button_Proc()</code></td></tr><tr><td><code>app_pwm</code></td><td>电机驱动</td><td>封装 TB6612，使用 PWM 控制电机转速、GPIO 控制转向，直接执行控制系统给出的电机控制指令</td><td>PWM ×1 + GPIO ×2 / 电机电机使能、转速、方向接口</td></tr><tr><td><code>app_encoder</code></td><td>编码器采集</td><td>获取电机实际转速与转动角度，作为速度闭环控制中的核心反馈量</td><td>编码器接口速度 / 角度读取函数</td></tr><tr><td><code>app_motor</code></td><td>电机调速系统</td><td>基于 PID 的电机转速闭环控制，利用实际转速反馈计算目标电压，并换算为 PWM 占空比交由电机驱动模块执行</td><td>实际转速反馈PWM 占空比输出</td></tr><tr><td><code>app_usart2</code></td><td>调试串口</td><td>通过串口输出运行状态与调试信息，用于参数整定和问题排查</td><td><code>USART2</code></td></tr><tr><td><code>app_mpu6050</code></td><td>姿态传感器</td><td>采集三轴加速度与角速度并计算欧拉角，其中俯仰角作为平衡控制中最关键的姿态反馈信号</td><td>I2C 接口俯仰角输出</td></tr><tr><td><code>app_control</code></td><td>平衡车控制系统</td><td>由多级 PID 串联构成的核心控制系统：电机转速环 → 俯仰角平衡环 → 前进/后退速度环 → 差速转向环，逐层约束并修正整车运动状态</td><td>各级 PID 输入 / 输出</td></tr><tr><td><code>app_rc</code></td><td>蓝牙遥控</td><td>接收遥控器控制指令并经 USART3 传输给单片机，用于控制小车运动方向与速度</td><td><code>USART3</code></td></tr></tbody></table>
<p>整个小车的一切，无论是硬件还是软件，都是围绕平衡小车的控制系统来设计的。<strong>所有模块的最终目标只有一个：服务于平衡控制系统</strong>。</p>
<ul>
<li class="">
<p>电池电压 → 系统供能与电压补偿</p>
</li>
<li class="">
<p>编码器 → 电机转速反馈</p>
</li>
<li class="">
<p>姿态传感器 → 俯仰角反馈</p>
</li>
<li class="">
<p>蓝牙模块 → 用户控制指令</p>
</li>
</ul>
<p>就拿这个主循环来说，代码中高亮的部分都是在获取传感器的输入或者控制指令，而最终会影响到整个控制系统。</p>
<div class="language-text codeBlockContainer_Ckt0 theme-code-block" style="--prism-color:#393A34;--prism-background-color:#f6f8fa"><div class="codeBlockContent_QJqH"><pre tabindex="0" class="prism-code language-text codeBlock_bY9V thin-scrollbar" style="color:#393A34;background-color:#f6f8fa"><code class="codeBlockLines_e6Vv"><span class="token-line" style="color:#393A34"><span class="token plain">while(1){</span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">		App_Bat_Proc();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		App_Button_Proc();</span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">		App_Motor_Proc();</span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">		App_MPU6050_Proc();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">		App_Control_Proc(); // 这个是核心，其他模块都为此服务</span><br></span><span class="token-line theme-code-block-highlighted-line" style="color:#393A34"><span class="token plain">		App_RC_Proc();</span><br></span><span class="token-line" style="color:#393A34"><span class="token plain">	};</span><br></span></code></pre></div></div>
<h2 class="anchor anchorTargetHideOnScrollNavbar_vjPI" id="参考资料">参考资料<a href="https://wheelslab.github.io/sites/blog/learn-stm32#%E5%8F%82%E8%80%83%E8%B5%84%E6%96%99" class="hash-link" aria-label="Direct link to 参考资料" title="Direct link to 参考资料" translate="no">​</a></h2>
<ul>
<li class="">
<p>STM32 视频教程：</p>
<ul>
<li class="">Bilibili@<strong>江协科技</strong>：<!-- -->
<ul>
<li class="">STM32 入门：<a href="https://www.bilibili.com/video/BV1th411z7sn/?share_source=copy_web&amp;vd_source=dfd0807ec9090236e4eccd0cc696b85b" target="_blank" rel="noopener noreferrer" class="">STM32入门教程-2023版 细致讲解 中文字幕</a></li>
<li class="">51 单片机：<a href="https://www.bilibili.com/video/BV1Mb411e7re/?spm_id_from=333.1387.favlist.content.click&amp;vd_source=09e40ceac2e24458541f02b7458cb1d5" target="_blank" rel="noopener noreferrer" class="">51单片机入门教程-2020版 程序全程纯手打 从零开始入门</a></li>
<li class="">PID：<a href="https://www.bilibili.com/video/BV1G9zdYQEr3/?share_source=copy_web&amp;vd_source=dfd0807ec9090236e4eccd0cc696b85b" target="_blank" rel="noopener noreferrer" class="">PID入门教程-电机控制 倒立摆 全程手把手打代码调试</a></li>
</ul>
</li>
<li class="">Bilibili@<strong>铁头山羊</strong>：<!-- -->
<ul>
<li class="">STM32 基础教程：<a href="https://www.bilibili.com/video/BV11X4y1j7si/?p=4&amp;share_source=copy_web&amp;vd_source=dfd0807ec9090236e4eccd0cc696b85b" target="_blank" rel="noopener noreferrer" class="">铁头山羊stm32 入门教程【新版】</a></li>
<li class="">STM32 平衡车：<a href="https://www.bilibili.com/video/BV1wdqhY4E3R/?share_source=copy_web&amp;vd_source=dfd0807ec9090236e4eccd0cc696b85b" target="_blank" rel="noopener noreferrer" class="">平衡车要开课了，先来个原地起飞~</a></li>
<li class="">STM32 HAL 库：<a href="https://www.bilibili.com/video/BV16J4m1w7HB/?share_source=copy_web" target="_blank" rel="noopener noreferrer" class="">[STM32 HAL库]课程介绍，最佳教程，没有之一~</a></li>
</ul>
</li>
</ul>
</li>
<li class="">
<p><a href="https://deepbluembedded.com/stm32-blue-pill-pinout-programming-guide/" target="_blank" rel="noopener noreferrer" class="">STM32 Blue Pill Pinout &amp; Programming Guide</a></p>
</li>
<li class="">
<p>裸机编程：</p>
<ul>
<li class="">Klein Embedded：<a href="https://kleinembedded.com/stm32-without-cubeide-part-1-the-bare-necessities/" target="_blank" rel="noopener noreferrer" class="">STM32 without CubeIDE (Part 1): The bare necessities</a></li>
<li class="">YouTube@<strong>Low Byte Productions</strong>：<a href="https://www.youtube.com/watch?v=uQQsDWLRDuI&amp;list=PLP29wDx6QmW7HaCrRydOnxcy8QmW0SNdQ" target="_blank" rel="noopener noreferrer" class="">Blinky To Bootloader: Bare Metal Programming Series</a></li>
<li class="">GitHub@<strong>cpq</strong>：<strong><a href="https://github.com/cpq/bare-metal-programming-guide" target="_blank" rel="noopener noreferrer" class="">bare-metal-programming-guide</a></strong></li>
</ul>
</li>
<li class="">
<p>reddit@<a href="https://www.reddit.com/r/embedded/" target="_blank" rel="noopener noreferrer" class="">r/embedded</a></p>
<ul>
<li class=""><a href="https://www.reddit.com/r/embedded/comments/18g3aae/stm32_learning_curve_for_beginners/" target="_blank" rel="noopener noreferrer" class="">STM32 Learning Curve for beginners</a></li>
</ul>
</li>
<li class="">
<p>自动控制原理：</p>
<ul>
<li class=""><a href="https://www.bilibili.com/video/BV1LKLPzfEm4/?share_source=copy_web&amp;vd_source=dfd0807ec9090236e4eccd0cc696b85b" target="_blank" rel="noopener noreferrer" class="">【4K修复】自动控制原理 卢京潮 西北工业大学 </a></li>
<li class=""><a href="https://www.bilibili.com/video/BV1jt411M7QU/?share_source=copy_web&amp;vd_source=dfd0807ec9090236e4eccd0cc696b85b" target="_blank" rel="noopener noreferrer" class="">自动控制原理 Bilibili@DR_CAN</a></li>
</ul>
</li>
<li class="">
<p>电子入门 视频教程</p>
<ul>
<li class="">Bilibili@<strong>洋桃电子</strong>
<ul>
<li class=""><a href="https://space.bilibili.com/277276709/lists/1852078?type=season" target="_blank" rel="noopener noreferrer" class="">合集·电子大百科（洋桃电子的技术科普）</a></li>
<li class=""><a href="https://space.bilibili.com/277276709/lists/2985482?type=season" target="_blank" rel="noopener noreferrer" class="">合集·极速入门数模电路（全新面包板入门电子制作）</a></li>
</ul>
</li>
</ul>
</li>
<li class="">
<p>电子入门：</p>
<ul>
<li class=""><a href="https://www.emoe.xyz/" target="_blank" rel="noopener noreferrer" class="">Emoe工作室</a>：<a href="https://www.emoe.xyz/all-about-electronics/#1-gt-gt" target="_blank" rel="noopener noreferrer" class="">电子入坑百科全书</a></li>
<li class=""><a href="https://thiscute.world/" target="_blank" rel="noopener noreferrer" class="">This Cute World</a>：<a href="https://thiscute.world/posts/electrical-engineering-circuits-basics-1/" target="_blank" rel="noopener noreferrer" class="">EE 入门（一） - 电子电路基础知识</a></li>
<li class="">YouTube@<strong>Science Buddies</strong>：<a href="https://youtu.be/MtiJz7gh1VU?si=wbZ2E7lPZTlAtegH" target="_blank" rel="noopener noreferrer" class="">How to Use a Breadboard</a></li>
<li class=""><a href="https://www.sparkfun.com/" target="_blank" rel="noopener noreferrer" class="">sparkfun</a>：<!-- -->
<ul>
<li class=""><a href="https://learn.sparkfun.com/tutorials/how-to-use-a-breadboard/all" target="_blank" rel="noopener noreferrer" class="">How to Use a Breadboard</a></li>
<li class=""><a href="https://www.sparkfun.com//engineering-essentials" target="_blank" rel="noopener noreferrer" class="">Engineering Essentials</a></li>
</ul>
</li>
</ul>
</li>
<li class="">
<p>一些书籍：</p>
<ul>
<li class=""><a href="https://www.amazon.com/Definitive-Guide-Cortex%C2%AE-M3-Cortex%C2%AE-M4-Processors/dp/0124080820" target="_blank" rel="noopener noreferrer" class="">The Definitive Guide to ARM® Cortex®-M3 and Cortex®-M4 Processors 3rd Edition</a></li>
<li class=""><a href="https://www.amazon.com/Making-Embedded-Systems-Patterns-Software/dp/1098151542/ref=pd_lpo_d_sccl_2/138-7367255-5244911?pd_rd_w=6hkNR&amp;content-id=amzn1.sym.4c8c52db-06f8-4e42-8e56-912796f2ea6c&amp;pf_rd_p=4c8c52db-06f8-4e42-8e56-912796f2ea6c&amp;pf_rd_r=MK2KSQRSB3YM3012YRZS&amp;pd_rd_wg=iskUL&amp;pd_rd_r=6ea5f405-fbd6-4709-8df5-80ff609787e1&amp;pd_rd_i=1098151542&amp;psc=1" target="_blank" rel="noopener noreferrer" class="">Making Embedded Systems: Design Patterns for Great Software 2nd</a></li>
<li class=""><a href="https://www.amazon.com/Make-Electronics-hands-electronics-enthusiast/dp/1680456873/ref=bmx_dp_d_sccl_1_2/138-7367255-5244911?pd_rd_w=9bqdf&amp;content-id=amzn1.sym.1db06c01-2868-43e5-b772-15226cedca7d&amp;pf_rd_p=1db06c01-2868-43e5-b772-15226cedca7d&amp;pf_rd_r=YPZ7X3JTBWWM6427MYPM&amp;pd_rd_wg=Xosqr&amp;pd_rd_r=f6d467e5-66d3-4bc2-b138-79ab846b4ef9&amp;pd_rd_i=1680456873&amp;psc=1" target="_blank" rel="noopener noreferrer" class="">Make: Electronics: Learning by Discovery: A hands-on primer for the new electronics enthusiast 3rd Edition</a></li>
<li class=""><a href="https://www.amazon.com/Practical-Electronics-Inventors-Fourth-Scherz/dp/1259587541/ref=pd_vtp_d_sccl_1_3/138-7367255-5244911?pd_rd_w=XB8qs&amp;content-id=amzn1.sym.2aec5a0f-72e8-4d2b-85c5-8e0dd71765ff&amp;pf_rd_p=2aec5a0f-72e8-4d2b-85c5-8e0dd71765ff&amp;pf_rd_r=T04RP2K6K3CBQYM2AE23&amp;pd_rd_wg=Asu3k&amp;pd_rd_r=06057bdf-6ea1-4758-b08d-b9e20ab2d545&amp;pd_rd_i=1259587541&amp;psc=1" target="_blank" rel="noopener noreferrer" class="">Practical Electronics for Inventors, Fourth Edition 4th Edition</a></li>
</ul>
</li>
<li class="">
<p>RTOS</p>
<ul>
<li class="">YouTube@<strong>DigiKey</strong>：<a href="https://youtu.be/F321087yYy4?si=kA3Z7I-tLQ9bgrqT" target="_blank" rel="noopener noreferrer" class="">Introduction to RTOS Part 1 - What is a Real-Time Operating System (RTOS)? | Digi-Key Electronics</a></li>
</ul>
</li>
<li class="">
<p>嵌入式软件开发</p>
<ul>
<li class="">YouTube@<strong>hoff._world</strong>：<a href="https://youtu.be/Dzn0woX-WW0?si=4qOjxvjYf7oMY88t" target="_blank" rel="noopener noreferrer" class="">COMPLETE EMBEDDED SYSTEMS Roadmap - What Arduino Won't Teach You</a></li>
</ul>
</li>
<li class="">
<p>YouTube@<strong>VisCircuit 電路筆記</strong>：<a href="https://youtu.be/t0zRpOQHeF4?si=hqLdwYkC-oYbySSw" target="_blank" rel="noopener noreferrer" class="">ESP32, Arduino, STM32 和 8051 是怎麼發明的？</a></p>
</li>
</ul>]]></content:encoded>
            <author>iclhchc@gmail.com (WheelsLab)</author>
            <category>STM32</category>
        </item>
    </channel>
</rss>