触摸屏宽度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)