踩了好几个坑 。用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();
}
}
原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/289932.html