giovedì 21 aprile 2011

NDS Touchscreen can be a cheap touchpad

In this post I show you the best way to get an high performance touchpad with a little fee.

So before continue be sure to have:
  • Arduino Board (In this tutorial I'm using Arduino uno); otherwise you can use a PIC of Microchip
  • NDS touchscreen (I'm using NDS XL touchscreen)
  • A breadboard (no need too big) with some wires
  • 4x10KΩ resistors for pulldown net
Optionally, but recommended:
  • A breakout connector for NDS touchscreen (strongly suggest)
  • Some leds for get hardware feedback
  • A stylus for NDS touchscreen
Also be sure to have a serial client (like PuTTy or serial monitor embedded into Arduino toolchain) and a recent version of Matlab: this last maybe will help you to see completely the signal produced by circuit.
Let's work! First get a circuit like this:
Schematic of connections

Be careful to put correctly NDS touchscreen because in only one side it properly works; in another one touches don't modify resistor property. If you place it as shown in the figure can't go wrong.
Now we are interested in understanding how a resistive touch screen works: it's a two dimensional sensing device constructed by two parallel sheets, kept separate lightly by a spacer dots matrix distributed in the whole area. One of these sheets was made in PET to be flexible (touchable), the other was made by common glass (hard). Both are inner covered by a layer of resistance material, generally a metal oxide. The PET, with a finger pressure that reduce distance between sheets, can push down the resistance coating that meets the other. Our goal is to understand where this contact has happened.


Focus on structure of resistive touchscreen
To catch this information we have to use A/D convertors of our board; in particular we have to measure the voltage drop caused by the contact between two sheets. See the pictures showed below to understand how:

Schematic of circuits and signals need to read X value


Schematic of circuits and signals need to read Y value

The A/D reads the voltage drop and it's as high as x position (or y position). Of course it's required in one cycle we must change the status of pins A0..A4 to get x value and y value.
Now you can understand the role of pull down resistors: in fact the high resistance can stabilize the signal to read; in this way we get two benefits:
  1. We have a range of values around 800
  2. We don't need calibration
However I'm illustrating a simple method to get a great calibration. So let's to see a few code:

#define leftX = A2
#define rightX = A0
#define topY = A1
#define bottomY = A3


void read(int &x, int &y){
pinMode(leftX,OUTPUT); //Set the pin of X as OUTPUT
pinMode(rightX,OUTPUT);
digitalWrite(leftX,LOW); //And feed the circuit properly
digitalWrite(rightX,HIGH);


digitalWrite(bottomY,LOW);
digitalWrite(topY,LOW);
pinMode(bottomY,INPUT); //To read the voltage drop
pinMode(topY,INPUT);


delay(1);


int x=analogRead(bottomY); //Read the value of X


pinMode(bottomY,OUTPUT); //Following dual configuration
pinMode(topY,OUTPUT);
digitalWrite(bottomY,LOW);
digitalWrite(topY,HIGH);


digitalWrite(leftX,LOW);
digitalWrite(rightX,LOW);
pinMode(leftX,INPUT);
pinMode(rightX,INPUT);


delay(1);


int y=analogRead(xLow);
}

So you transmit the coordinates with RS232 protocol over COM with native serial of Arduino: be sure to have in your void setup(){...} function this row:


 Serial.begin(9600);


If you want can increse the Baud Rate, but 9600 enough. After reading x and y put this information over serial in this way:



Serial.print(x);
Serial.print(y);

Open your preferred serial client and connect to right COM port and see the result.
In my example I'm using PuTTy on COM6 (if you want, in devices configuration, can click on Arduino Device and in advance window change the COM port as you wish).


In this implementation you can't see which is x and y, but in this way you don't need a parser to extract information
As extra you can implement a calibration (e.g. if you don't use a pulldown net or to get very precise values) and a test of nds touchscreen limits. See the code below:


#define STRING_TO_CONFIRM "hc" //Change with your string

void calibrate(){
String incoming;
String cmp= String (STRING_TO_CONFIRM);
boolean cond = false;
  int i=0;
Serial.println("Touch it on left border; when finish send \"STRING_TO_CONFIRM \"-->");
   while(!cond){
     readXY();
if(x!=0) xmin=x; //If user touches the screen (x not zero) save the value
    while(Serial.available()>0) incoming[i++]=Serial.read();
      if(i==2){
       Serial.print(xmin);
       if(incoming.equals(cmp)) cond=true;
     }
     i=0;
   }
...//And same for other 3 borders
}

Indeed with calibration you can discover where is the effective range that you can exploit: do it for a few times and get this information to put statically in your code. In this way you can know the X Y min and max, so can try this function:


#define limXMin 8
#define limYMin 9
#define limXMax 10
#define limYMax 11

void check_limits(int x, int y){
    if(x<xmin && x>0)
      digitalWrite(limXMin,HIGH);
    else
      digitalWrite(limXMin,LOW);
    if(x>xmax)
      digitalWrite(limXMax,HIGH);
    else
      digitalWrite(limXMax,LOW);
    if(y<ymin && y>0)
      digitalWrite(limYMin,HIGH);
    else
      digitalWrite(limYMin,LOW);
    if(y>ymax)
      digitalWrite(limYMax,HIGH);
    else
      digitalWrite(limYMax,LOW);
}

When the stylus goes near borderline you can light 4 leds.
At the end you can overwork making a potentiometer to adjust, with PWM mode, brightness of two leds easily:

#define aproxxmin PUT_YOUR_VALUES
#define aproxxmax PUT_YOUR_VALUES
#define aproxymin PUT_YOUR_VALUES
#define aproxymax PUT_YOUR_VALUES
#define pwmX 3 //A right PWM pin has the ~ symbol
#define pwmY 5


int pwmx, pwmy;
...


void setup(){
...


  pwmx = 255/(aproxxmax/10) ;
  pwmy = 255/(aproyxmax/10);
  pinMode(3, OUTPUT);


  pinMode(5, OUTPUT);


...
}


void loop(){
...


  int x_ap=(tc.getx()-aproxxmin )/10;
  int y_ap=(tc.gety()-aproxymin )/10;


  analogWrite(3, x_ap*pwmx);
  analogWrite(5, y_ap*pwmy);


...
}

The methods stretches (compresses) the A/D values in a range [0, 255] that is the PWM range: you considere a generic signal bounded in a range [a, b]; if you wanna stretch it (or compress) in a new range [c, d] you have to do


Surely you're wondering why I did these strange calculations. The only reason is that Arduino operands has only 8/16 bit in ATMega and if you apply directly that formula you can obtain an overflow or underflow; also the term  was constant and can calculate once. To balance calculations you can multiply the difference signal - a by 10 and divide the difference d-c by 10.


In alternative you can analyze completely the quality of touchpad using MatLab. In this environment you can read the values transmitting on COM port like a file.


Use this simple implementation

%Hardware Code
%Serial reader for nds touchpad
%
%Author: DarkIaspis

comnds=serial('COM6');
fopen(comnds);
x=zeros(1,1000);
y=zeros(1,1000);
h=plot(x,y,'b.', 'MarkerSize',16);
axis([0 800 0 800])
for i = 1:1000
    x(i)=fscanf(comnds, '%d');
    y(i)=fscanf(comnds, '%d');
    set(h,'XData', x);
    set(h,'YData', y);
    drawnow;
end
fclose(comnds);
clear comnds;



That's all falks! I hope it was clear and helpful.






Nessun commento:

Posta un commento