<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>天翔的博客</title>
        <link>https://blog.tnxg.moe</link>
        <description>明日尚未到来，希望凝于心上</description>
        <lastBuildDate>Fri, 31 Jul 2026 07:09:30 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>zh-CN</language>
        <image>
            <title>天翔的博客</title>
            <url>https://blog.tnxg.moe/avatar.png</url>
            <link>https://blog.tnxg.moe</link>
        </image>
        <copyright>All rights reserved 2026, Lee</copyright>
        <category>默认</category>
        <item>
            <title><![CDATA[Obsidian与AI Agent项目协作使用指南]]></title>
            <link>https://blog.tnxg.moe/posts/default/obsidian-ai-agent</link>
            <guid isPermaLink="false">obsidian-ai-agent</guid>
            <pubDate>Fri, 31 Jul 2026 07:09:30 GMT</pubDate>
            <description><![CDATA[
# Obsidian 与 AI Agent 项目协作使用指南

## 一、核心定位

最有效的用法，是把 Obsidian 当作“项目状态和决策数据库”，而不是保存所有聊天记录。

- Git 保存“代码怎么变了”。
- Obsidian 保存“为什么这样改、当前做到哪、验证到哪、下一步是什么”。
- AI Agent 负责读取相关项目记忆、检查真实代码、执行任务，再把稳定成果沉淀回 Obsid]]></description>
            <content:encoded><![CDATA[
# Obsidian 与 AI Agent 项目协作使用指南

## 一、核心定位

最有效的用法，是把 Obsidian 当作“项目状态和决策数据库”，而不是保存所有聊天记录。

- Git 保存“代码怎么变了”。
- Obsidian 保存“为什么这样改、当前做到哪、验证到哪、下一步是什么”。
- AI Agent 负责读取相关项目记忆、检查真实代码、执行任务，再把稳定成果沉淀回 Obsidian。

本地 Vault 路径：

```text
C:\D\Obsidian Vault\Local Vault
```

## 二、新项目启动

开始新项目时，可以对 AI Agent 说：

> 新项目名称是 XXX，仓库路径是 XXX。先读取 Obsidian 的使用规则和用户偏好，再检查项目目录，为它建立项目沉淀。当前只做项目建档，不修改代码。

建议建立以下结构：

```text
AI长期记忆/项目/项目名/
├── 项目名.md
├── 里程碑/
├── 功能分支/
├── 技术决策/
└── 问题记录/
```

主项目笔记记录：

- 项目目标和非目标
- 仓库路径和权威源码目录
- 软硬件结构
- 工具链、编码和构建规则
- 引脚、通信接口、寄存器等关键入口
- 当前阶段和下一步
- 验证方式
- 已知风险

项目开始时不必写得过满，先建立能够持续维护的骨架。

## 三、平时开发

### 任务开始

每次开始较大的任务时说：

> 先读取 Obsidian 中 XXX 项目的项目笔记、当前状态和相关已确认结论，再检查真实代码。不要扫描无关项目。

### 任务结束

任务完成后说：

> 把这次可复用的结论沉淀到 XXX 项目。记录修改文件、关键决策、验证状态和未完成事项，不保存聊天流水账。

建议只沉淀以下信息：

- 已确认的硬件行为
- 寄存器、协议和数据格式
- 重要架构决策及原因
- 已完成能力
- 失败方案和回退原因
- 编译、测试、运行和硬件验证结果
- 下次继续工作的准确入口

临时日志、截图说明和尚未确认的猜测先放入 `AI收件箱`。确认后再进入项目笔记或“已确认结论”。

## 四、项目达到里程碑

例如固件通信打通、上位机首版完成、硬件首次联调成功时说：

> XXX 项目达到 M1 里程碑。根据代码、Git 状态和测试结果创建里程碑记录，并更新项目主页。明确哪些已经完成，哪些只是源码完成，哪些已经硬件验证。

建议生成：

```text
里程碑/2026-07-20-M1-通信打通.md
```

里程碑笔记包含：

- 里程碑目标
- 已完成功能
- 关键提交或版本
- 协议、引脚和数据结构变化
- 验证环境和结果
- 尚未解决的问题
- 下一里程碑入口

里程碑是可以恢复项目上下文的“存档点”。几个月后重新打开，只读这一页就应能知道当时的真实状态。

## 五、开启新功能测试分支

创建分支后说：

> XXX 项目开启功能测试分支 `feature/xxx`。记录基础分支、起始提交、目标、允许修改范围、禁止覆盖的现有修改、测试矩阵和退出条件。

建议创建：

```text
功能分支/feature-xxx.md
```

分支笔记重点记录：

- 分支名和基础提交
- 为什么创建该分支
- 假设和预期结果
- 允许修改的模块
- 当前工作区已有修改
- 测试用例和测试环境
- 成功与失败退出条件
- 最终处理方式：合并、保留或废弃

开发期间可以说：

> 更新 `feature/xxx` 的测试记录。测试 1 已通过，测试 2 只有编译验证，测试 3 硬件失败。不要把失败项写成已完成。

分支结束时说：

> 总结这个功能分支的最终结果。把稳定结论提升到项目主页和“已确认结论”，失败方案保留在分支记录中。

## 六、项目结项

结项时说：

> 对 XXX 项目执行结项沉淀。检查项目笔记、Git 状态、文档和验证记录，生成结项总结。不要把未完成的硬件验证写成已完成。

结项笔记应包含：

- 最终交付物
- 最终版本、分支和提交
- 系统结构
- 核心技术结论
- 编译、测试和硬件验证情况
- 已知限制
- 遗留问题
- 维护和恢复方法
- 关键文档入口

随后将项目主页状态改为：

```yaml
状态: 已结项
结项日期: 2026-XX-XX
```

可复用结论进入 `已确认结论.md`，过程性内容保留在项目目录，不必全部塞进总索引。

## 七、推荐的日常节奏

### 每次任务开始

> 先读取 Obsidian 中 XXX 项目的相关记忆，再查看当前代码和 Git 状态。

### 每次任务结束

> 更新 XXX 项目的当前状态，只沉淀稳定结论、验证结果、失败经验和下一步入口。

### 每周或每个开发阶段结束

> 整理 XXX 项目的收件箱和近期记录，合并重复结论，标记失效内容，但不要删除原始证据。

### 硬件实测推翻原结论

> 以本次台架结果为准，更新旧结论为“已废弃”，说明原因并链接到新结论，不要直接抹掉旧记录。

## 八、高效使用原则

1. Git 保存代码变化，Obsidian 保存决策、上下文和验证状态。
2. 不记录所有聊天，只记录未来可能再次使用的信息。
3. 所有结果注明验证层级：源码、编译、测试、运行、硬件实测。
4. 新任务只读取相关项目，不无目的地扫描整个 Vault。
5. 旧结论失效时标记并链接新结论，不直接删除历史。
6. 不将密码、验证码、API 密钥等秘密信息写入 Obsidian。
7. 功能测试分支先记录目标和退出条件，避免测试过程中不断扩大范围。
8. 项目主页保持简洁，详细过程分别放入里程碑、功能分支和问题记录。
9. 硬件实测优先于通用惯例和早期推测。
10. 开始修改前先检查 Git 状态，保护用户已有的未提交内容。

## 九、新对话如何唤起长期记忆

新开的 Codex 任务不会天然知道需要使用哪个 Vault，最好明确说：

> 使用 `C:\D\Obsidian Vault\Local Vault` 作为长期记忆，先读取相关项目笔记。

最省事的固定用语是：

> 先读项目记忆再工作，结束后把稳定成果沉淀回 Obsidian。

如果只希望读取、不希望写入，可以说：

> 本次只读取 Obsidian 项目记忆，不修改任何笔记。

如果需要写入，可以说：

> 本次允许更新 XXX 项目的项目主页、里程碑和已确认结论，不修改其他项目。

## 十、常用提示词速查

### 建立项目

> 读取 Obsidian 使用规则和用户偏好，为 XXX 建立项目沉淀，只建档不改代码。

### 开始任务

> 先读取 XXX 项目的相关记忆，再检查代码和 Git 状态，然后开始任务。

### 完成任务

> 将本次稳定成果沉淀到 XXX，记录依据、验证状态、失败方案和下一步。

### 建立里程碑

> XXX 达到 M1，创建里程碑记录并更新项目主页，区分源码、编译、运行和硬件验证。

### 建立功能分支记录

> 为分支 `feature/xxx` 建立测试记录，写明基础提交、范围、测试矩阵和退出条件。

### 结束功能分支

> 总结 `feature/xxx`，稳定结论写回项目主页，失败尝试保留在分支记录。

### 项目结项

> 对 XXX 执行结项沉淀，核对 Git、文档和测试，生成最终交付、限制和维护入口。

### 整理收件箱

> 整理 XXX 相关的 AI 收件箱内容，保留来源，待验证内容不要提升为已确认结论。

]]></content:encoded>
            <author>admin@leegdhk.org (Lee)</author>
        </item>
        <item>
            <title><![CDATA[从“能编译”到“能控住”：STM32F103 风扇控制器的 Keil 移植与实机调试]]></title>
            <link>https://blog.tnxg.moe/posts/default/stm32f103-fan-controller-keil-pwm-tach-oled</link>
            <guid isPermaLink="false">stm32f103-fan-controller-keil-pwm-tach-oled</guid>
            <pubDate>Wed, 15 Jul 2026 05:53:03 GMT</pubDate>
            <description><![CDATA[将基于 Astra 风格 OLED UI 的风扇控制器移植到 STM32F103C8T6 与 Keil MDK，并记录 PWM 极性、测速接线、10k 上拉和小比例进度条等实机调试结论。]]></description>
            <content:encoded><![CDATA[这次 Fan Speed 工程的目标并不复杂：用 STM32F103C8T6 驱动一块 128x64 SSD1306 OLED，通过旋转编码器和按键调节风扇占空比，同时采集测速信号并在屏幕上显示转速。

真正花时间的部分，不是把几个外设初始化出来，而是把原有工程变成一个可以直接在 Keil 中使用的项目，并让代码最终服从真实硬件，而不是服从“常见接线”的想象。

## 硬件与功能

核心硬件包括：

- STM32F103C8T6 最小系统板
- SSD1306 128x64 OLED，IIC 接口
- 旋转编码器与两个按键
- NMB-MAT 2415KL-04W-B86 四线风扇
- PB8 输出 PWM 控制信号
- PA6 采集风扇测速信号
- PWM 控制线上使用 10k 电阻上拉到 3.3V

界面保留了 Astra 风格的过渡动画和小屏交互，同时加入占空比、进度条和 RPM 显示。

## 从 CMake 工程迁移到 Keil

原工程以 CMake 组织，但实际开发环境更适合 Keil MDK，因此我在 `MDK-ARM` 目录下补齐了完整工程：

- `FanController.uvprojx`：Keil 工程配置
- `STM32F103C8T6.sct`：ARMCC 5 分散加载文件
- `startup_stm32f103c8t6.s`：启动文件
- `platform_interrupts.c`：必要的中断入口

验证工具链为 Keil MDK 5.33 和 ARM Compiler 5.06u7。最终工程能够完成全量编译和链接，并生成 `FanController.hex` 与 `FanController.bin`。

迁移中最容易被忽略的是 SysTick。工程即使能够链接，如果 `SysTick_Handler` 没有调用 `HAL_IncTick()`，HAL 的延时和超时逻辑仍会停住：

```c
void SysTick_Handler(void)
{
    HAL_IncTick();
}
```

另一个问题来自 U8G2：当前源码中缺少 SSD1306 全缓冲 IIC 初始化函数 `u8g2_Setup_ssd1306_i2c_128x64_noname_f`。补齐对应 setup 后，显示部分才完成最终链接。

这次移植采用了比较稳妥的验证顺序：先编译业务代码，再分批编译 U8G2，最后做完整链接。这样可以把启动文件、库函数和业务代码的问题分开定位。

## 接线不能只看颜色

最初按照常见四线风扇的颜色约定判断 PWM 和测速线，结果与实机现象不一致。最终根据台架测试确认，这一只 2415KL-04W-B86 的实际接法是：

| MCU 引脚 | 风扇线 | 功能 |
| --- | --- | --- |
| PB8 / TIM4_CH3 | 黄色线 | PWM 控制 |
| PA6 / TIM3_CH1 | 蓝色线 | 转速脉冲输入 |

这里的结论只针对本次使用的风扇和实测接线，不应直接套用到其他四线风扇。颜色可以作为线索，但最终应由型号资料、示波器波形和实际响应共同确认。

PWM 控制线使用开漏思路时，曾尝试省掉外部上拉，但该风扇的控制变得不可靠。最终保留 10k 电阻上拉到 3.3V。减少外围器件当然有吸引力，不过已经被实机证明必要的器件，不值得为了“更简洁”强行删除。

## PWM 极性与线性调节

实测后将 PWM 极性确定为非反相：

```c
#define FAN_PWM_ACTIVE_LOW 0U
```

这样界面中的百分比越高，输出占空比越高，风扇转速也随之上升。编码器每次调整 5%，在 0% 到 100% 之间形成清晰的离散档位，比过细的步进更适合这块小屏和旋钮的交互。

界面设置值直接映射到 PWM，占空比不再经过额外的非线性变换。这样做也让调试更直观：显示 40% 时，就能明确知道定时器正在输出约 40% 的命令。

## 测速信号与快速校验

PA6 使用 TIM3_CH1 采集测速脉冲。代码默认风扇每转输出 2 个脉冲，因此转速和输入频率的关系为：

```text
RPM = 频率(Hz) x 60 / 2
```

例如 4000 RPM 对应的测速频率大约是 133 Hz。这个换算很适合现场快速判断：当 OLED 显示值、示波器频率和实际风声互相矛盾时，可以先用它检查测速链路是否合理。

为了区分真实转速和输入噪声，程序还保留了原始周期、滤波后周期以及被拒绝脉冲数等调试变量。相比只盯着最终 RPM，这些中间量更容易判断问题究竟来自 PWM 命令、接线、上拉还是测速干扰。

## 128x64 界面的边界问题

小屏界面最容易在极端值上出错。进度条在 2% 等很小数值时，圆角矩形的最小宽度会导致横向溢出；RPM 文本靠近右边缘时，也可能留下看起来像竖线的残影。

最终的处理方式是：

- 进度条宽度很小时改用普通实心矩形，不强行绘制圆角
- 对填充宽度做边界保护
- RPM 文本按实际字符宽度右对齐
- 优先检查 0%、2%、5% 和 100% 等边界画面

这类问题在中间占空比下往往完全看不出来，因此 OLED 界面验证不能只停留在 50% 这样的“正常画面”。

## 最终结果

最终工程完成了以下内容：

- 可直接使用的 Keil MDK 工程
- SSD1306 IIC 全缓冲显示
- 旋转编码器 5% 档位调节
- PB8 非反相 PWM 输出
- PA6 输入捕获测速
- 面向噪声排查的测速调试变量
- 适配极小百分比和右边缘文本的 OLED 界面

编译后的固件 ROM 约 16.77KB，RAM 约 2.50KB，适合 STM32F103C8T6 的资源规模。

这次调试最重要的经验，是让软件模型持续接受硬件反馈：先建立一个能编译、能链接的工程基线，再用真实波形和现象逐项修正接线、极性、滤波和界面。对于嵌入式项目，“常见做法”只能提供起点，实机结果才是最后的约束。

![风扇控制器实机调试画面](https://leegdhk.org/api/static/uploads/images/clipboard-1784094674359.png)

界面源代码参考：[AstraThreshold/oled-ui-astra](https://github.com/AstraThreshold/oled-ui-astra)]]></content:encoded>
            <author>admin@leegdhk.org (Lee)</author>
            <category>STM32F103</category>
            <category>Keil</category>
            <category>OLED</category>
            <category>风扇控制</category>
        </item>
        <item>
            <title><![CDATA[asd]]></title>
            <link>https://blog.tnxg.moe/notes/1</link>
            <guid isPermaLink="false">note-1</guid>
            <pubDate>Mon, 25 May 2026 02:35:00 GMT</pubDate>
            <description><![CDATA[sda sd asfafds

asda  ]]></description>
            <content:encoded><![CDATA[sda sd asfafds

asda  ]]></content:encoded>
            <author>admin@leegdhk.org (Lee)</author>
        </item>
    </channel>
</rss>