Interfacing with a touchscreen

From Mech
Jump to navigationJump to search

Overview

How a touchscreen works [1]

The goal of the project is to interface the PIC18F4520 with the 3M EX II 7720SC capacitive touchscreen. The spec sheet is located here: [2] (Use the last .pdf under Reference Materials). In addition, when a finger makes contact with the touchscreen, the X-Y coordinates will be displayed on a JHD 162A Parallel LCD (see C Example: Parallel Interfacing with LCDs).

There are many different types of touchscreen technologies. The one used below is a capacitive touchscreen. A capacitive touchscreen is usually coated in a charge storing material, such as indium tin oxide. Voltage is applied to each corner of the glass screen and electrodes are spread uniformly throughout the screen. Capacitive touchscreens are only responsive to finger touch which draw current from each side of the screen. The controller will then calculate the X-Y position of the finger from the current.

Advantages of the touchscreen are high touch resolution, high image clarity, and is not affected by dirt, grease, or moisture. However it can only be activated by the touch of something conductive, such as one's finger. [3]

On this page you will find the steps to implement the touchscreen interface on your own. This includes the code, circuit diagram, and other notes about creating the interface. If you build the circuit as displayed below and run the program through the PIC, you should be able to display on an LCD a finger's X-Y position on the touchscreen.




Circuit

Circuit schematic of connections between PIC, LCD, MAX232 and touchscreen
Photo of circuit

The image on the right is the circuit schematic showing the connections between all the components. An actual picture of the circuit is also shown.

The chips required for implementing this circuit are:
1) PIC 18F4520
2) MAX232N Dual EIA-232 Driver/Receiver
3) EXII 7720SC (touchscreen controller chip)
4) JHD 162A Parallel LCD

The PIC communicates with the touchscreen through the MAX232N chip. The MAX232N chip regulates the voltage of the input(RXD pin 3) and output(TXD pin 2) of the EXII 7720SC touchscreen chip(between -5V and +5V) to make it between 0 and +5V, since this is the signal range that is accepted by the PIC.

The +5V supply voltages and ground in the circuit can be connected to PIC +5V and ground.

A 10K potentiometer is used to adjust the contrast of the LCD.

The LCD displays X and Y coordinates starting from X:0 Y:0 to about X:16383 Y:16383 (this is when all the bits of X and Y are 1: 0011 1111 1111 1111). This means the touchscreen has 14-bit resolution. The origin is at the bottom left of the touchscreen as oriented in the photo on the right.

Note: When wiring the touchscreen you have a couple of options. The first option is to buy the appropriate connecting cables for the EXII 7720SC chip to interface with a PIC. If this is not a feasible option then a second option would be to take spare rainbow ribbon cable and fashion your own connecting cable. This can be down with a wire stripper and soldering. The circuit pictured here is an example of the second option.












Code

The file "flex_lcd.c" is required in order for the PIC to communicate with the LCD. The code for the file can be found here: C Example: Parallel Interfacing with LCDs

The PIC first transmits a "Format Tablet" command to the touchscreen chip, which tells the touchscreen what to transmit back to the PIC. When a finger makes contact with the touchscreen, the chip sends back a 10-byte string of hex values with the X and Y coordinates embedded in the first 5 bytes. This 10-byte string is processed by the PIC, which extracts the X and Y coordinates, converts them to int16 format, and outputs the numbers to the LCD.

The format of each touch signal returned from the touchscreen controller can be found on Table 8 (page 27) of the EXII 7720SC spec sheet. The code takes bits 0-13 of the X and Y parts of the signal (X0 - X13 and Y0 - Y13) and combines them into int16 variables x_pos and y_pos, which are displayed on the LCD.

Remember to change the baud rate in the code to 9600 baud, since this is the rate used by the touchscreen chip.

/*
touchscreen.c
Chris Chow, Anup Tapase, Lingyu Xie
Interface PIC with capacitive touchscreen and display X-Y coordinates on LCD
Feb 12, 2009
*/
#include <18f4520.h>
#use delay(clock=40000000)
#use rs232(baud=9600, UART1)      // hardware UART; uses  RC6/TX and RC7/RX
#include "flex_lcd.c"             //must include in order to output to LCD

int j;
int16 x_pos, y_pos;

void get_screen_pos(int16& x_pos, int16& y_pos);

void main()
{

   lcd_init();  // Always call this first.

   //command Format Tablet: "<SOH>FT<CR>" sent to touchscreen via RC6/TX pin
   putc(0x01);
   putc(0x46);
   putc(0x54);
   putc(0x0D);

   while (TRUE)
   {
      //get the finger position relative to the touchscreen in 16-bit int format
      get_screen_pos(x_pos, y_pos);

      printf(lcd_putc,"\fX: %Lu\n",x_pos); //output "X: <x_pos>" to first line of LCD
      printf(lcd_putc,"Y: %Lu",y_pos);     //output "Y: <y_pos>" to second line of LCD
   }
}

//Function adapted from Nick Marchuk's IR touchscreen code
void get_screen_pos(int16& x_pos, int16& y_pos)
{
   int i, gotD8, j;
   int touchscreen_rcx[20];
   int pos[5];
   int16 high16, low16, xtotal16, ytotal16;
   int temp4, total8;
   high16 = 0;
   low16 = 0;
   xtotal16 = 0;
   ytotal16 = 0;
   temp4 = 0;
   total8 = 0;

   //get 10 bytes from the touchscreen (each touch signal is 10 bytes)
   for (i=1;i<=10;++i)
   {
      touchscreen_rcx[i] = getc();
   }

   //find the first instance of 0xD8 (start of each signal)
   gotD8 = 0;
   j = 1;
   while(gotD8==0)
   {
      if((touchscreen_rcx[j] == 0xD8))
      {
         gotD8 = 1; //j is the location of 0xD8
      }
      else
      {
         j = j+1;
      }

      if(j==9)
      {
         gotD8 = 1; //didnt find it, dont loop forever
      }
   }

   pos[1] = touchscreen_rcx[j+1]; //xlow, bits: 0 X6 X5 X4 X3 X2 X1 X0 (see touchscreen datasheet for FT response))
   pos[2] = touchscreen_rcx[j+2]; //xhigh, bits: 0 X13 X12 X11 X10 X9 X8 X7
   pos[3] = touchscreen_rcx[j+3]; //ylow, bits: 0 Y6 Y5 Y4 Y3 Y2 Y1 Y0
   pos[4] = touchscreen_rcx[j+4]; //yhigh, bits: 0 Y13 Y12 Y11 Y10 Y9 Y8 Y7

   //make the x
   temp4 = pos[2];
   high16 = temp4; //make high16= 0000 0000 0X13X12X11 X10X9X8X7
   low16 = pos[1]; //make low16= 0000 0000 0X6X5X4 X3X2X1X0

   xtotal16 = low16|(high16<<7); //OR 00X13X12 X11X10X9X8 X7000 0000 with 0000 0000 0X6X5X4 X3X2X1X0
   x_pos = xtotal16; //x_pos=00X13X12 X11X10X9X8 X7X6X5X4 X3X2X1X0

   //make the y
   temp4 = pos[4];
   high16 = temp4; //make high16= 0000 0000 0Y13Y12Y11 Y10Y9Y8Y7
   low16 = pos[3]; //make low16= 0000 0000 0Y6Y5Y4 Y3Y2Y1Y0

   ytotal16 = low16|(high16<<7); //OR 00Y13Y12 Y11Y10Y9Y8 Y7000 0000 with 0000 0000 0Y6Y5Y4 Y3Y2Y1Y0
   y_pos = ytotal16;             //x_pos=00Y13Y12 Y11Y10Y9Y8 Y7Y6Y5Y4 Y3Y2Y1Y0
}


Experimental Notes

A vibration is felt when a finger is moved along the touchscreen. Since the finger activates the touchscreen by drawing current and acting as a capacitor, we think that the slight vibrations that are felt are due to the current being drawn through the finger.

When two fingers touch the screen at the same time, the output is the average of the two sets of coordinates. For example, if a finger is placed at X:0 Y:0 and another is placed on X: 16000 Y: 16000, the output is X: 8000 Y: 8000. We see the same behavior as we put more fingers on the screen at different locations; the output is the average of all the location coordinates. This can even be seen if only one finger is touching it; depending on how much of the finger is touching the screen, the output changes to get the center of the contact point.

The reason why a finger works with the touchscreen is that the finger exhibits capacitive qualities. The human body has charge that can draw current from the touchscreen. When someone touches the screen some of the charge on the surface is transferred to the person creating a drop in the charge on the screen. The relative difference in charge from each of the corners of the screen is calculated and a location is the output. We suspect that other materials that can draw current, such as a piece of fruit, might also work.[4]


Additional Code

The following code was developed as an extension to this project. It uses a very similar circuit, although there is another set of rs232 pins to communicate with the computer. It is also interrupt driven on the Rx UART1 pin and uses a LIFO circular input buffer.


//3M Touchscreen Code
//Jake Ware
//10/9/09

#include <18f4520.h>
#use delay(clock=20000000)
#use rs232(baud=9600, STREAM=TS, UART1, PARITY=N, BITS=8, STOP=1)
#use rs232(baud=9600, STREAM=PC, XMIT=PIN_B0, RCV=PIN_B1, PARITY=N, BITS=8, STOP=1, DISABLE_INTS)

#define LED_0 PIN_D0
#define LED_1 PIN_D1

unsigned int16 read = 0, write = 0;
int position[10];
int buffer[10];
int16 x_pos, y_pos;

void compute_pos(int16& x_pos, int16& y_pos);

#INT_RDA
void rs232_handler() 
{
   output_high(LED_0);
   buffer[read%10] = fgetc(TS);
   read++;
   output_low(LED_0);
}

//Main Program
void main()
{
   //start sequence
   fprintf(PC, "Program Start\r\n");
   
   //Set Touch Screen Controller Communication Format: "<SOH>PN812<CR>" (Parity = N, Bit = 8, Stop = 1, Baud = 9600)
   fputc(0x01, TS);
   fputc(0x50, TS);
   fputc(0x4e, TS);
   fputc(0x38, TS);
   fputc(0x31, TS);
   fputc(0x32, TS);
   fputc(0x0D, TS);

   //command Format Tablet: "<SOH>FT<CR>" sent to touchscreen via RC6/TX pin
   fputc(0x01, TS);
   fputc(0x46, TS);
   fputc(0x54, TS);
   fputc(0x0D, TS);
   
   enable_interrupts(INT_RDA);
   enable_interrupts(GLOBAL);
   
   output_high(LED_0);
   delay_ms(25);
   output_low(LED_0);

   while (TRUE)
   {
      if(kbhit(TS)) {
         output_high(LED_1);
         //get the finger position relative to the touchscreen in 16-bit int format
         compute_pos(x_pos, y_pos);
         if(x_pos < 1024 && y_pos < 1024) {
            fprintf(PC, "%Ld:%Ld\n", x_pos, y_pos);
//            fprintf(PC, "\r\n%Lu||%Lu\r\n", read, write);
         }
      } else {
         output_low(LED_1);
      }
   }
}

//Function adapted from Nick Marchuk's IR touchscreen code
void compute_pos(int16& x_pos, int16& y_pos)
{
   int i = 0, flag_D8 = 0, loc_D8 = 0;
   int pos[5];
   int16 high = 0, low = 0, total;

//   fprintf(PC, "\r\n\n//////Loop Start//////");
   
   while(flag_D8 == 0)
   {
      //get 10 bytes from the touchscreen (each touch signal is 5 bytes)
      for (i=0; i<10; i++) {
         position[i] = buffer[(((read+1)%10)+i)%10];
         write++;
      }   
      //find the first instance of 0xD8 (start of each signal) and then break out of loop
      for(i=0; i<6; i++) {
         if((position[i] == 0xD8)) {
            loc_D8 = i; //i is the location of 0xD8
            flag_D8 = 1;
            break;
         }
      }
   }

//   fprintf(PC, "\r\nloc_D8 = %d", loc_D8);

   pos[0] = position[loc_D8];
   pos[1] = position[loc_D8+1]; //xlow, bits: 0 X6 X5 X4 X3 X2 X1 X0 (see touchscreen datasheet for FT response))
   pos[2] = position[loc_D8+2]; //xhigh, bits: 0 X13 X12 X11 X10 X9 X8 X7
   pos[3] = position[loc_D8+3]; //ylow, bits: 0 Y6 Y5 Y4 Y3 Y2 Y1 Y0
   pos[4] = position[loc_D8+4]; //yhigh, bits: 0 Y13 Y12 Y11 Y10 Y9 Y8 Y7
   
//   fprintf(PC, "\r\npos[i]=[%x, %x, %x, %x, %x]", pos[0], pos[1], pos[2], pos[3], pos[4]);
   
   //make the x
   total = 0;
   high = pos[1];                              //make low16= 0000 0000 0X6X5X4 X3X2X1X0
   low = pos[2];                             //make high16= 0000 0000 0X13X12X11 X10X9X8X7
   total = (low << 8)|high;                //OR 00X13X12 X11X10X9X8 X7000 0000 with 0000 0000 0X6X5X4 X3X2X1X0
   x_pos = total/32;                            //x_pos=00X13X12 X11X10X9X8 X7X6X5X4 X3X2X1X0
   
/*   
   fprintf(PC, "\r\n\nMaking X:");
   fprintf(PC, "\r\nhigh = %Lx", high);
   fprintf(PC, "\r\nlow = %Lx", low);
   fprintf(PC, "\r\ntotal = %Lx", total);
*/   

   //make the y  
   total = 0;
   high = pos[3];                              //make low16= 0000 0000 0Y6Y5Y4 Y3Y2Y1Y0   
   low = pos[4];                               //make high16= 0000 0000 0Y13Y12Y11 Y10Y9Y8Y7  
   total = (low << 8)|high;                //OR 00Y13Y12 Y11Y10Y9Y8 0000 0000 with 0000 0000 0Y6Y5Y4 Y3Y2Y1Y0 
   y_pos = total/32;                            //x_pos=00Y13Y12 Y11Y10Y9Y8 Y7Y6Y5Y4 Y3Y2Y1Y0
   
/*   
   fprintf(PC, "\r\n\nMaking Y:");
   fprintf(PC, "\r\nhigh = %Lx", high);
   fprintf(PC, "\r\nlow = %Lx", low);
   fprintf(PC, "\r\ntotal = %Lx", total);
*/   
}