Problems with 16F88 & 2 Wire LCD (Assembly Language)

Thread Starter

icedtea

Joined Aug 28, 2010
10
Hello Everyone!

I recently started using PIC microcontollers for a project that I want to complete. I found the 2 Wire LCD program and schematic by Mike Predko at http://www.rentron.com/Myke1.htm The assembly code was written for the PIC16C84 and thought that I might be able to port it over to the PIC16F88 instead. I've been trying everything that I can and hunting through the online forums for any clue that might help me get it operational.

If anyone would be so kind to look over the code that has been modified from the original, unsuccessfully. :(

I know it has been done by someone else using the C language, however, I'm liking the assembly language and how easy it is to compile it into the .HEX file. The page with the C language code is located at: http://ghmicro.com/index.php?option...cd-interface&catid=6:16f88&Itemid=2&showall=1 if this helps at all.

The .asm file has been attached as a .txt document and the code has also been copied below:

Rich (BB code):
;  Using 2WireLCD to write messages to LCD Screen
;   - 4 Bit Mode
;   - Data is shifted out to a 74LS174 with The High Order Bit being a "Gate"
;    Bit connected to the LCD's "E" line.  The next Highest Bit goes to the
;    LCD's "RS" Bit.  The lowest Bit goes to D4 (and each Bit is higher from
;    there).
;
;  Hardware Notes:
;   - Reset is tied directly to Vcc and PWRT is Enabled.
;   - The PIC is a 16F88 Running at 4 MHz.
;   - PortA.0 is the Data Bit
;   - PortA.1 is the Clock Bit
;
;  Shift Data:
;  Bit 1 - Always High (Gate for "E")
;  Bit 2 - RS Bit
;  Bit 3 - LCD D4
;  Bit 4 - LCD D5
;  Bit 5 - LCD D6
;  Bit 6 - LCD D7
;
  LIST P=16F88, R=DEC          ;  16F88 Decimal
  errorlevel 0,-305
  INCLUDE "P16F88.inc"
 
;  Register Usage
 CBLOCK 0x00C       ;  Start Registers at End of the Values
Dlay             ;  8 Bit Delay Variable
Temp           ;  Temporary Value Used When Sending Out Data
NOTemp       ;  Temporary Value to "NybbleOutput"
CounterA      ;  Counter Value - For Time Delay Calculations
CounterB      ;  Counter Value - For Time Delay Calculations
CounterC      ;  Counter Value - For Time Delay Calculations
Next2           ;  Don't know why but MPLAB IDE told me I needed this one
 ENDC
 
;  Define Inforation
#DEFINE Data PORTA,0
#DEFINE Clock PORTA, 1
 
;  Macros
ClockStrobe MACRO  ;  Strobe the Data Bit
  bsf  Clock
  bcf  Clock
 ENDM
 
EStrobe MACRO   ;  Strobe the "E" Bit
  bsf  Data
  bcf  Data
 ENDM
 
 PAGE
 
 __CONFIG _CONFIG1, _CP_OFF & _CCP1_RB0 & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_ON & _PWRTE_ON & _WDT_OFF & _INTRC_IO
 __CONFIG _CONFIG2, _IESO_OFF & _FCMEN_OFF
 
  org    0
 
  clrf   PORTA
  clrf   PORTB
 
  bsf STATUS, RP0  ; BANK 1 
  movlw  b'01100000' ; Set internal osc to 4Mhz 
  movwf  OSCCON & 0x7F
  movlw  b'111100'  ; Set PortA 0 & 1 to Digital I/O - Added 8-24-10
  movwf  ANSEL   ; Write the data to ANSEL File - Added 8-24-10
  movlw  0x07       ; Load 7 into W register - Added 8-24-10
  movwf  CMCON    ; CMCON = contents of W register 7h - Added 8-24-10
  movwf  TRISA ^ 0x080
  bcf STATUS, RP0  ; BANK 0
 
  call   Dlay5                  ;  Wait 20 msecs before Reset
  call   Dlay5
  call   Dlay5
  call   Dlay5
 
  bcf    STATUS, C              ;  Clear Carry (Instruction Out)
  movlw  0x03                   ;  Reset Command
  call   NybbleOut              ;  Send the Nybble
  call  Dlay5   ;  Wait 5 msecs before Sending Again
 
  EStrobe
  call  Dlay160  ;  Wait 160 usecs before Sending the Third Time
  EStrobe
  call  Dlay160  ;  Wait 160 usecs before Sending the Third Time
  bcf    STATUS, C              
  movlw  0x02                   ;  Set 4 Bit Mode
  call   NybbleOut              
  call  Dlay160  
  movlw  0x028   ;  Note that it is a 2 Line Display
  call  SendINS
  movlw  0x008   ;  Turn off the Display
  call  SendINS
  movlw  0x001   ;  Clear the Display RAM
  call  SendINS
  call  Dlay5   ;  Note, Can take up to 4.1 msecs
  movlw  0x006   ;  Enable Cursor Move Direction
  call  SendINS
  movlw  0x00C   ;  Turn the LCD Back On
  call  SendINS
 
;----------------------------------------------------------------------
;OutPut Message Screen 1 Line 1
  call   OutLoopA
  call   IntroMessageLine1
  call   OutLoopC
 
;----------------------------------------------------------------------
;Delay 1 Second Before Displaying Screen 1 Line 2
Next1    ;  Next Line
  call   Delay1s  ;  1 Second Delay
  movlw  0x0C0   ;  Move to Next Line on LCD
  call  SendINS
 
;----------------------------------------------------------------------
;OutPut Message Screen 1 Line 2
  call   OutLoopA
  call   IntroMessageLine2
  call   OutLoopC
 
;----------------------------------------------------------------------
;Delay 4 Seconds Before Clearing LCD Screen and Displaying Next Screen
Next4     ;  4 Second Delay Loop
  call   Delay1s  ;  1 Second Delay
  call   Delay1s  ;  + 1 Second Delay = 2 Second Delay
  call   Delay1s  ;  + 1 Second Delay = 3 Second Delay
  call   Delay1s  ;  + 1 Second Delay = 4 Second Delay (5 Seconds Total)
 
;----------------------------------------------------------------------
;Display Program 1 Screen Line 1
  call   ClearDR
  call   OutLoopA
  call   Prog1Line1
  call   OutLoopC
 
;----------------------------------------------------------------------
;Display Program 1 Screen Line 2
  call   OutLoopA
  call   Prog1Line2
  call   OutLoopC
Loop123
  goto  Loop123    ;Loop forever until code development continues...
 
;----------------------------------------------------------------------
;Output Loops for Sending Text to LCD Screen
OutLoopA
  clrf  FSR   ;  Output the Message
OutLoopB
  movf  FSR, w   ;  Get the Offset to Output
  incf  FSR
  return
OutLoopC
  iorlw  0   ;  At the End of the Line?
  btfsc  STATUS, Z
  goto  NextLn   ;  Yes - Equal to Zero
  call  SendCHAR  ;  Output the ASCII Character
  goto  OutLoopB
  return
 
;----------------------------------------------------------------------
;Commands for Clearing LCD Screen & RAM
ClearDR
  movlw  0x001   ;  Clear the Display & RAM
  call  SendINS
  call  Dlay5   ;  Can take up to 4.c1 msecs
  return
 
;----------------------------------------------------------------------
;Commands for Moving to the Next Line on the LCD Screen
NextLn    ;  Next Line
  movlw  0x0C0   ;  Move to Next Line on LCD
  call  SendINS
  return
 
;  Subroutines
;----------------------------------------------------------------------
IntroMessageLine1  ;  Message to Output
  addwf  PCL   ;  Output the Characters
  dt  "Initializing...", 0
 
;----------------------------------------------------------------------
;Commands to Send Characters to LCD Screen
SendCHAR    ;  Send the Character to the LCD
  movwf  Temp   ;  Save the Temporary Value
  swapf  Temp, w  ;  Send the High Nybble
  bsf  STATUS, C  ;  RS = 1
  call  NybbleOut
  movf  Temp, w  ;  Send the Low Nybble
  bsf  STATUS, C
  call  NybbleOut
  return
 
;----------------------------------------------------------------------
IntroMessageLine2  ;  Message to Output
  addwf  PCL   ;  Output the Characters
  dt     "Loading Menu...", 0
  goto   SendCHAR
 
;----------------------------------------------------------------------
Prog1Line1   ;  Message to Output
  addwf  PCL   ;  Output the Characters
  dt     "Program #1:", 0
  goto   SendCHAR
 
;----------------------------------------------------------------------
Prog1Line2
  addwf  PCL   ;  Message to Output
  dt     "Reflex Timing", 0
  goto   SendCHAR
 
;----------------------------------------------------------------------
;Commands to Send Instructions to LCD Screen
 
SendINS     ;  Send the Instruction to the LCD
  movwf  Temp   ;  Save the Temporary Value
  swapf  Temp, w  ;  Send the High Nybble
  bcf  STATUS, C  ;  RS = 0
  call  NybbleOut
  movf  Temp, w  ;  Send the Low Nybble
  bcf  STATUS, C
  call  NybbleOut
  return
 
;----------------------------------------------------------------------
;Commands to Sending Nibbles to LCD Screen
 
NybbleOut    ;  Send a Nybble to the LCD
  movwf  NOTemp   ;  Save the Nybble to Shift Out
  swapf  NOTemp   ;  Setup to Output to the High Part of the Byte
  movlw  6   ;  Clear the Shift Register
  movwf  Dlay
 
NOLoop1
  ClockStrobe
  decfsz Dlay
   goto  NOLoop1
  bsf  Data   ;  Put out the Gate Bit
  ClockStrobe
  bcf  Data   ;  Put out the RS Bit
  rlf  PORTA
  ClockStrobe
  movlw  4   ;  Now, Shift out the Data
  movwf  Dlay
 
NOLoop2
  rlf  NOTemp   ;  Shift Through the Nybble to Output
  bcf  Data   ;  Clear the Data Bit (which is the Clock)
  rlf  PORTA   ;  Shift the Carry into the Shift Register
  ClockStrobe
  decfsz Dlay
   goto  NOLoop2
  EStrobe   ;  Strobe out the LCD Data
  return
 
;----------------------------------------------------------------------
Dlay160                         ;  Delay 160 usecs
  movlw  256 - ( 160 / 4 )      ;  Loop Until Carry Set
  addlw  1
  btfss  STATUS, C
   goto  $-2
  return
;----------------------------------------------------------------------
Dlay5                           ;  Delay 5 msecs
  movlw  4                      ;  Set up the Delay
  movwf  Dlay
  movlw  256 - 0x0E8
  addlw  1
  btfsc  STATUS, Z
   decfsz Dlay
    goto $-3
  return
;----------------------------------------------------------------------
Delay1s    ;  Delay Loop for 1 Second
  movlw  6
  movwf  CounterC
  movlw  24
  movwf  CounterB
  movlw  167
  movwf  CounterA
loop  decfsz  CounterA,1
  goto  loop
  decfsz  CounterB,1
  goto loop
  decfsz  CounterC,1
  goto  loop
  return
;----------------------------------------------------------------------
  end
Thanks for any insights you might be able to provide. I really, really appreciate it!
Jared
 

Attachments

eblc1388

Joined Nov 28, 2008
1,542
When porting codes from one PIC into another, one needs to take care of the general purpose registers(GPR) locations as newer PICs usually have more user registers but in different area of the memory map.

This by far is the most common gotcha concerning porting 16F84 codes into newer PICs.

Rich (BB code):
  LIST P=16F88, R=DEC          ;  16F88 Decimal
  errorlevel 0,-305
  INCLUDE "P16F88.inc"
 
;  Register Usage
 CBLOCK 0x00C       ;  Start Registers at End of the Values
Are you sure that the user GPR in 16F88 starts at 0x0C?

 

Attachments

Thread Starter

icedtea

Joined Aug 28, 2010
10
I did have the register location wrong like you pointed out. I changed this in the file and tried again but still, no luck with displaying anything but two symbols and two blocks (this is as far as I've ever gotten within the last three weeks). I'm not sure what I should do but am considering scrapping the 88 and switch to another PIC microcontroller that isn't as complicated as this one though I'd hate to do that.
 

MMcLaren

Joined Feb 14, 2010
861
After a quick glance at your code I wonder if using the rlf PORTA instructions might be a problem?

Does your Predko interface look anything like mine (below)?
 

Attachments

elementalrage

Joined Jul 30, 2009
59
Are you using an external crystal or internal clock? Many 16x2 LCDs, that I have used, won't work 100% with the internal clock...

The 16F88 is an awesome chip! Many tutorials were created using that chip.
 

Thread Starter

icedtea

Joined Aug 28, 2010
10
Update: I have finally got something to work. I used an 8-bit interface (11 pins used total) and a PIC16F54. Since this one does not have an internal oscillator I used a 20 MHz crystal hoping it would work. It seems to work perfectly!

The problem, however, is that the 16F54 has limited programming space to accomplish what I'm trying to do. Since this is working, I thought I'd try to get it to work on the 16F88 but am STILL running into problems.

I understand that this chip has a default configuration on PortA which needs to be turned off using the ANSEL register and also to turn the comparators off via the CMCON register.

Here is the 16F54 code that works:
Rich (BB code):
    LIST P=16F54, F=INHX8M
    Include <P16F5X.inc>
    __CONFIG _CP_OFF & _WDT_OFF & _HS_OSC

; Equates, I/O, vars
RESET_V        EQU    0x0000        ; Address of RESET Vector
ISR_V        EQU    0x0004        ; Address of Interrupt Vector
OSC_FREQ    EQU    D'20000000'    ; Oscillator Frequency = 20 MHz

LCD_DATA    EQU    PORTB        ; LCD data lines
LCD_CTRL    EQU    PORTA        ; LCD control lines

LCD_LINE0    EQU    0x000
LCD_LINE1    EQU    0x040

; PORTA Bits
LCD_E        EQU    2        ; LCD Enable control line
LCD_RW        EQU    1        ; LCD Read/Write control line
LCD_RS        EQU    0        ; LCD Register-Select control line

; PORTB Bits
DB7        EQU    7        ; LCD dataline 7 (MSB)
DB6        EQU    6
DB5        EQU    5
DB4        EQU    4
DB3        EQU    3
DB2        EQU    2
DB1        EQU    1
DB0        EQU    0        ; LCD dataline 0 (LSB)

; Miscellaneous
LCD_TEMP    EQU    0x007        ; LCD subroutines internal use
TABLE_INDEX    EQU    0x008        ; Index to table strings
DELAY        EQU    0x009        ; Used in DELAYxxx routines
X_DELAY        EQU    0x00A        ; Used in X_DELAYxxx routines
T1        EQU    0x00B        ; Delay Variables
T2        EQU    0x00C
T3        EQU    0x00D

; Program start
    ORG    RESET_V            ; RESET vector location
RESET        GOTO    START

; Initialize processor registers

START                    ; POWER_ON Reset (Beginning of program)
        CLRF    STATUS        ; Do initialization, Select bank 0
        CLRF    PORTA        ; ALL PORT output should output Low.
        CLRF    PORTB

        MOVLW    0x0F8        ; RA2-0 outputs, RA4-3 inputs
        TRIS    PORTA
        MOVLW    0x000        ; RB7-0 outputs
        TRIS    PORTB

; LCDINIT - Initialize LCD Display

                    ; Busy-flag is not yet valid
        CLRF    LCD_CTRL    ; ALL PORT output should output Low.
        MOVLW    0x028        ; Power-up Delay
        MOVWF    X_DELAY        ; +1    1 cycle
X_DELAY500_LOOP
        CALL    DELAY500    ; Step1    Wait 500uSec
        DECFSZ    X_DELAY, F    ; Step2    1 Cycle
        GOTO    X_DELAY500_LOOP    ; Step3    2 Cycles
        NOP
        NOP
                    ; Busy Flag should be valid from here
        MOVLW    0x038        ; 8-bit-interface, 2-lines
        CALL    LCDPUTCMD
        MOVLW    0x000        ; Display Off, Cursor Off, No-Blink
        ANDLW    0x007        ; Strip upper bits
        IORLW    0x008        ; Function set
        CALL    LCDPUTCMD
        MOVLW    0x001
        CALL    LCDPUTCMD
        MOVLW    0x004        ; Display On, Cursor Off
        ANDLW    0x007        ; Strip upper bits
        IORLW    0x008        ; Function set
        CALL    LCDPUTCMD
        MOVLW    0x002        ; Auto-Increment (Shift-Cursor)
        ANDLW    0x003        ; Strip upper bits
        IORLW    0x004        ; Function set
        CALL    LCDPUTCMD

; Display - Line0:|Welcome Message | & Line1:|Wait 4 seconds..|
        CALL    Delay1S

        MOVLW    LCD_LINE0    ; Position Cursor Leftmost on 1st Line        
        IORLW    0x080        ; Function set
        CALL    LCDPUTCMD
                        ; TABLE_MSG - Display Message
        MOVLW    0        ; Startindex of table message
DISP_MSG1
        MOVWF    TABLE_INDEX    ; Holds message address
        CALL    MSG1
        ANDLW    0x0FF        ; Check if at end of message
        BTFSC    STATUS, Z    ; (Zero returned at end)
        GOTO    TABLE_MSG_END1             
                            ; LCDPUTCHAR - Display Character
        MOVWF    LCD_TEMP    ; Character to be sent is in W
                            ; LCDBUSY - Wait for LCD to be ready
LCDBUSY1
        MOVLW    0x0FF            ; Set PORTB for input
        TRIS    PORTB    
        BCF        LCD_CTRL, LCD_RS; Set LCD for command mode
        BSF        LCD_CTRL, LCD_RW; Setup to read busy flag
        BSF        LCD_CTRL, LCD_E    ; LCD E-line High
        MOVF    LCD_DATA, W        ; Read busy flag + DDram address
        BCF        LCD_CTRL, LCD_E    ; LCD E-line Low
        ANDLW    0x80            ; Check Busy flag, High = Busy
        BTFSS    STATUS, Z
        GOTO    LCDBUSY1
LCDNOTBUSY1
        BCF    LCD_CTRL, LCD_RW
        MOVLW    0x000
        TRIS    PORTB        ; Set PORTB for output

        BCF    LCD_CTRL, LCD_RW; Set LCD in read mode
        BSF    LCD_CTRL, LCD_RS; Set LCD in data mode
        BSF    LCD_CTRL, LCD_E    ; LCD E-line High
        MOVF    LCD_TEMP, W
        MOVWF    LCD_DATA    ; Send data to LCD
        BCF    LCD_CTRL, LCD_E    ; LCD E-line Low

        MOVF    TABLE_INDEX, W    ; Point to next character
        INCF    TABLE_INDEX, W
        GOTO    DISP_MSG1
TABLE_MSG_END1

; 1 Second Delay
        CALL    Delay1S

        MOVLW    LCD_LINE1
        IORLW    0x080        ; Function set
        CALL    LCDPUTCMD
                            ; TABLE_MSG
        MOVLW    0            ; Startindex of table message
DISP_MSG2
        MOVWF    TABLE_INDEX    ; Holds message address
        CALL    MSG2
        ANDLW    0x0FF        ; Check if at end of message
        BTFSC    STATUS, Z    ; (zero returned at end)
        GOTO    TABLE_MSG_END2             
                            ; LCDPUTCHAR - Display Character
        MOVWF    LCD_TEMP    ; Character to be sent is in W
LCDBUSY3
        MOVLW    0x0FF        ; Set PORTB for input
        TRIS    PORTB    
        BCF    LCD_CTRL, LCD_RS; Set LCD for command mode
        BSF    LCD_CTRL, LCD_RW; Setup to read busy flag
        BSF    LCD_CTRL, LCD_E    ; LCD E-line High
        MOVF    LCD_DATA, W    ; Read busy flag + DDram address
        BCF    LCD_CTRL, LCD_E    ; LCD E-line Low
        ANDLW    0x80        ; Check Busy flag, High = Busy
        BTFSS    STATUS, Z
        GOTO    LCDBUSY3
LCDNOTBUSY3
        BCF    LCD_CTRL, LCD_RW
        MOVLW    0x000
        TRIS    PORTB        ; Set PORTB for output

        BCF    LCD_CTRL, LCD_RW; Set LCD in read mode
        BSF    LCD_CTRL, LCD_RS; Set LCD in data mode
        BSF    LCD_CTRL, LCD_E    ; LCD E-line High
        MOVF    LCD_TEMP, W
        MOVWF    LCD_DATA    ; Send data to LCD
        BCF    LCD_CTRL, LCD_E    ; LCD E-line Low

        MOVF    TABLE_INDEX, W    ; Point to next character
        INCF    TABLE_INDEX, W
        GOTO    DISP_MSG2
TABLE_MSG_END2

; 4 Second Delay
        CALL    Delay1S
        CALL    Delay1S
        CALL    Delay1S
        CALL    Delay1S

        MOVLW    0x001        ; LCDCLEAR
        CALL    LCDPUTCMD

; Program Ends Here
LOOP
        GOTO    LOOP        ; Loop forever

LCDPUTCMD
        MOVWF    LCD_TEMP    ; Command to be sent is in W
LCDBUSY
        MOVLW    0x0FF        ; Set PORTB for input
        TRIS    PORTB    
        BCF    LCD_CTRL, LCD_RS; Set LCD for command mode
        BSF    LCD_CTRL, LCD_RW; Setup to read busy flag
        BSF    LCD_CTRL, LCD_E    ; LCD E-line High
        MOVF    LCD_DATA, W    ; Read busy flag + DDram address
        BCF    LCD_CTRL, LCD_E    ; LCD E-line Low
        ANDLW    0x80        ; Check Busy flag, High = Busy
        BTFSS    STATUS, Z
        GOTO    LCDBUSY
LCDNOTBUSY
        BCF    LCD_CTRL, LCD_RW
        MOVLW    0x000
        TRIS    PORTB        ; Set PORTB for output
        BCF    LCD_CTRL, LCD_RW; Set LCD in read mode
        BCF    LCD_CTRL, LCD_RS; Set LCD in command mode
        BSF    LCD_CTRL, LCD_E    ; LCD E-line High
        MOVF    LCD_TEMP, W
        MOVWF    LCD_DATA    ; Send data to LCD
        BCF    LCD_CTRL, LCD_E    ; LCD E-line Low
        RETLW    0

; 500 uSecond Delay Routine

DELAY500                    ;2493 cycles
    movlw    0xF2
    movwf    T1
    movlw    0x02
    movwf    T2
Delay500_0
    decfsz    T1, f
    goto    $+2
    decfsz    T2, f
    goto    Delay500_0
    goto    $+1                ;3 cycles
    nop
    retlw    0                ;4 cycles (including call)

; 1 Second Delay Routine @ Clock frequency = 20 MHz

Delay1S                        ; 4999993 Cycles
    movlw    0x2C
    movwf    T1
    movlw    0xE7
    movwf    T2
    movlw    0x0B
    movwf    T3
Delay1S_0
    decfsz    T1, f
    goto    $+2
    decfsz    T2, f
    goto    $+2
    decfsz    T3, f
    goto    Delay1S_0
    goto    $+1                ; 3 Cycles
    nop
    retlw    0                ; 4 Cycles (including call)

; Table Messages to Display
MSG1
        addwf    PCL ,F        ;Jump to char pointed to in W reg
        retlw    'W'
        retlw    'e'
        retlw    'l'
        retlw    'c'
        retlw    'o'
        retlw    'm'
        retlw    'e'
        retlw    ' '
        retlw    'M'
        retlw    'e'
        retlw    's'
        retlw    's'
        retlw    'a'
        retlw    'g'
        retlw    'e'
        retlw    0

MSG2
        addwf    PCL ,F        ;Jump to char pointed to in W reg
        retlw    'W'
        retlw    'a'
        retlw    'i'
        retlw    't'
        retlw    ' '
        retlw    '4'
        retlw    ' '
        retlw    's'
        retlw    'e'
        retlw    'c'
        retlw    'o'
        retlw    'n'
        retlw    'd'
        retlw    's'
        retlw    '.'
        retlw    '.'
        retlw    0

    END                ; End of Program (Required)
 

Attachments

Thread Starter

icedtea

Joined Aug 28, 2010
10
The code that has been modified, yet does not yet work:
Rich (BB code):
    LIST P=16F88, F=INHX8M
    Include <P16F88.inc>
    ERRORLEVEL  -302
    __CONFIG    _CONFIG1, _CP_OFF & _CCP1_RB0 & _DEBUG_OFF & _WRT_PROTECT_OFF & _CPD_OFF & _LVP_OFF & _BODEN_OFF & _MCLR_OFF & _PWRTE_OFF & _WDT_OFF & _HS_OSC
    __CONFIG    _CONFIG2, _IESO_OFF & _FCMEN_OFF

; Equates, I/O, vars

RESET_V        EQU    0x0000     ; Address of RESET Vector
OSC_FREQ    EQU    D'20000000' ; Osc. Frequency = 20 MHz

LCD_DATA    EQU    PORTB    ; LCD data lines
LCD_CTRL    EQU    PORTA    ; LCD control lines

LCD_LINE0    EQU    0x000
LCD_LINE1    EQU    0x040

; PORTA Bits
LCD_E        EQU    2     ; LCD Enable control line
LCD_RW        EQU    1   ; LCD Read/Write control line
LCD_RS        EQU    0   ; LCD Register-Select control line

; PORTB Bits
DB7        EQU    7 ; LCD dataline 7 (MSB)
DB6        EQU    6
DB5        EQU    5
DB4        EQU    4
DB3        EQU    3
DB2        EQU    2
DB1        EQU    1
DB0        EQU    0 ; LCD dataline 0 (LSB)

; Miscellaneous
    CBLOCK    0x020
LCD_TEMP
TABLE_INDEX
DELAY     ; DELAYxxx routines
X_DELAY  ; X_DELAYxxx routines
T1          ; Delay Variables
T2
T3
    ENDC

; Program start

    ORG    RESET_V
RESET        GOTO    START

; Initialize Processor Registers
START
    clrf    STATUS
    clrf    PORTA
    clrf    PORTB
    movlw  0x000
    banksel TRISA    
    movwf  TRISA
    banksel TRISB
    movwf  TRISB
    banksel ANSEL
    clrf ANSEL        ; Set Port A to Digital I/O
    MOVLW    0x007
    BANKSEL    CMCON
    MOVWF    CMCON  ; Turn OFF Comparators

    banksel OSCCON
    bsf    OSCCON, IRCF2  ; Set 8 MHz clock (Back-up if Ext Osc fails)
    bsf    OSCCON, IRCF1
    bsf    OSCCON, IRCF0
                ; STABL    BTFSS    OSCCON,IOFS
                ; GOTO    STABL
    bcf    OSCCON,SCS1        ; Oscillator Mode Defined by FOSC<2:0>
    bcf    OSCCON,SCS0

    banksel    INTCON
KILLINT    BCF    INTCON,7   ; Turn GIE OFF
        BTFSC    INTCON,7    ; GIE is really OFF?
        GOTO    KILLINT

    banksel    TRISA
    MOVLW    0x0F8    ; RA2-0 outputs, RA4-3 inputs
    MOVWF    TRISA    
    banksel    TRISB
    MOVLW    0x000    ; RB7-0 outputs
    MOVWF    TRISB

    banksel PORTA

    CLRF PORTA
    CLRF PORTB

; LCDINIT
        CLRF    LCD_CTRL  ; ALL PORT output should be low
        MOVLW    0x028    ; Power-up Delay
        MOVWF    X_DELAY
X_DELAY500_LOOP
        CALL    DELAY500   ; Wait 500uSec
        DECFSZ    X_DELAY, F
        GOTO    X_DELAY500_LOOP
        NOP
        NOP

        MOVLW    0x038        ; 8-bit-interface, 2-lines
        CALL    LCDPUTCMD
        MOVLW    0x000        ; Display & Cursor Off, No-Blink
        ANDLW    0x007        ; Strip upper bits
        IORLW    0x008        ; Function (F(x)) set
        CALL    LCDPUTCMD
        MOVLW    0x001
        CALL    LCDPUTCMD
        MOVLW    0x004        ; Display On, Cursor Off
        ANDLW    0x007        ; Strip upper bits
        IORLW    0x008        ; F(x) set
        CALL    LCDPUTCMD
        MOVLW    0x002        ; Auto-Increment (Shift-Cursor)
        ANDLW    0x003        ; Strip upper bits
        IORLW    0x004        ; F(x) set
        CALL    LCDPUTCMD

; Display: Line0: |Welcome Message | & Line1: |Wait 4 seconds..|

        CALL    Delay1S
        MOVLW    LCD_LINE0    ; Position Cursor Home        
        IORLW    0x080        ; F(x) set
        CALL    LCDPUTCMD
; TABLE_MSG - Display Message
        MOVLW    0        ; Startindex of table message
DISP_MSG1
        MOVWF    TABLE_INDEX  ; Holds message address
        CALL    MSG1
        ANDLW    0x0FF  ; At end of message?
        BTFSC    STATUS, Z    ; (Zero returned at end)
        GOTO    TABLE_MSG_END1            
; LCDPUTCHAR - Display Character
        MOVWF    LCD_TEMP    ; Character to be sent is in W
; LCDBUSY - Wait for LCD to be ready
LCDBUSY1
        MOVLW    0x0FF            ; Set PORTB for input
        BSF        STATUS,RP0
        MOVWF    TRISB
        BCF        STATUS,RP0
        BCF        LCD_CTRL, LCD_RS; Set LCD for command mode
        BSF        LCD_CTRL, LCD_RW; Setup to read busy flag
        BSF        LCD_CTRL, LCD_E    ; LCD E-line High
        MOVF    LCD_DATA, W    ; Read busy flag + DDram address
        BCF        LCD_CTRL, LCD_E    ; LCD E-line Low
        ANDLW    0x80  ; Check Busy flag, High = Busy
        BTFSS    STATUS, Z
        GOTO    LCDBUSY1
LCDNOTBUSY1
        BCF    LCD_CTRL, LCD_RW
        MOVLW    0x000
        BSF        STATUS,RP0
        MOVWF    TRISB        ; Set PORTB for output
        BCF        STATUS,RP0

        BCF    LCD_CTRL, LCD_RW; Set LCD in read mode
        BSF    LCD_CTRL, LCD_RS; Set LCD in data mode
        BSF    LCD_CTRL, LCD_E    ; LCD E-line High
        MOVF    LCD_TEMP, W
        MOVWF    LCD_DATA    ; Send data to LCD
        BCF    LCD_CTRL, LCD_E   ; LCD E-line Low

        MOVF    TABLE_INDEX, W   ; Point to next character
        INCF    TABLE_INDEX, W
        GOTO    DISP_MSG1
TABLE_MSG_END1

; 1 Second Delay
        CALL    Delay1S

        MOVLW    LCD_LINE1
        IORLW    0x080        ; F(x) set
        CALL    LCDPUTCMD
; TABLE_MSG
        MOVLW    0    ; Startindex of table message
DISP_MSG2
        MOVWF    TABLE_INDEX  ; Holds message address
        CALL    MSG2
        ANDLW    0x0FF    ; At end of message?
        BTFSC    STATUS, Z
        GOTO    TABLE_MSG_END2            
; LCDPUTCHAR - Display Character
        MOVWF    LCD_TEMP  ; Character to be sent is in W
LCDBUSY2
        MOVLW    0x0FF        ; Set PORTB for input
        BSF        STATUS,RP0
        MOVWF    TRISB
        BCF        STATUS,RP0

        BCF    LCD_CTRL, LCD_RS; Set LCD for command mode
        BSF    LCD_CTRL, LCD_RW; Setup to read busy flag
        BSF    LCD_CTRL, LCD_E    ; LCD E-line High
        MOVF    LCD_DATA, W    ; Read busy flag + DDram address
        BCF    LCD_CTRL, LCD_E    ; LCD E-line Low
        ANDLW    0x80        ; Check Busy flag, High = Busy
        BTFSS    STATUS, Z
        GOTO    LCDBUSY2
LCDNOTBUSY2
        BCF    LCD_CTRL, LCD_RW
        MOVLW    0x000
        BSF        STATUS,RP0
        MOVWF    TRISB        ; Set PORTB for output
        BCF        STATUS,RP0

        BCF    LCD_CTRL, LCD_RW; Set LCD in read mode
        BSF    LCD_CTRL, LCD_RS; Set LCD in data mode
        BSF    LCD_CTRL, LCD_E    ; LCD E-line High
        MOVF    LCD_TEMP, W
        MOVWF    LCD_DATA    ; Send data to LCD
        BCF    LCD_CTRL, LCD_E    ; LCD E-line Low

        MOVF    TABLE_INDEX, W    ; Point to next character
        INCF    TABLE_INDEX, W
        GOTO    DISP_MSG2
TABLE_MSG_END2

; 4 Second Delay
        CALL    Delay1S
        CALL    Delay1S
        CALL    Delay1S
        CALL    Delay1S
; LCDCLEAR
        MOVLW    0x001
        CALL    LCDPUTCMD

; Program Ends Here (Loops Forever)
LOOP
        GOTO    LOOP

LCDPUTCMD
        MOVWF    LCD_TEMP    ; Command to be sent is in W
LCDBUSY
        MOVLW    0x0FF        ; Set PORTB for input
        MOVWF    TRISB    
        BCF    LCD_CTRL, LCD_RS; Set LCD for command mode
        BSF    LCD_CTRL, LCD_RW; Setup to read busy flag
        BSF    LCD_CTRL, LCD_E    ; LCD E-line High
        MOVF    LCD_DATA, W    ; Read busy flag + DDram address
        BCF    LCD_CTRL, LCD_E    ; LCD E-line Low
        ANDLW    0x80        ; Check Busy flag, High = Busy
        BTFSS    STATUS, Z
        GOTO    LCDBUSY
LCDNOTBUSY
        BCF    LCD_CTRL, LCD_RW
        MOVLW    0x000
        MOVWF    TRISB        ; Set PORTB for output
        BCF    LCD_CTRL, LCD_RW; Set LCD in read mode
        BCF    LCD_CTRL, LCD_RS; Set LCD in command mode
        BSF    LCD_CTRL, LCD_E    ; LCD E-line High
        MOVF    LCD_TEMP, W
        MOVWF    LCD_DATA    ; Send data to LCD
        BCF    LCD_CTRL, LCD_E    ; LCD E-line Low
        RETLW    0

; 500 uSecond Delay Routine

DELAY500                    ;2493 cycles
    movlw    0xF2
    movwf    T1
    movlw    0x02
    movwf    T2
Delay500_0
    decfsz    T1, f
    goto    $+2
    decfsz    T2, f
    goto    Delay500_0
    goto    $+1                ;3 cycles
    nop
    retlw    0                ;4 cycles (including call)

; 1 Second Delay Routine @ Clock frequency = 20 MHz

Delay1S                        ; 4999993 Cycles
    movlw    0x2C
    movwf    T1
    movlw    0xE7
    movwf    T2
    movlw    0x0B
    movwf    T3
Delay1S_0
    decfsz    T1, f
    goto    $+2
    decfsz    T2, f
    goto    $+2
    decfsz    T3, f
    goto    Delay1S_0
    goto    $+1                ; 3 Cycles
    nop
    retlw    0                ; 4 Cycles (including call)

; Table messages to display
MSG1
        addwf    PCL ,F        ;Jump to char pointed to in W reg
        retlw    'W'
        retlw    'e'
        retlw    'l'
        retlw    'c'
        retlw    'o'
        retlw    'm'
        retlw    'e'
        retlw    ' '
        retlw    'M'
        retlw    'e'
        retlw    's'
        retlw    's'
        retlw    'a'
        retlw    'g'
        retlw    'e'
        retlw    0

MSG2
        addwf    PCL ,F        ;Jump to char pointed to in W reg
        retlw    'W'
        retlw    'a'
        retlw    'i'
        retlw    't'
        retlw    ' '
        retlw    '4'
        retlw    ' '
        retlw    's'
        retlw    'e'
        retlw    'c'
        retlw    'o'
        retlw    'n'
        retlw    'd'
        retlw    's'
        retlw    '.'
        retlw    '.'
        retlw    0

    END                ; End of program
I've read some of the datasheet for this particular chip, however, there is more over 200 pages to read through. It would be easier to read up on the answers if I had some idea of what the problem is - but I'm stuck without knowing what I need to even check on.

Thanks for any ideas you might have. Your suggestions have helped getting some parts of the code right but there is more work to be done.
 

Thread Starter

icedtea

Joined Aug 28, 2010
10
Yes, to a point... I can step through until it get's stuck. For instance, it continually loops through the check to see if the internal oscillator is up to speed. Therefore, I 'commented out' that section to check the rest.

It then 'gets stuck' in the code that checks to see if the LCD display is busy. I suppose this is because the LCD is external hardware. How is MPLAB supposed to know when and if the LCD display's bit is clear (not processing any more commands)?

The code does work on the 16F54 with the 20 MHz crystal. All I'm doing is trying to set up the same code on the 16F88 with only the changes that should make it work. The changes I've made include:

1.) Change __CONFIG settings to those required by the 16F88
2.) Clear ANSEL Register (Digital I/O) on Port A
3.) Turn Comparators off on Port A
4.) Place variables in 0x020 memory area and later as required by the 16F88.

Still, the code refuses to run with darker squares on Line 0 of the LCD display (top line). I cannot figure this out...:(
 

Markd77

Joined Sep 7, 2009
2,806
I've spotted a couple of places where banksel TRISB, etc are missing. There could be more.
You can use the Stimulus window to change port values to get the code further in the simulator, or change the values in the Special Function Registers window.

Rich (BB code):
LCDBUSY
        MOVLW    0x0FF        ; Set PORTB for input
        MOVWF    TRISB    
        BCF    LCD_CTRL, LCD_RS; Set LCD for command mode
        BSF    LCD_CTRL, LCD_RW; Setup to read busy flag
        BSF    LCD_CTRL, LCD_E    ; LCD E-line High
        MOVF    LCD_DATA, W    ; Read busy flag + DDram address
        BCF    LCD_CTRL, LCD_E    ; LCD E-line Low
        ANDLW    0x80        ; Check Busy flag, High = Busy
        BTFSS    STATUS, Z
        GOTO    LCDBUSY
LCDNOTBUSY
        BCF    LCD_CTRL, LCD_RW
        MOVLW    0x000
        MOVWF    TRISB        ; Set PORTB for output

This bit threw me for a while - it essentially does very little but presumably needs 3 instructions for timing purposes.
Rich (BB code):
MOVLW    0x000        ; Display Off, Cursor Off, No-Blink
        ANDLW    0x007        ; Strip upper bits
        IORLW    0x008        ; Function set
        CALL    LCDPUTCMD
 

Thread Starter

icedtea

Joined Aug 28, 2010
10
Thanks Markd77!!! I guess I didn't catch them all when I was looking over the code earlier. I'll fix the problems you pointed out and give this a try early this afternoon.

I think the other section of code is just "stripping the upper bits" so that it doesn't interfere with anything else you are using the other pins on Port A for, i.e. switches, LEDs, etc. Though, I could be wrong. On the 16F54, the program runs flawlessly. It would take too much experimentation for me to fully understand it right now - maybe down the road. Thanks again for your help by pointing the BANKSEL problem out! I'll let you know...
 

Markd77

Joined Sep 7, 2009
2,806
You can ignore the second section, it's just a little odd:
movlw 0x00 ;set W to zero
andlw 0x007 ;W still zero
iorlw 0x008 ;W still zero
 

Thread Starter

icedtea

Joined Aug 28, 2010
10
I never got back to everyone but did get the code working on the 16F88. I have since opted to go with a bigger chip, the 16F917 and the 4-bit LCD communication route. Thanks again for all of your help in conquering the 2-wire LCD interface - I really appreciate all of your expertise! :)
 
Top