Merge branch 'tfry-git-work/xpt2046'

This commit is contained in:
Roger Clark 2018-04-01 16:18:13 +10:00
commit 1c48f1aaa7
2 changed files with 110 additions and 62 deletions

View File

@ -8,81 +8,97 @@
#include "Arduino.h"
#include "XPT2046_touch.h"
XPT2046_touch::XPT2046_touch(uint8_t _cs_pin, SPIClass _spiChan) : cs_pin(_cs_pin), my_SPI(_spiChan){
setOversampling();
setThreshold();
}
/****************************************************************************/
XPT2046_touch::XPT2046_touch(uint8_t _cs_pin, SPIClass _spiChan) : cs_pin(_cs_pin), my_SPI(_spiChan){
}
/****************************************************************************/
void XPT2046_touch::begin(){
void XPT2046_touch::begin(){
pinMode(cs_pin, OUTPUT);
digitalWrite(cs_pin, HIGH);
my_SPI.begin();
}
}
/****************************************************************************/
uint16_t XPT2046_touch::gatherSamples(uint8_t command) {
uint32_t sample_sum = 0;
uint16_t samples[MAX_OVERSAMPLING];
boolean XPT2046_touch::read_XY(uint16_t *xy){
int z1, z2, tmpH, tmpL;
my_SPI.transfer16(command); // discard first reading after switching MUX
for (int i = 0; i < oversampling; ++i) {
samples[i] = my_SPI.transfer16(command);
sample_sum += samples[i];
}
int32_t avg = sample_sum / oversampling;
if (oversampling < 3) {
return avg >> 3;
}
// occasionally, we get a reading that is a _far_ outlier.
// checking for, and removing those improves quality a lot.
uint8_t n = oversampling;
for (int i = 0; i < oversampling; ++i) {
if (abs(avg - samples[i]) > 80) { // NOTE: data is left shifted by 3 at this point. I.e. the test is for 10+ pixels deviation from average
sample_sum -= samples[i];
--n;
}
}
if (n < 2) return avg >> 3;
else return (sample_sum / n) >> 3;
}
TS_Point XPT2046_touch::getPoint() {
uint16_t z1, z2;
my_SPI.beginTransaction(SPISettings(2000000, MSBFIRST, SPI_MODE0)); // max clock freq for XPT2046
digitalWrite(cs_pin, LOW);
TS_Point ret;
//Check if touch screen is pressed.
SPI.transfer(B10110011); // Z1
delay(10);
tmpH = (my_SPI.transfer(0) << 5);
tmpL = (my_SPI.transfer(0) >> 3);
z1 = tmpH | tmpL;
my_SPI.transfer(B10110011); // trigger Z1 reading
z1 = my_SPI.transfer16(B11000011) >> 3; // read Z1, and trigger Z2 reading
z2 = my_SPI.transfer16(B10010011) >> 3; // read Z2, and trigger Y reading
ret.z = z1 + 4095 - z2;
SPI.transfer(B11000011); // Z2
delay(10);
tmpH = (my_SPI.transfer(0) << 5);
tmpL = (my_SPI.transfer(0) >> 3);
z2 = tmpH | tmpL;
if((z2 - z1) < Z_THRESHOLD){ //If the touch screen is pressed, read the X,Y coordinates from XPT2046.
my_SPI.transfer(B11010011); // X
delay(10);
tmpH = (my_SPI.transfer(0) << 5);
tmpL = (my_SPI.transfer(0) >> 3);
xy[0] = tmpH | tmpL;
my_SPI.transfer(B10010011); // Y
delay(10);
tmpH = (my_SPI.transfer(0) << 5);
tmpL = (my_SPI.transfer(0) >> 3);
xy[1] = tmpH | tmpL;
digitalWrite(cs_pin, HIGH);
return true;
if(ret.z >= threshold){ //If the touch screen is pressed, read the X,Y coordinates from XPT2046.
ret.x = gatherSamples(B10010011);
ret.y = gatherSamples(B11010011);
} else {
ret.z = 0;
}
my_SPI.transfer(B00000000); // enter power saving (and IRQ enable)
digitalWrite(cs_pin, HIGH);
return false;
}
/****************************************************************************/
void XPT2046_touch::setButtonsNumber(byte columnButtons, byte rowButtons ){
_rowButtons = rowButtons;
_columnButtons = columnButtons;
}
/****************************************************************************/
uint8_t XPT2046_touch::getButtonNumber(){
my_SPI.endTransaction();
return ret;
}
boolean XPT2046_touch::read_XY(uint16_t *xy) {
TS_Point p = getPoint();
xy[0] = p.x;
xy[1] = p.y;
return p.z > 0;
}
////////////////// Buttons ////////////////
void XPT2046_touch::setButtonsNumber(byte columnButtons, byte rowButtons ){
_rowButtons = rowButtons;
_columnButtons = columnButtons;
}
uint8_t XPT2046_touch::getButtonNumber(){
uint16_t xy[2];
uint8_t tmp, buttonNum;
int div;
if(read_XY(xy)){
div = (X_MAX + X_MIN) / (_columnButtons + 1);
buttonNum = ((xy[1] / div));
div = (Y_MAX + Y_MIN) / _rowButtons;
tmp = ((xy[0] / div));
return ((buttonNum * _rowButtons) + tmp + 1); //Return the button number.
div = (X_MAX + X_MIN) / (_columnButtons + 1);
buttonNum = ((xy[1] / div));
div = (Y_MAX + Y_MIN) / _rowButtons;
tmp = ((xy[0] / div));
return ((buttonNum * _rowButtons) + tmp + 1); //Return the button number.
}
return 0; //Touch screen is not pressed.
}
/****************************************************************************/
}

View File

@ -11,7 +11,8 @@
#include <Arduino.h>
#include <SPI.h>
#define Z_THRESHOLD 3000
#define Z_THRESHOLD 3500 // Note: reversed for backwards compatiblity: 4095-x
#define MAX_OVERSAMPLING 32
// Pre-defined touch screen calibration for using the 2.4" ILI9341 LCD
#define X_MIN 830
@ -19,23 +20,54 @@
#define Y_MIN 550
#define Y_MAX 3550
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_touch{
class XPT2046_touch {
private:
uint8_t cs_pin;
SPIClass my_SPI;
uint8_t _rowButtons = 1;
uint8_t _columnButtons = 1;
uint8_t oversampling;
uint16_t threshold;
uint16_t gatherSamples(uint8_t command);
public:
XPT2046_touch(uint8_t _cs_pin, SPIClass _spiChan); //Contructor.
/** c'tor. Note that no IRQ pin is supported, here. You can easily do that yourself:
* \code if(digitalRead(irq_pin)) {
* // no press: skip
* } else {
* // _may_ be touched, but not necessarily reach the threshold
* TS_Point p = ts.getPoint();
* if (p.z > 0) {
* // do something
* }
* }
* \endcode */
XPT2046_touch(uint8_t _cs_pin, SPIClass _spiChan); //Contructor
void begin();
void setButtonsNumber(byte rowButtons, byte columnButtons);
/** Number of samples to average per point 0..32 */
void setOversampling(uint8_t num_readings = 7) {
oversampling = max(1, min(num_readings, MAX_OVERSAMPLING));
}
void setThreshold(uint16_t threshold = 4095 - Z_THRESHOLD) {
XPT2046_touch::threshold = threshold;
}
uint8_t getButtonNumber();
boolean read_XY(uint16_t *xy);
TS_Point getPoint();
};
#endif