I can't see any alternate pin functions that would be causing trouble - LVP, the comparator and A/D converter are all disabled correctly. The fact that the code works fine on the 16F877A but not the 16F876A is very odd!
Could you please post the assembly code generated for the 876A by GCBASIC?
If you haven't already, it might also be worth checking to see if the PIC is working:
- Check that MCLR is pulled up to 5 volts
- Check that there is a voltage on the oscillator pins
- Download an LED flashing program, and see if it works
- Check that all of the LCD pins are wired up as specified in the constants
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I will post the assembly code. As far as the PIC is concerned, I have a 4K word program compiled with Oshonsoft Basic that is running fine. What I was in the process of doing is getting the same code compiled with GCBASIC but starting with some small test programs.
You notice that one main difference is the failing code uses the lower nibble of the port. Maybe the nibble section of the library has a problem.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
Using the lower nibble shouldn't make any difference, when in 4-bit mode the GCBASIC LCD library only uses operations that act on a single bit.
Does GCBASIC initialise the LCD properly? If you're using a 2-line LCD, you can tell by setting the contrast on the LCD to the maximum and then checking to see how many lines there are. 1 line means it's not initialised, 2 means it is.
I'll look thoroughly at the assembly when you post it, hopefully there will be some clue!
What version of GCBASIC are you using? The latest released version (0.9.3.0, dated January some time), or a more recent update? If you're using the latest update, what is the date on it?
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
;Program compiled by Great Cow BASIC (0.9 6/10/2007)
;Need help? See the GCBASIC forums at http://sourceforge.net/forum/?group_id=169286,
;check the documentation or email hconsidine@bigpond.com.
;Set up the assembler options (Chip type, clock source, other bits and pieces)
LIST p=16F876A, r=DEC
#include <P16F876A.inc>
__CONFIG _HS_OSC & _WDT_OFF & _LVP_OFF
;********************************************************************************
;Subroutines included in program
;********************************************************************************
The assembly produced looks absolutely fine - aside from a few (expected) differences, it's identical to the copy of your code that runs fine on the 877A I have.
Are you using the same LCD on your 876A and 877A? If not, it could be a timing issue.
Another possibility is that there is a problem with the R/W wire. GCBASIC reads the status from the LCD and doesn't continue until it is ready, but I know that some other compilers/routines don't do this.
Could you add some code to toggle a port to see if GCBASIC is detecting whether the LCD is ready? To do this, open include\lowlevel\lcd.h, find this section:
sub LCDWriteByte(LCDByte) #NR
#IFDEF LCD_IO 4,8
wait until LCDReady
set LCD_RW OFF 'Write mode
#ENDIF
and replace it with:
sub LCDWriteByte(LCDByte) #NR
#IFDEF LCD_IO 4,8
Set LED On
wait until LCDReady
Set LED Off
set LCD_RW OFF 'Write mode
#ENDIF
where LED is some output pin. If the pin stays on, then there is some problem with reading back the LCD status.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
I have tested LCDbusy, as you suggested, and it is working fine. I have written assembly code for an LCD before and I know they are very sensitive to timing. I looked closely at the library and I can't see anything obvious. I have also looked at the assembly code from the Pic_Sim_Ide from Oshonsoft, which is working. The only difference that I see, is that in the LCDWriteByte routine he checks busy at the end, not at the beginning of the routine.
If you would like to refer to this comment somewhere else in this project, copy and paste the following link:
'******* This version uses the 16F876A ****************
' This version fails
#chip 16F876a, 10
#define LCD_IO 4
#define LCD_DB4 PORTB.0
#define LCD_DB5 PORTB.1
#define LCD_DB6 PORTB.2
#define LCD_DB7 PORTB.3
#define LCD_RS PORTA.3
#define LCD_RW PORTA.2
#define LCD_Enable PORTA.1
'InitLCD
TRISA = 0x30
TRISB = 0xf0
ADCON1 = 0x07
loop:
Print "LCDterm II"
wait 1 sec
CLS
wait 100 ms
goto loop
'********************************************************
'******** This version uses the 16F877A
' This version runs
#chip 16F877a, 10
#define LCD_IO 4
#define LCD_DB4 PORTD.4
#define LCD_DB5 PORTD.5
#define LCD_DB6 PORTD.6
#define LCD_DB7 PORTD.7
#define LCD_RS PORTE.0
#define LCD_RW PORTE.1
#define LCD_Enable PORTE.2
'InitLCD
loop:
Print "LCDterm II"
wait 1 sec
CLS
wait 100 ms
goto loop
Very strange!
I can't see any alternate pin functions that would be causing trouble - LVP, the comparator and A/D converter are all disabled correctly. The fact that the code works fine on the 16F877A but not the 16F876A is very odd!
Could you please post the assembly code generated for the 876A by GCBASIC?
If you haven't already, it might also be worth checking to see if the PIC is working:
- Check that MCLR is pulled up to 5 volts
- Check that there is a voltage on the oscillator pins
- Download an LED flashing program, and see if it works
- Check that all of the LCD pins are wired up as specified in the constants
I will post the assembly code. As far as the PIC is concerned, I have a 4K word program compiled with Oshonsoft Basic that is running fine. What I was in the process of doing is getting the same code compiled with GCBASIC but starting with some small test programs.
You notice that one main difference is the failing code uses the lower nibble of the port. Maybe the nibble section of the library has a problem.
Using the lower nibble shouldn't make any difference, when in 4-bit mode the GCBASIC LCD library only uses operations that act on a single bit.
Does GCBASIC initialise the LCD properly? If you're using a 2-line LCD, you can tell by setting the contrast on the LCD to the maximum and then checking to see how many lines there are. 1 line means it's not initialised, 2 means it is.
I'll look thoroughly at the assembly when you post it, hopefully there will be some clue!
What version of GCBASIC are you using? The latest released version (0.9.3.0, dated January some time), or a more recent update? If you're using the latest update, what is the date on it?
;Program compiled by Great Cow BASIC (0.9 6/10/2007)
;Need help? See the GCBASIC forums at http://sourceforge.net/forum/?group_id=169286,
;check the documentation or email hconsidine@bigpond.com.
;********************************************************************************
;Set up the assembler options (Chip type, clock source, other bits and pieces)
LIST p=16F876A, r=DEC
#include <P16F876A.inc>
__CONFIG _HS_OSC & _WDT_OFF & _LVP_OFF
;********************************************************************************
;Set aside memory locations for variables
SysTempArray equ 454 ;Array
DELAYTEMP equ 32
DELAYTEMP2 equ 33
LCDBYTE equ 34
LCDREADY equ 35
PRINTLEN equ 36
SYSCALCTEMPA equ 37
SYSCALCTEMPA_H equ 38
SYSLCDTEMP equ 39
SYSPRINTTEMP equ 40
SYSSTRINGLENGTH equ 41
StringPointer equ 42
SysPRINTDATAHandler equ 43
SysPRINTDATAHandler_H equ 44
SysStringA equ 45
SysStringA_H equ 46
SysStringB equ 47
SysStringB_H equ 48
SysWaitTemp10US equ 49
SysWaitTempMS equ 50
SysWaitTempMS_H equ 51
SysWaitTempS equ 52
;********************************************************************************
;Jump to initialisation code when PIC is reset
ORG 0
clrf PCLATH
goto SystemInitialise
;********************************************************************************
;Interrupt vector
ORG 4
retfie
;Various initialisation routines, automatically called by GCBASIC
SystemInitialise
call INITSYS
call INITLCD
;********************************************************************************
;Start of the main program
movlw 48
banksel TRISA
movwf TRISA
movlw 240
movwf TRISB
movlw 7
movwf ADCON1
LOOP
movlw low SysTempArray
banksel SYSSTRINGB
movwf SysStringB
movlw high SysTempArray
movwf SysStringB_H
movlw low StringTable1
movwf SysStringA
movlw high StringTable1
movwf SysStringA_H
call SysReadString
movlw low SYSTEMPARRAY
movwf SysPRINTDATAHandler
movlw high SYSTEMPARRAY
movwf SysPRINTDATAHandler_H
call PRINT
movlw 1
movwf SysWaitTempS
call Delay_S
call CLS
movlw 100
movwf SysWaitTempMS
clrf SysWaitTempMS_H
call Delay_MS
goto LOOP
BASPROGRAMEND
sleep
goto $
;********************************************************************************
; String Lookup Table
SysStringTables
movf SysStringA_H,W
movwf PCLATH
movf SysStringA,W
incf SysStringA,F
btfsc STATUS,Z
incf SysStringA_H,F
movwf PCL
StringTable1
retlw 10
retlw 76 ;L
retlw 67 ;C
retlw 68 ;D
retlw 116 ;t
retlw 101 ;e
retlw 114 ;r
retlw 109 ;m
retlw 32 ;
retlw 73 ;I
retlw 73 ;I
;********************************************************************************
;Subroutines included in program
;********************************************************************************
CLS
bcf PORTA,3
movlw 1
movwf LCDBYTE
call LCDWRITEBYTE
movlw 2
movwf SysWaitTempMS
clrf SysWaitTempMS_H
call Delay_MS
movlw 128
movwf LCDBYTE
call LCDWRITEBYTE
movlw 10
movwf SysWaitTemp10US
call Delay_10US
return
;********************************************************************************
Delay_10US
D10US_START
movlw 8
movwf DELAYTEMP
D10US_LOOP
decfsz DELAYTEMP, F
goto D10US_LOOP
decfsz SysWaitTemp10US, F
goto D10US_START
return
;********************************************************************************
Delay_MS
incf SysWaitTempMS_H, F
DMS_START
movlw 10
movwf DELAYTEMP2
DMS_OUTER
movlw 83
movwf DELAYTEMP
DMS_INNER
decfsz DELAYTEMP, F
goto DMS_INNER
decfsz DELAYTEMP2, F
goto DMS_OUTER
decfsz SysWaitTempMS, F
goto DMS_START
decfsz SysWaitTempMS_H, F
goto DMS_START
return
;********************************************************************************
Delay_S
DS_START
movlw 232
movwf SysWaitTempMS
movlw 3
movwf SysWaitTempMS_H
call Delay_MS
decfsz SysWaitTempS, F
goto DS_START
return
;********************************************************************************
FN_LCDREADY
clrf LCDREADY
bcf SYSLCDTEMP,2
btfsc PORTA,3
bsf SYSLCDTEMP,2
bsf PORTA,2
bcf PORTA,3
bsf PORTA,1
movlw 5
movwf SysWaitTemp10US
call Delay_10US
banksel TRISB
bsf TRISB,3
banksel PORTB
btfsc PORTB,3
goto ENDIF1
movlw 255
movwf LCDREADY
ENDIF1
bcf PORTA,1
movlw 25
movwf SysWaitTemp10US
call Delay_10US
bcf PORTA,3
btfsc SYSLCDTEMP,2
bsf PORTA,3
return
;********************************************************************************
INITLCD
banksel TRISA
bcf TRISA,3
bcf TRISA,2
bcf TRISA,1
movlw 10
banksel SYSWAITTEMPMS
movwf SysWaitTempMS
clrf SysWaitTempMS_H
call Delay_MS
SysWaitLoop1
call FN_LCDREADY
movf LCDREADY,F
btfsc STATUS,Z
goto SysWaitLoop1
bcf PORTA,3
banksel TRISB
bcf TRISB,0
bcf TRISB,1
bcf TRISB,2
bcf TRISB,3
banksel PORTA
bcf PORTA,3
bcf PORTA,2
bcf PORTB,0
bsf PORTB,1
bcf PORTB,2
bcf PORTB,3
bsf PORTA,1
movlw 5
movwf SysWaitTemp10US
call Delay_10US
bcf PORTA,1
movlw 5
movwf SysWaitTempMS
clrf SysWaitTempMS_H
call Delay_MS
movlw 40
movwf LCDBYTE
call LCDWRITEBYTE
movlw 25
movwf SysWaitTemp10US
call Delay_10US
bcf PORTA,3
movlw 6
movwf LCDBYTE
call LCDWRITEBYTE
movlw 5
movwf SysWaitTemp10US
call Delay_10US
movlw 12
movwf LCDBYTE
call LCDWRITEBYTE
movlw 5
movwf SysWaitTemp10US
call Delay_10US
call CLS
return
;********************************************************************************
INITSYS
bcf ADCON0,ADON
banksel ADCON1
bcf ADCON1,ADFM
bcf ADCON1,PCFG3
bsf ADCON1,PCFG2
bsf ADCON1,PCFG1
bcf ADCON1,PCFG0
movlw 7
movwf CMCON
banksel PORTA
clrf PORTA
clrf PORTB
clrf PORTC
return
;********************************************************************************
LCDWRITEBYTE
SysWaitLoop2
call FN_LCDREADY
movf LCDREADY,F
btfsc STATUS,Z
goto SysWaitLoop2
bcf PORTA,2
banksel TRISB
bcf TRISB,0
bcf TRISB,1
bcf TRISB,2
bcf TRISB,3
banksel PORTB
bcf PORTB,0
bcf PORTB,1
bcf PORTB,2
bcf PORTB,3
btfsc LCDBYTE,7
bsf PORTB,3
btfsc LCDBYTE,6
bsf PORTB,2
btfsc LCDBYTE,5
bsf PORTB,1
btfsc LCDBYTE,4
bsf PORTB,0
bsf PORTA,1
movlw 5
movwf SysWaitTemp10US
call Delay_10US
bcf PORTA,1
movlw 5
movwf SysWaitTemp10US
call Delay_10US
bcf PORTB,0
bcf PORTB,1
bcf PORTB,2
bcf PORTB,3
btfsc LCDBYTE,3
bsf PORTB,3
btfsc LCDBYTE,2
bsf PORTB,2
btfsc LCDBYTE,1
bsf PORTB,1
btfsc LCDBYTE,0
bsf PORTB,0
bsf PORTA,1
movlw 5
movwf SysWaitTemp10US
call Delay_10US
bcf PORTA,1
movlw 5
movwf SysWaitTemp10US
call Delay_10US
bcf PORTB,3
bcf PORTB,2
bcf PORTB,1
bcf PORTB,0
return
;********************************************************************************
PRINT
movf SysPRINTDATAHandler,W
movwf FSR
bcf STATUS, IRP
btfsc SysPRINTDATAHandler_H,0
bsf STATUS, IRP
movf INDF,W
movwf PRINTLEN
movlw 0
subwf PRINTLEN,W
btfsc STATUS, Z
return
bsf PORTA,3
clrf SYSPRINTTEMP
SysForLoop1
incf SYSPRINTTEMP,F
movf SYSPRINTTEMP,W
addwf SysPRINTDATAHandler,W
movwf FSR
bcf STATUS, IRP
btfsc SysPRINTDATAHandler_H,0
bsf STATUS, IRP
movf INDF,W
movwf LCDBYTE
call LCDWRITEBYTE
movf PRINTLEN,W
subwf SYSPRINTTEMP,W
btfss STATUS, C
goto SysForLoop1
return
;********************************************************************************
SYSREADSTRING
movf SYSSTRINGB, W
movwf FSR
bcf STATUS, IRP
btfsc SYSSTRINGB_H, 0
bsf STATUS, IRP
call SYSSTRINGTABLES
movwf SYSCALCTEMPA
movwf INDF
addwf SYSSTRINGB, F
goto SYSSTRINGREADCHECK
SYSREADSTRINGPART
movf SYSSTRINGB, W
movwf FSR
bcf STATUS, IRP
btfsc SYSSTRINGB_H, 0
bsf STATUS, IRP
call SYSSTRINGTABLES
movwf SYSCALCTEMPA
addwf SYSSTRINGLENGTH,F
addwf SYSSTRINGB,F
SYSSTRINGREADCHECK
movf SYSCALCTEMPA,F
btfsc STATUS,Z
return
SYSSTRINGREAD
call SYSSTRINGTABLES
incf FSR, F
movwf INDF
decfsz SYSCALCTEMPA, F
goto SYSSTRINGREAD
return
;********************************************************************************
END
The assembly produced looks absolutely fine - aside from a few (expected) differences, it's identical to the copy of your code that runs fine on the 877A I have.
Are you using the same LCD on your 876A and 877A? If not, it could be a timing issue.
Another possibility is that there is a problem with the R/W wire. GCBASIC reads the status from the LCD and doesn't continue until it is ready, but I know that some other compilers/routines don't do this.
Could you add some code to toggle a port to see if GCBASIC is detecting whether the LCD is ready? To do this, open include\lowlevel\lcd.h, find this section:
sub LCDWriteByte(LCDByte) #NR
#IFDEF LCD_IO 4,8
wait until LCDReady
set LCD_RW OFF 'Write mode
#ENDIF
and replace it with:
sub LCDWriteByte(LCDByte) #NR
#IFDEF LCD_IO 4,8
Set LED On
wait until LCDReady
Set LED Off
set LCD_RW OFF 'Write mode
#ENDIF
where LED is some output pin. If the pin stays on, then there is some problem with reading back the LCD status.
No it is the very same 4x20 display in both cases. I will try your suggestion.
I have tested LCDbusy, as you suggested, and it is working fine. I have written assembly code for an LCD before and I know they are very sensitive to timing. I looked closely at the library and I can't see anything obvious. I have also looked at the assembly code from the Pic_Sim_Ide from Oshonsoft, which is working. The only difference that I see, is that in the LCDWriteByte routine he checks busy at the end, not at the beginning of the routine.