stm32驱动xpt2046触摸屏

上次我们使用的那块2.4寸ILI9341芯片LCD是带触摸的,触摸驱动芯片为xpt2046。这次我们来看如何使用stm32获取触摸屏的信息。

XPT2046

xpt2046是一款4线制电阻式触摸屏控制器芯片。它的核心功能是将触摸屏上的物理按压位置转换成数字信号,以便单片机读取和处理。与单片机的接口主要由以下几个引脚

  • VCC: 电源正极
  • GND: 电源地
  • CLK:SPI时钟信号,在我使用的板子上为和LCD的时钟区分,标记为T_CLK
  • DIN:SPI数据输入,接受单片机来的控制命令,在我使用的板子上对应的是MOSI
  • DOUT: SPI数据输出,向单片机发送转换后的数字数据,在我使用的板子上对应的是MISO
  • PEN:接触中断信号
  • CS: 片选,低电平有效,我使用板子上为了和LCD的CS区分,标记为T_CS

在这里插入图片描述

同样我们使用STM32F103RB,将引脚做以下连接

  • T_CLK:PB3
  • MISO:PB4
  • MOSI:PB5
  • T_CS: 连接到PC5
  • PEN: 连接到PC0

并且在STM32 CubeMX中做以下操作

  • 将SPI1设置为Full Duplex Master模式,对应PB3、PB4、PB5的设置
  • 将PC5设置为GPIO_OUTPUT, 并命名为T_CS
  • 将PC0设置为GPIO_EXTI0,并且GPIO mode设置为External Interrupt Mode with Falling edge trigger detection(下降沿触发), 并命名为T_PEN_INT
  • 在NVIC设置中,确保EXTI line0 interrupt 被勾选上
    在这里插入图片描述

我们就可以生成代码并实现相关驱动的代码了,部分关键代码如下所示:

#include "touch_xpt2046.h"


#define SAMPLE_TIMES 10 // 采样次数,因为触摸点会漂移,所以我们每次需要采样多次,然后取平均值返回

uint16_t Touch_Read_Data(uint8_t cmd) {
	uint8_t txData[3] = {cmd, 0, 0};
	uint8_t rxData[3] = {0};   // 这里rxData与rxData用同一个数组也是可以的
	
	__disable_irq(); // 在操作读取数据的时候需要禁止中断
	HAL_GPIO_WritePin(TOUCH_CS_PORT, TOUCH_CS_PIN, GPIO_PIN_RESET); // 片选使能
	HAL_SPI_TransmitReceive(&TOUCH_SPI_HANDLE, txData, rxData, 3, 1000);
	HAL_GPIO_WritePin(TOUCH_CS_PORT, TOUCH_CS_PIN, GPIO_PIN_SET);
	__enable_irq();
	
	uint16_t data = (rxData[1] << 8) | rxData[2]; //第一个字节是发送字节,可以丢弃,第二第三个字节需要合并
	return data >> 3; // 返回数据是12位的,最后3位无效值,丢弃
}

// 总是长边为x, 短边为y,需要根据实际情况转换为屏幕坐标
void Touch_Get_Pos(uint16_t* x, uint16_t* y) {
    uint16_t x_sum = 0, y_sum = 0;

	for (int i = 0; i < SAMPLE_TIMES; i++) { // 多次采样
		x_sum += Touch_Read_Data(0x90); // 0x90为读取x坐标的命令
		y_sum += Touch_Read_Data(0xD0); // 0xD0为读取y坐标的命令
	}
	
	*x = x_sum/SAMPLE_TIMES;
	*y = y_sum/SAMPLE_TIMES;

}

在实际应用中,还需要根据屏幕的朝向进行坐标转换。

在main.c中,添加全局变量touch_screen_pressed,初始化为false,并且添加中断处理函数

bool touch_screen_pressed = false;

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
  if (GPIO_Pin == T_PEN_INT_Pin) {
    if (!touch_screen_pressed) {
      log_write(LOG_LEVEL_DEBUG, "Touch screen pressed");
      touch_screen_pressed = true;
    }
  }
}

在main.c的主循环中

  while (1)
  {

    if (touch_screen_pressed) {
      uint16_t x = 0;
      uint16_t y = 0;
      Touch_Get_Pos(&x, &y);
      if (x == 4095 || y == 0) { // 当x为4905或y为0的时候,表示触摸结束
        touch_screen_pressed = false;
        log_write(LOG_LEVEL_DEBUG, "touch unpressed");
      } else {
        log_write(LOG_LEVEL_DEBUG, "X: %d, Y: %d", x, y);
      }
    }
    ...
  }

启动板子,用串口连接查看数据,就可以看到读取的触摸信息

在实际应用中,我们还需要考虑屏幕四个角坐标的偏移,所以通常需要做一个屏幕坐标与触摸坐标的映射功能,引导用户依次点击屏幕四角和中点的特定位置,即可得到转换的公式。
结合上一篇文章的屏幕显示方法,我们就可以在屏幕上用手绘制图案了

完整项目工程在这里:https://github.com/sqlxx/stm32-workshop/ (lcd_driver分支)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

帅帅兔子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值