STC32G12K128接电阻式触摸TFT彩屏, 用MCU自己的ADC实现触摸检测
STC32G12K128接电阻式触摸TFT彩屏,用MCU自己的ADC实现触摸检测,
想把XPT2046触摸屏检测芯片去掉,
帮提供方案
<p>好的,我来为您整理 <strong>STC32G12K128 片内 ADC 直驱 4 线电阻触摸屏、去掉 XPT2046 的完整方案</strong>。</p>
<hr />
<h2>✅ 方案可行性结论</h2>
<p><strong>完全可以</strong>。STC32G12K128 内置 <strong>12位高速ADC(15通道)</strong>,性能足够替代 XPT2046 实现电阻触摸检测。论坛已有成功先例:</p>
<blockquote>
<p><strong>网友实测:</strong> 利用 STC32G12K128 的 ADC 直连电阻触摸 TFT 彩屏,<strong>手写识别效果很好</strong>。<br />
—— 来源:<a href="https://www.stcaimcu.com/forum.php?mod=viewthread&tid=11264">STC 论坛 #11264</a>(乘风*** 帖 & 神*** 回复确认)</p>
</blockquote>
<hr />
<h2>🔧 方案原理</h2>
<h3>4 线电阻触摸屏结构</h3>
<p>触摸屏有 4 根线:<strong>X+、X-、Y+、Y-</strong></p>
<table>
<thead>
<tr>
<th>检测内容</th>
<th>供电方向</th>
<th>从哪根线读取电压</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>X 坐标</strong></td>
<td>X+ → VCC, X- → GND</td>
<td>Y+(或 Y-)上测电压</td>
</tr>
<tr>
<td><strong>Y 坐标</strong></td>
<td>Y+ → VCC, Y- → GND</td>
<td>X+(或 X-)上测电压</td>
</tr>
<tr>
<td><strong>触摸检测</strong></td>
<td>任一方向通电后,检测 ADC 值是否变化</td>
<td>—</td>
</tr>
</tbody>
</table>
<hr />
<h2>🔌 硬件接线方案(推荐)</h2>
<p>用 STC32G12K128 <strong>4 个 I/O 口</strong>接触摸屏的 4 根线,其中至少 <strong>2 个必须是 ADC 通道</strong>:</p>
<table>
<thead>
<tr>
<th>触摸屏引脚</th>
<th>接 MCU 引脚</th>
<th>功能说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>X+</strong></td>
<td><strong>P1.0 / ADC0</strong></td>
<td>既可当 ADC 输入(读 Y 坐标),也可推挽输出 VCC</td>
</tr>
<tr>
<td><strong>X-</strong></td>
<td><strong>P1.1 / ADC1</strong> 或 普通 I/O</td>
<td>既可当 ADC 输入,也可推挽输出 GND</td>
</tr>
<tr>
<td><strong>Y+</strong></td>
<td><strong>P1.4 / ADC4</strong> 或 普通 I/O</td>
<td>推挽输出 VCC(读 X 坐标时)或高阻输入(读 Y 坐标)</td>
</tr>
<tr>
<td><strong>Y-</strong></td>
<td><strong>P1.5 / ADC5</strong> 或 普通 I/O</td>
<td>推挽输出 GND(读 X 坐标时)或高阻输入(读 Y 坐标)</td>
</tr>
</tbody>
</table>
<blockquote>
<p><strong>引脚选择建议:</strong> STC32G12K128 的 ADC 通道有 ADC0<del>ADC14,分布在 P1.0/P1.1/P1.4</del>P1.7、P0.0~P0.7 等引脚(详见手册第4章管脚功能表)。<br />
建议选 <strong>P1 口(P1.0/P1.1/P1.4/P1.5)</strong>,它们自带 ADC 功能,并且不和 TFT 并口/LCM 接口冲突。</p>
</blockquote>
<h3>Vref+ 必须处理</h3>
<p>STC32G12K128 的 <strong>Vref+(第20脚)</strong> 不能浮空,必须接:</p>
<ul>
<li><strong>方案 A(推荐):</strong> Vref+ 直接短接到 <strong>VCC</strong>,用 VCC 作 ADC 基准(论坛案例即用此法)</li>
<li><strong>方案 B:</strong> 外接精密基准(如 TL431/REF3025)</li>
</ul>
<hr />
<h2>🧠 软件控制逻辑</h2>
<h3>步骤一:检测触摸(是否有按下)</h3>
<pre><code>X+ 推挽输出高,X- 推挽输出低(或反之)
Y+、Y- 设为高阻输入,不参与
ADC 读取 Y+(或 Y-)上的电压
若 ADC 值在合理范围内 → 有触摸
</code></pre>
<h3>步骤二:读取 X 坐标</h3>
<pre><code>X+ → 推挽输出高
X- → 推挽输出低
Y+ → 高阻输入(作为 ADC 采样脚)
Y- → 高阻输入(悬空)
ADC 通道切换到 Y+(如 ADC4)读取电压值
</code></pre>
<h3>步骤三:读取 Y 坐标</h3>
<pre><code>Y+ → 推挽输出高
Y- → 推挽输出低
X+ → 高阻输入(作为 ADC 采样脚,如 ADC0)
X- → 高阻输入(悬空)
ADC 通道切换到 X+(如 ADC0)读取电压值
</code></pre>
<h3>提高效率的技巧</h3>
<p>论坛回复中提到:</p>
<blockquote>
<p><strong>"用 DMA 来支持 ADC,这样减少 CPU 的压力 —— STC32G12K128 有 DMA 支持 ADC"</strong>(来源:神*** 回复,帖子 #10867)</p>
</blockquote>
<p>STC32G 手册第 <strong>30 章 DMA</strong> 支持 ADC→内存传输,可实现<strong>自动连续采样</strong>,CPU 只需读取最终结果,大幅提升触摸响应速度。</p>
<hr />
<h2>⚠️ 注意事项</h2>
<table>
<thead>
<tr>
<th>注意事项</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>I/O 模式切换</strong></td>
<td>检测时需快速切换 I/O 的推挽输出/高阻模式,注意设置 PxM0/PxM1 寄存器</td>
</tr>
<tr>
<td><strong>ADC 时序</strong></td>
<td>ADC 时钟 = sysclk/2/分频系数,建议设置 ADCTIM 和 ADCCFG 优化采样速度</td>
</tr>
<tr>
<td><strong>校准</strong></td>
<td>四角校准法:触摸屏四角采集 ADC 值,建立线性映射关系</td>
</tr>
<tr>
<td><strong>手写 vs 菜单</strong></td>
<td>做菜单按键效果很好;手写可接受但精度不如专用芯片(XPT2046)</td>
</tr>
<tr>
<td><strong>触摸中断</strong></td>
<td>可将某根线接到带中断的 I/O 口(如 INT0/INT1),实现触摸唤醒省电</td>
</tr>
</tbody>
</table>
<hr />
<h2>📚 参考资料</h2>
<ol>
<li><strong>STC32G 数据手册</strong> — 第 22 章 ADC(12位ADC寄存器及例程)、第 30 章 DMA</li>
<li><strong>论坛成功案例</strong>:
<ul>
<li><a href="https://www.stcaimcu.com/forum.php?mod=viewthread&tid=11264">内置ADC采样电阻式触摸屏TFT彩屏例程@8H8K64U,效果对比</a>(含 STC32G12K128 实测)</li>
<li><a href="https://www.stcaimcu.com/forum.php?mod=viewthread&tid=10867">8H8K64U单片机ADC检测LCD屏上贴的电阻式触摸屏坐标,含触屏中断源码分享</a>(含源码工程下载)</li>
</ul>
</li>
</ol>
<p>如果您需要,我可以进一步提供具体的初始化代码框架或引脚分配方案。</p>
<hr />
<p><a href="https://www.stcaimcu.com/plugin.php?id=twpx_xunsearch&mod=forum&q=STC32G12K128%E6%8E%A5%E7%94%B5%E9%98%BB%E5%BC%8F%E8%A7%A6%E6%91%B8TFT%E5%BD%A9%E5%B1%8F%20%E7%94%A8MCU%E8%87%AA%E5%B7%B1%E7%9A%84ADC%E5%AE%9E%E7%8E%B0%E8%A7%A6%E6%91%B8%E6%A3%80%E6%B5%8B%20%E6%83%B3%E6%8A%8A%20XPT2046%E8%A7%A6%E6%91%B8%E5%B1%8F%E6%A3%80%E6%B5%8B%E8%8A%AF%E7%89%87%E5%8E%BB%E6%8E%89&f=_all&m=yes&syn=yes&s=relevance&fid=0">🔍 搜索 "STC32G12K128接电阻式触摸TFT彩屏 用MCU自己的ADC实现触摸检测 想把 XPT2046触摸屏检测芯片去掉"</a></p>
<p><strong>📌 相关论坛讨论</strong></p>
<ol>
<li><a href="https://www.stcaimcu.com/forum.php?mod=viewthread&tid=24546&highlight=STC32G12K128%E6%8E%A5%E7%94%B5%E9%98%BB%E5%BC%8F%E8%A7%A6%E6%91%B8TFT%E5%BD%A9%E5%B1%8F%EF%BC%8C%0A%E7%94%A8MCU%E8%87%AA%E5%B7%B1%E7%9A%84ADC%E5%AE%9E%E7%8E%B0%E8%A7%A6%E6%91%B8%E6%A3%80%E6%B5%8B%EF%BC%8C%0A%E6%83%B3%E6%8A%8AXPT2046%E8%A7%A6%E6%91%B8%E5%B1%8F%E6%A3%80%E6%B5%8B%E8%8A%AF%E7%89%87%E5%8E%BB%E6%8E%89%EF%BC%8C%0A%0A%E5%B8%AE%E6%8F%90%E4%BE%9B%E6%96%B9%E6%A1%88&page=1&extra=#pid221758">STC8H8K64U接电阻式触摸TFT彩屏,用MCU自己的ADC实现触摸</a></li>
<li><a href="https://www.stcaimcu.com/forum.php?mod=viewthread&tid=20091&highlight=STC32G12K128%E6%8E%A5%E7%94%B5%E9%98%BB%E5%BC%8F%E8%A7%A6%E6%91%B8TFT%E5%BD%A9%E5%B1%8F%EF%BC%8C%0A%E7%94%A8MCU%E8%87%AA%E5%B7%B1%E7%9A%84ADC%E5%AE%9E%E7%8E%B0%E8%A7%A6%E6%91%B8%E6%A3%80%E6%B5%8B%EF%BC%8C%0A%E6%83%B3%E6%8A%8AXPT2046%E8%A7%A6%E6%91%B8%E5%B1%8F%E6%A3%80%E6%B5%8B%E8%8A%AF%E7%89%87%E5%8E%BB%E6%8E%89%EF%BC%8C%0A%0A%E5%B8%AE%E6%8F%90%E4%BE%9B%E6%96%B9%E6%A1%88&page=1&extra=#pid186234">请教一下 《38-2.4寸 ILI9325驱动TFT显示屏实验程序-带触摸功能》</a></li>
<li><a href="https://www.stcaimcu.com/forum.php?mod=viewthread&tid=20075&highlight=STC32G12K128%E6%8E%A5%E7%94%B5%E9%98%BB%E5%BC%8F%E8%A7%A6%E6%91%B8TFT%E5%BD%A9%E5%B1%8F%EF%BC%8C%0A%E7%94%A8MCU%E8%87%AA%E5%B7%B1%E7%9A%84ADC%E5%AE%9E%E7%8E%B0%E8%A7%A6%E6%91%B8%E6%A3%80%E6%B5%8B%EF%BC%8C%0A%E6%83%B3%E6%8A%8AXPT2046%E8%A7%A6%E6%91%B8%E5%B1%8F%E6%A3%80%E6%B5%8B%E8%8A%AF%E7%89%87%E5%8E%BB%E6%8E%89%EF%BC%8C%0A%0A%E5%B8%AE%E6%8F%90%E4%BE%9B%E6%96%B9%E6%A1%88&page=1&extra=#pid186042">请帮忙推荐一个试验箱</a></li>
</ol>
有具体的参考程序吗
<p>好的,以下是为 <strong>STC32G12K128</strong> 量身整理的完整参考程序。程序基于 <strong>4 线电阻触摸屏</strong> 的驱动原理,使用片内 <strong>12位ADC</strong> 分时切换测量 X/Y 坐标,并包含触摸检测功能。</p>
<hr />
<h2>📁 参考程序(C语言,适用于 STC32G12K128)</h2>
<pre><code class="language-c">/******************************************************************************
* 文件名:Touch_ADC_STC32G12K128.c
* 功能:使用 STC32G12K128 片内 ADC 驱动 4 线电阻触摸屏
* 替代 XPT2046 触摸检测芯片
* 硬件连接:
* 触摸屏 X+→ P1.0 (ADC0) — 既是ADC输入,也做驱动输出
* 触摸屏 X-→ P1.1 (ADC1) — 既是ADC输入,也做驱动输出
* 触摸屏 Y+→ P1.4 (ADC4) — 既是ADC输入,也做驱动输出
* 触摸屏 Y-→ P1.5 (ADC5) — 既是ADC输入,也做驱动输出
* Vref+ → 接 VCC(用VCC做ADC基准)
* 工作频率 :11.0592MHz / 40MHz 均可
******************************************************************************/
#include "stc32g.h"
#include "intrins.h"
// 触摸屏引脚定义(可自行修改)
#define TOUCH_XP_PIN 1 // P1.0
#define TOUCH_XM_PIN 1 // P1.1
#define TOUCH_YP_PIN 4 // P1.4
#define TOUCH_YM_PIN 5 // P1.5
#define ADC_XP_CH 0 // ADC通道0 → P1.0
#define ADC_XM_CH 1 // ADC通道1 → P1.1
#define ADC_YP_CH 4 // ADC通道4 → P1.4
#define ADC_YM_CH 5 // ADC通道5 → P1.5
// 触摸阈值(根据实际屏体调试)
#define TOUCH_THRESHOLD 200 // 低于此值认为有触摸按下
// 触摸坐标结构体
typedef struct {
uint16_t x;
uint16_t y;
uint8_tpressed;
} TouchPoint_t;
// 全局变量
TouchPoint_t g_tTouch;
//---------------------------------------------------------------------------
// 函数原型
void Touch_GPIO_Init(void);
void Touch_ADC_Init(void);
uint16_t Touch_ReadADC(uint8_t ch);
void Touch_SetDrive_X(void); // X方向供电
void Touch_SetDrive_Y(void); // Y方向供电
void Touch_SetIdle(void); // 高阻空闲
uint8_t Touch_DetectPress(void);
uint16_t Touch_ReadX(void);
uint16_t Touch_ReadY(void);
void Touch_GetPoint(TouchPoint_t *pt);
void delay_us(uint16_t us);
//---------------------------------------------------------------------------
// GPIO初始化:所有触摸引脚设为高阻输入
void Touch_GPIO_Init(void)
{
// P1.0, P1.1, P1.4, P1.5 设为高阻输入(ADC模式)
P1M0 &= ~(0x33); // P1.0/P1.1/P1.4/P1.5 的M0位清零
P1M1 |=(0x33); // P1.0/P1.1/P1.4/P1.5 的M1位置1 → 高阻
}
//---------------------------------------------------------------------------
// ADC初始化(12位,右对齐,最快速度)
void Touch_ADC_Init(void)
{
EAXFR = 1; // 使能访问XFR
ADCTIM = 0x3F; // ADC内部时序:最长采样时间
ADCCFG = 0x20 | 0x00; // bit5(RESFMT)=1: 右对齐;SPEED=0: 最快速度
ADC_POWER = 1; // 使能ADC模块
delay_us(10); // 等待ADC稳定
}
//---------------------------------------------------------------------------
// 读取单次ADC值(查询方式)
uint16_t Touch_ReadADC(uint8_t ch)
{
uint16_t res;
ADC_CONTR = (ADC_CONTR & 0xF0) | ch; // 选择ADC通道
ADC_START = 1; // 启动转换
_nop_(); _nop_();
while (!ADC_FLAG); // 等待转换完成
ADC_FLAG = 0; // 清除标志
res = ((uint16_t)ADC_RES << 8) | ADC_RESL;// 12位结果(右对齐)
return res;
}
//---------------------------------------------------------------------------
// X方向供电:X+ → VCC,X- → GND
// Y+、Y- 为高阻输入,作为ADC采样点
void Touch_SetDrive_X(void)
{
// X+ (P1.0) → 推挽输出高
P1M0 |= 0x01; P1M1 &= ~0x01;
P10 = 1;
// X- (P1.1) → 推挽输出低
P1M0 |= 0x02; P1M1 &= ~0x02;
P11 = 0;
// Y+ (P1.4)、Y- (P1.5) → 高阻输入(ADC采样)
P1M0 &= ~0x30;P1M1 |= 0x30;
}
//---------------------------------------------------------------------------
// Y方向供电:Y+ → VCC,Y- → GND
// X+、X- 为高阻输入,作为ADC采样点
void Touch_SetDrive_Y(void)
{
// Y+ (P1.4) → 推挽输出高
P1M0 |= 0x10; P1M1 &= ~0x10;
P14 = 1;
// Y- (P1.5) → 推挽输出低
P1M0 |= 0x20; P1M1 &= ~0x20;
P15 = 0;
// X+ (P1.0)、X- (P1.1) → 高阻输入(ADC采样)
P1M0 &= ~0x03;P1M1 |= 0x03;
}
//---------------------------------------------------------------------------
// 全部引脚恢复高阻(空闲状态/省电)
void Touch_SetIdle(void)
{
P1M0 &= ~0x33;
P1M1 |= 0x33;
}
//---------------------------------------------------------------------------
// 检测是否有触摸按下
uint8_t Touch_DetectPress(void)
{
uint16_t val;
// 随便选一个方向供电,看ADC是否有变化
Touch_SetDrive_X();
delay_us(5);
// 从Y+读取电压
val = Touch_ReadADC(ADC_YP_CH);
Touch_SetIdle();
// 有触摸时ADC值较低(相当于分压接地)
// 无触摸时IO浮空,ADC值接近满量程(4095)
if (val < TOUCH_THRESHOLD)
return 1; // 检测到触摸
else
return 0; // 无触摸
}
//---------------------------------------------------------------------------
// 读取X坐标
uint16_t Touch_ReadX(void)
{
uint16_t val;
Touch_SetDrive_X();
delay_us(5);
// X方向供电时,在Y+上读取X坐标分压
val = Touch_ReadADC(ADC_YP_CH);
Touch_SetIdle();
return val; // 原始ADC值,范围0~4095
}
//---------------------------------------------------------------------------
// 读取Y坐标
uint16_t Touch_ReadY(void)
{
uint16_t val;
Touch_SetDrive_Y();
delay_us(5);
// Y方向供电时,在X+上读取Y坐标分压
val = Touch_ReadADC(ADC_XP_CH);
Touch_SetIdle();
return val; // 原始ADC值,范围0~4095
}
//---------------------------------------------------------------------------
// 一次完整的触摸采样(含消抖、坐标读取)
void Touch_GetPoint(TouchPoint_t *pt)
{
uint8_t i;
uint32_t sum_x = 0, sum_y = 0;
// 检测触摸
if (!Touch_DetectPress())
{
pt->pressed = 0;
pt->x = 0;
pt->y = 0;
return;
}
// 连续采样8次取平均(软件滤波)
for (i = 0; i < 8; i++)
{
sum_x += Touch_ReadX();
sum_y += Touch_ReadY();
delay_us(2);
}
pt->x = (uint16_t)(sum_x >> 3); // 除以8
pt->y = (uint16_t)(sum_y >> 3);
pt->pressed = 1;
}
//---------------------------------------------------------------------------
// 简易延时
void delay_us(uint16_t us)
{
uint16_t i;
while (us--)
{
i = 12; // 11.0592MHz下约1us
while (i--);
}
}
//---------------------------------------------------------------------------
// 坐标校准:四角校准法(示例:将ADC值映射到LCD分辨率)
// 假设 LCD 分辨率为 320×240
// 需先采集触摸屏四角的ADC原始值:
// 左上(x_min,y_min),右下(x_max,y_max)
void Touch_Calibrate(uint16_t *px, uint16_t *py,
uint16_t x_min, uint16_t x_max,
uint16_t y_min, uint16_t y_max,
uint16_t lcd_w,uint16_t lcd_h)
{
// 注意:电阻触摸屏的X/Y通常与LCD反向
// 这里做线性映射
if (*px > x_max) *px = x_max;
if (*px < x_min) *px = x_min;
if (*py > y_max) *py = y_max;
if (*py < y_min) *py = y_min;
*px = (uint16_t)((uint32_t)(*px - x_min) * lcd_w / (x_max - x_min));
*py = (uint16_t)((uint32_t)(*py - y_min) * lcd_h / (y_max - y_min));
}
//---------------------------------------------------------------------------
// 主函数(示例)
void main(void)
{
uint16_t lcd_x, lcd_y;
// 系统初始化
WTST = 0x00; // 程序代码等待参数设为0(最快)
CKCON = 0x00; // 外部数据总线速度为最快
EAXFR = 1;
Touch_GPIO_Init();
Touch_ADC_Init();
// 这里加入您的 TFT LCD 初始化代码(如 ILI9341/ILI9488 等)
while (1)
{
Touch_GetPoint(&g_tTouch);
if (g_tTouch.pressed)
{
// 原始ADC值 → LCD像素坐标(需四角校准后使用)
lcd_x = g_tTouch.x;
lcd_y = g_tTouch.y;
// 使用校准函数(需先标定四角坐标)
// Touch_Calibrate(&lcd_x, &lcd_y,
// x_min, x_max, y_min, y_max,
// 320, 240);
// 将触摸坐标用于您的应用...
// 例如:在触摸点画一个点、响应菜单按键等
}
else
{
// 无触摸时的处理(如进入省电模式)
}
// 避免采样过快
delay_us(1000);
}
}
</code></pre>
<hr />
<h2>🧪 关键要点说明</h2>
<table>
<thead>
<tr>
<th>要点</th>
<th>说明</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>引脚选择</strong></td>
<td>P1.0/P1.1/P1.4/P1.5 兼具 ADC 功能,且不与 TFT 并口/LCM 接口冲突,是首选</td>
</tr>
<tr>
<td><strong>Vref+处理</strong></td>
<td><strong>必须接 VCC 或外部基准电压</strong>,不能浮空(手册第22章明确要求)</td>
</tr>
<tr>
<td><strong>I/O模式切换</strong></td>
<td>测量时需要把供电引脚切为<strong>推挽输出</strong>,采样引脚切为 <strong>高阻输入</strong></td>
</tr>
<tr>
<td><strong>触摸检测</strong></td>
<td>Y+上读电压:有触摸时ADC值低(屏体受压导通),无触摸时ADC接近满量程</td>
</tr>
<tr>
<td><strong>软件滤波</strong></td>
<td>程序中做了<strong>8次采样取平均</strong>,有效降低噪声抖动</td>
</tr>
<tr>
<td><strong>四角校准</strong></td>
<td>使用 <code>Touch_Calibrate()</code> 做线性映射,将ADC原始值转为LCD像素坐标</td>
</tr>
</tbody>
</table>
<hr />
<h2>📚 已有例程/源码获取</h2>
<p>除了上面的参考代码,您还可以从以下渠道获取 <strong>可直接编译运行的完整工程</strong>:</p>
<h3>1️⃣ 屠龙刀-STC32G12K128 官方例程包</h3>
<ul>
<li>帖子:<a href="https://www.stcaimcu.com/forum.php?mod=viewthread&tid=1939">屠龙刀-STC32G12K128核心功能实验板程序包</a></li>
<li>内含 <strong>ADC轮询例程(16路ADC)</strong>,可直接参考ADC配置</li>
<li>下载地址:STC官网 → 实验箱/开发板页面</li>
</ul>
<h3>2️⃣ 实验箱8.3例程(ILI9341 + 触摸)</h3>
<ul>
<li>下载地址:<strong>https://www.stcai.com/syx</strong></li>
<li>帖子 <a href="https://www.stcaimcu.com/forum.php?mod=viewthread&tid=11264">#11264</a> 的附件例子,针对 <strong>2.4寸ILI9341</strong> 屏</li>
<li>接线修改:将触摸电路断开后连接到 <strong>P1.4~P1.7</strong>,ADC基准改为 <strong>VCC</strong></li>
<li><strong>已确认 STC32G12K128 在此方案下手写识别效果很好</strong></li>
</ul>
<h3>3️⃣ 8H8K64U 触摸源码(原理完全通用)</h3>
<ul>
<li>帖子 <a href="https://www.stcaimcu.com/forum.php?mod=viewthread&tid=10867">#10867</a> 附件 <strong>"ST7571工程.zip"</strong>(190KB)</li>
<li>虽然是8H系列+ST7571驱动,但 <strong>触摸ADC采样的核心逻辑</strong> 与STC32G完全一致,直接参考</li>
</ul>
<h3>4️⃣ 使用 DMA 提升性能</h3>
<blockquote>
<p>论坛管理员神*** 建议:<strong>"用 DMA 来支持 ADC,这样减少 CPU 的压力 — STC32G12K128 有 DMA 支持 ADC"</strong>(帖子 #10867 回复)</p>
</blockquote>
<p>查阅 STC32G 手册第 <strong>30 章 DMA</strong>,可实现 ADC→内存自动传输,无需 CPU 逐次查询,大幅提升触摸响应速度。</p>
<hr />
<p>如果您需要,我可以进一步帮您将上述代码适配到您的具体 <strong>LCD型号(如ILI9341/ILI9488/ST7789等)</strong> 和 <strong>屏幕分辨率</strong>,或者给出 <strong>DMA+ADC</strong> 的优化版本。</p>
<hr />
<p><a href="https://www.stcaimcu.com/plugin.php?id=twpx_xunsearch&mod=forum&q=%E6%9C%89%E5%85%B7%E4%BD%93%E7%9A%84%E5%8F%82%E8%80%83%E7%A8%8B%E5%BA%8F%E5%90%97&f=_all&m=yes&syn=yes&s=relevance&fid=0">🔍 搜索 "有具体的参考程序吗"</a></p>
<p><strong>📌 相关论坛讨论</strong></p>
<ol>
<li><a href="https://www.stcaimcu.com/forum.php?mod=viewthread&tid=11104&highlight=%E6%9C%89%E5%85%B7%E4%BD%93%E7%9A%84%E5%8F%82%E8%80%83%E7%A8%8B%E5%BA%8F%E5%90%97&page=1&extra=#pid111184">我是怎样用 CosyOS构建系统的</a></li>
<li><a href="https://www.stcaimcu.com/forum.php?mod=viewthread&tid=6979&highlight=%E6%9C%89%E5%85%B7%E4%BD%93%E7%9A%84%E5%8F%82%E8%80%83%E7%A8%8B%E5%BA%8F%E5%90%97&page=1&extra=#pid61402">关于单片机与PC之间的USB通讯问题</a></li>
<li><a href="https://www.stcaimcu.com/forum.php?mod=viewthread&tid=3404&highlight=%E6%9C%89%E5%85%B7%E4%BD%93%E7%9A%84%E5%8F%82%E8%80%83%E7%A8%8B%E5%BA%8F%E5%90%97&page=1&extra=#pid22626">再次论述嵌入式系统现代编程的认知模型</a></li>
</ol>
建议增加一项:检测接触电阻,以免轻轻点击时位置飘移。
参考:
https://www.cnblogs.com/we-hjb/archive/2009/12/16/1626020.html
lcwswust 发表于 2026-6-30 10:43
建议增加一项:检测接触电阻,以免轻轻点击时位置飘移。
参考:
https://www.cnblogs.com/we-hjb/archive/2 ...
帮提供详细案例,方便大家学习,完善 STC【AI助手】知识库 神农鼎 发表于 2026-6-30 10:55
帮提供详细案例,方便大家学习,完善 STC【AI助手】知识库
参考链接中给了公式,能算出接触电阻,我也只是很久以前试过一次,
之后未经太多的测试,不保证准确性,仅供参考:
#define BIT(x) (1<<(x))
#define IOSET(port,x)(port)|=(x)
#define IOCLR(port,x)(port)&=~(x)
#define X0_H IOSET(P1,BIT(0))
#define X0_L IOCLR(P1,BIT(0))
#define X0_IN {IOCLR(P1M1,BIT(0));IOSET(P1M0,BIT(0)}
#define X0_OUT {IOCLR(P1M0,BIT(0));IOSET(P1M1,BIT(0)}
#define X0_UP {IOCLR(P1M1,BIT(0));IOCLR(P1M0,BIT(0));IOSET(P1,BIT(0));}
#define X1_H IOSET(P1,BIT(2))
#define X1_L IOCLR(P1,BIT(2))
#define X1_IN {IOCLR(P1M1,BIT(2));IOSET(P1M0,BIT(2)}
#define X1_OUT {IOCLR(P1M0,BIT(2));IOSET(P1M1,BIT(2)}
#define X1_UP {IOCLR(P1M1,BIT(2));IOCLR(P1M0,BIT(2));IOSET(P1,BIT(2));}
#define Y0_H IOSET(P1,BIT(1))
#define Y0_L IOCLR(P1,BIT(1))
#define Y0_IN {IOCLR(P1M1,BIT(1));IOSET(P1M0,BIT(1)}
#define Y0_OUT {IOCLR(P1M0,BIT(1));IOSET(P1M1,BIT(1)}
#define Y0_UP {IOCLR(P1M1,BIT(1));IOCLR(P1M0,BIT(1));IOSET(P1,BIT(1));}
#define Y1_H IOSET(P1,BIT(3))
#define Y1_L IOCLR(P1,BIT(3))
#define Y1_IN {IOCLR(P1M1,BIT(3));IOSET(P1M0,BIT(3)}
#define Y1_OUT {IOCLR(P1M0,BIT(3));IOSET(P1M1,BIT(3)}
#define Y1_UP {IOCLR(P1M1,BIT(3));IOCLR(P1M0,BIT(3));IOSET(P1,BIT(3));}
//读取x的AD
#define readadx0() adc_read(0)
//读取y的AD
#define readady0() adc_read(1)
//读取x脚的电平状态
#define readiox() (P1&BIT(2))
//x上拉
#define X_UP {IOCLR(P1M1,BIT(0)+BIT(2));IOCLR(P1M0,BIT(0)+BIT(2));IOSET(P1,BIT(0)+BIT(2));}
//X置为输入
#define X_IN {IOCLR(P1M1,BIT(0)+BIT(2));IOSET(P1M0,BIT(0)+BIT(2));}
//X置为输出
#define X_OUT {IOCLR(P1M0,BIT(0)+BIT(2));IOSET(P1M1,BIT(0)+BIT(2));}
#define Y_IN {IOCLR(P1M1,BIT(1)+BIT(3));IOSET(P1M0,BIT(1)+BIT(3));}
#define Y_OUT {IOCLR(P1M0,BIT(1)+BIT(3));IOSET(P1M1,BIT(1)+BIT(3));}
//x1,y1 置为输出
#define Z_OUT {IOCLR(P1M0,BIT(2)+BIT(3));IOSET(P1M1,BIT(2)+BIT(3));}
#define Z_IN {IOCLR(P1M1,BIT(2)+BIT(3));IOSET(P1M0,BIT(2)+BIT(3));}
//--------------------------------------------------
//相关变量
//--------------------------------------------------
#define BUFCNT 5
U16 xbuf,ybuf;
//--------------------------------------------------
//取得x座标
//--------------------------------------------------
U16 TS_getx(void)
{
U16 x;
//Y0_L;Y1_L;delayms(1);//放电
//Y_IN;
X0_H;X1_L;X_OUT;delayus(100);//delayms(1);
readady0();
x=readady0();
//X0_L;delayms(1);
X_IN;
return x;
}
//--------------------------------------------------
//取得y座标
//--------------------------------------------------
U16 TS_gety(void)
{
U16 y;
Y0_H;Y1_L;Y_OUT;delayus(100);//delayms(1);
readadx0();
y=readadx0();
//Y0_L;delayms(1);
Y_IN;
return y;
}
//--------------------------------------------------
//取得是否被按下的状态
//--------------------------------------------------
U8 TS_gets(void)
{
U8 s;
Y0_L;Y1_L;Y_OUT;
X0_H;X1_H;X_OUT;delayus(100);//delayms(1);//放电
X_UP;delayms(1);//X上拉输入
if(readiox()==0)
s=1;
else
s=0;
//X0_L;X1_L;delayms(1);
X_IN;Y_IN;
return s;
}
//--------------------------------------------------
//取得触摸电阻
//x1,y1 为输出
//--------------------------------------------------
void TS_getz(U16* Vz1,U16* Vz2)
{
// U16 z1,z2;
X1_H;Y1_L;Z_OUT;delayus(100);//delayms(1);
readadx0();
*Vz1=readadx0();
readady0();
*Vz2=readady0();
//Y0_L;delayms(1);
Z_IN;
}
//--------------------------------------------------
//n个数里求平均值(n>=3)
//--------------------------------------------------
U16 average(U16 a[],U8 n)
{
U16 max,min,ave=0,sum=0;
U8 i;
if(n<3)return 0;
max=a;
min=a;
for(i=0;i<n;i++)
{
if(max<a)max=a;
if(min>a)min=a;
sum+=a;
}
ave=(sum-min-max)/(n-2);
return ave;
}
//--------------------------------------------------
//获取坐标及是否按下
//--------------------------------------------------
void Touch_GetData(U8 *ud,U16 *x,U16 *y)
{
U8s,i;
U16 Vz1,Vz2;
U16 tempy,Rt;
s=TS_gets();
if(s)
{
for(i=0;i<BUFCNT;i++)
{
xbuf=TS_getx();
tempy=TS_gety();
ybuf=tempy;
TS_getz(&Vz1,&Vz2);
if(Vz2==0)Vz2=1;//除数不能为0
Rt=(U32)tempy*(Vz1-Vz2)/Vz2;//接触电阻
if(Rt>1500)s=0;//接触电阻过大
}
if(s)s=TS_gets();
if(s)
{
*x=average(xbuf,BUFCNT);
*y=average(ybuf,BUFCNT);
}
}
*ud=s;
}
//--------------------------------------------------
//屏初始化
//--------------------------------------------------
void TS_init(void)
{
X_IN;//引脚置为输入
Y_IN;
}
//--------------------------------------------------
//主函数
//--------------------------------------------------
void main(void)
{
U16 x,y;
U8 w,s,s0;
init_devices();
while(1)
{
for(w=0;w<200;w++)
{
Touch_GetData(&s,&x,&y);
if(s)break;
if(s0)break;
delayms(1);
}
uart1_sendbyte(0xaa);
uart1_sendbyte(s);
uart1_sendbyte(x>>8);
uart1_sendbyte(x);
uart1_sendbyte(y>>8);
uart1_sendbyte(y);
s0=s;
}
}
lcwswust 发表于 2026-6-30 11:21
参考链接中给了公式,能算出接触电阻,我也只是很久以前试过一次,
良好的经验参考
后来者可参考设计应用 lcwswust 发表于 2026-6-30 11:21
参考链接中给了公式,能算出接触电阻,我也只是很久以前试过一次,
帮给个 STC8H8K64U的帮 8位世界也前进下
STC8H8K64U接电阻式触摸TFT彩屏,用MCU自己的ADC实现触摸 - TFT彩屏,触摸屏,DMA-i8080/M6800并口自动刷屏,DMA-SPI刷屏,外设直接到外设 国芯人工智能技术交流网站 - AI32位8051交流社区
神农鼎 发表于 2026-6-30 11:35
帮给个 STC8H8K64U的帮 8位世界也前进下
STC8H8K64U接电阻式触摸TFT彩屏,用MCU自己的ADC实现触摸 - TFT彩 ...
不管8位、32位,原理是一样的。
刚翻了一下XPT2046的手册,其中的“压力测量”、“触摸电阻”也是一样的:
页:
[1]
2