简单易懂的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)

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: XPT2046是一种触摸屏控制器,通常被用于类似于Arduino的嵌入式系统中,用于触摸屏和微控制器之间的通信。为了确保触摸屏的准确性和稳定性,必须对XPT2046进行校准。 校准代码通常包含几个关键步骤。首先,需要计算出屏幕的尺寸并将其设定为常数。这样可以确保后续的校准操作都得到正确的数值。接下来,需要检测触摸点的位置和事件,以及屏幕的位置和事件。这可以通过编写一些简单的程序代码来实现,例如载入一个示例程序,然后测量Touch和Screen坐标之间的偏差。 在进行校准前,需要注意一些关键参数。例如,应该选择适当的触摸屏控制器模型,以确保其与您的微控制器兼容。此外,还需要设置适当的传感器类型和分辨率,以确保触摸点可以在屏幕上准确地确定位置。最后,您还应该调整校准参数,例如触摸屏的灵敏度和抗干扰性,以确保系统可以在不同条件下运行正常。 总体而言,XPT2046校准代码的编写需要一定的技术和经验。如果您在这方面缺乏经验,建议您咨询专业人士的意见,或参考一些经过验证和测试的示例程序。 ### 回答2: xpt2046校准代码是一段程序代码,用于针对触摸屏幕进行校准操作,通过校准可以使得触摸坐标的精度更高,避免误操作的发生。 一般而言,xpt2046校准代码主要包括以下步骤: 1. 定义变量:首先需要定义一些变量,如采样点个数、采样点时红色正方形的边长等。 2. 绘制红色正方形:通过设置绘图参数,绘制出一个红色的正方形,该正方形用于校准操作。 3. 采集坐标数据:进入循环,等待触摸事件的发生,一旦发生,则获取相应位置的坐标数据,并保存。 4. 绘制绿色点:在屏幕上绘制出一个小绿点作为标记,表示当前坐标已获取,并进行了校准。 5. 判断采样点个数:通过判断采样点个数是否达到预设值,来决定是否结束校准操作。 6. 计算校准参数:在所有的采样点坐标数据都获取完成后,通过对这些数据进行计算,可以得出校准参数,如kx,bx,ky,by等,这些参数被保存下来,用于后面的坐标转换操作。 7. 保存校准参数:将得到的校准参数保存到存储设备中,以便长期使用。 以上就是大致的xpt2046校准代码操作流程,在实际编程中需根据设备型号和具体情况进行调整。 ### 回答3: XPT2046是一款触摸屏控制芯片,校准代码是为了确保触摸屏的精确度和准确度。在使用XPT2046芯片的触摸屏时,我们需要进行校准操作,以便能够准确获取用户的触摸坐标信息。 XPT2046校准代码的主要流程是:首先获取原始触摸点的坐标和屏幕坐标,并将其进行相关计算;然后通过计算获得触摸点的坐标和实际屏幕坐标之间的差值,最后将差值应用到所有触摸点的坐标上,以实现校准。 在实际应用中,我们可以采用多种方法进行XPT2046的校准,例如通过官方提供的校准工具进行校准,或者使用校准代码进行手动校准。不同的校准方法可能会有所差异,但其基本原理都是相同的。 总之,XPT2046的校准代码是非常重要的,在使用触摸屏时必须正确进行校准,以确保其能够准确地响应用户操作,从而提高用户体验和设备的性能。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值