简单易懂的XPT2046触摸屏驱动

触摸屏宽度240,高度320,IO引脚为正点原子f103的2.4寸电阻触摸屏同款,修改引脚时修改LGPIO结构体和XPT2046_init()函数即可。

#include "xpt2046.h"

#include "xpt2046_command.h"

#define TOUCHPAD_WDITH		240
#define TOUCHPAD_HEIGHT		320
#define REPEATED_SAMPLING_TIMES		5	//重复取样次数,可以根据实际情况修改

//IO定义,引脚不同直接修改这里即可
static LGPIO PEN = { .GPIOx = GPIOF, .GPIO_Pin = GPIO_Pin_10, .GPIO_Speed = GPIO_Speed_50MHz, .GPIO_Mode = GPIO_Mode_IPU }; //PF10
static LGPIO CS = { .GPIOx = GPIOF, .GPIO_Pin = GPIO_Pin_11, .GPIO_Speed = GPIO_Speed_50MHz, .GPIO_Mode = GPIO_Mode_Out_PP }; //PF11
static LGPIO CLK = { .GPIOx = GPIOB, .GPIO_Pin = GPIO_Pin_1, .GPIO_Speed = GPIO_Speed_50MHz, .GPIO_Mode = GPIO_Mode_Out_PP }; //PB1
static LGPIO MISO = { .GPIOx = GPIOB, .GPIO_Pin = GPIO_Pin_2, .GPIO_Speed = GPIO_Speed_50MHz, .GPIO_Mode = GPIO_Mode_IPU }; //PB2
static LGPIO MOSI = { .GPIOx = GPIOF, .GPIO_Pin = GPIO_Pin_9, .GPIO_Speed = GPIO_Speed_50MHz, .GPIO_Mode = GPIO_Mode_Out_PP }; //PF9

void XPT2046_init()
{
	//根据实际情况修改
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOF, ENABLE);

	LGPIO_Init(&PEN);
	LGPIO_Init(&CS);
	LGPIO_Init(&CLK);
	LGPIO_Init(&MISO);
	LGPIO_Init(&MOSI);

	LGPIO_WriteBit(&CS, Bit_RESET);
}

//这里的延时可以删掉,延时函数可以调用SysTick延时函数
static void XPT2046_delay_us(u32 time)
{
	for (u32 i = 0; i < time; i++) {
		u8 uc = 12;     //设置值为12,大约延1微秒
		while (uc--)
			;     //延1微秒
	}
}

static void XPT2046_write_command(uint8_t command)
{
	LGPIO_WriteBit(&MOSI, Bit_RESET);
	LGPIO_WriteBit(&CLK, Bit_RESET);

	for (u8 i = 0; i < 8; i++) {
		LGPIO_WriteBit(&MOSI, (command >> (7 - i)) & 0x01);

		XPT2046_delay_us(5);
		LGPIO_WriteBit(&CLK, Bit_SET);
		XPT2046_delay_us(5);
		LGPIO_WriteBit(&CLK, Bit_RESET);
	}

}

static u16 XPT2046_read_data()
{
	u16 data = 0;

	LGPIO_WriteBit(&MOSI, Bit_RESET);
	LGPIO_WriteBit(&CLK, Bit_SET);

	for (u8 i = 0; i < 12; i++) {
		LGPIO_WriteBit(&CLK, Bit_RESET);

		data += LGPIO_ReadInputDataBit(&MISO);
		data <<= 1;

		LGPIO_WriteBit(&CLK, Bit_SET);
	}
	return data;
}

void XPT2046_getSourceValue(u16 *x_AD_AVG, u16 *y_AD_AVG)
{
	u16 x_AD[REPEATED_SAMPLING_TIMES] = { 0 };
	u16 y_AD[REPEATED_SAMPLING_TIMES] = { 0 };
	u16 x_AD_temp = 0;
	u16 y_AD_temp = 0;

	for (u8 i = 0; i < REPEATED_SAMPLING_TIMES;) {
		if (LGPIO_ReadInputDataBit(&PEN) == 0) {
			XPT2046_write_command(READ_CHANNEL_X);     //写读取X通道AD指令
			x_AD[i] = XPT2046_read_data();	//读取X通道AD值
			XPT2046_delay_us(1);
			XPT2046_write_command(READ_CHANNEL_Y);     //写读取Y通道AD指令
			y_AD[i] = XPT2046_read_data();	//读取Y通道AD值
			XPT2046_delay_us(1);
			i++;
		}
	}

	//冒泡排序
	for (u16 i = 0, temp = 0; i < REPEATED_SAMPLING_TIMES; i++)
		for (u8 j = 0; j < REPEATED_SAMPLING_TIMES - i - 1; j++) {
			if (x_AD[j] > x_AD[j + 1]) {
				temp = x_AD[j];
				x_AD[j] = x_AD[j + 1];
				x_AD[j + 1] = temp;
			}
			if (y_AD[j] > y_AD[j + 1]) {
				temp = y_AD[j];
				y_AD[j] = y_AD[j + 1];
				y_AD[j + 1] = temp;
			}
		}

	//去掉一个最大值,去掉一个最小值,取平均值
	for (u8 i = 1; i < REPEATED_SAMPLING_TIMES - 1; i++) {
		x_AD_temp += x_AD[i];
		y_AD_temp += y_AD[i];
	}

	x_AD_temp /= (REPEATED_SAMPLING_TIMES - 2);
	y_AD_temp /= (REPEATED_SAMPLING_TIMES - 2);

	//赋值
	*x_AD_AVG = x_AD_temp;
	*y_AD_AVG = y_AD_temp;
}

void XPT2046_getPoint(u16 *x, u16 *y)
{
	u16 x_AD_AVG = 0;
	u16 y_AD_AVG = 0;

	if (LGPIO_ReadInputDataBit(&PEN) == 0) {
		XPT2046_getSourceValue(&x_AD_AVG, &y_AD_AVG); //获取原始数据

		/*
		 * 具体计算依据如下,获取触摸屏左上角(800,7700)、右上角(7700,7700)、左下角(800,800)、右下角(7700,800)的AD值
		 * 发现x,y与对应的AD值成简单的线性关系,x对应的AD值从左到右由800增加到7700,y对应的AD值由7700减少到800,于是可以得到以下计算公式
		 */

		//计算点坐标
		*x = (x_AD_AVG - 800) * TOUCHPAD_WDITH / 6900;
		*y = 320 - (y_AD_AVG - 800) * TOUCHPAD_HEIGHT / 6900;

		//确保x和y不越界
		if (*x > TOUCHPAD_WDITH - 1)
			*x = TOUCHPAD_WDITH - 1;
		if (*y > TOUCHPAD_HEIGHT)
			*y = TOUCHPAD_HEIGHT;
	}

	return;
}

xpt2046.h

#ifndef HARDWARE_XPT2046_XPT2046_H_
#define HARDWARE_XPT2046_XPT2046_H_

#include "llib.h"

void XPT2046_init();
void XPT2046_getSourceValue(u16 *x_AD_AVG, u16 *y_AD_AVG); //这个函数可以用来校准数据
void XPT2046_getPoint(u16 *x, u16 *y); //获取按下的点的坐标

#endif /* HARDWARE_XPT2046_XPT2046_H_ */

xpt2046_command.h

#ifndef HARDWARE_XPT2046_XPT2046_COMMAND_H_
#define HARDWARE_XPT2046_XPT2046_COMMAND_H_


#define READ_CHANNEL_X		0xD0
#define READ_CHANNEL_Y		0x90

#endif /* HARDWARE_XPT2046_XPT2046_COMMAND_H_ */

用到的类型和宏:


typedef struct {
	GPIO_TypeDef *GPIOx;
	uint16_t GPIO_Pin;
	GPIOSpeed_TypeDef GPIO_Speed;
	GPIOMode_TypeDef GPIO_Mode;
} LGPIO;


#ifndef LGPIO_SPEED

#define LGPIO_InitTypeDef(LGPIO_Ptr)			((GPIO_InitTypeDef *)&((LGPIO_Ptr)->GPIO_Pin))

#define LGPIO_DeInit(GPIOx)						GPIO_DeInit(GPIOx)
#define LGPIO_AFIODeInit()						GPIO_AFIODeInit()
#define LGPIO_Init(LGPIO_Ptr)					GPIO_Init((LGPIO_Ptr)->GPIOx,LGPIO_InitTypeDef(LGPIO_Ptr))
#define LGPIO_StructInit(LGPIO_Ptr)				GPIO_StructInit(LGPIO_InitTypeDef(LGPIO_Ptr))
#define LGPIO_ReadInputDataBit(LGPIO_Ptr)		GPIO_ReadInputDataBit((LGPIO_Ptr)->GPIOx, (LGPIO_Ptr)->GPIO_Pin)
#define LGPIO_ReadInputData(GPIOx)				GPIO_ReadInputData(GPIOx)
#define LGPIO_ReadOutputDataBit(LGPIO_Ptr)		GPIO_ReadOutputDataBit((LGPIO_Ptr)->GPIOx, (LGPIO_Ptr)->GPIO_Pin)
#define LGPIO_ReadOutputData(GPIOx)				GPIO_ReadOutputData(GPIOx)
#define LGPIO_SetBits(LGPIO_Ptr)				GPIO_SetBits((LGPIO_Ptr)->GPIOx, (LGPIO_Ptr)->GPIO_Pin)
#define LGPIO_ResetBits(LGPIO_Ptr)				GPIO_ResetBits((LGPIO_Ptr)->GPIOx, (LGPIO_Ptr)->GPIO_Pin)
#define LGPIO_WriteBit(LGPIO_Ptr,BitVal)		GPIO_WriteBit((LGPIO_Ptr)->GPIOx, (LGPIO_Ptr)->GPIO_Pin, BitVal)
#define LGPIO_Write(GPIOx,PortVal)						GPIO_Write(GPIOx, PortVal)
#define LGPIO_PinLockConfig	(LGPIO_Ptr)			GPIO_PinLockConfig((LGPIO_Ptr)->GPIOx, (LGPIO_Ptr)->GPIO_Pin)
#define LGPIO_EventOutputConfig	(GPIO_PortSource,GPIO_PinSource)		GPIO_EventOutputConfig(GPIO_PortSource, GPIO_PinSource)
#define LGPIO_EventOutputCmd(NewState)									GPIO_EventOutputCmd(NewState)
#define LGPIO_PinRemapConfig(GPIO_Remap,NewState)						GPIO_PinRemapConfig(GPIO_Remap, NewState)
#define LGPIO_EXTILineConfig(GPIO_PortSource,GPIO_PinSource)			GPIO_EXTILineConfig(GPIO_PortSource, GPIO_PinSource)
#define LGPIO_ETH_MediaInterfaceConfig(GPIO_ETH_MediaInterface)			GPIO_ETH_MediaInterfaceConfig(GPIO_ETH_MediaInterface)

  • 3
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
xpt2046触摸屏是一种常见的电容式触摸屏,可以通过SPI接口与单片机嵌入式系统进行通信。在Linux系统中,可以通过编写驱动程序实现对xpt2046触摸屏的控制和数据读取。 以下是一个简单xpt2046触摸屏Linux驱动的示例代码: ```c #include <linux/module.h> #include <linux/kernel.h> #include <linux/spi/spi.h> #define XPT2046_CMD_X 0xD0 #define XPT2046_CMD_Y 0x90 #define XPT2046_MAX_X 4095 #define XPT2046_MAX_Y 4095 static struct spi_device *xpt2046_spi_dev; static int xpt2046_read_adc(u8 cmd) { u8 tx_buf[3] = {cmd, 0, 0}; u8 rx_buf[3] = {0, 0, 0}; struct spi_transfer transfer = { .tx_buf = tx_buf, .rx_buf = rx_buf, .len = 3, }; spi_sync_transfer(xpt2046_spi_dev, &transfer, 1); return ((rx_buf[1] << 8) | rx_buf[2]) >> 3; } static int xpt2046_read_touch(int *x, int *y) { int x_raw, y_raw; x_raw = xpt2046_read_adc(XPT2046_CMD_X); y_raw = xpt2046_read_adc(XPT2046_CMD_Y); *x = (x_raw * XPT2046_MAX_X) / 4096; *y = (y_raw * XPT2046_MAX_Y) / 4096; return 0; } static int xpt2046_probe(struct spi_device *spi_dev) { xpt2046_spi_dev = spi_dev; return 0; } static int xpt2046_remove(struct spi_device *spi_dev) { xpt2046_spi_dev = NULL; return 0; } static struct spi_driver xpt2046_spi_driver = { .driver = { .name = "xpt2046", .owner = THIS_MODULE, }, .probe = xpt2046_probe, .remove = xpt2046_remove, }; static int __init xpt2046_init(void) { return spi_register_driver(&xpt2046_spi_driver); } static void __exit xpt2046_exit(void) { spi_unregister_driver(&xpt2046_spi_driver); } module_init(xpt2046_init); module_exit(xpt2046_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Your Name"); MODULE_DESCRIPTION("XPT2046 Touchscreen Driver"); ``` 此示例代码实现了一个简单xpt2046触摸屏Linux驱动,可以通过SPI接口读取触摸坐标。在驱动程序中,首先定义了xpt2046触摸屏的命令码和最大坐标值。然后通过spi_sync_transfer()函数实现了SPI数据传输,读取x和y坐标。最后定义了驱动程序的初始化和退出函数,并注册到Linux内核中。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值