
做键盘这件事一开始我是拒绝的。市面上客制化键盘主控从几块钱到几十块钱的都有MCU换壳、固件刷好、到手即用何必自己画板子写代码直到前年我手头攒了十几片STM32F103C8T6最小系统板都是买别的模块顺手囤的单价压到三块出头我突然意识到为什么不能拿这颗芯片自己搓一把键盘STM32F103C8T6的USB Device、37个可用GPIO、20KB SRAM硬件底子完全够用。而键盘DIY这条链路——电路设计、PCB布局、固件烧录——刚好是把嵌入式基本功串起来的绝佳练手项目。这篇文章适合两类人一是想从跑马灯进阶到完整USB外设项目的嵌入式学习者二是想自己做一把客制化键盘、又不想被现成方案绑住的DIY玩家。我会从选型逻辑讲起把最小系统电路、按键矩阵、Type-C供电、PCB布局、CubeMX配置、WS2812灯效直到固件烧录完整走一遍每个环节都会提到我实际踩过的坑。不是那种照着抄就行的教程而是告诉你为什么这么画、为什么这么写、出了问题从哪里查。1. 为什么放着现成的键盘主控不用偏要折腾STM32F103C8T61.1 成本与供货的现实问题先说钱。2022年以后STM32F103C8T6的散片价格一度被炒到二十几块这时候自己DIY键盘确实不划算。但现在价格已经回落到正常区间国产替代型号比如GD32F103C8T6、APM32F103C8T6单价普遍在2到4元比专门的键盘主控芯片比如ATmega32U4便宜不少。更关键的是最小系统板遍地都是几块钱一片还带调试器底座新手完全可以从买现成的最小系统板开始跳过焊接LQFP48封装这一步。键盘这种项目对主控的消耗其实很低扫描矩阵用的是GPIOUSB HID是协议栈的事灯效是DMA的事。F103C8T6的64KB Flash实际出厂很多是128KB这个后面细说和20KB SRAM跑一套键盘固件加上灯效缓冲绰绰有余。1.2 这颗芯片做键盘的硬件底子盘点一下F103C8T6做键盘主控的资源全都在刀刃上USB 2.0 FS Device接口支持HID类设备不需要外部PHY芯片37个GPIO标准87键键盘用6行×17列的矩阵也就23个IO还有富余3个通用定时器加1个高级定时器其中一个可以输出PWMDMA多个ADC通道如果有旋钮、模拟摇杆之类的扩展需求也能接3个USART、2个SPI、2个I2C以后想加蓝牙模块、旋钮编码器、OLED屏幕都有接口最方便的是F103的USB_DP引脚的1.5k上拉电阻是芯片内部集成的外部电路只需要把D/D-引出来接Type-C座就行比很多要自己外接上拉电阻的方案省事。1.3 和其他主流键盘主控的横向对比主控方案单价散片参考FlashUSB外设开发难度备注STM32F103C8T63-8元64KB多为128KBFS Device中生态最全资料最多ATmega32U415-30元32KBFS Device低QMK原生支持但贵RP20405-10元2MB外部FlashFS Device低目前客制化圈热门需要外部FlashESP32-S38-15元8MB外部FlashFS Device中高带蓝牙WiFi功耗高GD32F103C8T62-5元64KB部分128KBFS Device中国产替代USB兼容性有差异表格里的结论很直接F103C8T6不是性能最强的但它是综合成本最低、资料最多、踩坑案例最丰富的选择。尤其对于学习目的遇到问题时能搜到的解决办法数量比其他方案多了一个量级。RP2040虽然也便宜但需要的开发环境偏Python/C SDK而且外部Flash方案对新手做键盘来说反而多了一层需要理解的东西。另外一个现实考量STM32CubeMX生成工程的速度太快了从零到能跑起来的键盘固件一个晚上就能完成。这一点在后面固件章节会展开。2. 电路设计最小系统、按键矩阵与Type-C供电一次讲透2.1 最小系统电路图的核心组成很多新手拿到F103C8T6最小系统板之后不知道板子上哪些东西是必需的。如果自己画PCB最小系统就这几样8MHz主晶振Y1两端分别接20pF左右的负载电容到GND。不要省这个晶振虽然F103内部有HSI但USB外设要求时钟精度在0.25%以内内部RC达不到必须靠外部晶振提供精确的48MHz USB时钟32.768kHz副晶振可选键盘这种应用基本不需要RTC可以省掉复位电路NRST引脚接10kΩ上拉到3.3V并联100nF电容到GND。这样能保证上电复位可靠也方便外部调试器复位芯片Boot0引脚下拉10kΩ到GNDBoot1随便接。确保从Flash启动否则上电容易跑进系统存储器里的bootloader电源去耦每个VDD引脚旁边放一个100nF陶瓷电容VDDA引脚加一个1μF10nF的组合VSSA直接接地。这是数据手册明确要求的别偷懒F103的LQFP48封装有PB2引脚的Boot1功能如果不当普通IO用也是下拉处理。这些细节在官方数据手册的最小系统参考电路里都有第一版可以直接抄。2.2 按键矩阵扫描原理与二极管方向键盘按键多不可能每个按键独占一个GPIO87键就需要87个IOF103总共才37个可用。所以用矩阵扫描行线和列线交叉每个交叉点放一个按键。以6行×17列为例只需要61723个IO。扫描逻辑是逐行输出低电平或逐列读取列线电平或行线检测到低电平说明该位置按键按下。我用的是行输出、列输入方案行线接GPIO推挽输出列线接GPIO上拉输入扫描时每次只把一行拉低其余行输出高组然后读所有列的电平列读到0说明该行该列有按键按下。这里有一个关键点必须给每个按键串联一个二极管。方向是阳极接行线、阴极接列线。原因很简单如果没有二极管同时按下三个键时电流会从被拉低的行经过多个按键流入非扫描的行再从另一列流回来导致鬼键——你只按了三个键系统却认为第四个键也按下了。二极管的单向导电性断了这条回流路径扫描结果就可靠了。市面上键盘用的1N4148小信号二极管单价几分钱一个按键一个87键的成本也就是几块钱。2.3 Type-C接口与供电设计现在的键盘基本都用Type-C口了正反插方便线材也好找。F103作为纯USB Device端接口电路非常简洁CC1和CC2引脚各接一个5.1kΩ下拉电阻到GND这是告诉对端电脑我是设备被动供电VBUS接5V电源输入D、D-直接连F103的PA12和PA11建议在VBUS入口加一个自恢复保险丝500mA的PPTC和TVS管防止热插拔时浪涌打坏主控D/D-上各串一个22Ω电阻可以抑制信号反射提高USB信号质量供电方面键盘主控功耗其实很低MCU核心加矩阵扫描正常工作电流也就30~50mA。用LDO线性稳压器比如AMS1117-3.3、ME6211从5V降到3.3V就行不需要开关电源。但是如果加了背光灯效情况完全不一样。一颗WS2812全亮白光就要60mA3×20mA几十颗灯就是好几安培电流。这时候3.3V路径和5V灯带路径必须分开设计具体在下面说。2.4 灯效供电boost和buck怎么选这是键盘发烧友绕不开的问题。键盘里用到DC-DC的场景无非两个一是给灯带供电二是给主控/其他外设供不同的电压轨。先给一个结论不要用boost电路去推WS2812灯带直接用USB的5V。WS2812本身工作在5VUSB口的5V刚好匹配用一个LDO把5V降成3.3V供主控就够了。这个时候你需要的是Buck降压电路把5V降到3.3V。但键盘主控电流小用LDO效率虽低、发热却可以忽略没必要上Buck。F103主控没有其他需要高电压的模块所以纯键盘项目其实不需要DC-DC。什么时候需要boost如果你做的是便携键盘用单节锂电池3.7V供电要驱动5V灯带那就得加一个boost升压电路从3.7V升到5V。常用的芯片有MT3608、FP6291这类外围就电感、二极管、反馈电阻这几个元件。核心注意点是boost电路的开关节点SW走线要短粗反馈电阻采样点要靠近输出电容不然输出纹波会大灯带会闪。但如果你只是做一把插线的桌面键盘这个复杂度完全可以省掉。2.5 按键模块电路设计时容易忽略的细节不管键盘是不是独立的按键模块本身的电路设计有几个细节直接影响手感稳定性和寿命行线和列线的走线不要和晶振、高频信号线平行长距离走线避免耦合干扰导致误触发上拉电阻列线要靠近MCU引脚放置不要放在矩阵远端否则走线寄生电容会让边沿变缓扫描频率高了可能漏键按键消抖不能只靠软件延时硬件上每根线上放一个100pF到1nF的电容到GND配合软件10~20ms去抖效果最好机械开关的引脚间距是标准的2.54mm很多Cherry MX类轴体还有定位柱画封装的时候务必对齐数据手册的机械图焊完了才发现轴体歪了就晚了3. PCB布局最容易翻车的3个地方晶振、噪声、矩阵走线3.1 晶振与时钟让它远离一切开关节点晶振的布线是新手最容易翻车的点。8MHz晶振如果离MOS管、Buck电感、按键矩阵这些有大电流跳变的地方太近时钟信号会被干扰轻则USB枚举不稳定重则系统跑飞。我第一版键盘PCB就吃过这个亏晶振放在了板子边缘旁边走了一排矩阵列线。表面看电路完全正确但USB插入电脑后经常出现无法识别的USB设备有时候重启十几秒才能枚举成功。排查了很久最后把晶振换到MCU附近、周围重新铺地才解决。正确的做法是晶振和负载电容尽量靠近OSC_IN和OSC_OUT引脚走线不要超过10mm晶振下方不要走其他信号线直接铺铜并且打地孔隔离晶振外壳接地如果有金属外壳的话晶体下面放一个隔离地平面3.2 电源噪声和模拟分区键盘里也有ADC/DAC要注意的事热词里提到的ADC/DAC电路设计规避时钟抖动与电源噪声放在键盘项目里同样成立——别以为没有ADC就能跳过电源设计。键盘的灯效、旋钮编码器、未来要加的麦克风、触摸滑条全都会碰到模拟信号处理。三个要点记下来直接能用第一模拟电源和数字电源要分路径。F103的VDDA引脚不要和VDD共用一个过孔。高噪声的数字电路尤其灯带数据线、晶振输出的电源路径和VDDA路径要分开走最后在输入端汇合。标准做法是VDDA前放一个磁珠或10Ω电阻再并1μF和10nF电容。第二时钟抖动对采样电路的影响往往被低估。如果你在键盘里加了触摸滑条自电容检测方案本质是ADC采样时钟抖动会让采样点漂移读数毛刺大。所以晶振地平面要独立不要和模拟采样电路的参考地混在一起。第三避免电流回流路径交叉。灯带数据线的返回电流和ADC参考电压的返回电流如果走了同一段地线灯效切换瞬间会在ADC参考上产生几十毫伏的跳变。这个问题的本质是接地阻抗解决办法就是把模拟地和数字地单点连接或者用0Ω电阻/磁珠隔开。3.3 按键矩阵走线与过孔矩阵走线多很容易乱但这里恰恰是体现设计功力的地方优先考虑双面板的布局行线走顶层列线走底层交叉处用过孔跳线过孔不要打太多每个按键一个过孔已经是极限多了会增加寄生电容、降低扫描可靠性矩阵信号是中低速数字信号不需要阻抗匹配但要注意同一根线上的过孔不要超过2个否则等效串联电感变大行线和列线的走线尽量均匀不要让某根线绕了很远而旁边的线很短否则矩阵扫描时的边沿延迟不一致高速扫描时会出现按行扫描右半部分键位误触发的情况3.4 我第一版板子的翻车经验第一版PCB做回来焊接完一阵欣喜插上电脑却不识别。我用逻辑分析仪抓了D和D-的信号发现时钟包络完全不对频率偏差明显。这让我怀疑USB时钟有问题。实测晶振两端的波形发现幅度只有0.5V不到。原因是晶振负载电容值选错了——我用了两个30pF而8MHz晶振推荐的负载电容是20pF。电容太大导致振荡幅度不足时钟不稳。这个问题的排查思路值得记下来遇到USB不识别先量晶振再看D/D-波形然后查电源纹波最后才怀疑固件问题。顺序不能反。USB协议栈对时钟要求极其严格晶振波形正常了一半的问题就解决了。还有一个坑是复位电路NRST的10k上拉电阻我一开始没焊结果每次上电都要手动复位才能正常启动。最小系统的每个元件都有它的作用别为了省几个元件跳过复位电路。4. 固件侧的关键决定扫描逻辑、CubeMX配置与FreeRTOS移植4.1 裸机状态机还是上FreeRTOS键盘固件的复杂度介于LED闪烁和多任务系统之间。核心任务就三个扫描矩阵、处理USB HID上报、灯效控制。外加可能的OLED显示、旋钮输入。裸机状态机完全可以胜任但为什么很多人习惯在F103上移植FreeRTOS因为键盘实际上是一个典型的实时事件驱动系统——按键动作是异步的USB上报周期是固定的USB HID默认1ms轮询一次灯效更新是周期性的。三个周期任务混在一起用状态机写也能写但代码会越来越难维护。我的建议是分阶段第一版用裸机状态机跑通全链路等逻辑稳定了再考虑移植FreeRTOS把矩阵扫描、HID上报、灯效控制拆成三个任务。这样你既能理解底层时序又能体会到RTOS带来的代码组织优势。4.2 CubeMX配置步骤与关键参数STM32CubeMX是绕不开的工具配置核心步骤如下1. 选择芯片STM32F103C8Tx勾选RCC高速时钟HSE为Crystal/Ceramic Resonator 2. 时钟树里配置HCLK为72MHz HSE8MHz - PLLM1, PLLN9, PLLP1 - SYSCLK72MHz APB1预分频/2 - APB136MHzUSB需要48MHz来自PLL的Q输出 3. USB使能USB Device模式选Device Only 4. GPIO配置行线设为输出推挽初始高列线设为输入上拉 5. 定时器TIM1用于WS2812PWM模式频率800kHzDMA请求使能 6. 生成工程工具链选MDK-ARMKeil这里容易漏的一个参数是USB时钟。F103的USB模块需要精确的48MHz时钟CubeMX中体现为USB外设的时钟源。默认配置如果PLL没有输出48MHz给USBUSB外设会异常。最简单的办法是直接用CubeMX的时钟树图形界面它会自动计算合法组合不要把时钟树页面里的红色警告忽略掉。4.3 按键矩阵扫描与USB HID上报的代码思路矩阵扫描的伪代码逻辑如下// 行引脚PA0-PA56行列引脚PB0-PB1516列PC131列 // 扫描间隔2ms一次连续检测到同一次按键状态才认为是稳定 #define MATRIX_ROWS 6 #define MATRIX_COLS 17 uint8_t matrix_state[MATRIX_ROWS][MATRIX_COLS]; uint8_t matrix_debounce[MATRIX_ROWS][MATRIX_COLS]; void matrix_scan(void) { for (uint8_t row 0; row MATRIX_ROWS; row) { // 拉低当前行 HAL_GPIO_WritePin(row_gpio[row], GPIO_PIN_RESET); delay_us(5); // 等待电平稳定 for (uint8_t col 0; col MATRIX_COLS; col) { uint8_t pressed (HAL_GPIO_ReadPin(col_gpio[col]) GPIO_PIN_RESET); if (pressed) { if (matrix_debounce[row][col] 10) { matrix_debounce[row][col]; if (matrix_debounce[row][col] 10) { matrix_state[row][col] 1; } } } else { if (matrix_debounce[row][col] 0) { matrix_debounce[row][col]--; if (matrix_debounce[row][col] 0) { matrix_state[row][col] 0; } } } } // 恢复当前行为高 HAL_GPIO_WritePin(row_gpio[row], GPIO_PIN_SET); } }注意去抖逻辑我用的是累加计数而不是固定延时。固定延时去抖会让按键响应延迟10ms而累加计数只在连续检测到变化时才确认状态这样既滤掉了抖动又能保证按下响应速度在2ms以内。USB HID上报的关键是标准键盘报告格式8字节。第0字节是修饰键Ctrl/Shift/Alt/Win第1字节保留后6字节是普通按键的键码。F103的USB库CubeMX生成的USB Device中间件已经封装好HID类的上报接口只需要维护一个按键缓冲uint8_t keyboard_report[8] {0, 0, 0, 0, 0, 0, 0, 0}; // 按下A键keyboard_report[2] 0x04; // 按下B键keyboard_report[3] 0x05; // 更新后调用 USBD_HID_SendReport(hUsbDeviceFS, keyboard_report, 8);一个细节组合键要用修饰键位表示比如CtrlC就是keyboard_report[0] 0x01然后keyboard_report[2]里放C的键码0x06。普通键盘最多同时上报6个按键加上4个修饰键这是USB HID Boot Protocol的限制。4.4 FreeRTOS移植的坑CubeMX里勾选FreeRTOS后需要手动分配三个任务ScanTask2ms周期、HIDReportTask1ms周期或事件触发、LedTask刷新灯效。优先级上HIDReportTask最高ScanTask其次LedTask最低。实际移植时遇到的两个坑第一是HAL_Delay在FreeRTOS里会失效。CubeMX生成的HAL库默认在SysTick中断里维护tick而FreeRTOS接管SysTick后HAL_Delay不再工作。解决办法是勾选CubeMX里的FreeRTOS tickless idle相关的HAL时基设置为TIM6把HAL的HAL_Delay独立出来。否则你会看到代码逻辑完全正确但就是扫描不动作。第二是stack空间不足。每个任务默认的栈大小是128 words对于键盘这种简单任务刚好够但如果你在任务里用了sprintf或者较大的局部数组就会溢出。建议每个任务栈至少256 words同时在FreeRTOSConfig.h里打开堆栈溢出检测。5. PA8的PWMDMA驱动WS2812一个定时器搞定整条灯带5.1 WS2812的时序要求WS2812灯带是单总线协议数据速率800kbps每个像素需要24bit数据G、R、B各8位。时序要求非常严格信号时间说明T0H0.35us ±0.15us0码高电平T0L0.80us ±0.15us0码低电平T1H0.70us ±0.15us1码高电平T1L0.60us ±0.15us1码低电平RESET50us帧间隔信号如果直接用HAL_GPIO_WritePin翻转GPIO来模拟这个时序任何中断打断都会导致信号错误灯带颜色就会闪。这就是为什么WS2812在F103上要用硬件PWMDMA。5.2 PWMDMA的实现原理思路很巧妙让TIM1在PA8引脚输出一个频率为800kHz即1.25us周期的PWM然后通过DMA通道把一个预先准备好的占空比序列逐字节写到TIM1的CCR寄存器里。每个bit的发送就是一个PWM周期占空比高代表1码占空比低代表0码。在72MHz时钟下ARR设置为8990个时钟周期 1.25us0码的CCR可以是28高电平0.39us1码的CCR可以是55高电平0.76us两个都在WS2812的容差范围内。DMA的好处是数据搬移完全不占CPU。你只需要准备一个buffer里面按顺序放好每个bit对应的CCR值DMA会自动把整个帧的数据发给TIM1。60个灯一共60×241440个bit需要1440×22880字节因为是16位CCR寄存器。F103的20KB SRAM完全吃得下这也是为什么我推荐用PA8做灯效数据线——TIM1_CH1的DMA通道是现成的。5.3 核心配置与代码片段CubeMX里的配置TIM1Clock Source 内部时钟Channel1 为 PWM Generation Prescaler0Period89生成800kHz频率 Pulse0初始占空比0 DMA Settings添加TIM1_CH1的DMA请求方向Memory To Peripheral模式Circular或Normal发送一个像素颜色的代码核心逻辑#define LED_NUM 60 #define ARR_VAL 89 uint16_t dma_buffer[LED_NUM * 24 1]; // 把一个像素的GRB颜色转换成PWM占空比序列 void ws2812_set_pixel(uint16_t index, uint8_t red, uint8_t green, uint8_t blue) { uint32_t pixel_data (green 24) | (red 16) | blue; uint16_t *buf dma_buffer[index * 24]; for (uint8_t i 0; i 24; i) { if (pixel_data (1 (23 - i))) { buf[i] 55; // 1码占空比 } else { buf[i] 28; // 0码占空比 } } } // 全部像素填充后启动DMA HAL_TIM_PWM_Start_DMA(htim1, TIM_CHANNEL_1, (uint32_t *)dma_buffer, LED_NUM * 24);注意最后一件事WS2812要求两个数据帧之间有大于50us的RESET信号。在PWMDMA方案里你可以在dma_buffer的最后补一段连续的0占空比CCR0这样帧尾自然出现低电平RESET不需要额外处理。5.4 灯效之外这个方案的扩展空间PWMDMA这套思路不止能驱动WS2812。同样的机制可以做智能门锁/密码锁键盘矩阵键盘加一个LED反馈环按键时灯带闪一下顺便改变配色提示输入状态。我在项目里就试过用同一颗F103C8T6做密码锁键盘固件改一下按键映射加个EEPROM存密码整个项目就转型了旋钮编码器如果你加一个EC11旋钮用另一个定时器的输入捕获模式检测旋转方向就能实现音量旋钮功能OLED菜单屏SPI或I2C接口再加一个定时器做软件I2C时序核心思路是把单次、周期性的波形输出任务交给硬件DMA把CPU解放出来处理真正需要逻辑判断的部分。这个设计思想学会了以后做任何涉及传感器采样、LED驱动、电机PWM的STM32项目都用得上。6. 固件烧录全流程与按真金白银踩出来的坑6.1 烧录电路与Boot模式F103支持SWD和USART1两种烧录方式。键盘PCB上一定要预留SWD 4针接口3.3V、SWDIO、SWCLK、GND。不要只留一堆测试点焊个4pin的排针或FPC座调试方便一百倍。Boot模式只影响串口烧录ISPSWD烧录模式下Boot0脚不重要。但如果用USART1做ISP需要把Boot0拉高烧完再拉低复位。所以在最小系统设计时Boot0没有简单接地而是通过0Ω电阻接到GND方便以后改跳线。6.2 DAPLink的接线与驱动调试器我推荐CMSIS-DAPDAPLink就是帖子热词里那个DAPLink——因为它便宜而且用F103最小系统板就能自己刷一个出来。DAPLink和ST-Link比最大的优势是跨平台Windows/Linux/macOS都免驱免驱指的是Win10以上的系统。接线方式调试器DAPLink输出 键盘SWD接口 3.3V ----------- 3.3V GND ----------- GND SWDIO ----------- SWDIO SWCLK ----------- SWCLK关键细节SWD线要尽量短不要超过20cm。线太长了在高速下载时会遇到时序问题表现为Keil里弹各种Communication error。另外如果DAPLink和目标板各自供电一定要共地——GND不接一切免谈。6.3 Keil/IAR环境下的烧录配置Keil MDK里的配置路径Options for Target - Debug - 选择CMSIS-DAP Debugger - Settings - Flash Download。IAR类似在Project Options里选CMSIS-DAP调试器。几个容易踩的配置点Flash Download里要勾选Reset and Run这样烧完自动复位运行不用手动按复位键编程算法的选择F103C8T6选STM32F10x Med-density Flash64KB不要选成High-density如果有读保护见6.5烧录前需要先Full Chip Erase否则报错6.4 烧录失败排查链路从现象到根因的完整过程这是我实际经历过的最完整的排查链路写出来给各位参考。现象DAPLink接上键盘板Keil点下载报错No target connected或者RDDI-DAP Error。排查逻辑第一步测目标板3.3V电压。如果为0检查LDO输出和电源路径。这里常见的问题是AMS1117的方向焊反或者是PCB上电源线和地线短路第二步测NRST引脚电平。正常应该是3.3V如果为0说明芯片在复位状态查复位电路元件是否虚焊第三步量SWDIO/SWCLK到MCU引脚是否连通。用万用表蜂鸣档量排针到MCU引脚之间阻值很多新手在这步发现SWDIO和SWCLK在PCB上标反了。这是个非常常见的低级错误——原理图里SWDIO画在PA13PCB封装引脚没对应上或者飞线时插反了第四步确认DAPLink驱动正常。设备管理器里能看到DAPLink CMSIS-DAP设备。如果系统里装了ST-Link驱动但没装CMSIS-DAP驱动Keil的调试器列表里就找不到DAPLink第五步如果以上都正常但仍报错用STM32CubeProgrammer的Connect模式测试看能不能读到芯片ID。能读到ID但Keil报错说明Keil的调试设置有问题比如选择了ST-Link而不是CMSIS-DAP排查链路里最反直觉的一步是第五步。我有一次刷写失败硬件全正常折腾半天发现只是Keil的Debugger选错了。每次在论坛看到我板子没坏但就是连不上的帖子八成都是这类设置问题。6.5 读保护与加密让固件不被直接读出来做键盘可能不涉及商业保密但如果你用的是公司项目代码或独立开发的固件还是要考虑加密。F103的读保护RDP分三个级别Level 0无保护SWD完全开放Level 1Flash不可读SWD可连接可擦除后重新烧录Level 2永久保护SWD彻底禁用芯片变砖操作方式STM32CubeProgrammer连接芯片后在Option Bytes选项卡里设置RDP为Level 1。先烧录固件再设置读保护顺序反了就只能先擦除再烧之前的东西全没了。还有一点提醒Level 2一旦设置将永久无法通过调试接口访问芯片包括复位和擦除。除非你有特殊需求否则永远不要设Level 2。另外国产替代芯片的读保护行为细节有时和ST原厂不完全一致用GD32之前最好先确认方案可行性。6.6 Flash容量陷阱64KB标称与实际128KBF103C8T6数据手册标注Flash是64KB但相当一部分芯片实际焊的是128KB的die——因为ST在产线复用C8和CB的晶圆。这意味着如果Keil里设置的是64KB编程算法编译固件超过64KB就会报错但如果手动选择高密度Flash算法可以把超过64KB的程序写进去。这件事对键盘项目的意义在于如果你加了FreeRTOS、Canvas级别的灯效、字库、开机动画固件体积很容易突破64KB这个时候可以尝试用128KB的编程算法烧录多数情况下能成功。注意这不是官方保证的行为如果做商业产品按64KB规划才是合规做法。另外国产替代芯片的Flash容量不能照搬ST的经验GD32F103C8T6有些批次是64KB全验证过的不要盲试。烧录环节最后一个建议每次烧录成功之后用STM32CubeProgrammer的Read Out Protection Level检查一遍确保芯片状态符合预期。这个小习惯能帮你节省无数个为什么灯不亮的排查时间。我做键盘项目到现在前后迭代了四版PCB。第一版问题最多晶振电容配错、复位电阻漏焊、SWD丝印反了。第二版解决了硬件问题固件又卡在USB枚举。到第三版才真正稳定——跑FreeRTOS加WS2812灯效每天连续使用一个月没有掉链子。回看整个过程收获最大的反而不是那把键盘而是建立了一套自己的排查方法论硬件问题和软件问题怎么区分、晶振波形怎么测、USB枚举失败从哪里下手、DAPLink报什么错对应什么原因。这些经验在其他STM32项目里全部能复用。如果你也想做我的建议是不要一上来就画板子先买一片现成的F103C8T6最小系统板外接矩阵键盘面包板也行把固件跑通再去用立创EDA画自己的PCB。硬件和软件分开调试哪个环节出了问题都能快速定位。等你把这条链路完整走一遍再回头看客制化键盘圈那些一两千块的成品你会有完全不同的视角。