惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
Netflix TechBlog - Medium
J
Java Code Geeks
爱范儿
爱范儿
雷峰网
雷峰网
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
博客园 - 三生石上(FineUI控件)
H
Hackread – Cybersecurity News, Data Breaches, AI and More
B
Blog RSS Feed
Google DeepMind News
Google DeepMind News
Jina AI
Jina AI
The GitHub Blog
The GitHub Blog
I
InfoQ
月光博客
月光博客
博客园 - 聂微东
博客园 - Franky
The Cloudflare Blog
阮一峰的网络日志
阮一峰的网络日志
博客园_首页
G
Google Developers Blog
Blog — PlanetScale
Blog — PlanetScale
L
LangChain Blog
罗磊的独立博客
Apple Machine Learning Research
Apple Machine Learning Research

博客园_首页

Linux实操--组管理、权限管理和定时任务 Java + EasyExcel 实现单个接口导出多个Excel Mem0 源码解析系列(二):提示词工程的深度剖析 Openclaw TaskFlow究竟是什么?和普通Skill技能有什么区别 博文阅读密码验证 - 博客园 嘉立创开源:应该是全网MicroPython教程最多的开发板 Hermes Agent 集成实践:从协议到生产 2026年AI编程工具横评:Cursor、Codex、Claude Code、Zed、Windsurf Java程序员必看的RAG入门教程 2026 AI效率神器:Superpowers + Claude Code 保姆级教程 本地大模型部署全攻略:从 0 到 1 玩转 Ollama 【从0到1构建一个ClaudeAgent】内存管理-上下文压缩 .NET 高级开发 | 设计、实现一个事件总线框架 电子小白入门之NE555 3. WorkBuddy:隐藏玩法,一键召唤专家,让 AI 以"专家身份"给你干活 和AI一起搞事情#3:Claude Teammate 游戏开发翻车实录 【OpenClaw】通过 Nanobot 源码学习架构---(7)Memory C# .NET 周刊|2026年3月3期 我在 Debian 11 上把 K8s 单机搭起来了,过程没你想的那么顺(/opt 目录版) 深度学习进阶(七)Data-efficient Image Transformer CLI+Skill搭建浏览器AI自动化框架,告别一切重复枯燥任务 告别Token账单无底洞:OpenClaw本地部署,重塑企业数据主权的唯一解 FastAPI+Vue:文件分片上传+秒传+断点续传,这坑我帮你踩平了! SBTI 爆火后,我做了个程序员版的 CBTI。。已开源 + 附开发过程 多模态检索开始进入工程期:用 Sentence Transformers 搭建可落地的 Multimodal RAG 100多行代码实现一个最简单的Agent(用ReAct) Claude Code 通关手册(八):推荐 5 个 Hooks,代码质量提升 3 倍 老板:“有人截图了!”。安全部门:“收到,马上查暗水印!” - why技术 技术之外,皆是人间 C#/.NET/.NET Core技术前沿周刊 | 第 69 期(2026年4.01-4.12)
GPIO同时复用(ADC与TIM)
ifndef · 2026-06-20 · via 博客园_首页

众所周知,MCU的GPIO可复用为不同的功能.那么是否可以同时使能多个功能呢?可以(当然,部分架构可能不支持)
常见示例:

  • 模拟IIC: GPIO在开漏输出的同时可以读IDR来获得输入
  • 无LPUART的MCU实现低功耗唤醒: 把RXD同时复用为外部中断来唤醒,但会丢失首字节
  • UART自动波特率识别: 配置RXD同时为TIM捕获,通过特定序列来抓取1bit时长来计算波特率

可见,在数字信号尤其同时为输入的场景下,一个GPIO被同时复用为多个功能的情况还是很常见的.但也基本都是无奈之举,硬件支持或有更多GPIO可用的情况,更推荐分离功能的方案.

本例讨论实际项目中遇到模拟输入与数字输入同时存在时的配置实现与缺陷.项目需采集外部信号,可能为模拟量信号或PWM(齿缺)信号.对于基础应用可前置RC将PWM转为模拟等方式归一化处理,或分别接入不同GPIO进行采集.项目需要分别不同信号源且获取原始数据,且出于成本和尺寸限制无法更换更大封装型号,只能在原板基础上实现此功能.项目采用CH32V003J4,10bitADC,选用引脚为PD6/PA1(内部合封,本质只用PA1).信号幅值较高通过100K+100K分压网络分压至5V(也为后文缺陷埋下伏笔)

image

查看GPIO结构图可见,本质配置GPIO_Mode只是控制几个开关(上下拉,输出Pmos,输出控制器,输入施密特触发器).对于输入来说,浮空输入上拉输入下拉输入为一组,区别在上下拉的开关组合,而模拟输出则是浮空输入+关闭施密特触发器(PS: 因此低功耗应用才推荐不用的GPIO配置为模拟输入,可以节约施密特触发器消耗).本例中的模拟信号从施密特触发器前的AnalogInput路径到ADC,TIM通道则走施密特触发器后的AlternateFunctionInput路径,因此GPIO应配置为浮空输入.

RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA, ENABLE );
/* GPIO PA1 T1CH2 */
GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_30MHz;
GPIO_Init( GPIOA, &GPIO_InitStructure );

之后正常按单一GPIO配置对应的ADC通道与TIM输入捕获即可.

测试验证

  1. 仅使能TIM捕获功能测试PWM信号,此场景就是常规的输入捕获,功能理应完全正常
  2. 仅使能ADC采样功能测试模拟信号,此场景与常规场景就是GPIO_Mode从AIN变float,但ADC在触发器前级采样,功能理应完全正常
  3. 同时使能TIM与ADC测试模拟信号,此场景TIM由于在施密特触发器后级,并不能影响前级的采样,ADC读数理应正常.TIM在模拟信号处于触发器阈值附近时触发连续的中断(此时忽略)
  4. 同时使能TIM与ADC测试PWM信号,此场景TIM应正常捕获信号,若出现异常短时长则调大数字滤波TIM_ICFilter即可解决

异常分析

在测试3测试4中,均有可能出现TIM捕获异常,这是由于施密特触发器前级的ADC采样导致的电压波动而误触发了施密特触发器.模拟信号时抓取引脚端信号如图:

DS1Z_QuickPrint1

可见模拟信号(分压后)存在规律性的抖动,这是ADC采样导致的.计算验证:

MCU主频24MHz,8分频作为ADC时钟,则ADC每cycle约为0.33us.本例共采样两通道,均采样73Cycles,因此可计算得到73x2x0.33us=48.2us,与图中抖动周期基本一致.

ADC内部存在采样电容C与采样开关电阻R. 查询芯片手册得知,C典型值3pF,R最大值1.5K(采最大值以计算最坏),外部100K分压即串联100K,电容充满至少需6.9RC.因此可计算得到6.9x101.5kx3pF=2.1us,也与图中抖动宽度基本一致(实际电路存在走线电容等影响).

ADC采样瞬间给内部采样电容充电,GPIO引出与内部仅有1.5K电阻,与信号源则有100K,因此被瞬间拉低到电容充电结束.测试3中周期性的噪声信号即由此产生.测试4中此异常叠在5V PWM信号内,对信号精度产生一定影响但可通过数字滤波消除

改善此异常的几种方式:

  • IO端增加小电容快速补偿以减少信号被拉低的幅值,使其减少触发施密特触发器.但电容会导致PWM信号斜率变化,需要评估
  • 降低分压阻值,即加快充能.使其能够轻易的被捕获滤波器滤除.需评估信号源,本例中就无法修改
  • 调整ADC频率与采样周期(需大于充能时间以保证精度)来尽可能避开PWM信号周期范围,通过软件滤除超范围的信号

本质此用法是受限于项目实际环境的无奈之举,在兼顾的同时必然无法专精采样精度等,因此常规项目更推荐分离的实现