Rotary Encoder on 20x4 LCD with pushbutton digit select and other features


Closed Thread
Results 1 to 24 of 24
  1. #1
    Join Date
    Jun 2017
    Posts
    27

    Post Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    '************************************************* ******************************
    ;* Name : PIC16F887.BAS
    ;* Author : CSANTEX
    ;* Date :
    ;* Version : DEFAULT
    ;* Notes :
    '************************************************* ******************************
    ;Max Word count available is 8192. Max EEPROM available is 256 bytes
    ;************************************************* ******************************
    ;This code displays a number that is incremented for clockwise rotation or decremented
    ;for counter-clockwise rotation on a 20x4 LCD. The display has two digits to the
    ;left of the decimal and three digits to the right of the decimal. Each time the
    ;shaft is pushed in, a digit is selected starting from left to right. This code
    ;could be used to display voltages that are preset by a user on a diy power supply
    ;or for Ampere presets or any of the like.
    ;The code is a bit long but it works well.
    ;Does not use interrupts.
    ;Written for use on PIC16F887 but can be modified to fit any PIC microcontroller.
    ;COULD USE SOME OPTIMIZATION!
    ;************************************************* ******************************
    ;************************************************* ******************************
    ' include "PIC16F887.PBPINC" ; processor specific variable definitions
    INCLUDE "Modedefs.Bas"


    @ ERRORLEVEL -306 ; Suppress messages related to Page Boundries.
    ;************************************************* ******************************
    #CONFIG
    __CONFIG _CONFIG1, _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _BOR_ON & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF & _INTOSCIO
    __CONFIG _CONFIG2, _WRT_OFF & _BOR40V
    #ENDCONFIG

    DEFINE OSC 8

    DEFINE LCD_DREG PORTD ' PORTA is LCD data port
    DEFINE LCD_DBIT 4 ' PORTA.4 is the data LSB ( 4 BIT MODE )
    DEFINE LCD_RSREG PORTB ' RS is connected to PORTA.1
    DEFINE LCD_RSBIT 0
    DEFINE LCD_EREG PORTB ' E is connected to PORTA.3
    DEFINE LCD_EBIT 1
    DEFINE LCD_BITS 4 ' 4 lines of data are used (4 BITS)
    DEFINE LCD_LINES 4 ' It is a 4-line display
    DEFINE LCD_COMMANDUS 1500 ' Use 1500uS command delay
    DEFINE LCD_DATAUS 44 ' Use 44uS data delay
    ;************************************************* ******************************
    OSCCON = 10000 ; Set PIC16F88 to 4MHz = 0100000, or 8MHz = 0110000
    TRISA = 11111 ; Port A set to inputs
    TRISB = 01100 ; Port B set to OUTPUTS
    TRISC = 11111 ; Port C set to inputs
    TRISD = 000000 ; Port D set to Ouputs
    PORTD.5 = 0 ; Set output low
    ANSEL = 0000 ; Set all analog pins to digital
    ANSELH = 0000
    ' LED var PortD.7 ; LED for flashing
    A_IN VAR PORTC.6
    B_IN VAR PORTC.5
    SW_IN VAR PORTC.4
    ;************************************************* ******************************
    ONES VAR BYTE ; VARIABLE
    TENS VAR BYTE ; VARIABLE
    HUND VAR BYTE ; VARIABLE
    THOU VAR BYTE ; VARIABLE
    TNTH VAR BYTE ; VARIABLE
    SUBTTL VAR WORD ; VARIABLE
    TOTAL VAR WORD ; TOTAL VALUE
    PLACE VAR BYTE ; VARIABLE


    MYFLAGS VAR BYTE
    ;************************************************* ******************************

    INIT:
    PAUSE 1000
    CLEAR
    PLACE = 6

    ' LCDOUT $FE, $C0, DEC PLACE ;FOR DEBUG ONLY
    ' LCDOUT $FE, $94, DEC5 (TNTH*10000)+(THOU*1000)+(HUND*100)+(TENS*10)+ONES ;FOR DEBUG ONLY

    LCDOUT $FE, $D4, DEC1 TNTH, DEC1 THOU, ".", DEC1 HUND, DEC1 TENS, DEC1 ONES

    ;************************************************* ******************************
    MAIN:
    IF A_IN < B_IN THEN
    IF PLACE = 6 AND TOTAL < 10000 THEN
    IF MYFLAGS.0 = 0 THEN
    ONES = ONES + 1
    IF ONES > 9 THEN
    ONES = 0
    TENS = TENS + 1
    ENDIF
    IF TENS > 9 THEN
    TENS = 0
    HUND = HUND + 1
    ENDIF
    IF HUND > 9 THEN
    HUND = 0
    THOU = THOU + 1
    ENDIF
    IF THOU > 9 THEN
    THOU = 0
    TNTH = TNTH + 1
    ENDIF
    IF TNTH > 1 THEN THOU = 0
    GOSUB SHOW_TOTAL
    ENDIF
    ENDIF
    IF MYFLAGS.0 = 1 THEN
    IF TNTH = 0 THEN
    IF PLACE = 5 THEN
    ONES = ONES + 1
    IF ONES > 9 THEN ONES = 0
    GOSUB SHOW_ONES
    ENDIF
    IF PLACE = 4 THEN
    TENS = TENS + 1
    IF TENS > 9 THEN TENS = 0
    GOSUB SHOW_TENS
    ENDIF
    IF PLACE = 3 THEN
    HUND = HUND + 1
    IF HUND > 9 THEN HUND = 0
    GOSUB SHOW_HUND
    ENDIF
    IF PLACE = 1 THEN
    THOU = THOU + 1
    IF THOU > 9 THEN THOU = 0
    GOSUB SHOW_THOU
    ENDIF
    ENDIF
    IF SUBTTL = 0 THEN
    IF PLACE = 0 THEN
    TNTH = TNTH + 1
    IF TNTH > 1 THEN TNTH = 0
    GOSUB SHOW_TNTH
    GOTO PUSHBUTTON
    ENDIF
    ENDIF
    ENDIF
    GOSUB SUM_TOTALS
    IF TOTAL = 10000 THEN
    LCDOUT $FE, $0C ;BLINK OFF
    LCDOUT $FE, $80, "MAXIMUM LIMIT"
    PAUSE 1000
    LCDOUT $FE, $80, " "
    ENDIF
    ENDIF

    PUSHBUTTON:
    IF SW_IN = 0 THEN
    PLACE = PLACE + 1
    IF PLACE = 2 THEN PLACE = 3
    IF PLACE > 6 THEN PLACE = 0
    ' LCDOUT $FE, $C0, DEC PLACE ;FOR DEBUG ONLY
    LCDOUT $FE, $D4+PLACE

    IF PLACE = 6 THEN
    LCDOUT $FE, $0C ;BLINK OFF
    MYFLAGS.0 = 0
    ELSE
    LCDOUT $FE, $0F
    LCDOUT $FE, $D4+PLACE
    MYFLAGS.0 = 1
    ENDIF

    GOSUB DEBOUNCE ;DO NOTHING WHILE WE WAIT TO RELEASE THE BUTTON.
    ENDIF
    GOSUB SUM_TOTALS
    IF PLACE != 6 THEN
    LCDOUT $FE, $0F
    LCDOUT $FE, $D4+PLACE
    ' MYFLAGS.0 = 1
    ENDIF


    DECREMENT:
    IF B_IN < A_IN THEN
    IF PLACE = 6 AND TOTAL > 0 THEN
    IF MYFLAGS.0 = 0 THEN
    ONES = ONES - 1
    IF ONES > 9 THEN
    ONES = 9
    TENS = TENS - 1
    ENDIF
    IF TENS > 9 THEN
    TENS = 9
    HUND = HUND - 1
    ENDIF
    IF HUND > 9 THEN
    HUND = 9
    THOU = THOU - 1
    ENDIF
    IF THOU > 9 THEN
    THOU = 9
    TNTH = TNTH - 1
    ENDIF
    IF TNTH > 1 THEN THOU = 0
    GOSUB SHOW_TOTAL
    ENDIF
    ENDIF
    IF MYFLAGS.0 = 1 THEN
    IF TNTH = 0 THEN
    IF PLACE = 5 THEN
    ONES = ONES - 1
    IF ONES > 9 THEN ONES = 9
    GOSUB SHOW_ONES
    GOTO MAIN
    ENDIF
    IF PLACE = 4 THEN
    TENS = TENS - 1
    IF TENS > 9 THEN TENS = 9
    GOSUB SHOW_TENS
    GOTO MAIN
    ENDIF
    IF PLACE = 3 THEN
    HUND = HUND - 1
    IF HUND > 9 THEN HUND = 9
    GOSUB SHOW_HUND
    GOTO MAIN
    ENDIF
    IF PLACE = 1 THEN
    THOU = THOU - 1
    IF THOU > 9 THEN THOU = 9
    GOSUB SHOW_THOU
    GOTO MAIN
    ENDIF
    ENDIF
    IF SUBTTL = 0 THEN
    IF PLACE = 0 THEN
    TNTH = TNTH - 1
    IF TNTH > 1 THEN TNTH = 1
    GOSUB SHOW_TNTH
    GOTO MAIN
    ENDIF
    ENDIF
    ENDIF
    GOSUB SUM_TOTALS
    IF TOTAL = 0 THEN
    LCDOUT $FE, $0C ;BLINK OFF
    LCDOUT $FE, $80, "MINIMUM LIMIT"
    PAUSE 1000
    LCDOUT $FE, $80, " "
    ENDIF
    ENDIF
    GOTO MAIN

    SHOW_TOTAL:
    ' LCDOUT $FE, $94, DEC5 (TNTH*10000)+(THOU*1000)+(HUND*100)+(TENS*10)+ONES ;FOR DEBUG ONLY
    LCDOUT $FE, $D4, DEC1 TNTH, DEC1 THOU, ".", DEC1 HUND, DEC1 TENS, DEC1 ONES


    DEBOUNCE:
    WHILE A_IN=0 OR B_IN=0 OR SW_IN=0 ;DO NOTHING WHILE WE WAIT TO RELEASE THE BUTTON.
    WEND
    RETURN


    ;************************************************* ******************************
    SHOW_TNTH:
    LCDOUT $FE, $0C ;BLINK OFF
    LCDOUT $FE, $D4, DEC1 TNTH
    LCDOUT $FE, $D4
    LCDOUT $FE, $0F ;BLINK ON
    GOSUB DEBOUNCE ;DO NOTHING WHILE WE WAIT TO RELEASE THE BUTTON.
    RETURN
    SHOW_THOU:
    LCDOUT $FE, $0C ;BLINK OFF
    LCDOUT $FE, $D5, DEC1 THOU
    LCDOUT $FE, $D5
    LCDOUT $FE, $0F
    GOSUB DEBOUNCE ;DO NOTHING WHILE WE WAIT TO RELEASE THE BUTTON.
    RETURN
    SHOW_HUND:
    LCDOUT $FE, $0C ;BLINK OFF
    LCDOUT $FE, $D7, DEC1 HUND
    LCDOUT $FE, $D7
    LCDOUT $FE, $0F
    GOSUB DEBOUNCE ;DO NOTHING WHILE WE WAIT TO RELEASE THE BUTTON.
    RETURN
    SHOW_TENS:
    LCDOUT $FE, $0C ;BLINK OFF
    LCDOUT $FE, $D8, DEC1 TENS
    LCDOUT $FE, $D8
    LCDOUT $FE, $0F
    GOSUB DEBOUNCE ;DO NOTHING WHILE WE WAIT TO RELEASE THE BUTTON.
    RETURN
    SHOW_ONES:
    LCDOUT $FE, $0C ;BLINK OFF
    LCDOUT $FE, $D9, DEC1 ONES
    LCDOUT $FE, $D9
    LCDOUT $FE, $0F
    GOSUB DEBOUNCE ;DO NOTHING WHILE WE WAIT TO RELEASE THE BUTTON.
    RETURN
    SUM_TOTALS:
    TOTAL = (TNTH*10000)+(THOU*1000)+(HUND*100)+(TENS*10)+ONES
    SUBTTL = (THOU*1000)+(HUND*100)+(TENS*10)+ONES
    RETURN
    ;************************************************* ******************************

    ;************************************************* ******************************
    END

  2. #2
    Join Date
    Jun 2017
    Posts
    27


    Did you find this post helpful? Yes | No

    Default Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    First post is obviously mislabeled since it didn't come out right but here it is the way it is supposed to be. Hopefully...

    Code:
    '*******************************************************************************
    ;*  Name    : PIC16F887.BAS                                    
    ;*  Author  : CSANTEX                                 
    ;*  Date    :                                  
    ;*  Version : DEFAULT                                               
    ;*  Notes   :
    '*******************************************************************************
    ;Max Word count available is 8192.  Max EEPROM available is 256 bytes
    ;*******************************************************************************
    ;This code displays a number that is incremented for clockwise rotation or decrements
    ;for counter-clockwise rotation on a 20x4 LCD.  The display has two digits to the
    ;left of the decimal and three digits to the right of the decimal.  Each time the
    ;shaft is pushed in, a digit is selected starting from left to right.  This code
    ;could be used to display voltages that are preset by a user on a diy power supply
    ;or for Ampere presets or any of the like.
    ;The code is a bit long but it works well.
    ;***This work was derrived from the thread "New Approach to Rotary Encoder", based on sample code
    ;submitted by Ioannis
    ;COULD USE SOME OPTIMIZATION!
    ;*******************************************************************************
    ;*******************************************************************************
    '	include	"PIC16F887.PBPINC"	; processor specific variable definitions
        INCLUDE "Modedefs.Bas" 
    
        @ ERRORLEVEL -306   ; Suppress messages related to Page Boundries.
    ;*******************************************************************************
        #CONFIG
    	__CONFIG    _CONFIG1, _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _BOR_ON & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF & _INTOSCIO 
    	__CONFIG    _CONFIG2, _WRT_OFF & _BOR40V
    	#ENDCONFIG
    	
        DEFINE OSC 8
           
        DEFINE LCD_DREG PORTD  ' PORTA is LCD data port 
        DEFINE LCD_DBIT 4  ' PORTA.4 is the data LSB ( 4 BIT MODE ) 
        DEFINE LCD_RSREG PORTB  ' RS is connected to PORTA.1 
        DEFINE LCD_RSBIT 0 
        DEFINE LCD_EREG PORTB  ' E is connected to PORTA.3
        DEFINE LCD_EBIT 1 
        DEFINE LCD_BITS 4  ' 4 lines of data are used (4 BITS)
        DEFINE LCD_LINES 4  ' It is a 4-line display 
        DEFINE LCD_COMMANDUS 1500 ' Use 1500uS command delay 
        DEFINE LCD_DATAUS 44   ' Use 44uS data delay
    ;*******************************************************************************
        OSCCON  = %01110000     ; Set PIC16F88 to 4MHz = %01100000, or
                                ; 8MHz = %01110000
        TRISA   = %11111111     ; Port A set to inputs
        TRISB   = %11101100     ; Port B set to OUTPUTS
        TRISC   = %01111111     ; Port C set to inputs
        TRISD   = %00000000     ; Port D set to Ouputs
        PORTD.5 = 0             ; Set output low
        ANSEL   = %00000000     ; Set all analog pins to digital
        ANSELH  = %00000000
    '    LED            var     PortD.7      ; LED for flashing
        A_IN           VAR     PORTC.6
        B_IN           VAR     PORTC.5
        SW_IN          VAR     PORTC.4
    ;*******************************************************************************
        ONES            VAR BYTE    ; VARIABLE
        TENS            VAR BYTE    ; VARIABLE
        HUND            VAR BYTE    ; VARIABLE
        THOU            VAR BYTE    ; VARIABLE
        TNTH            VAR BYTE    ; VARIABLE
        SUBTTL          VAR WORD    ; VARIABLE
        TOTAL           VAR WORD    ; TOTAL VALUE
        PLACE           VAR BYTE    ; VARIABLE
    
        MYFLAGS         VAR BYTE
    ;*******************************************************************************
    ;*******************************************************************************
    ;*******************************************************************************
    ;*******************************************************************************        
    ;*******************************************************************************
    ;*******************************************************************************
    ;*******************************************************************************
    ;******************************************************************************* 
    INIT: 
        PAUSE 1000
        CLEAR
        PLACE = 6    
    '    LCDOUT $FE, $C0, DEC PLACE    ;FOR DEBUG ONLY
    '    LCDOUT $FE, $94, DEC5 (TNTH*10000)+(THOU*1000)+(HUND*100)+(TENS*10)+ONES   ;FOR DEBUG ONLY
        LCDOUT $FE, $D4, DEC1 TNTH, DEC1 THOU, ".", DEC1 HUND, DEC1 TENS, DEC1 ONES
    
    
    MAIN:
        IF A_IN < B_IN THEN
            IF PLACE = 6 AND TOTAL < 10000 THEN
                IF MYFLAGS.0 = 0 THEN 
                    ONES = ONES + 1
                    IF ONES > 9 THEN 
                        ONES = 0
                        TENS = TENS + 1 
                    ENDIF                    
                    IF TENS > 9 THEN 
                        TENS = 0
                        HUND = HUND + 1 
                    ENDIF                        
                    IF HUND > 9 THEN
                        HUND = 0
                        THOU = THOU + 1 
                    ENDIF 
                    IF THOU > 9 THEN
                        THOU = 0
                        TNTH = TNTH + 1 
                    ENDIF                           
                    IF TNTH > 1 THEN THOU = 0 
                    GOSUB SHOW_TOTAL 
                ENDIF 
            ENDIF
            IF MYFLAGS.0 = 1 THEN
                IF TNTH = 0 THEN 
                    IF PLACE = 5 THEN  
                        ONES = ONES + 1
                        IF ONES > 9 THEN ONES = 0
                        GOSUB SHOW_ONES
                    ENDIF    
                    IF PLACE = 4 THEN 
                        TENS = TENS + 1
                        IF TENS > 9 THEN TENS = 0
                        GOSUB SHOW_TENS
                    ENDIF    
                    IF PLACE = 3 THEN  
                        HUND = HUND + 1
                        IF HUND > 9 THEN HUND = 0 
                        GOSUB SHOW_HUND
                    ENDIF    
                    IF PLACE = 1 THEN  
                        THOU = THOU + 1
                        IF THOU > 9 THEN THOU = 0
                        GOSUB SHOW_THOU
                    ENDIF
                ENDIF
                IF SUBTTL = 0 THEN     
                    IF PLACE = 0 THEN
                        TNTH = TNTH + 1
                        IF TNTH > 1 THEN TNTH = 0
                        GOSUB SHOW_TNTH
                        GOTO PUSHBUTTON
                    ENDIF
                ENDIF
            ENDIF    
            GOSUB SUM_TOTALS
            IF TOTAL = 10000 THEN 
                LCDOUT $FE, $0C  ;BLINK OFF
                LCDOUT $FE, $80, "MAXIMUM LIMIT"
                PAUSE 1000
                LCDOUT $FE, $80, "             "
            ENDIF        
        ENDIF 
        
    PUSHBUTTON:
        IF SW_IN = 0 THEN 
            PLACE = PLACE + 1
            IF PLACE = 2 THEN PLACE = 3 
            IF PLACE > 6 THEN PLACE = 0 
    '        LCDOUT $FE, $C0, DEC PLACE    ;FOR DEBUG ONLY
            LCDOUT $FE, $D4+PLACE
            
            IF PLACE = 6 THEN 
                LCDOUT $FE, $0C  ;BLINK OFF
                MYFLAGS.0 = 0
            ELSE
                LCDOUT $FE, $0F
                LCDOUT $FE, $D4+PLACE
                MYFLAGS.0 = 1
            ENDIF  
                   
            GOSUB DEBOUNCE  ;DO NOTHING WHILE WE WAIT TO RELEASE THE BUTTON.         
        ENDIF
        GOSUB SUM_TOTALS        
        IF PLACE != 6 THEN  
            LCDOUT $FE, $0F
            LCDOUT $FE, $D4+PLACE
    '        MYFLAGS.0 = 1
        ENDIF  
    
    DECREMENT:
        IF B_IN < A_IN THEN 
            IF PLACE = 6 AND TOTAL > 0 THEN
                IF MYFLAGS.0 = 0 THEN
                    ONES = ONES - 1   
                    IF ONES > 9 THEN 
                        ONES = 9  
                        TENS = TENS - 1
                    ENDIF
                    IF TENS > 9 THEN 
                        TENS = 9                     
                        HUND = HUND - 1 
                    ENDIF             
                    IF HUND > 9 THEN 
                        HUND = 9                  
                        THOU = THOU - 1 
                    ENDIF      
                    IF THOU > 9 THEN 
                        THOU = 9
                        TNTH = TNTH - 1
                    ENDIF
                    IF TNTH > 1 THEN THOU = 0  
                    GOSUB SHOW_TOTAL 
                ENDIF
            ENDIF
            IF MYFLAGS.0 = 1 THEN
                IF TNTH = 0 THEN 
                    IF PLACE = 5 THEN  
                        ONES = ONES - 1
                        IF ONES > 9 THEN ONES = 9
                        GOSUB SHOW_ONES
                        GOTO MAIN
                    ENDIF      
                    IF PLACE = 4 THEN  
                        TENS = TENS - 1
                        IF TENS > 9 THEN TENS = 9 
                        GOSUB SHOW_TENS
                        GOTO MAIN
                    ENDIF    
                    IF PLACE = 3 THEN  
                        HUND = HUND - 1
                        IF HUND > 9 THEN HUND = 9
                        GOSUB SHOW_HUND
                        GOTO MAIN
                    ENDIF    
                    IF PLACE = 1 THEN  
                        THOU = THOU - 1
                        IF THOU > 9 THEN THOU = 9
                        GOSUB SHOW_THOU
                        GOTO MAIN
                    ENDIF
                ENDIF 
                IF SUBTTL = 0 THEN       
                    IF PLACE = 0 THEN
                        TNTH = TNTH - 1
                        IF TNTH > 1 THEN TNTH = 1
                        GOSUB SHOW_TNTH
                        GOTO MAIN
                    ENDIF
                ENDIF
            ENDIF  
            GOSUB SUM_TOTALS
            IF TOTAL = 0 THEN 
                LCDOUT $FE, $0C  ;BLINK OFF
                LCDOUT $FE, $80, "MINIMUM LIMIT"
                PAUSE 1000
                LCDOUT $FE, $80, "             "
            ENDIF     
        ENDIF 
        GOTO MAIN
        
    SHOW_TOTAL: 
    '    LCDOUT $FE, $94, DEC5 (TNTH*10000)+(THOU*1000)+(HUND*100)+(TENS*10)+ONES    ;FOR DEBUG ONLY
        LCDOUT $FE, $D4, DEC1 TNTH, DEC1 THOU, ".", DEC1 HUND, DEC1 TENS, DEC1 ONES     
    
    DEBOUNCE:    
        WHILE A_IN=0 OR B_IN=0 OR SW_IN=0   ;DO NOTHING WHILE WE WAIT TO RELEASE THE BUTTON.
        WEND
        RETURN 
    
    ;******************************************************************************* 
    SHOW_TNTH:
        LCDOUT $FE, $0C ;BLINK OFF
        LCDOUT $FE, $D4, DEC1 TNTH
        LCDOUT $FE, $D4
        LCDOUT $FE, $0F ;BLINK ON
        GOSUB DEBOUNCE  ;DO NOTHING WHILE WE WAIT TO RELEASE THE BUTTON.
        RETURN
    SHOW_THOU:
        LCDOUT $FE, $0C ;BLINK OFF
        LCDOUT $FE, $D5, DEC1 THOU
        LCDOUT $FE, $D5
        LCDOUT $FE, $0F
        GOSUB DEBOUNCE  ;DO NOTHING WHILE WE WAIT TO RELEASE THE BUTTON.
        RETURN
    SHOW_HUND:
        LCDOUT $FE, $0C ;BLINK OFF
        LCDOUT $FE, $D7, DEC1 HUND
        LCDOUT $FE, $D7
        LCDOUT $FE, $0F
        GOSUB DEBOUNCE  ;DO NOTHING WHILE WE WAIT TO RELEASE THE BUTTON.
        RETURN
    SHOW_TENS:
        LCDOUT $FE, $0C ;BLINK OFF
        LCDOUT $FE, $D8, DEC1 TENS
        LCDOUT $FE, $D8
        LCDOUT $FE, $0F
        GOSUB DEBOUNCE  ;DO NOTHING WHILE WE WAIT TO RELEASE THE BUTTON.
        RETURN
    SHOW_ONES:
        LCDOUT $FE, $0C ;BLINK OFF
        LCDOUT $FE, $D9, DEC1 ONES
        LCDOUT $FE, $D9
        LCDOUT $FE, $0F
        GOSUB DEBOUNCE  ;DO NOTHING WHILE WE WAIT TO RELEASE THE BUTTON.
        RETURN
    SUM_TOTALS:
        TOTAL = (TNTH*10000)+(THOU*1000)+(HUND*100)+(TENS*10)+ONES
        SUBTTL = (THOU*1000)+(HUND*100)+(TENS*10)+ONES
        RETURN
    ;******************************************************************************* 
      
    ;*******************************************************************************
        END
    Last edited by csantex; - 7th February 2018 at 03:06.

  3. #3
    Join Date
    Jun 2017
    Posts
    27


    Did you find this post helpful? Yes | No

    Post Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    The previous post was an attempt to write code for a rotary encoder that would allow the user to increment or decrement the value displayed by a factor of 1, on a 20x4 LCD. The range was set for 00.000 to 10.000. With the push of the shaft button on the rotary encoder, the user could select any of the 4 least significant digits to change their value from 0 to 9 individually. The most significant digit could only be set to 1 or 0, depending on the value of the least 4. If the least 4 were set to all zeros, then the 5th digit could be set to 1.

    This next version accomplishes the same results with what I thought would be more efficient code. As it turns out, the original code uses 1549 words if you delete the command to clear PortD.5. It is not used nor necessary. The 2nd version does use less written code from the user but in turn, uses more words in memory than the original. 1572 words total to be exact. I have noticed and increase in word count at the time of compiling in other projects as well. I have come to the conclusion that using only "IF" statements uses less program memory.

    I believe this code to be reliable and beneficial to anyone needing the features it provides to the user. I know there is more efficient code out there. I'm not proficient in programming like others who have been doing this for a long time so I leave it to this forum to evaluate and critique it for everyone's gain. If anyone can make use of this code or learn from it, then my task is complete for I have learned from it as well.

    Please enjoy the code.
    New code below,

    csantex

    Code:
    '*******************************************************************************
    ;*  Name    : PIC16F887.BAS                                    
    ;*  Author  : CSANTEX                                   
    ;*  Notice  : Copyright (c) 2018                                
    ;*          : All Rights Reserved                               
    ;*  Date    :                                  
    ;*  Version : Version 2                                               
    ;*  Notes   :
    '*******************************************************************************
    ;Max Word count available is 8192.  Max EEPROM available is 256 bytes
    ;*******************************************************************************
    ;This code displays a number that is incremented for clockwise rotation or decrements
    ;for counter-clockwise rotation on a 20x4 LCD.  The display has two digits to the
    ;left of the decimal and three digits to the right of the decimal.  Each time the
    ;shaft is pushed in, a digit is selected starting from left to right.  This code
    ;could be used to display voltages that are preset by a user on a diy power supply
    ;or for Ampere presets or any of the like.
    ;The code is a bit long but it works well.
    
    ;COULD USE MORE OPTIMIZATION!
    
    ;Original workd count=1549
    ;V2 word count =1572
    ;*******************************************************************************
    ;*******************************************************************************
    '	include	"PIC16F887.PBPINC"	; processor specific variable definitions
        INCLUDE "Modedefs.Bas" 
    
        @ ERRORLEVEL -306   ; Suppress messages related to Page Boundries.
    ;*******************************************************************************
        #CONFIG
    	__CONFIG    _CONFIG1, _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _BOR_ON & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF & _INTOSCIO 
    	__CONFIG    _CONFIG2, _WRT_OFF & _BOR40V
    	#ENDCONFIG
    	
        DEFINE OSC 8
           
        DEFINE LCD_DREG PORTD  ' PORTA is LCD data port 
        DEFINE LCD_DBIT 4  ' PORTA.4 is the data LSB ( 4 BIT MODE ) 
        DEFINE LCD_RSREG PORTB  ' RS is connected to PORTA.1 
        DEFINE LCD_RSBIT 0 
        DEFINE LCD_EREG PORTB  ' E is connected to PORTA.3
        DEFINE LCD_EBIT 1 
        DEFINE LCD_BITS 4  ' 4 lines of data are used (4 BITS)
        DEFINE LCD_LINES 4  ' It is a 4-line display 
        DEFINE LCD_COMMANDUS 1500 ' Use 1500uS command delay 
        DEFINE LCD_DATAUS 44   ' Use 44uS data delay
    ;*******************************************************************************
        OSCCON  = %01110000     ; Set PIC16F88 to 4MHz = %01100000, or
                                ; 8MHz = %01110000
        TRISA   = %11111111     ; Port A set to inputs
        TRISB   = %11101100     ; Port B set to OUTPUTS
        TRISC   = %01111111     ; Port C set to inputs
        TRISD   = %00000000     ; Port D set to Ouputs
        ANSEL   = %00000000     ; Set all analog pins to digital
        ANSELH  = %00000000
    '    LED            var     PortD.7      ; LED for flashing
        A_IN           VAR     PORTC.6
        B_IN           VAR     PORTC.5
        SW_IN          VAR     PORTC.4
    ;*******************************************************************************
        ONES            VAR BYTE    ; VARIABLE
        TENS            VAR BYTE    ; VARIABLE
        HUND            VAR BYTE    ; VARIABLE
        THOU            VAR BYTE    ; VARIABLE
        TNTH            VAR BYTE    ; VARIABLE
        SUBTTL          VAR WORD    ; VARIABLE
        TOTAL           VAR WORD    ; TOTAL VALUE
        PLACE           VAR BYTE    ; VARIABLE
    
        MYFLAGS         VAR BYTE
    ;*******************************************************************************
    ;*******************************************************************************
    ;*******************************************************************************
    ;*******************************************************************************        
    ;*******************************************************************************
    ;*******************************************************************************
    ;*******************************************************************************
    ;******************************************************************************* 
    INIT: 
        PAUSE 1000
        CLEAR
        PLACE = 6    
    
    '    LCDOUT $FE, $C0, DEC PLACE    ;FOR DEBUG ONLY
    '    LCDOUT $FE, $94, DEC5 (TNTH*10000)+(THOU*1000)+(HUND*100)+(TENS*10)+ONES   ;FOR DEBUG ONLY
    
        LCDOUT $FE, $D4, DEC1 TNTH, DEC1 THOU, ".", DEC1 HUND, DEC1 TENS, DEC1 ONES
    
    
    MAIN:
        IF A_IN < B_IN THEN
            IF PLACE = 6 AND TOTAL < 10000 THEN
                IF MYFLAGS.0 = 0 THEN 
                    TOTAL = TOTAL + 1
                    ONES = TOTAL DIG 0
                    TENS = TOTAL DIG 1
                    HUND = TOTAL DIG 2
                    THOU = TOTAL DIG 3
                    TNTH = TOTAL DIG 4
                    GOSUB SHOW_TOTAL 
                ENDIF 
            ENDIF
            IF MYFLAGS.0 = 1 THEN
                IF TNTH = 0 THEN 
                    SELECT CASE PLACE
                        CASE 5
                            ONES = ONES + 1
                            IF ONES > 9 THEN ONES = 0
                            GOSUB SHOW_ONES
                        CASE 4
                            TENS = TENS + 1
                            IF TENS > 9 THEN TENS = 0 
                            GOSUB SHOW_TENS
                        CASE 3
                            HUND = HUND + 1
                            IF HUND > 9 THEN HUND = 0
                            GOSUB SHOW_HUND
                        CASE 1
                            THOU = THOU + 1
                            IF THOU > 9 THEN THOU = 0
                            GOSUB SHOW_THOU
                    END SELECT
                ENDIF
                IF SUBTTL = 0 THEN     
                    IF PLACE = 0 THEN
                        TNTH = TNTH + 1
                        IF TNTH > 1 THEN TNTH = 0
                        GOSUB SHOW_TNTH
                        GOTO PUSHBUTTON
                    ENDIF
                ENDIF 
            ENDIF   
            GOSUB SUM_TOTALS
            IF TOTAL = 10000 THEN 
                LCDOUT $FE, $0C  ;BLINK OFF
                LCDOUT $FE, $80, "MAXIMUM LIMIT"
                PAUSE 1000
                LCDOUT $FE, $80, "             "
            ENDIF        
        ENDIF 
        
    PUSHBUTTON:
        IF SW_IN = 0 THEN 
            PLACE = PLACE + 1
            IF PLACE = 2 THEN PLACE = 3 
            IF PLACE > 6 THEN PLACE = 0 
            LCDOUT $FE, $D4+PLACE
            
            IF PLACE = 6 THEN 
                LCDOUT $FE, $0C  ;BLINK OFF
                MYFLAGS.0 = 0
            ELSE
                LCDOUT $FE, $0F
                LCDOUT $FE, $D4+PLACE
                MYFLAGS.0 = 1
            ENDIF  
                   
            GOSUB DEBOUNCE  ;DO NOTHING WHILE WE WAIT TO RELEASE THE BUTTON.         
        ENDIF
        GOSUB SUM_TOTALS        
        IF PLACE != 6 THEN  
            LCDOUT $FE, $0F
            LCDOUT $FE, $D4+PLACE
        ENDIF  
    
    DECREMENT:
        IF B_IN < A_IN THEN 
            IF PLACE = 6 AND TOTAL > 0 THEN
                IF MYFLAGS.0 = 0 THEN
                    TOTAL = TOTAL - 1
                    ONES = TOTAL DIG 0
                    TENS = TOTAL DIG 1
                    HUND = TOTAL DIG 2
                    THOU = TOTAL DIG 3
                    TNTH = TOTAL DIG 4 
                    GOSUB SHOW_TOTAL 
                ENDIF
            ENDIF
            IF MYFLAGS.0 = 1 THEN
                IF TNTH = 0 THEN 
                    SELECT CASE PLACE
                        CASE 5
                            ONES = ONES - 1
                            IF ONES > 9 THEN ONES = 9
                            GOSUB SHOW_ONES
                            GOTO MAIN
                        CASE 4
                            TENS = TENS - 1
                            IF TENS > 9 THEN TENS = 9 
                            GOSUB SHOW_TENS
                            GOTO MAIN
                        CASE 3
                            HUND = HUND - 1
                            IF HUND > 9 THEN HUND = 9
                            GOSUB SHOW_HUND
                            GOTO MAIN
                        CASE 1
                            THOU = THOU - 1
                            IF THOU > 9 THEN THOU = 9
                            GOSUB SHOW_THOU
                            GOTO MAIN
                    END SELECT
                ENDIF 
                IF SUBTTL = 0 THEN       
                    IF PLACE = 0 THEN
                        TNTH = TNTH - 1
                        IF TNTH > 1 THEN TNTH = 1
                        GOSUB SHOW_TNTH
                        GOTO MAIN
                    ENDIF
                ENDIF 
            ENDIF
            GOSUB SUM_TOTALS
            IF TOTAL = 0 THEN 
                LCDOUT $FE, $0C  ;BLINK OFF
                LCDOUT $FE, $80, "MINIMUM LIMIT"
                PAUSE 1000
                LCDOUT $FE, $80, "             "
            ENDIF     
        ENDIF 
        GOTO MAIN
        
    SHOW_TOTAL: 
    '    LCDOUT $FE, $94, DEC5 (TNTH*10000)+(THOU*1000)+(HUND*100)+(TENS*10)+ONES    ;FOR DEBUG ONLY
    
        LCDOUT $FE, $D4, DEC1 TNTH, DEC1 THOU, ".", DEC1 HUND, DEC1 TENS, DEC1 ONES     
    
    DEBOUNCE:    
        WHILE A_IN=0 OR B_IN=0 OR SW_IN=0   ;DO NOTHING WHILE WE WAIT TO RELEASE THE BUTTON.
        WEND
        RETURN 
    
    ;******************************************************************************* 
    SHOW_TNTH:
        LCDOUT $FE, $0C ;BLINK OFF
        LCDOUT $FE, $D4, DEC1 TNTH
        LCDOUT $FE, $D4
        LCDOUT $FE, $0F ;BLINK ON
        GOSUB DEBOUNCE  ;DO NOTHING WHILE WE WAIT TO RELEASE THE BUTTON.
        RETURN
    SHOW_THOU:
        LCDOUT $FE, $0C ;BLINK OFF
        LCDOUT $FE, $D5, DEC1 THOU
        LCDOUT $FE, $D5
        LCDOUT $FE, $0F
        GOSUB DEBOUNCE  ;DO NOTHING WHILE WE WAIT TO RELEASE THE BUTTON.
        RETURN
    SHOW_HUND:
        LCDOUT $FE, $0C ;BLINK OFF
        LCDOUT $FE, $D7, DEC1 HUND
        LCDOUT $FE, $D7
        LCDOUT $FE, $0F
        GOSUB DEBOUNCE  ;DO NOTHING WHILE WE WAIT TO RELEASE THE BUTTON.
        RETURN
    SHOW_TENS:
        LCDOUT $FE, $0C ;BLINK OFF
        LCDOUT $FE, $D8, DEC1 TENS
        LCDOUT $FE, $D8
        LCDOUT $FE, $0F
        GOSUB DEBOUNCE  ;DO NOTHING WHILE WE WAIT TO RELEASE THE BUTTON.
        RETURN
    SHOW_ONES:
        LCDOUT $FE, $0C ;BLINK OFF
        LCDOUT $FE, $D9, DEC1 ONES
        LCDOUT $FE, $D9
        LCDOUT $FE, $0F
        GOSUB DEBOUNCE  ;DO NOTHING WHILE WE WAIT TO RELEASE THE BUTTON.
        RETURN
    SUM_TOTALS:
        TOTAL = (TNTH*10000)+(THOU*1000)+(HUND*100)+(TENS*10)+ONES
        SUBTTL = (THOU*1000)+(HUND*100)+(TENS*10)+ONES
        RETURN
    ;******************************************************************************* 
      
    ;*******************************************************************************
        END

  4. #4
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    3,795


    Did you find this post helpful? Yes | No

    Default Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    Good example csantex. Thanks for posting.

    Ioannis

  5. #5
    Join Date
    Jun 2017
    Posts
    27


    Did you find this post helpful? Yes | No

    Default Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    Thanks Ioannis, after all, it was your idea that started this little venture.

  6. #6
    Join Date
    May 2013
    Location
    australia
    Posts
    2,380


    Did you find this post helpful? Yes | No

    Default Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    if you do it more algorithmically the size can be reduced dramatically ,it becomes scalable digit wise

    more functions can easily be added and the mcu can be employed to perform a real task like pid control of a power supply and not just become a display controller


    ps note my lcd defines suite my setup and are different

    Code:
    '****************************************************************
    '*  Name    : LCD_TEST.BAS                                      *
    '*  Author  : RICHARD                                           *
    '           
    '*  Date    : 4/8/2017                                          *
    '*  Version : 1.0                                               *
    '*  Notes   :                                      *
    '*          :       16f887                                   *
    '****************************************************************
     
    
        #CONFIG
     __CONFIG    _CONFIG1, _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _BOR_ON & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF & _INTOSCIO 
     __CONFIG    _CONFIG2, _WRT_OFF & _BOR40V
     #ENDCONFIG
     
        DEFINE OSC 8
    
        
    'LCD defines begin here   
        DEFINE LCD_BITS 4  'defines the number of data interface lines (4 or 8) 
        DEFINE LCD_DREG PORTB 'defines the port where data lines are connected to
        DEFINE LCD_DBIT 0  'defines the position of data lines for 4-bit interface (0 or 4)
        DEFINE LCD_RSREG PORTB 'defines the port where RS line is connected to
        DEFINE LCD_RSBIT 4  'defines the pin where RS line is connected to 
        DEFINE LCD_EREG PORTB  'defines the port where E line is connected to 
        DEFINE LCD_EBIT 5  'defines the pin where E line is connected 
        DEFINE LCD_COMMANDUS 1500  'defines the delay after LCDOUT statement 
        DEFINE LCD_DATAUS 50   'delay in micro seconds
    'END of LCD DEFINES
    
                                
    Pause 500       ' LCD initialize time
    lcdout $FE,1 
      
    num_digits      con 5        ; range 4 t0 9 tested ok     note sum_total will not work for more than 5 digits 
    sw_threshhold   con 10
    lp_threshhold   con 100      ;long press
    sw_inhibit_time con 100
    msd_limit       con 5        ;limit value for msd  note sum_total will not work for more than 5 digits and limit > 5  ;optional
    digit       var byte[num_digits-1]
    d_index     var byte
    overflow    var bit
    underflow   var bit
    noroll_flg  var bit    ;optional
    d_inx       var byte
    sw_cnt      var byte 
    sw_flag     var bit
    re          var byte 
    last_re     var byte 
    ev          var byte 
    tmp1        var byte
    tmp2        var byte  ;optional
    tmp3        var byte  ;optional   
    sw_inhibit  var byte
    total       var word 
    enc_sw var PORTC.4
    enc_a  var portc.5
    enc_b  var portc.6
    clear
    d_index = num_digits
    re = porta&48
    last_re = re
    gosub dup
      
    
    main:
        if !sw_inhibit then gosub chk_sw
        if   sw_flag then    ;service the sw if active
            if sw_cnt > lp_threshhold then       ;long press clears settings
                for d_index = 0 to (num_digits-1)
                   digit[d_index] = 0
                next
                 gosub dup
            else
                d_index = d_index - 1      ;increment set digit {index posn 6 will stop editing of settinge}
                if d_index > num_digits then d_index = num_digits
                gosub set_cursor
                sw_inhibit = sw_inhibit_time      ; don't reactivate sw immediately [more user friendly] 
            endif 
            sw_cnt = 0
            sw_flag = 0 
        endif 
        ;poll encoder    a poll rate of 5-10ms is adequate
        re = portc&96   
        if re != last_re  then    ;encoder has moved
            ev=ev<<2              ;shift old reading into position  for compare
            ev=ev|((portc&96)>>5)  ;read enc pins 4,5  mask off others then  combine this reading with last reading
            ;lookup table is a form of digital filter to debounce encoder [no caps used on encoder at all]
            LOOKUP (ev&$f),[0,255, 1, 0, 1, 0, 0, 255, 255, 0, 0, 1, 0, 1, 255, 0],tmp1 ;lookup the decision matrix  to determine rotation
        endif
        ;service encoder result if there is one
        if tmp1 && re == 0 then    ; tmp1 255 is anticlockwise or 1 for clockwise    [swap a/b pins if direction incorrect]
            if d_index != num_digits then
                if tmp1 = 255 then 
                    gosub  dec_digit
                else
                    gosub  inc_digit
                endif 
            endif
            gosub dup
            tmp1 = 0
        endif 
        ;service sw inhibit if necessary
        if  sw_inhibit then sw_inhibit = sw_inhibit - 1     ; [make sw action more user friendly] 
        
        pause 5   ;adjust to suite desired responsiveness  or  more functions in loop
        
    goto main
    
    dup:       ;update lcd 
        LCDOUT $FE, $94
        tmp1=num_digits
        while tmp1
            tmp1=tmp1-1
            if tmp1 = 1  then
               LCDOUT  ".", digit[tmp1]+$30
            else
                LCDOUT  digit[tmp1]+$30
            endif
        wend
        gosub SUM_TOTALS
        LCDOUT $FE, $80, dec5 total
    set_cursor:      ;update cursor
        if d_index == num_digits then
            LCDOUT $FE,$0C
        elseif d_index > 1 then
            LCDOUT $FE,$0f,$fe,$94 + (num_digits - 1) - d_index
        else
            LCDOUT $FE,$0f,$fe,$94 + num_digits - d_index
        endif
    return
    
    inc_digit:      ;inc current digit
        d_inx = d_index
        gosub norollu        ;optional
        if noroll_flg then   ;optional
        digit[d_index] = digit[d_index] + 1
        gosub chk_ovf
        while overflow
            digit[d_inx] = 0
            d_inx = d_inx + 1
            if  d_inx >= num_digits then return
            gosub norollu        ;optional
            if noroll_flg then   ;optional
                digit[d_inx] = digit[d_inx] + 1
                gosub chk_ovf
            endif               ;optional
        wend
        endif                   ;optional
    return
    chk_ovf:       ;check if overflow occured
         overflow = 0
        if  digit[d_inx] > 9 then  overflow = 1
    return
     
    chk_unf:    ;check if underflow occured
        underflow = 0
        if  digit[d_inx] > 127 then  underflow = 1
    return
    dec_digit:      ;decrement current digit
        d_inx = d_index
        gosub norolld              ;optional
        if noroll_flg then         ;optional
        digit[d_index] = digit[d_index] - 1
            gosub chk_unf
            while underflow
                digit[d_inx] = 9
                d_inx= d_inx + 1
                if  d_inx >= num_digits then return
                gosub norolld       ;optional
                if noroll_flg then  ;optional
                    digit[d_inx] = digit[d_inx] - 1
                    gosub chk_unf
                endif              ;optional
            wend
        endif                      ;optional
    return
    chk_sw:      ;see if switch is active
        if sw_flag  then return 
        if !enc_sw  then 
            if    sw_cnt < 255 then sw_cnt = sw_cnt + 1
        else
            if sw_cnt > sw_threshhold then sw_flag = 1
        endif
     return
       
    norolld:       ; stop rollunder from 0000.00 to 9999.99  ;optional
       tmp3=digit[d_inx]                        ;optional
       noroll_flg=0                             ;optional
       for tmp2=(d_inx+1) to  (num_digits -1)   ;optional
          tmp3=tmp3+digit[tmp2]                 ;optional
       next                                     ;optional
       if tmp3 then noroll_flg = 1              ;optional
    return                                      ;optional                                     
    norollu:      ; stop rollover from 9999.99 to 0000.00    and limit msd
       noroll_flg=0                                 ;optional
       if  d_inx < (num_digits -1)  then            ;optional
           tmp3=9-digit[d_inx]                      ;optional
           for tmp2=(d_inx+1) to  (num_digits -2)   ;optional
               tmp3=tmp3+(9-digit[tmp2] )           ;optional
           next                                     ;optional
           tmp3=tmp3+(msd_limit-digit[tmp2] )       ;optional
       else                                         ;optional
           tmp3=msd_limit-digit[d_inx]              ;optional
       endif                                        ;optional
       if tmp3 then noroll_flg = 1                  ;optional
    return                                          ;optional
    SUM_TOTALS:    ;max digit is 5 and max_msd = 5 or else result will overflow
       tmp1=num_digits
       total=0
        while tmp1
            tmp1=tmp1-1
            total=total*10
            total=total+digit[tmp1]
        wend
    return
    Warning I'm not a teacher

  7. #7
    Join Date
    Jun 2017
    Posts
    27


    Did you find this post helpful? Yes | No

    Post Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    Thanks Richard for commenting and posting code. Your code takes up much less space. I made the hardware changes to my setup and included the necessary configuration registers for programming. I don't understand why you "and" PortA with decimal 48. Please explain. See example below.
    As per your code, it does not function properly on my setup even though I made the LCD changes. What am I not seeing or missing? See video of power up and what happens when I turn the knob of the encoder. See what happens when I select a digit and then turn the knob. I can only get it to respond to the knob turn when I do it fast, not when it is done slowly.


    Encoder type used: I had used 3 10nF caps on the 3 lines to ground for debounce in my original setup. Failed to mention that, but I used a new one with no caps and still didn't work.
    Name:  20180213_110653.jpg
Views: 2078
Size:  55.6 KB


    Video:


    Thanks, csantex



    Quote Originally Posted by richard View Post
    if you do it more algorithmically the size can be reduced dramatically ,it becomes scalable digit wise

    more functions can easily be added and the mcu can be employed to perform a real task like pid control of a power supply and not just become a display controller


    ps note my lcd defines suite my setup and are different

    Code:
    '*************************************************  ***************
    '*  Name    : LCD_TEST.BAS                                      *
    '*  Author  : RICHARD                                           *
    '           
    '*  Date    : 4/8/2017                                          *
    '*  Version : 1.0                                               *
    '*  Notes   :                                      *
    '*          :       16f887                                   *
    '*************************************************  ***************
     
    
        #CONFIG
     __CONFIG    _CONFIG1, _LVP_OFF & _FCMEN_OFF & _IESO_OFF & _BOR_ON & _CPD_OFF & _CP_OFF & _MCLRE_ON & _PWRTE_ON & _WDT_OFF & _INTOSCIO 
     __CONFIG    _CONFIG2, _WRT_OFF & _BOR40V
     #ENDCONFIG
     
        DEFINE OSC 8
    
        
    'LCD defines begin here   
        DEFINE LCD_BITS 4  'defines the number of data interface lines (4 or 8) 
        DEFINE LCD_DREG PORTB 'defines the port where data lines are connected to
        DEFINE LCD_DBIT 0  'defines the position of data lines for 4-bit interface (0 or 4)
        DEFINE LCD_RSREG PORTB 'defines the port where RS line is connected to
        DEFINE LCD_RSBIT 4  'defines the pin where RS line is connected to 
        DEFINE LCD_EREG PORTB  'defines the port where E line is connected to 
        DEFINE LCD_EBIT 5  'defines the pin where E line is connected 
        DEFINE LCD_COMMANDUS 1500  'defines the delay after LCDOUT statement 
        DEFINE LCD_DATAUS 50   'delay in micro seconds
    'END of LCD DEFINES
    
    ;TRIS REGISTERS FROM MY CODE WITH COMMENTS****************************
    
        OSCCON  = %01110000     ; Set PIC16F88 to 4MHz = %01100000, or
                                ; 8MHz = %01110000
    '    TRISA   = %11111111     ; Port A set to inputs    'COMMENTED OUT SINCE IT BOOTS UP AS INPUTS ANYWAYS.   <<<<<<<<<<<<<<<
    '    TRISB   = %11101100     ; Port B set to OUTPUTS   'COMMENTED OUT SINCE LCD DEFINES SET DATA DIRECTIONS.   <<<<<<<<<<<<<<<<
        TRISC   = %01111111     ; Port C set to inputs
    '    TRISD   = %00000000     ; Port D set to Ouputs     'NOT USED IN YOUR CODE    <<<<<<<<<<<<<<<<<<<<<<<
        ANSEL   = %00000000     ; Set all analog pins to digital
        ANSELH  = %00000000
    
    ;*************************************************  *********************
    
    ; YOUR CODE==============================================                            
    Pause 500       ' LCD initialize time
    lcdout $FE,1 
      
    num_digits      con 5        ; range 4 t0 9 tested ok     note sum_total will not work for more than 5 digits 
    sw_threshhold   con 10
    lp_threshhold   con 100      ;long press
    sw_inhibit_time con 100
    msd_limit       con 5        ;limit value for msd  note sum_total will not work for more than 5 digits and limit > 5  ;optional
    digit       var byte[num_digits-1]
    d_index     var byte
    overflow    var bit
    underflow   var bit
    noroll_flg  var bit    ;optional
    d_inx       var byte
    sw_cnt      var byte 
    sw_flag     var bit
    re          var byte 
    last_re     var byte 
    ev          var byte 
    tmp1        var byte
    tmp2        var byte  ;optional
    tmp3        var byte  ;optional   
    sw_inhibit  var byte
    total       var word 
    enc_sw var PORTC.4
    enc_a  var portc.5
    enc_b  var portc.6
    clear
    d_index = num_digits
    re = porta&48     '<<<<<<<<<<<<<<<  Why do you "&" dec48 with Port A?
    last_re = re    
    gosub dup
    
    The rest of the code is as you wrote it....
    Last edited by csantex; - 13th February 2018 at 18:26. Reason: typo

  8. #8
    Join Date
    Jun 2017
    Posts
    27


    Did you find this post helpful? Yes | No

    Default Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    For anyone interested, here is a video of my code, even though its long, but working with the hardware setup as in Richard's comment. Changed my code to reflect that. I think it would help me if we could see a video of Richards code in action. I'm very interested.

    csantex

    Last edited by csantex; - 13th February 2018 at 19:24. Reason: tweak

  9. #9
    Join Date
    May 2013
    Location
    australia
    Posts
    2,380


    Did you find this post helpful? Yes | No

    Default Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    I don't understand why you "and" PortA with decimal 48. Please explain
    I originally had encoder on pins 4,5 . and missed fixing that line when I moved re pins to 5,6
    it only sets re initial state so after first move its not important , the first move could be in error though
    I should "and" PortA with decimal 96. for those pins
    Warning I'm not a teacher

  10. #10
    Join Date
    May 2013
    Location
    australia
    Posts
    2,380


    Did you find this post helpful? Yes | No

    Default Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    oops
    and moved it to portc too to match your setup
    Warning I'm not a teacher

  11. #11
    Join Date
    May 2013
    Location
    australia
    Posts
    2,380


    Did you find this post helpful? Yes | No

    Default Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    As per your code, it does not function properly on my setup even though I made the LCD changes. What am I not seeing or missing? See video of power up and what happens when I turn the knob of the encoder. See what happens when I select a digit and then turn the knob. I can only get it to respond to the knob turn when I do it fast, not when it is done slowly.
    I have the identical rotary encoder module and use no caps at all on it,
    I have used a pic18f458 @8mhz , a pic18f25k22 @64mhz they both work perfectly.
    I don't have a pic16 chip with the correct pinout to suit the lcd wiring in my easypic7 board so I can't test for those chips
    but can see no reason for it not to work.
    Warning I'm not a teacher

  12. #12
    Join Date
    Jun 2017
    Posts
    27


    Did you find this post helpful? Yes | No

    Post Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    Quote Originally Posted by richard View Post
    oops
    and moved it to portc too to match your setup
    I caught that earlier and made the changes then but it still didn't work. Here is my schematic:
    Hope its not too big. If too small, I provided an image attachment.


    Name:  ENCODER SCH.png
Views: 2119
Size:  49.6 KB
    Attached Files Attached Files
    Last edited by csantex; - 14th February 2018 at 00:37. Reason: bad image

  13. #13
    Join Date
    Jun 2017
    Posts
    27


    Did you find this post helpful? Yes | No

    Default Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    Quote Originally Posted by richard View Post
    I have the identical rotary encoder module and use no caps at all on it,
    I have used a pic18f458 @8mhz , a pic18f25k22 @64mhz they both work perfectly.
    I don't have a pic16 chip with the correct pinout to suit the lcd wiring in my easypic7 board so I can't test for those chips
    but can see no reason for it not to work.
    If your using 18F chips then that may be the reason why. Perhaps the commands are getting compiled differently for 18F's than for 16F's??
    No matter, I have an 18F4423 I can use to test that theory...
    Thanks.

  14. #14
    Join Date
    May 2013
    Location
    australia
    Posts
    2,380


    Did you find this post helpful? Yes | No

    Default Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    I don't use lcd's or pic16's much but here is a trap


    LCDOUT ".", digit[tmp1]+$30
    inline math for lcdout on a pic16 turns to crap,you need to do the math first then print result

    Code:
    tmp2 =digit[tmp1]+$30
    
    LCDOUT  ".", tmp2
    the code still fails on pic16, may be too many nested gosubs
    Warning I'm not a teacher

  15. #15
    Join Date
    May 2013
    Location
    australia
    Posts
    2,380


    Did you find this post helpful? Yes | No

    Default Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    moved enc to porta 234 on 16f648a, reduced nesting by two levels

    now works

    Code:
    '****************************************************************
    '*  Name    : LCD_TEST.BAS                                      *
    '*  Author  : RICHARD                                           *
    '           
    '*  Date    : 4/8/2017                                          *
    '*  Version : 1.0                                               *
    '*  Notes   :                                      *
    '*          :       16f648a                                   *
    '****************************************************************
    #CONFIG
      __config  _HS_OSC & _WDT_ON & _PWRTE_OFF & _MCLRE_ON & _BODEN_ON & _LVP_OFF & _CP_OFF
    #ENDCONFIG
     
        DEFINE OSC 8
    
        
    'LCD defines begin here   
        DEFINE LCD_BITS 4  'defines the number of data interface lines (4 or 8) 
        DEFINE LCD_DREG PORTB 'defines the port where data lines are connected to
        DEFINE LCD_DBIT 0  'defines the position of data lines for 4-bit interface (0 or 4)
        DEFINE LCD_RSREG PORTB 'defines the port where RS line is connected to
        DEFINE LCD_RSBIT 4  'defines the pin where RS line is connected to 
        DEFINE LCD_EREG PORTB  'defines the port where E line is connected to 
        DEFINE LCD_EBIT 5  'defines the pin where E line is connected 
        DEFINE LCD_COMMANDUS 1500  'defines the delay after LCDOUT statement 
        DEFINE LCD_DATAUS 50   'delay in micro seconds
    'END of LCD DEFINES
        DEFINE LCD_LINES 4
    cmcon=7                           
    Pause 500       ' LCD initialize time
    lcdout $FE,1 
      
    num_digits      con 5        ; range 4 t0 9 tested ok     note sum_total will not work for more than 5 digits 
    sw_threshhold   con 10
    lp_threshhold   con 100      ;long press
    sw_inhibit_time con 100
    msd_limit       con 5        ;limit value for msd  note sum_total will not work for more than 5 digits and limit > 5  ;optional
    digit       var byte[num_digits]
    d_index     var byte
    overflow    var bit
    underflow   var bit
    noroll_flg  var bit    ;optional
    d_inx       var byte
    sw_cnt      var byte 
    sw_flag     var bit
    re          var byte 
    last_re     var byte 
    ev          var byte 
    tmp1        var byte
    tmp2        var byte  ;optional
    tmp3        var byte  ;optional   
    sw_inhibit  var byte
    total       var word
    enc_act     var byte
    enc_sw var PORTa.4
    enc_a  var porta.2
    enc_b  var porta.3
    
    clear
    d_index = num_digits
    re = porta&12
    last_re = re
    gosub dup
     
    
    main:
        if !sw_inhibit then gosub chk_sw
        if   sw_flag then    ;service the sw if active
            if sw_cnt > lp_threshhold then       ;long press clears settings
                for d_index = 0 to (num_digits-1)
                   digit[d_index] = 0
                next
                 gosub dup
            else
                d_index = d_index - 1      ;increment set digit {index posn 6 will stop editing of settinge}
                if d_index > num_digits then d_index = num_digits
                gosub set_cursor
                sw_inhibit = sw_inhibit_time      ; don't reactivate sw immediately [more user friendly] 
            endif 
            sw_cnt = 0
            sw_flag = 0 
        endif 
        ;poll encoder    a poll rate of 5-10ms is adequate
        re = porta&12   
        if re != last_re  then    ;encoder has moved
            last_re = re   ; this line fell off pic18 version
            ev=ev<<2              ;shift old reading into position  for compare
            ev=ev|((porta&12)>>2)  ;read enc pins 4,5  mask off others then  combine this reading with last reading
            ;lookup table is a form of digital filter to debounce encoder [no caps used on encoder at all]
            LOOKUP (ev&$f),[0,255, 1, 0, 1, 0, 0, 255, 255, 0, 0, 1, 0, 1, 255, 0],enc_act ;lookup the decision matrix  to determine rotation
        endif
        ;service encoder result if there is one
        if enc_act && (re == 0) then    ; tmp1 255 is anticlockwise or 1 for clockwise    [swap a/b pins if direction incorrect]
            if d_index != num_digits then
                if enc_act = 255 then 
                        d_inx = d_index
                        gosub norolld              ;optional
                        if noroll_flg then         ;optional
                        digit[d_index] = digit[d_index] - 1
                            underflow = 0
                            if  digit[d_inx] > 127 then  underflow = 1
                            while underflow
                                underflow = 0
                                digit[d_inx] = 9
                                d_inx= d_inx + 1
                                if  d_inx < num_digits then 
                                    gosub norolld       ;optional
                                    if noroll_flg then  ;optional
                                        digit[d_inx] = digit[d_inx] - 1
                                        if  digit[d_inx] > 127 then  underflow = 1
                                    endif              ;optional
                                endif
                            wend
                        endif                      ;optional
                else
                        d_inx = d_index
                        gosub norollu        ;optional
                        if noroll_flg then   ;optional
                        digit[d_index] = digit[d_index] + 1
                        overflow = 0
                        if  digit[d_inx] > 9 then  overflow = 1
                        while overflow
                            overflow = 0
                            digit[d_inx] = 0
                            d_inx = d_inx + 1
                            if  d_inx < num_digits then 
                                gosub norollu        ;optional
                                if noroll_flg then   ;optional
                                    digit[d_inx] = digit[d_inx] + 1
                                    if  digit[d_inx] > 9 then  overflow = 1
                                endif               ;optional
                            endif
                        wend
                        endif                   ;optional
                endif 
            gosub dup    
            endif
            
            enc_act = 0
        endif 
        ;service sw inhibit if necessary
        if  sw_inhibit then sw_inhibit = sw_inhibit - 1     ; [make sw action more user friendly] 
        
        pause 5   ;adjust to suite desired responsiveness  or  more functions in loop
        
    goto main
    
    dup:       ;update lcd 
        LCDOUT $FE, $94
        tmp1=num_digits
        while tmp1
            tmp1=tmp1-1
            tmp2 = digit[tmp1]+$30
            if tmp1 = 1  then
               LCDOUT  ".", tmp2
            else
               LCDOUT  tmp2
            endif
        wend
        gosub SUM_TOTALS
        LCDOUT $FE, $80, dec5 total
    set_cursor:      ;update cursor
        if d_index == num_digits then
            LCDOUT $FE,$0C
        else
            tmp2 =  $94 + num_digits - d_index
            if d_index > 1 then  tmp2=tmp2-1
            LCDOUT $FE,$0f,$fe,tmp2 
        endif
    return
     
    chk_sw:      ;see if switch is active
        if sw_flag  then return 
        if !enc_sw  then 
            if    sw_cnt < 255 then sw_cnt = sw_cnt + 1
        else
            if sw_cnt > sw_threshhold then 
               sw_flag = 1
            else
               sw_cnt=0
            endif
        endif
     return
       
    norolld:       ; stop rollunder from 0000.00 to 9999.99  ;optional
       tmp3=digit[d_inx]                        ;optional
       noroll_flg=0                             ;optional
       for tmp2=(d_inx+1) to  (num_digits -1)   ;optional
          tmp3=tmp3+digit[tmp2]                 ;optional
       next                                     ;optional
       if tmp3 then noroll_flg = 1              ;optional
    return                                      ;optional                                     
    norollu:      ; stop rollover from 9999.99 to 0000.00    and limit msd
       noroll_flg=0                                 ;optional
       if  d_inx < (num_digits -1)  then            ;optional
           tmp3=9-digit[d_inx]                      ;optional
           for tmp2=(d_inx+1) to  (num_digits -2)   ;optional
               tmp3=tmp3+(9-digit[tmp2] )           ;optional
           next                                     ;optional
           tmp3=tmp3+(msd_limit-digit[tmp2] )       ;optional
       else                                         ;optional
           tmp3=msd_limit-digit[d_inx]              ;optional
       endif                                        ;optional
       if tmp3 then noroll_flg = 1                  ;optional
    return                                          ;optional
    SUM_TOTALS:    ;max digit is 5 and max_msd = 5 or else result will overflow
       tmp1=num_digits
       total=0
        while tmp1
            tmp1=tmp1-1
            total=total*10
            total=total+digit[tmp1]
        wend
    return
    Warning I'm not a teacher

  16. #16
    Join Date
    Jun 2017
    Posts
    27


    Did you find this post helpful? Yes | No

    Default Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    Quote Originally Posted by richard View Post
    moved enc to porta 234 on 16f648a, reduced nesting by two levels

    now works
    Yes now it does and I now see what you meant by scalable. Range is 000.00 to 599.99
    So at startup with no button push, the knob does nothing until the user is ready to use it.
    Push Button, user selects the hundreds digit from 000.00 to 500.00.
    Next push, user selects the tens digit for a range of 000.00 to 590.00.
    Next push, user selects the ones digit for a range of 000.00 to 599.00
    Next push is for tenths. 599.90
    Nest push is for hundredths. 599.99
    Push button for a second or so and it clears it all to zero.
    Last push, the knob is disabled again.

    Very interesting way of doing it. I must say that this method is way more functional that what I was doing.

    Thanks for a great lesson in programming.

    On a side note, this pic has an 8 level stack. I only counted 2 nested GOSUBS max. I guess 2 was 2 much...

  17. #17
    Join Date
    May 2013
    Location
    australia
    Posts
    2,380


    Did you find this post helpful? Yes | No

    Default Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    On a side note, this pic has an 8 level stack. I only counted 2 nested GOSUBS max. I guess 2 was 2 much...
    pbp uses 4 of them before your code even starts

    now see what happens when
    num_digits con 5 is changed

    try 4 up to 9 or beyond

    also try changing
    msd_limit con 5

    to other values


    also hold switch down for a couple of seconds
    Warning I'm not a teacher

  18. #18
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    3,795


    Did you find this post helpful? Yes | No

    Default Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    On the http://www.best-microcontroller-proj...y-encoder.html site there was an article that uses a different type of encoder polling.

    It is in C but if I can read it then everyone can!

    I have not yet understood completely how it decodes the encoder data but seems very interesting and as the author says it decodes also the speed?

    No hardware set up to test it but if anyone has the time I'd like to know the results.

    Ioannis

  19. #19
    Join Date
    May 2013
    Location
    australia
    Posts
    2,380


    Did you find this post helpful? Yes | No

    Default Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    I have not yet understood completely how it decodes the encoder
    it looks like a cruel hoax to me, maybe you need to sign up to get the working version.
    if the encoder is static [on detent] after 12 polls state=0xffff
    you then need 12 polls in a row where the clk pin is 0 to reach the
    0xf000 state , since the polling is asynchronous I cannot see how that can happen
    reliably ,so I tried it in my example

    ' enstate = (enstate<<1 )| enc_a | $e000
    ' if enstate == $f000 then
    ' enstate=0


    ' if enc_b then
    and it fails as I expected when polled @5mS
    the example polls @100uS , if you need that much horse power I can't see the point
    Warning I'm not a teacher

  20. #20
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    3,795


    Did you find this post helpful? Yes | No

    Default Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    Thanks for testing it Richard. It was very strange to me.

    Anyway, no other version exists. I did sign in to the site but no other version exists.

    Ioannis

  21. #21
    Join Date
    Jun 2017
    Posts
    27


    Did you find this post helpful? Yes | No

    Post Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    For anyone interested in Richard's code example and how it works, watch the video below.
    The video shows most of what the code does. Thanks for sharing Richard.

    csantex


  22. #22
    Join Date
    May 2013
    Location
    australia
    Posts
    2,380


    Did you find this post helpful? Yes | No

    Default Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    Thanks for testing it Richard. It was very strange to me.

    Anyway, no other version exists. I did sign in to the site but no other version exists.

    Ioannis

    tried it on Arduino mega
    @100uS it worked
    @200uS its patchy
    @400uS or longer its crap

    conclusion , not much use but quaint
    Warning I'm not a teacher

  23. #23
    Join Date
    Feb 2013
    Posts
    1,078


    Did you find this post helpful? Yes | No

    Default Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    I tried to re-use Richards code, but I have encoder on PORTB.3 and PORTB.4 and not using button. I've changed enc_a to portb.4
    and enc_b to portb.3, but I guess I also have to modify re = porta&12 ? to what it set?

  24. #24
    Join Date
    May 2013
    Location
    australia
    Posts
    2,380


    Did you find this post helpful? Yes | No

    Default Re: Rotary Encoder on 20x4 LCD with pushbutton digit select and other features

    I've changed enc_a to portb.4 and enc_b to portb.3, but I guess I also have to modify re = porta&12 ? to what it set?
    its a simple binary mask used to select only the port pin data from the two pins of interest
    the mask value is 2 to power of enc_a.bit + 2 to power of enc_b.bit.


    you also need to shift the data gathered into bits 0 and 1 for proper evaluation
    Warning I'm not a teacher

Similar Threads

  1. Using an incremental rotary encoder?
    By keithv in forum mel PIC BASIC Pro
    Replies: 5
    Last Post: - 12th January 2016, 23:23
  2. Instant Interrupts for rotary encoder
    By fnovau in forum mel PIC BASIC Pro
    Replies: 7
    Last Post: - 15th August 2014, 09:24
  3. New approach to Rotary Encoder
    By Ioannis in forum Code Examples
    Replies: 90
    Last Post: - 11th July 2013, 22:05
  4. Automotive quality rotary encoder
    By d1camero in forum mel PIC BASIC Pro
    Replies: 1
    Last Post: - 8th October 2004, 16:46

Members who have read this thread : 3

You do not have permission to view the list of names.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts