terça-feira, maio 25, 2021

Examinando um Shield Arduino com Display LCD TTF de 2,4" Sensível ao Toque - Parte 2

Na primeira parte vimos como é a interface com o controlador do display.  E a detecção de toque? Esta parte não é tratada pelo controlador, porém utiliza alguns pinos em comum com ele. Quais pinos e como implementar a detecção de toque deu um pouco de trabalho.


De forma resumida, quando realizamos um toque, é feito o contato entre duas linhas resistivas ortogonais (em formato de cruz). Dois pino estão ligados ao extremo da linha X e dois pinos estão ligados ao extremo da linha Y. Para conseguirmos detectar a posição do toque é preciso que pelo menos um extremo de cada linha esteja ligado a uma entrada analógica:

  • Detectar se temos um toque: colocamos em nível baixo os dois extremos de uma linha (por exemplo X), ligamos uma ponta da outra linha à alimentação via um pullup (basta configurar este pino como entrada com pullup) e examinamos a tensão na outra ponta. Se tiver toque, a tensão será próxima de zero (devido ao contato com a linha aterrada), caso contrário será alguma tensão positiva (devido ao pullup).
  • Determinar a posição no eixo X: Colocamos uma ponta do Y em nível alto e a outra em nível baixo e medimos a tensão na ponta do X ligada à entrada analógica.
  • Determinar a posição no eixo Y: Colocamos uma ponta do X em nível alto e a outra em nível baixo e medimos a tensão na ponta do Y ligada à entrada analógica.
Como descobrir quais os pinos usados? Basta desconectar o shield do Arduino e usar um multímetro para medir a resistência entre os pinos analógicos e os demais. A maioria das combinações vai ser indicada pelo multímetro como "aberto" (sem conexão). Dois pares vão indicar resistência, são os extremos das linhas. No meu caso foram (6, A1) e (7, A8). Você pode fazer um teste colocando o multímetro para medir a resistência entre uma ponta de uma linha e uma ponta da outra: sem toque fica em aberto, com toque resulta numa resistência que muda conforme onde você toca.

O programa abaixo mostra a detecção de toque e a determinação da posição:
// Conexões do display
const int lcdRST = A4;
const int lcdCS = A3;
const int lcdRS = A2;
const int lcdWR = A1;
const int lcdRD = A0;

const int lcdDATA[] = {8, 9, 2, 3, 4, 5, 6, 7 };

// Conexões do sensor de toque
const int touchY1 = A1;
const int touchY2 = 7;
const int touchX1 = A2;
const int touchX2 = 6;

// Iniciação
void setup() {
  // Inicia o controlador do display
  // (para ter certeza que não vai interferir)
  for (int i = 0; i < 8; i++) {
    pinMode(lcdDATA[i], INPUT);
  }
  pinMode(lcdRST, OUTPUT);
  digitalWrite (lcdRST, HIGH);
  delay(10);
  digitalWrite (lcdRST, LOW);
  delay(10);
  digitalWrite (lcdRST, HIGH);
  delay(10);
  pinMode(lcdCS, OUTPUT);
  digitalWrite (lcdCS, HIGH);
  pinMode(lcdRS, OUTPUT);
  digitalWrite (lcdRS, HIGH);
  pinMode(lcdRD, OUTPUT);
  digitalWrite (lcdRD, HIGH);
  pinMode(lcdWR, OUTPUT);
  digitalWrite (lcdWR, HIGH);

  // Inicia a serial
  Serial.begin(115200);
}

// Laço perpétuo
void loop() {
  static int maxX = 0, maxY = 0;
  static int minX = 1024, minY = 1024;
  int x, y;
  
  if (temToque()) {
    // Lê a posição
    x = toqueX();
    y = toqueY();

    // Atualiza mínimo e máximo
    if (x < minX) {
      minX = x;
    }
    if (x > maxX) {
      maxX = x;
    }
    if (y < minY) {
      minY = y;
    }
    if (y > maxY) {
      maxY = y;
    }

    // Mostra o resultado
    Serial.print ("X = ");
    Serial.print (x);
    Serial.print (" [");
    Serial.print (minX);
    Serial.print (":");
    Serial.print (maxX);
    Serial.print ("] Y = ");
    Serial.print (y);
    Serial.print (" [");
    Serial.print (minY);
    Serial.print (":");
    Serial.print (maxY);
    Serial.println ("]");
  }
  delay (1000);
}

// Verifica se tem toque
bool temToque() {
  pinMode (touchY1, INPUT);
  pinMode (touchY2, INPUT_PULLUP);
  pinMode (touchX1, OUTPUT);
  pinMode (touchX2, OUTPUT);
  digitalWrite (touchX1, LOW);
  digitalWrite (touchX2, LOW);
  delay(5);
  Serial.print ("Teste de toque: ");
  Serial.println (analogRead(touchY1));
  return analogRead(touchY1) < 30;
}

// Le a coordenada X do toque (sem escala)
int toqueX() {
  pinMode (touchX1, OUTPUT);
  pinMode (touchX2, OUTPUT);
  pinMode (touchY1, INPUT);
  pinMode (touchY2, INPUT);
  digitalWrite (touchX1, LOW);
  digitalWrite (touchX2, HIGH);
  delay(1);
  int soma = 0;
  for (int i = 0; i < 5; i++) {
    soma += analogRead(touchY1);
  }
  return soma/5;
}

// Le a coordenada Y do toque (sem escala)
int toqueY() {
  pinMode (touchX1, INPUT);
  pinMode (touchX2, INPUT);
  pinMode (touchY1, OUTPUT);
  pinMode (touchY2, OUTPUT);
  digitalWrite (touchY1, LOW);
  digitalWrite (touchY2, HIGH);
  delay(1);
  int soma = 0;
  for (int i = 0; i < 5; i++) {
    soma += analogRead(touchX1);
  }
  return soma/5;
}
Experimentando um pouco você vai ver que a variação da leitura fica apenas numa parte da faixa de 0 a 1023 do ADC. Você precisa fazer um processo de calibração para determinar os valores para os limites (pode variar de display para display); os valores intermediários são deduzidos supondo que a resistência varia linearmente.



Partes das informações aqui eu peguei em https://www.hackster.io/calogerus/arduino-uno-2-4-tft-lcd-display-shield-touch-panel-ili9341-576b1b. Notar que o display deste artigo tem a detecção de toque ligada em pinos diferentes.

Nenhum comentário: