20
BUILDING A SIMPLE EIGHT-BUTTON TOUCH PANEL

Project 6

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.)

sqr Select the LED to address

sqr Turn LED on and off

sqr Select steady on or blinking for each LED

sqr 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

f0280-01

Figure 20.1 A small touch panel frame with IR emitters and photo-transistors in place.

f0280-02

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.

f0281-01

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.

f0282-01

Figure 20.4 Touch panel schematic wiring diagram. (On the 16F877A, PORTD and PORTE are being used for the LCD.)

BUILDING THE TOUCH PANEL FRAME

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

f0283-01

Figure 20.5 Touch panel ready for connection to LAB-X1.

f0284-01

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.

f0284-02

Figure 20.7 Single IR transmitter—phototransistor pair wiring. (Signal to the PORTB pin is on or high when beam is not broken.)

f0285-01

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.

f0285-02

Figure 20.9 The finished touch panel.

THE SOFTWARE

We will divide the software into three independent modules:

sqr Read which of the eight points has been selected with getkey.

sqr Display the information on the LAB-X1 so we can see what is going on with display.

sqr 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.