PDA

View Full Version : LCD displays, rotary encoders, and the WRITE statement



keithv
- 15th March 2018, 23:59
I'm having trouble using incremental rotary encoders with an LCD display and using the WRITE command together. The first problem was getting the rotary encoders to work well and read out on the LCD. I found that for the LCD screen to display clearly, it needs a small pause each time the screen is cleared and updated. Unfortunately, adding this pause made the encoders not work well. They seem to not want any pause or debounce at all. I found that if I use an interrupt for the LCD display code and have the rotary encoder code in the main code it works great. However, after resolving that and moving on to the next phase, I'm finding that the WRITE statment doesn't work.

I have added DEFINE WRITE_INT 1 and this did not help.

I wrote an alternate version of the code that does not use the interrupt and the READ/WRITE statements works fine, so I think I'm using it correctly....it's just that the encoders don't work very well.

Is there something else I should be doing besides the DEFINE WRITE_INT 1? Is there some trick to getting encoders to work with an LCD without using an interrupt?

Dave
- 16th March 2018, 11:39
You do realize that the WRITE statement is writing to EEPROM and each time it is executed there is a up to 10Ms. delay in the writing process. DEFINE WRITE_INT 1 is to be used when there are active interrupts in your source code. It allows for the command to complete before executing the next statement. I have to ask, why are you writing to eeprom during your rotary encoder decoding?

mpgmike
- 16th March 2018, 14:28
Create a variable to count each time you loop through your Main segment. Only display to the LCD when your counter reaches 50 (or whatever). This way it will just skip the LCD write 49 times, giving it the needed display time for visibility.

keithv
- 16th March 2018, 21:10
I used mpgmike's suggestion and added a 200ms counter for the LCD display. The read or write (i'm not sure which one) statement still isn't working correctly. I was wrong before when I said it worked when I removed the interrupt. After fiddling with it some more, I realized it doesn't work correctly. So I'm not sure what I'm doing wrong. Hopefully it's something obvious. Here's what's going on:

I'm using a PIC16F887. I have an LCD display connected. There are also 3 incremental rotary encoders connected. Each of the rotary encoders also has a pushbutton switch. I want to display each rotary encoder's "position" of 0 - 255 on the LCD. This is part is working.

I want to be able to save and recall the settings of the rotary encoders. I am using the button on encoder2 as a "save" button. I'm using the button on encoder1 to move backwards through the saved settings and the button on encoder3 to move forward through the saved settings. This is the part that is not working. I'm not sure if it isn't writing correctly or isn't reading correctly...well...I'm sure it's doing what it's supposed to do correctly, I just did something wrong.




CLEAR
define LOADER_USED 1
define OSC 4
define LCD_DREG PORTD
define LCD_DBIT 0
define LCD_RSREG PORTE
define LCD_RSBIT 0
define LCD_EREG PORTE
define LCD_EBIT 1
define LCD_RWREG PORTE
define LCD_RWBIT 2
define LCD_BITS 4
define LCD_LINES 4
define LCD_COMMANDUS 2000
define LCD_DATAUS 50




ANSEL = %00000000
ANSELH = %00000000
TRISD = %00000000
TRISE = %00000000

TRISB = %11111111
TRISC = %10000000

encoder1_counter var byte
encoder1_LastStateA var bit
encoder1_StateA var bit
encoder2_counter var byte
encoder2_LastStateA var bit
encoder2_StateA var bit
encoder3_counter var byte
encoder3_LastStateA var bit
encoder3_StateA var bit
preset_counter var byte
saved_counter var byte
display_counter var byte
encoder1_pinA var PORTB.7
encoder1_pinB var PORTB.6
encoder2_pinA var PORTB.5
encoder2_pinB var PORTB.4
encoder3_pinA var PORTB.3
encoder3_pinB var PORTB.2
button1 var PORTB.1
button2 var PORTB.0
button3 var PORTC.7

encoder1_preset var byte
encoder2_preset var byte
encoder3_preset var byte

encoder1_counter = 50
encoder2_counter = 50
encoder3_counter = 50
preset_counter = 1
display_counter = 0
saved_counter = 0
encoder1_LastStateA = encoder1_pinA
encoder2_LastStateA = encoder2_pinA
encoder3_LastStateA = encoder3_pinA

pause 500

'=====================MAIN LOOP TO READ INCREMENTAL ROTARY ENCODERS========================
mainloop:

encoder1_StateA = encoder1_pinA ' read first encoder
if encoder1_StateA != encoder1_LastStateA then
if encoder1_pinB != encoder1_StateA then
encoder1_counter = encoder1_counter + 1
else
encoder1_counter = encoder1_counter - 1
endif
encoder1_LastStateA = encoder1_StateA
endif

encoder2_StateA = encoder2_pinA ' read second encoder
if encoder2_StateA != encoder2_LastStateA then
if encoder2_pinB != encoder2_StateA then
encoder2_counter = encoder2_counter + 1
else
encoder2_counter = encoder2_counter - 1
endif
encoder2_LastStateA = encoder2_StateA
endif

encoder3_StateA = encoder3_pinA ' read third encoder
if encoder3_StateA != encoder3_LastStateA then
if encoder3_pinB != encoder3_StateA then
encoder3_counter = encoder3_counter + 1
else
encoder3_counter = encoder3_counter - 1
endif
encoder3_LastStateA = encoder3_StateA
endif

'=====================MAIN LOOP TO RECOGNIZE BUTTON PRESSES==============================

if button1 = 0 then 'when preset down button on encoder1 is pressed
preset_counter = preset_counter - 1
gosub read_preset
pause 25
do until button1 = 1 ' debounce
pause 25
loop
pause 25
endif

if button2 = 0 then 'when save button on encoder2 is pressed
gosub save_preset
pause 25
do until button1 = 1 ' debounce
pause 25
loop
pause 25
endif

if button3 = 0 then 'when preset up button on encoder3 is pressed
preset_counter = preset_counter + 1
gosub read_preset
pause 25
do until button3 = 1 'debounce
pause 25
loop
pause 25
endif

display_counter = display_counter + 1 '200ms delay between LCD updates
pause 1
if display_counter >= 200 then
gosub display
display_counter = 0
endif

goto mainloop
end

read_preset: ' read presets from EEPROM and change values for encoder positions

read preset_counter, encoder1_preset, encoder2_preset, encoder3_preset
pause 25
encoder1_counter = encoder1_preset
encoder2_counter = encoder2_preset
encoder3_counter = encoder3_preset

return

save_preset: 'save encoder positions to EEPROM and display "saved" message

lcdout $fe, 1
lcdout $fe, $c0, " PRESET ", dec2 preset_counter
lcdout $fe, $94, " SAVED"
write preset_counter, encoder1_counter, encoder2_counter, encoder3_counter
pause 1500

return


display: ' LCD display text
lcdout $fe, 1

lcdout $fe, $80, "*****PRESET ", dec2 preset_counter, "******"

lcdout $fe, $94 + 1, "NCDR1"
lcdout $fe, $d4 + , dec encoder1_counter

lcdout $fe, $94 + 8, "NCDR2"
lcdout $fe, $d4 + 9, dec encoder2_counter

lcdout $fe, $94 + 14, "NCDR3"
lcdout $fe, $d4 + 15, dec encoder3_counter
return

keithv
- 16th March 2018, 21:20
You do realize that the WRITE statement is writing to EEPROM and each time it is executed there is a up to 10Ms. delay in the writing process. DEFINE WRITE_INT 1 is to be used when there are active interrupts in your source code. It allows for the command to complete before executing the next statement. I have to ask, why are you writing to eeprom during your rotary encoder decoding?

I want to save the settings on the rotary encoders and be able to recall them as presets. I posted the code for the project.

tumbleweed
- 16th March 2018, 23:28
write preset_counter, encoder1_counter, encoder2_counter, encoder3_counter
Each time you write you're writing three bytes of data, but you're only incrementing the address (preset_counter) by one.
The next time you write you'll be overwriting part of the previously saved data.

When you go to write/read, multiply preset_counter by 4 and use that as the address so the three bytes are preserved.
Make sure preset_counter is never more than 255/4 or the address will wrap since it's a byte value.

keithv
- 16th March 2018, 23:53
Yes! That fixed it. I didn't realize that each data space had its own address. I thought everything in the statement was stored at the designated address.

write 4, 1, 2, 3

So 1 is stored at address 4, 2 is stored at address 5, and 3 is stored at address 6? And then if I want to write something else, it would have to be "write 7, 4, 5, 6" if I didn't want to overwrite the other data? Is that how it works?

tumbleweed
- 17th March 2018, 00:05
Basically, yes, as long as you're talking about bytes.

EEPROM is byte-addressable, and each byte has its own address. Muti-byte variables like words and longs take multiple bytes (addresses) for each value.

keithv
- 17th March 2018, 00:10
Thanks so much!