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

    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

  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

    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...

  3. #3
    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

    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

  4. #4
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    4,170


    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

  5. #5
    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

    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

  6. #6
    Join Date
    Nov 2003
    Location
    Greece
    Posts
    4,170


    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

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