PDA

View Full Version : Changing LCD display refresh rate



pxidr84
- 3rd November 2011, 18:15
Hi everyone,

In my program, the LCD commands are placed in a loop.

But the refresh rate of the LCD is too fast, so in certain conditions (when reading an unstable ADC value for example), the displayed numbers are changing very quickly, so it's unreadable.

So, it will be better if my LCD refresh displayed values every 200/500ms.

I don't want to use a delay/wait command in my loop.

Did the DEFINE LCD [...] commands can solve this problem?

Thanks a lot.

cc1984
- 3rd November 2011, 18:59
Why not just add a condition that only updates the LCD if the ADC value changes by a certain amount from the last reading. That would reduce the updates and also make it less resposive to small changes in voltage.

rsocor01
- 3rd November 2011, 19:32
Well, this is just an idea. Take 10 readings, then obtain the average, and display it in the LCD. Something like this,



MAIN:

FOR I = 0 TO 9
....Take ADC reading READING[I]
NEXT I

'Next obtain the average
AVERAGE = (READING[0] + READING[1] + ......) / 10

LCDOUT $FE, 1, DEC AVERAGE

GOTO MAIN


Robert

pxidr84
- 3rd November 2011, 19:33
How do that?

Here is a sample of my loop :


lp:

ADCON0.1=%1
WHILE ADCON0.1=%1:WEND

' Store ADC results
isense.HIGHBYTE=ADRESH
isense.LOWBYTE=ADRESL

' Security fault verifications
IF isense**40000>imax THEN flt=1

' LCD
idisp=isense**40000
lcdout $fe,$c0,$1,$20,"1 ISENS: ",DEC idisp DIG 2,DEC idisp DIG 1,".",DEC idisp DIG 0,"A"


goto lp

Acetronics2
- 3rd November 2011, 19:44
lp:

ADCON0.1=%1
WHILE ADCON0.1=%1:WEND

' Store ADC results
isense.HIGHBYTE=ADRESH
isense.LOWBYTE=ADRESL

' Security fault verifications
IF isense**40000>imax THEN flt=1

I = I+1 ; insert @top " I var Byte "
IF I = 1 THEN ; also can use IF I // 200 = 1 ... and adjust "200" to the desired rate

' LCD
idisp=isense**40000
lcdout $fe,$c0,$1,$20,"1 ISENS: ",DEC idisp DIG 2,DEC idisp DIG 1,".",DEC idisp DIG 0,"A"

ENDIF


goto lp

rsocor01
- 3rd November 2011, 19:58
How do that?


Something like this,


lp:

AVERAGE = 0
FOR I = 0 TO 9
ADCON0.1=%1
WHILE ADCON0.1=%1:WEND

' Store ADC results
isense.HIGHBYTE=ADRESH
isense.LOWBYTE=ADRESL

AVERAGE = AVERAGE + isense
NEXT I

AVERAGE = AVERAGE / 10
ISENSE = AVERAGE

' Security fault verifications
IF isense**40000>imax THEN flt=1

' LCD
idisp=isense**40000
lcdout $fe,$c0,$1,$20,"1 ISENS: ",DEC idisp DIG 2,DEC idisp DIG 1,".",DEC idisp DIG 0,"A"


goto lp

Charles Linquis
- 4th November 2011, 00:03
A slightly different method:

Updating LCDs is really time consuming, from a PIC viewpoint. I find that a .25(once every 4 seconds) update rate is about right for most people, especially if it a two-line display.

The code below lets your code run at full speed and updates the LCD once every 4 seconds. Of course the rate can be changed to suit the user. It uses an ASM interrupt for low overhead.
Of course, you could read the timer directly, but I find that I always need interrupts anyway.




DEFINE OSC 4

MasterClock VAR WORD BANKA SYSTEM
;----------------Timer Setup-----------------------------------
T0CON = 000010 ; /1:8 prescaler, tmr0 ON
;
;-------------------------------------------------------------

INCLUDE "DT_INTS-18.bas" '
;---------------------------------------------------------------
asm
INT_LIST macro
INT_Handler TMR0_INT, MainTimer, ASM, yes
endm
INT_CREATE
endasm
''----------------- Initialization Done! -----------------------------
Goto OverInt
;----------------------- Timer INt ------------------------------------
ASM
MainTimer
movlw 0xCF ; 100 mSec @ 4MHz
movwf TMR0H
movlw 0x2C
movwf TMR0L

btfsc MasterClock + 1,7 ; Don't let MasterClock roll over
bra DontCount
infsnz MasterClock
incf MasterClock + 1


DontCount

bcf INTCON,2
INT_ENABLE TMR0_INT
INT_RETURN
ENDASM
;---------------------------------------------------------------------
OverInt:

INTCON.7 = 1 ; Main Ints
INTCON.6 = 1 ; Peripheral ints

MasterClock = 0
@ bcf INTCON,2
@ INT_ENABLE TMR0_INT
TopOfLoop:
If MasterClock >= 20 then ; 20 X .1 sec = 2 seconds
MasterClock = 0

; Do LCD routines here
endif

; Your main program here

goto TopOfLoop

pxidr84
- 4th November 2011, 09:49
There is no @ int_return at the end?
I already use a timer1 DT interrupt, this one will not affect my program?

pxidr84
- 4th November 2011, 12:09
Note : I use a 40MHz xtal, and my LCD desired refresh rate is about 0.5s.

Charles Linquis
- 4th November 2011, 13:10
The ISR is not written in PBP. It is in assembly. The only INT_RETURN you need is at the end of the interrupt service routine - just before the ENDASM.

For 40Mhz -
Lines you need to change

DEFINE OSC 40
T0CON = %10000011 ; Turn timer on, divide by 16 prescaler

movlw 0x0B ; 100 mSec @ 40MHz
movwf TMR0H
movlw 0xDC
movwf TMR0L


If MasterClock >= 5 then ; 5 X .1 sec = .5 seconds


And no, it will not affect anything else you have running.

pxidr84
- 6th November 2011, 09:57
Ok, so I've integrated a very simple counter whos counts the number of loops and refresh the LCD after a certain amount of loops :


' Main entire program loop
lp:


' Start ADC conversion
ADCON0.1=%1
WHILE ADCON0.1=%1:WEND


' Store ADC results
isense.HIGHBYTE=ADRESH
isense.LOWBYTE=ADRESL
usense.HIGHBYTE=ADRESH
usense.LOWBYTE=ADRESL
tsense.HIGHBYTE=ADRESH
tsense.LOWBYTE=ADRESL
psense.HIGHBYTE=ADRESH
psense.LOWBYTE=ADRESL


' Security fault verifications
IF isense**40000>imax THEN flt=1
IF usense>880 THEN flt=2
IF tsense>880 THEN flt=3


' Security fault tripping
IF flt>0 THEN GOTO fltsub


' Brake/surge resistor control
IF usense>800 then
if run=%1 then high PORTD.7
else
LOW PORTD.7
endif

' Frequency reference control by potentiometer
psense=((psense<<6)**maxf)+10
IF psense<>freq+10 THEN freq=psense:flag=%1


' Frequency limits
IF freq<minf THEN freq=minf
IF freq>maxf THEN freq=maxf


' Recalculations
IF flag=%1 THEN


' Reload timer calculation
dum=dum1*dum2
stor=DIV32 freq
rld=(65535-stor)+8


' U/F calculation
IF freq<=500 THEN
amp=(freq*131)+35
ELSE
amp=65535
ENDIF


flag=%0
ENDIF


' Run
IF run=%1 THEN
IF flag1=%0 THEN PWMCON0.6=%1:HIGH PORTD.6:flag1=%1
ENDIF


' Stop
IF run=%0 THEN
IF flag1=%0 THEN PWMCON0=%0:LOW PORTD.6:flag1=%1
ENDIF


' FWD rotation
IF rot=%1 THEN
IF flag2=%0 THEN ustep=89:vstep=59:wstep=29:write 0,rot:flag2=%1
ENDIF


' RWD rotation
IF rot=%0 THEN
IF flag2=%0 THEN ustep=29:vstep=59:wstep=89:write 0,rot:flag2=%1
ENDIF


' - button
IF PORTE.0=%1 then
if flag8=%0 then
IF menu=%0 THEN mpos=mpos-1:d=1200:E=%0:F=%0
ENDIF
flag8=%1
endif


' + button
IF PORTE.1=%1 then
if flag9=%0 then
IF menu=%0 THEN mpos=mpos+1:d=1200:E=%0:F=%0
endif
flag9=%1
endif


' Run/stop button
IF PORTC.0=%1 THEN
IF run=%0 AND mpos<6 AND flag3=%0 THEN run=%1:flag1=%0:flag3=%1:f=%0
IF run=%1 AND flag3=%0 THEN run=%0:flag1=%0:flag3=%1:f=%0
ENDIF


' FWD/RWD button
IF PORTC.1=%1 THEN
IF rot=%0 AND run=%0 AND flag4=%0 THEN rot=%1:flag2=%0:flag4=%1
IF rot=%1 AND run=%0 AND flag4=%0 THEN rot=%0:flag2=%0:flag4=%1
ENDIF


' Menu/OK button
IF PORTC.2=%1 THEN
IF menu=%0 AND run=%0 AND mpos>5 AND flag5=%0 THEN menu=%1:flag5=%1
IF menu=%1 AND flag5=%0 THEN menu=%0:flag5=%1
ENDIF


' Buttons released state
IF PORTC.0=%0 THEN flag3=%0
IF PORTC.1=%0 THEN flag4=%0
IF PORTC.2=%0 THEN flag5=%0
IF PORTE.0=%0 THEN flag8=%0
IF PORTE.1=%0 THEN flag9=%0


' LCD first line writing
c=c+1
if c>800 then
IF rot=%1 THEN LCDOUT $fe,$2,"+"
IF rot=%0 THEN LCDOUT $fe,$2,"-"
LCDOUT DEC freq DIG 3,DEC freq DIG 2,DEC freq DIG 1,".",DEC freq DIG 0,"Hz"
IF run=%1 THEN LCDOUT REP 32\5,"RUN"
IF run=%0 THEN LCDOUT REP 32\4,"STOP"
c=0
endif


' Inverter menu (LCD second line writing)
SELECT CASE mpos


' Menu limits
IF mpos<1 THEN mpos=1
IF mpos>11 THEN mpos=11
IF run=%1 THEN
IF mpos>5 THEN mpos=5
ENDIF


' Current sensing submenu
CASE 1
d=d+1
if d>1200 then
idisp=isense**40000
lcdout $fe,$c0,$1,$20,"1 ISENS: ",DEC idisp DIG 2,DEC idisp DIG 1,".",DEC idisp DIG 0,"A"
d=0
endif


' Voltage sensing submenu
CASE 2
d=d+1
if d>1200 then
udisp=usense**29600
lcdout $fe,$c0,$1,$0,"2 USENS: ",DEC3 udisp,"V",32
d=0
endif


' Temperature sensing submenu
CASE 3
d=d+1
if d>1200 then
tdisp=(tsense-280)/8
lcdout $fe,$c0,$1,$0,"3 TEMP: ",DEC tdisp DIG 1,DEC tdisp DIG 0,$df,"C",REP $20\2
d=0
endif


' Last fault reading submenu
CASE 4
if e=%0 then
lcdout $fe,$c0,$1,$0,"4 LASTFAULT: ",DEC1 lastf
e=%1
endif


' Firmware version reading submenu
CASE 5
IF run=%1 THEN
IF f=%0 then
lcdout $fe,$c0,$1,$20,"5 FW: V2011.00"
f=%1
ENDIF
ENDIF
IF run=%0 THEN
IF F=%0 THEN
lcdout $fe,$c0,$1,$0,"5 FW: V2011.00"
f=%1
ENDIF
endif


' Maximum frequency adjust submenu
CASE 6
IF menu=%1 THEN
Lcdout $fe,$c0,$3e,$3e,"A MAX: ",DEC maxf DIG 3,DEC maxf DIG 2,DEC maxf DIG 1,".",DEC maxf DIG 0,"Hz"
BUTTON PORTE.0,1,200,10,a,0,ret
IF maxf>minf THEN maxf=maxf-1
ret:
BUTTON PORTE.1,1,200,10,b,0,ret1
IF maxf<1200 THEN maxf=maxf+1
ret1:
flag6=%0
ELSE
lcdout $fe,$c0,$1,$0,"A MAX: ",DEC maxf DIG 3,DEC maxf DIG 2,DEC maxf DIG 1,".",DEC maxf DIG 0,"Hz"
if flag6=%0 then write 1,maxf.HIGHBYTE:write 2,maxf.LOWBYTE:flag6=%1
ENDIF


' Minimum frequency adjust submenu
CASE 7
IF menu=%1 THEN
Lcdout $fe,$c0,$3e,$3e,"B MIN: ",DEC minf DIG 3,DEC minf DIG 2,DEC minf DIG 1,".",DEC minf DIG 0,"Hz"
BUTTON PORTE.0,1,200,10,a,0,ret2
IF minf>10 THEN minf=minf-1
ret2:
BUTTON PORTE.1,1,200,10,b,0,ret3
IF minf<maxf THEN minf=minf+1
ret3:
flag6=%0
ELSE
lcdout $fe,$c0,$1,$0,"B MIN: ",DEC minf DIG 3,DEC minf DIG 2,DEC minf DIG 1,".",DEC minf DIG 0,"Hz"
if flag6=%0 then write 3,minf.HIGHBYTE:write 4,minf.LOWBYTE:flag6=%1
ENDIF


' Current trip adjust submenu
CASE 8
IF menu=%1 THEN
Lcdout $fe,$c0,$3e,$3e,"C ITRIP: ",DEC imax DIG 2,DEC imax DIG 1,".",DEC imax DIG 0,"A"
BUTTON PORTE.0,1,200,20,a,0,ret4
IF imax>0 THEN imax=imax-1
ret4:
BUTTON PORTE.1,1,200,20,b,0,ret5
IF imax<150 THEN imax=imax+1
ret5:
flag6=%0
ELSE
lcdout $fe,$c0,$1,$0,"C ITRIP: ",DEC imax DIG 2,DEC imax DIG 1,".",DEC imax DIG 0,"A"
IF flag6=%0 THEN write 5,imax:flag6=%1
ENDIF


' PWM carrier frequency adjust submenu
CASE 9
IF menu=%1 THEN
Lcdout $fe,$c0,$3e,$3e,"D PWMFREQ: ",DEC1 pwmf,REP $20\2
BUTTON PORTE.0,1,200,50,a,0,ret6
IF pwmf>1 THEN pwmf=pwmf-1
ret6:
BUTTON PORTE.1,1,200,50,b,0,ret7
IF pwmf<4 THEN pwmf=pwmf+1
ret7:
flag6=%0
ELSE
lcdout $fe,$c0,$1,$0,"D PWMFREQ: ",DEC1 pwmf,REP $20\2
IF flag6=%0 THEN write 6,pwmf:GOSUB pwmsub:flag6=%1
ENDIF


' LCD backlight submenu
CASE 10
IF menu=%1 THEN
Lcdout $fe,$c0,$3e,$3e,"E BACKLIGHT: ",DEC1 bl
IF PORTE.0=%1 then
IF bl=%1 THEN bl=%0
endif
if PORTE.1=%1 then
IF bl=%0 THEN bl=%1
ENDIF
flag6=%0
ELSE
lcdout $fe,$c0,$1,$0,"E BACKLIGHT: ",DEC1 bl
IF flag6=%0 THEN write 7,bl:GOSUB blsub:flag6=%1
endif


' Reset all settings submenu
CASE 11
IF menu=%1 THEN
IF flag7=%0 THEN
rot=%1:write 0,rot
maxf=500:write 1,maxf.HIGHBYTE:write 2,maxf.LOWBYTE
minf=10:write 3,minf.HIGHBYTE:write 4,minf.LOWBYTE
imax=150:write 5,imax
pwmf=3:write 6,pwmf:GOSUB pwmsub
bl=%1:write 7,bl:GOSUB blsub
Lcdout $fe,$c0,$3e,$3e,"F RESET? OK",REP $20\3:flag7=%1
ENDIF
else
IF menu=%0 THEN lcdout $fe,$c0,$20,$0,"F RESET?",REP $20\6:flag7=%0
endif


END SELECT


GOTO lp


It's working very well, the gain of speed of the loop is incredible (about ten times faster than the old program).

But sometimes, when I navigate into the menu, the LCD freeze and the PIC "resets". I don't know why. What's happen?