Continue to Site

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.

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

LED SignBoard 64X8 - PIC 16F628A

Status
Not open for further replies.
Hi Suraj,

It seems you have the correct procedure. You need to keep track of the row number and select the correct five bytes (40 bits) of data from your display array during each interrupt. You'll clock out those 40 bits into the daisy-chained shift registers, blank the display, latch the shift register data onto the outputs, then select the new row to turn the display back on. You do this procedure each interrupt to display a new row.

Regards, Mike

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

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:
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:
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:
My ROM character arrays are similar to your first example.

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

Attachments

  • MacMux™ 7x40.PNG
    MacMux™ 7x40.PNG
    39.8 KB · Views: 1,052
Last edited:
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:
Gayan,

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

Thanks Mike give me time to think this off.
 
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?
mapping-png.34998
 

Attachments

  • Mapping.PNG
    Mapping.PNG
    20.6 KB · Views: 2,776
Last edited:
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:
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
 
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.
 
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:
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:
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]
  }
}
 

Attachments

  • usign buffer.PNG
    usign buffer.PNG
    37.9 KB · Views: 1,180
Last edited:
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:
;===========================================================================
;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:
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:
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

k8lh-7x55-%C2%B5sign-concept-png.34823
 
I'm doing a research these days what is the speediest way of doing a multiplex routine.
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.
 
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.
 

Attachments

  • Register Placing.PNG
    Register Placing.PNG
    9.2 KB · Views: 918
Last edited:
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:
                      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:
;
;  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                  ;
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.
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:
Brilliant.

Your Character Generator routine for my display buffer method is excellent.

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.

Thanks for your time & effort Mike.

Mike said:
Ok, I see what you're doing. That seems like a good method.

That's what I want from you master.

Mike said:
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, I can do it in about 250 cycles, maybe faster if I tried.

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:
Jason (AtomSoft),

Did you ever order any of these 0.7-inch 5x7 displays for 69 cents each? They might be a nice candidate for a 7x40 or 7x80 display using my MacMux™ architecture and relatively inexpensive 74HC595 column driver ICs.

macmux%E2%84%A2-7x40-png.34017


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

New Articles From Microcontroller Tips

Back
Top