News:

PROTON pic BASIC Compilers for PIC, PIC24, dsPIC33

Main Menu

4x20 chr LCD with Rotary Encoder for a menu system

Started by Peter Truman, Oct 22, 2024, 05:38 AM

Previous topic - Next topic

Peter Truman

Hi

I'm working on a project which is based on the NHD-0420AZ-FL-YBW-33V3 4 line, 20 chr Monochrome LCD.

This LCD uses the ST7066U controller - the ST7066U controller is not listed in the Positron Manual but my understanding is that this controller is that is compatible with the HD44780 which is listed.

I'm planning on using a 12 pulse per rev Rotary Encoder with the intention of building a scrolling menu system (may maybe 3 levels - more likely 2 levels)

So I have two questions if I may - 1.. does anyone see any issues controlling this display and, 2.. Is there any example code demonstrating how I might go about the menu procedure?

I'm thinking I will group my menu structure as follows

From the lowest level up

Var_1, sub-group_1, group_1
Var_2, sub-group_1, group_1
Var_1, sub-group_1, group_2

and so on.

I'll have this setup in a procedure and pass info such as the group, sub-group and var, along with an associated prompt - that sort of thing.

I'm hoping to be able to scroll through the various groups (probably more than 4 - so I'll need to move each line of the LCD up or down accordingly), press the button in to select the group, then the same procedure to scroll through the sub-groups, then press the button to select the variable of interest.

Can I ask if anyone has any experience of this?

Is there anycode out there that would get me started?

Many thanks in anticipation.

JonW

I did this a few years back and found that a state machine was best for processing the different screens. The rotary switch would update a state machine variable (just a variable), you can jump using a select case on this variable to each screen update case. I used buttons instead of a rotary encoder, and if pressed, the state_machine variable was incremented, and the loop exited; the last menu screen updated the state-machine variable to 0 again, creating a menu loop.  The screen was updated independently in each case statement (or menu screen). 




Stephen Moss

Quote from: Peter Truman on Oct 22, 2024, 05:38 AMThis LCD uses the ST7066U controller - the ST7066U controller is not listed in the Positron Manual but my understanding is that this controller is that is compatible with the HD44780 which is listed.
I have used displays with this controller and can confirm that it worked find for me with the standard Positron LCD commands.

SCV

Get clear in your mind how you will navigate the menu - ie when selecting pages how do you then adjust a parameter...

I have a menu system I use (simple 2x16 display) where the top row is used to title the page with a "<" and ">" at the start and end to highlight you are changing pages. A press of the encoder then changes the "<" and ">" to the bottom row to indicate the variable can be increased or decreased. Pressing the encoder down again reverts back to page selection.

Once you have a simple system running then you can start to refine it. I don't see any advantage to using procedures, keep it simple - debugging can be tricky! I use a common variable in the encoder and load/save the value at the change of a page. I can't show you code as it's written in Pic Basic Pro!

Here is a simple example showing three pages and different ranges of values. Adapt them at will. Once you have it working, then look at streamlining the code.

SYMBOL ENC_A = PORTB.0      'A channel of encoder. Pulled to v+ with 10k resistor. Encoder common is ground
SYMBOL ENC_B = PORTB.1      'B channel of encoder. Pulled to v+ with 10k resistor. Encoder common is ground
SYMBOL ENC_TD = PORTB.2     'Touch down switch of encoder. Pulled to ground with 10k resistor

DIM ENC_VALUE   AS BYTE
DIM MIN_VALUE   AS BYTE
DIM MAX_VALUE   AS BYTE
DIM PAGE        AS BYTE
DIM RED         AS BYTE
DIM GREEN       AS BYTE
DIM BLUE        AS BYTE
DIM EDIT_FLAG   AS BIT
DIM ENC_AL      AS BIT
DIM ENC_BL      AS BIT

INIT:   INPUT ENC_A
        INPUT ENC_B
        INPUT ENC_TD
        ENC_AL = ENC_A      'Store state of encoder
        ENC_BL = ENC_B

        PAGE = 1            'Always start with page 1
        edit_flag = 0       'Page mode at start up

        GOTO load_min_max

'=================================================
MAIN:   'Other stuff happens here...
        GOTO SCAN

'=================================================
SCAN:   IF ENC_A <> ENC_AL THEN
            'Encoder has moved...

            if enc_a <> enc_b then
                'Encoder moving CW
                IF EDIT_FLAG = 0 THEN
                    PAGE = PAGE + 1
                    GOTO LOAD_MIN_MAX
                ELSE
                    IF ENC_VALUE < MAX_VALUE THEN ENC_VALUE = ENC_VALUE + 1
                ENDIF
            ELSE
                IF EDIT_FLAG = 0 THEN
                    PAGE = PAGE - 1
                    GOTO LOAD_MIN_MAX
                ELSE
                    IF ENC_VALUE > MIN_VALUE THEN ENC_VALUE = ENC_VALUE - 1
                ENDIF
            ENDIF

            GOTO MENUS
        ENDIF

        GOTO MAIN

'=================================================
LOAD_MIN_MAX:
        SELECT PAGE
            CASE 1
            'red offset. Valid range 4 to 10
            ENC_VALUE = RED
            MIN_VALUE = 4
            MAX_VALUE = 10


            CASE 2
            ENC_VALUE = GREEN
            MIN_VALUE = 3
            MAX_VALUE = 9

            CASE 3
            ENC_VALUE = BLUE
            MIN_VALUE = 30
            MAX_VALUE = 200

        ENDSELECT


MENUS:  enc_al = enc_a          'Normalise the last state of encoder channels
        enc_bl = enc_b
        BRANCH PAGE, [PAGE_UNDER,_
                      PAGE_1,_
                      PAGE_2,_
                      PAGE_3,_
                      PAGE_OVER]

PAGE_OVER:                      'Roll over to first page
        PAGE = 1
        GOTO LOAD_MIN_MAX

'=================================================
PAGE_UNDER:                     'Roll under to last page
        PAGE = 3
        GOTO LOAD_MIN_MAX

'=================================================
PAGE_1: IF EDIT_FLAG = 1 THEN EDIT_1
        'Print LCD routine
        '[   Red Offset      >]
        '[                    ]
        '[                    ]
        '[      xx            ] where xx is red offset
        'Action routine here...

        GOTO MAIN

EDIT_1:
        'Print LCD routine
        '[   Red Offset       ]
        '[                    ]
        '[                    ]
        '[<     xx           >] where xx is red offset
        'Action routine here...

        GOTO MAIN

'=================================================
PAGE_2: IF EDIT_FLAG = 1 THEN EDIT_2
        'Print LCD routine
        '[<  Green Offset    >]
        '[                    ]
        '[                    ]
        '[      xx            ] where xx is green offset
        'Action routine here...

        GOTO MAIN

EDIT_2:
        'Print LCD routine
        '[   Green Offset     ]
        '[                    ]
        '[                    ]
        '[<     xx           >] where xx is green offset

        GOTO MAIN

'=================================================
PAGE_3: IF EDIT_FLAG = 1 THEN EDIT_3
        'Print LCD routine
        '[<  Blue Offset      ]
        '[                    ]
        '[                    ]
        '[      xx            ] where xx is Blue offset

        GOTO MAIN

EDIT_3:
        'Print LCD routine
        '[   Blue Offset      ]
        '[                    ]
        '[                    ]
        '[<     xx           >] where xx is blue offset

        GOTO MAIN

'=================================================

Peter Truman

Quote from: Stephen Moss on Oct 22, 2024, 08:40 AM
Quote from: Peter Truman on Oct 22, 2024, 05:38 AMThis LCD uses the ST7066U controller - the ST7066U controller is not listed in the Positron Manual but my understanding is that this controller is that is compatible with the HD44780 which is listed.
I have used displays with this controller and can confirm that it worked find for me with the standard Positron LCD commands.

Thanks Stephen - just the reassurance I need, didn't want to commit to having the PCB's made without being sure.

Peter Truman

That really useful SCV, gives me a head-start. Thanks

Peter Truman

Quote from: JonW on Oct 22, 2024, 07:59 AMI did this a few years back and found that a state machine was best for processing the different screens. The rotary switch would update a state machine variable (just a variable), you can jump using a select case on this variable to each screen update case. I used buttons instead of a rotary encoder, and if pressed, the state_machine variable was incremented, and the loop exited; the last menu screen updated the state-machine variable to 0 again, creating a menu loop.  The screen was updated independently in each case statement (or menu screen). 




I've been looking at state machines recently - I know a guy who is a C developer for uC (Way, Way above me) and he is writing the code for a project for which I did the hardware (PIC32 based) - he is writing that as a state machine. He's explained the process, which seems simple enough - but I keep falling back to doing things the way I have always done them (mostly badly  :o when it comes to programming). I've been learning a bit of C programming, but when it comes to actually producing something that must work, I fall back to Positron! (because it makes more sense than C)

JonW

Hi Peter, state machines are not related to C they are just a process.  All you are doing is using a variable to hold a state, (a number).  This number is incremented or decremented from the current state when something happens, ie you change the encoder or push a button. The loop is then exited and re entered checking the state again.

I am currently doing embedded C, not by choice, and it is no different to basic, you still have the same registers, pherpherals, processor, memory etc. In the end every compiler reduces to hex.