TOUCH PANELS
Today, we see touch panels used everywhere. Every restaurant and store you visit has a handful of them. But how exactly do they work? Well, this chapter describes one way to skin this cat.
If you design an instrument or controller that needs a control panel in a hurry, by far the easiest way to make one is to do it with a touch panel. They are flexible and inexpensive and they go together fast. They are easily reprogrammed and most can be used with many applications just by changing the software. Depending on your requirements, the panel may be able to employ the PIC used by the instrument/controller you are designing, or it can be designed to have its own dedicated PIC.
In this project, we will build a touch panel to be placed over a plain piece of paper, with the functions written on the paper (see Figure 20.1). This panel will control the operation of two LEDs connected to the LAB-X1. We will control the operation of the LEDs from this panel. The following functions will be implemented. (Make a mental note that the control of a couple of small dc motors would be almost identical to this application.)
Select the LED to address
Turn LED on and off
Select steady on or blinking for each LED
Blink slower and blink faster for each LED
The principles involved in creating a touch interface for any number of applications are the same. Once you know how to create the interface on the LAB-X1, you will be able to add the interface to any surface. Though usually placed in front of a CRT, a touch interface is particularly well suited to being placed in front of printed and painted surfaces to
Figure 20.1 A small touch panel frame with IR emitters and photo-transistors in place.
Figure 20.2 The components soldered into the touch panel frame.
replace any number of pushbuttons. It can be made relatively weatherproof easily and has no moving parts. Of course, the same principles also apply for touch panels placed in front of CRTs, and CRTs have the advantage that we can change what is displayed with each touch.
Our goal is to create a two-position-by-four-position interface for the LEDs. This will give us the equivalent of the eight buttons we need for the operations we have in mind. We will use the interface to control two LEDs that we will add to the LAB-X1. As mentioned earlier, we want to be able to turn each one on and off and be able to control the rate at which each of the LEDs blinks independently.
HARDWARE NEEDS
In order to create this eight-button interface, we need six infrared (IR) light beams, one for each of the two rows and one each for the four columns. Each IR light beam needs an emitter and a sensor. We will also need a simple frame to hold the 12 opto-electronic devices in place above the piece of paper describing the functions of the eight buttons. Figure 20.2 shows the scheme used by me in its initial phase with the components in place and ready to be wired together. Figure 20.3 shows the next phase in the wiring.
SOFTWARE NEEDS
The function of the eight buttons that the interface will simulate will have to provide the following operations for the two LEDs:
LED 1 |
ON/OFF |
Steady or blink |
Blink faster |
Blink slower |
LED 2 |
ON/OFF |
Steady or blink |
Blink faster |
Blink slower |
Simultaneously, we will display the conditions inside the LAB-X1 on the LAB-X1’s LCD so we can actually see what is going on.
Figure 20.3 Detail wiring for the touch panel—close-up of one side. (For our immediate purposes, exposed wiring is acceptable.)
The operation of a touch interface is very similar to the scanning of a keyboard except that the wires and switches are replaced by infrared light beams and, of course, instead of making a contact with a switch, we break a light beam and detect the effect on a phototransistor. The problem is that light beams scatter and can illuminate more than one detector, while the wires go to one button only, making them easier to use. This means the scanning has to be more device-specific to be successful. We need to turn on one IR emitter at a time and look at the one phototransistor opposite it (ignoring all others). You will more clearly see what I mean by this as we go along.
Port usage: PORTA (two lines), PORTB (six lines), and PORTC (six lines) will be used for the project. Let’s use PORTB (six lines) for connection to the six phototransistors, and use PORTC’s (six lines) to power the six infrared LEDs one at a time. We will use the two lines (A.2 and A.3) on PORTA for the two LEDs. The wiring diagram for the touch screen as we will wire it is shown in Figure 20.4.
Figure 20.4 Touch panel schematic wiring diagram. (On the 16F877A, PORTD and PORTE are being used for the LCD.)
Now that we know what we need in the way of hardware, let’s build a simple touch frame. The easiest way to do this is to use a prefabricated PC board with lines on the back, and then cut out the parts you need to fit. Assemble the frame with the solder side out (as shown in Figure 20.5) and solder in the components. The IR beams that go across the LCD do not have to be at the same height as the ones that go across the short side but it will look better if they do.
The frame I made is approximately 4 inches long by 2 inches wide with sides 1 inch high. The infrared transmitters and phototransistors are to be placed on the half inch mark at every inch. I first assembled the frame and inserted the IR LEDs, the phototransistors and the resistors in place and make sure that they would all fit and still allow ample room for the wiring needed to connect everything up. Figure 20.4 shows how everything is wired together.
As shown in Figure 20.5, the LEDs and phototransistors are mounted in the printed circuit board segments that were cut from larger PC boards. The corners of the PC boards are held together with number 12 wire and then soldered firm. The wiring is extended from the LEDs and transistors back to the LAB-X1 ports as shown in the photos. Each wire has a push-on terminal attached to it that it is then placed in a header, which in turn fits on the pins that have been added to the LAB-X1 (see Figure 20.6). The two controlled LEDs can be mounted to the LAB-X1 board frame, or at a convenient location of your choice.
The basic scheme for using the IR transmitters with the photosensors is to turn them on and look at them a pair at a time in a suitable sequence and then to respond to the combination that indicates that a light beam that has been interrupted. The software
Figure 20.5 Touch panel ready for connection to LAB-X1.
Figure 20.6 Headers added to the LAB-X1 board for extension of pin signals to the panel.
pulls all of PORTB up with the internal pullups (OPTION_REG.7=0) and then grounds each line when the phototransistor conducts. Conduction takes place when the transistor is illuminated with IR. The circuitry for a one-line pair is shown in Figure 20.7.
Figure 20.7 Single IR transmitter—phototransistor pair wiring. (Signal to the PORTB pin is on or high when beam is not broken.)
Figure 20.8 Single IR transmitter—phototransistor pair wiring.
Note In the preceding case, we have pulled all the pins on PORTB high. So the dormant condition for our setup should keep the signal high when the light beam is not interrupted. When the phototransistor sees the IR, it conducts and its resistance goes to near zero and the signal goes to whatever side the phototransistor is connected to. In our case, this is 5 volts, so the signal is high when the IR is on and makes the transistor conduct. Figure 20.8 provides the opposite condition.
The signal to the PORTB pin is off or low when the beam is not broken. We do not want this condition. The finished panel is shown in Figure 20.9.
Figure 20.9 The finished touch panel.
We will divide the software into three independent modules:
Read which of the eight points has been selected with getkey.
Display the information on the LAB-X1 so we can see what is going on with display.
React to the selected key with do_it.
We need to set up the scan routine to determine which of the infrared beams have been interrupted so we can identify the area of the LCD that has been selected. The scheme for doing so is similar to the scheme used in scanning a keyboard. It consists of turning on the LED for column 1 and then checking to see if light beams for the column have been interrupted. We do this for each column one at a time. If a beam has been interrupted, the line associated with it will remain high. If it has not, we go on to the next line and check it. We make a record of the selection if a column was selected.
We do the same thing for the other row and then pass the information to the display routine, and then the execution routine. The execution routine uses the select case statement to choose the rows and column and react to them. After we are done, we reset the row and column variables to 0 and start over.
We start by creating all the code needed to activate the LAB-X1’s liquid crystal display (see Program 20.1). This is the standard code we use in all our programs that use the LCD.
Program 20.1 Segment 1, LCD DEFINEs
CLEAR ; always start with clear
DEFINE OSC 4 ; define oscillator speed
DEFINE LCD_DREG PORTD ; define LCD connections
DEFINE LCD_DBIT 4 ; data starts at bit 4
DEFINE LCD_DATA 4 ; 4 bit path
DEFINE LCD_RSREG PORTE ; select reg
DEFINE LCD_RSBIT 0 ; select bit
DEFINE LCD_EREG PORTE ; enable register
DEFINE LCD_EBIT 1 ; enable bit
LOW PORTE.2 ; make low for write only
ADCON1=%00001110 ; set the ports for PORTs A, and
; E to digital
PAUSE 500 ; pause for LCD start up
LCDOUT $FE, 1 ; clear LCD
Next, let’s set the data direction registers for all the ports we will be using. We will use PORTC for turning on the LEDs, and PORTB for detecting the condition of each of the phototransistors. PORTA will be used to turn the two LEDs on and off.
PORTD and PORTE are being used by the LCD, as indicated in Program 20.1.
Program 20.1 Segment 2—Set up the ports
TRISA = %00011001 ; Set PORTA
TRISB = %00111111 ; Set PORTB
TRISC = %00000110 ; Set PORTC
TRISD = %00000000 ; Set PORTD
TRISE = %00000000 ; Set PORTE
All the lines on PORTB are pulled high internally by the setting the option register as shown in Program 20.1
Program 20.1 Segment 3—Pull up PORTB
OPTION_REG.7=0
We are going to be looking at six of the eight lines on PORTB to determine if the touch panel has been accessed. (In our particular case, B.6,7 will not be used.) The six lines are connected as two rows of four columns to create the equivalent of an eight-button keypad. Check the wiring diagram again to see what is connected to what.
In this touchpad, we sense a selection when one of the column beams and one of the row beams is interrupted at the same time. The intersection identifies the selected area of the panel. In order to make sure one, and only one, area is selected, we turn on one column and then one row beam at a time, and if both of them are interrupted, we know we are at their intersection. We then turn on the next row on that column and check to see if both beams are interrupted and so on till all the rows and all the columns have been checked. We have to do it this way because the IR beams are diffuse and will illuminate more than one target when turned on. We eliminate all incorrect targets by looking at the intended target only.
In our wiring scheme, we turn the IR LEDs on in a sequence and look at the corresponding pin on PORTB to see if they have not been excited (= interrupted). On PORTC, the LEDs represented by 0 are turned on (the other side of the LEDs is tied to 5 volts). On PORTB, the pins will go 0 when on. (They were pulled up and showed as 1s when they were dormant.) We have to look at the six possible conditions and respond to each of them.
When the infrared illuminates the phototransistor, the transistor conducts and pulls the associated line on PORTB low. If your finger interrupts the beam, the PORTB line will become high. That is what we are looking for.
The rest of Program 20.1 follows, with extensive annotations:
Program 20.1 Final segment to make a finished program—the touch panel
X VAR WORD ; counter variable
Y VAR BYTE ; counter variable
ALPHA VAR WORD ; counter variable
BETA VAR WORD ; counter variable
STAT_1 VAR BYTE ; status of led
STAT_2 VAR BYTE ; status of led
LCD_1 VAR BYTE ; memory space
LCD_2 VAR BYTE ; memory space
LCD_ONE VAR PORTA.2 ; LCD connection
LCD_ONE=0 ; LCD turned off
LCD_TWO VAR PORTA.3 ; LCD connection
LCD_TWO=0 ; LCD turned off
COL VAR BYTE ; column counter
ROW VAR BYTE ; row counter
TIM0 VAR WORD ; time 0
TIM0 =10 ;
TIM1 VAR WORD ; time 1
TIM1=10 ;
BLINK VAR BIT ; blink status indication
BLINK=1 ;
GLOW VAR BIT ; glow status indication
GLOW=0 ;
ACTIVE VAR BIT ; active status indication
ACTIVE=1 ;
INACTIVE VAR BIT ; inactive status indication
INACTIVE=0 ;
;
PAUSE 500 ; pause for LCD startup
LCDOUT $FE, $01, “CLEARING LCD” ; clear LCD
PAUSE 250 ;
LCDOUT $FE, $01 ;
;
MAIN: ; main loop of the program
GOSUB GETKEY ; get the column and row
GOSUB DISPLAY ; display information on the LCD
GOSUB DO_IT ; take the necessary action
COL=0 ; rest the column memory
ROW=0 ; reset the row memory
GOTO MAIN ; do it forever
;
GETKEY: ; routine to get the row and column
PORTC=%11101111 ; turn on column 1
PAUSE 1 ; pause needed for LED to react
IF PORTB.0=1 THEN COL=1; check photo for col 1 and save if is 1
PORTC=%11011111 ; turn on column
PAUSE 1 ; pause needed for LED to react
IF PORTB.1=1 THEN COL=2; check photo for col 2 and save if is 1
PORTC=%10111111 ; turn on column
PAUSE 1 ; pause needed for LED to react
IF PORTB.2=1 THEN COL=3; check photo for col 3 and save if is 1
PORTC=%01111111 ; turn on column
PAUSE 1 ; pause needed for LED to react
IF PORTB.3=1 THEN COL=4 ; check photo for col 4 and save if is 1
PORTC=%11111110 ; turn on column
PAUSE 2 ; pause needed for LED to react
IF PORTB.4=1 THEN ROW=1 ; check photo for row 1 and save
; if is 1
PORTC=%11110111 ; turn on column
PAUSE 2 ; pause needed for LED to react
IF PORTB.5=1 THEN ROW=2 ; check photo for row 2 and save if
; is 1
PORTC=%11111111 ; turn everything off
RETURN ; end of routine
;
DISPLAY: ; show selection and PORTB and C
LCDOUT $FE, $80,”R=“,DEC1 ROW ,” C=“,DEC1 COL,” D=“,DEC3 TIM0,”_D=“,DEC3 TIM1
LCDOUT $FE, $C0, “B”, BIN8 PORTB, “ C”, BIN8 PORTC
RETURN ;
;
DO_IT: ; routine executes effect of selections
SELECT CASE ROW ; first look at the rows
CASE 1 ; ROW 1
SELECT CASE COL ; look at the columns
;
CASE 1 ; Column 1
IF LCD_ONE=1 THEN ; if LCD in ON
LCD_ONE=0 ; turn if OFF
LCD_1=INACTIVE ; set it as inactive
ELSE ; else
LCD_1=ACTIVE ; set it active
LCD_ONE=1 ; turn it on
STAT_1=GLOW ; remember it is glowing not blinking
TIM0=10 ; reset time to 10 count
ENDIF ; end of comparison
GOSUB PAUSER ; pause to de-bounce
;
CASE 2 ; column 2
IF LCD_1=ACTIVE THEN ; react only if the LED is on
IF STAT_1=GLOW THEN ; if it is glowing
STAT_1=BLINK ; turn it to blinking
ELSE ; else
STAT_1=GLOW ; turn it to glow
LCD_ONE=1 ; turn it on
ENDIF ; end of comparison
GOSUB PAUSER ; pause to de-bounce
ENDIF ; end of comparison
;
CASE 3 ; column 3
TIM0=TIM0-1 ; decrease time to make faster blink
IF TIM0 <1 THEN TIM0=1 ; if it is too low keep it at
; minimum of 1
GOSUB PAUSER1 ; delay for de bounce ;
CASE 4 ; column 4
TIM0=TIM0 + 1 ; increment the delay timer
IF TIM0 >20 THEN TIM0=20 ; if it is too high, set it as
; high
GOSUB PAUSER1 ; delay for de-bounce
CASE ELSE ; here if there was something else
END SELECT ; end of selection of all the rows
;
CASE 2 ; row 2
SELECT CASE COL ; look at the columns
CASE 1 ;
IF LCD_TWO=1 THEN ; the rest of the code duplicates what
LCD_TWO=0 ; was done for row 1 above line
; for line
LCD_2=INACTIVE ;
ELSE ;
LCD_2=ACTIVE ;
LCD_TWO=1 ;
STAT_2=GLOW ;
TIM1=10 ;
ENDIF ;
GOSUB PAUSER ;
;
CASE 2 ;
IF STAT_2=GLOW THEN ;
STAT_2=BLINK ;
ELSE ;
STAT_2=GLOW ;
ENDIF ;
GOSUB PAUSER ;
;
CASE 3 ;
TIM1=TIM1-1 ;
IF TIM1 <1 THEN TIM1=1 ;
GOSUB PAUSER1 ;
;
CASE 4 ;
TIM1=TIM1+1 ;
IF TIM1 >20 THEN TIM1=20 ;
GOSUB PAUSER1 ;
CASE ELSE ;
;
END SELECT ;
CASE ELSE ;
END SELECT ;
;The following segment of code uses the two “time counters” to
;turn the two LEDs on
;and off as specified by the faster/slower buttons. It counts each
;timing sequence
;independently and turns the related LED on and off.
IF LCD_1=ACTIVE THEN ;
IF STAT_1=BLINK THEN ;
ALPHA=ALPHA +1 ;
IF ALPHA>=TIM0 THEN ;
ALPHA=0 ;
TOGGLE LCD_ONE ;
ENDIF ;
ENDIF ;
ENDIF ;
IF LCD_2=ACTIVE THEN ;
IF STAT_2=BLINK THEN ;
BETA=BETA +1 ;
IF BETA>=TIM1 THEN ;
BETA=0 ;
TOGGLE LCD_TWO ;
ENDIF ;
ENDIF ;
ENDIF ;
RETURN ;
;
PAUSER: ; pause to de-bounce, long
FOR X=1 TO 300 ;
PAUSE 1 ;
NEXT X ;
RETURN ;
;
PAUSER1: ; pause to de-bounce, short
FOR X=1 TO 50 ;
PAUSE 1 ;
NEXT X ;
RETURN ;
END ;
EXERCISE
Modify the hardware and the Program 20.1 so the four columns are detected on lines B4 to B7, and then use the interrupt capability of these four lines to improve the performance of this program by making its operation crisper.