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


Closed Thread
Results 1 to 24 of 24

Hybrid View

  1. #1
    Join Date
    May 2013
    Location
    australia
    Posts
    2,681


    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

  2. #2
    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: 8614
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

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