当前位置: 首页 > news >正文

ARM(15) - LCD(2)显示字母数字+touch

一、配置

参考手册

二、程序

(一)、显示字母和数字

调用

(二)、触屏功能实现

1、整体框架与核心数据结构

首先明确代码的核心目标:通过 I2C 与触摸芯片通信,利用中断捕获触摸事件,读取触摸坐标并在 LCD 上显示

1. 隐含的数据结构(关键!)

代码中未显式定义touch_data_tpoint_t,但通过逻辑可反推其结构(通常在touch.h中声明),是触摸数据存储的基础:

// 触摸点坐标结构体(单个触摸点的x/y坐标)
typedef struct {unsigned short x;  // x轴坐标(16位,适配常见LCD分辨率)unsigned short y;  // y轴坐标(16位)
} point_t;// 触摸数据全局结构体(存储所有触摸信息,供中断与主函数共享)
typedef struct {unsigned char flag_valid;       // 数据有效标志(1=有新触摸数据,0=无)unsigned char num_point;        // 当前触摸点数量(0~5,FT5x06支持最多5点触摸)point_t point_data[5];          // 5个触摸点的坐标数据(对应最多5点)
} touch_data_t;// 全局变量:中断处理函数与主函数通过该变量传递触摸数据
touch_data_t touch_data;

2. 核心外设依赖

代码依赖 MCIMX6Y2 的多个外设,需先初始化才能保证触屏功能正常:

  • I2C2:与触摸芯片通信(触摸芯片为 I2C 从设备,地址0x14);
  • GPIO:2 个关键引脚(复位引脚 GPIO5_IO09、中断引脚 GPIO1_IO09);
  • GIC(通用中断控制器):管理 GPIO 中断,使能中断响应;
  • LCD:显示触摸坐标(依赖lcd_show_string函数)。

2、模块 1:触摸硬件初始化(touch_init

touch_init是触屏功能的 “启动入口”,负责完成引脚配置、触摸芯片复位、中断配置三大核心工作,确保触摸芯片进入就绪状态。

1. 步骤 1:引脚复用与电气属性配置

MCIMX6Y2 的引脚需通过IOMUXC(引脚复用控制器)配置为目标功能:

// 1. 配置复位引脚(GPIO5_IO09):复用为GPIO功能
IOMUXC_SetPinMux(IOMUXC_SNVS_SNVS_TAMPER9_GPIO5_IO09, 0);
// 2. 配置中断引脚(GPIO1_IO09):复用为GPIO功能
IOMUXC_SetPinMux(IOMUXC_GPIO1_IO09_GPIO1_IO09, 0);// 3. 配置引脚电气属性(拉电阻、驱动能力、 slew rate等)
// 0x10B0:通常表示“下拉电阻+100KΩ+驱动能力适中”(具体需查IMX6Y2手册)
IOMUXC_SetPinConfig(IOMUXC_SNVS_SNVS_TAMPER9_GPIO5_IO09, 0x10B0);
// 0xF0B0:中断引脚可能配置为“上拉电阻”(匹配触摸芯片中断输出电平)
IOMUXC_SetPinConfig(IOMUXC_GPIO1_IO09_GPIO1_IO09, 0xF0B0);

2. 步骤 2:触摸芯片复位(关键时序)

触摸芯片上电后需复位才能正常工作,通过 GPIO5_IO09 输出高低电平实现复位时序:

gpio_pin_t pin;
pin.dir = gpio_output;  // 复位引脚设为输出模式
pin.def_val = 0;
gpio_init(GPIO5, 9, &pin);  // 初始化GPIO5_IO09(复位引脚)
gpio_init(GPIO1, 9, &pin);  // 先将中断引脚设为输出(临时拉低复位?)// 复位时序:拉低10ms(硬件复位)→ 拉高100ms(等待芯片启动)
gpio_write(GPIO5, 9, 0);  // 复位引脚拉低
gpio_write(GPIO1, 9, 0);  // 中断引脚临时拉低(可选,看芯片要求)
delay_ms(10);             // 保持拉低10ms(满足芯片复位时序)
gpio_write(GPIO5, 9, 1);  // 复位引脚拉高(结束复位)
delay_ms(100);            // 等待芯片初始化完成

3. 步骤 3:触摸芯片寄存器初始化(可选调试与配置)

代码中包含读取芯片状态、配置工作模式的逻辑(部分注释掉,用于调试):

unsigned char buf[20] = {0};
// 读0x8056寄存器:获取触摸触发模式(0x3可能表示“中断触发模式”)
touch_read(0x8056, buf, 1); 
sprintf(buf,"triger mode:%d",buf[0] & 0x3);  // 格式化模式值(调试用)// 写0x8040寄存器:配置触摸芯片工作模式(如“中断使能”“多点触摸使能”)
buf[0] = 0;  // 具体值需查芯片手册(如0=默认模式)
touch_write(0x8040, buf, 1);
delay_ms(100);  // 等待配置生效

4. 步骤 4:GPIO 中断配置(捕获触摸事件)

触摸芯片在检测到触摸时,会拉低中断引脚(GPIO1_IO09),需配置 GPIO 中断以捕获该事件:

// 1. 中断引脚改为输入模式(接收触摸芯片的中断信号)
pin.dir = gpio_input;
gpio_init(GPIO1, 9, &pin);// 2. 配置中断触发方式(GPIO1->ICR1:中断配置寄存器1)
// (3 << 18):配置GPIO1_IO09的触发方式(3=下降沿触发,因触摸芯片中断为低电平脉冲)
// 注:ICR1的bit18~19对应IO9(IMX6 GPIO中断配置规则:bit[2n+1:n]对应IOn)
GPIO1->ICR1 |= (3 << 18); // 3. 解除中断屏蔽(GPIO1->IMR:中断屏蔽寄存器)
// (1 << 9):允许GPIO1_IO09产生中断
GPIO1->IMR |= (1 << 9);// 4. 注册中断处理函数并使能GIC中断
// 把“GPIO1_Combined_0_15_IRQn”中断与“touch_screen_interrupt_handler”绑定
system_interrupt_register(GPIO1_Combined_0_15_IRQn, touch_screen_interrupt_handler);
// 在GIC中使能该中断(Cortex-A7必须通过GIC管理中断)
GIC_EnableIRQ(GPIO1_Combined_0_15_IRQn);

3、模块 2:I2C 通信层(touch_write/touch_read

触摸芯片通过 I2C 协议与 MCU 通信,touch_writetouch_read是封装好的 I2C 读写接口,负责与触摸芯片的寄存器交互。

1. I2C 写函数(touch_write

功能:向触摸芯片的指定寄存器写入数据(如配置寄存器、清除标志)。

void touch_write(unsigned short reg_addr, unsigned char *data, unsigned short len)
{// I2C消息结构体(定义在i2c.h中,描述一次I2C传输的所有参数)struct I2C_Msg msg = {.dev_addr = 0x14,        // 触摸芯片的I2C从设备地址(FT5x06默认0x14).reg_addr = reg_addr,    // 目标寄存器地址(如0x8040、0x814E).reg_len = 2,            // 寄存器地址长度(2字节,因reg_addr是unsigned short).data = data,            // 要写入的数据缓冲区.len = len,              // 写入数据的长度(字节数).dir = I2C_write         // 传输方向:写};// 调用I2C底层驱动,执行一次I2C写传输(I2C2总线)i2c_transfer(I2C2, &msg);
}

I2C 写流程:MCU(I2C 主设备)发送「设备地址 + 写标志」→ 发送「2 字节寄存器地址」→ 发送「数据」→ 停止信号。

2. I2C 读函数(touch_read

功能:从触摸芯片的指定寄存器读取数据(如触摸点数量、坐标)。

void touch_read(unsigned short reg_addr, unsigned char *data, unsigned short len)
{struct I2C_Msg msg = {.dev_addr = 0x14,        //  same as write.reg_addr = reg_addr,    // 目标寄存器地址.reg_len = 2,            // 寄存器地址长度(2字节).data = data,            // 存储读取数据的缓冲区.len = len,              // 要读取的数据长度.dir = I2C_read          // 传输方向:读};i2c_transfer(I2C2, &msg);  // 执行I2C读传输
}

I2C 读流程(关键:需 “两次启动”):

  1. 第一次启动:MCU 发送「设备地址 + 写标志」→ 发送「2 字节寄存器地址」→ 发送「重复启动信号」;
  2. 第二次启动:MCU 发送「设备地址 + 读标志」→ 接收「数据」→ 发送「NACK + 停止信号」。

4、模块 3:中断处理(touch_screen_interrupt_handler

当有触摸时,触摸芯片拉低 GPIO1_IO09,触发中断,中断处理函数负责读取触摸数据并存储到全局变量,是触屏功能的 “数据采集核心”。

中断处理流程

void touch_screen_interrupt_handler(void)
{// 1. 确认中断源:是否为GPIO1_IO09的中断(避免误触发)if (GPIO1->ISR & (1 << 9)) {unsigned char num;        // 触摸点数量unsigned char i = 0;unsigned char point[20] = {0};  // 存储单个触摸点的4字节数据(x低8、x高8、y低8、y高8)// 2. 读0x814E寄存器:获取当前触摸点数量(FT5x06的“触摸点数量寄存器”)touch_read(0x814E, &num, 1);touch_data.num_point = num & 0x0F;  // 低4位有效(0~5,最多5点)// 3. 若有触摸点,读取每个点的坐标if (0 != touch_data.num_point){touch_data.flag_valid = 1;  // 置“数据有效”标志,通知主函数有新数据// 循环读取每个触摸点的坐标(array_point是坐标寄存器地址表)// array_point[0] = 0x8150(第1点)、0x8158(第2点)... 0x8170(第5点)for (i = 0; i < touch_data.num_point; i++){// 读4字节数据(每个触摸点坐标占4字节)touch_read(array_point[i], point, 4);// 拼接x坐标(point[0]=x低8位,point[1]=x高8位 → 16位x)touch_data.point_data[i].x = point[1] << 8 | point[0];// 拼接y坐标(point[2]=y低8位,point[3]=y高8位 → 16位y)touch_data.point_data[i].y = point[3] << 8 | point[2];}}// 4. 写0x814E寄存器为0:清除触摸点数量标志(避免重复触发中断)num = 0;touch_write(0x814E, &num, 1);// 5. 清除GPIO中断标志(IMX6 GPIO的ISR寄存器“写1清中断”)GPIO1->ISR |= (1 << 9);}
}

关键注意点

  • 中断处理函数需 “快进快出”,但此处读取 I2C 数据为阻塞操作(若触摸芯片响应快,影响可忽略);
  • 坐标拼接逻辑需与触摸芯片的寄存器格式匹配(FT5x06 的坐标寄存器格式就是 “低 8 位 + 高 8 位”)。

5、模块 4:数据交互接口(get_touch_screen_data

主函数不直接操作中断或 I2C,而是通过get_touch_screen_data获取触摸数据 —— 该函数是 “中断层” 与 “应用层” 的隔离接口,降低耦合。

unsigned char get_touch_screen_data(point_t *data)
{unsigned char i = 0;// 若数据有效(中断已采集到新触摸数据)if (touch_data.flag_valid != 0){// 把全局变量的触摸点数据复制到传入的data数组(主函数的point数组)for (i = 0; i < touch_data.num_point; i++){data[i].x = touch_data.point_data[i].x;data[i].y = touch_data.point_data[i].y;}touch_data.flag_valid = 0;  // 清“数据有效”标志(避免重复读取)return touch_data.num_point;  // 返回触摸点数量(0~5)}return 0;  // 无有效数据,返回0
}

6、模块 5:主函数逻辑(main

主函数是触屏功能的 “应用入口”,负责初始化所有外设,然后循环读取触摸数据并在 LCD 上显示。

主函数核心流程

int main(void)
{// 1. 初始化基础外设(时钟、中断控制器、LED/蜂鸣器/按键等)clock_init();          // 初始化系统时钟(IMX6Y2核心时钟、外设时钟)system_interrupt_init();// 初始化中断控制器(GIC)led_init();            // 初始化LED(可选,用于触摸反馈)beep_init();           // 初始化蜂鸣器(可选)key_init();            // 初始化按键(可选)// 2. 初始化定时器、UART、I2C等通信/定时外设epit1_init();          // EPIT定时器(可选)gpt1_init();           // GPT定时器(可选,用于delay_ms)uart1_init();          // UART1(可选,用于串口打印调试)i2c1_init();           // I2C1(其他设备,如LM75温度传感器)i2c2_init();           // I2C2(关键!触摸芯片通信总线)// 3. 初始化模拟外设与显示外设adc1_init();           // ADC(可选)pwm1_init();           // PWM(可选,如背光控制)pwm1_set_g_f(1);       // 设置PWM参数(可选)lcd_init();            // 初始化LCD(关键!显示触摸坐标)delay_ms(50);          // 等待LCD启动lcd_clear();           // 清屏(避免残留画面)// 4. 初始化触摸功能(关键!前面讲解的touch_init)touch_init();// 5. 主循环:读取触摸数据并显示while (1){point_t point[5];  // 存储最多5个触摸点的坐标int i = 0;char buf[20] = {0};// 格式化坐标字符串// 读取触摸数据(返回触摸点数量,0=无触摸)unsigned char ret = get_touch_screen_data(point);if (ret != 0)  // 若有触摸数据{// 循环显示每个触摸点的坐标(x,y)for (i = 0; i < ret; i++){// 格式化字符串:“0: 123, 456”(第0个点,x=123,y=456)sprintf(buf, "%d: %d, %d", i, point[i].x, point[i].y);// 在LCD上显示:位置(100, 100+32*i),字体32x32// 32*i:每个点占32像素高度,避免文字重叠lcd_show_string(100, 100 + 32 * i, strlen(buf)*16, 32, 32, buf);}}}
}
http://www.dtcms.com/a/392668.html

相关文章:

  • 五、炫饭馆项目实战
  • 01.容器生态系统
  • CSS Grid 布局示例 - grid-template-areas
  • 基于脚手架微服务的视频点播系统-客户端业务逻辑处理部分(一)
  • 501. 二叉搜索树中的众数
  • Go面试题及详细答案120题(81-100)
  • 在跨平台C++项目中条件化使用Intel MKL与LAPACK/BLAS进行矩阵计算
  • 知芽AI(paperxx)写作:开题报告写作宝典
  • c++26新功能—模板参数中的概念与变量模板
  • Linux服务器上安装配置GitLab的步骤
  • Netty原理介绍
  • 【已解决】在windows系统安装fasttext库,解决安装fasttext报错问题
  • 从“free”到“free_s”:内存释放更安全——free_s函数深度解析与free全方位对比
  • 【LeetCode 每日一题】1733. 需要教语言的最少人数
  • 多模态知识图谱
  • 基于python spark的航空数据分析系统的设计与实现
  • 【每日一问】运放单电源供电和双电源供电的区别是什么?
  • LeetCode算法领域的经典题目之“三数之和”和“滑动窗口最大值”问题
  • SpringCloudConfig:分布式配置中心
  • Go变量与类型简明指南
  • 每天学习一个统计检验方法--曼-惠特尼U检验(以噩梦障碍中的心跳诱发电位研究为例)
  • linux创建服务器
  • 线性代数基础 | 零空间 / 行空间 / 列空间 / 左零空间 / 线性无关 / 齐次 / 非齐次
  • 【StarRocks】-- 同步物化视图实战指南
  • 【C++项目】微服务即时通讯系统:服务端
  • 开源WordPress APP(LaraPressAPP)文档:1.开始使用
  • 单调破题:当指数函数遇上线性方程的奇妙对决
  • 【C++】vector 的使用和底层
  • 指标体系单一只关注速度会造成哪些风险
  • 智能体落地与大模型能力关系论