news 2026/6/2 10:03:34

单片机触摸屏实验

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
单片机触摸屏实验

单片机 :STM32F407
开发板:DMF407电机开发板
平台:keil V5.31

HSE 为8MHZ
HSI为16MHZ

原理图:

主函数:

int main(void) { HAL_Init(); /* 初始化HAL库 */ sys_stm32_clock_init(336,8,2,7); /* 设置时钟, 168Mhz */ delay_init(168); /* 延时初始化 */ usart_init(115200); /* 串口初始化为115200 */ led_init(); /* 初始化LED */ lcd_init(); /* 初始化LCD */ key_init(); /* 初始化按键 */ tp_dev.init(); /* 触摸屏初始化 */ lcd_show_string(30, 50, 200, 16, 16, "STM32", RED); lcd_show_string(30, 70, 200, 16, 16, "TOUCH TEST", RED); lcd_show_string(30, 90, 200, 16, 16, "ATOM@ALIENTEK", RED); if (tp_dev.touchtype != 0xFF) { lcd_show_string(30, 110, 200, 16, 16, "Press KEY0 to Adjust", RED); /* 电阻屏才显示 */ } delay_ms(1500); load_draw_dialog(); if (tp_dev.touchtype & 0x80) { ctp_test(); /* 电容屏测试 */ } else { rtp_test(); /* 电阻屏测试 */ } }

配置:

/* 电阻触摸屏驱动IC T_PEN/T_CS/T_MISO/T_MOSI/T_SCK 引脚 定义 */ #define T_PEN_GPIO_PORT GPIOH #define T_PEN_GPIO_PIN GPIO_PIN_7 #define T_PEN_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOH_CLK_ENABLE(); }while(0) /* 所在IO口时钟使能 */ #define T_CS_GPIO_PORT GPIOG #define T_CS_GPIO_PIN GPIO_PIN_1 #define T_CS_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOG_CLK_ENABLE(); }while(0) /* 所在IO口时钟使能 */ #define T_MISO_GPIO_PORT GPIOD #define T_MISO_GPIO_PIN GPIO_PIN_11 #define T_MISO_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOD_CLK_ENABLE(); }while(0) /* 所在IO口时钟使能 */ #define T_MOSI_GPIO_PORT GPIOH #define T_MOSI_GPIO_PIN GPIO_PIN_8 #define T_MOSI_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOH_CLK_ENABLE(); }while(0) /* 所在IO口时钟使能 */ #define T_CLK_GPIO_PORT GPIOH #define T_CLK_GPIO_PIN GPIO_PIN_6 #define T_CLK_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOH_CLK_ENABLE(); }while(0) /* 所在IO口时钟使能 */ /******************************************************************************************/ /* 电阻触摸屏控制引脚 */ #define T_PEN HAL_GPIO_ReadPin(T_PEN_GPIO_PORT, T_PEN_GPIO_PIN) /* T_PEN */ #define T_MISO HAL_GPIO_ReadPin(T_MISO_GPIO_PORT, T_MISO_GPIO_PIN) /* T_MISO */ #define T_MOSI(x) do{ x ? \ HAL_GPIO_WritePin(T_MOSI_GPIO_PORT, T_MOSI_GPIO_PIN, GPIO_PIN_SET) : \ HAL_GPIO_WritePin(T_MOSI_GPIO_PORT, T_MOSI_GPIO_PIN, GPIO_PIN_RESET); \ }while(0) /* T_MOSI */ #define T_CLK(x) do{ x ? \ HAL_GPIO_WritePin(T_CLK_GPIO_PORT, T_CLK_GPIO_PIN, GPIO_PIN_SET) : \ HAL_GPIO_WritePin(T_CLK_GPIO_PORT, T_CLK_GPIO_PIN, GPIO_PIN_RESET); \ }while(0) /* T_CLK */ #define T_CS(x) do{ x ? \ HAL_GPIO_WritePin(T_CS_GPIO_PORT, T_CS_GPIO_PIN, GPIO_PIN_SET) : \ HAL_GPIO_WritePin(T_CS_GPIO_PORT, T_CS_GPIO_PIN, GPIO_PIN_RESET); \ }while(0) /* T_CS */ #define TP_PRES_DOWN 0x8000 /* 触屏被按下 */ #define TP_CATH_PRES 0x4000 /* 有按键按下了 */ #define CT_MAX_TOUCH 10 /* 电容屏支持的点数,固定为5点 */ /* 触摸屏控制器 */ typedef struct { uint8_t (*init)(void); /* 初始化触摸屏控制器 */ uint8_t (*scan)(uint8_t); /* 扫描触摸屏.0,屏幕扫描;1,物理坐标; */ void (*adjust)(void); /* 触摸屏校准 */ uint16_t x[CT_MAX_TOUCH]; /* 当前坐标 */ uint16_t y[CT_MAX_TOUCH]; /* 电容屏有最多10组坐标,电阻屏则用x[0],y[0]代表:此次扫描时,触屏的坐标,用 * x[9],y[9]存储第一次按下时的坐标. */ uint16_t sta; /* 笔的状态 * b15:按下1/松开0; * b14:0,没有按键按下;1,有按键按下. * b13~b10:保留 * b9~b0:电容触摸屏按下的点数(0,表示未按下,1表示按下) */ /* 5点校准触摸屏校准参数(电容屏不需要校准) */ float xfac; /* 5点校准法x方向比例因子 */ float yfac; /* 5点校准法y方向比例因子 */ short xc; /* 中心X坐标物理值(AD值) */ short yc; /* 中心Y坐标物理值(AD值) */ /* 新增的参数,当触摸屏的左右上下完全颠倒时需要用到. * b0:0, 竖屏(适合左右为X坐标,上下为Y坐标的TP) * 1, 横屏(适合左右为Y坐标,上下为X坐标的TP) * b1~6: 保留. * b7:0, 电阻屏 * 1, 电容屏 */ uint8_t touchtype; } _m_tp_dev; uint8_t tp_init(void) { GPIO_InitTypeDef gpio_init_struct; tp_dev.touchtype = 0; /* 默认设置(电阻屏 & 竖屏) */ tp_dev.touchtype |= lcddev.dir & 0X01; /* 根据LCD判定是横屏还是竖屏 */ if (lcddev.id == 0x7796) /* 3.5寸屏有两种,一种屏幕ID为0x5510带电阻触摸屏,一种屏幕ID为0x7796带GT型号的电容触摸屏 */ { if (gt9xxx_init() == 0) /* 初始化GT系列触摸屏成功,即当前3.5寸屏为电容触摸屏 */ { tp_dev.scan = gt9xxx_scan; /* 扫描函数指向GT9147触摸屏扫描 */ tp_dev.touchtype |= 0X80; /* 电容屏 */ return 0; } } if (lcddev.id == 0X5510 || lcddev.id == 0X9806 || lcddev.id == 0X4342 || lcddev.id == 0X4384 || lcddev.id == 0X1018) /* 电容触摸屏,4.3寸/10.1寸屏 */ { gt9xxx_init(); tp_dev.scan = gt9xxx_scan; /* 扫描函数指向GT9147触摸屏扫描 */ tp_dev.touchtype |= 0X80; /* 电容屏 */ return 0; } return 1; } uint8_t gt9xxx_init(void) { GPIO_InitTypeDef gpio_init_struct; uint8_t temp[5]; GT9XXX_RST_GPIO_CLK_ENABLE(); /* RST引脚时钟使能 */ GT9XXX_INT_GPIO_CLK_ENABLE(); /* INT引脚时钟使能 */ gpio_init_struct.Pin = GT9XXX_RST_GPIO_PIN; gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出 */ gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */ gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; /* 高速 */ HAL_GPIO_Init(GT9XXX_RST_GPIO_PORT, &gpio_init_struct); /* 初始化RST引脚 */ gpio_init_struct.Pin = GT9XXX_INT_GPIO_PIN; gpio_init_struct.Mode = GPIO_MODE_INPUT; /* 输入 */ gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */ gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; /* 高速 */ HAL_GPIO_Init(GT9XXX_INT_GPIO_PORT, &gpio_init_struct); /* 初始化INT引脚 */ ct_iic_init(); /* 初始化电容屏的I2C总线 */ GT9XXX_RST(0); /* 复位 */ delay_ms(10); GT9XXX_RST(1); /* 释放复位 */ delay_ms(10); /* INT引脚模式设置, 输入模式, 浮空输入 */ gpio_init_struct.Pin = GT9XXX_INT_GPIO_PIN; gpio_init_struct.Mode = GPIO_MODE_INPUT; /* 输入 */ gpio_init_struct.Pull = GPIO_NOPULL; /* 不带上下拉,浮空模式 */ gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; /* 高速 */ HAL_GPIO_Init(GT9XXX_INT_GPIO_PORT, &gpio_init_struct); /* 初始化INT引脚 */ delay_ms(100); gt9xxx_rd_reg(GT9XXX_PID_REG, temp, 4); /* 读取触摸IC的ID */ temp[4] = 0; /* 判断一下是否是特定的触摸屏 */ if ( strcmp((char *)temp, "911") && strcmp((char *)temp, "9147") && strcmp((char *)temp, "1158") && strcmp((char *)temp, "9271")) { return 1; /* 若不是触摸屏用到的GT911/9147/1158/9271,则初始化失败,需硬件查看触摸IC型号以及查看时序函数是否正确 */ } printf("CTP ID:%s\r\n", temp); /* 打印ID */ if (strcmp((char *)temp, "9271") == 0) /* ID==9271, 支持10点触摸 */ { g_gt_tnum = 10; /* 支持10点触摸屏 */ } temp[0] = 0X02; gt9xxx_wr_reg(GT9XXX_CTRL_REG, temp, 1); /* 软复位GT9XXX */ delay_ms(10); temp[0] = 0X00; gt9xxx_wr_reg(GT9XXX_CTRL_REG, temp, 1); /* 结束复位, 进入读坐标状态 */ return 0; } uint8_t gt9xxx_scan(uint8_t mode) { uint8_t buf[4]; uint8_t i = 0; uint8_t res = 0; uint16_t temp; uint16_t tempsta; static uint8_t t = 0; /* 控制查询间隔,从而降低CPU占用率 */ t++; if ((t % 10) == 0 || t < 10) /* 空闲时,每进入10次CTP_Scan函数才检测1次,从而节省CPU使用率 */ { gt9xxx_rd_reg(GT9XXX_GSTID_REG, &mode, 1); /* 读取触摸点的状态 */ if ((mode & 0x80) && ((mode & 0XF) <= g_gt_tnum)) { i = 0; gt9xxx_wr_reg(GT9XXX_GSTID_REG, &i, 1); /* 清标志 */ } if ((mode & 0XF) && ((mode & 0XF) <= g_gt_tnum)) { temp = 0XFFFF << (mode & 0XF); /* 将点的个数转换为1的位数,匹配tp_dev.sta定义 */ tempsta = tp_dev.sta; /* 保存当前的tp_dev.sta值 */ tp_dev.sta = (~temp) | TP_PRES_DOWN | TP_CATH_PRES; tp_dev.x[g_gt_tnum - 1] = tp_dev.x[0]; /* 保存触点0的数据,保存在最后一个上 */ tp_dev.y[g_gt_tnum - 1] = tp_dev.y[0]; for (i = 0; i < g_gt_tnum; i++) { if (tp_dev.sta & (1 << i)) /* 触摸有效? */ { gt9xxx_rd_reg(GT9XXX_TPX_TBL[i], buf, 4); /* 读取XY坐标值 */ if (lcddev.id == 0X5510 || lcddev.id == 0X9806 || lcddev.id == 0X7796) /* 4.3寸800*480 和 3.5寸480*320 MCU屏 */ { if (tp_dev.touchtype & 0X01) /* 横屏 */ { tp_dev.x[i] = lcddev.width - (((uint16_t)buf[3] << 8) + buf[2]); tp_dev.y[i] = ((uint16_t)buf[1] << 8) + buf[0]; } else { tp_dev.x[i] = ((uint16_t)buf[1] << 8) + buf[0]; tp_dev.y[i] = ((uint16_t)buf[3] << 8) + buf[2]; } } else /* 其他型号 */ { if (tp_dev.touchtype & 0X01) /* 横屏 */ { tp_dev.x[i] = ((uint16_t)buf[1] << 8) + buf[0]; tp_dev.y[i] = ((uint16_t)buf[3] << 8) + buf[2]; } else { tp_dev.x[i] = lcddev.width - (((uint16_t)buf[3] << 8) + buf[2]); tp_dev.y[i] = ((uint16_t)buf[1] << 8) + buf[0]; } } //printf("x[%d]:%d,y[%d]:%d\r\n", i, tp_dev.x[i], i, tp_dev.y[i]); } } res = 1; if (tp_dev.x[0] > lcddev.width || tp_dev.y[0] > lcddev.height) /* 非法数据(坐标超出了) */ { if ((mode & 0XF) > 1) /* 有其他点有数据,则复第二个触点的数据到第一个触点. */ { tp_dev.x[0] = tp_dev.x[1]; tp_dev.y[0] = tp_dev.y[1]; t = 0; /* 触发一次,则会最少连续监测10次,从而提高命中率 */ } else /* 非法数据,则忽略此次数据(还原原来的) */ { tp_dev.x[0] = tp_dev.x[g_gt_tnum - 1]; tp_dev.y[0] = tp_dev.y[g_gt_tnum - 1]; mode = 0X80; tp_dev.sta = tempsta; /* 恢复tp_dev.sta */ } } else { t = 0; /* 触发一次,则会最少连续监测10次,从而提高命中率 */ } } } if ((mode & 0X8F) == 0X80) /* 无触摸点按下 */ { if (tp_dev.sta & TP_PRES_DOWN) /* 之前是被按下的 */ { tp_dev.sta &= ~TP_PRES_DOWN; /* 标记按键松开 */ } else /* 之前就没有被按下 */ { tp_dev.x[0] = 0xffff; tp_dev.y[0] = 0xffff; tp_dev.sta &= 0XE000; /* 清除点有效标记 */ } } if (t > 240)t = 10; /* 重新从10开始计数 */ return res; } void ctp_test(void) { uint8_t t = 0; uint8_t i = 0; uint16_t lastpos[10][2]; /* 最后一次的数据 */ uint8_t maxp = 5; if (lcddev.id == 0x1018)maxp = 10; while (1) { tp_dev.scan(0); for (t = 0; t < maxp; t++) { if ((tp_dev.sta) & (1 << t)) { if (tp_dev.x[t] < lcddev.width && tp_dev.y[t] < lcddev.height) /* 坐标在屏幕范围内 */ { if (lastpos[t][0] == 0xFFFF) { lastpos[t][0] = tp_dev.x[t]; lastpos[t][1] = tp_dev.y[t]; } lcd_draw_bline(lastpos[t][0], lastpos[t][1], tp_dev.x[t], tp_dev.y[t], 2, POINT_COLOR_TBL[t]); /* 画线 */ lastpos[t][0] = tp_dev.x[t]; lastpos[t][1] = tp_dev.y[t]; if (tp_dev.x[t] > (lcddev.width - 24) && tp_dev.y[t] < 20) { load_draw_dialog(); /* 清除 */ } } } else { lastpos[t][0] = 0xFFFF; } } delay_ms(5); i++; if (i % 20 == 0) { LED0_TOGGLE(); } } }

debug:

测试结果:

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/2 10:03:04

框架游戏设计:融合游戏化思维与结构化学习,提升教学效果

1. 项目概述&#xff1a;当“游戏框架”遇上“学术成功”“Unlocking Academic Success with Frame Games for Learning”&#xff0c;这个标题直译过来是“用学习框架游戏解锁学术成功”。乍一看&#xff0c;可能觉得有点抽象&#xff0c;像是某种教育理论的包装。但作为一个在…

作者头像 李华
网站建设 2026/6/2 10:02:58

智能设计革命:SD-PPP如何将Photoshop转变为AI创作平台

智能设计革命&#xff1a;SD-PPP如何将Photoshop转变为AI创作平台 【免费下载链接】sd-ppp A Photoshop AI plugin 项目地址: https://gitcode.com/gh_mirrors/sd/sd-ppp 在数字创意领域&#xff0c;工作流效率直接影响着创作质量与产出速度。传统AI图像生成与专业设计软…

作者头像 李华
网站建设 2026/6/2 10:01:59

告别图形界面!用mbpoll命令行批量自动化测试Modbus PLC,效率提升指南

工业自动化实战&#xff1a;mbpoll命令行工具在Modbus PLC批量测试中的高阶应用当产线上数百台Modbus设备需要同步进行寄存器校验时&#xff0c;图形界面工具往往成为效率瓶颈。去年某汽车零部件工厂的验收环节中&#xff0c;工程师团队通过命令行工具将原本需要3天完成的设备测…

作者头像 李华
网站建设 2026/6/2 9:57:46

炉石传说终极增强插件HsMod:如何让游戏体验提升8倍?

炉石传说终极增强插件HsMod&#xff1a;如何让游戏体验提升8倍&#xff1f; 【免费下载链接】HsMod Hearthstone Modification Based on BepInEx 项目地址: https://gitcode.com/GitHub_Trending/hs/HsMod 还在为炉石传说中那些让你抓狂的小问题烦恼吗&#xff1f;日常任…

作者头像 李华
网站建设 2026/6/2 9:55:34

构建个人数字记忆体:从数据管理到知识图谱的实践指南

1. 项目概述&#xff1a;从“遗忘”到“全记录”的范式转移十年前&#xff0c;如果有人告诉我&#xff0c;我可以瞬间找到十年前某个下午浏览过的网页、五年前孩子随手涂鸦的画作照片&#xff0c;或者上周随手拍下的购物小票&#xff0c;我大概会觉得这是科幻小说里的情节。但今…

作者头像 李华