原版的标准库触摸板用的是软件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); }