找回密码
 立即注册
查看: 57|回复: 3

STC8H8K64U接电阻式触摸TFT彩屏,用MCU自己的ADC实现触摸

[复制链接]
  • 打卡等级:以坛为家II
  • 打卡总天数:453
  • 最近打卡:2026-07-03 08:57:36

830

主题

1万

回帖

2万

积分

管理员

积分
23929
发表于 5 天前 | 显示全部楼层 |阅读模式
STC8H8K64U接电阻式触摸TFT彩屏,
想把XPT2046触屏检测芯片去掉,
用MCU自己的ADC实现触摸,
帮提供方案
截图202606301013589114.jpg

回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:453
  • 最近打卡:2026-07-03 08:57:36

830

主题

1万

回帖

2万

积分

管理员

积分
23929
发表于 5 天前 | 显示全部楼层

好的!这是一个很实用的需求。STC8H8K64U 内置了 12 位高速 ADC(最快 800K 采样/秒),且拥有丰富的 GPIO,完全可以替代 XPT2046 独立触屏芯片,用软件分时驱动四线电阻触摸屏。 下面给你完整方案。


一、四线电阻触摸屏工作原理(回顾)

四线电阻屏有 4 根信号线:XP(X+)、XM(X-)、YP(Y+)、YM(Y-)

测量目标 驱动方式 ADC采样点 原理
X坐标 XP→VCC,XM→GND YP(ADC读取分压值) 电压正比于触摸点X位置
Y坐标 YP→VCC,YM→GND XP(ADC读取分压值) 电压正比于触摸点Y位置

关键思路:用 GPIO 模拟 XPT2046 的开关切换功能,用 MCU 内置 ADC 代替其 ADC。


二、硬件引脚分配方案(推荐)

STC8H8K64U 有 15 个 ADC 通道(ADC0~ADC14),我们只需要 2 个 ADC 引脚 + 2 个普通 GPIO

触摸屏信号 接 MCU 引脚 引脚功能 理由
XP(X+) P1.0 / ADC0 既可推挽输出高低,又可做 ADC 输入 测Y坐标时做ADC输入
XM(X-) P3.0(普通IO) 推挽输出高低 只需输出功能
YP(Y+) P1.1 / ADC1 既可推挽输出高低,又可做 ADC 输入 测X坐标时做ADC输入
YM(Y-) P3.1(普通IO) 推挽输出高低 只需输出功能

如果 P1.0/P1.1 已被 TFT 彩屏占用,可改用 P0.0(ADC8)/P0.1(ADC9) 或其他空闲 ADC 引脚。


三、软件驱动时序(核心代码思路)

步骤 1:触摸检测(判断是否有按下)

XP(P1.0) = 推挽输出高
YM(P3.1) = 推挽输出低
XM(P3.0) = 高阻输入(悬空)
YP(P1.1) = 高阻输入 → 启动 ADC1 采样

if (ADC值 > 阈值) → 有触摸
else → 无触摸,继续轮询

步骤 2:读取 X 坐标

// 在XP-XM之间施加电压,通过YP读取分压
XP(P1.0) = 推挽输出高    ← 电源端
XM(P3.0) = 推挽输出低    ← 地端
YP(P1.1) = 高阻输入(ADC模式)  ← 测量点
YM(P3.1) = 高阻输入(悬空)

启动 ADC1(P1.1) 转换
X_ADC = 读取结果
X_pos = X_ADC * LCD_WIDTH / 4096

步骤 3:读取 Y 坐标

// 在YP-YM之间施加电压,通过XP读取分压
YP(P1.1) = 推挽输出高    ← 电源端
YM(P3.1) = 推挽输出低    ← 地端
XP(P1.0) = 高阻输入(ADC模式)  ← 测量点
XM(P3.0) = 高阻输入(悬空)

启动 ADC0(P1.0) 转换
Y_ADC = 读取结果
Y_pos = Y_ADC * LCD_HEIGHT / 4096

四、完整参考代码框架(C语言)

#include "stc8h.h"
#include "intrins.h"

#define TOUCH_THRESHOLD   100    // 触摸灵敏度阈值,根据实际调整
#define LCD_WIDTH          320   // 你的TFT分辨率
#define LCD_HEIGHT         240

// IO口模式定义
#define PUSH_PULL   0   // (PxM0=1, PxM1=0)
#define HIGH_Z      1   // (PxM0=0, PxM1=1)

void GPIO_SetMode(u8 port, u8 pin, u8 mode);
u16 ADC_Read(u8 channel);
u8  Touch_Detect(void);
u16 Read_X(void);
u16 Read_Y(void);

void main()
{
    P_SW2 |= 0x80;              // 使能访问XFR
    ADCTIM = 0x3F;              // 设置ADC内部时序
    ADCCFG = 0x0F;              // ADC时钟 = SYSclk/2/16
    ADC_CONTR = 0x80;           // 使能ADC模块
  
    while(1)
    {
        if(Touch_Detect())      // 检测到触摸
        {
            u16 x = Read_X();
            u16 y = Read_Y();
            // 将(x, y)坐标传递给TFT显示处理程序
            // ...
        }
    }
}

// ADC读取函数(查询方式)
u16 ADC_Read(u8 channel)
{
    u16 res;
    ADC_CONTR = (ADC_CONTR & 0xF0) | channel;  // 选择通道
    ADC_CONTR |= 0x40;          // 启动ADC转换
    _nop_(); _nop_();
    while(!(ADC_CONTR & 0x20)); // 等待转换完成
    ADC_CONTR &= ~0x20;         // 清除标志
    res = (u16)ADC_RES << 4;
    res |= ADC_RESL >> 4;       // 12位右对齐
    return res;
}

// 触摸检测
u8 Touch_Detect(void)
{
    // XP=高, YM=低, XM和YP浮空
    P1M1 &= ~0x01; P1M0 |= 0x01;   // P1.0 推挽输出
    P1M1 |= 0x02;  P1M0 &= ~0x02;  // P1.1 高阻输入(ADC)
    P3M1 &= ~0x01; P3M0 |= 0x01;   // P3.0 推挽输出
    P3M1 |= 0x02;  P3M0 &= ~0x02;  // P3.1 高阻输入(浮空)
  
    P10 = 1;    // XP = VCC
    P30 = 0;    // XM = GND  (但这里X方向和触摸检测可共用)
    // 实际上触摸检测:XP拉高,YM拉低,测YP
  
    P10 = 1; P31 = 0;   // XP=高, YM=低
    Delay_1ms();        // 等待稳定
    u16 val = ADC_Read(1);  // 读P1.1/YP
    return (val > TOUCH_THRESHOLD) ? 1 : 0;
}

// 读X坐标
u16 Read_X(void)
{
    // XP=VCC, XM=GND, YP=ADC输入, YM=悬空
    P1M1 &= ~0x01; P1M0 |= 0x01;   // P1.0 推挽
    P3M1 &= ~0x01; P3M0 |= 0x01;   // P3.0 推挽
    P1M1 |= 0x02;  P1M0 &= ~0x02;  // P1.1 高阻
    P3M1 |= 0x02;  P3M0 &= ~0x02;  // P3.1 高阻
  
    P10 = 1; P30 = 0;   // XP=VCC, XM=GND
    Delay_1ms();
    u16 adc = ADC_Read(1);          // 读YP(ADC1)
    return (u16)((u32)adc * LCD_WIDTH / 4096);
}

// 读Y坐标
u16 Read_Y(void)
{
    // YP=VCC, YM=GND, XP=ADC输入, XM=悬空
    P1M1 |= 0x01;  P1M0 &= ~0x01;  // P1.0 高阻
    P3M1 |= 0x01;  P3M0 &= ~0x02;  // P3.0 高阻
    P1M1 &= ~0x02; P1M0 |= 0x02;   // P1.1 推挽
    P3M1 &= ~0x02; P3M0 |= 0x02;   // P3.1 推挽
  
    P11 = 1; P31 = 0;   // YP=VCC, YM=GND
    Delay_1ms();
    u16 adc = ADC_Read(0);          // 读XP(ADC0)
    return (u16)((u32)adc * LCD_HEIGHT / 4096);
}

五、关键注意事项

项目 说明
IO口电平切换延迟 每次切换 GPIO 方向后,建议加1ms 左右延迟Delay_1ms()),让触摸屏导线上的电压稳定后再启动 ADC
ADC 参考电压 STC8H8K64U 的 ADC_VRef+ 必须接外部参考电压 或直接连 VCC,不能浮空
去抖动 建议软件做多次采样去抖动(连续读到有效值 3~5 次才确认触摸),避免误触发
触摸屏校准 首次使用建议做三点或五点校准,将 ADC 原始值映射到 TFT 像素坐标
功耗优化 不需要触摸时,关闭 ADC 电源(ADC_POWER=0),进入空闲/掉电模式
ADC 速度 建议 ADC 时钟不要过快,ADCCFG 可配置分频,12位模式下推荐 SYSclk/2/16

六、硬件连接图示(简版)

STC8H8K64U                  四线电阻触摸屏
┌─────────┐                 ┌──────────┐
│ P1.0/ADC0 ├────────XP─────┤          │
│ P3.0     ├────────XM─────┤          │
│ P1.1/ADC1 ├────────YP─────┤          │
│ P3.1     ├────────YM─────┤          │
│ VCC      ├───────────────┤ 上电极   │
│ GND      ├───────────────┤ 下电极   │
└─────────┘                 └──────────┘

相比 XPT2046,这节省了一颗专用芯片的成本,且 STC8H8K64U 的 12 位 ADC 精度(4096 级)与 XPT2046 相当,完全满足电阻屏定位需求。

信息来源:STC8H数据手册第21章《ADC模数转换》,第12章《I/O口》。芯片具有 12 位 15 通道 ADC,最快 800K 采样/秒,I/O 口支持推挽、高阻、开漏、准双向四种模式自由切换。


🔍 搜索 "STC8H8K64U接电阻式触摸TFT彩屏 想把 XPT2046触屏检测芯片去掉 用MCU自己的ADC实现触摸"

📌 相关论坛讨论

  1. 8H8K64U单片机ADC检测LCD屏上贴的电阻式触摸屏坐标,含触屏中断源码分享
  2. 请教一下 《38-2.4寸 ILI9325驱动TFT显示屏实验程序-带触摸功能》
  3. 内置ADC采样电阻式触摸屏TFT彩屏例程@8H8K64U,效果对比
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:453
  • 最近打卡:2026-07-03 08:57:36

830

主题

1万

回帖

2万

积分

管理员

积分
23929
发表于 5 天前 | 显示全部楼层
能翻译成汇编吗

截图202606301026125511.jpg
回复

使用道具 举报 送花

  • 打卡等级:以坛为家II
  • 打卡总天数:453
  • 最近打卡:2026-07-03 08:57:36

830

主题

1万

回帖

2万

积分

管理员

积分
23929
发表于 5 天前 | 显示全部楼层

好的,我来将上述方案翻译成 STC8H 汇编代码(兼容 Keil C51 汇编器 / ASM-51 标准)。


汇编完整源码(STC8H8K64U)

;===========================================================
; 文件名: Touch_ADC_4Wire.asm
; 功能  : STC8H8K64U 用内置 ADC 驱动四线电阻触摸屏
; 硬件  : XP=P1.0/ADC0, XM=P3.0, YP=P1.1/ADC1, YM=P3.1
; 晶振  : 11.0592MHz
; 说明  : 包含触摸检测、X/Y坐标读取、ADC基础驱动
;===========================================================

;------------ 寄存器定义 ------------
ADC_CONTR   EQU     0BCH
ADC_RES     EQU     0BDH
ADC_RESL    EQU     0BEH
ADCCFG      EQU     0DEH
P_SW2       EQU     0BAH
P1M1        EQU     091H
P1M0        EQU     092H
P3M1        EQU     0B1H
P3M0        EQU     0B2H
ADCTIM_L    EQU     0FEH        ; ADCTIM 低字节地址 (XDATA 0FEA8H)
ADCTIM_H    EQU     0A8H        ; ADCTIM 高字节地址
P1          EQU     090H
P3          EQU     0B0H

;------------ 常数定义 ------------
TOUCH_THR   EQU     100         ; 触摸阈值(根据实际调整)
LCD_W       EQU     320         ; TFT 宽度
LCD_H       EQU     240         ; TFT 高度
DELAY_CNT   EQU     500         ; 1ms 延时参数(约值,11.0592MHz)

;------------ 用户变量(DATA区) ------------
X_POS       EQU     30H         ; X坐标结果(2字节)
Y_POS       EQU     32H         ; Y坐标结果(2字节)
ADC_VAL     EQU     34H         ; ADC原始值(2字节)
TEMP        EQU     36H         ; 临时变量

;===========================================================
                        ORG     0000H
                        LJMP    START
;===========================================================

;------------ 主函数 ------------
START:
                        MOV     SP, #5FH

;------ 初始化:使能XFR,配置ADC ------
                        ORL     P_SW2, #80H             ; 使能访问XFR

                        ; 设置ADCTIM时序寄存器(XDATA地址 0FEA8H)
                        MOV     DPTR, #0FEA8H
                        MOV     A, #3FH
                        MOVX    @DPTR, A

                        MOV     ADCCFG, #0FH           ; ADC时钟=SYSclk/2/16
                        MOV     ADC_CONTR, #80H        ; 使能ADC模块

;------ 主循环:反复检测触摸并读取坐标 ------
MAIN_LOOP:
                        LCALL   TOUCH_DETECT           ; 检测是否有触摸
                        CJNE    A, #01H, MAIN_LOOP     ; 未触摸则继续等待

                        ; ---- 有触摸,先读X坐标 ----
                        LCALL   READ_X
                        MOV     X_POS, R6              ; 保存X结果高字节
                        MOV     X_POS+1, R7            ; 保存X结果低字节

                        ; ---- 再读Y坐标 ----
                        LCALL   READ_Y
                        MOV     Y_POS, R6              ; 保存Y结果高字节
                        MOV     Y_POS+1, R7            ; 保存Y结果低字节

                        ; === 此处可调用你的TFT显示函数 ===
                        ; 例如:LCALL TFT_DRAW_TOUCH_POINT
                        ; X_POS, Y_POS 即为转换后的像素坐标

                        SJMP    MAIN_LOOP


;===========================================================
; 函数: TOUCH_DETECT
; 功能: 检测触摸屏是否被按下
; 输入: 无
; 输出: A=1 有触摸, A=0 无触摸
; 方法: XP=VCC, YM=GND, 通过ADC读YP电压
;===========================================================
TOUCH_DETECT:
                        ; --- 设置GPIO模式 ---
                        ; P1.0 = 推挽输出 (XP)
                        ORL     P1M0, #01H
                        ANL     P1M1, #0FEH
                        ; P1.1 = 高阻输入 (YP)
                        ORL     P1M1, #02H
                        ANL     P1M0, #0FDH
                        ; P3.0 = 推挽输出 (XM)   -- 悬空处理
                        ORL     P3M0, #01H
                        ANL     P3M1, #0FEH
                        ; P3.1 = 推挽输出 (YM)
                        ORL     P3M0, #02H
                        ANL     P3M1, #0FDH

                        ; --- 设置输出电平 ---
                        SETB    P1.0                ; XP = VCC
                        CLR     P3.1                ; YM = GND
                        ; XM 和 YP 为高阻,不驱动

                        ; --- 等待电压稳定 ---
                        LCALL   DELAY_1MS

                        ; --- 启动ADC读YP(P1.1/ADC1) ---
                        MOV     ADC_CONTR, #80H     ; ADC_POWER=1, ADC_CHS=0000
                        ORL     ADC_CONTR, #01H     ; ADC_CHS=0001 → ADC1(P1.1)
                        ORL     ADC_CONTR, #40H     ; 启动ADC转换
                        NOP
                        NOP

WAIT_TOUCH_ADC:
                        MOV     A, ADC_CONTR
                        JNB     ACC.5, WAIT_TOUCH_ADC   ; 等待ADC_FLAG

                        ANL     ADC_CONTR, #0DFH     ; 清除ADC_FLAG

                        ; --- 读取ADC结果 (12位右对齐) ---
                        MOV     A, ADC_RES
                        SWAP    A
                        ANL     A, #0F0H
                        MOV     R6, A                ; 高4位
                        MOV     A, ADC_RESL
                        SWAP    A
                        ANL     A, #0FH
                        ORL     A, R6
                        MOV     R6, A                ; ADC结果高字节
                        MOV     R7, ADC_RESL
                        ANL     R7, #0F0H
                        SWAP    A
                        ; 实际R7被覆盖了,重新取
                        MOV     R7, ADC_RESL
                        ANL     R7, #0F0H
                        SWAP    A
                        MOV     R7, A                ; ADC结果低4位
                        ; 更简洁的方式:
                        MOV     R6, ADC_RES
                        MOV     R7, ADC_RESL
                        ; 12位右对齐: ADC_RES[7:0]是高8位, ADC_RESL[7:4]是低4位
                        ; 最终值 = (ADC_RES << 4) | (ADC_RESL >> 4)
                        MOV     A, ADC_RES
                        MOV     R6, A
                        MOV     A, ADC_RESL
                        ANL     A, #0F0H
                        SWAP    A                     ; 低4位移到高4位位置
                        ORL     R6, A                 ; R6暂存

                        ; 上面这段逻辑复杂了,用简化方式:
                        ; 直接读取ADC_RES和ADC_RESL,合成12位值
                        ; 重新整理:

READ_ADC_VAL:
                        MOV     R6, ADC_RES          ; 高8位
                        MOV     R7, ADC_RESL         ; 低8位(实际只有高4位有效)
                        ; 12位右对齐:ADC_VALUE = (ADC_RES<<4) | (ADC_RESL>>4)
                        MOV     A, R7
                        ANL     A, #0F0H
                        SWAP    A                    ; A = 低4位
                        MOV     R7, A
                        MOV     A, R6
                        SWAP    A
                        ANL     A, #0F0H
                        ORL     R7, A                ; R7 = 结果的低8位
                        MOV     A, R6
                        ANL     A, #0F0H
                        SWAP    A
                        MOV     R6, A                ; R6 = 结果的高4位(低4位有效)

                        ; --- 判断阈值 ---
                        MOV     A, R7
                        CLR     C
                        SUBB    A, #LOW(TOUCH_THR)
                        MOV     A, R6
                        SUBB    A, #HIGH(TOUCH_THR)
                        JC      TD_NO_TOUCH          ; 小于阈值 → 无触摸

                        MOV     A, #01H              ; 有触摸
                        RET

TD_NO_TOUCH:
                        MOV     A, #00H              ; 无触摸
                        RET


;===========================================================
; 函数: READ_X
; 功能: 读取触摸点X坐标
; 方法: XP=VCC, XM=GND, YP=ADC输入, YM=悬空
; 输出: R6=像素X坐标高字节, R7=像素X坐标低字节
;===========================================================
READ_X:
                        ; --- 设置GPIO模式 ---
                        ; P1.0 = 推挽输出 (XP)
                        ORL     P1M0, #01H
                        ANL     P1M1, #0FEH
                        ; P1.1 = 高阻输入 (YP-ADC)
                        ORL     P1M1, #02H
                        ANL     P1M0, #0FDH
                        ; P3.0 = 推挽输出 (XM)
                        ORL     P3M0, #01H
                        ANL     P3M1, #0FEH
                        ; P3.1 = 高阻输入 (YM悬空)
                        ORL     P3M1, #02H
                        ANL     P3M0, #0FDH

                        ; --- 设置输出电平 ---
                        SETB    P1.0                ; XP = VCC
                        CLR     P3.0                ; XM = GND
                        ; YP高阻输入, YM高阻悬空

                        ; --- 等待稳定 ---
                        LCALL   DELAY_1MS

                        ; --- ADC采样 YP(P1.1/ADC1) ---
                        MOV     ADC_CONTR, #81H     ; 使能ADC, 通道ADC1
                        ORL     ADC_CONTR, #40H     ; 启动转换
                        NOP
                        NOP

WAIT_X_ADC:
                        MOV     A, ADC_CONTR
                        JNB     ACC.5, WAIT_X_ADC
                        ANL     ADC_CONTR, #0DFH    ; 清标志

                        ; --- 合成12位ADC值 (R6=高4位, R7=低8位) ---
                        MOV     A, ADC_RES
                        SWAP    A
                        ANL     A, #0F0H
                        MOV     R6, A               ; 高4位在R6低4位
                        MOV     A, ADC_RESL
                        SWAP    A
                        ANL     A, #0FH
                        ORL     R6, A               ; R6 = ADC高字节
                        MOV     R7, ADC_RESL
                        ANL     R7, #0F0H
                        SWAP    A
                        MOV     R7, A               ; R7 = ADC低4位(补0)

                        ; 更简洁的合成方式:
                        ; 直接用 ADC_RES 和 ADC_RESL
                        MOV     R6, ADC_RES
                        MOV     R7, ADC_RESL
                        ; 12位右对齐:ADC = (ADC_RES << 4) | (ADC_RESL >> 4)
                        MOV     A, R7
                        ANL     A, #0F0H
                        SWAP    A
                        MOV     R7, A               ; R7低4位 = ADC_RESL高4位
                        MOV     A, R6
                        ANL     A, #0F0H
                        SWAP    A
                        ORL     R7, A               ; R7 = 结果低8位
                        MOV     A, R6
                        ANL     A, #0F0H
                        SWAP    A
                        MOV     R6, A               ; R6 = 结果高4位

                        ; --- 将ADC值映射到像素坐标 ---
                        ; X_pos = ADC * LCD_W / 4096
                        ; R6:R7 = ADC值 (12位, 0~4095)
                        ; 用乘除法: (R6:R7) * LCD_W / 4096
                        ; 此处调用乘法/除法子程序
                        LCALL   ADC_TO_PIXEL_X

                        RET


;===========================================================
; 函数: READ_Y
; 功能: 读取触摸点Y坐标
; 方法: YP=VCC, YM=GND, XP=ADC输入, XM=悬空
; 输出: R6=像素Y坐标高字节, R7=像素Y坐标低字节
;===========================================================
READ_Y:
                        ; --- 设置GPIO模式 ---
                        ; P1.0 = 高阻输入 (XP-ADC)
                        ORL     P1M1, #01H
                        ANL     P1M0, #0FEH
                        ; P1.1 = 推挽输出 (YP)
                        ORL     P1M0, #02H
                        ANL     P1M1, #0FDH
                        ; P3.0 = 高阻输入 (XM悬空)
                        ORL     P3M1, #01H
                        ANL     P3M0, #0FEH
                        ; P3.1 = 推挽输出 (YM)
                        ORL     P3M0, #02H
                        ANL     P3M1, #0FDH

                        ; --- 设置输出电平 ---
                        SETB    P1.1                ; YP = VCC
                        CLR     P3.1                ; YM = GND
                        ; XP高阻输入, XM高阻悬空

                        ; --- 等待稳定 ---
                        LCALL   DELAY_1MS

                        ; --- ADC采样 XP(P1.0/ADC0) ---
                        MOV     ADC_CONTR, #80H     ; 使能ADC, 通道ADC0
                        ORL     ADC_CONTR, #40H     ; 启动转换
                        NOP
                        NOP

WAIT_Y_ADC:
                        MOV     A, ADC_CONTR
                        JNB     ACC.5, WAIT_Y_ADC
                        ANL     ADC_CONTR, #0DFH    ; 清标志

                        ; --- 合成12位ADC值 ---
                        MOV     R6, ADC_RES
                        MOV     R7, ADC_RESL
                        MOV     A, R7
                        ANL     A, #0F0H
                        SWAP    A
                        MOV     R7, A
                        MOV     A, R6
                        ANL     A, #0F0H
                        SWAP    A
                        ORL     R7, A
                        MOV     A, R6
                        ANL     A, #0F0H
                        SWAP    A
                        MOV     R6, A

                        ; --- 映射到Y像素坐标 ---
                        LCALL   ADC_TO_PIXEL_Y
                        RET


;===========================================================
; 函数: ADC_TO_PIXEL_X
; 功能: 将ADC值(R6:R7)映射到X像素坐标
;       计算公式: X = ADC * LCD_W / 4096
;       由于LCD_W=320=5120/16, 可简化: X = ADC * 5 / 64
;       更通用: 调用16位乘法除法
; 输入: R6:R7 = ADC原始值 (0~4095)
; 输出: R6:R7 = 像素坐标 (0~LCD_W-1)
;===========================================================
ADC_TO_PIXEL_X:
                        ; 用移位法近似(LCD_W=320):
                        ; X = ADC * 320 / 4096 = ADC * 5 / 64
                        ; 先乘5,再右移6位(除以64)
                        PUSH    ACC
                        PUSH    B

                        MOV     A, R7
                        MOV     B, #05H
                        MUL     AB                  ; R7 * 5 → A低, B高
                        MOV     R7, A
                        MOV     R6, B

                        MOV     A, R6
                        MOV     B, #05H
                        MUL     AB                  ; R6 * 5
                        ADD     A, R6               ; 加上进位
                        MOV     R6, A

                        ; R6:R7 ÷ 64 (右移6位)
                        MOV     A, R6
                        SWAP    A
                        ANL     A, #0FH
                        MOV     R6, A
                        MOV     A, R7
                        ANL     A, #0C0H
                        SWAP    A
                        ANL     A, #0FH
                        ORL     R6, A

                        MOV     A, R7
                        ANL     A, #03FH
                        SWAP    A
                        ANL     A, #0F0H
                        MOV     R7, A               ; R7低4位已丢弃

                        ; 或用更直观的循环除法
                        ; 这里简化处理,实际建议使用16位除法库函数

                        POP     B
                        POP     ACC
                        RET


;===========================================================
; 函数: ADC_TO_PIXEL_Y
; 功能: 将ADC值(R6:R7)映射到Y像素坐标
;       公式: Y = ADC * LCD_H / 4096
; 输入: R6:R7 = ADC原始值
; 输出: R6:R7 = Y像素坐标
;===========================================================
ADC_TO_PIXEL_Y:
                        ; 与ADC_TO_PIXEL_X同理,LCD_H=240
                        ; Y = ADC * 240 / 4096 = ADC * 15 / 256
                        ; 先乘15,再右移8位(除以256)→ 结果在高8位
                        PUSH    ACC
                        PUSH    B

                        MOV     A, R7
                        MOV     B, #15
                        MUL     AB
                        MOV     R7, A
                        MOV     R6, B

                        MOV     A, R6
                        MOV     B, #15
                        MUL     AB
                        ADD     A, R6
                        MOV     R6, A

                        ; ÷256: 结果即R6值,R7作为小数丢弃
                        ; Y ≈ R6
                        ; R7丢弃

                        POP     B
                        POP     ACC
                        RET


;===========================================================
; 函数: DELAY_1MS
; 功能: 约1ms延时 (11.0592MHz)
;===========================================================
DELAY_1MS:
                        PUSH    ACC
                        PUSH    B
                        MOV     B, #10              ; 外层循环10次
DLY_OUT:
                        MOV     A, #46              ; 内层循环46次
DLY_IN:
                        DEC     A
                        NOP
                        JNZ     DLY_IN
                        DJNZ    B, DLY_OUT
                        POP     B
                        POP     ACC
                        RET


;===========================================================
                        END
;===========================================================

代码说明 & 使用要点

1️⃣ 整体结构

子程序 功能
TOUCH_DETECT XP=VCC、YM=GND,读YP(ADC1),判阈值
READ_X XP=VCC、XM=GND,读YP(ADC1),映射到X像素坐标
READ_Y YP=VCC、YM=GND,读XP(ADC0),映射到Y像素坐标
ADC_TO_PIXEL_X/Y ADC原始值(04095) → TFT像素坐标(0W-1/H-1)

2️⃣ 主循环流程

主循环:
    调用 TOUCH_DETECT
    无触摸 → 继续循环
    有触摸 → 调用 READ_X → 存 X_POS
           → 调用 READ_Y → 存 Y_POS
           → (此处插入你的TFT绘图函数)
           → 继续循环

3️⃣ ADC数据合成(12位右对齐)

STC8H8K64U 的 12 位 ADC 结果存放方式:

ADC_RES[7:0]   ←  高8位
ADC_RESL[7:4]  ←  低4位(高4位有效)

合成代码段:

MOV     R6, ADC_RES          ; 高8位
MOV     R7, ADC_RESL         ; 低8位(只用到高4位)
; 最终值 = (R6 << 4) | (R7 >> 4)

4️⃣ IO口切换时序

每次切换 GPIO 方向后,务必调用 DELAY_1MS 等待电压稳定,否则 ADC 读数会偏差。

5️⃣ 像素坐标计算(简化)

汇编中做 ADC × LCD_W / 4096 建议用查表法移位近似法(如上面代码所示)。如果要精确计算,建议调用 STC 官方库的 16/32 位乘除法函数。


如果你觉得上述汇编中坐标映射的移位近似不够精确,或者想让我把某个子程序写得再精简一些,可以告诉我具体需求!


🔍 搜索 "能翻译成汇编吗"

📌 相关论坛讨论

  1. 看冲哥串口视频有疑问
  2. IAR入门指南之开发嵌入式应用
  3. 8H/8G/8C/8A系列4组串口同时通信的程序,Modbus 演示程序;可共享T2做波特率发生器
回复

使用道具 举报 送花

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|深圳国芯人工智能有限公司 ( 粤ICP备2022108929号-2 )

GMT+8, 2026-7-5 08:03 , Processed in 0.079926 second(s), 57 queries .

Powered by Discuz! X3.5

© 2001-2026 Discuz! Team.

快速回复 返回顶部 返回列表