• PicŪ Basic


  • Code for Driving 2 to 8 seven segment displays

    I have recovered from the forum background a code to drive 4 seven segment displays. The author is unknown, it could be a Les Johnson code. I have renewed the code to adapt it to the new versions of the compiler (V3603). I have tried to make the code as efficient and fast as possible. Now I have been able to extend the code to scan 6 digits. See later in this article for 8 digit displays.

    Writing such a code in the main program is a very difficult task almost impossible without imposing a very strict timing for its application, restricting its possibilities. It is for this reason it is better to use interrupts to scan the digits.

    Several projects:
    You will find several projects in this article.
    These projects are slightly different, I keep them because they could be very interesting in any case. I have developed a new project specially applied in incorporating a keyboard to the display system that has already been presented in the multiplexer example.
    You can find a manual where the great part of the information of this article is compiled.

    Configuration of the DisplayInit_Sub:
    This routine contains all the PIC and hardware parameters. The code will depend on each PIC and it will be the responsibility of the user PDS to adapt it. In particular putting the pins to digital, which is not so simple for some PICs.

    Configuration of the PORTs:
    The configuration of the ports must be done at the beginning of the program.
    Code:
        '/ Definition of the PORTS for Display segments.
        Symbol SEGMENTS = LATD
    
        '/ Definition of the pins to enable displays to write.
        $if NumberDigits = 6
        Symbol DIGIT1 = LATE.0
        Symbol DIGIT2 = LATE.1
        Symbol DIGIT3 = LATE.2
        Symbol DIGIT4 = LATC.0 
        Symbol DIGIT5 = LATC.1
        Symbol DIGIT6 = LATC.2
        $endif
    Data Table:
    To perform the conversion of numbers to segments, a data table is needed.
    In the original code, this table was written in ROM with CData. But I found out that by placing it in the eeprom, access to the data could be faster. Provided that the table starts at address 0 of the eeprom.
    For beginners, it is necessary to know when the entry or exit of a routine is a byte, the compiler almost always places the result to the WREG SFR. In this code, one line could be deleted.
    Transformation of the original code into new code to read the ROM:

    With this code for example:
    Code:
        TempByte = Dig DISPVAL,0
        ONES = CRead8 SegmentsData[TempByte]
    
    Change to:
    
        WREG = Dig DISPVAL,0                ' Using WREG 1 line of code is saved.
        ONES = CRead8 SegmentsData[WREG]
    You get this code in asm:
    Code:
        movff DISPVALH,PP0H
        movff DISPVAL,PP0
        movlw 0
        rcall Dig
    
        clrf TBLPTRLH,0
        movwf TBLPTRL,0
        movlw (SegmentsData & 0XFF)
        addwf TBLPTRL,F,0
        movlw ((SegmentsData >> 8) & 0XFF)
        addwfc TBLPTRH,F,0
        clrf EECON1,0
        bsf EECON1,PP_EEPGD,0
        tblrd*
        movff TABLAT,ONES
    You can see that "movwf TempByte,0" has disappeared. Using this technique, you could save 1 line of code.

    These codes must be repeated for each digit. It is more effective if the eeprom is read in this way:
    Considering that "EECON1 = 0" can be written only once in the routine, then the following could be done. The Eread command is more complex and uses more lines of code.
    Code:
        EEADR = Dig DISPVAL,0               
        EECON1bits_RD = 1
        ONES = EEDATA
    You get this code in much more efficient asm:
    Code:
        movff DISPVALH,PP0H
        movff DISPVAL,PP0
        movlw 0
        rcall Dig
        movwf EEADR,0
    
        bsf EECON1,0,0
        movff EEDATA,ONES
    By reading the asm code generated by the compiler you can learn how it works and write your basic code accordingly to optimize it to the maximum. That is why I consider that the Proton Basic is a very good compiler.
    I use this technique a lot in writing my libraries.

    Interrupt routine:
    To do the scan and write the PORT:
    I have modified the original code to improve the flicker, in the old case it could be some microseconds. The displays are off when the value of the PORT is changed.
    Code:
        DIGIT6 = 0        '/ Turn OFF the Display 6.
        SEGMENTS = PRINT_ONES    '/ Change the value of the PORT (segments)
        DIGIT1 = 1        '/ Turn On the Display 1.
    Originally the table was written for displays with common anode. Using a very fast trick the code can be adapted to display with common cathode.
    SegmentsData: CData Byte 192,249,164,176,153,146,131,248,128,152,255

    Common anode:
    Code:
        DIGIT6 = 1        '/ Turn OFF the Display 6.
        SEGMENTS = PRINT_ONES    '/ Change the value of the PORT (segments)
        DIGIT1 = 0        '/ Turn On the Display 1.
    Common cathode:
    Code:
        DIGIT6 = 0        '/ Turn OFF the Display 6.
        SEGMENTS = ~PRINT_ONES    '/ Change the value of the PORT (segments)
        DIGIT1 = 1        '/ Turn On the Display 1.
    Only inverting the bits of the PORT and the ON/OFF polarity of DIGIT1 to DIGIT6.

    Avoid the blinking of interruptions:
    If the interrupt occurs during the execution of the routine "Build_Digits_Sub" we could send the digits some old values for the high and new digits for the low digits at the same time. To solve this problem I have created some buffers whose load is independent of the interrupts in the following way. The interrupt generated by the Timer stops for a very short time.
    Code:
            ' Make a copy to print the values for the interrupt routine.
            DisPlayInterruptEnable = 0           '/ Avoid blinking.
            PRINT_ONES = ONES
            PRINT_TENS = TENS
            PRINT_HUNDREDS = HUNDREDS
            PRINT_THOUSANDS = THOUSANDS        
            PRINT_TENTHOUSANDS = TENTHOUSANDS 
            PRINT_HUNDREDTHOUSANDS = HUNDREDTHOUSANDS 
            DisPlayInterruptEnable = 1
    Configuration of the program:
    Read the manual.

    06/19/2018 Update code for driving 7 displays + sign. (total 8 displays)
    Thanks to the very good structure of the code written by the original author (Les Johnson I suppose) I have been able to write this new template. The code seems complicated, but everything is based on modules that can be adapted.
    The program manages input signed numbers such as SByte / SWord and variable SDword variables.

    06/20/2018 Update new version 2.2. I have expanded to 8 digits for integer variables.

    06/22/2018 Update code for driving 8 displays with one PORT only with the help of simple and economical logic. (74HC5411 + 74HC238)
    Some improvements have been introduced in all the libraries.
    Note: It is important to remember to adjust the delays in the interrupt routine to adapt them to the real circuits for better efficiency.
    Also I have updated the previous codes. All codes are built as 3 libraries.

    06/28/2018 update version 3.0
    In the main program I had left the variable DISPVAL as a test variable. Using a library variable is not the most convenient. To expand the possibilities for the PDS user I have modified the macro "BuilDigits (MyDword)" so you can enter any variable from your main program.
    BuilDigits (MyWord)
    BuilDigits (MyByte)
    Read the manual.

    06/30/2018 New library for 3 to 8 seven segment displays.
    Proton allows software functions to be modified. I have modified RsOut to continue to use modifiers, but instead of outputting to a serial pin the output goes to the pins driving the 7 segment displays. This has made it easier to send integers, floats, strings etc to the pins connected to the displays.
    Read the manual.

    07/04/2018 New version 1.1 of library for 3 to 8 seven segment displays.
    Read the manual.

    07/22/2018 New Project: 2 to 8 seven segments display with KEYPAD.
    I hope that my comments on my code are accurate enough so that PDS users can modify the test code to make it their own.
    Good luck for your project.

    You can get the code HERE.
    Alberto
  • Recent Activity

    See_Mos-247

    Simple timer

    Thread Starter: amod

    Iam making a simple timer for 60 seconds with setpoint.suppose if I set 45 then timer start with a pulse and when I get 0 then timer stop. I tried...

    See_Mos Yesterday, 19:23 Go to last post