1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice

LED SignBoard 64X8 - PIC 16F628A

Discussion in 'Microcontrollers' started by Gayan Soyza, Mar 8, 2009.

  1. Suraj143

    Suraj143 Active Member

    Joined:
    Jan 11, 2007
    Messages:
    1,586
    Likes:
    2
    Location:
    South Mald Isld
    Hi Thanks for the help mike.

    From your reply I noticed that you have only 5 registers (5bytes) for the 40 column display not 40 registers like I do.
     
  2. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,642
    Likes:
    109
    Location:
    Michigan, USA
    Hi Suraj,

    I use a 35 byte display array, 5 bytes (40 bits) for each of the seven rows, so I must select the correct 5 bytes to send to the shift registers each interrupt.

    Why do you have a 40 byte array?
     
    Last edited: Oct 18, 2009
  3. Gayan Soyza

    Gayan Soyza Active Member

    Joined:
    Oct 23, 2006
    Messages:
    1,822
    Likes:
    19
    Location:
    Colombo
    Mike I have a doubt in your macMUX design. To drive 40 columns you have 5 bytes (40bits) for each row. For 7 rows you have 35bytes.

    If you are writing a table pattern for your design what way do you write the table from the below mentioned ways?

    See the letter “A” appearing in the table.

    Code (text):

    Table   addwf   PCL,F
        retlw   b'000[COLOR="Red"]111[/COLOR]00'    ; char "A"
        retlw   b'00[COLOR="Red"]1[/COLOR]000[COLOR="Red"]1[/COLOR]0'
        retlw   b'00[COLOR="Red"]11111[/COLOR]0'
        retlw   b'00[COLOR="Red"]1[/COLOR]000[COLOR="Red"]1[/COLOR]0'
        retlw   b'00[COLOR="Red"]1[/COLOR]000[COLOR="Red"]1[/COLOR]0'

    Table   addwf   PCL,F
        retlw   b'00[COLOR="Red"]111111[/COLOR]'    ; char "A"
        retlw   b'0[COLOR="Red"]1[/COLOR]00[COLOR="Red"]1[/COLOR]000'
        retlw   b'0[COLOR="Red"]1[/COLOR]00[COLOR="Red"]1[/COLOR]000'
        retlw   b'0[COLOR="Red"]1[/COLOR]00[COLOR="Red"]1[/COLOR]000'
        retlw   b'00[COLOR="Red"]111111[/COLOR]'
        retlw   b'00000000'
     
    Last edited: Nov 1, 2009
  4. dave

    Dave New Member

    Joined:
    Jan 12, 1997
    Messages:
    -
    Likes:
    0


     
  5. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,642
    Likes:
    109
    Location:
    Michigan, USA

    My ROM character arrays are similar to your first example.

    Code (text):
    r08 romchar[] = { 0b0111000,    // "0"
                      0b1000100,    //
                      0b1001100,    //
                      0b1010100,    //
                      0b1100100,    //
                      0b0111000,    //
                      ~~~~~~~~~


                      0b0[COLOR=Red]111[/COLOR]000,    // "A"
                      0b[COLOR=Red]1[/COLOR]000[COLOR=Red]1[/COLOR]00,    //
                      0b[COLOR=Red]1[/COLOR]000[COLOR=Red]1[/COLOR]00,    //
                      0b[COLOR=Red]11111[/COLOR]00,    //
                      0b[COLOR=Red]1[/COLOR]000[COLOR=Red]1[/COLOR]00,    //
                      0b[COLOR=Red]1[/COLOR]000[COLOR=Red]1[/COLOR]00,    //
                      0b[COLOR=Red]1[/COLOR]000[COLOR=Red]1[/COLOR]00,    //
                      0b1111000,    // "B"
                      0b1000100,    //
                      0b1000100,    //
                      0b1111000,    //
                      0b1000100,    //
                      0b1000100,    //
                      0b1111000,    //
                      0b0111000,    // "C"
                      0b1000100,    //
                      0b1000000,    //
                      0b1000000,    //
                      0b1000000,    //
                      0b1000100,    //
                      0b0111000,    //
                      ~~~~~~~~~
     
     
    Last edited: Nov 2, 2009
  6. Gayan Soyza

    Gayan Soyza Active Member

    Joined:
    Oct 23, 2006
    Messages:
    1,822
    Likes:
    19
    Location:
    Colombo
    Ahhhh here now comes the problem..........

    In your method it can load a particular byte of a character to the shift register directly.But consider when showing the 2nd character theres a three column gap.How do you overcome this problem mike?

    But I see your clock is displaying within the shift register columns nicely.
     

    Attached Files:

    Last edited: Nov 2, 2009
  7. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,642
    Likes:
    109
    Location:
    Michigan, USA
    Gayan,

    The following text refers to my 7x55 design.

    I use a "character generator" subroutine to place the character pixel bits into the display[] array. This sub' will shift and mask the character pattern as necessary according to an 'htab' value of 0..55. The display[] array maps directly to the display hardware, that is, the display[0..6] bytes are row 0 with bit 7 in the display[0] byte mapping to the left most row 0 pixel and bit 0 in the display[6] byte mapping to the right most row 0 pixel. The ISR automatically loads the shift registers from the display[] array, using bytes in display[0..6] for a row 0 update, or bytes in display[7..13] for a row 1 update, etc..

    Regards, Mike
     
    Last edited: Nov 2, 2009
  8. Gayan Soyza

    Gayan Soyza Active Member

    Joined:
    Oct 23, 2006
    Messages:
    1,822
    Likes:
    19
    Location:
    Colombo
    Thanks Mike give me time to think this off.
     
  9. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,642
    Likes:
    109
    Location:
    Michigan, USA
    Gayan,

    May I ask if you're using an array of bytes as a video buffer in your designs? In other words, do you have an ISR which takes data directly from this buffer (array) to "paint" the display hardware and does your 'main' program simply manipulates bits in the video buffer (array)?

    Mike

    <added>

    This may give you an idea of what you need to do with the rom character pattern for the number "2" to place it into the display array (straddling an 8-bit shift register boundary). Seems daunting, doesn't it?
    [​IMG]
     

    Attached Files:

    Last edited: Nov 2, 2009
  10. Gayan Soyza

    Gayan Soyza Active Member

    Joined:
    Oct 23, 2006
    Messages:
    1,822
    Likes:
    19
    Location:
    Colombo
    Hi Mike thanks for your ideas & time.Now I see what you doing.

    My ISR takes data directly from the column registers.The advantage of this method is character placing is very easy even though it takes more RAMs.

    Mike couple of questions.

    If you need to display a letter let say from 12th column, first you loading 12 & calling your character generator?

    What about displaying a word like "MIKE" do you have to send the starting columns of each letter to the character generator?

    While traveling I thinked your method its hard mike you have to deal with 14 registers every time when you have to place a letter.
     
    Last edited: Nov 2, 2009
  11. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,642
    Likes:
    109
    Location:
    Michigan, USA
    Gayan,

    I just use "htab = 12" to set or change the htab. The character generator automatically advances "htab" by 6 after writing each character to the display buffer so no need to change "htab" for each letter.

    Yes, the character generator is a bit more involved when you multiplex rows and it updates 14 bytes in the display buffer for each character but the advantage is that adding columns to this type of multiplexed display does not reduce the LED duty cycle (and brightness).

    Mike
     
  12. Gayan Soyza

    Gayan Soyza Active Member

    Joined:
    Oct 23, 2006
    Messages:
    1,822
    Likes:
    19
    Location:
    Colombo
    Mike i'm doing a row scan for larger designs like my last youtube signboard.if i have 64 columns i'm taking 64 registers.in ur method you are taking 56 registers.in isr routine i track the row position & bit mask the appropriate bit & fill the entire row bit by bit .but you are filling entire row byte by byte.thats the different between us.
     
  13. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,642
    Likes:
    109
    Location:
    Michigan, USA
    Hi Gayan,

    If I was simply doing a scrolling signboard then I would probably increase the size of the display array (see drawing below) so that one complete character can be built outside of the display area and scrolled into the display one column at a time. Copy the character pattern from rom (table) into those right-most row bytes (no byte boundary problems), scroll one new column at a time into the viewable portion of the display buffer, then do it again for the next character.

    The scroll_left routine is simple (and fast);
    Code (text):
    void scroll_left_()             // 17 words, 92 cycles
    { u08 i = 7;                    //
      fsr0 = 0x47;                  // fsr0 = &display[7]
      do                            //
      { asm                         //
        { rlcf  _postdec0,F         // scroll row
          rlcf  _postdec0,F         //
          rlcf  _postdec0,F         //
          rlcf  _postdec0,F         //
          rlcf  _postdec0,F         //
          rlcf  _postdec0,F         //
          rlcf  _postdec0,F         //
          movlw 15                  // prep index for next row
          addwf _fsr0l,F            //
        }                           //
        i--;                        //
      } while(i);                   //
    }
     
    Pulling a new character pattern from the rom character array (table) and placing it in ram is relatively easy too;
    Code (text):
    void getromchar(u08 charval)    // 31 words, 43 cycles
    { asm                           //
      { movlw   7                   // tblptr = @display + charval * 7
        mulwf   _charval            //
        movlw   low(romchar)        //
        addwf   _prodl,W            //
        movwf   _tblptrl            //
        movlw   high(romchar)       //
        addwfc  _prodh,W            //
        movwf   _tblptrh            //
        clrf    _tblptru            //
        tblrd*+                     //
        movff   _tablat,_display+7  // display[7] = romchar[charval*7+0]
        tblrd*+                     //
        movff   _tablat,_display+15 // display[15] = romchar[charval*7+1]
        tblrd*+                     //
        movff   _tablat,_display+23 // display[23] = romchar[charval*7+2]
        tblrd*+                     //
        movff   _tablat,_display+31 // display[31] = romchar[charval*7+3]
        tblrd*+                     //
        movff   _tablat,_display+39 // display[39] = romchar[charval*7+4]
        tblrd*+                     //
        movff   _tablat,_display+47 // display[47] = romchar[charval*7+5]
        tblrd*+                     //
        movff   _tablat,_display+55 // display[55] = romchar[charval*7+6]
      }
    }
     
     

    Attached Files:

    Last edited: Nov 5, 2009
  14. Gayan Soyza

    Gayan Soyza Active Member

    Joined:
    Oct 23, 2006
    Messages:
    1,822
    Likes:
    19
    Location:
    Colombo
    Hi mike thanks for those wonderful comments.

    I just checked your way of doing.Scrolling all 4 ways easy but the problem with character aligning.

    I just wrote a character generator subroutine.

    Code (text):

    ;===========================================================================
    ;File   -   Char Generator
    ;Author -   Gayan Soyza
    ;Date   -   08-11-2009
    ;===========================================================================
    ;Notes
    ;
    ;Character Tables must arrange like this starting from MSB

    ;Char_A     Retlw   b'0[COLOR="Red"]111[/COLOR]0000'        ; Letter A
    ;       Retlw   b'[COLOR="Red"]1[/COLOR]000[COLOR="Red"]1[/COLOR]000'
    ;       Retlw   b'[COLOR="Red"]1[/COLOR]000[COLOR="Red"]1[/COLOR]000'
    ;       Retlw   b'[COLOR="Red"]11111[/COLOR]000'
    ;       Retlw   b'[COLOR="Red"]1[/COLOR]000[COLOR="Red"]1[/COLOR]000'
    ;       Retlw   b'[COLOR="Red"]1[/COLOR]000[COLOR="Red"]1[/COLOR]000'
    ;       Retlw   b'[COLOR="Red"]1[/COLOR]000[COLOR="Red"]1[/COLOR]000'

    ;GP registers used

    ;Htab       ; Horizontal Tab (Starting Column of a char)
    ;Byte_H     ; division byteH - Integer
    ;Byte_L     ; division byteL - fraction
    ;Rotate_Count   ; Rotate couns for make masks
    ;Mask_1     ; mask bits of a char,0 bits will affected by new data
    ;Mask_2     ; mask bits of a char,0 bits will affected by new data
    ;Temp_H     ; Temperory byteH for char placing from table
    ;Temp_L     ; Temperory byteL for char placing from table
    ;Pointer    ; offset values to table patterns
    ;----------------------------------------------------------------------------

    Char_Generator  movwf   Htab            ; ex: 11th column
            movwf   Byte_H          ;
            movlw   b'00000011'     ; Make default masks first
            movwf   Mask_1          ; 00000011 11111111
            movlw   b'11111111'     ;
            movwf   Mask_2
            bcf STATUS,C
            rrf Byte_H,F        ; divide by 8
            rrf Byte_L,F
            bcf STATUS,C
            rrf Byte_H,F
            rrf Byte_L,F
            bcf STATUS,C
            rrf Byte_H,F        ; 00000001
            rrf Byte_L,F        ; 01100000
            swapf   Byte_L,F
            bcf STATUS,C
            rrf Byte_L,F        ; 00000011
            ;
            movf    Byte_L,W        ; remainder = 3
            btfsc   STATUS,Z
            goto    Char_Place_Loop
            movwf   Rotate_Count        ; 3
            ;
    Make_Masks  bsf STATUS,C
            rrf Mask_1,F        ; 11100000
            rrf Mask_2,F        ; 01111111
            decfsz  Rotate_Count,F
            goto    Make_Masks
            ;      
    ;-----------------------------------------------------------------------------     
            ;
    Char_Place_Loop movf    Byte_L,W        ;
            movwf   Rotate_Count
            movf    Byte_H,W        ; position register
            addlw   20h
            movwf   FSR         ; add the position from 20h    
            movf    Pointer,W
            call    Table           ; get the character pattern
            movwf   Temp_H          ; store in temp
            movf    Htab,W          ; get column
            btfsc   STATUS,Z        ; is it zero column ?
            goto    Place_Set_1     ; yes,then no need adjust pattern
    Adjust_Pattern  bcf STATUS,C        ; no,
            rrf Temp_H,F
            rrf Temp_L,F
            decfsz  Rotate_Count,F
            goto    Adjust_Pattern 
            ;
    Place_Set_1 movf    INDF,W
            andwf   Mask_1,W
            iorwf   Temp_H,W
            movwf   INDF
            ;
            incf    FSR,F
    Place_Set_2 movf    INDF,W
            andwf   Mask_2,W
            iorwf   Temp_L,W
            movwf   INDF
            decf    FSR,F
            ;
            decfsz  Row_Counter,F
            goto    $+4
            movlw   .7
            movwf   Row_Counter
            retlw   0x00            ; end of placing a char
            movlw   .6
            addwf   FSR,F
            incf    Pointer,F
            goto    Char_Place_Loop    
    But I still wondering do I need a character generator.To do a basic scrolling you don't need a Character generator.

    I'm doing a research these days what is the speediest way of doing a multiplex routine.
     
    Last edited: Nov 8, 2009
  15. Gayan Soyza

    Gayan Soyza Active Member

    Joined:
    Oct 23, 2006
    Messages:
    1,822
    Likes:
    19
    Location:
    Colombo
    Let me tell it again.

    Mike I'm doing a row scan.If I want to do a 56 column display I'm taking 56 column registers.But in your case you are taking 49 registers.

    The method I'm following doesn't need a character generator & its really easy to place charactors.I'll post a picture for better understanding.
     
    Last edited: Nov 8, 2009
  16. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,642
    Likes:
    109
    Location:
    Michigan, USA
    That's what I was trying to say -- if all you're doing is scrolling text then you don't need a character generator function. Just stuff your character pattern into the display buffer outside of the viewable area (see diagram in my previous post). There's no alignment problems. You simply copy the seven byte character pattern into the display array.

    I'm currently writing a demo' program for you that simply scrolls text based on the design below. Just need to finish creating the rom 5x7 font array (may take awhile). If you have 5x7 modules with anode rows you would swap out the N-FET row drivers with P-FET drivers (also requires a small soft' driver change).

    I will look at your code in a moment.

    Regards, Mike

    [​IMG]
     
  17. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,642
    Likes:
    109
    Location:
    Michigan, USA
    Quickly loading 56 bits of column data for each row scan is probably only a problem because you're using 74HC164 shift registers. If you used another serial-to-parallel IC with a <strobe> or <latch> pin then you could take your time loading the shift registers and then simply blank the display (turn off the row) for a couple cycles while you toggle the <strobe> pin to copy the shift register data onto the outputs.
     
  18. Gayan Soyza

    Gayan Soyza Active Member

    Joined:
    Oct 23, 2006
    Messages:
    1,822
    Likes:
    19
    Location:
    Colombo
    Mike I'm using 74HC595 registers for larger displays.Here are the register placing between us.I'm placing registers vertically.In ISR routine I track the row position & bit mask the appropriate bit & fill the entire row bit by bit.
     

    Attached Files:

    Last edited: Nov 8, 2009
  19. Mike - K8LH

    Mike - K8LH Well-Known Member

    Joined:
    Jan 22, 2005
    Messages:
    3,642
    Likes:
    109
    Location:
    Michigan, USA
    Ok now I see why you're using 56 bytes for the display buffer.

    Your Character Generator routine for my display buffer method is excellent. Of course you don't need it if you're only scrolling messages but you really did "nail it".

    Here's a version of your routine that I just threw together with pseudo C code comments for anyone that's interested in a different perspective, comments, etc.

    Basically the character generator shifts a 16 bit mask and a 16 bit character pattern which is necessary in order to write a character into the display buffer with 1 pixel horizontal resolution (with my particular display architecture);

    Code (text):
                          bit mask        character pattern
    htab % 8 == 0    00000111 11111111    CCCCC000 00000000
    htab % 8 == 1    10000011 11111111    0CCCCC00 00000000
    htab % 8 == 2    11000001 11111111    00CCCCC0 00000000
    htab % 8 == 3    11100000 11111111    000CCCCC 00000000
    htab % 8 == 4    11110000 01111111    0000CCCC C0000000
    htab % 8 == 5    11111000 00111111    00000CCC CC000000
    htab % 8 == 6    11111100 00011111    000000CC CCC00000
    htab % 8 == 7    11111110 00001111    0000000C CCCC0000
     
    Code (text):
    ;
    ;  insert character pattern into display buffer at htab position
    ;
    ;  void chargen()               //
    ;  { MaskL = 0b00000111;        // Mask = 00000111 11111111
    ;    MaskR = 0b11111111;        //
    ;    Count = htab % 8;          // 0..7
    ;    while(Count)               //
    ;    { asm                      //
    ;      { setc                   //
    ;        rrf    MaskL,F         //
    ;        rrf    MaskR,F         //
    ;      }                        //
    ;      Count--;                 //
    ;    }                          //
    ;    fsr = 0x20 + htab / 8;     // fsr = &display[0..6]
    ;    row = 0;                   //
    ;    do                         //
    ;    { CharL = GetChar(charval,row);
    ;      CharR = 0;               //
    ;      Count = htab % 8;        // 0..7
    ;      while(Count)             //
    ;      { asm                    //
    ;        { clrc                 //
    ;          rrf     CharL,F      //
    ;          rrf     CharR,F      //
    ;        }                      //
    ;        Count--;               //
    ;      }                        //
    ;      indf &= MaskL;           //
    ;      indf |= CharL;           //
    ;      fsr++;                   //
    ;      indf &= MaskR;           //
    ;      indf |= CharR;           //
    ;      fsr += 6;                // bump index for next row
    ;      row++;                   //
    ;    } while(row < 7);          //
    ;  }
    ;
    CharGen
            movlw   b'00000011'     ; display bit mask
            movwf   Mask_L          ; 00000011 11111111
            movlw   b'11111111'     ;
            movwf   Mask_R          ;
            movf    Htab,W          ; 0..50 max
            andlw   7               ; W = Htab % 8 --> 0..7
            goto    RTest           ;
    RMask   setc                    ;
            rrf     Mask_L,F        ; rotate 16 bit mask
            rrf     Mask_R,F        ;
    RTest   addlw   -1              ; done rotating?
            bnz     RMask           ; no, branch, else
    ;
            movf    Htab,W          ; 0..50 max
            andlw   b'11111000'     ; toss b2..b0 fraction bits
            movwf   FSR             ; 0, 8, 16, 24, 32, 40, 48
            swapf   FSR,F           ; pseudo divide-by-16
            rlf     FSR,W           ; preserve Carry and multiply by 2
            rlf     FSR,F           ; FSR = htab / 8
            movlw   Display         ; W = &display[0]
            addwf   FSR,F           ; FSR = &display[0..6]
    ;
            clrf    Row             ; Row = 0
    DoRow   call    GetChar         ; W = getchar(charval,row)
            movwf   Char_L          ;
            clrf    Char_R          ;
            movf    Htab,W          ; 0..50
            andlw   7               ; W = Htab % 8 --> 0..7
            goto    Check           ;
    Shift   clrc                    ; shift 16 bit pattern
            rrf     Char_L,F        ;
            rrf     Char_R,F        ;
    Check   addlw   -1              ; done shifting?
            bnz     Shift           ; no, branch, else
            movf    INDF,W          ; display[rowindex+htab/8]
            andwf   Mask_L,W        ;
            iorwf   Char_L,W        ;
            movwf   INDF            ;
            incf    FSR,F           ;
            movf    INDF,W          ; display{rowindex+htab/8+1]
            andwf   Mask_R,W        ;
            iorwf   Char_R,W        ;
            movwf   INDF            ;
            movlw   6               ;
            addwf   FSR,F           ; bump index for next row
            incf    Row,F           ;
            movf    Row,W           ;
            xorlw   7               ; all 7 rows done?
            bnz     DoRow           ; no, branch, else
            return                  ;
     
    Ok, I see what you're doing. That seems like a good method. I had thought you were still using '164 drivers and were concerned about how long you had to blank the display while loading the shift registers with 56 bits of column data during each row update. With the '595 drivers you should only have to blank the display for a few cycles when you latch the shift register data onto the outputs and select the new row and so it shouldn't matter how long you take to actually load the shift registers with 56 bits of data during each interrupt, unless you're trying for some extremely fast refresh rates.

    How may cycles do you use in your ISR to update a 56 bit row? My 7x55 or 7x56 MacMux design uses 160 cycles (18F') up to about 190 cycles (16F'). If I were to use three seperate pins to load 56 bits into daisy-chained 74HC595 drivers, instead of using the MacMux interface, it would probably take about 350 cycles.

    Regards, Mike
     
    Last edited: Nov 10, 2009
  20. Gayan Soyza

    Gayan Soyza Active Member

    Joined:
    Oct 23, 2006
    Messages:
    1,822
    Likes:
    19
    Location:
    Colombo
    Brilliant.

    Thanks for your time & effort Mike.

    That's what I want from you master.

    I'll let you know this.Your MacMux method saves a lot cycles.I've got used to daisy-chained 74HC595 drivers mike.If Its pretty hard to change my hardware to mac mux structure.Because I have to change my all pcb's & driver boards.

    Anyway nice to hear new name called MacMux.

    Gud Luck
     
    Last edited: Nov 10, 2009
  21. supra_2010

    supra_2010 Member

    Joined:
    Nov 12, 2009
    Messages:
    49
    Likes:
    0
    Location:
    Toronto, Canada

    Can u send me source code? I'm using pic16f628A/74HC154. also have pic18F4525 and dspic30F4013. But i haven't tried it yet.
     

Share This Page