<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>归档 on 栈外随记</title>
    <link>https://btio.cn/</link>
    <description>Recent content in 归档 on 栈外随记</description>
    <image>
      <title>栈外随记</title>
      <url>https://btio.cn/images/logo-arong.svg</url>
      <link>https://btio.cn/images/logo-arong.svg</link>
    </image>
    <generator>Hugo</generator>
    <language>zh-CN</language><lastBuildDate>Sun, 01 Nov 2026 00:00:00 +0800</lastBuildDate>
    <atom:link href="https://btio.cn/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>我为什么越来越看好 AI 眼镜</title>
      <link>https://btio.cn/posts/2026/11/01/%E6%88%91%E4%B8%BA%E4%BB%80%E4%B9%88%E8%B6%8A%E6%9D%A5%E8%B6%8A%E7%9C%8B%E5%A5%BD-ai-%E7%9C%BC%E9%95%9C/</link>
      <pubDate>Sun, 01 Nov 2026 00:00:00 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/11/01/%E6%88%91%E4%B8%BA%E4%BB%80%E4%B9%88%E8%B6%8A%E6%9D%A5%E8%B6%8A%E7%9C%8B%E5%A5%BD-ai-%E7%9C%BC%E9%95%9C/</guid>
      <description>&lt;p&gt;最近研究了一圈 AI 眼镜，我越来越觉得，这个东西值得认真关注。&lt;/p&gt;
&lt;h2 align=&#34;center&#34;&gt;一、为什么这么多厂商都在做&lt;/h2&gt;
&lt;p&gt;按照 Omdia 的估算，2025 年全球 AI 眼镜出货量约 870 万副，接近 900 万副。市场还不大，但已经吸引了不少厂商进场。&lt;strong&gt;大家争的除了眼前的销量，还有未来 AI 入口的位置。&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;眼镜的位置，确实太好了。眼睛、耳朵、嘴巴都在附近，适合采集画面、接收声音，再通过语音或者显示给你反馈。遇到不认识的东西，看着它问一句，AI 就能结合画面回答，不用再拿着手机对准、拍照、上传。&lt;/p&gt;
&lt;p&gt;手机当然也能做，但眼镜有机会把这些操作变得更自然。尤其当你正在走路、搬东西，或者双手忙着的时候，这个区别就出来了。&lt;/p&gt;
&lt;p&gt;我看好的，其实是 AI 从“等你提问”，慢慢变成一个能理解你当下处境的助手。它知道你刚才让它看了什么，正在处理什么事情，再结合这些信息提供帮助。如果做得好，交流起来就不用每次都从头解释。&lt;/p&gt;
&lt;h2 align=&#34;center&#34;&gt;二、眼镜能帮我们做什么&lt;/h2&gt;
&lt;p&gt;翻译，导航，拍摄，录屏，听歌，提词、消息提醒，扫码付款，全天候记录等等，这些都是比较容易想到的场景。并且，交互也不只有语音。或者触摸按键，眨眼这种控制，Meta 已经推出配合眼镜使用的肌电腕带，通过手腕处的肌肉电信号识别细微动作，让人动动手指就能操作。在不方便开口的时候，也能通过手势完成选择、确认等操作。&lt;/p&gt;
&lt;h2 align=&#34;center&#34;&gt;三、一个能帮人记住事情的助手&lt;/h2&gt;
&lt;p&gt;不过，最让我感兴趣的，还是“帮人记住事情”。临时冒出一个想法，说一句就保存下来；过了几天想不起细节，再问它：“上次那件事，我们最后怎么说的？”&lt;/p&gt;
&lt;p&gt;如果这些能力足够可靠，眼镜就不只是拍摄工具了。它可能逐渐积累起一个和你生活有关的资料库，帮你找回那些经历过、却已经忘掉的信息。&lt;/p&gt;
&lt;h2 align=&#34;center&#34;&gt;四、长期记录会带来多少数据&lt;/h2&gt;
&lt;p&gt;顺着这个方向想，背后的存储需求也很值得关注。&lt;/p&gt;
&lt;p&gt;我们现在拍照录像，通常是主动选一个时刻。如果未来变成每天长时间记录，数据量就完全不同了。做个简单假设：视频平均码率为 5 Mbps，每天记录 8 小时，**一天大约就是 18 GB，一年约 6.6 TB。**这还只是一个人的一份视频，没有算备份。&lt;/p&gt;
&lt;p&gt;这不是在预测未来每个人都会这样录，而是说，一旦长时间记录普及，个人存储需求确实有可能上一个台阶。再乘上大量用户，云端存储、数据上传，以及 AI 检索和处理的需求，都可能跟着增加。&lt;/p&gt;
&lt;p&gt;当然，也不一定所有原始视频都往云端传。上传要电量和带宽，长期保存要花钱，用户也未必愿意把生活完整交出去。更现实的做法，可能是设备先筛选，保留重要片段，把普通内容整理成文字摘要，再由用户决定哪些上传、哪些删除。&lt;/p&gt;
&lt;p&gt;这么看，未来值得竞争的能力还有：**怎样用更少的空间，留下真正有用的信息。**毕竟存了一年的录像，问一句却找不到答案，那也只是多了一堆文件。&lt;/p&gt;
&lt;p&gt;这也让我想到另一件事：买眼镜可能只是第一笔费用。如果后面还有云空间、AI 服务和数据处理，用户每个月愿意花多少钱？厂商能不能靠这些收入覆盖成本？这些问题，可能会影响产品最终怎么设计。&lt;/p&gt;
&lt;h2 align=&#34;center&#34;&gt;五、隐私是绕不开的问题&lt;/h2&gt;
&lt;p&gt;但越往“随身记忆助手”发展，隐私问题就越突出。&lt;/p&gt;
&lt;p&gt;手机举起来拍，别人通常看得出来。眼镜一直戴在脸上，即便有拍摄指示灯，对方也未必留意。如果连聊天内容、生活轨迹都长期保存，一旦泄露，影响也会更大。记录是否经过同意，拍摄状态是否明显，数据能否导出和彻底删除，都会影响人们愿不愿意接受它。&lt;/p&gt;
&lt;h2 align=&#34;center&#34;&gt;六、续航、重量和颜值都很重要&lt;/h2&gt;
&lt;p&gt;硬件也有实实在在的难题。芯片、电池、摄像头和光学模组要塞进小小的镜架，功能越多，重量、发热和续航就越难兼顾。能戴一天，不代表能连续录一天；拿在手里觉得不重，也不代表架在鼻梁上几个小时还舒服。&lt;/p&gt;
&lt;p&gt;针对续航，已经有厂商采用可换电设计。例如，夸克 AI 眼镜 S1 使用可更换的双电池方案，用户可以通过更换电池延长使用时间。此外，部分产品配有充电盒，方便外出补电。&lt;/p&gt;
&lt;p&gt;还有颜值，哈哈，这个真的不能忽略。我之前在线下体验过，有些款式对我来说确实有点影响颜值。眼镜每天都在脸上，功能再强，如果不好看、夹头、压鼻梁，最后可能还是放进抽屉里。&lt;/p&gt;
&lt;p&gt;对本来就需要戴眼镜的人来说，它又有天然的吸引力。如果度数配得合适，外观和舒适度也过关，相当于把原来就要戴的东西升级了。但不同人的脸型、鼻梁和度数不同，厂商还得把配镜和售后这些事情做好。&lt;/p&gt;
&lt;h2 align=&#34;center&#34;&gt;七、它会取代手机吗&lt;/h2&gt;
&lt;p&gt;眼镜取代手机，会成为一个趋势，现在更可能先发生的，是一些简单、频繁的操作逐渐转移到眼镜上，手机继续承担大屏操作和其他任务。&lt;/p&gt;
&lt;p&gt;眼镜最后能走多远，既要看 AI 有多聪明，硬件发展有多快，也要看它能不能让人舒服地戴着，持续解决问题，还负担得起长期使用的费用。&lt;/p&gt;
&lt;p&gt;如果以后出门，一副眼镜就能帮我翻译、导航、记录重点，需要时还能找回忘记的事情，那我确实会很想买。再往后想，它带来的变化可能还会延伸到存储、计算、服务和我们管理个人数据的方式。&lt;/p&gt;
&lt;p&gt;越研究，越觉得这件事有意思。但真正让我期待的，还是它什么时候能从“演示起来很酷”，变成我每天都愿意戴的东西。&lt;/p&gt;
&lt;hr&gt;
&lt;h2 id=&#34;参考资料与视频&#34;&gt;参考资料与视频&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;https://omdia.tech.informa.com/pr/2026/mar/global-ai-glasses-shipments-reach-8point7-million-units-with-mainland-china-emerging-as-the-fastest-growing-market&#34;&gt;Omdia：2025 年全球 AI 眼镜出货量约 870 万副&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.alizila.com/alibaba-launches-new-quark-ai-glasses-series-in-china-deeply-integrated-with-qwen/&#34;&gt;阿里巴巴：夸克 AI 眼镜 S1 的可换电双电池方案&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;https://www.youtube.com/watch?v=gZ9IsB72nVk&#34;&gt;扎克伯格演示智能眼镜与肌电腕带（YouTube 官方视频，约 4 分钟）&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;注：存储容量为指定码率和记录时长下的简单测算；关于存储、云服务和商业模式的内容属于个人推演，并非确定的行业预测。&lt;/p&gt;</description>
    </item>
    <item>
      <title>周末重拾 STM32，从点灯开始</title>
      <link>https://btio.cn/posts/2026/10/31/%E9%87%8D%E6%8B%BE-stm32%E4%BB%8E%E7%82%B9%E7%81%AF%E5%BC%80%E5%A7%8B/</link>
      <pubDate>Sat, 31 Oct 2026 00:00:00 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/10/31/%E9%87%8D%E6%8B%BE-stm32%E4%BB%8E%E7%82%B9%E7%81%AF%E5%BC%80%E5%A7%8B/</guid>
      <description>&lt;h2 align=&#34;center&#34;&gt;背景介绍&lt;/h2&gt;
&lt;p&gt;毕业后很久没用过 STM32 了，今天刚好周末，看到家里还有一块 STM32F103C8T6 最小系统开发板，就拿出来玩一下。这次从点灯开始，回顾从 CubeMX 配置到 VS Code 编译、烧录并运行的流程，顺手记录下来，方便以后回顾。&lt;/p&gt;
&lt;p&gt;这次使用 &lt;strong&gt;MacBook&lt;/strong&gt; 开发，硬件是 &lt;strong&gt;STM32F103C8T6 最小系统开发板和 USB 转 TTL 模块&lt;/strong&gt;，通过串口烧录。&lt;/p&gt;
&lt;p&gt;软件用到以下四款工具：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;STM32CubeMX&lt;/strong&gt;：配置时钟、GPIO 等，生成工程。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;STM32CubeIDE&lt;/strong&gt;：提供当前工程使用的 ARM GCC 和 Make 编译工具。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;STM32CubeProgrammer&lt;/strong&gt;：负责烧录、校验，通过命令行工具发送启动命令。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;VS Code&lt;/strong&gt;：编辑代码，通过“项目助手”扩展调用上述编译、烧录工具，实现一键编译烧录并运行。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;最终实现的效果是：日常修改和下载都在 VS Code 中完成，每次下载前手动按一下开发板 RESET，再点击“编译烧录并运行”即可。&lt;/p&gt;
&lt;p&gt;下面按实际操作顺序，记录具体的配置和烧录流程。&lt;/p&gt;
&lt;h2 align=&#34;center&#34;&gt;一、CubeMX 配置工程&lt;/h2&gt;
&lt;h3 align=&#34;center&#34;&gt;1. 配置外部时钟&lt;/h3&gt;
&lt;p&gt;在 &lt;strong&gt;System Core → RCC&lt;/strong&gt; 中，将 HSE 设置为 &lt;strong&gt;Crystal/Ceramic Resonator&lt;/strong&gt;，使用开发板上的外部晶振。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;RCC 外部晶振配置&#34; loading=&#34;lazy&#34; src=&#34;https://picgocloud.com/m/a6a1b5a0-a3f1-4db4-b478-8e1c70dddbdf.png&#34;&gt;&lt;/p&gt;
&lt;h3 align=&#34;center&#34;&gt;2. 配置时钟树&lt;/h3&gt;
&lt;p&gt;在 &lt;strong&gt;Clock Configuration&lt;/strong&gt; 中，使用 8 MHz 外部晶振，经 PLL 倍频至 &lt;strong&gt;72 MHz&lt;/strong&gt;，选择 PLLCLK 作为系统时钟；APB1 二分频至 &lt;strong&gt;36 MHz&lt;/strong&gt;。&lt;/p&gt;</description>
    </item>
    <item>
      <title>【BES】编译配置（03）：Make 变量怎样变成 C 宏</title>
      <link>https://btio.cn/posts/2026/10/23/bes%E7%BC%96%E8%AF%91%E9%85%8D%E7%BD%AE03make-%E5%8F%98%E9%87%8F%E6%80%8E%E6%A0%B7%E5%8F%98%E6%88%90-c-%E5%AE%8F/</link>
      <pubDate>Fri, 23 Oct 2026 00:00:00 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/10/23/bes%E7%BC%96%E8%AF%91%E9%85%8D%E7%BD%AE03make-%E5%8F%98%E9%87%8F%E6%80%8E%E6%A0%B7%E5%8F%98%E6%88%90-c-%E5%AE%8F/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://btio.cn/posts/2026/10/22/bes%E7%BC%96%E8%AF%91%E9%85%8D%E7%BD%AE02%E6%9E%84%E5%BB%BA%E7%9B%AE%E6%A0%87%E4%B8%8E%E9%85%8D%E7%BD%AE%E8%A6%86%E7%9B%96/&#34;&gt;前一篇&lt;/a&gt;
讨论了 Make 变量从哪里来、怎样覆盖。接下来还要弄清楚：配置文件中的开关，怎样影响 C 源码里的 &lt;code&gt;#ifdef&lt;/code&gt;？&lt;/p&gt;
&lt;h2 id=&#34;一从变量到宏的传递过程&#34;&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;Make&lt;/td&gt;
					&lt;td&gt;Makefile、&lt;code&gt;.mk&lt;/code&gt; 文件&lt;/td&gt;
					&lt;td&gt;根据配置安排构建，并组织传给编译器的参数&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;C 编译器&lt;/td&gt;
					&lt;td&gt;&lt;code&gt;.c&lt;/code&gt;、&lt;code&gt;.h&lt;/code&gt; 等源码文件&lt;/td&gt;
					&lt;td&gt;根据宏和源码内容，生成目标文件&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;写在 &lt;code&gt;.mk&lt;/code&gt; 文件中的变量，是给 Make 使用的。C 编译器不会自动读取这些变量。&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;先用一个简单的 &lt;code&gt;MY_FEATURE&lt;/code&gt; 开关说明。&lt;/p&gt;
&lt;h3 id=&#34;11-定义-make-变量&#34;&gt;1.1 定义 Make 变量&lt;/h3&gt;
&lt;p&gt;假设 &lt;code&gt;.mk&lt;/code&gt; 文件里写了：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-makefile&#34; data-lang=&#34;makefile&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;MY_FEATURE&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;MY_FEATURE&lt;/code&gt; 是 Make 变量，Make 用 &lt;code&gt;$(MY_FEATURE)&lt;/code&gt; 取值。例如，判断这个开关是否等于 &lt;code&gt;1&lt;/code&gt;：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-makefile&#34; data-lang=&#34;makefile&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;ifeq&lt;/span&gt; &lt;span class=&#34;err&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;$(&lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;MY_FEATURE&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;err&#34;&gt;,1)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c&#34;&gt;# 在这里安排开启功能时的构建操作
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;err&#34;&gt;endif&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;12-export传递给子-make&#34;&gt;1.2 &lt;code&gt;export&lt;/code&gt;：传递给子 Make&lt;/h3&gt;
&lt;p&gt;如果顶层 Make 另外启动子 Make 来构建模块，后面的子 Make 也可能需要这个开关。这时可以前面加 &lt;code&gt;export&lt;/code&gt; 将变量传过去：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-makefile&#34; data-lang=&#34;makefile&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;export &lt;/span&gt;&lt;span class=&#34;nv&#34;&gt;MY_FEATURE&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;m&#34;&gt;1&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;export&lt;/code&gt; 会把变量带给后续子进程，子 Make 因而也能读取 &lt;code&gt;MY_FEATURE&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;这里说的子 Make，是另外启动的 Make 进程。如果是同一个 Make， 通过 &lt;code&gt;include&lt;/code&gt; 读入多个配置文件时，变量可以在该进程内使用，无需为了 &lt;code&gt;include&lt;/code&gt; 单独加 &lt;code&gt;export&lt;/code&gt;。&lt;/p&gt;</description>
    </item>
    <item>
      <title>【BES】编译配置（04）：源码怎样编译成固件</title>
      <link>https://btio.cn/posts/2026/10/23/bes%E7%BC%96%E8%AF%91%E9%85%8D%E7%BD%AE04%E6%BA%90%E7%A0%81%E6%80%8E%E6%A0%B7%E7%BC%96%E8%AF%91%E6%88%90%E5%9B%BA%E4%BB%B6/</link>
      <pubDate>Fri, 23 Oct 2026 00:00:00 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/10/23/bes%E7%BC%96%E8%AF%91%E9%85%8D%E7%BD%AE04%E6%BA%90%E7%A0%81%E6%80%8E%E6%A0%B7%E7%BC%96%E8%AF%91%E6%88%90%E5%9B%BA%E4%BB%B6/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://btio.cn/posts/2026/10/23/bes%E7%BC%96%E8%AF%91%E9%85%8D%E7%BD%AE03make-%E5%8F%98%E9%87%8F%E6%80%8E%E6%A0%B7%E5%8F%98%E6%88%90-c-%E5%AE%8F/&#34;&gt;前一篇&lt;/a&gt;
说明了配置怎样变成编译参数。除了参数，构建系统还需要知道哪些目录、哪些源文件参与构建。这里继续借助本地 BES SDK，从源码清单查到编译命令，再看目标文件怎样链接成固件。&lt;/p&gt;
&lt;h2 id=&#34;一源码选择与编译&#34;&gt;一、源码选择与编译&lt;/h2&gt;
&lt;h3 id=&#34;11-core-y选择顶层目录&#34;&gt;1.1 &lt;code&gt;core-y&lt;/code&gt;：选择顶层目录&lt;/h3&gt;
&lt;p&gt;要选择参与构建的源码，先要确定它们所在的目录。这份 SDK 在 &lt;code&gt;target.mk&lt;/code&gt; 中通过 &lt;code&gt;core-y&lt;/code&gt; 列出顶层构建目录：&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;正文配图&#34; loading=&#34;lazy&#34; src=&#34;https://picgocloud.com/m/71c4332f-e353-4fb1-a7fb-be5bbd0cc556.png&#34;&gt;
&lt;em&gt;图 1：&lt;code&gt;target.mk&lt;/code&gt; 用 &lt;code&gt;core-y&lt;/code&gt; 指定顶层构建目录&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;当前面没有指定 &lt;code&gt;EXT_SRC_DIR&lt;/code&gt; 时，会把 &lt;code&gt;apps/&lt;/code&gt; 和 &lt;code&gt;services/&lt;/code&gt; 加入这部分构建列表。后续再进入这些目录，读取各自的 Makefile。&lt;/p&gt;
&lt;h3 id=&#34;12-obj-y列出子目录和目标文件&#34;&gt;1.2 &lt;code&gt;obj-y&lt;/code&gt;：列出子目录和目标文件&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;core-y&lt;/code&gt; 加入 &lt;code&gt;services/&lt;/code&gt; 后，构建系统会读取 &lt;code&gt;services/Makefile&lt;/code&gt;。里面的 &lt;code&gt;obj-y&lt;/code&gt; 再决定这个目录下哪些内容参与构建。&lt;/p&gt;
&lt;p&gt;在这套构建系统里，&lt;code&gt;obj-y&lt;/code&gt; 是当前目录的构建清单，里面既可以写子目录，也可以写目标文件。清单的名称和处理方式由 SDK 的构建脚本约定，Make 本身不会因为变量叫 &lt;code&gt;obj-y&lt;/code&gt; 就自动编译它。&lt;/p&gt;
&lt;h4 id=&#34;1子目录条目&#34;&gt;（1）子目录条目&lt;/h4&gt;
&lt;p&gt;在 &lt;code&gt;services/Makefile&lt;/code&gt; 的 &lt;code&gt;obj-y&lt;/code&gt; 列表中，可以找到：&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;正文配图&#34; loading=&#34;lazy&#34; src=&#34;https://picgocloud.com/m/2cd1527f-f90e-4558-8d91-4f5b94644d5b.png&#34;&gt;
&lt;em&gt;图 2：&lt;code&gt;services/Makefile&lt;/code&gt; 用 &lt;code&gt;obj-y&lt;/code&gt; 列出子目录&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;audio_process/&lt;/code&gt; 末尾带 &lt;code&gt;/&lt;/code&gt;，表示还要进入这个子目录，继续读取 &lt;code&gt;services/audio_process/Makefile&lt;/code&gt;。&lt;/p&gt;
&lt;h4 id=&#34;2目标文件条目&#34;&gt;（2）目标文件条目&lt;/h4&gt;
&lt;p&gt;进入 &lt;code&gt;services/audio_process/&lt;/code&gt; 后，里面有这些源文件：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;audio_process.c
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;audio_process_vol.c
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;audio_spectrum.cpp
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这些源码需要经过编译，生成对应的 &lt;code&gt;.o&lt;/code&gt; 文件。例如，&lt;code&gt;audio_process.c&lt;/code&gt; 编译后生成 &lt;code&gt;audio_process.o&lt;/code&gt;。&lt;/p&gt;</description>
    </item>
    <item>
      <title>【BES】外设适配（01）：触摸输入从采样到事件</title>
      <link>https://btio.cn/posts/2026/10/23/bes%E5%A4%96%E8%AE%BE%E9%80%82%E9%85%8D01%E8%A7%A6%E6%91%B8%E8%BE%93%E5%85%A5%E4%BB%8E%E9%87%87%E6%A0%B7%E5%88%B0%E4%BA%8B%E4%BB%B6/</link>
      <pubDate>Fri, 23 Oct 2026 00:00:00 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/10/23/bes%E5%A4%96%E8%AE%BE%E9%80%82%E9%85%8D01%E8%A7%A6%E6%91%B8%E8%BE%93%E5%85%A5%E4%BB%8E%E9%87%87%E6%A0%B7%E5%88%B0%E4%BA%8B%E4%BB%B6/</guid>
      <description>&lt;h2 id=&#34;一tws-按键交互背景&#34;&gt;一、TWS 按键交互背景&lt;/h2&gt;
&lt;p&gt;耳机可以通过电容触摸、压力感应、实体按键或敲击检测等方式接收用户操作。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;正文配图&#34; loading=&#34;lazy&#34; src=&#34;https://picgocloud.com/m/d818f1bd-4b8b-44c6-859a-2e64d98ab0ce.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;我接触的这份 BES 项目使用 CAPSENSOR 电容感应方案。
以“双击暂停音乐”为例，先要完成触摸检测，得到“某个事件”，应用才能继续执行对应功能。&lt;/p&gt;
&lt;h2 id=&#34;二触摸检测的基本流程&#34;&gt;二、触摸检测的基本流程&lt;/h2&gt;
&lt;p&gt;手指接近或接触感应区域，会引起电容变化。硬件按一定节奏测量，将结果转换成程序能读取的数值，这个过程叫作&lt;strong&gt;采样&lt;/strong&gt;。软件再结合数据随时间的变化，识别单击、双击或长按。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;正文配图&#34; loading=&#34;lazy&#34; src=&#34;https://picgocloud.com/m/e4093ded-3ee8-48a1-8d76-e21d216407ec.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;采样数据是测量结果，触摸事件是识别结果。&lt;/strong&gt; 在实际开发中，重点先确认检测能启动、事件能产生，再将事件接入业务。&lt;/p&gt;
&lt;h2 id=&#34;三开机后从应用初始化到触摸初始化&#34;&gt;三、开机后，从应用初始化到触摸初始化&lt;/h2&gt;
&lt;p&gt;先看开机时这条主线&lt;/p&gt;
&lt;div class=&#34;mermaid-diagram&#34; role=&#34;group&#34; aria-label=&#34;流程图&#34;&gt;
  &lt;pre class=&#34;mermaid&#34;&gt;%%{init: {&amp;#34;flowchart&amp;#34;: {&amp;#34;htmlLabels&amp;#34;: true, &amp;#34;wrappingWidth&amp;#34;: 1000, &amp;#34;rankSpacing&amp;#34;: 30}, &amp;#34;themeVariables&amp;#34;: {&amp;#34;lineColor&amp;#34;: &amp;#34;#71829a&amp;#34;}, &amp;#34;themeCSS&amp;#34;: &amp;#34;.nodeLabel { white-space: nowrap; } .nodeLabel p { margin: 0; }&amp;#34;}}%%
flowchart TB
    subgraph INIT[&amp;#34;① 应用初始化&amp;#34;]
        direction LR
        A[&amp;#34;应用入口&amp;lt;br/&amp;gt;app_init()&amp;#34;]
        B[&amp;#34;初始化触摸模块&amp;lt;br/&amp;gt;app_mcu_core_capsensor_init()&amp;#34;]
        C[&amp;#34;准备时钟和模拟电路&amp;lt;br/&amp;gt;capsensor_driver_init()&amp;#34;]
        D[&amp;#34;创建检测线程&amp;lt;br/&amp;gt;cap_sensor_core_thread_init()&amp;#34;]
        A --&amp;gt; B --&amp;gt; C --&amp;gt; D
    end

    subgraph TASK[&amp;#34;② 检测线程&amp;#34;]
        direction LR
        E[&amp;#34;线程开始执行&amp;lt;br/&amp;gt;capsensor_thread()&amp;#34;]
        F[&amp;#34;配置并启动采样&amp;lt;br/&amp;gt;capsensor_drv_start()&amp;#34;]
        G[&amp;#34;设置采样中断&amp;lt;br/&amp;gt;cap_sensor_irqinit()&amp;#34;]
        E --&amp;gt; F --&amp;gt; G
    end

    INIT -..-&amp;gt;|&amp;#34;创建线程后，由 RTOS 调度运行&amp;#34;| TASK

    classDef initPhase fill:#e8f2ff,stroke:#7ba4d8,color:#23456b,stroke-width:1.5px;
    classDef taskPhase fill:#e7f4ec,stroke:#78aa8b,color:#24563a,stroke-width:1.5px;
    class A,B,C,D initPhase;
    class E,F,G taskPhase;
    style INIT fill:#f1f6fd,stroke:#b8cfe8,color:#23456b
    style TASK fill:#f0f8f3,stroke:#b9d7c4,color:#24563a&lt;/pre&gt;
&lt;/div&gt;&lt;h3 id=&#34;31-从应用入口进入检测初始化&#34;&gt;3.1 从应用入口进入检测初始化&lt;/h3&gt;
&lt;p&gt;&lt;code&gt;app_init()&lt;/code&gt; 在 &lt;code&gt;CAPSENSOR_ENABLE&lt;/code&gt; 开启时，调用 &lt;code&gt;app_mcu_core_capsensor_init()&lt;/code&gt;。图中前一个函数用于恢复佩戴检测的校准参数，这里继续沿第二个函数看触摸初始化。&lt;/p&gt;</description>
    </item>
    <item>
      <title>【BES】外设适配（02）：触摸事件怎样交给应用</title>
      <link>https://btio.cn/posts/2026/10/23/bes%E5%A4%96%E8%AE%BE%E9%80%82%E9%85%8D02%E8%A7%A6%E6%91%B8%E4%BA%8B%E4%BB%B6%E6%80%8E%E6%A0%B7%E4%BA%A4%E7%BB%99%E5%BA%94%E7%94%A8/</link>
      <pubDate>Fri, 23 Oct 2026 00:00:00 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/10/23/bes%E5%A4%96%E8%AE%BE%E9%80%82%E9%85%8D02%E8%A7%A6%E6%91%B8%E4%BA%8B%E4%BB%B6%E6%80%8E%E6%A0%B7%E4%BA%A4%E7%BB%99%E5%BA%94%E7%94%A8/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://btio.cn/posts/2026/10/23/bes%E5%A4%96%E8%AE%BE%E9%80%82%E9%85%8D01%E8%A7%A6%E6%91%B8%E8%BE%93%E5%85%A5%E4%BB%8E%E9%87%87%E6%A0%B7%E5%88%B0%E4%BA%8B%E4%BB%B6/&#34;&gt;上一篇&lt;/a&gt;
讲到检测线程得到单击、双击等事件。这篇接着看：事件怎样进入应用，最后找到对应业务。&lt;/p&gt;
&lt;p&gt;本项目的 MCU 处理路径如下：&lt;/p&gt;
&lt;div class=&#34;mermaid-diagram&#34; role=&#34;group&#34; aria-label=&#34;流程图&#34;&gt;
  &lt;pre class=&#34;mermaid&#34;&gt;%%{init: {&amp;#34;flowchart&amp;#34;: {&amp;#34;htmlLabels&amp;#34;: true, &amp;#34;wrappingWidth&amp;#34;: 1000, &amp;#34;rankSpacing&amp;#34;: 30}, &amp;#34;themeVariables&amp;#34;: {&amp;#34;lineColor&amp;#34;: &amp;#34;#71829a&amp;#34;}}}%%
flowchart TB
    subgraph R0[&amp;#34;① 检测线程：调用接收函数&amp;#34;]
        direction LR
        R0N0[&amp;#34;得到检测事件&amp;lt;br/&amp;gt;status.event&amp;#34;]
        R0N1[&amp;#34;转换为应用按键事件&amp;lt;br/&amp;gt;app_capsensor_click_event()&amp;#34;]
        R0N2[&amp;#34;放入应用邮箱&amp;lt;br/&amp;gt;capsensor_key_event_process()&amp;#34;]
        R0N0 --&amp;gt; R0N1 --&amp;gt; R0N2
    end
    class R0N0,R0N1,R0N2 blue;
    style R0 fill:#f1f6fd,stroke:#b8cfe8,color:#23456b
    subgraph R1[&amp;#34;② 应用线程：取消息并分发&amp;#34;]
        direction LR
        R1N0[&amp;#34;还原按键消息&amp;lt;br/&amp;gt;app_key_handle_process()&amp;#34;]
        R1N1[&amp;#34;进入产品处理&amp;lt;br/&amp;gt;app_ibrt_user_key()&amp;#34;]
        R1N2[&amp;#34;按产品状态、左右耳和事件类型&amp;lt;br/&amp;gt;分发到对应业务函数&amp;#34;]
        R1N0 --&amp;gt; R1N1 --&amp;gt; R1N2
    end
    class R1N0,R1N1,R1N2 green;
    style R1 fill:#f0f8f3,stroke:#b9d7c4,color:#24563a
    R0 -..-&amp;gt;|&amp;#34;通过邮箱交给应用线程&amp;#34;| R1
    classDef blue fill:#e8f2ff,stroke:#7ba4d8,color:#23456b,stroke-width:1.5px;
    classDef green fill:#e7f4ec,stroke:#78aa8b,color:#24563a,stroke-width:1.5px;
    classDef amber fill:#fff3df,stroke:#d5a25b,color:#72501e,stroke-width:1.5px;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&#34;一初始化时登记事件接收函数&#34;&gt;一、初始化时，登记事件接收函数&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;app_mcu_core_capsensor_init()&lt;/code&gt; 中有一行：&lt;/p&gt;</description>
    </item>
    <item>
      <title>【BES】编译配置（01）：编译命令与构建脚本</title>
      <link>https://btio.cn/posts/2026/10/22/bes%E7%BC%96%E8%AF%91%E9%85%8D%E7%BD%AE01%E7%BC%96%E8%AF%91%E5%91%BD%E4%BB%A4%E4%B8%8E%E6%9E%84%E5%BB%BA%E8%84%9A%E6%9C%AC/</link>
      <pubDate>Thu, 22 Oct 2026 00:00:00 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/10/22/bes%E7%BC%96%E8%AF%91%E9%85%8D%E7%BD%AE01%E7%BC%96%E8%AF%91%E5%91%BD%E4%BB%A4%E4%B8%8E%E6%9E%84%E5%BB%BA%E8%84%9A%E6%9C%AC/</guid>
      <description>&lt;p&gt;在&lt;a href=&#34;https://btio.cn/posts/2026/10/20/bes%E7%B3%BB%E7%BB%9F%E6%80%BB%E8%A7%8801%E7%BC%96%E8%AF%91%E9%85%8D%E7%BD%AE%E5%A6%82%E4%BD%95%E5%86%B3%E5%AE%9A%E5%9B%BA%E4%BB%B6%E5%8A%9F%E8%83%BD/&#34;&gt;《系统总览（01）：编译配置如何决定固件功能》&lt;/a&gt;
中，用 ANC 介绍了配置对源码的影响。实际构建项目时，还要先弄清楚该执行什么命令、得到什么文件，以及是否需要后续处理。&lt;/p&gt;
&lt;p&gt;这里通过我在实际项目开发中所使用的BES  2700这款芯片的SDK 所用的构建命令进行介绍。包含构建目标、输出路径和 CRC 处理方式。&lt;/p&gt;
&lt;h2 id=&#34;一执行编译命令&#34;&gt;一、执行编译命令&lt;/h2&gt;
&lt;p&gt;编译bes工程，可以在工程根目录打开终端，输入：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-bash&#34; data-lang=&#34;bash&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;make &lt;span class=&#34;nv&#34;&gt;T&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;best1306p -j
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Make 会读取工程里的 Makefile，并按其中的规则完成构建。这条命令中，&lt;code&gt;T=best1306p&lt;/code&gt; 是用于选择这份工程的构建配置，&lt;code&gt;-j&lt;/code&gt; 用于并行构建。&lt;/p&gt;
&lt;p&gt;平时修改的 &lt;code&gt;.c&lt;/code&gt;、&lt;code&gt;.cpp&lt;/code&gt; 源码。经过编译、链接，源码会变成芯片能够执行的程序，并与相关数据一起组成固件。本例生成的固件文件路径是 &lt;code&gt;out/best1306p/best1306p.bin&lt;/code&gt;。&lt;/p&gt;
&lt;h2 id=&#34;二为固件补充校验信息&#34;&gt;二、为固件补充校验信息&lt;/h2&gt;
&lt;h3 id=&#34;21-crc-后处理&#34;&gt;2.1 CRC 后处理&lt;/h3&gt;
&lt;p&gt;编译生成固件后，有些项目还需要为后续升级补充校验信息。例如，接收方要检查收到的数据是否与准备好的固件一致，就需要一个用于比较的校验值。这里以 CRC32 为例。&lt;/p&gt;
&lt;p&gt;CRC 的中文名称是“循环冗余校验”。电脑先算好一个值，接收方拿到数据后，再按相同范围、相同算法算一次，与保存的值比较：&lt;/p&gt;
&lt;div class=&#34;mermaid-diagram&#34; role=&#34;group&#34; aria-label=&#34;流程图&#34;&gt;
  &lt;pre class=&#34;mermaid&#34;&gt;%%{init: {&amp;#34;flowchart&amp;#34;: {&amp;#34;htmlLabels&amp;#34;: true, &amp;#34;wrappingWidth&amp;#34;: 1000, &amp;#34;rankSpacing&amp;#34;: 30}, &amp;#34;themeVariables&amp;#34;: {&amp;#34;lineColor&amp;#34;: &amp;#34;#71829a&amp;#34;}}}%%
flowchart TB
    subgraph R0[&amp;#34;① 电脑上准备固件时&amp;#34;]
        direction LR
        R0N0[&amp;#34;生成固件&amp;#34;]
        R0N1[&amp;#34;计算 CRC&amp;#34;]
        R0N2[&amp;#34;将校验值填入固件&amp;#34;]
        R0N0 --&amp;gt; R0N1 --&amp;gt; R0N2
    end
    class R0N0,R0N1,R0N2 blue;
    style R0 fill:#f1f6fd,stroke:#b8cfe8,color:#23456b
    subgraph R1[&amp;#34;② 后续设备接收后&amp;#34;]
        direction LR
        R1N0[&amp;#34;读取收到的固件数据&amp;#34;]
        R1N1[&amp;#34;耳机重新计算 CRC&amp;#34;]
        R1N2[&amp;#34;与固件中保存的 CRC 比较&amp;#34;]
        R1N0 --&amp;gt; R1N1 --&amp;gt; R1N2
    end
    class R1N0,R1N1,R1N2 green;
    style R1 fill:#f0f8f3,stroke:#b9d7c4,color:#24563a
    R0 -..-&amp;gt;|&amp;#34;后续设备收到文件&amp;#34;| R1
    classDef blue fill:#e8f2ff,stroke:#7ba4d8,color:#23456b,stroke-width:1.5px;
    classDef green fill:#e7f4ec,stroke:#78aa8b,color:#24563a,stroke-width:1.5px;
    classDef amber fill:#fff3df,stroke:#d5a25b,color:#72501e,stroke-width:1.5px;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;对比结果不同，说明数据在传输中发生了变化；结果相同，表示通过校验，数据传输正常。&lt;/p&gt;</description>
    </item>
    <item>
      <title>【BES】编译配置（02）：构建目标与配置覆盖</title>
      <link>https://btio.cn/posts/2026/10/22/bes%E7%BC%96%E8%AF%91%E9%85%8D%E7%BD%AE02%E6%9E%84%E5%BB%BA%E7%9B%AE%E6%A0%87%E4%B8%8E%E9%85%8D%E7%BD%AE%E8%A6%86%E7%9B%96/</link>
      <pubDate>Thu, 22 Oct 2026 00:00:00 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/10/22/bes%E7%BC%96%E8%AF%91%E9%85%8D%E7%BD%AE02%E6%9E%84%E5%BB%BA%E7%9B%AE%E6%A0%87%E4%B8%8E%E9%85%8D%E7%BD%AE%E8%A6%86%E7%9B%96/</guid>
      <description>&lt;p&gt;&lt;a href=&#34;https://btio.cn/posts/2026/10/22/bes%E7%BC%96%E8%AF%91%E9%85%8D%E7%BD%AE01%E7%BC%96%E8%AF%91%E5%91%BD%E4%BB%A4%E4%B8%8E%E6%9E%84%E5%BB%BA%E8%84%9A%E6%9C%AC/&#34;&gt;前一篇&lt;/a&gt;
介绍了如何执行构建命令。这篇看配置怎样被选中和加载。&lt;/p&gt;
&lt;h2 id=&#34;一构建目标与配置加载&#34;&gt;一、构建目标与配置加载&lt;/h2&gt;
&lt;h3 id=&#34;11-t选择构建目标&#34;&gt;1.1 &lt;code&gt;T&lt;/code&gt;：选择构建目标&lt;/h3&gt;
&lt;p&gt;要知道本次构建用了哪套配置，可以先查构建命令传入了哪些变量、Makefile 怎样使用它们。&lt;/p&gt;
&lt;p&gt;这份 SDK 用 &lt;code&gt;T&lt;/code&gt; 选择构建目标，顶层 &lt;code&gt;Makefile&lt;/code&gt; 根据T的值，拼出配置文件路径。传入 &lt;code&gt;T=best1306p&lt;/code&gt;，选中的就是 &lt;code&gt;config/best1306p/target.mk&lt;/code&gt;：&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;正文配图&#34; loading=&#34;lazy&#34; src=&#34;https://picgocloud.com/m/a4529f52-b717-46a8-aa9e-b7499d57cbee.png&#34;&gt;
&lt;em&gt;图 1：顶层 &lt;code&gt;Makefile&lt;/code&gt; 根据 &lt;code&gt;T&lt;/code&gt; 拼出配置路径&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;默认的构建输出目录如下：&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;正文配图&#34; loading=&#34;lazy&#34; src=&#34;https://picgocloud.com/m/ce61f938-c97f-4f36-b850-ba3bf3375d4f.png&#34;&gt;
&lt;em&gt;图 2：顶层 &lt;code&gt;Makefile&lt;/code&gt; 中的输出目录设置与目标检查&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Makefile 还会检查这个文件是否存在。不存在时，会报 &lt;code&gt;Invalid target&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;修改配置前先看构建命令里的 &lt;code&gt;T&lt;/code&gt;，再去找对应目录，避免改了另一套配置。&lt;/p&gt;
&lt;h3 id=&#34;12-chip指定芯片平台&#34;&gt;1.2 &lt;code&gt;CHIP&lt;/code&gt;：指定芯片平台&lt;/h3&gt;
&lt;p&gt;选出产品配置后，还需要指定它使用的芯片平台。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-makefile&#34; data-lang=&#34;makefile&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nv&#34;&gt;CHIP&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;?=&lt;/span&gt; best1306p
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;这里用的也是 &lt;code&gt;best1306p&lt;/code&gt; 作为默认值。&lt;/p&gt;
&lt;p&gt;两个变量的用途分别是：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;T&lt;/code&gt;&lt;/strong&gt;：选择哪套产品或构建配置。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;code&gt;CHIP&lt;/code&gt;&lt;/strong&gt;：指定这套配置使用的芯片平台。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;这次两者恰好都叫 &lt;code&gt;best1306p&lt;/code&gt;。换成产品目标时，它们可能不同。&lt;/p&gt;
&lt;h3 id=&#34;13-配置文件的加载顺序&#34;&gt;1.3 配置文件的加载顺序&lt;/h3&gt;
&lt;p&gt;配置拆在多个文件中时，Make 可以用 &lt;code&gt;include&lt;/code&gt; 读入其他文件。因此，查配置除了找赋值，还要沿着 &lt;code&gt;include&lt;/code&gt; 看它们的加载顺序。&lt;/p&gt;
&lt;p&gt;这份工程的顶层 &lt;code&gt;Makefile&lt;/code&gt; 先读入下面两个文件：&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;正文配图&#34; loading=&#34;lazy&#34; src=&#34;https://picgocloud.com/m/7309d56c-162d-47de-b7ca-7618c2b455a3.png&#34;&gt;
&lt;em&gt;图 3：先读取目标配置，再读取公共配置&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;srctree&lt;/code&gt; 表示源码根目录。这里先读取 &lt;code&gt;target.mk&lt;/code&gt;，再读取 &lt;code&gt;common.mk&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;target.mk&lt;/code&gt; 里面还有其他 &lt;code&gt;include&lt;/code&gt;。Make 读到这里，会先处理被包含的文件，再回来接着读后面的配置。&lt;/p&gt;</description>
    </item>
    <item>
      <title>【BES】系统总览（02）：开机初始化到应用模块</title>
      <link>https://btio.cn/posts/2026/10/21/bes%E7%B3%BB%E7%BB%9F%E6%80%BB%E8%A7%8802%E5%BC%80%E6%9C%BA%E5%88%9D%E5%A7%8B%E5%8C%96%E5%88%B0%E5%BA%94%E7%94%A8%E6%A8%A1%E5%9D%97/</link>
      <pubDate>Wed, 21 Oct 2026 00:00:00 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/10/21/bes%E7%B3%BB%E7%BB%9F%E6%80%BB%E8%A7%8802%E5%BC%80%E6%9C%BA%E5%88%9D%E5%A7%8B%E5%8C%96%E5%88%B0%E5%BA%94%E7%94%A8%E6%A8%A1%E5%9D%97/</guid>
      <description>&lt;p&gt;耳机开机后，应用层需要先准备好运行环境：读取配置数据、创建消息处理机制、初始化各业务模块，之后才能处理按键、连接、音乐播放等事件。&lt;/p&gt;
&lt;h2 id=&#34;一应用层从哪里开始&#34;&gt;一、应用层从哪里开始&lt;/h2&gt;
&lt;p&gt;正常启动时，&lt;code&gt;main()&lt;/code&gt; 完成平台侧准备，然后调用 &lt;code&gt;app_init()&lt;/code&gt;：&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;正文配图&#34; loading=&#34;lazy&#34; src=&#34;https://picgocloud.com/m/30cdfc02-8d91-4454-a25d-e36f7f48da40.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;app_init()&lt;/code&gt; 是应用层初始化的主要入口。看这个函数，可以了解 SDK 开机时启用了哪些模块，以及模块之间的初始化顺序和条件。&lt;/p&gt;
&lt;h2 id=&#34;二app_init-初始化系统和模块&#34;&gt;二、&lt;code&gt;app_init()&lt;/code&gt; 初始化系统和模块&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;app_init()&lt;/code&gt; 下，关键的初始化函数有：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;nv_record_init()&lt;/code&gt;：准备 NV 数据、工厂参数&lt;/li&gt;
&lt;li&gt;&lt;code&gt;app_os_init()&lt;/code&gt;：创建 app 邮箱和线程&lt;/li&gt;
&lt;li&gt;&lt;code&gt;app_battery_open()&lt;/code&gt;：检查电池、充电状态，确定启动分支&lt;/li&gt;
&lt;li&gt;&lt;code&gt;app_key_open()&lt;/code&gt;：按键检测及开机按键处理&lt;/li&gt;
&lt;li&gt;&lt;code&gt;bt_app_init()&lt;/code&gt;：蓝牙模块&lt;/li&gt;
&lt;li&gt;&lt;code&gt;app_audio_open()&lt;/code&gt;：音频模块&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;这里的初始化，是为了让模块具备处理业务的条件。例如，音频模块初始化完成，并不代表已经开始播放音乐，后面还需要播放事件触发。&lt;/p&gt;
&lt;h2 id=&#34;三建立应用线程和邮箱&#34;&gt;三、建立应用线程和邮箱&lt;/h2&gt;
&lt;p&gt;在 &lt;code&gt;app_init()&lt;/code&gt; 中，会调用 &lt;code&gt;app_os_init()&lt;/code&gt;：&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;正文配图&#34; loading=&#34;lazy&#34; src=&#34;https://picgocloud.com/m/9e87eacd-d73b-489b-8afb-56a30c4396a4.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;这个函数主要完成两件事：先创建 app 邮箱，再创建 app 线程。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;正文配图&#34; loading=&#34;lazy&#34; src=&#34;https://picgocloud.com/m/16f47e13-f664-487e-8a8c-c7b7463f2820.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;邮箱用于保存待处理的应用消息，&lt;code&gt;app_thread&lt;/code&gt; 负责取出消息，并根据模块编号交给对应的处理函数。所以，这里的消息链路大致为：&lt;/p&gt;
&lt;div class=&#34;mermaid-diagram&#34; role=&#34;group&#34; aria-label=&#34;流程图&#34;&gt;
  &lt;pre class=&#34;mermaid&#34;&gt;%%{init: {&amp;#34;flowchart&amp;#34;: {&amp;#34;htmlLabels&amp;#34;: true, &amp;#34;wrappingWidth&amp;#34;: 1000, &amp;#34;rankSpacing&amp;#34;: 30}, &amp;#34;themeVariables&amp;#34;: {&amp;#34;lineColor&amp;#34;: &amp;#34;#71829a&amp;#34;}}}%%
flowchart TB
    subgraph R0[&amp;#34;① 消息投递&amp;#34;]
        direction LR
        R0N0[&amp;#34;模块产生消息&amp;#34;]
        R0N1[&amp;#34;放入 app 邮箱&amp;#34;]
        R0N0 --&amp;gt; R0N1
    end
    class R0N0,R0N1 blue;
    style R0 fill:#f1f6fd,stroke:#b8cfe8,color:#23456b
    subgraph R1[&amp;#34;② 应用线程处理&amp;#34;]
        direction LR
        R1N0[&amp;#34;app_thread 取出消息&amp;#34;]
        R1N1[&amp;#34;调用对应模块的处理函数&amp;#34;]
        R1N0 --&amp;gt; R1N1
    end
    class R1N0,R1N1 green;
    style R1 fill:#f0f8f3,stroke:#b9d7c4,color:#24563a
    R0 -..-&amp;gt;|&amp;#34;通过邮箱交接&amp;#34;| R1
    classDef blue fill:#e8f2ff,stroke:#7ba4d8,color:#23456b,stroke-width:1.5px;
    classDef green fill:#e7f4ec,stroke:#78aa8b,color:#24563a,stroke-width:1.5px;
    classDef amber fill:#fff3df,stroke:#d5a25b,color:#72501e,stroke-width:1.5px;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;这是 app 线程的处理方式。蓝牙和音频等子系统也有各自的线程或回调，整个 SDK 由这些任务协作运行。&lt;/p&gt;</description>
    </item>
    <item>
      <title>【BES】系统总览（03）：事件如何触发业务处理</title>
      <link>https://btio.cn/posts/2026/10/21/bes%E7%B3%BB%E7%BB%9F%E6%80%BB%E8%A7%8803%E4%BA%8B%E4%BB%B6%E5%A6%82%E4%BD%95%E8%A7%A6%E5%8F%91%E4%B8%9A%E5%8A%A1%E5%A4%84%E7%90%86/</link>
      <pubDate>Wed, 21 Oct 2026 00:00:00 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/10/21/bes%E7%B3%BB%E7%BB%9F%E6%80%BB%E8%A7%8803%E4%BA%8B%E4%BB%B6%E5%A6%82%E4%BD%95%E8%A7%A6%E5%8F%91%E4%B8%9A%E5%8A%A1%E5%A4%84%E7%90%86/</guid>
      <description>&lt;h1 id=&#34;bes系统总览03事件如何触发业务处理&#34;&gt;【BES】系统总览（03）：事件如何触发业务处理&lt;/h1&gt;
&lt;p&gt;上一篇介绍了开机初始化：创建线程、邮箱，初始化按键、蓝牙、音频等模块。&lt;/p&gt;
&lt;p&gt;初始化完成后，耳机就可以响应各种变化。例如，用户双击耳机、手机连接成功、App 切换降噪模式，都会触发相应的处理。&lt;/p&gt;
&lt;p&gt;这一篇主要介绍：&lt;strong&gt;一个事件发生后，是怎样进入业务代码的。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id=&#34;一事件与业务的区别&#34;&gt;一、事件与业务的区别&lt;/h2&gt;
&lt;p&gt;事件描述“发生了什么”，业务决定“接下来做什么”。&lt;/p&gt;
&lt;p&gt;例如，用户双击左耳：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;事件&lt;/strong&gt;：左耳发生双击。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;业务&lt;/strong&gt;：根据当前状态，执行播放、暂停或者接听电话等操作。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;同一个操作，在不同状态下可能执行不同功能。&lt;/p&gt;
&lt;p&gt;整体流程可以这样理解：&lt;/p&gt;
&lt;div class=&#34;mermaid-diagram&#34; role=&#34;group&#34; aria-label=&#34;流程图&#34;&gt;
  &lt;pre class=&#34;mermaid&#34;&gt;%%{init: {&amp;#34;flowchart&amp;#34;: {&amp;#34;htmlLabels&amp;#34;: true, &amp;#34;wrappingWidth&amp;#34;: 1000, &amp;#34;rankSpacing&amp;#34;: 30}, &amp;#34;themeVariables&amp;#34;: {&amp;#34;lineColor&amp;#34;: &amp;#34;#71829a&amp;#34;}}}%%
flowchart TB
    subgraph R0[&amp;#34;① 事件传递&amp;#34;]
        direction LR
        R0N0[&amp;#34;检测到变化&amp;#34;]
        R0N1[&amp;#34;传递事件&amp;#34;]
        R0N2[&amp;#34;找到处理函数&amp;#34;]
        R0N0 --&amp;gt; R0N1 --&amp;gt; R0N2
    end
    class R0N0,R0N1,R0N2 blue;
    style R0 fill:#f1f6fd,stroke:#b8cfe8,color:#23456b
    subgraph R1[&amp;#34;② 业务处理&amp;#34;]
        direction LR
        R1N0[&amp;#34;判断当前状态&amp;#34;]
        R1N1[&amp;#34;执行具体操作&amp;#34;]
        R1N0 --&amp;gt; R1N1
    end
    class R1N0,R1N1 green;
    style R1 fill:#f0f8f3,stroke:#b9d7c4,color:#24563a
    R0 --&amp;gt; R1
    classDef blue fill:#e8f2ff,stroke:#7ba4d8,color:#23456b,stroke-width:1.5px;
    classDef green fill:#e7f4ec,stroke:#78aa8b,color:#24563a,stroke-width:1.5px;
    classDef amber fill:#fff3df,stroke:#d5a25b,color:#72501e,stroke-width:1.5px;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;下面结合 BES 的触摸链路来看。&lt;/p&gt;</description>
    </item>
    <item>
      <title>【BES】系统总览（01）：编译配置如何决定固件功能</title>
      <link>https://btio.cn/posts/2026/10/20/bes%E7%B3%BB%E7%BB%9F%E6%80%BB%E8%A7%8801%E7%BC%96%E8%AF%91%E9%85%8D%E7%BD%AE%E5%A6%82%E4%BD%95%E5%86%B3%E5%AE%9A%E5%9B%BA%E4%BB%B6%E5%8A%9F%E8%83%BD/</link>
      <pubDate>Tue, 20 Oct 2026 00:00:00 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/10/20/bes%E7%B3%BB%E7%BB%9F%E6%80%BB%E8%A7%8801%E7%BC%96%E8%AF%91%E9%85%8D%E7%BD%AE%E5%A6%82%E4%BD%95%E5%86%B3%E5%AE%9A%E5%9B%BA%E4%BB%B6%E5%8A%9F%E8%83%BD/</guid>
      <description>&lt;h2 id=&#34;一编译配置是什么&#34;&gt;一、编译配置是什么&lt;/h2&gt;
&lt;p&gt;配置主要由 &lt;code&gt;.mk&lt;/code&gt; 文件决定。看这些文件，可以了解当前选择了什么平台、加入了哪些模块，以及使用了哪些配置。&lt;/p&gt;
&lt;p&gt;编译配置发生在电脑生成固件时。耳机上电后，运行的是已经编译好的固件。&lt;/p&gt;
&lt;p&gt;整体流程如下：&lt;/p&gt;
&lt;div class=&#34;mermaid-diagram&#34; role=&#34;group&#34; aria-label=&#34;流程图&#34;&gt;
  &lt;pre class=&#34;mermaid&#34;&gt;%%{init: {&amp;#34;flowchart&amp;#34;: {&amp;#34;htmlLabels&amp;#34;: true, &amp;#34;wrappingWidth&amp;#34;: 1000, &amp;#34;rankSpacing&amp;#34;: 30}, &amp;#34;themeVariables&amp;#34;: {&amp;#34;lineColor&amp;#34;: &amp;#34;#71829a&amp;#34;}}}%%
flowchart TB
    subgraph R0[&amp;#34;① 电脑上构建&amp;#34;]
        direction LR
        R0N0[&amp;#34;读取配置&amp;#34;]
        R0N1[&amp;#34;编译、链接&amp;#34;]
        R0N2[&amp;#34;生成固件&amp;#34;]
        R0N0 --&amp;gt; R0N1 --&amp;gt; R0N2
    end
    class R0N0,R0N1,R0N2 blue;
    style R0 fill:#f1f6fd,stroke:#b8cfe8,color:#23456b
    subgraph R1[&amp;#34;② 耳机上运行&amp;#34;]
        direction LR
        R1N0[&amp;#34;烧录固件&amp;#34;]
        R1N1[&amp;#34;上电启动&amp;#34;]
        R1N2[&amp;#34;运行固件中的代码&amp;#34;]
        R1N0 --&amp;gt; R1N1 --&amp;gt; R1N2
    end
    class R1N0,R1N1,R1N2 green;
    style R1 fill:#f0f8f3,stroke:#b9d7c4,color:#24563a
    R0 --&amp;gt; R1
    classDef blue fill:#e8f2ff,stroke:#7ba4d8,color:#23456b,stroke-width:1.5px;
    classDef green fill:#e7f4ec,stroke:#78aa8b,color:#24563a,stroke-width:1.5px;
    classDef amber fill:#fff3df,stroke:#d5a25b,color:#72501e,stroke-width:1.5px;&lt;/pre&gt;
&lt;/div&gt;&lt;h2 id=&#34;二anc-配置如何影响源码&#34;&gt;二、ANC 配置如何影响源码&lt;/h2&gt;
&lt;h3 id=&#34;1-判断是否加载-anc-配置&#34;&gt;1. 判断是否加载 ANC 配置&lt;/h3&gt;
&lt;p&gt;下面是 &lt;code&gt;target.mk&lt;/code&gt; 中的判断：&lt;/p&gt;</description>
    </item>
    <item>
      <title>【中科蓝讯】耳机电量是怎样更新到手机的</title>
      <link>https://btio.cn/posts/2026/08/17/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AF%E8%80%B3%E6%9C%BA%E7%94%B5%E9%87%8F%E6%98%AF%E6%80%8E%E6%A0%B7%E6%9B%B4%E6%96%B0%E5%88%B0%E6%89%8B%E6%9C%BA%E7%9A%84/</link>
      <pubDate>Mon, 17 Aug 2026 15:18:41 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/08/17/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AF%E8%80%B3%E6%9C%BA%E7%94%B5%E9%87%8F%E6%98%AF%E6%80%8E%E6%A0%B7%E6%9B%B4%E6%96%B0%E5%88%B0%E6%89%8B%E6%9C%BA%E7%9A%84/</guid>
      <description>&lt;p&gt;从功能表面看，耳机电量更新并不复杂：ADC 采到电池电压，再查表换算成百分比，手机就能显示。&lt;/p&gt;
&lt;p&gt;但在实际项目中，电量更新并不是采样后直接查表：采样值要先经过滤波，查表得到的也只是参考电量，手机最终显示的还要由软件继续维护。先把实际电压、参考电量和显示电量这三个值分清楚，整条链路就容易理解了。&lt;/p&gt;
&lt;p&gt;先看完整链路：前 3 步把采样值处理成参考电量，后 3 步由软件维护显示值、完成双耳同步，最后上报手机。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;TWS 耳机电量更新六步流程&#34; loading=&#34;lazy&#34; src=&#34;https://btio.cn/images/csdn/163825929/%E7%94%B5%E9%87%8F%E6%9B%B4%E6%96%B0%E5%85%AD%E6%AD%A5%E6%B5%81%E7%A8%8B.png&#34;&gt;&lt;/p&gt;
&lt;h2 id=&#34;电池电压是怎么采出来的&#34;&gt;电池电压是怎么采出来的？&lt;/h2&gt;
&lt;p&gt;顺着中科蓝讯 SDK 的调用关系看，系统会在 5ms 任务中检查 ADC 转换状态。转换完成后，读取电池通道和内部参考通道的 ADC 值。内部参考电压的已知值用于校准换算比例，再结合电池采样值和分压系数，得到实际电池电压。&lt;/p&gt;
&lt;h2 id=&#34;为什么采到电压后还不能直接使用&#34;&gt;为什么采到电压后还不能直接使用？&lt;/h2&gt;
&lt;p&gt;播放音乐或者蓝牙发射时，电池电压会短暂下降，负载变小后又会回升，所以一次采样不能直接拿来估算电量。&lt;/p&gt;
&lt;p&gt;结合耳机电压变化缓慢、但采样又容易受负载影响的特点，我更推荐用递推平均的方式更新电压：每来一个新采样值，只让平均电压向它靠近一小步。平均电压变化达到条件后，才更新稳定电压。下降条件更容易触发，上升条件更严格，可以减少电压回弹的影响。&lt;/p&gt;
&lt;h2 id=&#34;参考电量为什么不直接给手机&#34;&gt;参考电量为什么不直接给手机？&lt;/h2&gt;
&lt;p&gt;稳定电压通过“电压—电量对照表”换算成参考电量。它只用来判断当前显示偏高还是偏低，不是手机最终看到的电量。&lt;/p&gt;
&lt;p&gt;如果每次都用参考电量覆盖显示电量，负载变化仍然会造成百分比跳变。&lt;/p&gt;
&lt;h2 id=&#34;显示电量是怎么变化的&#34;&gt;显示电量是怎么变化的？&lt;/h2&gt;
&lt;p&gt;电量管理任务大约每 10 秒运行一次，并根据当前状态选择更新方式。&lt;/p&gt;
&lt;p&gt;放电时，参考电量低于显示电量，软件就让显示电量逐级下降，不会一次跳到参考值；电压短暂回升时，也不会把电量加回来。&lt;/p&gt;
&lt;p&gt;充电时，电压回升很快，不能直接用它增加百分比。软件根据充电电流和时间估算充入容量，再换算成显示电量；底层确认充满后，才显示 100%。&lt;/p&gt;
&lt;p&gt;温度决定当前能不能充电、使用多大的充电电流。低电提醒主要看显示电量，低压关机最终看实际电压。&lt;/p&gt;
&lt;h2 id=&#34;为什么内部电量和手机显示还可能不同&#34;&gt;为什么内部电量和手机显示还可能不同？&lt;/h2&gt;
&lt;p&gt;显示电量发生变化后会被保存，耳机下次开机可以从上次的结果继续计算。耳机内部按 1% 维护电量，当前 App 路径按 5% 一档显示。&lt;/p&gt;
&lt;p&gt;例如内部电量是 59%，手机仍然显示 60%；内部电量下降到 55% 后，手机才显示 55%。&lt;/p&gt;
&lt;h2 id=&#34;左右耳电量最后由谁上报&#34;&gt;左右耳电量最后由谁上报？&lt;/h2&gt;
&lt;p&gt;左右耳各自计算本耳电量，再通过 TWS 交换耳机和充电盒电量。主耳汇总左耳、右耳和充电盒数据后，统一上报给手机系统和配套 App。&lt;/p&gt;
&lt;p&gt;现在再看这条链路，重点就是分清三份数据：&lt;strong&gt;实际电压&lt;/strong&gt;反映电池状态，&lt;strong&gt;参考电量&lt;/strong&gt;判断变化方向，&lt;strong&gt;显示电量&lt;/strong&gt;负责最终呈现。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;原文：&lt;a href=&#34;https://blog.csdn.net/qq_56070244/article/details/163825929&#34;&gt;CSDN · 【中科蓝讯】耳机电量是怎样更新到手机的？&lt;/a&gt;
&lt;/p&gt;</description>
    </item>
    <item>
      <title>【中科蓝讯】耳机电量与充电问题复盘</title>
      <link>https://btio.cn/posts/2026/08/17/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AF%E8%80%B3%E6%9C%BA%E7%94%B5%E9%87%8F%E4%B8%8E%E5%85%85%E7%94%B5%E9%97%AE%E9%A2%98%E5%A4%8D%E7%9B%98/</link>
      <pubDate>Mon, 17 Aug 2026 00:00:00 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/08/17/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AF%E8%80%B3%E6%9C%BA%E7%94%B5%E9%87%8F%E4%B8%8E%E5%85%85%E7%94%B5%E9%97%AE%E9%A2%98%E5%A4%8D%E7%9B%98/</guid>
      <description>&lt;p&gt;本文先整理电压采样的方案设计思路，再复盘下面五类电量与充电问题：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#section-1&#34;&gt;电压稳定方案的设计思路&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-2&#34;&gt;电量曲线&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-3&#34;&gt;温度采样&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-4&#34;&gt;上报精度&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-5&#34;&gt;电量管控&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-6&#34;&gt;状态刷新&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;section-1&#34;&gt;一、电压稳定方案的设计思路&lt;/h2&gt;
&lt;p&gt;电量计算不会直接使用一次 ADC 采样结果。播放音乐、蓝牙发射和负载切换都会造成短时波动，因此在进入电量估算前，需要先得到一份相对稳定的电压。&lt;/p&gt;
&lt;p&gt;这里先分清三个值：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;数据&lt;/th&gt;
					&lt;th&gt;含义&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;新采样电压&lt;/td&gt;
					&lt;td&gt;ADC 本次换算得到的电压，每次都可能变化&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;tr&gt;
					&lt;td&gt;稳定电压&lt;/td&gt;
					&lt;td&gt;达到更新条件后才改变，提供给后续电量算法使用&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;稳定电压不是手机显示的百分比，也不是永远固定不变。它只是在平均电压没有达到更新条件时保持原值。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;方案一：去极值后取平均值&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;先连续采集一组电压，去掉其中几个最大值和最小值，再对剩余数据求平均。偶发的异常高值和异常低值不会直接影响结果，适合 ADC 容易出现尖峰干扰的场景。&lt;/p&gt;
&lt;p&gt;这种方案的优点是抗单点异常能力强，思路也比较直观。缺点是需要保存一组采样数据，还要完成极值查找或排序，会占用更多内存和计算资源。采样窗口越长，结果越稳定，但输出延迟也越大，真实电压发生变化时不容易及时跟上。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;方案二：递推平均加更新阈值&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;递推平均不需要保存整组数据。每得到一个有效采样值，就让原来的平均电压向新采样值移动一小步。新采样值低于旧平均值时向下移动，高于旧平均值时向上移动，每次移动的大小由两者差值和递推系数决定。&lt;/p&gt;
&lt;p&gt;这种方案的优点是内存和计算开销小，适合持续采样，也可以通过调整递推系数改变响应速度。缺点是它不会自动剔除异常值，一个突发尖峰会影响后续一段时间；系数过小，电压变化跟得慢，系数过大，又容易把短时波动带进结果。&lt;/p&gt;
&lt;p&gt;以递推系数 &lt;code&gt;1/32&lt;/code&gt; 为例：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;当前平均电压和稳定电压都是 &lt;code&gt;4000mV&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;本次新采样电压为 &lt;code&gt;3800mV&lt;/code&gt;，与平均电压相差 &lt;code&gt;200mV&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;本次只向下移动差值的 &lt;code&gt;1/32&lt;/code&gt;，也就是 &lt;code&gt;6.25mV&lt;/code&gt;，新的平均电压约为 &lt;code&gt;3993.75mV&lt;/code&gt;。&lt;/li&gt;
&lt;li&gt;新的平均电压再与稳定电压比较。两者向下相差约 &lt;code&gt;6.25mV&lt;/code&gt;，达到当前项目的下降更新条件，稳定电压才更新。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;如果旧平均电压低于新采样电压，处理方向相反：旧平均电压加上两者差值的 &lt;code&gt;1/32&lt;/code&gt;，得到新的平均电压。无论差值大小，每次采样都会参与递推；更新阈值只负责决定稳定电压是否改变。&lt;/p&gt;
&lt;p&gt;当前项目在平均电压下降约 &lt;code&gt;5mV&lt;/code&gt; 时允许更新稳定电压，向上则需要变化约 &lt;code&gt;10mV&lt;/code&gt;。下降阈值更小，可以及时反映放电趋势；上升阈值更大，可以减少负载解除后电压回弹带来的影响。&lt;/p&gt;
&lt;p&gt;对于 TWS 耳机这种电压变化缓慢、需要持续采样的设备，递推平均占用资源少，也方便调整响应速度，当前 SDK 采用的就是第二种方案。如果还会出现明显的异常采样，可以先剔除异常值，再进入递推平均。&lt;/p&gt;
&lt;h2 id=&#34;section-2&#34;&gt;二、电量曲线&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;问题现象&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;耳机从满电持续播放音乐时，有些 &lt;code&gt;10%&lt;/code&gt; 很快掉完，有些区间长时间不变化；左右耳在同一电量区间的续航也可能相差较大。总续航接近要求，但百分比曲线不均匀。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题原因&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这次问题的直接原因是软件仍使用旧电池的电压—电量表，与当前电芯的充放电曲线不匹配，导致各百分比区间对应的实际续航不均匀。左右耳的主从角色还会带来功耗差异，因此双耳验证时也要把主从切换考虑进去。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;处理结果&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;根据当前电芯的实测充放电数据更新电量表，同时调整电量相关的主从切换逻辑。修改后分别在 ANC 开启和关闭场景下完成整轮放电验证，各 &lt;code&gt;10%&lt;/code&gt; 区间的续航恢复到要求范围内。&lt;/p&gt;
&lt;h2 id=&#34;section-3&#34;&gt;三、温度采样&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;问题现象&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>【中科蓝讯】机盒通信问题单复盘</title>
      <link>https://btio.cn/posts/2026/08/16/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AF%E6%9C%BA%E7%9B%92%E9%80%9A%E4%BF%A1%E9%97%AE%E9%A2%98%E5%8D%95%E5%A4%8D%E7%9B%98/</link>
      <pubDate>Sun, 16 Aug 2026 00:00:00 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/08/16/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AF%E6%9C%BA%E7%9B%92%E9%80%9A%E4%BF%A1%E9%97%AE%E9%A2%98%E5%8D%95%E5%A4%8D%E7%9B%98/</guid>
      <description>&lt;p&gt;本文围绕下面四类问题，整理对应的现象、问题原因和处理结果：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&#34;#section-1&#34;&gt;快速开关盖后异常断连&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-2&#34;&gt;左右耳回复不一致，盒子灯效频闪&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-3&#34;&gt;耳机已经进入配对，盒子却不显示配对灯效&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-4&#34;&gt;配对超时后，盒子显示了错误灯效&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;section-1&#34;&gt;一、快速开关盖后异常断连&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;问题现象&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;快速开关盖时，耳机低概率断开。日志中没有完整的关盖命令，耳机却进入了充电状态。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题原因&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;快速开关盖时，充电盒重新拉起供电。电平持续时间超过原来的防抖阈值，耳机提前判断为稳定入盒。状态切换由充电检测触发，不是串口丢包。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;处理结果&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;将充电电平持续检测时间从约 &lt;code&gt;600 ms&lt;/code&gt; 延长到 &lt;code&gt;1 s&lt;/code&gt;，避免短暂电平触发充电模式。连续快速开关盖验证后，未再出现异常断连。&lt;/p&gt;
&lt;h2 id=&#34;section-2&#34;&gt;二、左右耳回复不一致，盒子灯效频闪&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;问题现象&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;耳机进入配对状态并放入盒内后，充电盒白灯闪烁不均匀，部分场景出现频闪或亮度异常。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题原因&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;左右耳返回给充电盒的配对状态不一致。盒子先收到一只耳机的配对状态，又收到另一只耳机的非配对状态，灯效状态被反复切换。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;左耳回复：配对中
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;右耳回复：非配对
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;盒子灯效在两个状态之间反复切换
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;处理结果&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;由从耳同步主耳的配对状态，确保左右耳向充电盒返回一致的数据。双耳状态一致后，配对灯效恢复正常。&lt;/p&gt;
&lt;h2 id=&#34;section-3&#34;&gt;三、耳机进入配对，盒子却不显示配对灯效&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;问题现象&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;耳机已经连接一台手机，再进入配对模式并放入盒内。充电盒只显示耳机电量，没有显示配对灯效。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题原因&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;耳机同时存在“已连接”和“可发现可连接”两个状态。原来的回复逻辑优先返回已连接状态，覆盖了正在配对的状态，盒子因此没有进入配对灯效。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* 修改前 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;phone_connected&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;report_connected&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;pairing&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;report_pairing&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;cm&#34;&gt;/* 修改后 */&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;pairing&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;report_pairing&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;phone_connected&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;())&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;report_connected&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;处理结果&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;回复状态时优先判断配对状态，再判断手机连接状态。修改后，耳机在已连接状态下重新进入配对，盒子能够正常显示配对灯效。&lt;/p&gt;
&lt;h2 id=&#34;section-4&#34;&gt;四、配对超时后，盒子显示了错误灯效&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;问题现象&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;耳机在配对状态下入盒，配对超时后，充电盒显示了配对成功灯效，而不是结束灯效。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题原因&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;耳机在配对超时后返回无效状态，充电盒却把这个状态按配对成功处理。数据传输正常，但两端对同一状态的含义没有统一。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;处理结果&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;统一耳机与充电盒对回复状态的定义。收到无效状态时直接结束灯效，不再进入配对成功灯效。&lt;/p&gt;
&lt;p&gt;这四类问题对应的检查入口是：&lt;strong&gt;充电电平、左右耳回复是否一致、状态判断优先级、两端状态定义。&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>【中科蓝讯】TWS 耳机机盒通信链路</title>
      <link>https://btio.cn/posts/2026/08/15/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFtws-%E8%80%B3%E6%9C%BA%E6%9C%BA%E7%9B%92%E9%80%9A%E4%BF%A1%E9%93%BE%E8%B7%AF/</link>
      <pubDate>Sat, 15 Aug 2026 00:00:00 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/08/15/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFtws-%E8%80%B3%E6%9C%BA%E6%9C%BA%E7%9B%92%E9%80%9A%E4%BF%A1%E9%93%BE%E8%B7%AF/</guid>
      <description>&lt;p&gt;机盒通信的主链路是：UART 收包、协议解析、校验与寻址、命令分发、业务执行、应答返回。这篇记录我负责该模块时使用的应用层调用链。&lt;/p&gt;
&lt;h2 id=&#34;section-1&#34;&gt;一、UART 收包与协议解析&lt;/h2&gt;
&lt;div class=&#34;mermaid-diagram&#34; role=&#34;group&#34; aria-label=&#34;流程图&#34;&gt;
  &lt;pre class=&#34;mermaid&#34;&gt;%%{init: {&amp;#34;flowchart&amp;#34;: {&amp;#34;htmlLabels&amp;#34;: true, &amp;#34;wrappingWidth&amp;#34;: 1000, &amp;#34;rankSpacing&amp;#34;: 30}, &amp;#34;themeVariables&amp;#34;: {&amp;#34;lineColor&amp;#34;: &amp;#34;#71829a&amp;#34;}}}%%
flowchart LR
    N0[&amp;#34;充电盒发送数据&amp;#34;]
    N1[&amp;#34;UART 中断接收字节&amp;lt;br/&amp;gt;并写入环形缓冲区&amp;#34;]
    N2[&amp;#34;协议状态机&amp;lt;br/&amp;gt;拼接完整数据包&amp;#34;]
    N3[&amp;#34;应用任务&amp;lt;br/&amp;gt;从缓冲区取包并校验&amp;#34;]
    N0 --&amp;gt; N1
    N1 --&amp;gt; N2
    N2 --&amp;gt; N3
    class N0,N1,N2,N3 blue;
    classDef blue fill:#e8f2ff,stroke:#7ba4d8,color:#23456b,stroke-width:1.5px;
    classDef green fill:#e7f4ec,stroke:#78aa8b,color:#24563a,stroke-width:1.5px;
    classDef amber fill:#fff3df,stroke:#d5a25b,color:#72501e,stroke-width:1.5px;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;UART 中断侧负责收字节和快速识别数据包：&lt;/p&gt;
&lt;div class=&#34;mermaid-diagram&#34; role=&#34;group&#34; aria-label=&#34;流程图&#34;&gt;
  &lt;pre class=&#34;mermaid&#34;&gt;%%{init: {&amp;#34;flowchart&amp;#34;: {&amp;#34;htmlLabels&amp;#34;: true, &amp;#34;wrappingWidth&amp;#34;: 1000, &amp;#34;rankSpacing&amp;#34;: 30}, &amp;#34;themeVariables&amp;#34;: {&amp;#34;lineColor&amp;#34;: &amp;#34;#71829a&amp;#34;}}}%%
flowchart TB
    subgraph R0[&amp;#34;① 中断与接收回调&amp;#34;]
        direction LR
        R0N0[&amp;#34;uart1_isr()&amp;#34;]
        R0N1[&amp;#34;uart1_rx_done_cb()&amp;#34;]
        R0N0 --&amp;gt; R0N1
    end
    class R0N0,R0N1 blue;
    style R0 fill:#f1f6fd,stroke:#b8cfe8,color:#23456b
    subgraph R1[&amp;#34;② 解析与接收处理&amp;#34;]
        direction LR
        R1N0[&amp;#34;bsp_uart_packet_parse()&amp;#34;]
        R1N1[&amp;#34;charge_box_packet_recv()&amp;#34;]
        R1N0 --&amp;gt; R1N1
    end
    class R1N0,R1N1 green;
    style R1 fill:#f0f8f3,stroke:#b9d7c4,color:#24563a
    R0 --&amp;gt; R1
    classDef blue fill:#e8f2ff,stroke:#7ba4d8,color:#23456b,stroke-width:1.5px;
    classDef green fill:#e7f4ec,stroke:#78aa8b,color:#24563a,stroke-width:1.5px;
    classDef amber fill:#fff3df,stroke:#d5a25b,color:#72501e,stroke-width:1.5px;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;中断将字节写入环形缓冲区，快速解析一次以记录收包时间及开盖、心跳等标志。&lt;code&gt;charge_box_ssw_process(charge_sta)&lt;/code&gt; 再从缓冲区取出字节，重新组包、校验并处理命令。&lt;/p&gt;</description>
    </item>
    <item>
      <title>【中科蓝讯】TWS音量是怎样同步的</title>
      <link>https://btio.cn/posts/2026/08/14/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFtws%E9%9F%B3%E9%87%8F%E6%98%AF%E6%80%8E%E6%A0%B7%E5%90%8C%E6%AD%A5%E7%9A%84/</link>
      <pubDate>Fri, 14 Aug 2026 10:38:44 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/08/14/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFtws%E9%9F%B3%E9%87%8F%E6%98%AF%E6%80%8E%E6%A0%B7%E5%90%8C%E6%AD%A5%E7%9A%84/</guid>
      <description>&lt;p&gt;这篇梳理音乐音量在应用层的处理：手机下发的音量怎样换算为本地等级，左右耳怎样同时生效，以及耳机按键调节后怎样同步手机音量条。通话音量只作区分，不展开 HFP 细节。&lt;/p&gt;
&lt;h2 id=&#34;section-1&#34;&gt;一、手机调节音量后的主流程&lt;/h2&gt;
&lt;p&gt;一次音量调节要对应下面四处状态：&lt;/p&gt;
&lt;div class=&#34;mermaid-diagram&#34; role=&#34;group&#34; aria-label=&#34;流程图&#34;&gt;
  &lt;pre class=&#34;mermaid&#34;&gt;%%{init: {&amp;#34;flowchart&amp;#34;: {&amp;#34;htmlLabels&amp;#34;: true, &amp;#34;wrappingWidth&amp;#34;: 1000, &amp;#34;rankSpacing&amp;#34;: 30}, &amp;#34;themeVariables&amp;#34;: {&amp;#34;lineColor&amp;#34;: &amp;#34;#71829a&amp;#34;}}}%%
flowchart LR
    N0[&amp;#34;手机音量条&amp;#34;]
    N1[&amp;#34;耳机内部音量级&amp;#34;]
    N2[&amp;#34;左右耳同步状态&amp;#34;]
    N3[&amp;#34;DAC 实际输出音量&amp;#34;]
    N0 --&amp;gt; N1
    N1 --&amp;gt; N2
    N2 --&amp;gt; N3
    class N0,N1,N2,N3 blue;
    classDef blue fill:#e8f2ff,stroke:#7ba4d8,color:#23456b,stroke-width:1.5px;
    classDef green fill:#e7f4ec,stroke:#78aa8b,color:#24563a,stroke-width:1.5px;
    classDef amber fill:#fff3df,stroke:#d5a25b,color:#72501e,stroke-width:1.5px;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;手机和耳机的音量范围并不相同。AVRCP 绝对音量是 0～127，SDK 内部可配置为 16 级或 32 级，最后还要通过音量表转换为 DAC 使用的数字音量。&lt;/p&gt;
&lt;p&gt;因此，手机显示 50% 不等于把数值 50 直接写入 DAC，而是先换算、再查表。&lt;/p&gt;
&lt;p&gt;这里的“绝对音量”指手机音量条和耳机媒体音量相互对应：任一侧调节，另一侧都要更新。&lt;/p&gt;
&lt;p&gt;手机调节音乐音量后，协议栈将新的媒体音量交给应用层，主线如下：&lt;/p&gt;
&lt;div class=&#34;mermaid-diagram&#34; role=&#34;group&#34; aria-label=&#34;流程图&#34;&gt;
  &lt;pre class=&#34;mermaid&#34;&gt;%%{init: {&amp;#34;flowchart&amp;#34;: {&amp;#34;htmlLabels&amp;#34;: true, &amp;#34;wrappingWidth&amp;#34;: 1000, &amp;#34;rankSpacing&amp;#34;: 30}, &amp;#34;themeVariables&amp;#34;: {&amp;#34;lineColor&amp;#34;: &amp;#34;#71829a&amp;#34;}}}%%
flowchart TB
    subgraph R0[&amp;#34;① 接收与换算&amp;#34;]
        direction LR
        R0N0[&amp;#34;收到手机设置的媒体音量&amp;#34;]
        R0N1[&amp;#34;把 0～127&amp;lt;br/&amp;gt;换算为本地音量级&amp;#34;]
        R0N2[&amp;#34;发起 TWS 定时音量请求&amp;#34;]
        R0N0 --&amp;gt; R0N1 --&amp;gt; R0N2
    end
    class R0N0,R0N1,R0N2 blue;
    style R0 fill:#f1f6fd,stroke:#b8cfe8,color:#23456b
    subgraph R1[&amp;#34;② 定时执行与保存&amp;#34;]
        direction LR
        R1N0[&amp;#34;左右耳在约定时间设置 DAC&amp;#34;]
        R1N1[&amp;#34;更新当前音量&amp;lt;br/&amp;gt;后续再延时保存&amp;#34;]
        R1N0 --&amp;gt; R1N1
    end
    class R1N0,R1N1 green;
    style R1 fill:#f0f8f3,stroke:#b9d7c4,color:#24563a
    R0 --&amp;gt; R1
    classDef blue fill:#e8f2ff,stroke:#7ba4d8,color:#23456b,stroke-width:1.5px;
    classDef green fill:#e7f4ec,stroke:#78aa8b,color:#24563a,stroke-width:1.5px;
    classDef amber fill:#fff3df,stroke:#d5a25b,color:#72501e,stroke-width:1.5px;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;TWS 路径不会在当前回调里直接设置 DAC，而是先发起定时请求；到达定时点后，左右耳再一起设置实际音量。&lt;/p&gt;</description>
    </item>
    <item>
      <title>【中科蓝讯】TWS 耳机音量问题单复盘</title>
      <link>https://btio.cn/posts/2026/08/14/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFtws-%E8%80%B3%E6%9C%BA%E9%9F%B3%E9%87%8F%E9%97%AE%E9%A2%98%E5%8D%95%E5%A4%8D%E7%9B%98/</link>
      <pubDate>Fri, 14 Aug 2026 00:00:00 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/08/14/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFtws-%E8%80%B3%E6%9C%BA%E9%9F%B3%E9%87%8F%E9%97%AE%E9%A2%98%E5%8D%95%E5%A4%8D%E7%9B%98/</guid>
      <description>&lt;h2 id=&#34;preface&#34;&gt;写在开始&lt;/h2&gt;
&lt;p&gt;这篇文章整理项目中比较有代表性的音量问题单。只保留已经写明原因和处理方向的内容，并按音量控制链路归为三类。&lt;/p&gt;
&lt;p&gt;排查音量问题时，可以先确认四个结果：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;1. 收到的目标音量是否正确
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2. 左右耳保存的音量是否一致
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;3. 两耳应用音量的时间是否一致
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;4. 实际写入硬件的音量是否正确
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;本文围绕下面三类问题，整理对应的现象和排查思路：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;#section-1&#34;&gt;回连后的初始音量不对&lt;/a&gt;
；&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-2&#34;&gt;快速调节时双耳音量不同步&lt;/a&gt;
；&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-3&#34;&gt;出盒恢复时单耳突然变大&lt;/a&gt;
。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;section-1&#34;&gt;一、回连后的初始音量不对&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;问题现象 1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;耳机重新组队并连接手机后，预期使用耳机的默认音量，实际却变成手机之前保存的最大音量。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;排查思路 1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;按时间确认三个值：重新组队后恢复的默认音量、手机首次下发的历史音量，以及最终实际生效的音量。若默认值恢复正确，但最终值变成手机历史值，说明问题出在手机下发后的覆盖。&lt;/p&gt;
&lt;p&gt;耳机重新组队后已恢复到默认音量，但手机连接时下发的历史音量又覆盖了本地值。如果要求重新组队后采用耳机默认音量，可以在首次连接的短暂保护窗口内忽略手机下发的音量，使用耳机的默认音量，同时将默认音量写回给 App。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题现象 2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;一拖二场景下，设备 A 已连接耳机且音量调到最大；设备 B 的音量较小，在播放音乐时抢连耳机。抢连成功后，音乐开始时仍按设备 A 的最大音量播放，随后才突然降到设备 B 的低音量。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;排查思路 2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;检查抢连后耳机采用的是哪台设备的音量，以及 A2DP 开始播放前硬件音量是否已经更新。&lt;/p&gt;
&lt;p&gt;已有问题中，设备 B 抢连成功后，硬件音量设置晚于音乐开始，导致开始播放时仍保留设备 A 的最大音量。处理时要在 A2DP 出声前，按设备 B 的音量设置好硬件音量。&lt;/p&gt;
&lt;h2 id=&#34;section-2&#34;&gt;二、快速调节时双耳音量不同步&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;问题现象 1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;长按手机音量键或快速滑动音量条时，声音会短暂偏向一边；从最大音量降到静音时，一只耳机比另一只更晚无声。反复在最大和最小音量之间切换时，还可能出现音量跳变。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;排查思路 1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;先看手机下发音量后，主从耳是不是在 alarm 到点前就各自更新了本地媒体音量；再对比 alarm 回调里两边实际采用的目标值。&lt;/p&gt;
&lt;p&gt;已有问题中，主从耳在 alarm 到点前更新本地媒体音量的路径不同。快速滑动时，虽然两边在同一时刻进入 alarm 回调，但取到的音量基准已经不一致，所以会出现一边先变大、先变小或更晚静音。&lt;/p&gt;</description>
    </item>
    <item>
      <title>【中科蓝讯】ANC 模式是怎样切换的</title>
      <link>https://btio.cn/posts/2026/08/12/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFanc-%E6%A8%A1%E5%BC%8F%E6%98%AF%E6%80%8E%E6%A0%B7%E5%88%87%E6%8D%A2%E7%9A%84/</link>
      <pubDate>Wed, 12 Aug 2026 10:34:45 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/08/12/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFanc-%E6%A8%A1%E5%BC%8F%E6%98%AF%E6%80%8E%E6%A0%B7%E5%88%87%E6%8D%A2%E7%9A%84/</guid>
      <description>&lt;p&gt;最开始看原厂 SDK 时，我觉得它的切换很简单：确定关闭、降噪或通透，再调用模式接口即可。&lt;/p&gt;
&lt;p&gt;随着 App 控制、按键配置、单双耳记忆和出入盒切换逐渐加进来，我才发现应用层维护的并不只是一个 ANC 模式。提示音何时播放、左右耳怎样同步、状态什么时候保存和上报，也都在这条链路里。&lt;/p&gt;
&lt;h2 id=&#34;section-1&#34;&gt;一、先把 ANC 的几条链路放在一起&lt;/h2&gt;
&lt;p&gt;ANC 模式可能因为三类事件发生变化：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;App 下发一个明确的目标模式；&lt;/li&gt;
&lt;li&gt;用户通过耳机按键切换模式；&lt;/li&gt;
&lt;li&gt;耳机出入盒或 TWS 连接状态变化，需要重新选择单双耳记忆。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;把三个入口放在一起，我目前是这样理解的：&lt;/p&gt;
&lt;div class=&#34;mermaid-diagram&#34; role=&#34;group&#34; aria-label=&#34;流程图&#34;&gt;
  &lt;pre class=&#34;mermaid&#34;&gt;%%{init: {&amp;#34;flowchart&amp;#34;: {&amp;#34;htmlLabels&amp;#34;: true, &amp;#34;wrappingWidth&amp;#34;: 1000, &amp;#34;rankSpacing&amp;#34;: 30}, &amp;#34;themeVariables&amp;#34;: {&amp;#34;lineColor&amp;#34;: &amp;#34;#71829a&amp;#34;}}}%%
flowchart TB
    subgraph R0[&amp;#34;① 确定目标模式&amp;#34;]
        direction LR
        R0N0[&amp;#34;收到 ANC 相关事件&amp;lt;br/&amp;gt;App 指令、按键事件&amp;lt;br/&amp;gt;出入盒或 TWS 状态变化&amp;#34;]
        R0N1[&amp;#34;确定当前使用场景&amp;lt;br/&amp;gt;单耳、双耳&amp;lt;br/&amp;gt;或者双耳都在盒内&amp;#34;]
        R0N2[&amp;#34;得到本次目标模式&amp;lt;br/&amp;gt;关闭、通透、不同等级的降噪&amp;lt;br/&amp;gt;或自适应降噪&amp;#34;]
        R0N0 --&amp;gt; R0N1 --&amp;gt; R0N2
    end
    class R0N0,R0N1,R0N2 blue;
    style R0 fill:#f1f6fd,stroke:#b8cfe8,color:#23456b
    subgraph R1[&amp;#34;② 同步并应用&amp;#34;]
        direction LR
        R1N0[&amp;#34;更新并同步状态&amp;lt;br/&amp;gt;选择或更新单耳、双耳记忆&amp;lt;br/&amp;gt;必要时通知对耳&amp;#34;]
        R1N1[&amp;#34;处理提示音并应用模式&amp;lt;br/&amp;gt;按触发来源处理提示音&amp;lt;br/&amp;gt;再转换成 SDK 模式&amp;#34;]
        R1N2[&amp;#34;保存并更新 App&amp;lt;br/&amp;gt;写入记忆；按键或状态变化时&amp;lt;br/&amp;gt;更新 App 显示&amp;#34;]
        R1N0 --&amp;gt; R1N1 --&amp;gt; R1N2
    end
    class R1N0,R1N1,R1N2 green;
    style R1 fill:#f0f8f3,stroke:#b9d7c4,color:#24563a
    R0 --&amp;gt; R1
    classDef blue fill:#e8f2ff,stroke:#7ba4d8,color:#23456b,stroke-width:1.5px;
    classDef green fill:#e7f4ec,stroke:#78aa8b,color:#24563a,stroke-width:1.5px;
    classDef amber fill:#fff3df,stroke:#d5a25b,color:#72501e,stroke-width:1.5px;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;这是一条方便理解的主线。实际代码里，App、按键和状态变化的处理顺序并不完全相同，后面再分别展开。&lt;/p&gt;</description>
    </item>
    <item>
      <title>【中科蓝讯】TWS 耳机 ANC 问题单复盘</title>
      <link>https://btio.cn/posts/2026/08/12/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFtws-%E8%80%B3%E6%9C%BA-anc-%E9%97%AE%E9%A2%98%E5%8D%95%E5%A4%8D%E7%9B%98/</link>
      <pubDate>Wed, 12 Aug 2026 00:00:00 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/08/12/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFtws-%E8%80%B3%E6%9C%BA-anc-%E9%97%AE%E9%A2%98%E5%8D%95%E5%A4%8D%E7%9B%98/</guid>
      <description>&lt;h2 id=&#34;preface&#34;&gt;写在开始&lt;/h2&gt;
&lt;p&gt;这篇文章整理项目中比较有代表性的 ANC 问题单，并按问题现象归为五类。&lt;/p&gt;
&lt;p&gt;有些问题标题虽然带有 ANC，但最后确认是电量、功耗或连接问题，这里不展开。本文只保留能够放回 ANC 控制链路解释的问题，没有明确结论的地方也不补充猜测。&lt;/p&gt;
&lt;p&gt;先把 ANC 控制流程简化成四步：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;1. 收到切换请求
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2. 确定并同步目标模式
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;3. 加载参数，更新实际效果
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;4. 保存状态并上报 App
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;本文围绕下面五类问题，整理对应的问题现象和排查思路：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;#section-1&#34;&gt;实际模式正常，App 显示却不对&lt;/a&gt;
；&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-2&#34;&gt;单耳和双耳切换后，ANC 状态混乱&lt;/a&gt;
；&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-3&#34;&gt;按键或 App 操作后，ANC 没有切换&lt;/a&gt;
；&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-4&#34;&gt;模式切换成功，降噪效果却不对&lt;/a&gt;
；&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-5&#34;&gt;切换 ANC 时出现杂音、短暂无声或突变&lt;/a&gt;
。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;section-1&#34;&gt;一、实际模式正常，App 显示却不对&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;问题现象 1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;从耳长按切换 ANC 后，耳机实际已经切换，App 仍显示原来的模式；&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;排查思路 1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;先确认三个结果：从耳是否识别到长按、左右耳实际模式是否变化、主耳是否向 App 上报了新状态。&lt;/p&gt;
&lt;p&gt;如果从耳和两耳实际模式都正常，重点查主耳是否收到新的目标模式、更新本地状态并上报 App。问题单中，从耳已经完成 ANC 切换，但主耳没有更新状态并发送新模式，因此问题出在主耳的状态同步和上报链路。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题现象 2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;耳机实际是高降噪，App 却显示低降噪；重新进入 App 后，等级还会发生跳变。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;排查思路 2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;对照耳机内部等级、协议值和 App 显示值是否一致。问题单中，耳机使用 &lt;code&gt;1&lt;/code&gt; 表示低降噪、&lt;code&gt;3&lt;/code&gt; 表示高降噪，App 却映射成1是高降噪，3是低降噪，导致高低等级颠倒。这是状态映射错误，不是 ANC 参数没有生效。&lt;/p&gt;</description>
    </item>
    <item>
      <title>【中科蓝讯】TWS 耳机提示音问题单复盘</title>
      <link>https://btio.cn/posts/2026/08/11/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFtws-%E8%80%B3%E6%9C%BA%E6%8F%90%E7%A4%BA%E9%9F%B3%E9%97%AE%E9%A2%98%E5%8D%95%E5%A4%8D%E7%9B%98/</link>
      <pubDate>Tue, 11 Aug 2026 00:00:00 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/08/11/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFtws-%E8%80%B3%E6%9C%BA%E6%8F%90%E7%A4%BA%E9%9F%B3%E9%97%AE%E9%A2%98%E5%8D%95%E5%A4%8D%E7%9B%98/</guid>
      <description>&lt;h2 id=&#34;section-1&#34;&gt;一、本文要解决哪些提示音问题&lt;/h2&gt;
&lt;p&gt;这篇文章记录的是我对 TWS 耳机提示音问题的整理和理解。我结合问题单、原厂 SDK 以及实际修改点，把零散的问题按现象和根因重新归类，并从业务请求、队列、播放到状态恢复，整理出一套排查思路。&lt;/p&gt;
&lt;p&gt;具体问题的修改结论，以问题单和现有代码记录为准；没有明确依据的地方，我不额外延伸。理解提示音问题，可以先把流程分成四步：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;1. 业务事件发生
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;2. 提示音请求进入队列
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;3. 提示音开始播放
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;       ↓
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;4. 播放结束，恢复音频状态
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;有些提示音只是给用户提供声音反馈，有些提示音还和业务回调绑定在一起。原厂 SDK 中，ANC 和音乐/游戏模式会在提示音播放完成后更新；接听、拒接和回拨也会在提示音相关回调中触发。&lt;/p&gt;
&lt;p&gt;所以排查时不能只看“有没有声音”，还要看对应的业务回调是否按预期执行。遇到问题时，先分清是“声音没有正常播放”，还是“提示音对应的业务动作没有执行”：前者检查资源、音量和播放链路，后者检查业务请求和回调。&lt;/p&gt;
&lt;p&gt;本文主要围绕以下 7 类问题展开，后文会分别说明问题现象、原因和排查思路：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href=&#34;#section-2&#34;&gt;业务已经发生，提示音却没响或播错&lt;/a&gt;
；&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-3&#34;&gt;提示音太大、太小，或换资源后异常&lt;/a&gt;
；&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-4&#34;&gt;连续或快速操作后，提示音消失、滞后或重复&lt;/a&gt;
；&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-5&#34;&gt;提示音响错耳朵&lt;/a&gt;
；&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-6&#34;&gt;双耳提示音不同步，或音乐恢复不同步&lt;/a&gt;
；&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-7&#34;&gt;提示音响完，音乐却出现杂音或无声&lt;/a&gt;
；&lt;/li&gt;
&lt;li&gt;&lt;a href=&#34;#section-8&#34;&gt;来电和双连接时，响铃状态混乱&lt;/a&gt;
。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;section-2&#34;&gt;二、业务已经发生，提示音却没响或播错&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;问题现象 1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;电量已经低于 10%，却没有低电提示音。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;排查思路 1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;先确认低电条件是否真的触发。比如电量从 11% 直接变成 9% 时，可能跳过“等于 10%”的判断，后面就不会提交低电提示音。确认条件后，再检查代码是否走到提示音调用位置。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;问题现象 2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;来电双击已经接听，却播放成三击提示音。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;排查思路 2&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;这个问题说明提示音请求已经提交，但事件和提示音没有正确对应。重点检查双击事件最终传入的提示音资源编号，确认是否误用了三击提示音。&lt;/p&gt;
&lt;p&gt;这类问题可以按“业务条件、提示音调用、资源编号”的顺序检查。前三步没有问题后，再进入队列和播放流程。&lt;/p&gt;
&lt;h2 id=&#34;section-3&#34;&gt;三、提示音太大、太小，或换资源后异常&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;问题现象 1&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;通过 App 的“查找耳机”功能播放正常，但在手机设置中的 Google“查找设备”页面，点击“让耳机响铃”时声音偏小。&lt;/p&gt;</description>
    </item>
    <item>
      <title>【中科蓝讯】TWS 耳机提示音是怎样播放出来的</title>
      <link>https://btio.cn/posts/2026/08/10/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFtws-%E8%80%B3%E6%9C%BA%E6%8F%90%E7%A4%BA%E9%9F%B3%E6%98%AF%E6%80%8E%E6%A0%B7%E6%92%AD%E6%94%BE%E5%87%BA%E6%9D%A5%E7%9A%84/</link>
      <pubDate>Mon, 10 Aug 2026 15:06:42 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/08/10/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFtws-%E8%80%B3%E6%9C%BA%E6%8F%90%E7%A4%BA%E9%9F%B3%E6%98%AF%E6%80%8E%E6%A0%B7%E6%92%AD%E6%94%BE%E5%87%BA%E6%9D%A5%E7%9A%84/</guid>
      <description>&lt;p&gt;在 TWS 耳机里，开机、蓝牙连接、低电量和降噪模式切换，通常都会伴随一段提示音。&lt;/p&gt;
&lt;p&gt;从表面看，提示音像是准备一个音频文件，需要时调用播放函数即可。实际上，一段提示音从代码触发到左右耳真正出声，中间还要经过资源查找、播放排队、双耳同步和音频恢复。&lt;/p&gt;
&lt;p&gt;本文以中科蓝讯 BT891x 原厂 SDK 的实现为例，重点分析提示音播放的核心流程。不同 SDK 的接口名称可能不一样，但整体思路通常可以互相参考。&lt;/p&gt;
&lt;h2 id=&#34;section-1&#34;&gt;一、提示音播放的完整链路&lt;/h2&gt;
&lt;p&gt;一段提示音的完整流程，可以先简化成下面五步：&lt;/p&gt;
&lt;div class=&#34;mermaid-diagram&#34; role=&#34;group&#34; aria-label=&#34;流程图&#34;&gt;
  &lt;pre class=&#34;mermaid&#34;&gt;%%{init: {&amp;#34;flowchart&amp;#34;: {&amp;#34;htmlLabels&amp;#34;: true, &amp;#34;wrappingWidth&amp;#34;: 1000, &amp;#34;rankSpacing&amp;#34;: 30}, &amp;#34;themeVariables&amp;#34;: {&amp;#34;lineColor&amp;#34;: &amp;#34;#71829a&amp;#34;}}}%%
flowchart TB
    subgraph R0[&amp;#34;① 准备播放请求&amp;#34;]
        direction LR
        R0N0[&amp;#34;业务触发&amp;#34;]
        R0N1[&amp;#34;找到对应的提示音资源&amp;#34;]
        R0N2[&amp;#34;把播放请求加入队列&amp;#34;]
        R0N0 --&amp;gt; R0N1 --&amp;gt; R0N2
    end
    class R0N0,R0N1,R0N2 blue;
    style R0 fill:#f1f6fd,stroke:#b8cfe8,color:#23456b
    subgraph R1[&amp;#34;② 同步与播放&amp;#34;]
        direction LR
        R1N0[&amp;#34;确定哪只耳机播放&amp;lt;br/&amp;gt;并完成双耳同步&amp;#34;]
        R1N1[&amp;#34;解码播放&amp;lt;br/&amp;gt;结束后恢复原来的音频状态&amp;#34;]
        R1N0 --&amp;gt; R1N1
    end
    class R1N0,R1N1 green;
    style R1 fill:#f0f8f3,stroke:#b9d7c4,color:#24563a
    R0 --&amp;gt; R1
    classDef blue fill:#e8f2ff,stroke:#7ba4d8,color:#23456b,stroke-width:1.5px;
    classDef green fill:#e7f4ec,stroke:#78aa8b,color:#24563a,stroke-width:1.5px;
    classDef amber fill:#fff3df,stroke:#d5a25b,color:#72501e,stroke-width:1.5px;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;比如手机连接耳机成功以后，蓝牙业务只需要提出“播放连接成功提示音”这个请求。至于提示音文件放在哪里、左右耳什么时候开始播放、当前音乐要不要降低音量，都会继续交给提示音模块处理。&lt;/p&gt;</description>
    </item>
    <item>
      <title>【中科蓝讯】TWS 按键问题单复盘</title>
      <link>https://btio.cn/posts/2026/08/07/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFtws-%E6%8C%89%E9%94%AE%E9%97%AE%E9%A2%98%E5%8D%95%E5%A4%8D%E7%9B%98/</link>
      <pubDate>Fri, 07 Aug 2026 20:17:54 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/08/07/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFtws-%E6%8C%89%E9%94%AE%E9%97%AE%E9%A2%98%E5%8D%95%E5%A4%8D%E7%9B%98/</guid>
      <description>&lt;h2 id=&#34;section-1&#34;&gt;一、写在开始&lt;/h2&gt;
&lt;p&gt;我参与的是一款基于中科蓝讯 BT8910 的 TWS 耳机品牌项目，目前这个项目已经完成。&lt;/p&gt;
&lt;p&gt;项目结束后，我想把开发过程中接触到的 Jira 问题单重新梳理一遍。其中既有我参与处理的内容，也有同事负责的模块。&lt;/p&gt;
&lt;p&gt;现在查一个函数、一个配置项并不难，真正值得记录的是：面对一个问题现象时，应该先判断哪一层，为什么往这个方向查，以及怎么通过日志一步步缩小范围。&lt;/p&gt;
&lt;p&gt;所以这次复盘不是给出一套标准答案，而是站在我目前对应用层的理解上，把问题现象、判断过程和排查思路整理下来，供遇到类似问题的同学参考。&lt;/p&gt;
&lt;p&gt;整理过程中我还发现，很多反馈看起来不一样，根因却有重复。按根因归类后，下次遇到类似现象时，就可以先判断问题属于哪个环节，再沿对应链路往下查。&lt;/p&gt;
&lt;p&gt;后续我会继续按模块整理项目中的问题单，包括按键、提示音、机盒通信、ANC、音量控制、功耗管理、出入盒、双耳同步、蓝牙问题和连接问题等内容。这一篇先从按键开始，归纳其中比较常见的 4 类问题。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;阅读提示&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;全文约 2 300 字，预计 10 分钟读完。&lt;/p&gt;
&lt;p&gt;本文包含 4 类按键问题：完全无响应、场景功能错误、误触，以及复杂手势互相干扰。重点不是讲基础原理，而是遇到类似反馈时，应该先查哪里、再往哪里查。&lt;/p&gt;
&lt;p&gt;本文只讨论按键链路本身。如果按键已经触发正确功能，只是提示音没有播放或播放不对，就归到后续的提示音问题中。&lt;/p&gt;
&lt;h2 id=&#34;section-2&#34;&gt;二、所有手势都没有反应&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;客户反馈&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;其中一只耳机的触控按键完全无效，双击、三击、长按都没有反应。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;排查思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一步：确认触控输入&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;先看这只耳机的触控按键是否有按下、松开的日志。&lt;/p&gt;
&lt;p&gt;没有日志：先查这个触控按键的输入本身，例如触控是否启用、耳机是否在盒内、是否正处于禁键时间、触控阈值或通道是否正常。&lt;/p&gt;
&lt;p&gt;有日志：说明这个触控按键已经有输入，继续往下查。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二步：确认手势识别&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;再看目标手势有没有识别出来。&lt;/p&gt;
&lt;p&gt;没有识别出来：重点查双击间隔、长按时间、松手后状态是否复位，以及组合手势是否把普通手势挡住了。&lt;/p&gt;
&lt;p&gt;识别出来：说明手势已经产生，继续看功能。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第三步：确认功能消息&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;最后看手势有没有转换成正确的功能消息。&lt;/p&gt;
&lt;p&gt;没有、为空或错误：查按键定义、场景切换和配置更新。&lt;/p&gt;
&lt;p&gt;有正确消息：再确认功能处理是否执行；如果功能已经执行，后面只是没有提示音，就属于提示音问题，不再按按键问题处理。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;判断与处理&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;“完全无效”不一定是触控硬件问题，也可能是手势已经产生、但后面没有正确链接到功能。处理时不要一开始就调灵敏度或改功能定义，先通过日志确认问题停在哪一层。&lt;/p&gt;
&lt;h2 id=&#34;section-3&#34;&gt;三、同一手势，功能却错了&lt;/h2&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;App 改完触控后，耳机执行的功能不对。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;排查思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一步：固定一个场景复现&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;只测听歌、只测来电响铃，或只测通话，避免混在一起判断。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第二步：确认手势已经识别&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;如果手势都没出来，回到第一类问题排查。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第三步：核对当前场景的功能&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;手势正常后，直接看耳机最后想执行的是什么功能。&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;同样是“双击”：听歌时可能是切歌，来电时应该是接听或拒接，通话中又可能是其他操作。&lt;/li&gt;
&lt;li&gt;来电时双击却去切歌：说明双击识别没有问题，只是耳机还在按“听歌时的规则”处理。&lt;/li&gt;
&lt;li&gt;只有通话异常：重点检查进入通话后，双击和长按是否已经改成通话时该做的功能。&lt;/li&gt;
&lt;li&gt;App 改完才异常：重点检查新设置是否把听歌、来电或通话时的功能改错了。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;判断与处理&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;听歌、来电响铃、通话时都可以识别同一个“双击”或“长按”，但后续要执行的功能并不相同。&lt;/p&gt;
&lt;p&gt;这类问题通常是耳机没有按当前使用状态执行对应功能。处理重点是把每种状态下的功能对应关系确认清楚。&lt;/p&gt;
&lt;h2 id=&#34;section-4&#34;&gt;四、不该响应时仍然响应&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;客户反馈&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;耳机放在盒内还能切歌；刚出盒或拿取耳机时，容易误触切换功能。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;排查思路&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;第一步：确认误触发生的时机&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>【中科蓝讯】TWS 耳机按键处理流程</title>
      <link>https://btio.cn/posts/2026/08/07/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFtws-%E8%80%B3%E6%9C%BA%E6%8C%89%E9%94%AE%E5%A4%84%E7%90%86%E6%B5%81%E7%A8%8B/</link>
      <pubDate>Fri, 07 Aug 2026 18:39:14 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/08/07/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFtws-%E8%80%B3%E6%9C%BA%E6%8C%89%E9%94%AE%E5%A4%84%E7%90%86%E6%B5%81%E7%A8%8B/</guid>
      <description>&lt;p&gt;上一篇已经把 SDK 的几个核心概念过了一遍，包括模式状态机、process/message/display 和消息分层。&lt;/p&gt;
&lt;p&gt;这一篇就拿按键功能做一次具体分析，从一个按键事件出发，一直追到最终执行的位置。&lt;/p&gt;
&lt;p&gt;以我接触到的 TWS 项目来看，按键是应用层里相对好理解、也比较容易上手的一部分：改单击功能、加长按、加多击，或者调整不同模式下的按键行为。这些需求在 SDK 里都对应到同一套机制，弄懂之后，定位修改位置会更快。&lt;/p&gt;
&lt;h2 id=&#34;section-1&#34;&gt;一、先跑一遍完整链路&lt;/h2&gt;
&lt;p&gt;一个按键从手指按下到功能执行，在 SDK 里走了这几步：&lt;/p&gt;
&lt;div class=&#34;mermaid-diagram&#34; role=&#34;group&#34; aria-label=&#34;流程图&#34;&gt;
  &lt;pre class=&#34;mermaid&#34;&gt;%%{init: {&amp;#34;flowchart&amp;#34;: {&amp;#34;htmlLabels&amp;#34;: true, &amp;#34;wrappingWidth&amp;#34;: 1000, &amp;#34;rankSpacing&amp;#34;: 30}, &amp;#34;themeVariables&amp;#34;: {&amp;#34;lineColor&amp;#34;: &amp;#34;#71829a&amp;#34;}}}%%
flowchart TB
    subgraph R0[&amp;#34;① 输入与识别&amp;#34;]
        direction LR
        R0N0[&amp;#34;手指按下&amp;lt;br/&amp;gt;用户触发按键&amp;#34;]
        R0N1[&amp;#34;硬件扫描&amp;lt;br/&amp;gt;读取按键编号&amp;#34;]
        R0N2[&amp;#34;消抖 / 识别&amp;lt;br/&amp;gt;判断短按、长按、多击&amp;#34;]
        R0N0 --&amp;gt; R0N1 --&amp;gt; R0N2
    end
    class R0N0,R0N1,R0N2 blue;
    style R0 fill:#f1f6fd,stroke:#b8cfe8,color:#23456b
    subgraph R1[&amp;#34;② 消息与业务&amp;#34;]
        direction LR
        R1N0[&amp;#34;查按键表&amp;lt;br/&amp;gt;找到对应消息&amp;#34;]
        R1N1[&amp;#34;消息入队&amp;lt;br/&amp;gt;放入消息队列&amp;#34;]
        R1N2[&amp;#34;模式分发&amp;lt;br/&amp;gt;按当前模式处理&amp;#34;]
        R1N3[&amp;#34;功能执行&amp;lt;br/&amp;gt;播放、切歌、接听等&amp;#34;]
        R1N0 --&amp;gt; R1N1 --&amp;gt; R1N2 --&amp;gt; R1N3
    end
    class R1N0,R1N1,R1N2,R1N3 green;
    style R1 fill:#f0f8f3,stroke:#b9d7c4,color:#24563a
    R0 --&amp;gt; R1
    classDef blue fill:#e8f2ff,stroke:#7ba4d8,color:#23456b,stroke-width:1.5px;
    classDef green fill:#e7f4ec,stroke:#78aa8b,color:#24563a,stroke-width:1.5px;
    classDef amber fill:#fff3df,stroke:#d5a25b,color:#72501e,stroke-width:1.5px;&lt;/pre&gt;
&lt;/div&gt;&lt;p&gt;前两步主要回答“这个按键物理上发生了什么”。从第 3 步开始，软件才把按键行为转换成功能。&lt;/p&gt;</description>
    </item>
    <item>
      <title>【中科蓝讯】聊聊我对这套SDK的理解</title>
      <link>https://btio.cn/posts/2026/08/06/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AF%E8%81%8A%E8%81%8A%E6%88%91%E5%AF%B9%E8%BF%99%E5%A5%97sdk%E7%9A%84%E7%90%86%E8%A7%A3/</link>
      <pubDate>Thu, 06 Aug 2026 19:59:39 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/08/06/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AF%E8%81%8A%E8%81%8A%E6%88%91%E5%AF%B9%E8%BF%99%E5%A5%97sdk%E7%9A%84%E7%90%86%E8%A7%A3/</guid>
      <description>&lt;p&gt;前两篇记录了环境搭建和 com/bank 内存的事。这篇主要想讲一下中科蓝汛的 SDK——不讲具体细节，也不列目录结构，每个项目的目录可能都不太一样，列了也没太大意义。主要是聊一下我对这套 SDK 几个核心概念的理解。以后不管拿到哪个版本、做什么功能，这几个概念应该都不会变。&lt;/p&gt;
&lt;h2 id=&#34;section-1&#34;&gt;一、SDK 就是一个&amp;quot;模式状态机&amp;quot;&lt;/h2&gt;
&lt;p&gt;这是做完项目之后最大的感受。一颗 TWS 耳机芯片，任何时候只处于一个&amp;quot;模式&amp;quot;——蓝牙模式、充电模式、IDLE 待机、关机。切模式就是改一个变量 &lt;code&gt;func_cb.sta&lt;/code&gt;。&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// func_run() —— 整个 SDK 的主循环就长这样
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;func_enter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;switch&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;func_cb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sta&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;FUNC_BT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;      &lt;span class=&#34;nf&#34;&gt;func_bt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;      &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 蓝牙
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;FUNC_CHARGE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;func_charge&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 充电
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;FUNC_IDLE&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;    &lt;span class=&#34;nf&#34;&gt;func_idle&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 待机
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;case&lt;/span&gt; &lt;span class=&#34;nl&#34;&gt;FUNC_PWROFF&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;  &lt;span class=&#34;nf&#34;&gt;func_pwroff&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;  &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 关机
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;default&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;:&lt;/span&gt;           &lt;span class=&#34;nf&#34;&gt;func_exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;    &lt;span class=&#34;k&#34;&gt;break&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;  &lt;span class=&#34;c1&#34;&gt;// 退出，切下一个
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;虽然每个模式做的事情不一样，但内部结构都有共同点。拿蓝牙模式看：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;func_bt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;func_bt_enter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;                    &lt;span class=&#34;c1&#34;&gt;// 进来先初始化
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;while&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;func_cb&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sta&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;FUNC_BT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;    &lt;span class=&#34;c1&#34;&gt;// 没切模式就一直在这转
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;func_bt_process&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;              &lt;span class=&#34;c1&#34;&gt;// 轮询事件
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;func_bt_message&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;nf&#34;&gt;msg_dequeue&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;());&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 处理消息
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;nf&#34;&gt;func_bt_display&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;              &lt;span class=&#34;c1&#34;&gt;// 刷新显示
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;nf&#34;&gt;func_bt_exit&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;();&lt;/span&gt;                     &lt;span class=&#34;c1&#34;&gt;// 走之前收尾
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;就是 enter → while → process/message/display → exit。再看 idle 模式，几乎一模一样——&lt;code&gt;func_idle_enter()&lt;/code&gt; → &lt;code&gt;while(func_cb.sta == FUNC_IDLE)&lt;/code&gt; → &lt;code&gt;process/message/display&lt;/code&gt; → 退出。充电和关机模式虽然内部细节不同，但也是 enter → 做事 → exit 这个三段式。&lt;/p&gt;</description>
    </item>
    <item>
      <title>【中科蓝讯】从两次偶发死机，理解 com 区和 bank 区</title>
      <link>https://btio.cn/posts/2026/08/06/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AF%E4%BB%8E%E4%B8%A4%E6%AC%A1%E5%81%B6%E5%8F%91%E6%AD%BB%E6%9C%BA%E7%90%86%E8%A7%A3-com-%E5%8C%BA%E5%92%8C-bank-%E5%8C%BA/</link>
      <pubDate>Thu, 06 Aug 2026 08:00:00 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/08/06/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AF%E4%BB%8E%E4%B8%A4%E6%AC%A1%E5%81%B6%E5%8F%91%E6%AD%BB%E6%9C%BA%E7%90%86%E8%A7%A3-com-%E5%8C%BA%E5%92%8C-bank-%E5%8C%BA/</guid>
      <description>&lt;p&gt;刚接触中科蓝讯 SDK 时，我经常看到函数前面有 &lt;code&gt;AT(.com_text.xxx)&lt;/code&gt;。一开始我只知道照着原有代码写，却不明白它为什么在这里。后来看了资料和工程里的写法，我才认识到：SDK 把代码分区域存放，不同区域的运行方式不一样。&lt;/p&gt;
&lt;p&gt;这篇只是我目前从应用侧整理的一点理解，重点放在看到 &lt;code&gt;AT(...)&lt;/code&gt; 时怎么读。&lt;/p&gt;
&lt;h2 id=&#34;section-1&#34;&gt;一、com 区和 bank 区有什么区别&lt;/h2&gt;
&lt;p&gt;&lt;img alt=&#34;com 区和 bank 区的存放与运行示意&#34; loading=&#34;lazy&#34; src=&#34;https://btio.cn/images/csdn/163511359/image.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;按照官方资料的说明，芯片上电后，一部分代码会从 Flash 搬到 RAM 里常驻下来，这部分就是 &lt;code&gt;com&lt;/code&gt; 区；剩下的代码继续待在 Flash，用到时才被加载到 &lt;code&gt;bank&lt;/code&gt; 运行区。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;区域&lt;/th&gt;
					&lt;th&gt;简单理解&lt;/th&gt;
					&lt;th&gt;适合放什么&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;com&lt;/code&gt; 区&lt;/td&gt;
					&lt;td&gt;上电后会加载到 RAM，并在运行期间常驻&lt;/td&gt;
					&lt;td&gt;中断函数、实时性要求高的&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;code&gt;bank&lt;/code&gt; 区&lt;/td&gt;
					&lt;td&gt;代码存在 Flash，运行时按需加载到 bank 运行区&lt;/td&gt;
					&lt;td&gt;大多数普通应用逻辑&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;code&gt;com&lt;/code&gt; 区的空间有限，所以不要因为更快，就把普通功能都放进去。&lt;/p&gt;
&lt;h2 id=&#34;section-2&#34;&gt;二、真正要注意的是中断和它调用的函数&lt;/h2&gt;
&lt;p&gt;中断函数和它调到的关键函数，通常需要放在 &lt;code&gt;com&lt;/code&gt; 区。因为中断来了要马上处理，不能等到需要时再去加载代码。&lt;/p&gt;
&lt;p&gt;在工程里看定时和一些中断相关代码时，我能看到类似下面的写法：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;AT&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;com_text&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;user_timer_isr&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;c1&#34;&gt;// 中断中的处理
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;实际用的时候，我是先看同模块已有代码的写法，不凭空猜。但照抄还不够——踩过两次坑才知道，光盯着函数本身的 &lt;code&gt;AT&lt;/code&gt;，容易漏掉更深层的依赖。&lt;/p&gt;
&lt;p&gt;第一次是在中断里调了一个普通函数，我给那个函数加了 &lt;code&gt;AT(.com_text.xxx)&lt;/code&gt;，以为这就完事了。结果还是偶发异常。排查后发现，这个函数内部又调了另一个普通函数，那个子函数没加 &lt;code&gt;AT&lt;/code&gt;。中断触发时 CPU 跳到 com 区，执行到嵌套的子函数时，它的代码还在 bank 区没加载进来，一样挂。这件事的风险在于，被调函数可能还调了其他函数，嵌套几层之后很容易漏掉。所以给函数加 &lt;code&gt;AT&lt;/code&gt; 时，得顺着调用链往下检查，确保整条执行路径上的函数都在 com 区。如果调用深度比较大，更稳妥的做法是通过消息转发把逻辑放到其他线程执行，避免在 com 区里越套越深。&lt;/p&gt;</description>
    </item>
    <item>
      <title>【中科蓝讯】SDK 环境搭建与烧录</title>
      <link>https://btio.cn/posts/2026/08/05/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFsdk-%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA%E4%B8%8E%E7%83%A7%E5%BD%95/</link>
      <pubDate>Wed, 05 Aug 2026 14:16:23 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/08/05/%E4%B8%AD%E7%A7%91%E8%93%9D%E8%AE%AFsdk-%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA%E4%B8%8E%E7%83%A7%E5%BD%95/</guid>
      <description>&lt;p&gt;以我最近实际接触的中科蓝讯 BT891x 项目为例，刚开始最先要做的就是把开发环境搭起来：准备资料和工具、打开工程、编译生成 &lt;code&gt;app.dcf&lt;/code&gt;，再用 Downloader 完成后续烧录。&lt;/p&gt;
&lt;p&gt;不同 SDK 版本和开发板的目录、工具版本可能不一样，最终以当前资料包和工程说明为准。&lt;/p&gt;
&lt;h2 id=&#34;section-1&#34;&gt;一、准备资料和工具&lt;/h2&gt;
&lt;p&gt;如果手上的 SDK 对应特定的 TWS 开发板，原理图和相关硬件资料也要一并保存好，后面核对硬件配置、下载和外设问题时都会用到。&lt;/p&gt;
&lt;p&gt;刚开始做 BT891x 时，主要先准备下面四项资料和工具：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;内容&lt;/th&gt;
					&lt;th&gt;先拿它做什么&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;BT891x 固件 SDK&lt;/td&gt;
					&lt;td&gt;后续的功能开发主要就在这里进行&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;CodeBlocks 开发环境&lt;/td&gt;
					&lt;td&gt;打开 &lt;code&gt;.cbp&lt;/code&gt; 工程并发起编译&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;RV32 Toolchain&lt;/td&gt;
					&lt;td&gt;供 CodeBlocks 调用的 RISC-V 编译工具链&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;Downloader&lt;/td&gt;
					&lt;td&gt;读取 &lt;code&gt;app.dcf&lt;/code&gt;，进行配置和烧录处理&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;如果当前使用的是串口下载方式，还要保留蓝讯提供的串口驱动。资料包里的驱动通常以 CP210x 驱动包的形式提供，用于让电脑识别 CP2102 或 XLink 模块对应的 COM 口。&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;BT891x 工具目录与安装、编译、烧录流程&#34; loading=&#34;lazy&#34; src=&#34;https://btio.cn/images/csdn/163496844/2e1ff8f206554d969a4660b56c737383.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;CodeBlocks 和 RV32 Toolchain 都是双击安装程序后，按提示一路选择 &lt;code&gt;Next&lt;/code&gt;、默认路径安装即可。CodeBlocks 用来打开 &lt;code&gt;.cbp&lt;/code&gt; 工程并编译，RV32 Toolchain 是真正执行编译的工具。&lt;/p&gt;
&lt;p&gt;如果使用串口下载，按当前下载器对应的驱动安装即可。下载器和设备接入电脑后，系统能够识别出 COM 口，Downloader 才能继续扫描设备。&lt;/p&gt;
&lt;p&gt;Downloader 不需要安装，解压后直接运行 &lt;code&gt;Downloader.exe&lt;/code&gt; 即可。&lt;/p&gt;
&lt;h2 id=&#34;section-2&#34;&gt;二、编译与烧录&lt;/h2&gt;
&lt;p&gt;环境装完后，我不会马上改功能，而是先在 CodeBlocks 中打开 SDK 里的 &lt;code&gt;.cbp&lt;/code&gt; 工程并编译一次。&lt;/p&gt;</description>
    </item>
    <item>
      <title>一副 TWS 耳机，为什么既要用经典蓝牙，又要用 BLE</title>
      <link>https://btio.cn/posts/2026/08/04/%E4%B8%80%E5%89%AF-tws-%E8%80%B3%E6%9C%BA%E4%B8%BA%E4%BB%80%E4%B9%88%E6%97%A2%E8%A6%81%E7%94%A8%E7%BB%8F%E5%85%B8%E8%93%9D%E7%89%99%E5%8F%88%E8%A6%81%E7%94%A8-ble/</link>
      <pubDate>Tue, 04 Aug 2026 17:48:36 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/08/04/%E4%B8%80%E5%89%AF-tws-%E8%80%B3%E6%9C%BA%E4%B8%BA%E4%BB%80%E4%B9%88%E6%97%A2%E8%A6%81%E7%94%A8%E7%BB%8F%E5%85%B8%E8%93%9D%E7%89%99%E5%8F%88%E8%A6%81%E7%94%A8-ble/</guid>
      <description>&lt;p&gt;做 TWS 耳机时，经常会同时看到经典蓝牙和 BLE。&lt;/p&gt;
&lt;p&gt;手机已经通过蓝牙连接耳机，可以播放音乐、接打电话，为什么配套 App 还要再连接一次 BLE？我刚开始接触时，也没有认真区分这两部分，只知道它们都叫蓝牙。&lt;/p&gt;
&lt;p&gt;后来做 App 交互功能多了，我才慢慢理解：在目前常见的 TWS 产品里，它们处理的事情并不一样。经典蓝牙主要负责音乐、通话和媒体控制，BLE 更像一条给 App 使用的数据通道。&lt;/p&gt;
&lt;h2 id=&#34;section-1&#34;&gt;一、经典蓝牙主要负责耳机的基本功能&lt;/h2&gt;
&lt;p&gt;平时用耳机听歌、调节音量和接打电话，主要涉及经典蓝牙中的几个 Profile：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;Profile&lt;/th&gt;
					&lt;th&gt;在耳机中的主要作用&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;A2DP&lt;/td&gt;
					&lt;td&gt;传输音乐音频&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;AVRCP&lt;/td&gt;
					&lt;td&gt;播放、暂停、切歌和音量控制&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;HFP&lt;/td&gt;
					&lt;td&gt;来电、接听、挂断等通话控制&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;通话时的语音通常还会通过 SCO/eSCO 链路传输。&lt;/p&gt;
&lt;p&gt;这些功能决定了一副耳机能不能正常听歌和通话。以我目前接触到的应用开发来说，平时主要处理 SDK 上报的 A2DP、AVRCP 和 HFP 事件，再根据当前状态执行对应的产品逻辑。&lt;/p&gt;
&lt;h2 id=&#34;section-2&#34;&gt;二、BLE 主要负责耳机与 App 交互&lt;/h2&gt;
&lt;p&gt;配套 App 需要做的事情和播放音乐不太一样。它传输的通常不是连续音频，而是一些控制命令和状态数据。&lt;/p&gt;
&lt;p&gt;我做过的项目里，BLE 主要用于这些功能：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;修改 EQ；&lt;/li&gt;
&lt;li&gt;切换 ANC 模式；&lt;/li&gt;
&lt;li&gt;读取耳机电量；&lt;/li&gt;
&lt;li&gt;OTA 升级；&lt;/li&gt;
&lt;li&gt;查找耳机。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;例如用户在 App 上切换 ANC，App 会通过 BLE 把命令发给耳机；耳机执行以后，还可能需要把最新状态返回给 App。读取电量也是类似的过程，只是数据方向和触发时机可能不同。&lt;/p&gt;
&lt;p&gt;我接触过 GATT 的 Service、Characteristic、读写和通知，不过实际开发时，大部分数据收发还是通过 SDK 封装好的接口完成。刚开始看这些名词时，我觉得它们比较抽象。结合 TWS 耳机的功能，可以先这样理解：&lt;/p&gt;</description>
    </item>
    <item>
      <title>做耳机开发，需要掌握哪些 C 语言知识</title>
      <link>https://btio.cn/posts/2026/08/03/%E5%81%9A%E8%80%B3%E6%9C%BA%E5%BC%80%E5%8F%91%E9%9C%80%E8%A6%81%E6%8E%8C%E6%8F%A1%E5%93%AA%E4%BA%9B-c-%E8%AF%AD%E8%A8%80%E7%9F%A5%E8%AF%86/</link>
      <pubDate>Mon, 03 Aug 2026 16:29:04 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/08/03/%E5%81%9A%E8%80%B3%E6%9C%BA%E5%BC%80%E5%8F%91%E9%9C%80%E8%A6%81%E6%8E%8C%E6%8F%A1%E5%93%AA%E4%BA%9B-c-%E8%AF%AD%E8%A8%80%E7%9F%A5%E8%AF%86/</guid>
      <description>&lt;p&gt;TWS 应用层的大部分工作，最后还是要落到 C 代码上。这篇整理开发中经常用到、也容易混淆的内容，方便需要时快速回顾。&lt;/p&gt;
&lt;h2 id=&#34;section-1&#34;&gt;一、数据类型与类型转换&lt;/h2&gt;
&lt;p&gt;嵌入式代码经常使用 &lt;code&gt;uint8_t&lt;/code&gt;、&lt;code&gt;uint16_t&lt;/code&gt; 和 &lt;code&gt;uint32_t&lt;/code&gt;，因为它们的位宽是明确的。&lt;/p&gt;
&lt;p&gt;&lt;code&gt;int&lt;/code&gt; 占多少字节，由芯片架构和编译器决定。在常见的 32 位平台上，&lt;code&gt;int&lt;/code&gt; 通常占 4 字节；在部分嵌入式平台上，也可能只占 2 字节。可以使用 &lt;code&gt;sizeof&lt;/code&gt; 查看当前平台上的实际大小：&lt;/p&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;nf&#34;&gt;printf&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;int size: %u&lt;/span&gt;&lt;span class=&#34;se&#34;&gt;\n&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;k&#34;&gt;sizeof&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;));&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;sizeof&lt;/code&gt; 返回的是 &lt;code&gt;size_t&lt;/code&gt; 类型。这里先把结果转换成 &lt;code&gt;unsigned int&lt;/code&gt;，再使用 &lt;code&gt;%u&lt;/code&gt; 输出，适合常见的嵌入式 &lt;code&gt;printf&lt;/code&gt;。&lt;/p&gt;
&lt;p&gt;普通计算和循环计数可以使用 &lt;code&gt;int&lt;/code&gt;。通信协议、Flash 数据、文件格式和寄存器字段需要明确长度时，优先使用固定位宽类型。&lt;/p&gt;
&lt;p&gt;类型转换主要注意下面几种情况：&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;情况&lt;/th&gt;
					&lt;th&gt;需要注意什么&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;大类型转小类型&lt;/td&gt;
					&lt;td&gt;高位可能被截断&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;tr&gt;
					&lt;td&gt;无符号与有符号比较&lt;/td&gt;
					&lt;td&gt;有符号数可能先被转成无符号数&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;blockquote&gt;
&lt;p&gt;注意：有符号数和无符号数比较前，尽量把两边统一成合适的类型。进行指针类型转换时，要确认原内存长度不小于目标类型的大小。例如原数据只有 1 字节，转换成 &lt;code&gt;uint32_t *&lt;/code&gt; 后却按照 4 字节读取，就会读到不属于它的内存。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&#34;section-2&#34;&gt;二、指针、数组与生命周期&lt;/h2&gt;
&lt;p&gt;指针保存的是地址。使用前主要检查四件事：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;指针是否为空。&lt;/li&gt;
&lt;li&gt;指向的内存是否仍然有效。&lt;/li&gt;
&lt;li&gt;访问长度是否越界。&lt;/li&gt;
&lt;li&gt;指针指向的数据类型是否正确。&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;update_state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uint8_t&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;nb&#34;&gt;NULL&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;state&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;mi&#34;&gt;1&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;数组传入函数后通常会退化成指针，函数内部无法再通过 &lt;code&gt;sizeof&lt;/code&gt; 得到原数组长度。因此传递缓冲区时，最好同时传入长度。&lt;/p&gt;</description>
    </item>
    <item>
      <title>做 TWS 应用开发，到底需不需要懂协议栈</title>
      <link>https://btio.cn/posts/2026/08/03/%E5%81%9A-tws-%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E5%88%B0%E5%BA%95%E9%9C%80%E4%B8%8D%E9%9C%80%E8%A6%81%E6%87%82%E5%8D%8F%E8%AE%AE%E6%A0%88/</link>
      <pubDate>Mon, 03 Aug 2026 11:26:31 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/08/03/%E5%81%9A-tws-%E5%BA%94%E7%94%A8%E5%BC%80%E5%8F%91%E5%88%B0%E5%BA%95%E9%9C%80%E4%B8%8D%E9%9C%80%E8%A6%81%E6%87%82%E5%8D%8F%E8%AE%AE%E6%A0%88/</guid>
      <description>&lt;p&gt;刚接触 TWS 应用开发时，我一直有一个疑问：蓝牙协议栈大部分已经由芯片原厂封装好了，平时做功能主要是调用 SDK 接口、处理事件和编写产品逻辑，还有没有必要专门学习协议栈？&lt;/p&gt;
&lt;p&gt;刚入行的时候，我也尝试过从头学习蓝牙协议。当时下载了一份 Bluetooth Core Specification 6.0，打开后看到整整 3815 页，心里压力一下就上来了。里面有大量英文术语、状态、命令和数据包格式，我硬着头皮看了几天，还是很难把规范里的内容和手上的代码对应起来，最后没有坚持下去。&lt;/p&gt;
&lt;p&gt;工作两年左右，我对协议栈内部仍然谈不上有多深入的理解，平时接触最多的还是应用层代码。所以我现在的看法是：**需要了解一些，但没必要一开始钻得特别深。**这篇文章只是记录我目前在项目中用到的一些认识。&lt;/p&gt;
&lt;h2 id=&#34;section-1&#34;&gt;一、我目前主要关注什么&lt;/h2&gt;
&lt;p&gt;以我目前的工作内容来说，HCI、L2CAP 以及各个 Profile 的内部状态机，我其实没有深入研究。日常开发更常见的是调用 SDK 接口、接收事件，再根据产品状态处理业务。&lt;/p&gt;
&lt;p&gt;为了不把不同问题混在一起，我会先记住几个和工作直接相关的区别：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ACL 连接和 Profile 连接不是一回事。&lt;/li&gt;
&lt;li&gt;A2DP 负责音乐，AVRCP 负责播放控制和音量同步。&lt;/li&gt;
&lt;li&gt;HFP 负责通话控制，SCO/eSCO 承载通话语音。&lt;/li&gt;
&lt;li&gt;SPP 和 BLE GATT 常用于 App 数据通信。&lt;/li&gt;
&lt;li&gt;接口调用成功，不一定代表异步操作已经完成，还要等待后续事件。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;为了更直观地区分这些连接和业务，可参考蓝牙连接关系简化图：&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;手机与 TWS 耳机的蓝牙连接关系&#34; loading=&#34;lazy&#34; src=&#34;https://btio.cn/images/csdn/163436393/%E6%89%8B%E6%9C%BA%E4%B8%8ETWS%E8%80%B3%E6%9C%BA%E7%9A%84%E8%93%9D%E7%89%99%E8%BF%9E%E6%8E%A5%E5%85%B3%E7%B3%BB.png&#34;&gt;&lt;/p&gt;
&lt;p&gt;图中把 GATT 单独放在 BLE 连接下。严格来说，协议内部的承载关系还要更细，这里只保留我在应用开发中经常接触到的部分。&lt;/p&gt;
&lt;p&gt;我目前也就是先把这些常见概念分清。这样遇到异常时，至少知道先看哪一类状态，不至于一上来就把所有现象都归结成“蓝牙有问题”。&lt;/p&gt;
&lt;h2 id=&#34;section-2&#34;&gt;二、实际项目里，我能接触到什么&lt;/h2&gt;
&lt;p&gt;以我使用的中科蓝讯 &lt;code&gt;bt8910&lt;/code&gt; SDK 为例，工程里可以看到 A2DP、HFP、SPP 和 TWS 相关的配置及适配代码，但真正的核心实现主要由预编译的 &lt;code&gt;libbtstack.a&lt;/code&gt; 提供。&lt;/p&gt;
&lt;p&gt;应用层这边，A2DP 和 HFP 主要是调整部分参数、接收事件和处理业务回调；SPP 的 SDP Record 和数据收发回调可以看到并修改；GATT 可以添加 Service、Characteristic 和读写回调；TWS 这边则能做一些业务状态同步和主从切换处理。&lt;/p&gt;</description>
    </item>
    <item>
      <title>一副 TWS 耳机里，有哪些软件模块</title>
      <link>https://btio.cn/posts/2026/07/31/%E4%B8%80%E5%89%AF-tws-%E8%80%B3%E6%9C%BA%E9%87%8C%E6%9C%89%E5%93%AA%E4%BA%9B%E8%BD%AF%E4%BB%B6%E6%A8%A1%E5%9D%97/</link>
      <pubDate>Fri, 31 Jul 2026 18:32:50 +0800</pubDate>
      <guid>https://btio.cn/posts/2026/07/31/%E4%B8%80%E5%89%AF-tws-%E8%80%B3%E6%9C%BA%E9%87%8C%E6%9C%89%E5%93%AA%E4%BA%9B%E8%BD%AF%E4%BB%B6%E6%A8%A1%E5%9D%97/</guid>
      <description>&lt;h2 id=&#34;section-1&#34;&gt;一、先看整体&lt;/h2&gt;
&lt;p&gt;如果暂时不考虑具体芯片平台，TWS 耳机的软件大致可以分成下面几个部分：&lt;/p&gt;
&lt;p&gt;&lt;img alt=&#34;TWS 耳机软件模块组成&#34; loading=&#34;lazy&#34; src=&#34;https://btio.cn/images/csdn/163373023/software-modules.svg&#34;&gt;&lt;/p&gt;
&lt;p&gt;这不是严格的分层架构。实际 SDK 中，各部分往往会互相调用，甚至放在同一个模块里。这样划分主要是为了看清楚：一个耳机功能背后，通常有哪些软件在配合。&lt;/p&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;软件模块&lt;/th&gt;
					&lt;th&gt;主要负责什么&lt;/th&gt;
					&lt;th&gt;常见内容&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;系统与 RTOS&lt;/td&gt;
					&lt;td&gt;让程序和多个任务运行起来&lt;/td&gt;
					&lt;td&gt;任务、消息、定时器、内存、看门狗&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;驱动与电源&lt;/td&gt;
					&lt;td&gt;与耳机硬件交互&lt;/td&gt;
					&lt;td&gt;GPIO、ADC、I2C、I2S、充电、休眠、唤醒&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;蓝牙连接&lt;/td&gt;
					&lt;td&gt;与手机建立和维护蓝牙业务&lt;/td&gt;
					&lt;td&gt;配对、回连、A2DP、AVRCP、HFP、BLE&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;双耳协同&lt;/td&gt;
					&lt;td&gt;让左右耳保持一致&lt;/td&gt;
					&lt;td&gt;双耳组对、角色、状态同步、音频协同&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;音频系统&lt;/td&gt;
					&lt;td&gt;管理声音输入和输出&lt;/td&gt;
					&lt;td&gt;编解码、播放、录音、提示音、ANC、ENC&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;产品应用&lt;/td&gt;
					&lt;td&gt;决定耳机具体怎样工作&lt;/td&gt;
					&lt;td&gt;按键、LED、佩戴检测、状态机、功能优先级&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;数据与升级&lt;/td&gt;
					&lt;td&gt;保存配置并更新固件&lt;/td&gt;
					&lt;td&gt;配对记录、用户设置、OTA、版本管理&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;调试与测试&lt;/td&gt;
					&lt;td&gt;帮助发现和定位问题&lt;/td&gt;
					&lt;td&gt;日志、异常信息、测试模式、量产支持&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h2 id=&#34;section-2&#34;&gt;二、系统与 RTOS&lt;/h2&gt;
&lt;p&gt;TWS 耳机一般不是从上到下只执行一条固定流程。蓝牙事件、按键、音频、充电和定时任务可能在不同时间发生，因此软件需要同时管理多种事情。&lt;/p&gt;
&lt;p&gt;这一部分通常包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;系统启动和各模块初始化&lt;/li&gt;
&lt;li&gt;任务或线程的创建与调度&lt;/li&gt;
&lt;li&gt;事件、消息和队列&lt;/li&gt;
&lt;li&gt;软件定时器&lt;/li&gt;
&lt;li&gt;内存分配与任务栈&lt;/li&gt;
&lt;li&gt;中断处理&lt;/li&gt;
&lt;li&gt;看门狗和异常恢复&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;应用层开发中经常接触到的，并不是 RTOS 调度器本身，而是平台提供的任务、消息和回调接口。&lt;/p&gt;
&lt;p&gt;例如，按键驱动检测到一次双击后，不一定会直接执行“切换降噪模式”。它可能先产生按键事件，再把事件投递给应用任务，最后由应用代码根据当前状态决定是否执行这个功能。&lt;/p&gt;
&lt;p&gt;所以，当我们阅读一个新 SDK 时，找到事件入口和消息流转路径很重要。&lt;/p&gt;
&lt;h2 id=&#34;section-3&#34;&gt;三、硬件驱动与电源管理&lt;/h2&gt;
&lt;p&gt;耳机虽然体积不大，但里面仍然有不少硬件。软件需要通过不同接口读取状态或者控制这些器件。&lt;/p&gt;
&lt;p&gt;常见内容包括：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GPIO：NTC供电、LED、使能信号&lt;/li&gt;
&lt;li&gt;ADC：按键电压、其他模拟量&lt;/li&gt;
&lt;li&gt;UART：日志输出、机盒&lt;/li&gt;
&lt;li&gt;充电与盒仓检测：识别 DC、入盒、出盒、开盖、关盖、充电和满电等状态&lt;/li&gt;
&lt;li&gt;佩戴检测：红外、触摸或其他传感器&lt;/li&gt;
&lt;li&gt;I2C、SPI：传感器、外部芯片或存储器&lt;/li&gt;
&lt;li&gt;I2S、PCM：数字音频数据传输&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;驱动层负责把硬件状态转换成软件可以识别的数据或事件，应用层再决定怎样处理。&lt;/p&gt;
&lt;p&gt;“耳机入盒”背后涉及盒仓状态检测、TWS 对耳同步、按键禁用、ANC 和音乐处理、DAC 控制及主从切换；关盖后还要关闭蓝牙并进入 &lt;code&gt;FUNC_IDLE&lt;/code&gt;或 charge等其他模式。处理不完整，可能导致左右耳状态不一致、盒内仍播放声音或关盖后仍连接手机。&lt;/p&gt;</description>
    </item>
    <item>
      <title>蓝牙核心系统架构介绍</title>
      <link>https://btio.cn/posts/2025/11/10/%E8%93%9D%E7%89%99%E6%A0%B8%E5%BF%83%E7%B3%BB%E7%BB%9F%E6%9E%B6%E6%9E%84%E4%BB%8B%E7%BB%8D/</link>
      <pubDate>Mon, 10 Nov 2025 00:08:08 +0800</pubDate>
      <guid>https://btio.cn/posts/2025/11/10/%E8%93%9D%E7%89%99%E6%A0%B8%E5%BF%83%E7%B3%BB%E7%BB%9F%E6%9E%B6%E6%9E%84%E4%BB%8B%E7%BB%8D/</guid>
      <description>&lt;h2 id=&#34;section-1&#34;&gt;一、蓝牙的两种模式&lt;/h2&gt;
&lt;h3 id=&#34;1经典蓝牙bredr&#34;&gt;（1）经典蓝牙（BR/EDR）&lt;/h3&gt;
&lt;p&gt;用于高数据速率应用，如无线耳机、音箱、键盘。&lt;/p&gt;
&lt;p&gt;特点是连接稳定，适合持续传输音频或大量数据。&lt;/p&gt;
&lt;h3 id=&#34;2低功耗蓝牙ble&#34;&gt;（2）低功耗蓝牙（BLE）&lt;/h3&gt;
&lt;p&gt;专为低功耗设备设计，如智能手环、温度计、传感器。&lt;/p&gt;
&lt;p&gt;特点是耗电低，适合间歇性传输小数据。&lt;/p&gt;
&lt;p&gt;总结：两种模式底层都用无线信号传输数据，都遵循蓝牙协议，只是侧重点不同。经典蓝牙重视速度和稳定，BLE重视省电和简单连接。&lt;/p&gt;
&lt;h2 id=&#34;section-2&#34;&gt;二、蓝牙核心系统组成&lt;/h2&gt;
&lt;p&gt;蓝牙核心系统由主机（Host）和控制器（Controller）两部分组成。&lt;/p&gt;
&lt;p&gt;主机负责高层协议和控制逻辑，控制器处理底层射频和信号传输。两者分工合作，设备才能正常工作。&lt;/p&gt;
&lt;h2 id=&#34;section-3&#34;&gt;三、主机部分（Host）&lt;/h2&gt;
&lt;p&gt;主机包含多个协议模块，经典蓝牙和BLE有所不同。&lt;/p&gt;
&lt;p&gt;经典蓝牙主要模块：&lt;/p&gt;
&lt;p&gt;GAP（通用访问协议）：管理设备发现和连接建立。&lt;/p&gt;
&lt;p&gt;SDP（服务发现协议）：帮助设备发现对方支持的服务。&lt;/p&gt;
&lt;p&gt;L2CAP（逻辑链路控制协议）：管理数据流，负责数据分段和重组。&lt;/p&gt;
&lt;p&gt;SMP（安全管理协议）：负责加密连接和密钥管理。&lt;/p&gt;
&lt;p&gt;BLE主要模块：&lt;/p&gt;
&lt;p&gt;GAP（通用访问协议）：管理设备发现和连接建立。&lt;/p&gt;
&lt;p&gt;GATT（通用属性协议）：规定设备如何描述和交换数据属性。&lt;/p&gt;
&lt;p&gt;ATT（属性协议）：按照GATT规则传输数据。&lt;/p&gt;
&lt;p&gt;SMP（安全管理协议）：负责加密连接和密钥管理。&lt;/p&gt;
&lt;p&gt;经典蓝牙工作流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;GAP搜索附近设备并建立连接&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SDP查找对方支持的服务&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;L2CAP处理数据传输，分段重组&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SMP管理密钥和加密&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;BLE工作流程：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;GAP搜索附近设备并建立连接&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;GATT列出设备支持的服务和数据属性&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;ATT按照GATT规定格式传送数据&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;SMP保障连接和数据安全&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;section-4&#34;&gt;四、控制器部分（Controller）&lt;/h2&gt;
&lt;p&gt;控制器处理蓝牙底层功能，直接与硬件交互。&lt;/p&gt;
&lt;p&gt;主要模块：&lt;/p&gt;
&lt;p&gt;LL（链路层）：管理蓝牙设备的链路状态和数据包传输。&lt;/p&gt;
&lt;p&gt;RF（射频层）：处理蓝牙信号的发送和接收。&lt;/p&gt;
&lt;p&gt;IAL（等时音频层）：BLE特有，处理高实时性数据传输，例如音频。&lt;/p&gt;
&lt;p&gt;控制器主要负责：&lt;/p&gt;
&lt;p&gt;链路管理：连接的建立、维持、断开。&lt;/p&gt;
&lt;p&gt;无线信号传输：信号调制解调、频率管理、纠错编码。&lt;/p&gt;
&lt;p&gt;硬件交互：直接控制无线电模块发射和接收。&lt;/p&gt;
&lt;h2 id=&#34;section-5&#34;&gt;五、HCI（主机控制器接口）&lt;/h2&gt;
&lt;p&gt;HCI是连接主机和控制器的桥梁，负责两部分之间通信。&lt;/p&gt;
&lt;p&gt;特点：&lt;/p&gt;
&lt;p&gt;标准化接口，让不同厂商的设备互相兼容。&lt;/p&gt;
&lt;p&gt;传输命令、事件和数据包。&lt;/p&gt;
&lt;p&gt;举例：手机的应用层通过HCI命令告诉蓝牙芯片&amp;quot;开始扫描附近设备&amp;quot;，芯片执行后通过HCI事件返回扫描结果。&lt;/p&gt;
&lt;h2 id=&#34;section-6&#34;&gt;六、双模蓝牙&lt;/h2&gt;
&lt;p&gt;双模蓝牙同时支持经典蓝牙和BLE，一个设备两种能力&lt;/p&gt;
&lt;p&gt;硬件层面同时支持BR/EDR和BLE。软件层面整合经典蓝牙和BLE的高层协议。&lt;/p&gt;
&lt;p&gt;支持经典蓝牙的SDP和BLE的GATT，灵活切换。&lt;/p&gt;
&lt;p&gt;举例：手机可以同时连接蓝牙耳机（经典蓝牙）和智能手环（BLE）&lt;/p&gt;
&lt;h2 id=&#34;section-7&#34;&gt;七、总结&lt;/h2&gt;
&lt;p&gt;经典蓝牙和BLE虽然侧重不同，但架构相似：都是主机管逻辑，控制器管硬件，通过HCI通信&lt;/p&gt;
&lt;p&gt;经典蓝牙适合持续大数据传输，BLE适合低功耗间歇传输。&lt;/p&gt;
&lt;p&gt;双模设备兼具两种能力，应用更广泛。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;原文：&lt;a href=&#34;https://blog.csdn.net/qq_56070244/article/details/154621561&#34;&gt;CSDN · 蓝牙核心系统架构介绍&lt;/a&gt;
&lt;/p&gt;</description>
    </item>
    <item>
      <title>BLE设备地址介绍</title>
      <link>https://btio.cn/posts/2025/11/09/ble%E8%AE%BE%E5%A4%87%E5%9C%B0%E5%9D%80%E4%BB%8B%E7%BB%8D/</link>
      <pubDate>Sun, 09 Nov 2025 21:19:34 +0800</pubDate>
      <guid>https://btio.cn/posts/2025/11/09/ble%E8%AE%BE%E5%A4%87%E5%9C%B0%E5%9D%80%E4%BB%8B%E7%BB%8D/</guid>
      <description>&lt;h2 id=&#34;section-1&#34;&gt;什么是BLE设备地址&lt;/h2&gt;
&lt;p&gt;BLE设备地址48位长度，用来识别低功耗蓝牙设备。&lt;/p&gt;
&lt;p&gt;地址分为公共地址和随机地址两大类，现代BLE设备为保护隐私，很少直接用公共地址广播。&lt;br&gt;
注意：BLE地址和经典蓝牙地址虽然都是48位，但机制不同。&lt;/p&gt;
&lt;h2 id=&#34;section-2&#34;&gt;一、公共设备地址&lt;/h2&gt;
&lt;p&gt;由IEEE官方分配，全球唯一，永久不变。&lt;br&gt;
常见设备：早期蓝牙键盘、鼠标。&lt;br&gt;
优点：全球唯一，不会冲突。&lt;br&gt;
缺点：申请要钱，容易被追踪定位。&lt;br&gt;
地址结构：通常前3字节是厂商代码，后3字节厂商自己分配，也可以自定义。&lt;/p&gt;
&lt;p&gt;举例：00:1A:7D:12:34:56&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;00:1A:7D = 苹果厂商代码&lt;/li&gt;
&lt;li&gt;12:34:56 = 苹果内部设备序号&lt;br&gt;
  &lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;section-3&#34;&gt;二、随机设备地址&lt;/h2&gt;
&lt;p&gt;BLE随机设备地址，设备自己生成，分三种：&lt;/p&gt;
&lt;h3 id=&#34;1-静态随机地址&#34;&gt;1. 静态随机地址&lt;/h3&gt;
&lt;p&gt;开机时随机生成，本次开机内不变，重启后重新生成。&lt;br&gt;
地址特征：最高两位为&amp;quot;11&amp;quot;，地址C0-FF开头。&lt;br&gt;
常见设备：智能手环、体重秤、温度计。&lt;br&gt;
优点：免费，开机内稳定连接。&lt;br&gt;
缺点：设备多了可能冲突，重启后地址变化可能影响自动重连。&lt;/p&gt;
&lt;h3 id=&#34;2-可解析私有地址&#34;&gt;2. 可解析私有地址&lt;/h3&gt;
&lt;p&gt;BLE隐私保护核心。地址定期变化（通常15分钟），配对过的设备可通过IRK密钥识别真实身份。&lt;br&gt;
地址特征：最高两位为&amp;quot;01&amp;quot;，地址40-7F开头。&lt;br&gt;
常见设备：iPhone、Apple Watch、Android手机、AirPods。&lt;br&gt;
工作原理：设备用IRK密钥生成临时地址，配对设备存有IRK可验证身份，陌生设备只看到随机地址。&lt;br&gt;
举例：商场里手机地址每10分钟变一次，商家无法追踪你。但AirPods能认出你的手机，因为有共享密钥。&lt;br&gt;
优点：防位置追踪，不影响已配对设备连接。&lt;br&gt;
缺点：需要密钥管理和地址解析算法。&lt;/p&gt;
&lt;h3 id=&#34;3-不可解析私有地址nrpa&#34;&gt;3. 不可解析私有地址（NRPA）&lt;/h3&gt;
&lt;p&gt;完全随机临时地址，任何设备都无法识别。&lt;br&gt;
地址特征：最高两位为&amp;quot;00&amp;quot;，地址00-3F开头&lt;br&gt;
常见场景：BLE Beacon广播、一次性数据推送。&lt;br&gt;
举例：商场Beacon广播促销信息，路人收到即可，无需连接和识别。&lt;br&gt;
优点：最强隐私保护。&lt;br&gt;
缺点：无法建立连接，只能单向广播。&lt;/p&gt;
&lt;h2 id=&#34;section-4&#34;&gt;三、应用场景对比&lt;/h2&gt;
&lt;p&gt;蓝牙键盘鼠标：公共地址，稳定识别。&lt;br&gt;
智能手环体重秤：静态随机地址，成本低。&lt;br&gt;
iPhone和智能手表：可解析私有地址，防追踪。&lt;br&gt;
BLE Beacon：不可解析私有地址，一次性推送。&lt;/p&gt;
&lt;h2 id=&#34;section-5&#34;&gt;四、BLE和经典蓝牙地址区别&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;经典蓝牙主要用公共地址，很少变化。&lt;/li&gt;
&lt;li&gt;BLE主流用随机地址（特别是可解析私有地址），定期变化保护隐私。&lt;/li&gt;
&lt;li&gt;同一设备可能同时有经典蓝牙地址和BLE地址，它们独立。&lt;/li&gt;
&lt;li&gt;BLE地址最高2位标识类型，经典蓝牙没有。&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&#34;section-6&#34;&gt;五、实用知识&lt;/h2&gt;
&lt;p&gt;查看BLE地址（Android）：设置→关于手机→状态信息→蓝牙地址。&lt;br&gt;
手机地址为什么总变？现代手机用可解析私有地址，每10-15分钟换一次，防止被追踪。&lt;/p&gt;
&lt;p&gt;识别地址类型看第一字节：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;C0-FF：静态随机&lt;/li&gt;
&lt;li&gt;40-7F：可解析私有&lt;/li&gt;
&lt;li&gt;00-3F：不可解析私有&lt;/li&gt;
&lt;li&gt;其他：公共地址&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&#34;section-7&#34;&gt;总结：&lt;/h2&gt;
&lt;p&gt;BLE地址虽然分为四类，但一般都使用随机地址，在开发中&lt;/p&gt;
&lt;p&gt;小型外设一般用静态随机，简单省钱&lt;br&gt;
手机可穿戴一般用可解析私有，保护隐私&lt;br&gt;
广播类一般用不可解析私有，单向推送&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;原文：&lt;a href=&#34;https://blog.csdn.net/qq_56070244/article/details/154617680&#34;&gt;CSDN · BLE设备地址介绍&lt;/a&gt;
&lt;/p&gt;</description>
    </item>
    <item>
      <title>BLE的7种工作状态</title>
      <link>https://btio.cn/posts/2025/11/09/ble%E7%9A%847%E7%A7%8D%E5%B7%A5%E4%BD%9C%E7%8A%B6%E6%80%81/</link>
      <pubDate>Sun, 09 Nov 2025 21:11:30 +0800</pubDate>
      <guid>https://btio.cn/posts/2025/11/09/ble%E7%9A%847%E7%A7%8D%E5%B7%A5%E4%BD%9C%E7%8A%B6%E6%80%81/</guid>
      <description>&lt;p&gt;BLE芯片的链路层定义了7种工作状态，同一时间只能处于一种状态，不同状态之间可以切换，一颗芯片可以有多个状态机同时工作，下面对这些状态进行介绍。&lt;/p&gt;
&lt;h2 id=&#34;section-1&#34;&gt;七大状态介绍&lt;/h2&gt;
&lt;h3 id=&#34;section-2&#34;&gt;一、待机状态（Idle）&lt;/h3&gt;
&lt;p&gt;芯片既不发送也不接收数据，处于休眠。&lt;/p&gt;
&lt;p&gt;特点：&lt;/p&gt;
&lt;p&gt;可以从任何状态进入待机状态&lt;/p&gt;
&lt;p&gt;可以从待机进入除连接状态外的所有状态&lt;/p&gt;
&lt;p&gt;不发射不接收，最省电&lt;/p&gt;
&lt;p&gt;举例：你的手环没在用时，芯片就在待机状态睡觉。&lt;/p&gt;
&lt;h3 id=&#34;section-3&#34;&gt;二、广播状态（Advertising）&lt;/h3&gt;
&lt;p&gt;芯片主动发送广告包，告诉周围&amp;quot;我在这里&amp;quot;。&lt;/p&gt;
&lt;p&gt;作用：让别人发现你，并能回复扫描请求。&lt;/p&gt;
&lt;p&gt;举例：蓝牙音箱进入配对模式，不断广播&amp;quot;我是XX音箱，快来连我&amp;quot;。&lt;/p&gt;
&lt;p&gt;可以从广告状态直接进入连接状态。&lt;/p&gt;
&lt;h3 id=&#34;section-4&#34;&gt;三、扫描状态（Scanning）&lt;/h3&gt;
&lt;p&gt;芯片监听周围的广告包，寻找可用设备。&lt;/p&gt;
&lt;p&gt;作用：发现附近的BLE设备。&lt;/p&gt;
&lt;p&gt;举例：手机打开蓝牙，扫描附近设备，此时手机处于扫描状态。&lt;/p&gt;
&lt;h3 id=&#34;section-5&#34;&gt;四、发起状态（Initiating）&lt;/h3&gt;
&lt;p&gt;芯片接收特定设备的广告包，并回复连接请求。&lt;/p&gt;
&lt;p&gt;作用：主动发起连接。&lt;/p&gt;
&lt;p&gt;举例：手机点击&amp;quot;连接手环&amp;quot;，进入发起状态，向手环发送连接请求。&lt;/p&gt;
&lt;p&gt;可以从发起状态进入连接状态。&lt;/p&gt;
&lt;h3 id=&#34;section-6&#34;&gt;五、连接状态（Connection）&lt;/h3&gt;
&lt;p&gt;设备已建立连接，可以双向传输数据。&lt;/p&gt;
&lt;p&gt;作用：进行数据交互。&lt;/p&gt;
&lt;p&gt;举例：手环和手机已连接，正在同步步数和心率数据。&lt;/p&gt;
&lt;p&gt;注意：只能从广播状态或发起状态进入连接状态，不能从待机直接连接&lt;/p&gt;
&lt;h3 id=&#34;section-7&#34;&gt;六、同步状态（Synchronization）&lt;/h3&gt;
&lt;p&gt;芯片接收周期性广告的数据包。&lt;/p&gt;
&lt;p&gt;作用：同步接收定期更新的信息。&lt;/p&gt;
&lt;p&gt;举例：接收BLE定位信标的周期性位置信息。&lt;/p&gt;
&lt;p&gt;适用场景：需要定时接收广播数据但不建立连接。&lt;/p&gt;
&lt;h3 id=&#34;section-8&#34;&gt;七、等时广播状态（Isochronous Broadcasting）&lt;/h3&gt;
&lt;p&gt;芯片在等时信道上发送数据包。&lt;/p&gt;
&lt;p&gt;作用：发送对时间敏感的数据流。&lt;/p&gt;
&lt;p&gt;举例：BLE音频设备同步传输音乐到多个耳机（LE Audio）。&lt;/p&gt;
&lt;p&gt;适用场景：需要精确时序的音频或数据传输。&lt;/p&gt;
&lt;h3 id=&#34;section-9&#34;&gt;八、状态切换规则&lt;/h3&gt;
&lt;p&gt;常见切换路径：&lt;/p&gt;
&lt;p&gt;待机 → 广播 → 连接（外设被连接）&lt;/p&gt;
&lt;p&gt;待机 → 扫描 → 发起 → 连接（中心设备主动连接）&lt;/p&gt;
&lt;p&gt;连接 → 待机（断开连接）&lt;/p&gt;
&lt;p&gt;任何状态 → 待机（随时可以休眠省电）&lt;/p&gt;
&lt;p&gt;待机 → 广播/扫描/同步/等时广播（但不能直接到连接）&lt;/p&gt;
&lt;h3 id=&#34;section-10&#34;&gt;九、实际应用场景&lt;/h3&gt;
&lt;p&gt;智能手环：&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;没用时：待机状态（省电）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;等待连接：广播状态（被发现）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;已连接：连接状态（传数据）&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;断开后：回到待机&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;手机：&lt;/p&gt;</description>
    </item>
    <item>
      <title>无线通信是如何实现的</title>
      <link>https://btio.cn/posts/2025/11/08/%E6%97%A0%E7%BA%BF%E9%80%9A%E4%BF%A1%E6%98%AF%E5%A6%82%E4%BD%95%E5%AE%9E%E7%8E%B0%E7%9A%84/</link>
      <pubDate>Sat, 08 Nov 2025 18:45:37 +0800</pubDate>
      <guid>https://btio.cn/posts/2025/11/08/%E6%97%A0%E7%BA%BF%E9%80%9A%E4%BF%A1%E6%98%AF%E5%A6%82%E4%BD%95%E5%AE%9E%E7%8E%B0%E7%9A%84/</guid>
      <description>&lt;p&gt;无线通信技术早已经融入我们的生活，如手机通信，WiFi，蓝牙。背后都离不开它的支撑。那么，这项技术究竟是如何实现的呢？&lt;/p&gt;
&lt;h2 id=&#34;section-1&#34;&gt;一、基本实现原理&lt;/h2&gt;
&lt;p&gt;无线通信用的是电磁波信号，我们说话的语音，拍的图片，听的音乐，这些信息首先通过调制技术加载到无线载波上，然后由发射设备发送出去。接收方通过解调操作，把载波上的信息取下来，恢复成原始信号。&lt;/p&gt;
&lt;h2 id=&#34;section-2&#34;&gt;二、系统构建复杂性&lt;/h2&gt;
&lt;p&gt;构建一个无线通信系统很复杂，它主要涉及以下几个部分：&lt;/p&gt;
&lt;p&gt;1.模数转换           （确保传输和处理时兼容）&lt;/p&gt;
&lt;p&gt;2.RF射频设计      （负责信号发射和接收频率调控）&lt;/p&gt;
&lt;p&gt;3.协议栈                （无线通信标准）&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;专业开发要求&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;硬件设计需要高精度元器件匹配，系统调试需专门开发环境与经验，因此市场上很少从头搭建系统，而是普遍采用常用无线通信模块。把多个核心元器件集成在一起，直接实现特定通信功能，大大降低了应用门槛。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;无线通信模块&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;无线通信模块就像是一个与装好的工具箱，主要由基带芯片，射频收发器等关键元器件组成，能直接作为通信终端使用，其中两大核心部分尤为重要。&lt;/p&gt;
&lt;p&gt;1.系带芯片：调制解调。同时还会检测传输中可能出现的错误，并及时纠正，确保信息准确。&lt;/p&gt;
&lt;p&gt;2.射频前端电路：信号强化器。射频信号在传输过程中可能会衰减，混入杂音，射频前端就负责对信号进行放大（提升强度，让传输更远）和滤波（过滤杂音）处理好的信号在通过天线发射出去，确保对方能清晰收到。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;总结&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;无线通信系统的实现就是信息数字化“编码调制-射频发射-接收解调-信息还原”的闭环，在通过核心硬件的协同和统一标准的规定，最终实现稳定，高效的无线通信。&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;原文：&lt;a href=&#34;https://blog.csdn.net/qq_56070244/article/details/154576210&#34;&gt;CSDN · 无线通信是如何实现的&lt;/a&gt;
&lt;/p&gt;</description>
    </item>
    <item>
      <title>无线通信原理</title>
      <link>https://btio.cn/posts/2025/11/08/%E6%97%A0%E7%BA%BF%E9%80%9A%E4%BF%A1%E5%8E%9F%E7%90%86/</link>
      <pubDate>Sat, 08 Nov 2025 17:09:46 +0800</pubDate>
      <guid>https://btio.cn/posts/2025/11/08/%E6%97%A0%E7%BA%BF%E9%80%9A%E4%BF%A1%E5%8E%9F%E7%90%86/</guid>
      <description>&lt;h2 id=&#34;section-1&#34;&gt;1. 无线通信的本质：把信息“寄”到空气里&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;：看不见摸不着，却能把内容送出去。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;要传的内容 = 信息&lt;/strong&gt;：音乐、指令、传感器数据等。&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;无线通信的流程只有两步：&lt;/p&gt;
&lt;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;/ol&gt;
&lt;h3 id=&#34;section-2&#34;&gt;✏️ 蓝牙通信实例&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;调制&lt;/strong&gt;：手机播放音乐时，蓝牙芯片把音频数据调制到 2.4 GHz 电磁波上，同时选择合适的频道，避免和 Wi-Fi “撞车”。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;解调&lt;/strong&gt;：蓝牙耳机接收到电磁波后，芯片解调数据并还原成声音。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;section-3&#34;&gt;2. 无线通信绕不开的麻烦：干扰&lt;/h2&gt;
&lt;p&gt;常见两种干扰类型：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;同频干扰&lt;/strong&gt; Wi-Fi、蓝牙鼠标都在用 2.4 GHz，像多辆快递车挤同一条路。一旦有人开大功率 Wi-Fi，旁边的蓝牙键盘就会延迟。解决办法是让蓝牙跳频，类似换车道。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;环境干扰&lt;/strong&gt; 金属、墙体会衰减信号；厚衣物、人体遮挡都会减弱电磁波；旁边的蓝牙音箱可能会“滋滋”响。&lt;/li&gt;
&lt;/ol&gt;
&lt;hr&gt;
&lt;h2 id=&#34;section-4&#34;&gt;3. 蓝牙的抗干扰技术&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;自适应跳频（AFH）&lt;/strong&gt; 蓝牙在 2.4 GHz 频段的 79 个子信道里高速跳频，每秒最多跳 1600 次。检测到某个频道被占用，就换到空闲频道，降低碰撞概率。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;纠错编码（FEC）&lt;/strong&gt; 发送时附加冗余信息，即使部分数据受干扰被破坏，也能用冗余位恢复原数据，保证语音、音乐的连续性。&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h2 id=&#34;section-5&#34;&gt;4. 常见无线技术对比&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;技术&lt;/th&gt;
					&lt;th&gt;典型用途&lt;/th&gt;
					&lt;th&gt;特点与蓝牙对比&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;蓝牙&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;耳机、音箱、手表、键鼠&lt;/td&gt;
					&lt;td&gt;功耗低、延迟小、距离短（约 10 米），适合随身设备&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;Wi-Fi&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;上网、智能家居联网&lt;/td&gt;
					&lt;td&gt;速率高、覆盖远，但功耗大，不适合小电池设备&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;LoRa / NB-IoT&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;远程传感器、智慧城市场景&lt;/td&gt;
					&lt;td&gt;覆盖远、功耗低，但速率慢，延迟大，不适合音视频&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&#34;section-6&#34;&gt;5. 常见蓝牙连接问题排查&lt;/h2&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;现象&lt;/th&gt;
					&lt;th&gt;可能原因&lt;/th&gt;
					&lt;th&gt;建议处理&lt;/th&gt;
			&lt;/tr&gt;
	&lt;/thead&gt;
	&lt;tbody&gt;
			&lt;tr&gt;
					&lt;td&gt;蓝牙耳机偶尔卡顿&lt;/td&gt;
					&lt;td&gt;Wi-Fi 同频干扰&lt;/td&gt;
					&lt;td&gt;远离路由器或尝试重连&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;穿墙后信号大幅衰减&lt;/td&gt;
					&lt;td&gt;墙体、金属屏蔽电磁波&lt;/td&gt;
					&lt;td&gt;尽量保持直线距离，避免多层阻挡&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;口袋里手机连接手表不稳定&lt;/td&gt;
					&lt;td&gt;人体吸收 2.4 GHz 信号&lt;/td&gt;
					&lt;td&gt;手机放包里或手表靠近手机&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;微波炉一开蓝牙噪音变大&lt;/td&gt;
					&lt;td&gt;微波炉辐射同频信号&lt;/td&gt;
					&lt;td&gt;避免同时使用或保持距离&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr&gt;
&lt;h2 id=&#34;section-7&#34;&gt;6. 总结&lt;/h2&gt;
&lt;p&gt;无线通信的核心是“调制 + 电磁波传输 + 解调”。蓝牙之所以适合日常设备，是因为它在功耗、抗干扰和延迟之间做到了平衡。如果遇到连接问题，多半是干扰或遮挡导致。&lt;/p&gt;</description>
    </item>
    <item>
      <title>LE audio介绍</title>
      <link>https://btio.cn/posts/2025/11/07/le-audio%E4%BB%8B%E7%BB%8D/</link>
      <pubDate>Fri, 07 Nov 2025 00:15:34 +0800</pubDate>
      <guid>https://btio.cn/posts/2025/11/07/le-audio%E4%BB%8B%E7%BB%8D/</guid>
      <description>&lt;h2 id=&#34;section-1&#34;&gt;LE audio介绍&lt;/h2&gt;
&lt;p&gt;LE Audio是它全称是Low Energy Audio（低功耗音频）&lt;/p&gt;
&lt;p&gt;是蓝牙技术联盟在5.2核心规范里引入的全新，低功耗音频技术标准&lt;/p&gt;
&lt;p&gt;在低功耗、多设备连接和音频共享上实现了超大突破！&lt;/p&gt;
&lt;h2 id=&#34;section-2&#34;&gt;LC3编解码器&lt;/h2&gt;
&lt;p&gt;全新的音频编解码器LC3,是LE audio的灵魂所在，&lt;/p&gt;
&lt;p&gt;和传统SBC编解码器比起来，哪怕数据速率更低，也能提供相同甚至更好的音质。&lt;/p&gt;
&lt;p&gt;不管是日常听歌还是打电话，都能在省功耗的同时稳稳保住音质。&lt;/p&gt;
&lt;h2 id=&#34;section-3&#34;&gt;多流音频技术&lt;/h2&gt;
&lt;p&gt;多流音频是LE audio的另一种优势！以前耳机主副耳要转发信号，现在智能手机等源设备能独立同步给两个耳机发多个音频流，直接消除了转发环节。 带来的好处：连接更可靠、延迟更低、左右声道同步更完美！&lt;/p&gt;
&lt;p&gt;比如听歌时来电话，不用断开音乐，能无缝切到通话，挂完电话又自动切回音乐，丝滑不卡顿。&lt;/p&gt;
&lt;h2 id=&#34;section-4&#34;&gt;广播音频功能&lt;/h2&gt;
&lt;p&gt;广播音频功能是LE Audio最具有革命性的功能，直接开启了音频共享的新时代！蓝牙联盟将其品牌化为 Auracast™。 它允许一个音频源设备（比如手机）能以发射器身份，把一个音频流广播给附近无数个接收设备（比如不同品牌的耳机，只要支持LE Audio就能订阅，Auracast支持跨品牌设备接收） 比如：大家可以用不同的耳机听同一个音频，可以是音乐，电影，广播。&lt;/p&gt;
&lt;h2 id=&#34;section-5&#34;&gt;总结：LE Audio为啥是未来趋势？&lt;/h2&gt;
&lt;p&gt;简单说就是三个字：长！高！稳！ 更长的续航，更高的音质、更稳定的连接，现在支持LE Audio的设备越来越多，妥妥的未来蓝牙音频主流方向。 新手宝子如果想了解蓝牙音频新技术，LE Audio一定要重点关注！收藏这篇，随时回看。&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;原文：&lt;a href=&#34;https://blog.csdn.net/qq_56070244/article/details/154504131&#34;&gt;CSDN · LE audio介绍&lt;/a&gt;
&lt;/p&gt;</description>
    </item>
    <item>
      <title>蓝牙启蒙认知</title>
      <link>https://btio.cn/posts/2025/10/14/%E8%93%9D%E7%89%99%E5%90%AF%E8%92%99%E8%AE%A4%E7%9F%A5/</link>
      <pubDate>Tue, 14 Oct 2025 19:29:36 +0800</pubDate>
      <guid>https://btio.cn/posts/2025/10/14/%E8%93%9D%E7%89%99%E5%90%AF%E8%92%99%E8%AE%A4%E7%9F%A5/</guid>
      <description>&lt;h2 id=&#34;section-1&#34;&gt;蓝牙入门知识&lt;/h2&gt;
&lt;h3 id=&#34;section-2&#34;&gt;一、蓝牙名字的由来&lt;/h3&gt;
&lt;p&gt;        蓝牙名字,来自1000年前丹麦国王&amp;quot;哈拉尔德·蓝牙&amp;quot;的名字,因为这位国王统一了丹麦和挪威的部落。而蓝牙技术则统一了无线通信标准。&lt;/p&gt;
&lt;h3 id=&#34;section-3&#34;&gt;二、蓝牙解决了什么问题&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;代替有线连接：告别数据线的束缚&lt;/li&gt;
&lt;li&gt;设备互联互通：不同设备也能通信（统一标准）&lt;/li&gt;
&lt;li&gt;低成本低功耗：比wifi省钱，比红外线灵活&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;蓝牙让短距离无线连接变得简单，便宜，省电。&lt;/p&gt;
&lt;h3 id=&#34;section-4&#34;&gt;三、蓝牙是如何工作的&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;发现（Discovery）:搜索附近的蓝牙设备&lt;/li&gt;
&lt;li&gt;配对（Paring）:首次建立信任，交换秘钥&lt;/li&gt;
&lt;li&gt;连接（Connection）:正式通信，传输数据&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;技术层面：&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;跳频，采用2.4Ghz 频段，这个频段很多设备。为了不被干扰，蓝牙采用了跳频技术，所以不会被窃听或干扰。&lt;/li&gt;
&lt;li&gt;握手，设备首次建立信任，交换密钥，验证双方的身份，验证通过后，就能传输数据。&lt;/li&gt;
&lt;li&gt;蓝牙传输数据，蓝牙传输数据就像是寄快递，会把大文件切成多个小包（经典蓝牙单包最多339字节，BLE单包最多251字节），每个包都贴上“收件人地址”和“顺序编号”，通过无线电波“快递”过去，对方收到后按编号重新拼装。&lt;/li&gt;
&lt;li&gt;连接稳定性，当距离太远（一般有效范围10~100米，取决于蓝牙功率，一般设置为10米左右），障碍物遮挡，电量不足，电磁干扰（wifi,微波炉），发射和接收功率设置，蓝牙版本不兼容，都会影响蓝牙连接的稳定性。&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;补充：蓝牙是如何空气中传输数据的&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;img alt=&#34;正文配图 1&#34; loading=&#34;lazy&#34; src=&#34;https://btio.cn/images/csdn/152378955/image-01.png&#34;&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3 id=&#34;section-5&#34;&gt;四、什么是2.4GHz频段&lt;/h3&gt;
&lt;p&gt;频率范围：2.400-2.4835GHZ&lt;/p&gt;
&lt;p&gt;全球免许可：不需要申请就能用&lt;/p&gt;
&lt;p&gt;穿透力适中：能穿墙但不会太远，10米左右&lt;/p&gt;
&lt;p&gt;注意：2.4Ghz频段很拥挤，WIFI，微波炉，无线鼠标都在用，所以蓝牙必须有抗干扰技术&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;蓝牙为什么不用其他频段？&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;低频段（比如900Mhz）:穿透性强但传输速度慢，天线太大装不进小设备&lt;/p&gt;
&lt;p&gt;        高频段（比如5GHz）:传输速度快但穿透性差，耗电更多&lt;/p&gt;
&lt;p&gt;        2.4Ghz刚好平衡了所有需求，够快，够小，够省电，够穿透&lt;/p&gt;
&lt;h3 id=&#34;section-6&#34;&gt;五、跳频技术原理&lt;/h3&gt;
&lt;p&gt;经典蓝牙把2.4Ghz分成79个信道（每个1Mhz）,频率范围2402~2480，跳频速率固定1600次/秒（每625微秒跳一次，一个时隙625微秒），跳频序列是随机的，只有配对设备才知道。工作原理是提前约定好下一跳的信道，在79个信道中快速切换见面。经典蓝牙没有专门的广播专用信道，数据信道79个都可以用于传输。&lt;/p&gt;
&lt;p&gt;BLE和经典蓝牙不同的点在于，BLE把2.4Ghz分成40个信道（每个2Mhz），跳频速率自适应，有3个广播专用通道，37个数据通道。&lt;/p&gt;
&lt;h3 id=&#34;section-7&#34;&gt;六、为什么蓝牙不会互相干扰&lt;/h3&gt;
&lt;p&gt;跳频序列不同，每个蓝牙设备都在不同的跳频，即使跳到同一信道，时间也是错开的，万一真的碰上，有重传机制。&lt;/p&gt;
&lt;h3 id=&#34;section-8&#34;&gt;七、主设备&amp;amp;从设备&lt;/h3&gt;
&lt;p&gt;主设备（Master）:发起连接，管理网络，控制时钟&lt;/p&gt;
&lt;p&gt;从设备（Slave）：响应连接，被动接收指令&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;举例：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;        手机连蓝牙总是手机主动，耳机被动。这是蓝牙世界的基本规则，所以必须分出老大和小弟，这是蓝牙世界的等级制度。其中，一个当老大（Master），其他当小弟（Slave）,通常是主动发起连接的当老大，老大说了算，小弟负责听指挥。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;责任划分：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;        主设备决定大家按什么顺序跳频，分配谁什么时候可以“说话”，当多个从设备同时要传输数据时，主设备决定谁先传谁后传。&lt;/p&gt;
&lt;p&gt;        从设备必须跟着主设备时钟走，主从设备会定期进行时钟同步，短时间偏差会通过重传机制纠正，只有长时间失去同步才会断连。蓝牙采用时分双工机制，主设备占用偶数时隙，从设备占用奇数时隙，每个时隙为625微秒。&lt;/p&gt;
&lt;p&gt;        分主从是避免混乱，如果设备都平等，谁来决定跳频顺序和分配传输时间。所以必须分主从来进行管理。主从结构让协议变的简单，主设备负责复杂的管理工作，从设备只需听指令就行。主设备下达命令，从设备立即执行，不用讨论。但主从之间有距离限制，距离太远，主设备管不到的地方，从设备就会断连。主从角色在某些情况可以切换，比如在TWS耳机中，耳机组队可以协商谁当主设备，谁当从设备。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;典型例子：&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;        手机=主设备，蓝牙耳机=从设备&lt;/p&gt;
&lt;p&gt;        电脑=主设备，蓝牙鼠标=从设备&lt;/p&gt;
&lt;p&gt;        注意：一个主设备最多连接7个从设备（蓝牙使用3位地址标识从设备，其中000保留，所以实际可用001~111=7个）&lt;/p&gt;
&lt;h3 id=&#34;section-9&#34;&gt;八、微微网概念&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;**核心理解：**微微网是蓝牙世界的基本单位，微微网=1个主设备+最多7个从设备组成的蓝牙小网络。&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;基本规则&lt;/strong&gt;：必须有一个主设备，最多有8个成员，并且保持同一个频率节奏，所有成员必须同步跳频，跟着主设备的节拍走。&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;：主设备分配时隙，每个从设备按顺序说话，每0.625毫秒为一个时间片。&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-text&#34; data-lang=&#34;text&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;时间轴（每个时隙625微秒）：
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;0    1    2    3    4    5    6    7
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;|____|____|____|____|____|____|____|
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 主   从1  主   从2  主   从3  主   从1
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;规则：
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- 偶数时隙：主设备发送
&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;- 奇数时隙：从设备发送
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;strong&gt;为什么叫微微网？&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
    <item>
      <title>01-蓝牙协议栈介绍</title>
      <link>https://btio.cn/posts/2025/03/19/01-%E8%93%9D%E7%89%99%E5%8D%8F%E8%AE%AE%E6%A0%88%E4%BB%8B%E7%BB%8D/</link>
      <pubDate>Wed, 19 Mar 2025 01:41:41 +0800</pubDate>
      <guid>https://btio.cn/posts/2025/03/19/01-%E8%93%9D%E7%89%99%E5%8D%8F%E8%AE%AE%E6%A0%88%E4%BB%8B%E7%BB%8D/</guid>
      <description>&lt;h2 id=&#34;section-1&#34;&gt;01 蓝牙入门-蓝牙协议栈介绍&lt;/h2&gt;
&lt;h3 id=&#34;section-2&#34;&gt;一、蓝牙类型&lt;/h3&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;特性&lt;/th&gt;
					&lt;th&gt;经典蓝牙（BR,EDR)&lt;/th&gt;
					&lt;th&gt;低功耗蓝牙(BLE)&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;Basic Rate / Enhanced Data Rate&lt;/td&gt;
					&lt;td&gt;Bluetooth Low Energy&lt;/td&gt;
					&lt;td&gt;经典蓝牙在嵌入式领域基本被放弃使用，现在着重使用低功耗蓝牙&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;主要用途&lt;/td&gt;
					&lt;td&gt;音频传输&lt;/td&gt;
					&lt;td&gt;低功耗设备&lt;/td&gt;
					&lt;td&gt;经典蓝牙适合大数据传输，BLE适合小数据、低功耗场景&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;传输速度&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;1-3 Mbps&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;1 Mbps&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;功耗&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;高&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;极低&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;BLE的功耗是经典蓝牙的1/10到1/100，适合电池供电设备&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;连接时间&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;较长&lt;/strong&gt;（通常需要几秒）&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;极短&lt;/strong&gt;（毫秒级）&lt;/td&gt;
					&lt;td&gt;BLE连接快，适合频繁连接和断开的场景&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;兼容性&lt;/td&gt;
					&lt;td&gt;仅支持经典蓝牙&lt;/td&gt;
					&lt;td&gt;仅支持BLE的蓝牙&lt;/td&gt;
					&lt;td&gt;双模蓝牙设备可以同时支持经典蓝牙和BLE，兼容性更强&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;ul&gt;
&lt;li&gt;这两种协议都包括 搜索管理，连接管理等机制，但他们底层是相互独立，不能互通的技术&lt;/li&gt;
&lt;li&gt;厂家如果只实现了一种，那么只能与同样实现该技术的设备互通，如果厂家需要所有的蓝牙设备互通，那么就必须同时实现两种技术，而不去管是否真的需要&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&#34;section-3&#34;&gt;二、方案介绍&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;三种方案对比：&lt;/strong&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;table&gt;
	&lt;thead&gt;
			&lt;tr&gt;
					&lt;th&gt;&lt;strong&gt;方案&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;单芯片方案&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;蓝牙+MCU方案&lt;/strong&gt;&lt;/th&gt;
					&lt;th&gt;&lt;strong&gt;Host+Controller方案&lt;/strong&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;/td&gt;
					&lt;td&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;td&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;strong&gt;低&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;中等&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;高&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;成本&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;低&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;中等&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;高&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;功耗&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;低&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;中等&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;&lt;strong&gt;高&lt;/strong&gt;&lt;/td&gt;
			&lt;/tr&gt;
			&lt;tr&gt;
					&lt;td&gt;&lt;strong&gt;蓝牙协议栈位置&lt;/strong&gt;&lt;/td&gt;
					&lt;td&gt;集成在单芯片中&lt;/td&gt;
					&lt;td&gt;蓝牙芯片负责通信，MCU负责逻辑处理&lt;/td&gt;
					&lt;td&gt;蓝牙协议栈在主芯片中，蓝牙芯片负责底层通信&lt;/td&gt;
			&lt;/tr&gt;
	&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3 id=&#34;section-4&#34;&gt;三、蓝牙协议栈&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;HFP&lt;/strong&gt;：接电话、挂电话。 【蓝牙电话协议】&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A2DP&lt;/strong&gt;：听音乐。 【蓝牙音频传输协议】&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AVRCP&lt;/strong&gt;：切歌、调音量。 【蓝牙音视频远程控制协议】&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;PBAP&lt;/strong&gt;：同步联系人。 【蓝牙电话本访问协议】&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;MAP&lt;/strong&gt;：查看短信。 【蓝牙短信访问协议】&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;蓝牙协议的简化架构图&lt;/strong&gt;&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
