7
CLOCKS, MEMORY, AND SOCKETS

Sockets U3, U4, and U5: For Serial One-Wire Memory Devices

Most PIC microcontrollers come with a certain amount of on-chip memory. This memory is enough for most applications created for these tiny processors, but there are times when more memory is needed to get the job done. The LAB-X1 has five empty 8-pin sockets. Three of these (the three on the left) are designed to allow us to experiment with three types of single-wire memory ICs. The ICs don’t need just one wire for full control, but the data does go back and forth on one wire.

Note Each memory socket accepts only one type of memory device, and only one of the ICs is allowed to be in place at any one time because the lines are shared between the sockets, so having more than one device plugged in can create conflicts.

Depending on the type of memory you want to experiment with, one of the three schematics in Figure 7.1 is applicable.

The interfaces that have been developed for the three types of one-wire memory give you the choices you need for flexibility in board design and layout, but it also means that a single interface and protocol won’t work for everything. The interfaces vary in speed, number of signal lines, and in other important details.

Since the memories are all one-wire serial devices, their memory content can vary from 128 bytes to 4 kilobytes or more and still maintain the 8-pin interface.

The salient characteristics of the three types of memory are as follows:

sqr I2C SEEPROM I2C SEEPROMs are serial, electrically erasable and programmable, read-only memories. They are best suited for applications needing a modest amount of inexpensive nonvolatile memory where a lot of I/O lines are not available for memory transfers. Requires four lines for control.

f0114-01

Figure 7.1 One-wire memory sockets. (The three types of memory you can experiment with on the LAB-X1 and their wiring layouts; only one IC may be in place at any one time.)

sqr Microwire Microwire is a National Semiconductor standard and is specially suited to use with their microcontrollers. Though often called a three-wire interface, it is actually a five-wire interface with four signal lines and a ground.

sqr SPI SPI (serial peripheral interface) originated at Motorola. It is much like Microwire, though the signal names, polarities, and other details vary. Like Microwire, SPI is often referred to as a three-wire interface, though a read/write interface actually requires two data lines, a clock, a chip select, and a common ground, making five wires.

Other manufacturers provide products to meet the standards that have been established.

Which EEPROM Type Should You Use?

I2C is the best EEPROM type to use if you have just two signal lines to spare, or if you have a cabled interface (I2C also has the strongest drivers).

If you want a clock rate faster than 400 kHz, use Microwire or SPI.

For more on using serial EEPROMs, refer to the manufacturers’ pages on the Web, especially the following sites:

sqr National Semiconductor

www.national.com/design/
(Contains many application notes on Microwire)

sqr Motorola Semiconductor

www.mcu.motsps.com/mc.html
(Onsite microcontroller references contain SPI documentation.)

Jan Axelson’s article in Circuit Cellar is a good source of detailed information on these devices. The article can be found at www.lvr.com/files/seeprom.pdf.

The PICBASIC PRO Compiler provides the instructions necessary to access these serial memories.

In all the programs I have listed in this chapter, I have used the programs and documentation verbatim from the microEngineering Labs Web site. I did this for two reasons. One, to not reinvent the wheel since the work has already been done by microEngineering Labs, and two, to expose the readers to how the programs are structured by a programmer other than myself. Each programmer has his or her own style of doing things and it is well worth being exposed to the work of other programmers.

Socket U3—I2C SEEPROM

Socket U3 accommodates I2C memory only. Figure 7.2 and Program 7.1 illustrate the use of this memory type.

f0116-01

Figure 7.2 I2C SEEPROM. (Wiring and circuitry requirements.)

Program 7.1 Program to read from and write to I2C SEEPROMs

 ;This microEngineering Labs program can be found on their 
 ;Web site. Use the latest version.
 CLEAR                                   ; clear memory
 SO CON 0                                ; define serial output pin
 N2400 CON 4                             ; set serial mode
                                         ; define variables
 DPIN   VAR PORTA.0                      ; I2C data pin
 CPIN   VAR PORTA.1                      ; I2C clock pin
 B0 VAR BYTE                             ; variable declaration
 B1 VAR BYTE                             ; variable declaration
 B2 VAR BYTE                             ; variable declaration
                                         ; write to the memory
 FOR B0 = 0 TO 15                        ; loop 16 times
   I2CWRITE DPIN, CPIN, $A0, B0, [B0]    ; write each location's
                                         ; address to itself
   PAUSE 10                              ; delay 10 ms after each
                                         ; write is needed
 NEXT B0                                 ;
                                         ;
 LOOP:                                   ;
 FOR B0 = 0 TO 15 STEP 2                 ; loop 8 times
   I2CREAD DPIN, CPIN, $A0, B0, [B1, B2] ; read 2 locations in 
                                         ; a row
   SEROUT SO, N2400, [#B1,” ”,#B2,” “]   ; print 2 locations to
                                         ; CRT
 NEXT B0                                 ;
                                         ;
 SEROUT SO, N2400, [13,10]               ; print a line feed
 GOTO LOOP                               ;
 END                                     ;

f0117-01

Figure 7.3 SPI SEEPROM. (Wiring and circuitry requirements.)

Socket U4—SPI SEEPROM

Socket U4 is wired to use SPI memory only. Figure 7.3 and Program 7.2 illustrate the use of this memory type.

Program 7.2 Program to read from and write to SPI SEEPROMs

 ; This microEngineering Labs program can be found on their 
 ; Web site. Use the latest version.
 ; PICBASIC PRO program to read and write to SPI SEEPROMs
 ; Write to the first 16 locations of an external serial EEPROM
 ; Read first 16 locations back and send to LCD repeatedly
 ; Note: For SEEPROMs with word-sized addresses
 DEFINE LOADER_USED 1              ; allows use of the boot 
                                   ; loader. 
                                   ; this will not affect 
                                   ; normal program operation.
 DEFINE LCD_DREG PORTD             ; define LCD registers and 
                                   ; bits
 DEFINE LCD_DBIT 4                 ;
 DEFINE LCD_RSREG PORTE            ;
 DEFINE LCD_RSBIT 0                ;
 DEFINE LCD_EREG PORTE             ;
 DEFINE LCD_EBIT 1                 ;
 INCLUDE “MODEDEFS.BAS”            ;

 CS VAR PORTA.5                    ; chip select pin
 SCK VAR PORTC.3                   ; clock pin
 SI VAR PORTC.4                    ; data in pin
 SO VAR PORTC.5                    ; data out pin
 ADDR VAR WORD                     ; address
 B0 VAR BYTE                       ; data
 TRISA.5 = 0                       ; set CS to output
 ADCON1 =%00000111                 ; set all of PORTA and PORTE
                                   ; to digital
 LOW PORTE.2                       ; LCD R/W line low (W)
 PAUSE 100                         ; wait for LCD to start up
 FOR ADDR = 0 TO 15                ; loop 16 times
   B0 = ADDR + 100                 ; B0 is data for SEEPROM
   GOSUB EEWRITE                   ; write to SEEPROM
   PAUSE 10                        ; delay 10 ms after each 
                                   ; write
 NEXT ADDR                         ;
 LOOP:                             ;
 FOR ADDR = 0 TO 15                ; loop 16 times
   GOSUB EEREAD                    ; read from SEEPROM
   LCDOUT $FE, 1, #ADDR,”: ”,#B0   ; display
   PAUSE 1000                      ;
   NEXT ADDR                       ;
 GOTO LOOP                         ;
 ; Subroutine to read data from addr in serial EEPROM
 EEREAD: CS = 0                    ; enable serial EEPROM
   SHIFTOUT SI, SCK, MSBFIRST, [$03, ADDR.BYTE1, ADDR.BYTE0]
                                   ; Send read cmd and addr
   SHIFTIN SO, SCK, MSBPRE, [B0]   ; Read data
   CS = 1                          ; disable
 RETURN                            ;
                                   ; Subr to write data at addr
                                   ; in serial EEPROM
 EEWRITE:                          ;
   CS = 0                          ; enable serial EEPROM
   SHIFTOUT SI, SCK, MSBFIRST, [$06] ; send write enable command
   CS = 1                          ; disable to execute command
   CS = 0                          ; enable
   SHIFTOUT SI, SCK, MSBFIRST, [$02, ADDR.BYTE1, ADDR.BYTE0, B0]
                                   ; Sends address and data
   CS = 1                          ; disable
 RETURN                            ;
 END                               ; end program

Socket U5—Microwire Devices

Socket U5 is wired to use Microwire memory. Figure 7.4 and Program 7.3 illustrate the use of this memory type.

f0119-01

Figure 7.4 Microwire SEEPROM. (Wiring and circuitry requirements.)

This microEngineering Labs program (Program 7.3)—to read and write Microwire SEEPROM devices—can be found on their Web site. Use the latest version.

Program 7.3 Program to read from and write to Microwire SEEPROMs

; PICBASIC PRO program to read and write to Microwire
; SEEPROM 93LC56A
; Write to the first 16 locations of an external serial EEPROM
; Read first 16 locations back and send to LCD repeatedly
; Note: For SEEPROMs with byte-sized address
                              ;
DEFINE LCD_DREG PORTD         ; define LCD registers and bits
DEFINE LCD_DBIT 4             ;
DEFINE LCD_RSREG PORTE        ;
DEFINE LCD_RSBIT 0            ;
DEFINE LCD_EREG PORTE         ;
DEFINE LCD_EBIT 1             ;
INCLUDE “MODEDEFS.BAS”        ;
CS VAR PORTA.5                ; chip select pin
CLK VAR PORTC.3               ; clock pin
DI VAR PORTC.4                ; data in pin
DO VAR PORTC.5                ; data out pin
ADDR VAR BYTE                 ; address
B0 VAR BYTE                   ; data
LOW CS                        ; chip select inactive
ADCON1 = 7                    ; set PORTA and PORTE to digital
LOW PORTE.2                   ; LCD R/W line low (W)
PAUSE 100                     ; wait for LCD to start up
GOSUB EEWRITEEN               ; enable SEEPROM writes
FOR ADDR = 0 TO 15            ; loop 16 times
  B0 = ADDR + 100             ; B0 is data for SEEPROM
  GOSUB EEWRITE               ; write to SEEPROM
  PAUSE 10                    ; Delay 10ms after each write

NEXT ADDR                     ;
LOOP:                         ;
FOR ADDR = 0 TO 15            ; loop 16 times
  GOSUB EEREAD                ; read from SEEPROM
  LCDOUT $FE, 1, #ADDR,”: ”,#B0  ; display
  PAUSE 1000                  ;
  NEXT ADDR                   ;
GOTO LOOP                     ;
; Subroutine to read data from addr in serial EEPROM
EEREAD:                       ;
CS = 1                        ; enable serial EEPROM
SHIFTOUT DI, CLK, MSBFIRST, [%1100\4, ADDR]   ; send read cmd
                                              ; and address
SHIFTIN DO, CLK, MSBPOST, [B0]; read data
CS = 0                        ; disable
RETURN                        ;
                              ; subroutine to write data at
                              ; addr in serial EEPROM
EEWRITE: CS = 1               ; Enable serial EEPROM
SHIFTOUT DI, CLK, MSBFIRST, [%1010\4, ADDR, B0]
                              ; sends write command, address
                              ; and data
CS = 0                        ; disable
RETURN                        ;
; Subroutine to enable writes to serial EEPROM
EEWRITEEN:                    ; subroutine
CS = 1                        ; enable serial EEPROM
SHIFTOUT DI, CLK, MSBFIRST, [%10011\5, 0\7]
                              ; send write enable cmd and
                              ; dummy clocks
CS = 0                        ; disable
RETURN                        ;
END                           ; end program

Socket U6—Real-Time Clocks

Four options are available for using socket U6. This socket is designed to let us experiment with three real-time clocks and with a 12-bit analog-to-digital converter. It connects to the microcontroller as shown:

As shown in Figure 7.5, this is a four-wire interface between the MCU and the IC. The wiring for this chip is similar to the wiring for the Microwire SEEPROMS and the Microwire memory ICs. Essentially, this looks like a memory chip to the processor. When we write to this memory, we are writing to the clock, and when we read from this chip, we are reading an ever changing memory content that gives us information that we can interpret as “time.” So the program to read and write to this clock looks like a program that interacts with the Microwire family of SEEPROMS. (See Program 7.3.)

f0121-01

Figure 7.5 Clock implemented using IC NJU6355. (To the MCU, this clock IC looks like a set of memory locations.)

The same is true for the other chips. See Figures 7.6 and 7.7.

The NJU6355, the DS1202, and the DS1302 real-time clocks are the three integrated circuits for use in socket U6.

Note 1 Jumper J5 which is used for soldering in the crystal for the clock ICs is also the connection that the analog signal for the 12-bit A-to-D converter goes into. So, if you solder in a crystal, you will have to remove the crystal and make arrangements to read in the analog signal when you want to experiment with the LTC1298 12-bit A-to-D converter. The A-to-D converter uses the same socket (U6) as is used by the three clock chips.

f0122-01

Figure 7.6 Clock implemented using IC DS1202. (To the MCU, this clock IC looks like a set of memory locations.)

Note 2 There are a total of six empty sockets—U3, U4, U5, U6, U7, and U10—on the LAB-X1 board as received. Though more than one socket can be occupied by an IC at any one time, it is best if only one IC is experimented with at any one time. This will ensure that there are no conflicts between the various devices. If the extreme right RS485 socket U10 is to be used, the RS 232 IC in the socket just to the left of it, in U9, must be removed. One of these two communication chips can remain in place at all times in that the communications circuitry does not conflict with the memory locations.

THE CLOCK ICS (IN SOCKET U6)

The two 8-pin Dallas Semiconductor clock ICs are interchangeable, and each of them goes into the existing empty socket U6. The DS1302 is the successor to the DS1202.

The NJU6355 also goes into socket U6, but it is not pin-for-pin compatible with the Dallas Semiconductor chips. Fortunately, it too needs to have its crystal between pins 2 and 3, and its other lines can share the connections to the PIC 16F877A.

f0123-01

Figure 7.7 Clock implemented using IC DS1302. (To the MCU, this clock IC Looks like a set of memory locations.)

Before you can use the NJU6355, the DS1202, or the DS1302, you have to install a crystal between pins 2 and 3 of the chip socket. This has to be a 32.768 kHz crystal and it is to be installed at jumper J5 next to the real-time clock IC socket. If you do not have a crystal in place, the program will show the date and other items on the LCD, but the clock will not move forward.

If you want to have battery backup for the clock, you need to install a battery at jumper J4 (at the edge of the board next to U10). The pins for this jumper are already on the board when you receive it. The IC will accept from 2.0 to 5.5 volts, so three AA cells in series can provide an inexpensive backup power source. (The power drawn by this IC is 300 nano-amps at 2.0 volts. Two AA cells may not provide enough voltage because of the voltage drop across the in-line diode, so I have recommended three cells.)

The DS1302 (in Socket U6) The DS1302 is the successor to the DS1202. The DS1302 IC is very similar except for backup power capability and seven additional bytes of scratch pad memory. See the datasheet for more specific details.

The emphasis in the program we will develop is to see how we get the data to and from the real-time clock. Setting the clock is going to be done in the program startup routine, and the time cannot be modified once the program is running. If you want that, you can add that to the program you write.

The DS1302 has 31 RAM registers. When you want to send or receive data to the IC, the data can be transferred to and from the clock/RAM one byte at a time, or in a burst of up to 31 bytes.

The LTC1298 12-Bit A-to-D Converter (Also Used in Socket U6)

For our purposes, in making instruments and controllers, 8-, 10-, and 12-bit A-to-D converters are used as interfaces between sensors and microprocessors. Sensors usually provide a change in resistance, inductance, or capacitance as some other factor is manipulated. These changes are usually very small and need to be amplified and digitized so they can be manipulated in a digital environment. The interface that converts these small analog signals to useful digital information is the A-to-D converter. Getting comfortable with A-to-D converters is an important part of making instruments and controllers.

MicroEngineering Labs provide a program on their Web site that shows how to read the 12-bit LTC1298. It’s shown in Program 7.4.

Program 7.4 Program to read from 12-bit LTC1298 A-to-D chip by microEngineering Labs

 ; PICBASIC PRO program to read LTC1298 ADC by microEngineering
 ; Labs.
 ; Define LOADER_USED to allow use of the boot loader.
 ; This will not affect normal program operation.
 DEFINE LOADER_USED 1     ;
 DEFINE LCD_DREG PORTD    ; define LCD pins
 DEFINE LCD_DBIT 4        ;
 DEFINE LCD_RSREG PORTE   ;
 DEFINE LCD_RSBIT 0       ;
 DEFINE LCD_EREG PORTE    ;
 DEFINE LCD_EBIT 1        ;
 INCLUDE “MODEDEFS.BAS”   ;
                          ; alias pins
 CS VAR PORTC.5           ; chip select
 CK VAR PORTC.3           ; clock
 DI VAR PORTA.2           ; data in
 DO VAR PORTC.1           ; data out
                          ; allocate variables
 ADDR VAR BYTE            ; channel address / mode

 RESULT VAR WORD          ;
 X VAR WORD               ;
 Y VAR WORD               ;
 Z VAR WORD               ;
 HIGH CS                  ; chip select inactive
 ADCON1 = 7               ; set PORTA, PORTE to digital
 LOW PORTE.2              ; LCD R/W line low (W)
 PAUSE 100                ; wait for LCD to start
 GOTO MAINLOOP            ; skip subroutines
                          ; subroutine to read a/d converter
 GETAD:                   ;
   CS = 0                 ; chip select active
                          ; send address / mode – 
                          ; start bit, 3 bit addr, null bit]
   SHIFTOUT DI, CK, MSBFIRST, [1\1, ADDR\3, 0\1]
   SHIFTIN DO, CK, MSBPRE, [RESULT\12]; get 12-bit result
   CS = 1                 ; chip select inactive
 RETURN                   ;
                          ; subroutine to get x value (channel 0)
 GETX:                    ;
   ADDR = %00000101       ; single ended, channel 0, MSBF high
   GOSUB GETAD            ;
   X = RESULT             ;
 RETURN                   ;
                          ; subroutine to get y value (channel 1)
 GETY:                    ;
   ADDR = %00000111       ; single ended, channel 1, MSBF high
   GOSUB GETAD            ;
   Y = RESULT             ;
 RETURN                   ;
                          ; subroutine to get z value 
                          ; (differential)
 GETZ:                    ;
   ADDR = %00000001       ; diff (ch0 = +, ch1 = -), MSBF high
   GOSUB GETAD            ;
   Z = RESULT             ;
 RETURN                   ;
                          ;
 MAINLOOP:                ;
   GOSUB GETX             ; get x value
   GOSUB GETY             ; get y value
   GOSUB GETZ             ; get z value
   LCDOUT $FE, 1, “X=”, #X, ; send values to LCD
   “Y=”, #Y, “Z=”, #Z
   PAUSE 100              ; do it about 10 times a second
 GOTO MAINLOOP            ; do it forever
 END                      ; end program

Program 7.4 reads three values from the A-to-D converter and displays them as X, Y, and Z values on the LCD. The 1298 is a two-channel device, and the two signals are read from pins 2 and 3 on the device. The third value being displayed on the LCD is the differential between the two values, meaning that the device is now being used for looking at the two inputs, not as individual inputs but as one signal across the two lines (as compared to two signals between each of the pins and ground).

The two channels are connected to the two pins at J5. These are the two pins that the crystal for the clocks goes across and, as mentioned before,because of this there is a hardware conflict between using the clock chips and the A-to-D converter.

The LTC 1298 can provide a maximum of 11.1 thousand samples per second. The device accepts an analog reference voltage between –0.3 and Vcc +0.3 volts, so the signals to be read must be conditioned to reflect these requirements.

Sockets U7 (and U8)

Sockets U7 and U8 are designed for temperature-sensing experiments. (U8 is a three-hole group for soldering in a three-wire temperature-sensing device and is located next to U7.) How this is done is demonstrated in Programs 7.5 and 7.6.

The DS1820 temperature reading device goes in socket U7.

The DS1620 temperature sensor has to be soldered into socket U8.

Program 7.5 Using the DS1820 (Program to read temperature by microEngineering Labs)

 ; This microEngineering Labs program can be found on their 
 ; Web site. Use the latest version.
 ; PICBASIC PRO program to read DS1820 1-wire temperature sensor
 ; and display the temperature on the LCD
 DEFINE LCD_DREG PORTD    ; define lcd pins
 DEFINE LCD_DBIT 4        ;
 DEFINE LCD_RSREG PORTE   ;
 DEFINE LCD_RSBIT 0       ;
 DEFINE LCD_EREG PORTE    ;
 DEFINE LCD_EBIT 1        ;
                          ; allocate variables
 COMMAND VAR BYTE         ; storage for command
 I VAR BYTE               ; storage for loop counter
 TEMP VAR WORD            ; storage for temperature
 DQ VAR PORTC.0           ; alias DS1820 data pin
 DQ_DIR VAR TRISC.0       ; alias DS1820 data direction pin
                          ;
                          ;

 ADCON1 =%00000111        ; set PORTA and PORTE to digital
 LOW PORTE.2              ; lcd r/w line low (w)
 PAUSE 100                ; wait for lcd to start
 LCDOUT $FE, 1, “TEMP IN DEGREES C”   ; display sign-on message
                          ;
 ; mainloop to read the temperature and display on lcd
 MAINLOOP:                ;
 GOSUB INIT1820           ; init the DS1802
 COMMAND = %11001100      ; issue skip rom command
 GOSUB WRITE1820          ;
 COMMAND = %01000100      ; start temperature conversion
 GOSUB WRITE1820          ;
 PAUSE 2000               ; wait 2 seconds for conversion to 
                          ; complete
 GOSUB INIT1820           ; do another init
 COMMAND = %11001100      ; issue skip rom command
 GOSUB WRITE1820          ;
 COMMAND = %10111110      ; read the temperature
 GOSUB WRITE1820          ;
 GOSUB READ1820           ;
                          ; display the decimal temperature
 LCDOUT $FE, 1, DEC (TEMP >> 1), “.”, DEC (TEMP.0 * 5),_
 “ DEGREES C”
 GOTO MAINLOOP            ; do it forever
                          ; initialize DS1802 and check for 
                          ; presence
 INIT1820:                ;
 LOW DQ                   ; Set the data pin low to init
 PAUSEUS 500              ; wait > 480us
 DQ_DIR = 1               ; release data pin (set to input 
                          ; for high)
 PAUSEUS 100              ; wait > 60us
 IF DQ = 1 THEN           ;
 LCDOUT $FE, 1, “DS1820 NOT PRESENT”  ;
 PAUSE 500                ;
 GOTO MAINLOOP            ; try again
 ENDIF                    ;
 PAUSEUS 400              ; Wait for end of presence pulse
 RETURN                   ;
                          ; write “command” byte to the ds1820
 WRITE1820:               ;
 FOR I = 1 TO 8           ; 8 bits to a byte
   IF COMMAND.0 = 0 THEN  ;
     GOSUB WRITE0         ; write a 0 bit
   ELSE                   ;
     GOSUB WRITE1         ; write a 1 bit

   ENDIF                  ;
     COMMAND = COMMAND >> 1   ; shift to next bit
   NEXT I                 ;
 RETURN                   ;
                          ; write a 0 bit to the DS1802
 WRITE0:                  ;
   LOW DQ                 ;
   PAUSEUS 60             ; low for > 60us for 0
   DQ_DIR = 1             ; release data pin (set to input
                          ; for high)
 RETURN                   ; write a 1 bit to the DS1820
 WRITE1:                  ;
   LOW DQ                 ; low for < 15us for 1
   @NOP                   ; delay 1us at 4mhz
   DQ_DIR = 1             ; release data pin (set to input
                          ; for high)
   PAUSEUS 60             ; use up rest of time slot
 RETURN                   ; read temperature from the DS1820
 READ1820:                ;
   FOR I = 1 TO 16        ; 16 bits to a word
     TEMP = TEMP >> 1     ; shift down bits
     GOSUB READBIT        ; get the bit to the top of temp
   NEXT I                 ;
 RETURN                   ; read a bit from the DS1820
 READBIT:                 ;
   TEMP.15 = 1            ; preset read bit to 1
   LOW DQ                 ; start the time slot
   @NOP                   ; delay 1us at 4mhz
   DQ_DIR = 1             ; release data pin (set to input
                          ; for high)
   IF DQ = 0 THEN         ;
     TEMP.15 = 0          ; set bit to 0
   ENDIF                  ;
   PAUSEUS 60             ; wait out rest of time slot
 RETURN                   ;
 END                      ; end

Program 7.6 Using the DS1620 (microEngineering Labs program to read temperature)

 ; This microEngineering Labs program, too, can be found on
 ; their Web site. Use the latest version.
 ; PICBASIC PRO program to read DS1620 three-wire temperature
 ; sensor
 ; and display temperature on the LCD

 INCLUDE “MODEDEFS.BAS”    ;
 DEFINE LCD_DREG PORTD     ; define lcd pins
 DEFINE LCD_DBIT 4         ;
 DEFINE LCD_RSREG          PORTE;
 DEFINE LCD_RSBIT 0        ;
 DEFINE LCD_EREG PORTE     ;
 DEFINE LCD_EBIT 1         ;
                           ; alias pins
 RST VAR PORTC.0           ; reset pin
 DQ VAR PORTC.1            ; data pin
 CLK VAR PORTC.3           ; clock pin
                           ; allocate variables
 TEMP VAR WORD             ; storage for temperature
 LOW RST                   ; reset the device
 ADCON1 =%00000111         ; set PORTA and PORTE to digital
 LOW PORTE.2               ; lcd r/w line low (w)
 PAUSE 100                 ; wait for lcd to start
 LCDOUT $FE, 1, “TEMP IN DEGREES C”   ; display sign-on message
                           ; loop to read the temp and display 
                           ; on lcd
 MAINLOOP:                 ;
 RST = 1                   ; enable device
 SHIFTOUT DQ, CLK, LSBFIRST, [$EE]     ; start conversion
 RST = 0                   ;
 PAUSE 1000                ; wait 1 second for conversion to 
                           ; complete
 RST = 1                   ;
 SHIFTOUT DQ, CLK, LSBFIRST, [$AA]     ; send read command
 SHIFTIN DQ, CLK, LSBPRER, [TEMP\9]    ; read 9 bit temperature
 RST = 0                   ;
                           ; display the decimal temperature
 LCDOUT $FE, 1, DEC (TEMP >> 1), “.”, DEC (TEMP.0 * 5),_
 “DEGREES C”
 GOTO MAINLOOP             ; do it forever
 END                       ; end program