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();
    }
}

 

 

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/tech/pnotes/289932.html

(0)
上一篇 2022年9月17日 02:29
下一篇 2022年9月17日 02:45

相关推荐

发表回复

登录后才能评论