xpt2046电阻触摸屏 arduino库适配spi2在红牛stmf103例程红牛板_Touch(2.8和3.2寸)(2016.05.04)改硬spi
踩了好几个坑 。用hal库改写了触摸板例程后 尝试用arduino的 xpt2046库 始终读出来错的数据。尝试用了下tft-espi的触摸驱动 发现它的是正确的的。仔细阅读tft-espi的库。终于发现了原因
1.网上的xpt2046都是使用默认的spi1接口。在arduino框架了SPI已经被定义就是默认的第一个spi接口。想要使用红牛版的spi2通道,需要重新定义一个spi实例,并且名字不能是SPI2(这个名字被stm32的库中用到了)
2 网上的库给xpt2046传递的的参数不对。
这是我改写后的 实验可以读出来。使用stm32 的spi2,pb12做模拟片选,pg7做触摸中断
XPT2046_Touchscreen_h
/* Touchscreen library for XPT2046 Touch Controller Chip * Copyright (c) 2015, Paul Stoffregen, paul@pjrc.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice, development funding notice, and this permission * notice shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef _XPT2046_Touchscreen_h_ #define _XPT2046_Touchscreen_h_ #include "Arduino.h" #include <SPI.h> class TS_Point { public: TS_Point(void) : x(0), y(0), z(0) {} TS_Point(int16_t x, int16_t y, int16_t z) : x(x), y(y), z(z) {} bool operator==(TS_Point p) { return ((p.x == x) && (p.y == y) && (p.z == z)); } bool operator!=(TS_Point p) { return ((p.x != x) || (p.y != y) || (p.z != z)); } int16_t x, y, z; }; class XPT2046_Touchscreen { public: XPT2046_Touchscreen(uint8_t cspin, uint8_t tirq=255); bool begin(); TS_Point getPoint(); bool touched(); void readData(uint16_t *x, uint16_t *y, uint8_t *z); bool bufferEmpty(); uint8_t bufferSize() { return 1; } // protected: bool isrWake; private: void update(); uint8_t csPin, tirqPin; int16_t xraw, yraw, zraw; uint32_t msraw; }; #endif
XPT2046_Touchscreen.cpp
/* Touchscreen library for XPT2046 Touch Controller Chip * Copyright (c) 2015, Paul Stoffregen, paul@pjrc.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice, development funding notice, and this permission * notice shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "XPT2046_Touchscreen.h" #define Z_THRESHOLD 400 #define Z_THRESHOLD_INT 75 #define MSEC_THRESHOLD 3 #define SPI_SETTING SPISettings(2500000, MSBFIRST, SPI_MODE0) //使用spi2,注意不能用SPI2这个名字,stm32的库用到了这个。SPI是arduino默认的接口。如果要把他改成spi2需要改写arduino库。这里为了兼容不这么写 #define TFT_MOSI PB15 #define TFT_MISO PB14 #define TFT_SCLK PB13 SPIClass spi2(TFT_MOSI, TFT_MISO, TFT_SCLK); XPT2046_Touchscreen::XPT2046_Touchscreen(uint8_t cs, uint8_t tirq) { csPin = cs; tirqPin = tirq; msraw = 0x80000000; xraw = 0; yraw = 0; zraw = 0; isrWake = true; } static XPT2046_Touchscreen *isrPinptr; void isrPin(void); bool XPT2046_Touchscreen::begin() { spi2.begin(); pinMode(csPin, OUTPUT); digitalWrite(csPin, HIGH); if (255 != tirqPin) { pinMode(tirqPin, INPUT_PULLUP); attachInterrupt(tirqPin, isrPin, FALLING); isrPinptr = this; } return true; } void isrPin(void) { XPT2046_Touchscreen *o = isrPinptr; o->isrWake = true; } TS_Point XPT2046_Touchscreen::getPoint() { update(); return TS_Point(xraw, yraw, zraw); } bool XPT2046_Touchscreen::touched() { update(); return (zraw >= Z_THRESHOLD); } void XPT2046_Touchscreen::readData(uint16_t *x, uint16_t *y, uint8_t *z) { update(); *x = xraw; *y = yraw; *z = zraw; } bool XPT2046_Touchscreen::bufferEmpty() { return ((millis() - msraw) < MSEC_THRESHOLD); } static int16_t besttwoavg(int16_t x, int16_t y, int16_t z) { int16_t da, db, dc; int16_t reta = 0; if (x > y) da = x - y; else da = y - x; if (x > z) db = x - z; else db = z - x; if (z > y) dc = z - y; else dc = y - z; if (da <= db && da <= dc) reta = (x + y) >> 1; else if (db <= da && db <= dc) reta = (x + z) >> 1; else reta = (y + z) >> 1; // else if ( dc <= da && dc <= db ) reta = (x + y) >> 1; return (reta); } // TODO: perhaps a future version should offer an option for more oversampling, // with the RANSAC algorithm https://en.wikipedia.org/wiki/RANSAC void XPT2046_Touchscreen::update() { int16_t data[6]; if (!isrWake) return; uint32_t now = millis(); if (now - msraw < MSEC_THRESHOLD) return; //原版传递的参数都多了1,不知道为什么 spi2.beginTransaction(SPI_SETTING); digitalWrite(csPin, LOW); spi2.transfer(0xb0 /* Z1 */); // z1 0xb1 int16_t z1 = spi2.transfer16(0xC0 /* Z2 */) >> 3; // z2 0xc1 int z = z1 + 4095; int16_t z2 = spi2.transfer16(0x90 /* X */) >> 3; // x 0x91 z -= z2; if (z >= Z_THRESHOLD) { spi2.transfer16(0x91 /* X */); // dummy X measure, 1st is always noisy data[0] = spi2.transfer16(0xD0 /* Y */) >> 3; // y 0xD1 data[1] = spi2.transfer16(0x90 /* X */) >> 3; // make 3 x-y measurements data[2] = spi2.transfer16(0xD0 /* Y */) >> 3; data[3] = spi2.transfer16(0x90 /* X */) >> 3; } else data[0] = data[1] = data[2] = data[3] = 0; // Compiler warns these values may be used unset on early exit. data[4] = spi2.transfer16(0xD0 /* Y */) >> 3; // Last Y touch power down data[5] = spi2.transfer16(0) >> 3; digitalWrite(csPin, HIGH); spi2.endTransaction(); // Serial.printf("z=%d :: z1=%d, z2=%d ", z, z1, z2); if (z < 0) z = 0; if (z < Z_THRESHOLD) { // if ( !touched ) { // Serial.println(); zraw = 0; if (z < Z_THRESHOLD_INT) { // if ( !touched ) { if (255 != tirqPin) isrWake = false; } return; } zraw = z; // Average pair with least distance between each measured x then y // Serial.printf(" z1=%d,z2=%d ", z1, z2); // Serial.printf("p=%d, %d,%d %d,%d %d,%d", zraw, // data[0], data[1], data[2], data[3], data[4], data[5]); int16_t x = besttwoavg(data[0], data[2], data[4]); int16_t y = besttwoavg(data[1], data[3], data[5]); // Serial.printf(" %d,%d", x, y); // Serial.println(); if (z >= Z_THRESHOLD) { msraw = now; // good read completed, set wait xraw = x; yraw = y; } }
main.cpp
#include <Arduino.h> #include "WB_LCD.h" #include "XPT2046_Touchscreen.h" #define CS_PIN PB12 #define TIRQ_PIN PG7 XPT2046_Touchscreen ts(CS_PIN, TIRQ_PIN); void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {}; RCC_PeriphCLKInitTypeDef PeriphClkInit = {}; /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE; RCC_OscInitStruct.HSEState = RCC_HSE_ON; RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE; RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK) { Error_Handler(); } PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC | RCC_PERIPHCLK_USB; PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6; PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5; if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK) { Error_Handler(); } } void setup() { SystemClock_Config(); //启动72M主频 // put your setup code here, to run once: Serial.begin(57600); //这里使用usb cdc串口驱动 // while (!Serial) // { // ; /* code */ // } Serial.println("初始化lcd屏"); ts.begin(); LCD_Init(); // 初始化lcd屏 uint16_t lcd_id = DeviceCode; Serial.print("初始化完成, lcd id:0x"); Serial.println(lcd_id, HEX); Serial.print("主频:"); Serial.print(HAL_RCC_GetSysClockFreq()); Display_Test(); } void loop() { // put your main code here, to run repeatedly: LCD_Clear(WHITE); HAL_Delay(25); LCD_Clear(BLACK); HAL_Delay(25); LCD_Clear(BLUE); HAL_Delay(25); LCD_Clear(RED); HAL_Delay(25); LCD_Clear(GREEN); HAL_Delay(25); LCD_Clear(MAGENTA); HAL_Delay(25); LCD_Clear(CYAN); HAL_Delay(25); LCD_Clear(YELLOW); HAL_Delay(25); LCD_Clear(GRAY); HAL_Delay(25); LCD_Clear(BROWN); HAL_Delay(25); if (ts.touched()) { // ts操作 TS_Point p = ts.getPoint(); //打印信息 Serial.print("Pressure = "); Serial.print(p.z); Serial.print(", x = "); Serial.print(p.x); Serial.print(", y = "); Serial.print(p.y); delay(300); Serial.println(); } }
更新版 使用触摸参数直接返回坐标。或者用GitHub - achillhasler/TFT_eTouch: generic touch support for resistive chips 也可以
/* Touchscreen library for XPT2046 Touch Controller Chip * Copyright (c) 2015, Paul Stoffregen, paul@pjrc.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice, development funding notice, and this permission * notice shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #ifndef _XPT2046_Touchscreen_h_ #define _XPT2046_Touchscreen_h_ #include "Arduino.h" #include <SPI.h> class TS_Point { public: /* 触摸矫正参数 */ uint16_t X_WIDTH = 320;//屏x分辨率 uint16_t Y_WIDTH = 240; //屏Y分辨率 uint16_t min_x = 212; uint16_t min_y = 91; uint16_t max_x = 3933; uint16_t max_y = 3779; int16_t x, y, z; bool operator==(TS_Point p) { return ((p.x == x) && (p.y == y) && (p.z == z)); } bool operator!=(TS_Point p) { return ((p.x != x) || (p.y != y) || (p.z != z)); } // TS_Point(void) : x(0), y(0), z(0) {} TS_Point(int16_t x, int16_t y, int16_t z) ; }; class XPT2046_Touchscreen { public: XPT2046_Touchscreen(uint8_t cspin, uint8_t tirq = 255); bool begin(); TS_Point getPoint(); bool touched(); void readData(uint16_t *x, uint16_t *y, uint8_t *z); bool bufferEmpty(); uint8_t bufferSize() { return 1; } // protected: bool isrWake; private: void update(); uint8_t csPin, tirqPin; int16_t xraw, yraw, zraw; uint32_t msraw; };
#endif
/* Touchscreen library for XPT2046 Touch Controller Chip * Copyright (c) 2015, Paul Stoffregen, paul@pjrc.com * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice, development funding notice, and this permission * notice shall be included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ #include "XPT2046_Touchscreen.h" #define Z_THRESHOLD 400 #define Z_THRESHOLD_INT 75 #define MSEC_THRESHOLD 3 #define SPI_SETTING SPISettings(2500000, MSBFIRST, SPI_MODE0) //使用spi2,注意不能用SPI2这个名字,stm32的库用到了这个。SPI是arduino默认的接口。如果要把他改成spi2需要改写arduino库。这里为了兼容不这么写 #define TFT_MOSI PB15 #define TFT_MISO PB14 #define TFT_SCLK PB13 SPIClass spi2(TFT_MOSI, TFT_MISO, TFT_SCLK); TS_Point::TS_Point(int16_t xraw, int16_t yraw, int16_t z) { if (max_x > min_x) { x = (xraw - min_x) * X_WIDTH / (max_x - min_x); } else if (max_x < min_x) { x = (min_x - xraw) * X_WIDTH / (min_x - max_x); } if (max_y > min_y) { y = (yraw - min_y) * Y_WIDTH / (max_y - min_y); } else if (max_y < min_y) { y = (min_y - yraw) * Y_WIDTH / (min_y - max_y); } } XPT2046_Touchscreen::XPT2046_Touchscreen(uint8_t cs, uint8_t tirq) { csPin = cs; tirqPin = tirq; msraw = 0x80000000; xraw = 0; yraw = 0; zraw = 0; isrWake = true; } static XPT2046_Touchscreen *isrPinptr; void isrPin(void); bool XPT2046_Touchscreen::begin() { spi2.begin(); pinMode(csPin, OUTPUT); digitalWrite(csPin, HIGH); if (255 != tirqPin) { pinMode(tirqPin, INPUT_PULLUP); attachInterrupt(tirqPin, isrPin, FALLING); isrPinptr = this; } return true; } void isrPin(void) { XPT2046_Touchscreen *o = isrPinptr; o->isrWake = true; } TS_Point XPT2046_Touchscreen::getPoint() { return TS_Point(xraw, yraw, zraw); } bool XPT2046_Touchscreen::touched() { update(); return (zraw >= Z_THRESHOLD); } void XPT2046_Touchscreen::readData(uint16_t *x, uint16_t *y, uint8_t *z) { update(); *x = xraw; *y = yraw; *z = zraw; } bool XPT2046_Touchscreen::bufferEmpty() { return ((millis() - msraw) < MSEC_THRESHOLD); } static int16_t besttwoavg(int16_t x, int16_t y, int16_t z) { int16_t da, db, dc; int16_t reta = 0; if (x > y) da = x - y; else da = y - x; if (x > z) db = x - z; else db = z - x; if (z > y) dc = z - y; else dc = y - z; if (da <= db && da <= dc) reta = (x + y) >> 1; else if (db <= da && db <= dc) reta = (x + z) >> 1; else reta = (y + z) >> 1; // else if ( dc <= da && dc <= db ) reta = (x + y) >> 1; return (reta); } // TODO: perhaps a future version should offer an option for more oversampling, // with the RANSAC algorithm https://en.wikipedia.org/wiki/RANSAC void XPT2046_Touchscreen::update() { int16_t data[6]; if (!isrWake) return; uint32_t now = millis(); if (now - msraw < MSEC_THRESHOLD) return; //原版传递的参数都多了1,不知道为什么 spi2.beginTransaction(SPI_SETTING); digitalWrite(csPin, LOW); spi2.transfer(0xb0 /* Z1 */); // z1 0xb1 int16_t z1 = spi2.transfer16(0xC0 /* Z2 */) >> 3; // z2 0xc1 int z = z1 + 4095; int16_t z2 = spi2.transfer16(0x90 /* X */) >> 3; // x 0x91 z -= z2; if (z >= Z_THRESHOLD) { spi2.transfer16(0x91 /* X */); // dummy X measure, 1st is always noisy data[0] = spi2.transfer16(0xD0 /* Y */) >> 3; // y 0xD1 data[1] = spi2.transfer16(0x90 /* X */) >> 3; // make 3 x-y measurements data[2] = spi2.transfer16(0xD0 /* Y */) >> 3; data[3] = spi2.transfer16(0x90 /* X */) >> 3; } else data[0] = data[1] = data[2] = data[3] = 0; // Compiler warns these values may be used unset on early exit. data[4] = spi2.transfer16(0xD0 /* Y */) >> 3; // Last Y touch power down data[5] = spi2.transfer16(0) >> 3; digitalWrite(csPin, HIGH); spi2.endTransaction(); // Serial.printf("z=%d :: z1=%d, z2=%d ", z, z1, z2); if (z < 0) z = 0; if (z < Z_THRESHOLD) { // if ( !touched ) { // Serial.println(); zraw = 0; if (z < Z_THRESHOLD_INT) { // if ( !touched ) { if (255 != tirqPin) isrWake = false; } return; } zraw = z; // Average pair with least distance between each measured x then y // Serial.printf(" z1=%d,z2=%d ", z1, z2); // Serial.printf("p=%d, %d,%d %d,%d %d,%d", zraw, // data[0], data[1], data[2], data[3], data[4], data[5]); int16_t x = besttwoavg(data[0], data[2], data[4]); int16_t y = besttwoavg(data[1], data[3], data[5]); // Serial.printf(" %d,%d", x, y); // Serial.println(); if (z >= Z_THRESHOLD) { msraw = now; // good read completed, set wait xraw = x; yraw = y; } }