STM32F103C6示波器源码实战:Keil5跑通ADC采样与TFT显示
简介这份资源是面向嵌入式初学者与电子爱好者的STM32F103C6示波器项目源码基于Keil5开发环境帮助读者理解如何用Cortex-M3内核单片机实现模拟信号采集与实时传输。项目核心思路是ADC采集探头电压信号经DMA自动搬运至内存以减轻CPU负担再通过USB HID协议将数据实时发送到PC端显示波形是学习信号采集与USB通信的典型实践案例。压缩包共969个文件以572个c源文件、257个h头文件、51个s汇编文件为主另含crf、icf、lib、uvprojx等工程与库文件整体约11.72MB目录涵盖Drivers驱动、Src源码、Inc头文件、Middlewares中间件及MDK-ARM工具链结构完整便于按模块研读。目前已有922人学习下载读者可据此掌握ADCDMAHID的完整链路并在此基础上扩展滤波、存储与分析等功能。1. 一块 F103C6 做示波器为什么这版 Keil5 源码值得你花一个晚上跑通手头有一块最小系统板芯片是 STM32F103C6Flash 只有 32KB、RAM 10KB引脚也不多。很多人第一反应是「这点资源能干嘛」但恰恰是这种资源受限的芯片最适合拿来吃透 ADC 采样、定时器触发和 TFT 刷屏这条完整链路。这份示波器源码就是围绕 F103C6 搭的一套可运行工程Keil5 打开就能编译烧进去接上信号就能看到波形。它解决的不是「做一个商用示波器」而是让你在一块便宜到可以随手焊坏的单片机上把「模拟信号怎么变成屏幕上那条线」这件事从头到尾走一遍。适合刚学完 GPIO 和串口、想找个综合项目练手的人也适合手上正好有 C6 板子、想验证自己硬件是否正常的熟手。下面我按实际拆包和复现的顺序讲参数、坑点、改法都落到具体位置。2. 拆开工程看结构F103C6 的 32KB 到底怎么分配2.1 目录里都有什么哪些文件动不得拿到源码包第一件事不是急着编译而是先看清楚目录结构。这类 Keil5 工程通常长这样根目录下有一个.uvprojx工程文件一个User文件夹放main.c和中断服务函数一个Hardware或BSP文件夹放 LCD、ADC、定时器的驱动还有一个Start或CMSIS文件夹放启动文件和内核头文件。F103C6 属于中容量产品启动文件要选startup_stm32f103xb.s这一档选错了链接阶段会报一堆未定义符号。有几个文件是「动不得」的启动文件、system_stm32f1xx.c里的时钟配置、以及stm32f1xx.h里的寄存器定义。这些是芯片能跑起来的地基改错一个时钟树参数现象就是程序卡在SystemInit里出不来串口一行字都不打印。真正需要你关注的是main.c的主循环、ADC 的初始化函数、以及 LCD 的刷屏函数这三块决定了示波器的采样率和刷新率。我一般会先做一件事把工程编译一遍看 Code、RO-data、RW-data、ZI-data 四个数字。F103C6 的 Flash 是 32KBRAM 是 10KB如果编译出来 Code 超过 30KB 或者 ZI-data 逼近 10KB后面加任何功能都会溢出。这份源码之所以能在 C6 上跑就是因为它在缓冲区大小和显示区域上做了裁剪这一点在后面的参数章节会具体说。2.2 采样、触发、显示三个模块怎么串起来示波器的核心链路其实就三步采样、触发、显示。采样靠 ADC触发靠比较逻辑显示靠 LCD 刷点。这份源码里ADC 配置成规则通道连续转换由定时器 TRGO 事件触发这样采样间隔是确定的不会因为主循环里干了别的活而抖动。定时器的更新频率决定了采样率比如 72MHz 主频下预分频 72、重装载 100得到的就是 10kHz 的触发频率。触发逻辑是很多人第一次做示波器会忽略的地方。没有触发波形在屏幕上会左右乱跑根本没法看。源码里的做法是在 ADC 中断里判断采样值是否越过设定的触发电平越过了才开始往缓冲区写写满一屏就停主循环再把缓冲区刷到 LCD 上。这就是最简单的上升沿触发。缓冲区大小直接决定了一屏能显示多少个点F103C6 的 RAM 只有 10KB用uint16_t存 512 个点就是 1KB加上 LCD 的显存和栈空间基本就到头了。显示部分源码用的是并口或 SPI 的 TFT 屏刷一列点的方式画波形。这里有个取舍如果每采一个点就刷一次屏刷新率会被 LCD 拖死所以正确做法是采满一屏再统一刷。主循环里那个while(1)干的就是这件事——等缓冲区满然后逐列画点画完清标志等下一屏。理解了这个数据流后面调参数才知道该动哪里。3. 在 Keil5 里把它跑起来从新建工程到第一道波形3.1 打开工程先改这三处配置拿到.uvprojx直接双击打开Keil5 会提示器件包。F103C6 需要安装Keil.STM32F1xx_DFP这个 Device Family Pack没装的话器件列表里找不到 STM32F103C6编译按钮是灰的。装好包之后在 Options for Target 里确认三件事。第一Device 页选对型号必须是 STM32F103C6选成 C8 或 RB 虽然引脚兼容但 Flash 和 RAM 大小不一样链接脚本可能对不上。第二Target 页的晶振频率填你板子上的实际值最小系统板一般是 8MHz 外部晶振填错了SystemInit算出来的主频就不对定时器采样率跟着全错。第三Debug 页选对你的下载器ST-Link 就选 ST-Link DebuggerJ-Link 就选 J-LINK然后在 Settings 里确认能读到芯片 ID。# 编译后如果报 cannot open source input file stm32f1xx.h # 说明头文件路径没加全检查 Options - C/C - Include Paths # 至少要包含以下三个路径按你实际目录替换 .\Start\CMSIS\Device\ST\STM32F1xx\Include .\Start\CMSIS\Include .\User这段不是让你敲命令而是提醒你Keil 工程最常见的翻车就是头文件路径。源码包如果是从别人机器上打包的路径里可能带着绝对路径换台电脑就找不到。解决办法是在 Include Paths 里把带盘符的路径删掉重新用相对路径加一遍。3.2 采样率、缓冲区、触发电平三个参数怎么定工程能编译只是第一步真正决定示波器好不好用的是三个参数。我把它们和对应的代码位置列出来你照着改就行。参数典型值代码位置影响定时器预分频71TIM2 初始化和重装载值共同决定采样率定时器重装载99TIM2 初始化同上采样率 72M/(711)/(991)ADC 缓冲区长度512main.c 数组定义决定一屏点数越大越占 RAM触发电平2048触发判断处12 位 ADC 的中值可调采样率的算法是主频除以预分频1再除以重装载1。上面这组值算出来是 10kHz也就是每 100 微秒采一个点。对于音频以下的信号够用想看更快的信号就得减小重装载值但注意 ADC 本身有转换时间F103 的 ADC 最快也就 1MHz 左右别把定时器设得比 ADC 还快那样采到的点是重复的。缓冲区长度和 RAM 的关系要算清楚。512 个uint16_t是 1KB如果 LCD 驱动自己还开了显存比如 240x320 的屏用 16 位色一屏就是 150KBF103C6 根本放不下。所以这类小资源示波器通常用「只画波形区域、不整屏缓存」的方式或者用 8 位色、小尺寸屏。你如果换了大屏第一件事就是确认显存是不是开在芯片内部 RAM 里是的话赶紧改成局部刷新。触发电平设成 2048 是因为 12 位 ADC 的范围是 0 到 4095中值对应 1.65V 左右。如果你的信号是 0 到 3.3V 摆幅触发点设中间最稳如果信号只在小范围波动比如 1V 到 1.5V那触发电平要相应调低否则永远触发不了屏幕就是一条直线。3.3 烧录后没波形先查这四步烧进去屏幕亮了但没波形别急着改代码按这个顺序查。第一步用万用表量 ADC 输入引脚确认信号真的到了引脚上很多人是杜邦线没插紧或者接错了通道。第二步在 ADC 中断里翻转一个 GPIO用示波器或逻辑分析仪看有没有翻转有翻转说明采样在跑没有就是定时器或 ADC 没启动。第三步看触发电平是不是设得太高或太低把信号直接接到 3.3V 或 GND看屏幕有没有反应。第四步检查 LCD 的刷屏函数单独写个测试把屏幕刷成纯色确认显示链路是通的。这四步走完基本能定位到是采样问题还是显示问题。我见过最多的翻车是 ADC 引脚和 LCD 引脚复用了同一个 GPIO初始化的时候后初始化的把前面的覆盖了现象就是屏幕正常但采样值永远是 0。查引脚复用表把冲突的引脚错开就行。4. 避坑与排查F103C6 做示波器最容易栽的五个地方4.1 现象编译通过但一烧录就卡死原因通常是栈溢出或者中断向量表偏移不对。F103C6 的 RAM 只有 10KB如果局部数组开得太大比如在函数里定义一个 512 字节的缓冲栈直接爆掉程序跑飞。解决方法是把大数组改成全局或静态放到 ZI-data 区同时把启动文件里的栈大小从默认的 0x400 调到 0x200 甚至更小给堆留空间。4.2 现象波形能显示但抖动厉害这是触发没做好或者采样和显示不同步。如果触发判断放在主循环里采样中断和主循环抢缓冲区波形就会左右跳。正确做法是触发和写缓冲都在 ADC 中断里完成主循环只负责读一个「缓冲满」标志然后刷屏。另外刷屏期间如果 ADC 还在写同一个缓冲区也会撕裂所以要么双缓冲要么刷屏前先关中断。4.3 现象采样率标称 10kHz 但实际差很多多半是定时器时钟源没配对。F103 的 TIM2 挂在 APB1 上如果 APB1 预分频不为 1定时器时钟会是 APB1 的两倍。很多人按 36MHz 算实际是 72MHz采样率直接翻倍。查RCC_GetClocksFreq的返回值或者直接在定时器初始化后翻转 GPIO 用示波器量周期这是最准的验证方法。4.4 现象换一块同型号板子就不工作F103C6 有多个封装引脚定义不一样。源码如果是按 LQFP48 写的你换成 TSSOP20 的板子很多引脚根本不存在初始化这些引脚要么没反应要么报错。换板子第一件事是对着数据手册的引脚定义表把 LCD 和 ADC 用到的引脚重新核对一遍尤其是复用功能和重映射。4.5 现象屏幕花屏或颜色不对LCD 驱动的初始化序列和屏幕控制器型号必须匹配。常见的小屏控制器有 ILI9341、ST7789、ST7735初始化命令差别很大用错序列就是花屏。源码里如果写死了某一种你换屏就要改初始化数组。另外颜色格式也要对RGB565 和 RGB666 的字节顺序不同接反了颜色会偏。先刷纯色测试红绿蓝各刷一遍颜色对了再调波形。5. 进阶把这份源码改成能测更高频信号的双缓冲版本跑通基础版本之后你会发现两个瓶颈一是采样率上不去二是刷屏时波形会闪。这两个问题可以用双缓冲加 DMA 解决。思路是开两个缓冲区ADC 由定时器触发、DMA 搬运填满一个缓冲区就切换主循环刷另一个互不干扰。F103C6 的 DMA 有 7 个通道ADC1 对应 DMA1 通道 1配置成循环模式缓冲区大小设成 256两个缓冲就是 512 个uint16_t1KBRAM 还扛得住。// ADC DMA 双缓冲关键配置放在 ADC 初始化之后 #define BUF_LEN 256 uint16_t adc_buf[2][BUF_LEN]; // 双缓冲共 1KB // DMA 配置外设到内存循环模式半满和全满都产生中断 DMA_InitStructure.DMA_PeripheralBaseAddr (uint32_t)ADC1-DR; DMA_InitStructure.DMA_MemoryBaseAddr (uint32_t)adc_buf; DMA_InitStructure.DMA_BufferSize BUF_LEN * 2; // 两个缓冲连续存放 DMA_InitStructure.DMA_DIR DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_Mode DMA_Mode_Circular; DMA_InitStructure.DMA_MemoryInc DMA_MemoryInc_Enable; DMA_InitStructure.DMA_PeripheralInc DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_PeripheralDataSize DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize DMA_MemoryDataSize_HalfWord; DMA_Init(DMA1_Channel1, DMA_InitStructure); DMA_ITConfig(DMA1_Channel1, DMA_IT_TC | DMA_IT_HT, ENABLE); // 全满和半满中断 DMA_Cmd(DMA1_Channel1, ENABLE);这段代码的逻辑是DMA 把 ADC 数据自动搬到adc_buf搬满一半触发 HT 中断搬满全部触发 TC 中断。在中断里切换「当前该刷哪个缓冲」的标志主循环根据标志刷屏。这样采样和显示彻底解耦采样率只受 ADC 和定时器限制刷屏慢一点也不会丢数据。参数上BUF_LEN设 256 是折中太小了中断太频繁太大了 RAM 吃紧。中断优先级里 DMA 要比主循环高但别设成最高留一点给 systick。验证方法很简单输入一个已知频率的方波比如 1kHz看屏幕上是不是稳定显示两个周期。如果波形稳定不抖说明双缓冲生效了如果还是抖检查 DMA 中断里有没有清标志位F1 系列的 DMA 中断标志必须手动清忘了清就会一直进中断主循环根本跑不到刷屏。从那以后我每次改采样相关的代码都会先用 GPIO 翻转法量一遍实际采样率再去看波形不然调半天都是玄学。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

NVIDIA Nemotron 3.5 Lightning 30B A3B函数调用实战:基于qwen3_coder解析器的AI Agent工具集成完整教程

NVIDIA Nemotron 3.5 Lightning 30B A3B函数调用实战:基于qwen3_coder解析器的AI Agent工具集成完整教程

【免费下载链接】NVIDIA-Nemotron-3.5-Lightning-30B-A3B-bf16 项目地址: https://ai.gitcode.com/hf_mirrors/mlx-community/NVIDIA-Nemotron-3.5-Lightning-30B-A3B-bf16 点击查看 免费下载 NVIDIA Nemotron 3.5 Lightning 30B A3B 函数调用如何快速落地&#xf…

2026/10/18 3:05:12 阅读更多 →
IDEA升级后无法启动?从日志到插件、JDK、VM参数的完整排查指南

IDEA升级后无法启动?从日志到插件、JDK、VM参数的完整排查指南

点了升级按钮之后,IDE 就再也进不去了——这个问题我见过太多次。图标转了两圈消失在任务栏里,或者进度条走到一半直接闪退,又或者弹出一个 Internal Error 窗口,点完确定一切归零。多数人的第一反应是卸载重装,但这里…

2026/10/18 3:04:12 阅读更多 →
Git push报错全解析:non-fast-forward、权限拒绝与分支不匹配的排查与解决

Git push报错全解析:non-fast-forward、权限拒绝与分支不匹配的排查与解决

1. 从一次深夜提交失败说起:为什么git push的报错值得单独拎出来讲但凡写过几年代码的人,几乎都有过这样的经历:本地跑得好好的,commit也提交了,结果一个git push下去,终端里蹦出一段红字,整个人…

2026/10/18 3:04:12 阅读更多 →

最新新闻

从零跑通开源大模型:选型、环境、加载与推理全指南

从零跑通开源大模型:选型、环境、加载与推理全指南

很多人第一次看到“初始大模型”这个说法,第一反应是:是不是得先啃下一堆数学公式和论文?我在刚开始接触时也是这么想的,后来才发现,初始大模型这件事拆开来看,无非是两条线:一条是认知线&#…

2026/10/18 3:51:21 阅读更多 →
Transformer车道线预测:从控制点建模到物理一致性优化

Transformer车道线预测:从控制点建模到物理一致性优化

1. 为什么车道形状预测突然需要Transformer——从传统方法的“缝合怪”说起我第一次在某自动驾驶实验室看到用CNNRNN组合做车道线拟合时,心里就打了个问号:为什么要把图像特征提取、序列建模、几何约束三套系统硬凑在一起?当时团队用ResNet提…

2026/10/18 3:51:21 阅读更多 →
深度学习入侵检测系统实战:从流量抓包到实时告警的完整链路

深度学习入侵检测系统实战:从流量抓包到实时告警的完整链路

先把话放前面:网上打着“深度学习入侵检测”旗号的源码项目,十个里至少有九个是拿公开数据集跑个准确率就完事。我之前也经历过这个阶段,但直到把模型丢进真实抓包环境,才意识到从原始流量到告警通知,这条链路上全是文…

2026/10/18 3:51:21 阅读更多 →
专科论文写作不用慌:AI辅助选题到降重全流程实战指南

专科论文写作不用慌:AI辅助选题到降重全流程实战指南

专科生要写毕业论文,但凡经历过的人都知道那种从头焦虑到尾的感觉:题目不知道怎么定、开题报告格式看不懂、正文憋了一周还是空白、查重一红就是一大片。我也见过太多人从毕业季拖到最后一周,在打印店里对着格式要求硬改。说实话,…

2026/10/18 3:51:21 阅读更多 →
YOLOv8换EfficientNetV2骨干:端侧部署延迟与int8量化双优化实践

YOLOv8换EfficientNetV2骨干:端侧部署延迟与int8量化双优化实践

把 YOLOv8 默认的 CSPDarknet53 主干换成 EfficientNetV2 的均质性网络架构,这件事我前后折腾了将近半年。起因很现实:一个工业外观检测项目要求在边缘设备上跑进 15ms 的单帧延迟,我拿 YOLOv8n 直接部署,精度达标了,但…

2026/10/18 3:51:21 阅读更多 →
具身智能中的协同机理研究(138):TVA与VLA破解动态场景时序一致性机制

具身智能中的协同机理研究(138):TVA与VLA破解动态场景时序一致性机制

前沿技术探索:TVA智能体(简称TVA) TVA智能体(亦称“AI智能体视觉”)是依托Transformer架构与“因式智能体”理论构建的新型工业视觉系统,也是当前最具代表性的具身视觉技术之一。它有机融合深度强化学习&a…

2026/10/18 3:50:21 阅读更多 →

日新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

周新闻

基于GMM的语音识别系统原理与MATLAB实现详解

基于GMM的语音识别系统原理与MATLAB实现详解

说到基于高斯混合模型(GMM)的语音识别系统,很多人第一反应就是一堆数学公式,觉得门槛很高。但如果你真的在MATLAB里把它落地跑通,会发现核心其实就是三件事:把声音变成特征向量,用GMM给每个类别…

2026/10/18 0:00:55 阅读更多 →
数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理入门:反白、灰度化、调色板修改与导出txt实践

数字图像处理这四个字听起来挺唬人,但落到具体操作上,无非就是让计算机按你的想法“摆弄”像素。我在一个模拟项目X里用了一套特别经典的基础处理流程:对图像做反白、改调色板、彩色转灰度,最后把像素数据导出成txt文件。单看每一…

2026/10/18 0:00:55 阅读更多 →
机器人大脑技术盘点:具身智能的感知、决策与数据闭环

机器人大脑技术盘点:具身智能的感知、决策与数据闭环

如果你的信息流最近也天天刷到“机器人大脑”这个词,你会发现一个很有意思的现象:每个人说的“大脑”根本不是同一个东西。有人指的是大语言模型,有人指的是运动控制系统,还有人指的是能理解物理世界的端到端模型。在2026年这个时…

2026/10/18 0:00:55 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/18 0:55:02 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/17 17:22:31 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/16 14:23:36 阅读更多 →