STM32F103C8T6驱动TTP223电容触摸模块+OLED显示(完整工程讲解)
前言
本篇博客基于 STM32F103C8T6 最小系统板,搭配 TTP223 电容触摸模块以及 I2C‑OLED 显示屏,实现触摸检测、触摸状态显示、触摸次数统计功能。 很多同学会把 TTP223 当成普通按键,其实它是电容触摸芯片,检测的是电容变化,不是触点导通。本文从硬件接线、工作原理、软件逻辑、实物演示、源码说明几个方面完整讲解,工程可以直接移植使用。
硬件平台:STM32F103C8T6 最小系统板 外设:TTP223电容触摸模块、0.96 寸 I2C OLED 屏幕
一、项目实现效果
手指靠近 / 接触 TTP223 触摸电极 → 电极对地电容发生改变 → TTP223 芯片检测电容变化,修改 OUT 引脚输出电平 → STM32 通过 PB12 引脚读取电平信号 → 软件做消抖确认,识别触摸、松开事件 → OLED 屏幕实时刷新触摸状态,同时统计触摸总次数。
简单概括:TTP223 把手指带来的电容变化转换成高低电平;STM32 读取电平,软件校验之后,更新 OLED 显示以及触摸计数。

二、硬件接线说明
⚠️重点:所有模块 GND 必须接到一起,也就是单片机和外设必须共地,否则会出现检测异常、乱触发问题。
| 模块引脚 | STM32F103C8T6 引脚 | 功能说明 |
|---|---|---|
| TTP223 OUT(SIG) | PB12 | 触摸信号输出,本工程高电平代表触摸 |
| TTP223 VCC | 5V | TTP223 模块供电 |
| TTP223 GND | GND | 电源地 |
| OLED SCL | PB8 | 软件 I2C 时钟 |
| OLED SDA | PB9 | 软件 I2C 数据 |
| OLED VCC | 3.3V | OLED 屏幕供电 |
| OLED GND | GND | OLED 电源地 |
引脚配置注意事项
- TTP223‑BA6 芯片工作电压 2.0V‑5.5V,这里使用 5V 供电,OUT 输出高电平接近 5V。
- PB12 属于 FT 类型 5V 容忍 IO 口,可以接收 5V 电平;根据芯片手册,FT 引脚接收高于 VDD+0.3V 信号时,要关闭内部上拉下拉。
- 工程源码默认使用下拉输入
GPIO_Mode_IPD,可以悬空时保持低电平,但是不符合手册规范,长期使用建议修改为浮空输入GPIO_Mode_IN_FLOATING。 - 如果你的单片机 IO 不支持 5V 容忍,OUT 引脚必须增加分压或者电平转换电路,防止烧坏 IO。
TTP223 模块模式匹配
TTP223 成品模块板上有焊盘,可以修改工作模式,我们本工程软件默认配置:
- ✅高电平有效 + 直接模式
- 未触摸:OUT 输出低电平
- 触摸按住:OUT 输出高电平
- 松手释放:OUT 回到低电平
如果你的模块是低电平有效,OLED 显示状态会完全颠倒;如果是切换模式,触摸计数逻辑会失效,使用前确认模块硬件模式。
三、TTP223 电容触摸工作原理
TTP223 属于单通道电容触摸检测芯片,和机械按键原理完全不一样。机械按键依靠金属触点导通断开,而 TTP223 检测触摸电极的对地电容变化。
- 触摸铜箔本身就存在很小的寄生电容,人体可以和大地形成电容耦合。当手指靠近或者接触触摸电极,电极等效对地电容就会变大。
- 手指离得越近、接触面积越大,电容变化越明显;它可以隔着薄玻璃、亚克力、塑料完成触摸检测,不需要手指直接接触铜箔。
- 如果覆盖材料太厚、触摸面积太小、周围电磁干扰大,触摸灵敏度会明显下降。
芯片内部会周期性检测电极充放电特性,上电生成环境基准电容值,实时对比当前电容。当电容变化达到判定阈值,直接修改 OUT 引脚电平。手指移开电容恢复,OUT 电平复原。
💡重点:TTP223 输出的是已经处理完成的数字电平,不是模拟信号,STM32 不需要 ADC 采集;芯片不能检测压力大小,按压效果差异来自接触面积改变。芯片还会自动校准基准,适配温度、湿度缓慢变化。
四、STM32 软件逻辑讲解
4.1 GPIO 读取逻辑
PB12 作为数字输入引脚,只识别高低两种逻辑电平:
- PB12 为低电平:状态为释放,没有触摸
- PB12 为高电平:状态为触摸
直接读取引脚输入寄存器,就可以获取瞬时触摸信号,不需要 ADC。
4.2 轮询扫描与软件消抖
虽然电容触摸没有机械按键的触点抖动,但是电源噪声、长线干扰、信号跳变瞬间,依然会产生毛刺干扰。 工程中主循环每 10ms 调用一次触摸扫描函数:
- 读取 PB12 当前电平,和上一次确认稳定状态对比;
- 如果电平没有变化,直接返回无事件;
- 如果电平发生改变,延时 20ms 再次读取引脚;
- 两次读取状态一致,才判定状态真正发生切换;否则判定为干扰毛刺,直接丢弃。
参数说明:10ms 是主循环轮询间隔,20ms 是状态变化复核消抖时间。最终整体响应延迟包含芯片本身响应时间、轮询间隔、OLED 刷新耗时。
4.3 事件与触摸计数逻辑
程序区分状态和事件两个概念:
- 状态:当前持续是触摸还是释放;
- 事件:状态发生跳变的一瞬间产生的信号。
| 事件类型 | 触发条件 | 程序动作 |
|---|---|---|
| EVENT_NONE | 状态无变化,或者消抖复核失败 | 不做任何处理 |
| EVENT_TOUCH | 状态从释放切换到触摸 | 触摸计数 + 1,OLED 显示 TOUCHED |
| EVENT_RELEASE | 状态从触摸切换到释放 | 计数不变,OLED 显示 RELEASED |
👉 按住触摸不放的时候,只会触发一次 EVENT_TOUCH,计数只加 1;必须松开之后再次触摸,才会再次计数。计数最大 99999,溢出之后自动归零,防止五位显示溢出。
4.4 OLED 屏幕显示效果
屏幕输出内容:
TTP223 TOUCH DEMO
OUT PIN: PB12
STATE:TOUCHED
COUNT:00001
松开触摸之后 STATE 行变为STATE:RELEASED。
五、源代码存放区
工程文件结构参考:
- TTP223.h:引脚、事件、消抖参数宏定义
- TTP223.c:初始化、读取、扫描处理函数
- main.c:主循环,事件处理、OLED 状态刷新函数
main.c代码
/* TTP223 touch teaching demonstration for STM32F103C8T6. */
#include "delay.h"
#include "sys.h"
#include "oled.h"
#include "TTP223.h"
#define TOUCH_POLL_TIME_MS 10U
#define TOUCH_COUNT_MAX 99999UL
static void TTP223_ShowStatus(u8 touch_state, u32 touch_count);
int main(void)
{
TTP223_EventTypeDef event;
u32 touch_count = 0U;
delay_init();
NVIC_Configuration();
OLED_Init();
OLED_ColorTurn(0);
OLED_DisplayTurn(0);
TTP223_Init();
TTP223_ShowStatus(TTP223_GetState(), touch_count);
while(1)
{
event = TTP223_Scan();
if(event == TTP223_EVENT_TOUCH)
{
if(touch_count < TOUCH_COUNT_MAX)
{
touch_count++;
}
else
{
touch_count = 0U;
}
TTP223_ShowStatus(TTP223_TOUCHED, touch_count);
}
else if(event == TTP223_EVENT_RELEASE)
{
TTP223_ShowStatus(TTP223_RELEASED, touch_count);
}
delay_ms(TOUCH_POLL_TIME_MS);
}
}
static void TTP223_ShowStatus(u8 touch_state, u32 touch_count)
{
OLED_Clear();
OLED_ShowString(0, 0, (u8 *)"TTP223 TOUCH DEMO", 12);
OLED_ShowString(0, 16, (u8 *)"OUT PIN: PB12", 12);
OLED_ShowString(0, 32, (u8 *)"STATE:", 12);
if(touch_state == TTP223_TOUCHED)
{
OLED_ShowString(42, 32, (u8 *)"TOUCHED ", 12);
}
else
{
OLED_ShowString(42, 32, (u8 *)"RELEASED", 12);
}
OLED_ShowString(0, 48, (u8 *)"COUNT:", 12);
OLED_ShowNum(42, 48, touch_count, 5, 12);
OLED_Refresh();
}
TTP223.c代码
#include "TTP223.h"
#include "delay.h"
static u8 TTP223_StableState = TTP223_RELEASED;
/**
* @brief 初始化 TTP223 触摸模块。
* @note 将 PB12 配置为下拉输入。模块未连接时,下拉电阻可以使输入
* 保持为确定的低电平;标准 TTP223 模块在检测到触摸时输出高电平。
*/
void TTP223_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/* 开启 GPIOB 外设时钟。 */
RCC_APB2PeriphClockCmd(TTP223_GPIO_CLK, ENABLE);
/* 将连接 TTP223 OUT 的 PB12 配置为下拉输入。 */
GPIO_InitStructure.GPIO_Pin = TTP223_GPIO_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(TTP223_GPIO_PORT, &GPIO_InitStructure);
/* 保存上电后的初始电平,防止首次扫描产生错误事件。 */
TTP223_StableState = TTP223_Read();
}
/**
* @brief 读取 TTP223 OUT 引脚的瞬时电平。
* @retval TTP223_TOUCHED:检测到触摸;TTP223_RELEASED:未触摸。
*/
u8 TTP223_Read(void)
{
if(GPIO_ReadInputDataBit(TTP223_GPIO_PORT, TTP223_GPIO_PIN) == Bit_SET)
{
return TTP223_TOUCHED;
}
return TTP223_RELEASED;
}
/**
* @brief 获取最近一次经过消抖确认的稳定触摸状态。
* @retval TTP223_TOUCHED 或 TTP223_RELEASED。
*/
u8 TTP223_GetState(void)
{
return TTP223_StableState;
}
/**
* @brief 扫描 TTP223,并判断是否发生触摸状态切换。
* @note 本函数应在主循环中反复调用。当检测到 PB12 电平发生变化时,
* 延时 TTP223_DEBOUNCE_MS 后再次读取;只有两次结果一致,才确认
* 本次状态切换有效。
* @retval TTP223_EVENT_NONE:状态未改变或消抖失败;
* TTP223_EVENT_TOUCH:确认发生触摸;
* TTP223_EVENT_RELEASE:确认触摸被释放。
*/
TTP223_EventTypeDef TTP223_Scan(void)
{
u8 current_state;
/* 当前电平与稳定状态相同时,不产生新事件。 */
current_state = TTP223_Read();
if(current_state == TTP223_StableState)
{
return TTP223_EVENT_NONE;
}
/* 延时后再次采样,以滤除状态切换瞬间的干扰。 */
delay_ms(TTP223_DEBOUNCE_MS);
current_state = TTP223_Read();
if(current_state == TTP223_StableState)
{
return TTP223_EVENT_NONE;
}
/* 更新稳定状态,并根据新状态返回对应事件。 */
TTP223_StableState = current_state;
if(current_state == TTP223_TOUCHED)
{
return TTP223_EVENT_TOUCH;
}
return TTP223_EVENT_RELEASE;
}
TTP223.h代码
#ifndef __TTP223_H
#define __TTP223_H
#include "stm32f10x.h"
/* TTP223 的 OUT 引脚连接至 PB12,模块默认为高电平有效。 */
#define TTP223_GPIO_PORT GPIOB
#define TTP223_GPIO_PIN GPIO_Pin_12
#define TTP223_GPIO_CLK RCC_APB2Periph_GPIOB
/* 触摸状态切换时的消抖时间,单位:毫秒。 */
#define TTP223_DEBOUNCE_MS 20U
/* 消抖后的稳定触摸状态。 */
#define TTP223_RELEASED 0U
#define TTP223_TOUCHED 1U
/* TTP223 扫描事件:状态不变、触摸按下、触摸释放。 */
typedef enum
{
TTP223_EVENT_NONE = 0,
TTP223_EVENT_TOUCH,
TTP223_EVENT_RELEASE
} TTP223_EventTypeDef;
/* 初始化 PB12,并记录模块上电后的初始状态。 */
void TTP223_Init(void);
/* 直接读取 PB12 的瞬时电平,不进行消抖。 */
u8 TTP223_Read(void);
/* 获取最近一次经过消抖确认的稳定状态。 */
u8 TTP223_GetState(void);
/* 扫描并返回经过消抖确认的触摸或释放事件。 */
TTP223_EventTypeDef TTP223_Scan(void);
#endif
六、实物演示章节
6.1 实物接线搭建
把 STM32 最小系统板、TTP223 触摸模块、OLED 屏幕按照上面表格接线,接线完成检查:
- 确认所有 GND 共地;TTP223 接 5V 供电,OLED 接 3.3V;
- TTP223 OUT 引脚确认接 PB12;OLED SCL 接 PB8,SDA 接 PB9;
- 确认 TTP223 硬件模式为高电平有效、直接输出模式。
烧录程序之后,上电,上电前手指不要放在触摸片上,TTP223 上电需要约 0.5 秒做基准校准,校准阶段触摸检测不正常。
6.2 现象观察
- 没有触摸:OLED 显示
STATE:RELEASED,COUNT 保持不变; - 手指触摸感应片:屏幕立刻切换
STATE:TOUCHED,触摸计数 + 1; - 手指持续按住不放:状态保持 TOUCHED,计数不会持续上涨;
- 松开手指:变回 RELEASED,计数保持不变;
- 反复触摸松开,COUNT 数字不断累加,到 99999 之后再次触摸自动归零。

拓展观察:可以用万用表测量 TTP223 的 OUT 引脚电压,触摸时输出接近 5V 高电平,松开回到低电平。
6.3 常见问题排查
遇到触摸乱触发、触摸没反应,按照下面顺序排查:
- 检查供电、地线,确认全部共地,接线牢固;
- 确认模块硬件模式:高电平有效、直接模式;
- 重新上电,上电 0.5s 校准时间手不要碰触摸电极;
- OUT 信号线尽量缩短,远离开关电源、电机等强干扰源;
- 修改触摸铜箔面积,调整模块灵敏度,减少遮挡覆盖层厚度。
七、补充知识点
- TTP223 是硬件完成触摸判断,STM32 只做信号读取和软件抗干扰,不负责电容采样;
- FT 引脚虽然支持 5V 输入,但不代表可以长期乱接,尽量遵循芯片手册要求关闭内部上下拉;
- 电容触摸很容易受电源、地线、环境湿度影响,实际产品开发必须重视电源滤波和布线。
八、总结
手指靠近触摸电极,改变电极等效电容;TTP223 芯片把电容变化转换成 OUT 引脚高低电平;STM32 读取 PB12 引脚电平,软件做消抖复核识别触摸、释放事件;最后把触摸状态和触摸次数输出到 OLED 屏幕,完成整套工程功能。
更多推荐



所有评论(0)