Fix mode-select focus and touch pipeline; add return-to-home gesture.

Preserve focus across redraws, improve XPT2046 sampling, and log touch coords via RTT for ongoing debug.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
yuquanjun 2026-08-31 11:13:01 +08:00
parent b996c8876e
commit b8eaf2c808
9 changed files with 259 additions and 190 deletions

View File

@ -1,64 +1,46 @@
#include "includes.h"
/* ============================================================================
* app_touch
*
* Touch_Process
* IDLE PRESS_WAIT_STABLE PRESS_STABLE SLIDING
*
*
* 20ms (TOUCH_STABLE_TIME)
* 10px (TOUCH_SLIDE_THRESH)
* 5px (TOUCH_SLIDE_STEP)
* 1000ms (TOUCH_LONG_PRESS_TIME)
* 120ms (TOUCH_REPEAT_INTERVAL)
* ==========================================================================*/
/* 按下即发点击;抬起仅补发未发出的短按 */
/* ==================== 状态机枚举 ==================== */
typedef enum {
TOUCH_IDLE, /* 空闲 */
TOUCH_PRESS_WAIT_STABLE, /* 按下,等待稳定判定 */
TOUCH_PRESS_STABLE, /* 稳定按下(可长按) */
TOUCH_SLIDING /* 滑动中 */
TOUCH_IDLE,
TOUCH_PRESS_WAIT_STABLE,
TOUCH_PRESS_STABLE,
TOUCH_SLIDING
} touch_state_t;
/* ==================== 时序参数 ==================== */
#define TOUCH_STABLE_TIME 20 /* 按下稳定判定时间 ms */
#define TOUCH_SLIDE_THRESH 10 /* 进入滑动的最小位移 px */
#define TOUCH_SLIDE_STEP 5 /* 滑动事件最小步进 px */
#define TOUCH_LONG_PRESS_TIME 1000 /* 长按触发 ms */
#define TOUCH_REPEAT_INTERVAL 120 /* 长按重复间隔 ms */
#define TOUCH_STABLE_TIME 8
#define TOUCH_SLIDE_THRESH 12
#define TOUCH_SLIDE_STEP 5
#define TOUCH_LONG_PRESS_TIME 800
#define TOUCH_REPEAT_INTERVAL 120
/* ==================== 状态变量 ==================== */
static touch_state_t touch_state = TOUCH_IDLE;
static uint16_t down_x = 0;
static uint16_t down_y = 0;
static uint32_t touch_tick = 0;
static uint32_t repeat_tick = 0;
static uint8_t long_press_fired = 0;
static uint8_t click_sent = 0;
static uint16_t last_slide_x = 0;
static uint16_t last_slide_y = 0;
/* 取绝对值(避免引入 math.h */
static inline uint16_t abs_diff(int16_t a, int16_t b)
{
int16_t d = a - b;
return (d < 0) ? (uint16_t)(-d) : (uint16_t)d;
}
/* ==================== 重置 ==================== */
void app_touch_reset(void)
{
touch_state = TOUCH_IDLE;
down_x = down_y = 0;
touch_tick = repeat_tick = 0;
long_press_fired = 0;
click_sent = 0;
last_slide_x = last_slide_y = 0;
}
/* ==================== 手势识别 ==================== */
app_touch_result_t app_touch_process(uint16_t x, uint16_t y, uint8_t pressed)
{
app_touch_result_t r;
@ -68,22 +50,25 @@ app_touch_result_t app_touch_process(uint16_t x, uint16_t y, uint8_t pressed)
uint32_t now = rt_tick_get();
/* ---------- 抬起处理 ---------- */
if (!pressed) {
/* 若曾稳定按下且未触发长按 → 释放(可当作 TAP */
if (touch_state == TOUCH_PRESS_STABLE && !long_press_fired) {
if (!long_press_fired && !click_sent &&
(touch_state == TOUCH_PRESS_WAIT_STABLE ||
touch_state == TOUCH_PRESS_STABLE))
{
r.gesture = GESTURE_RELEASE;
r.x = down_x; r.y = down_y; /* 用按下点作为释放坐标 */
r.x = down_x;
r.y = down_y;
MainTask_Sendmsg(MSG_ID_TOUCH, 1, down_x, down_y);
}
touch_state = TOUCH_IDLE;
down_x = down_y = 0;
last_slide_x = last_slide_y = 0;
touch_tick = repeat_tick = 0;
long_press_fired = 0;
click_sent = 0;
return r;
}
/* ---------- 按下处理 ---------- */
switch (touch_state)
{
case TOUCH_IDLE:
@ -91,29 +76,27 @@ app_touch_result_t app_touch_process(uint16_t x, uint16_t y, uint8_t pressed)
down_y = y;
touch_tick = now;
long_press_fired = 0;
click_sent = 0;
repeat_tick = 0;
touch_state = TOUCH_PRESS_WAIT_STABLE;
/* 第一帧就发点击,模式选择等页跟手 */
click_sent = 1;
MainTask_Sendmsg(MSG_ID_TOUCH, 1, down_x, down_y);
break;
case TOUCH_PRESS_WAIT_STABLE:
if ((now - touch_tick) >= TOUCH_STABLE_TIME) {
/* 位移小 → 进入稳定 */
if (abs_diff(x, down_x) < 8 && abs_diff(y, down_y) < 8) {
if (abs_diff(x, down_x) < 24 && abs_diff(y, down_y) < 24)
touch_state = TOUCH_PRESS_STABLE;
last_slide_x = down_x;
last_slide_y = down_y;
else {
down_x = x;
down_y = y;
touch_tick = now;
MainTask_Sendmsg(MSG_ID_TOUCH, 1, down_x, down_y);
} else {
/* 位移大 → 视为误触,回到空闲 */
touch_state = TOUCH_IDLE;
}
}
break;
case TOUCH_PRESS_STABLE:
{
/* ----- 长按检测 ----- */
if (!long_press_fired && (now - touch_tick) >= TOUCH_LONG_PRESS_TIME) {
long_press_fired = 1;
repeat_tick = now;
@ -121,14 +104,12 @@ app_touch_result_t app_touch_process(uint16_t x, uint16_t y, uint8_t pressed)
MainTask_Sendmsg(MSG_ID_TOUCH_LONG_REPEAT, 1, down_x, down_y);
return r;
}
/* ----- 长按重复 ----- */
if (long_press_fired && (now - repeat_tick) >= TOUCH_REPEAT_INTERVAL) {
repeat_tick = now;
r.gesture = GESTURE_REPEAT;
MainTask_Sendmsg(MSG_ID_TOUCH_LONG_REPEAT, 1, down_x, down_y);
return r;
}
/* ----- 位移进入滑动 ----- */
if (abs_diff(x, down_x) >= TOUCH_SLIDE_THRESH ||
abs_diff(y, down_y) >= TOUCH_SLIDE_THRESH) {
touch_state = TOUCH_SLIDING;
@ -136,15 +117,12 @@ app_touch_result_t app_touch_process(uint16_t x, uint16_t y, uint8_t pressed)
last_slide_y = y;
}
break;
}
case TOUCH_SLIDING:
{
/* 位移超过步进 → 产生拖动事件 */
if (abs_diff(x, last_slide_x) >= TOUCH_SLIDE_STEP ||
abs_diff(y, last_slide_y) >= TOUCH_SLIDE_STEP) {
r.gesture = GESTURE_DRAG;
r.down_x = last_slide_x; /* 记录上次位置,便于消费端算增量 */
r.down_x = last_slide_x;
r.down_y = last_slide_y;
MainTask_Sendmsg(MSG_ID_TOUCH, 1, x, y);
last_slide_x = x;
@ -152,12 +130,11 @@ app_touch_result_t app_touch_process(uint16_t x, uint16_t y, uint8_t pressed)
return r;
}
break;
}
default:
touch_state = TOUCH_IDLE;
break;
}
return r; /* 无手势 */
return r;
}

View File

@ -52,37 +52,33 @@ Fader_t faders[4] = {
const Touch_AreaTypeDef Touch_Areas[] =
{
// Xmin, Xmax, Ymin, Ymax, flag,value ID, action
{ 0, 60, 25, 90, -1, 0, GUI_TRANSPOSE, NULL },
{ 60, 120, 25, 90, 1, 0, GUI_TRANSPOSE, NULL },
/* Xmin,Xmax,Ymin,Ymax, Flag, Value, ID, action — 坐标相对 240x320 */
{ 0, 60, 25, 95, -1, 0, GUI_TRANSPOSE, NULL },
{ 60, 120, 25, 95, 1, 0, GUI_TRANSPOSE, NULL },
{ 125, 180, 25, 90, -1, 0, GUI_SPEED, NULL },
{ 180, 240, 25, 90, 1, 0, GUI_SPEED, NULL },
{ 125, 180, 25, 95, -1, 0, GUI_SPEED, NULL },
{ 180, 239, 25, 95, 1, 0, GUI_SPEED, NULL },
{ 0, 80, 90, 120, 0, 0, GUI_AUTOBAND_SW, NULL },
{ 90, 170, 90, 120, 0, 1, GUI_AUTOBAND_SW, NULL },
{ 80, 140, 0, 30, 0, 0, GUI_BL_SW, NULL },
{ 0, 85, 95, 130, 0, 0, GUI_AUTOBAND_SW, NULL },
{ 90, 175, 95, 130, 0, 1, GUI_AUTOBAND_SW, NULL },
{ 0, 120, 120, 150, -1, 0, GUI_MODE_PARAM, NULL },
{120, 240, 120, 150, 1, 0, GUI_MODE_PARAM, NULL },
{ 0, 120, 130, 165, -1, 0, GUI_MODE_PARAM, NULL },
{ 120, 239, 130, 165, 1, 0, GUI_MODE_PARAM, NULL },
{ 10, 120, 125, 150, -1, 0, GUI_MODE_PARAM, NULL },
{ 80, 140, 0, 30, 0, 0, GUI_MODE_PARAM, NULL },
{ 0, 117, 155, 200, -1, 0, GUI_TIMBRE_SELECT, NULL },
{ 120, 240, 155, 200, 1, 0, GUI_TIMBRE_SELECT, NULL },
{ 10, 50, 275, 340, 0,2, GUI_TAB_INDEX, NULL },
{ 70, 130, 275, 340, 0,0, GUI_TAB_INDEX, NULL },
{ 130, 170, 275, 340, 0,1, GUI_TAB_INDEX, NULL },
{ 190, 230, 275, 340, 0,3, GUI_TAB_INDEX, NULL },
{ 10, 60, 240, 320, 0,0, GUI_PLAY_SECTION, NULL },
{ 60, 110, 240, 320, 0,1, GUI_PLAY_SECTION, NULL },
{ 110, 170, 240, 320, 0,2, GUI_PLAY_SECTION, NULL },
{ 170, 220, 240, 320, 0,3, GUI_PLAY_SECTION, NULL },
{ 0, 120, 165, 215, -1, 0, GUI_TIMBRE_SELECT, NULL },
{ 120, 239, 165, 215, 1, 0, GUI_TIMBRE_SELECT, NULL },
/* 演奏段落 1~4 */
{ 10, 60, 220, 270, 0, 0, GUI_PLAY_SECTION, NULL },
{ 60, 110, 220, 270, 0, 1, GUI_PLAY_SECTION, NULL },
{ 110, 165, 220, 270, 0, 2, GUI_PLAY_SECTION, NULL },
{ 165, 220, 220, 270, 0, 3, GUI_PLAY_SECTION, NULL },
/* 底栏 TAB万能/普通/专业/设置Value=目标 TAB */
{ 0, 60, 275, 319, 0, 0, GUI_TAB_INDEX, NULL },
{ 60, 120, 275, 319, 0, 2, GUI_TAB_INDEX, NULL },
{ 120, 180, 275, 319, 0, 1, GUI_TAB_INDEX, NULL },
{ 180, 239, 275, 319, 0, 3, GUI_TAB_INDEX, NULL },
};
int16_t MIC_VOL_MAP[10]= {-9000,-7000,-5000,-3000,-1000,1000,3000,5000,7000,9000};

View File

@ -22,6 +22,28 @@ void RGB_Y_TO_G()
/* 模式选择页焦点0=万能 1=普通 2=专业,默认选中万能(与规范一致) */
static uint8_t s_mode_select_focus = 0;
extern bool InModeFlag;
static void UI_ModeSelect_DrawButtons(void);
static void UI_ModeSelect_SetFocus(uint8_t idx)
{
if (idx > 2 || idx == s_mode_select_focus)
return;
s_mode_select_focus = idx;
UI_ModeSelect_DrawButtons();
}
void UI_ReturnToModeSelect(void)
{
StartFlag = 0;
InModeFlag = false;
AutoBandTop1_Stop();
s_mode_select_focus = 0;
CallUI_Idle();
UI_DrawModeSelectScreen();
}
/* 0831 美工试用图:图标+MiSans 文字整行位图 */
static void UI_DrawModeSelectButton(uint16_t y, const uint8_t *row, uint8_t focused)
{
@ -45,15 +67,8 @@ static void UI_DrawModeSelectButton(uint16_t y, const uint8_t *row, uint8_t focu
LCD_WR_PIC_Trans(row_x, row_y, UI_MODE0831_ROW_W, UI_MODE0831_ROW_H, row, BLACK);
}
void UI_DrawModeSelectScreen(void)
static void UI_ModeSelect_DrawButtons(void)
{
UI_ClearFocus();
s_mode_select_focus = 0;
pCurrentTouch_Area = Touch_ModeSelect_Areas;
LCD_FillByColor(0, 0, 240, 320, BLACK);
label_top();
UI_DrawModeSelectButton(40,
gImage_Mode0831_Universal_Row_180_52,
s_mode_select_focus == 0);
@ -65,12 +80,21 @@ void UI_DrawModeSelectScreen(void)
s_mode_select_focus == 2);
}
void UI_DrawModeSelectScreen(void)
{
UI_ClearFocus();
pCurrentTouch_Area = Touch_ModeSelect_Areas;
LCD_FillByColor(0, 0, 240, 320, BLACK);
label_top();
UI_ModeSelect_DrawButtons();
}
const Touch_AreaTypeDef Touch_ModeSelect_Areas[] = {
/* Xmin,Xmax,Ymin,Ymax, Flag, Value, ID, action
* Flag=ID= TAB0Song / 1Expert / 2Free */
{ 10, 229, 40, 126, 0, 0, 0, NULL }, /* 万能模式 → SongMode */
{ 10, 229, 132, 218, 1, 0, 2, NULL }, /* 普通模式 → FreeMode */
{ 10, 229, 224, 310, 2, 0, 1, NULL }, /* 专业模式 → ExpertMode */
/* Flag=按钮序号(0万能/1普通/2专业)ID=进入 TAB */
{ 0, 239, 38, 127, 0, 0, 0, NULL },
{ 0, 239, 128, 219, 1, 0, 2, NULL },
{ 0, 239, 220, 311, 2, 0, 1, NULL },
};
#define TOUCH_AREA_MODE_SELECT_NUM (sizeof(Touch_ModeSelect_Areas)/sizeof(Touch_AreaTypeDef))
@ -156,7 +180,8 @@ void IdleProcess(DisplayTaskMessage_Type msg)
LCD_FillByColor(0, 0, 240, 320, WHITE);
LCD_WR_PIC_FROM_FLASH(40, 80, 168, 155, 0x00000000);
BSP_SelectAdcChannel(6);
wk_delay_ms(1000);
/* 让出 CPU避免忙等卡住触摸/主循环线程 */
rt_thread_mdelay(1000);
LoadConfig();
vol = ADC_ReadChannel(ADC_CHANNEL_1)>>5;
if (vol <= 5) level = 0;
@ -167,6 +192,7 @@ void IdleProcess(DisplayTaskMessage_Type msg)
else level = 5;
Send_volume(vol);
s_mode_select_focus = 0;
UI_DrawModeSelectScreen();
TM1629D_AllLedOn(LED_COLOR_G);
TM1629D_UpdateDisplay(0);
@ -190,12 +216,20 @@ void IdleProcess(DisplayTaskMessage_Type msg)
if( msg.HiByte >= Touch_ModeSelect_Areas[k].x_min && msg.HiByte <= Touch_ModeSelect_Areas[k].x_max &&
msg.LoByte >= Touch_ModeSelect_Areas[k].y_min && msg.LoByte <= Touch_ModeSelect_Areas[k].y_max )
{
uint8_t row = (uint8_t)Touch_ModeSelect_Areas[k].Flag;
if (row == s_mode_select_focus)
Touch_Mode_Select_Action(Touch_ModeSelect_Areas[k].Flag, Touch_ModeSelect_Areas[k].ID, k);
else
UI_ModeSelect_SetFocus(row);
break;
}
}
break;
case MSG_ID_TOUCH_LONG_REPEAT:
/* 模式页暂无长按动作 */
break;
case MSG_ID_BATTERY_VALUE:
Draw_Status_Battery_Icon(msg.ID);
break;

View File

@ -417,6 +417,12 @@ void UI_SongMode_Process(DisplayTaskMessage_Type msg)
break;
case MSG_ID_TOUCH_LONG_REPEAT:
{
/* 长按顶栏y<28返回三键模式选择页 */
if (msg.LoByte < 28)
{
UI_ReturnToModeSelect();
break;
}
for(uint8_t k=0; k<TOUCH_AREA_NUM; k++)
{
if( msg.HiByte >= pCurrentTouch_Area[k].x_min && msg.HiByte <= pCurrentTouch_Area[k].x_max &&

View File

@ -9,7 +9,7 @@ typedef enum {
extern const Touch_AreaTypeDef Touch_ModeSelect_Areas[];
extern void UI_DrawModeSelectScreen(void);
extern void UI_ReturnToModeSelect(void);
extern void IdleProcess(DisplayTaskMessage_Type xEvent);

View File

@ -7,6 +7,7 @@
#define LCD_DUMP_RTT_UP_CH 1
#define LCD_DUMP_RTT_DOWN_CH 0
#define LCD_DUMP_CMD "DUMP"
#define LCD_DUMP_TAP_CMD "TAP"
#define LCD_DUMP_MAGIC "SCRN"
#define LCD_DUMP_FMT_RGB565 1
#define LCD_DUMP_CMD_BUF_SIZE 16
@ -208,6 +209,15 @@ static uint8_t LCD_Dump_CommandPending(void)
s_cmd_buf[s_cmd_len++] = c;
s_cmd_buf[s_cmd_len] = '\0';
/* 合成点击:验证 UI 命中路径(点万能按钮中心) */
if (strstr(s_cmd_buf, LCD_DUMP_TAP_CMD) != NULL) {
s_cmd_len = 0U;
s_cmd_buf[0] = '\0';
MainTask_Sendmsg(MSG_ID_TOUCH, 1, 120, 80);
SEGGER_RTT_WriteString(0, "TAP inject 120,80\n");
continue;
}
if (c == 0x01 || strstr(s_cmd_buf, LCD_DUMP_CMD) != NULL) {
s_cmd_len = 0U;
s_cmd_buf[0] = '\0';

View File

@ -97,110 +97,148 @@ uint16_t TP_Read_AD(uint8_t cmd)
uint8_t i;
uint16_t adc_val = 0;
TP_CS_Clr(); // 片选拉低选中XPT2046
Delay_us(2); // 片选稳定时间
TP_Write_Byte(cmd); // MCU通过DIN发送命令XPT2046的DIN输入接收
// 等待XPT2046完成AD转换约6us转换期间OUT无有效数据
TP_CS_Clr();
Delay_us(2);
TP_Write_Byte(cmd);
Delay_us(6);
// 读取16位数据XPT2046通过自身OUT输出数据MCU通过OUT输入读取
for (i = 0; i < 16; i++)
{
adc_val <<= 1; // 左移,准备接收下一位
// 时钟上升沿XPT2046更新OUT引脚输出下降沿MCU读取OUT输入
adc_val <<= 1;
TP_CLK_Set();
Delay_us(1);
TP_CLK_Clr();
Delay_us(1);
// MCU读取OUT引脚的输入数据高12位有效低4位丢弃
if (TP_OUT_Read())
{
adc_val |= 0x01;
}
TP_CS_Set();
return adc_val >> 4;
}
TP_CS_Set(); // 释放片选
return adc_val >> 4; // 取高12位有效数据
}
// 简单去抖动读取连续n次相同状态视为有效
uint8_t TP_CheckPressed(uint8_t n)
{
uint8_t count = 0;
uint8_t i;
for (uint8_t i = 0; i < n; i++)
for (i = 0; i < n; i++)
{
if (TP_IRQ_Read() == 0)
{ // IRQ低电平表示按下
count++;
}
Delay_us(100);
}
return (count >= n/2) ? 1 : 0;
return (count >= (n / 2)) ? 1 : 0;
}
static uint16_t TP_SampleAxis(uint8_t cmd)
{
(void)TP_Read_AD(cmd);
Delay_us(15);
return TP_Read_AD(cmd);
}
// 读取原始坐标(未校准)
TP_Point TP_ReadRaw(void)
{
TP_Point p = {0, 0, 0};
uint32_t x_sum = 0, y_sum = 0;
uint8_t i;
if (!TP_CheckPressed(3))
{ // 检查触摸状态
return p;
}
// 多次读取取平均值,减少噪声
uint32_t x_sum = 0, y_sum = 0;
for (uint8_t i = 0; i < 5; i++)
for (i = 0; i < 5; i++)
{
x_sum += TP_Read_AD(XPT2046_READ_X);
y_sum += TP_Read_AD(XPT2046_READ_Y);
x_sum += TP_SampleAxis(XPT2046_READ_X);
Delay_us(15);
y_sum += TP_SampleAxis(XPT2046_READ_Y);
Delay_us(15);
}
p.x = x_sum / 5;
p.y = y_sum / 5;
p.pressed = 1;
p.x = (uint16_t)(x_sum / 5);
p.y = (uint16_t)(y_sum / 5);
/* Y 通道常为 0 时,交换 X/Y 命令再采一次 */
if (p.y < 80u && p.x > 80u)
{
uint32_t sx = 0, sy = 0;
for (i = 0; i < 3; i++)
{
sx += TP_SampleAxis(XPT2046_READ_Y);
Delay_us(15);
sy += TP_SampleAxis(XPT2046_READ_X);
Delay_us(15);
}
if (sy / 3u > p.y)
{
p.x = (uint16_t)(sx / 3);
p.y = (uint16_t)(sy / 3);
}
}
p.pressed = 1;
return p;
}
// 校准参数需实际触摸四个角后修改示例为240x320屏
#define CALIB_X_MIN 200 // 最小X原始值
#define CALIB_X_MAX 3800 // 最大X原始值
#define CALIB_Y_MIN 200 // 最小Y原始值
#define CALIB_Y_MAX 3800 // 最大Y原始值
#define LCD_WIDTH 240 // LCD宽度
#define LCD_HEIGHT 320 // LCD高度
#define CALIB_X_MIN 200
#define CALIB_X_MAX 3800
#define CALIB_Y_MIN 200
#define CALIB_Y_MAX 3800
/* 竖屏:多数 ILI9341+XPT2046 板级需 XY 对调X 镜像与历史 240-tp.x 一致 */
#define TP_SWAP_XY 1
#define TP_MIRROR_X 1
#define TP_MIRROR_Y 0
static uint16_t TP_MapAxis(uint16_t adc, uint16_t adc_min, uint16_t adc_max, uint16_t px_max)
{
int32_t v = (int32_t)adc;
int32_t a0 = (int32_t)adc_min;
int32_t a1 = (int32_t)adc_max;
int32_t span = a1 - a0;
int32_t px;
if (span <= 0)
return 0;
if (v < a0)
v = a0;
if (v > a1)
v = a1;
px = (v - a0) * (int32_t)px_max / span;
if (px < 0)
px = 0;
if (px > (int32_t)px_max)
px = (int32_t)px_max;
return (uint16_t)px;
}
// 校准后获取LCD坐标
TP_Point TP_Read(void)
{
// char Info[40];
TP_Point raw = TP_ReadRaw();
// sprintf (Info, "(x=%03d y=%03d) ", raw.x, raw.y);
// LCD_ShowString(2, 176+16, (const uint8_t*)Info, RED, WHITE, 16, 0);
TP_Point calib = {0, 0, raw.pressed};
uint16_t ax, ay;
if (!raw.pressed) {
if (!raw.pressed)
return calib;
}
// 线性映射将原始ADC值转换为LCD像素坐标
calib.x = (raw.x - CALIB_X_MIN) * LCD_WIDTH / (CALIB_X_MAX - CALIB_X_MIN);
calib.y = (raw.y - CALIB_Y_MIN) * LCD_HEIGHT / (CALIB_Y_MAX - CALIB_Y_MIN);
#if TP_SWAP_XY
ax = TP_MapAxis(raw.y, CALIB_Y_MIN, CALIB_Y_MAX, (uint16_t)(LCD_W - 1));
ay = TP_MapAxis(raw.x, CALIB_X_MIN, CALIB_X_MAX, (uint16_t)(LCD_H - 1));
#else
ax = TP_MapAxis(raw.x, CALIB_X_MIN, CALIB_X_MAX, (uint16_t)(LCD_W - 1));
ay = TP_MapAxis(raw.y, CALIB_Y_MIN, CALIB_Y_MAX, (uint16_t)(LCD_H - 1));
#endif
// 边界限制
if (calib.x > LCD_WIDTH - 1) calib.x = LCD_WIDTH - 1;
if (calib.x == 0) calib.x = 0;
if (calib.y > LCD_HEIGHT - 1) calib.y = LCD_HEIGHT - 1;
if (calib.y == 0) calib.y = 0;
#if TP_MIRROR_X
ax = (uint16_t)(LCD_W - 1 - ax);
#endif
#if TP_MIRROR_Y
ay = (uint16_t)(LCD_H - 1 - ay);
#endif
calib.x = ax;
calib.y = ay;
return calib;
}

View File

@ -33,11 +33,11 @@
#define TP_DIN_Clr() gpio_bits_reset(TP_DIN_PORT, TP_DIN_PIN) // DIN输出低MCU→XPT2046
#define TP_DIN_Set() gpio_bits_set(TP_DIN_PORT, TP_DIN_PIN) // DIN输出高MCU→XPT2046
// XPT2046命令定义
#define XPT2046_READ_X 0xD0 // 读X坐标命令MCU通过DIN发送给XPT2046
#define XPT2046_READ_Y 0x90 // 读Y坐标命令
#define XPT2046_READ_Z1 0xB0 // 读压力Z1
#define XPT2046_READ_Z2 0xC0 // 读压力Z2
// XPT2046命令(与 BOOT 工程一致)
#define XPT2046_READ_X 0xD0
#define XPT2046_READ_Y 0x90
#define XPT2046_READ_Z1 0xB0
#define XPT2046_READ_Z2 0xC0
// 触摸状态结构体
typedef struct

View File

@ -1,4 +1,5 @@
#include "includes.h"
#include "SEGGER_RTT.h"
static struct rt_thread TaskScanThread;
static struct rt_thread TaskUIThread;
@ -44,13 +45,20 @@ void TaskUIThread_entry(void* parameter)
void TaskTouchThread_entry(void* parameter)
{
static uint8_t s_last_pressed = 0;
while(1)
{
TP_Point tp = TP_Read(); /* 读 XPT2046 触摸坐标 */
app_touch_process(240-tp.x, tp.y, tp.pressed);
/* DUMP 由 lcd_dump 专用线程轮询,勿在触摸线程里做 SPI 读屏,避免卡死触摸 */
TP_Point tp = TP_Read(); /* 已含轴交换/镜像,直接进手势 */
if (tp.pressed && !s_last_pressed)
{
char buf[40];
sprintf(buf, "TP %u,%u\n", (unsigned)tp.x, (unsigned)tp.y);
SEGGER_RTT_WriteString(0, buf);
}
s_last_pressed = tp.pressed;
app_touch_process(tp.x, tp.y, tp.pressed);
Read_Cur_Measure();
rt_thread_mdelay(10);
rt_thread_mdelay(8);
}
}