红牛stmf103原版例程红牛板_Touch(2.8和3.2寸)(2016.05.04)改硬spi
原版的标准库触摸板用的是软件gpio模拟spi 但是读出来的值都是0无法使用。参考以前的官方bsp教程使用硬件spi读取触摸芯片的值。把用spi操作的部分改成硬spi
Touch.h
#ifndef __TOUCH_H #define __TOUCH_H #include "stm32f10x.h" #include "WB_LCD.h" #include "stdlib.h" #include "math.h" #include "24c02.h" #include "delay.h" #define Key_Down 0x01 //触摸状态 #define Key_Up 0x00 #define READ_TIMES 15 //读取次数 #define LOST_VAL 5 //丢弃值 #define ERR_RANGE 10 //误差范围 typedef struct { u16 X0; //原始坐标 u16 Y0; u16 X; //最终/暂存坐标 u16 Y; u8 Key_Sta; //笔的状态 float xfac; //触摸屏校准参数 float yfac; short xoff; short yoff; }Pen_Holder; extern Pen_Holder Pen_Point; //触摸屏芯片连接引脚配置 #define PEN GPIOG->IDR&0x0080 //PG7 INT #define DOUT GPIOB->IDR&0x4000 //PB14 MISO #define TDIN(x) ((x) ? (GPIOB->BSRR = 0x00008000):(GPIOB->BSRR = 0x80000000)) //PB15 MOSI #define TCLK(x) ((x) ? (GPIOB->BSRR = 0x00002000):(GPIOB->BSRR = 0x20000000)) //PB13 SCLK #define TCS(x) ((x) ? (GPIOB->BSRR = 0x00001000):(GPIOB->BSRR = 0x10000000)) //PB12 CS //ADS7843/7846/UH7843/7846/XPT2046/TSC2046 指令集 #define CMD_RDY 0x90 //0B10010000即用差分方式读X坐标 #define CMD_RDX 0xD0 //0B11010000即用差分方式读Y坐标 void Touch_Init(void); void Touch_Adjust(void); void Convert_Pos(void); void Pen_Int_Set(uint8_t en); void Touch_Configuration(void); uint8_t SPI_WriteByte(uint8_t data); uint16_t ADS_Read_AD(uint8_t TOUCH_MSR_XY); uint16_t ADS_Read_XY(uint8_t xy); uint8_t Read_TP_Once(void); uint8_t Read_ADS2(uint16_t *x,uint16_t *y); uint8_t Read_ADS(uint16_t *x,uint16_t *y); void Save_Adjdata(void); //保存校准参数 void Drow_Touch_Point(uint8_t x,uint16_t y,uint16_t Color); void Draw_Big_Point(uint8_t x,uint16_t y,uint16_t Color); //打点 void Load_Drow_Dialog(void); void Draw_Color_Box(void); #endif
touch/c 修改了spi读写函数,spi初始化函数
/** * @file Touch.c * @author WB R&D Team - openmcu666 * @version V1.0 * @date 2016.05.05 * @brief Touch Driver */ #include "Touch.h" Pen_Holder Pen_Point; //定义笔实体 /** * @brief SPI写1byte数据 * @param 写入的数据 * @retval 接收到的字节 */ uint8_t SPI_WriteByte(uint8_t data) { //Wait until the transmit buffer is empty while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET); // Send the byte SPI_I2S_SendData(SPI2, data); //Wait until a data is received while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_RXNE) == RESET); // Get the received data data = SPI_I2S_ReceiveData(SPI2); // Return the shifted data return data; } /** * @brief 从7846/7843/XPT2046/UH7843/UH7846读取adc值 * @param 命令 * @retval 读取的数据 */ uint16_t ADS_Read_AD(uint8_t TOUCH_MSR_XY) { uint16_t usAdc; TCS(0); /* 使能TS2046的片选 */ SPI_WriteByte(TOUCH_MSR_XY); usAdc = (SPI_WriteByte(0x00) & 0x7F) << 5; usAdc |= (SPI_WriteByte(0x00) >> 3) & 0x1F; TCS(1); /* 禁能片选 */ //printf("%d ", TOUCH_MSR_XY); //测试用 //printf("%d ", usAdc); //测试用 return (usAdc); } /** * @brief 连续读取READ_TIMES次数据,对这些数据升序排列, 然后去掉最低和最高LOST_VAL个数,取平均值 * @param 读坐标命令 * @retval 坐标值 */ uint16_t ADS_Read_XY(uint8_t xy) { uint16_t i, j; uint16_t buf[READ_TIMES]; uint16_t sum = 0; uint16_t temp; for (i = 0; i < READ_TIMES; i++) { buf[i] = ADS_Read_AD(xy); } for (i = 0; i < READ_TIMES - 1; i++) //排序 { for (j = i + 1; j < READ_TIMES; j++) { if (buf[i] > buf[j]) //升序排列 { temp = buf[i]; buf[i] = buf[j]; buf[j] = temp; } } } sum = 0; for (i = LOST_VAL; i < READ_TIMES - LOST_VAL; i++) sum += buf[i]; temp = sum / (READ_TIMES - 2 * LOST_VAL); return temp; } /** * @brief 带滤波的坐标读取 最小值不能少于200. * @param xy首地址 * @retval return 1读数成功 */ uint8_t Read_ADS(uint16_t *x, uint16_t *y) { uint16_t xtemp, ytemp; xtemp = ADS_Read_XY(CMD_RDX); ytemp = ADS_Read_XY(CMD_RDY); if (xtemp < 200 || ytemp < 200) return 0; //读数失败 *x = xtemp; *y = ytemp; return 1; //读数成功 } /** * @brief 2次读取ADS7846,连续读取2次有效的AD值,且这两次的偏差不能超过 ERR_RANGE,满足条件,则认为读数正确,否则读数错误. * @param xy首地址 * @retval return 1读数成功 */ uint8_t Read_ADS2(uint16_t *x, uint16_t *y) { uint16_t x1, y1; uint16_t x2, y2; uint8_t flag; flag = Read_ADS(&x1, &y1); if (flag == 0) return (0); flag = Read_ADS(&x2, &y2); if (flag == 0) return (0); if (((x2 <= x1 && x1 < x2 + ERR_RANGE) || (x1 <= x2 && x2 < x1 + ERR_RANGE)) //前后两次采样在+-50内 && ((y2 <= y1 && y1 < y2 + ERR_RANGE) || (y1 <= y2 && y2 < y1 + ERR_RANGE))) { *x = (x1 + x2) / 2; *y = (y1 + y2) / 2; return 1; } else return 0; } /** * @brief 读取一次坐标值,直到PEN松开才返回! * @param None * @retval return 1读数成功 */ uint8_t Read_TP_Once(void) { uint8_t t = 0; Pen_Int_Set(0); //关闭中断 Pen_Point.Key_Sta = Key_Up; Read_ADS2(&Pen_Point.X, &Pen_Point.Y); while (!(PEN & 0x80) && t <= 250) { t++; Delay(10); } Pen_Int_Set(1); //开启中断 if (t >= 250) return 0; //按下2.5s 认为无效 else return 1; } /** * @brief 画一个触摸点,用来校准用的 * @param x,y:TFT坐标 * @retval None */ void Drow_Touch_Point(uint8_t x, uint16_t y, uint16_t Color) { LCD_DrawLine(x - 12, y, x + 13, y, Color); //横线 LCD_DrawLine(x, y - 12, x, y + 13, Color); //竖线 LCD_DrawPoint(x + 1, y + 1, Color); LCD_DrawPoint(x - 1, y + 1, Color); LCD_DrawPoint(x + 1, y - 1, Color); LCD_DrawPoint(x - 1, y - 1, Color); LCD_DrawCircle(x, y, 6, Color); //画中心圈 } /** * @brief 画一个2*2的点 * @param x,y:TFT坐标 Color 打点颜色 * @retval None */ void Draw_Big_Point(uint8_t x, uint16_t y, uint16_t Color) { LCD_DrawPoint(x, y, Color); //中心点 LCD_DrawPoint(x + 1, y, Color); LCD_DrawPoint(x, y + 1, Color); LCD_DrawPoint(x + 1, y + 1, Color); } /** * @brief 根据触摸屏的校准参数来决定转换后的结果,保存在X0,Y0中 * @param None * @retval None */ void Convert_Pos(void) { if (Read_ADS2(&Pen_Point.X, &Pen_Point.Y)) { Pen_Point.X0 = Pen_Point.xfac * Pen_Point.X + Pen_Point.xoff; Pen_Point.Y0 = Pen_Point.yfac * Pen_Point.Y + Pen_Point.yoff; } } /** * @brief 获取校准值 * @param None * @retval return 1 读数成功 */ u8 Get_Adjdata(void) { s32 temp_data; u16 temp[8], i; temp_data = AT24CXX_Read(0x20, temp, 8); if (temp[0] == 0xff) { for (i = 0; i < 8; i++) { temp[i] = 0; } AT24CXX_Read(0x00, temp, 8); temp_data = (s32)((temp[3] << 24) | (temp[2] << 16) | (temp[1] << 8) | temp[0]); Pen_Point.xfac = (float)temp_data / 100000000; AT24CXX_Read(0x08, temp, 8); temp_data = (s32)((temp[3] << 24) | (temp[2] << 16) | (temp[1] << 8) | temp[0]); Pen_Point.yfac = (float)temp_data / 100000000; AT24CXX_Read(0x10, temp, 8); temp_data = (s32)((temp[1] << 8) | temp[0]); Pen_Point.xoff = temp_data; AT24CXX_Read(0x18, temp, 8); temp_data = (s32)((temp[1] << 8) | temp[0]); Pen_Point.yoff = temp_data; return 1; } return 0; } /** * @brief 得到四个校准参数 * @param None * @retval None */ void Touch_Adjust(void) { uint16_t pos_temp[4][2]; //坐标缓存值 uint8_t cnt = 0; uint16_t d1, d2; uint32_t tem1, tem2; float fac; cnt = 0; LCD_Clear(WHITE); //清屏 Drow_Touch_Point(20, 20, RED); //画点1 Pen_Point.Key_Sta = Key_Up; //消除触发信号 Pen_Point.xfac = 0; // xfac用来标记是否校准过,所以校准之前必须清掉!以免错误 while (1) { if (Pen_Point.Key_Sta == Key_Down) //按键按下了 { if (Read_TP_Once()) //得到单次按键值 { pos_temp[cnt][0] = Pen_Point.X; pos_temp[cnt][1] = Pen_Point.Y; cnt++; } switch (cnt) { case 1: LCD_Clear(WHITE); //清屏 Drow_Touch_Point(220, 20, RED); //画点2 break; case 2: LCD_Clear(WHITE); //清屏 Drow_Touch_Point(20, 300, RED); //画点3 break; case 3: LCD_Clear(WHITE); //清屏 Drow_Touch_Point(220, 300, RED); //画点4 break; case 4: //全部四个点已经得到 //对边相等 tem1 = abs(pos_temp[0][0] - pos_temp[1][0]); // x1-x2 tem2 = abs(pos_temp[0][1] - pos_temp[1][1]); // y1-y2 tem1 *= tem1; tem2 *= tem2; d1 = sqrt(tem1 + tem2); //得到1,2的距离 tem1 = abs(pos_temp[2][0] - pos_temp[3][0]); // x3-x4 tem2 = abs(pos_temp[2][1] - pos_temp[3][1]); // y3-y4 tem1 *= tem1; tem2 *= tem2; d2 = sqrt(tem1 + tem2); //得到3,4的距离 fac = (float)d1 / d2; if (fac < 0.95 || fac > 1.05 || d1 == 0 || d2 == 0) //不合格 { cnt = 0; LCD_Clear(WHITE); //清屏 Drow_Touch_Point(20, 20, RED); continue; } tem1 = abs(pos_temp[0][0] - pos_temp[2][0]); // x1-x3 tem2 = abs(pos_temp[0][1] - pos_temp[2][1]); // y1-y3 tem1 *= tem1; tem2 *= tem2; d1 = sqrt(tem1 + tem2); //得到1,3的距离 tem1 = abs(pos_temp[1][0] - pos_temp[3][0]); // x2-x4 tem2 = abs(pos_temp[1][1] - pos_temp[3][1]); // y2-y4 tem1 *= tem1; tem2 *= tem2; d2 = sqrt(tem1 + tem2); //得到2,4的距离 fac = (float)d1 / d2; if (fac < 0.95 || fac > 1.05) //不合格 { cnt = 0; LCD_Clear(WHITE); //清屏 Drow_Touch_Point(20, 20, RED); continue; } //正确了 //对角线相等 tem1 = abs(pos_temp[1][0] - pos_temp[2][0]); // x1-x3 tem2 = abs(pos_temp[1][1] - pos_temp[2][1]); // y1-y3 tem1 *= tem1; tem2 *= tem2; d1 = sqrt(tem1 + tem2); //得到1,4的距离 tem1 = abs(pos_temp[0][0] - pos_temp[3][0]); // x2-x4 tem2 = abs(pos_temp[0][1] - pos_temp[3][1]); // y2-y4 tem1 *= tem1; tem2 *= tem2; d2 = sqrt(tem1 + tem2); //得到2,3的距离 fac = (float)d1 / d2; if (fac < 0.95 || fac > 1.05) //不合格 { cnt = 0; LCD_Clear(WHITE); //清屏 Drow_Touch_Point(20, 20, RED); continue; } //正确了 //计算结果 Pen_Point.xfac = (float)200 / (pos_temp[1][0] - pos_temp[0][0]); //得到xfac Pen_Point.xoff = (240 - Pen_Point.xfac * (pos_temp[1][0] + pos_temp[0][0])) / 2; //得到xoff Pen_Point.yfac = (float)280 / (pos_temp[2][1] - pos_temp[0][1]); //得到yfac Pen_Point.yoff = (320 - Pen_Point.yfac * (pos_temp[2][1] + pos_temp[0][1])) / 2; //得到yoff LCD_Clear(WHITE); //清屏 LCD_DisplayStr(35, 110, (unsigned char *)"Touch Screen Adjust OK!", RED, WHITE); //显示校正完成 Delay(1000); LCD_Clear(WHITE); //清屏 return; //校正完成 } } } } /** * @brief 保存校准参数 * @param None * @retval None */ void Save_Adjdata(void) { s32 temp_data; u16 temp[8]; temp_data = Pen_Point.xfac * 100000000; //保存x校正因素 temp[0] = (u8)(temp_data & 0xff); //保存x校正因素 temp[1] = (u8)((temp_data >> 8) & 0xff); //保存x校正因素 temp[2] = (u8)((temp_data >> 16) & 0xff); //保存x校正因素 temp[3] = (u8)((temp_data >> 24) & 0xff); //保存x校正因素 AT24CXX_Write(0x00, temp, 8); temp_data = Pen_Point.yfac * 100000000; //保存y校正因素 temp[0] = (u8)(temp_data & 0xff); //保存x校正因素 temp[1] = (u8)((temp_data >> 8) & 0xff); //保存x校正因素 temp[2] = (u8)((temp_data >> 16) & 0xff); //保存x校正因素 temp[3] = (u8)((temp_data >> 24) & 0xff); //保存x校正因素 AT24CXX_Write(0x08, temp, 8); temp_data = Pen_Point.xoff; temp[0] = (u8)(temp_data & 0xff); temp[1] = (u8)((temp_data >> 8) & 0xff); AT24CXX_Write(0x10, temp, 8); temp_data = Pen_Point.yoff; temp[0] = (u8)(temp_data & 0xff); temp[1] = (u8)((temp_data >> 8) & 0xff); AT24CXX_Write(0x18, temp, 8); temp[0] = 0xff; AT24CXX_Write(0x20, temp, 8); } /** * @brief SPI引脚配置(x模拟SPIx) 使能硬件SPI2, 片选由软件控制 * @param None * @retval None */ void Touch_Configuration() //把模拟spi改成硬件spi { GPIO_InitTypeDef GPIO_InitStructure; SPI_InitTypeDef SPI_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOG | RCC_APB2Periph_AFIO, ENABLE); //重要!! //下面是SPI相关GPIO初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //通用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); // Configure PB12 pin: TP_CS pin PB12片选 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //通用推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); // Configure PC5??? pin: TP_INT pin GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; // TOUCH_INT PG7触摸中断 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入 GPIO_Init(GPIOG, &GPIO_InitStructure); NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断分组2 NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; //配置中断线7 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; //先占优先级0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //次占优先级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); /* SPI1总线 配置 */ SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //全双工 SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主模式 SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; // 8位 SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //时钟极性 空闲状态时,SCK保持低电平 SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //时钟相位 数据采样从第一个时钟边沿开始 SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //软件产生NSS SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64; //波特率控制 SYSCLK/64 SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据高位在前 SPI_InitStructure.SPI_CRCPolynomial = 7; // CRC多项式寄存器初始值为7 SPI_Init(SPI2, &SPI_InitStructure); /* SPI2 使能 */ SPI_Cmd(SPI2, ENABLE); } /** * @brief 触摸初始化 * @param None * @retval None */ void Touch_Init() { EXTI_InitTypeDef EXTI_InitStructure; Touch_Configuration(); Read_ADS(&Pen_Point.X, &Pen_Point.Y); //第一次读取初始化 RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //使能IO复用功能,使用中断功能重要!!! /* Connect PEN EXTI Line to Key Button GPIO Pin */ GPIO_EXTILineConfig(GPIO_PortSourceGPIOG, GPIO_PinSource7); /* Configure PEN EXTI Line to generate an interrupt on falling edge */ EXTI_InitStructure.EXTI_Line = EXTI_Line7; EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; EXTI_InitStructure.EXTI_LineCmd = ENABLE; EXTI_Init(&EXTI_InitStructure); /* Generate software interrupt: simulate a falling edge applied on PEN EXTI line */ EXTI_GenerateSWInterrupt(EXTI_Line7); LCD_Clear(WHITE); //清屏 if (Get_Adjdata()) { return; } //已经校准 else //未校准 { Touch_Adjust(); //屏幕校准 Save_Adjdata(); //保存校准值 } Get_Adjdata(); //获取校准值 } /** * @brief 中断开关 * @param 1开中断 0关中断 * @retval None */ void Pen_Int_Set(uint8_t en) { if (en) EXTI->IMR |= 1 << 7; //开启line7上的中断 else EXTI->IMR &= ~(1 << 7); //关闭line7上的中断 } /** * @brief 清除画图区域 * @param None * @retval None */ void Load_Drow_Dialog(void) { LCD_Fill(50, 0, 240, 320, WHITE); LCD_DrawCircle(230, 10, 10, RED); } /** * @brief 显示画笔颜色选择框 * @param None * @retval None */ void Draw_Color_Box(void) { LCD_Fill(20, 30, 50, 60, RED); LCD_Fill(20, 70, 50, 100, GREEN); LCD_Fill(20, 110, 50, 140, BLUE); LCD_Fill(20, 150, 50, 180, YELLOW); LCD_Fill(20, 190, 50, 220, MAGENTA); LCD_DrawCircle(230, 10, 10, RED); }
附上使用hal库函数的文件
TOUCH_H
#ifndef __TOUCH_H #define __TOUCH_H #include "stm32f1xx_hal.h" #include "main.h" #include "spi.h" extern SPI_HandleTypeDef hspi2; void MX_SPI2_Init(void); typedef struct { uint16_t usAdcNowX; uint16_t usAdcNowY; uint16_t coordX; uint16_t coordY; uint16_t min_x, max_x; uint16_t min_y, max_y; uint8_t Enable; /* �������ʹ�ܱ�־ */ } TOUCH_T; extern TOUCH_T touch_device; /* �����¼� */ enum { TOUCH_NONE = 0, /* ���� */ TOUCH_DOWN = 1, /* ���� */ TOUCH_MOVE = 2, /* �ƶ� */ TOUCH_RELEASE = 3 /* �ͷ� */ }; /* ���ⲿ���õĺ������� */ void TOUCH_InitHard(void); void TOUCH_SCAN(void); #endif
touch.c
#include <stdio.h> #include "touch.h" /* PB12 --> TP_CS PB13 --> TP_SCK PB14 --> TP_MISO PB15 --> TP_MOSI PG7 --> TP_PEN_INT */ /* TSC2046 片选 */ #define CS_0() HAL_GPIO_WritePin(TP_CS_GPIO_Port, TP_CS_Pin, GPIO_PIN_RESET) #define CS_1() HAL_GPIO_WritePin(TP_CS_GPIO_Port, TP_CS_Pin, GPIO_PIN_SET) #define TOUCH_PressValid HAL_GPIO_ReadPin(GPIOG, TP_INT_Pin) /* TSC2046读取转换命令 */ #define TOUCH_MSR_X 0xd0 //读X轴坐标指令 #define TOUCH_MSR_Y 0x90 //读Y轴坐标指令 #define X_WIDTH 240 #define Y_WIDTH 320 /* 触屏模块用到的全局变量 */ TOUCH_T touch_device; static void TSC2046_InitHard(void); uint16_t TSC2046_ReadAdc(uint8_t _ucCh); void TOUCH_LoadParam(void); void TOUCH_SaveParam(void); int32_t TOUCH_Abs(int32_t x); /* ********************************************************************************************************* * 函 数 名: TOUCH_InitHard * 功能说明: 配置STM32和触摸相关的口线,使能硬件SPI2, 片选由软件控制 * 形 参:无 * 返 回 值: 无 ********************************************************************************************************* */ void TOUCH_InitHard(void) { TSC2046_InitHard(); TOUCH_LoadParam(); /* 读取校准参数 */ touch_device.Enable = 1; } /* ********************************************************************************************************* * 函 数 名: TOUCH_DataFilter * 功能说明: 读取一个坐标值(x或者y) * 连续读取XPT2046_READ_TIMES次数据,对这些数据升序排列, * 然后去掉最低和最高XPT2046_LOST_VAL个数,取平均值 * 形 参:无 * 返 回 值: 读到的数据 ********************************************************************************************************* */ /* 读取次数 */ #define XPT2046_READ_TIMES 5 /* 丢弃值 */ #define XPT2046_LOST_VAL 1 uint16_t TOUCH_DataFilter(uint8_t _ucCh) { uint16_t i, j; uint16_t buf[XPT2046_READ_TIMES]; uint16_t usSum; uint16_t usTemp; /* 读取READ_TIMES次数据*/ for (i = 0; i < XPT2046_READ_TIMES; i++) { buf[i] = TSC2046_ReadAdc(_ucCh); } /* 升序排列 */ for (i = 0; i < XPT2046_READ_TIMES - 1; i++) { for (j = i + 1; j < XPT2046_READ_TIMES; j++) { if (buf[i] > buf[j]) { usTemp = buf[i]; buf[i] = buf[j]; buf[j] = usTemp; } } } usSum = 0; /*求和 */ for (i = XPT2046_LOST_VAL; i < XPT2046_READ_TIMES - XPT2046_LOST_VAL; i++) { usSum += buf[i]; } /*求平均 */ usTemp = usSum / (XPT2046_READ_TIMES - 2 * XPT2046_LOST_VAL); return usTemp; } /* ********************************************************************************************************* * 函 数 名: TOUCH_ReadAdcXY * 功能说明: 连续2次读取触摸屏IC,且这两次的偏差不能超过 * ADC_ERR_RANGE,满足条件,则认为读数正确,否则读数错误. * 该函数能大大提高准确度 * 形 参:x,y:读取到的坐标值 * 返 回 值: 0,失败;1,成功 ********************************************************************************************************* */ /* 误差范围 */ uint8_t ADC_ERR_RANGE = 5; uint8_t TOUCH_ReadAdcXY(int16_t *_usX, int16_t *_usY) { uint16_t iX1, iY1; uint16_t iX2, iY2; int16_t iX, iY; iX1 = TOUCH_DataFilter(TOUCH_MSR_X); iY1 = TOUCH_DataFilter(TOUCH_MSR_Y); iX2 = TOUCH_DataFilter(TOUCH_MSR_X); iY2 = TOUCH_DataFilter(TOUCH_MSR_Y); iX = TOUCH_Abs(iX1 - iX2); iY = TOUCH_Abs(iY1 - iY2); /* 前后两次采样在+-ERR_RANGE内 */ if ((iX <= ADC_ERR_RANGE) && (iY <= ADC_ERR_RANGE)) { *_usY = (iX1 + iX2) / 2; *_usX = (iY1 + iY2) / 2; // *_usX = (iX1 + iX2) / 2; // *_usY = (iY1 + iY2) / 2; return 1; } else { return 0; } } void Coord_trans(void) { if (touch_device.max_x > touch_device.min_x) { touch_device.coordX = (touch_device.usAdcNowX - touch_device.min_x) * Y_WIDTH / (touch_device.max_x - touch_device.min_x); } else if (touch_device.max_x < touch_device.min_x) { touch_device.coordX = (touch_device.min_x - touch_device.usAdcNowX) * Y_WIDTH / (touch_device.min_x - touch_device.max_x); } if (touch_device.max_y > touch_device.min_y) { touch_device.coordY = (touch_device.usAdcNowY - touch_device.min_y) * X_WIDTH / (touch_device.max_y - touch_device.min_y); } else if (touch_device.max_y < touch_device.min_y) { touch_device.coordY = (touch_device.min_y - touch_device.usAdcNowY) * X_WIDTH / (touch_device.min_y - touch_device.max_y); } } /* ********************************************************************************************************* * 函 数 名: TOUCH_SCAN * 功能说明: 触摸板事件检测程序。该函数被周期性调用,每1ms调用1次. 见 bsp.c * 形 参:无 * 返 回 值: 无 ********************************************************************************************************* */ void TOUCH_SCAN(void) { uint8_t s_invalid_count = 0; if (TOUCH_PressValid == 0) { while (!TOUCH_ReadAdcXY(&touch_device.usAdcNowX, &touch_device.usAdcNowY) && s_invalid_count < 20) ; { s_invalid_count++; } if (s_invalid_count >= 20) { touch_device.usAdcNowX = -1; touch_device.usAdcNowY = -1; } } else { touch_device.usAdcNowX = -1; touch_device.usAdcNowY = -1; } } static void NVIC_Configuration(void) //中断设置 { // NVIC_InitTypeDef NVIC_InitStructure; // /* Enable the EXTI0 Interrupt */ // NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn; // NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // NVIC_Init(&NVIC_InitStructure); } void EXTI_Enable(uint32_t enable) //开启关闭中断功能 { // EXTI_InitTypeDef EXTI_InitStructure; // /* Configure EXTI */ // EXTI_InitStructure.EXTI_Line = EXTI_Line7; // EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; // EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // Falling下降沿 Rising上升 if (enable) { /* enable */ HAL_NVIC_EnableIRQ(EXTI9_5_IRQn); } else { /* disable */ HAL_NVIC_DisableIRQ(EXTI9_5_IRQn); } // EXTI_Init(&EXTI_InitStructure); // EXTI_ClearITPendingBit(EXTI_Line7); } static void EXTI_Configuration(void) //已在cubeMX自动生成 { // { // GPIO_InitTypeDef GPIO_InitStructure; // RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE); // GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; // GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz; // GPIO_Init(GPIOG, &GPIO_InitStructure); // } // GPIO_EXTILineConfig(GPIO_PortSourceGPIOG, GPIO_PinSource7); // /* Configure EXTI */ // EXTI_Enable(1); } /* ********************************************************************************************************* * 函 数 名: TSC2046_InitHard * 功能说明: 配置STM32和触摸相关的口线,使能硬件SPI2, 片选由软件控制 * 形 参:无 * 返 回 值: 无 ********************************************************************************************************* */ static void TSC2046_InitHard(void) // spi跟按键设置需要用hal替代 { // GPIO_InitTypeDef GPIO_InitStructure; // SPI_InitTypeDef SPI_InitStructure; // // NVIC_Configuration(); // // EXTI_Configuration(); // RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2,ENABLE); // RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOG | RCC_APB2Periph_AFIO, ENABLE ); //重要!! // //下面是SPI相关GPIO初始化 // GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15; // GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //通用推挽输出 // GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // GPIO_Init(GPIOB,&GPIO_InitStructure); // //Configure PB12 pin: TP_CS pin // GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; // GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //通用推挽输出 // GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // GPIO_Init(GPIOB,&GPIO_InitStructure); //已经在gpio。c中设置 // //Configure PG7 pin: TP_INT pin // GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; // GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入??? // GPIO_Init(GPIOG,&GPIO_InitStructure);//已经在gpio。c中设置 // /* SPI1总线 配置 */ // SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex; //全双工 // SPI_InitStructure.SPI_Mode = SPI_Mode_Master; //主模式 // SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b; //8位 // SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; //时钟极性 空闲状态时,SCK保持低电平 // SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; //时钟相位 数据采样从第一个时钟边沿开始 // SPI_InitStructure.SPI_NSS = SPI_NSS_Soft; //软件产生NSS // SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_64; //波特率控制 SYSCLK/64 // SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB; //数据高位在前 // SPI_InitStructure.SPI_CRCPolynomial = 7; //CRC多项式寄存器初始值为7 // SPI_Init(SPI2, &SPI_InitStructure); // /* SPI2 使能 */ // SPI_Cmd(SPI2,ENABLE); } /* ********************************************************************************************************* * 函 数 名: SPI_WriteByte * 功能说明: 向SPI总线发送一个字节,同时返回接收到的字节 * 形 参:写入的数据 * 返 回 值: 接收到的字节 ********************************************************************************************************* */ static uint8_t SPI_WriteByte(uint8_t data) { // Wait until the transmit buffer is empty // while (SPI_I2S_GetFlagStatus(SPI2, SPI_I2S_FLAG_TXE) == RESET) // while (__HAL_SPI_GET_FLAG(&hspi2, SPI_FLAG_TXE) == RESET) ; // Send the byte // SPI_I2S_SendData(hspi2, data); // Wait until a data is received // while (SPI_I2S_GetFlagStatus(hspi2, SPI_I2S_FLAG_RXNE) == RESET) // while (__HAL_SPI_GET_FLAG(&hspi2, SPI_FLAG_TXE) == RESET) ; // Get the received data // data = SPI_I2S_ReceiveData(hspi2); // Return the shifted data // return data; uint8_t Rxdata; HAL_SPI_TransmitReceive(&hspi2, &data, &Rxdata, 1, 1000); return Rxdata; //返回收到的数据 } /* ********************************************************************************************************* * 函 数 名: Touch_Delay * 功能说明: 延时 * 形 参:时间 * 返 回 值: 无 ********************************************************************************************************* */ void Touch_Delay(uint32_t DelayCnt) { uint32_t i; for (i = 0; i < DelayCnt; i++) ; } /* ********************************************************************************************************* * 函 数 名: TSC2046_ReadAdc * 功能说明: 选择一个模拟通道,启动ADC,并返回ADC采样结果 * 形 参:_ucCh = TOUCH_MSR_X表示X通道; TOUCH_MSR_Y表示Y通道 * 返 回 值: 12位ADC值 ********************************************************************************************************* */ uint16_t TSC2046_ReadAdc(uint8_t TOUCH_MSR_XY) { uint16_t usAdc; CS_0(); /* 使能TS2046的片选 */ SPI_WriteByte(TOUCH_MSR_XY); usAdc = (SPI_WriteByte(0x00) & 0x7F) << 5; usAdc |= (SPI_WriteByte(0x00) >> 3) & 0x1F; CS_1(); /* 禁能片选 */ return (usAdc); } /* ********************************************************************************************************* * 函 数 名: TOUCH_Abs * 功能说明: 计算绝对值 * 形 参:无 * 返 回 值: 无 ********************************************************************************************************* */ int32_t TOUCH_Abs(int32_t x) { if (x >= 0) { return x; } else { return -x; } } /* ********************************************************************************************************* * 函 数 名: TOUCH_SaveParam * 功能说明: 保存校准参数 s_usAdcX1 s_usAdcX2 s_usAdcY1 s_usAdcX2 * 形 参:无 * 返 回 值: 无 ********************************************************************************************************* */ void TOUCH_SaveParam(void) { #if 0 /* 保存下面的4个变量即可 */ uint16_t usBuf[5]; usBuf[0] = touch_device.min_x; usBuf[1] = touch_device.min_y; usBuf[2] = touch_device.max_x; usBuf[3] = touch_device.max_y; #endif } /* ********************************************************************************************************* * 函 数 名: TOUCH_LoadParam * 功能说明: 读取校准参数 * 形 参:无 * 返 回 值: 无 ********************************************************************************************************* */ void TOUCH_LoadParam(void) { #if 1 /* 保存下面的5个变量即可 */ // uint16_t usBuf[5]; /* ReadParamToBuf() */ touch_device.min_x = 212; // usBuf[0]; touch_device.min_y = 91; // usBuf[1]; touch_device.max_x = 3933; // usBuf[2]; touch_device.max_y = 3779; // usBuf[3]; #endif } // void EXTI9_5_IRQHandler(void) //中断事件 被回调函数重写 // { // /* disable interrupt */ // EXTI_Enable(0); // TOUCH_SCAN(); // EXTI_ClearITPendingBit(EXTI_Line7); // EXTI_Enable(1); // } void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) //中断事件 { if (GPIO_Pin == TP_INT_Pin) { EXTI_Enable(0); TOUCH_SCAN(); __HAL_GPIO_EXTI_CLEAR_IT(TP_INT_Pin); EXTI_Enable(1); } }