Shop OBEX P1 Docs P2 Docs Learn Events
Digit Animation Help — Parallax Forums

Digit Animation Help

skynuggetskynugget Posts: 172
edited 2009-12-15 07:15 in General Discussion
Hey all, im working on a clock project, that is based on three 74HC595 registers shifting out BCD data to 6 BCD to 7 segment driver chips. I'm trying to do a basic scroll right animation, and its turning out really lousy. if you send $f to the decoder, it will blank the digit. so basically i need to shift the following pattern out the 595 array.

Time var byte(3) is my byte array storing the time value
time = $00, $12, $13 for this example time is 13:12:00

$0F,$FF,$FF
$00,$FF,$FF
$20,$0F,$FF
$12,$00,$FF
$31,$20,$0F
$13,$12,$00

i have something put together, but its like 52 lines of code, and doesn't quite animate right.
      
   BLANK_DIS    'send out $FF,$FF,$FF                                    
    'example secs = 22
    tmpb1 = secs & $0F          'make secs 02                                        
    SWAP tmpb1                    'make secs 20
    tmpb1 = tmpb1 + $0F       'make secs 2f
    
    SHIFTOUT DataIO, Clk, MSBFIRST, tmpb1 '   shift out 2f
    PULSOUT HC595, 5 
    pause scrollspeed
    
    BLANK_DIS    ' blank display                                    
    
    SHIFTOUT DataIO, Clk, MSBFIRST, SECS     'shift out 22
    PULSOUT HC595, 5
    pause scrollspeed
    
    BLANK_DIS    
    
    tmpb1 = mins & $0F                                            
    SWAP tmpb1
    tmpb1 = tmpb1 + $0F
    
    
    SHIFTOUT DataIO, Clk, MSBFIRST, SECS 
    SHIFTOUT DataIO, Clk, MSBFIRST, tmpb1
    PULSOUT HC595, 5 
    pause scrollspeed

    BLANK_DIS    
    
    SHIFTOUT DataIO, Clk, MSBFIRST, SECS 
    SHIFTOUT DataIO, Clk, MSBFIRST, mins
    PULSOUT HC595, 5 
    pause scrollspeed
    
    BLANK_DIS
    
    tmpb1 = HRS & $0F                                            
    SWAP tmpb1
    tmpb1 = tmpb1 + $0F

    SHIFTOUT DataIO, Clk, MSBFIRST, SECS 
    SHIFTOUT DataIO, Clk, MSBFIRST, mins
    SHIFTOUT DataIO, Clk, MSBFIRST, tmpb1
    PULSOUT HC595, 5 
    pause scrollspeed
    
    BLANK_DIS
    
    SHIFTOUT DataIO, Clk, MSBFIRST, SECS 
    SHIFTOUT DataIO, Clk, MSBFIRST, mins
    SHIFTOUT DataIO, Clk, MSBFIRST, hrs
    PULSOUT HC595, 5 
    pause scrollspeed




thanks in advance!

Comments

  • JonnyMacJonnyMac Posts: 9,212
    edited 2009-12-08 05:11
    The trick is that you use four bits per digit. What you might consider is writing a routine that can map any [noparse][[/noparse]valid] 7-segment value into the appropriate nib; once have all have been updated you can shift out the works.
  • skynuggetskynugget Posts: 172
    edited 2009-12-08 14:47
    thanks Mr. Mac! [noparse][[/noparse]again :>]

    i started off trying to accomplish what you suggested, and hit a wall. i can figure out how to isolate the nibs, but putting them where they need to go in a display buffer array, and figuring out with nibs need blanked is over my head.
    here is where i am so far:
    
    anbuf     var byte(3)         ' nibs 1 - 6
        
    PUT_NIB    
    'use: put_nib  byte, highnib location, lownib location 
    ' if location is 0, then nib is off display
      
      iobyte var __param1
      hinib    var tmpb1
        lonib    var tmpb2
        hiidx var __param2    
        loidx    var __param3
    
    
        hinib = iobyte >> 4
        lonib = iobyte AND $0F        
               
        'put the hignib somwhere
        if hiidx = (an even number)
            hinib = secs AND $0F
        else 'highidx is an odd number 
            swap hinib
            hinib = hinib |$0F
        endif    
        
        hiidx = hiidx // 6    'figure out wich byte it goes in
        put anbuf(hiidx) hinib
    
        'same for lonib
    
    

    Post Edited (skynugget) : 12/8/2009 7:40:03 PM GMT
  • JonnyMacJonnyMac Posts: 9,212
    edited 2009-12-08 20:41
    Most times simpler is better. Consider these three (dirt simple) functions that do what you want. They are easy to use and don't require any program variables -- the functionality is so simple it can be handled in assembly using SX/B's internal parameter variables.

    NIB_LO          FUNC    1, 2, 2, Byte, Byte, Byte
    NIB_HI          FUNC    1, 2, 2, Byte, Byte, Byte
    MERGE           FUNC    1, 2, 2, Byte, Byte, Byte
    



    ' Use: bResult = NIB_LO target, value
    ' -- moves value into low nibble of target
    ' -- value truncated to four bits
    
    FUNC NIB_LO
      ASM
        AND   __param1, #$F0                        ' clear low nib
        AND   __param2, #$0F                        ' truncate to 4 bits
        OR    __param1, __param2                    ' merge
      ENDASM
      ENDFUNC
    
    
    ' Use: bResult = NIB_HI target, value
    ' -- moves value into high nibble of target
    ' -- value truncated to four bits
    
    FUNC NIB_HI
      ASM
        AND   __param1, #$0F                        ' clear high nib
        AND   __param2, #$0F                        ' truncate to 4 bits
        SWAP  __param2                              ' move value to high nib
        OR    __param1, __param2                    ' merge
      ENDASM
      ENDFUNC
    
    
    ' Use: bResult = MERGE value1, value2
    ' -- merge two 4-bit values into a byte
    ' -- value1 to high nibble, value2 to low nibble
    ' -- values truncated to four bits
    
    FUNC MERGE
      ASM
        AND   __param1, #$0F                        ' truncate to 4 bits
        SWAP  __param1                              ' move to high nibble
        AND   __param2, #$0F                        ' truncate to 4 bits
        OR    __param1, __param2                    ' merge
      ENDASM
      ENDFUNC
    



    I know, I know... Assembly is supposed to be "hard." Well, it really isn't and I am frequently adding very efficient Assembly sections to my SX/B programs.
  • skynuggetskynugget Posts: 172
    edited 2009-12-08 23:28
    lol, do you think would could come up with a replicator in assembly, so i can email you a beer? thanks again john, i will play with these tonight.
  • skynuggetskynugget Posts: 172
    edited 2009-12-12 21:17
    and a week later of pulling my hair out and i still haven't come up with a usable routine, using the nib functions, that will scroll the time in from the left. is there some unbelievably simple solution that I'm overlooking?
  • ZootZoot Posts: 2,227
    edited 2009-12-13 15:37
    Since you don't have 32 digits or anything like that, the easiest thing to do might be to set up a display buffer -- an array for all the digits -- the actual values you want to display are already taken care of, so on each "frame" of the scrolling, you'll need to copy the values over to the buffer in their new positions. The buffer is what would actually be "sent" to the display.

    Why don't you ATTACH your full program.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    When the going gets weird, the weird turn pro. -- HST

    1uffakind.com/robots/povBitMapBuilder.php
    1uffakind.com/robots/resistorLadder.php
  • JonnyMacJonnyMac Posts: 9,212
    edited 2009-12-13 18:10
    I agree with Zoot on both points.
  • skynuggetskynugget Posts: 172
    edited 2009-12-13 23:38
    thanks guys,
    i get what your saying about using a display buffer, but the whole thing that is throwing a wrench in shifting half a byte, i guess.

    anyway here is what im working with so far source/schematic, its basically the bs2 ds1302 timer ported over, on top of JohnnyMacs PWM ISR routine that i use for dimming digits.

    the thing thats neat about using bcd through the shift registers, is that there is a bcd to anything driver chip out there, i guess that's why i started out the way i did.
  • JonnyMacJonnyMac Posts: 9,212
    edited 2009-12-14 02:56
    As and idea... you could rename the nibble write routines and create complimentary read routines. For example:

    ' Use: bResult = RD_NIB_LO value
    ' -- returns low nibble of value
    
    FUNC RD_NIB_LO
      ASM
        AND   __param1, $0F                         ' clear high nibble
      ENDASM
      ENDFUNC
    
    
    ' Use: bResult = RD_NIB_HI value
    ' -- returns high nibble of value
    
    FUNC RD_NIB_LO
      ASM
        AND   __param1, $F0                         ' clear low nibble
        SWAP  __param1
      ENDASM
      ENDFUNC
    
    
    ' Use: bResult = WR_NIB_LO target, value
    ' -- moves value into low nibble of target
    ' -- value truncated to four bits
    
    FUNC WR_NIB_LO
      ASM
        AND   __param1, #$F0                        ' clear low nib
        AND   __param2, #$0F                        ' truncate to 4 bits
        OR    __param1, __param2                    ' merge the nibbles
      ENDASM
      ENDFUNC
    
    
    ' Use: bResult = NIB_HI target, value
    ' -- moves value into high nibble of target
    ' -- value truncated to four bits
    
    FUNC WR_NIB_HI
      ASM
        AND   __param1, #$0F                        ' clear high nib
        AND   __param2, #$0F                        ' truncate to 4 bits
        SWAP  __param2                              ' move value to high nib
        OR    __param1, __param2                    ' merge
      ENDASM
      ENDFUNC
    
    
    ' Use: bResult = MERGE value1, value2
    ' -- merge two 4-bit values into a byte
    ' -- value1 to high nibble, value2 to low nibble
    ' -- values truncated to four bits
    
    FUNC MERGE
      ASM
        AND   __param1, #$0F                        ' truncate to 4 bits
        SWAP  __param1                              ' move to high nibble
        AND   __param2, #$0F                        ' truncate to 4 bits
        OR    __param1, __param2                    ' merge
      ENDASM
      ENDFUNC
    



    Now you could do something like this to scroll the digits left (blanking the right-most display element):

    SUB DISPLAY_LEFT
      SWAP hrs                              ' move 1s to 10s position
      tmpB1 = RD_NIB_HI mins                ' get 10s from next section
      hrs = WR_NIB_LO tmpB1
      SWAP mins
      tmpB1 = RD_NIB_HI secs
      secs = WR_NIB_LOW tmpB1
      SWAP secs
      secs = WR_NIB_LOW $F                  ' blanking value
      ENDSUB
    



    Note that this is not designed to be cute or clever (i.e., optimized), it is meant to be obvious and easy. Running this routine six times with a delay in between will scroll the time off. Now... if you want the seconds to be updating during the scrolling, well, that's going to take some more work. Try this first, then move on to that if it is a requirement.
  • JonnyMacJonnyMac Posts: 9,212
    edited 2009-12-14 03:35
    Since you're not using an ISR to update the digits you could keep the time running while scrolling like this:

    Scroll_Off:
      FOR digits = 1 TO 6
        GET_TIME
        FOR idx = 1 TO digits
          DISPLAY_LEFT
        NEXT
        SHOW_TIME
        DELAY_MS 1_000    
      NEXT
    
  • skynuggetskynugget Posts: 172
    edited 2009-12-14 21:49
    Thanks for the aha moment, i get it now!

    how about this?

    SHIFT_LEFT: 
    tmpb1 = GET_LONIB hrs
    tmpb2 = GET_HINIB mins
    hrs = merge tmpb1,tmpb2
    tmpb1 = GET_LONIB mins
    tmpb2 = GET_HINIB secs
    mins = merge tmpb1,tmpb2
    tmpb1 = GET_LONIB secs
    secs = merge tmpb1,$F
    
    SHIFT_RIGHT:
    tmpb1 = GET_LONIB mins
    tmpb2 = GET_HINIB secs
    secs = merge tmpb1,tmpb2
    tmpb1 = GET_LONIB hrs
    tmpb2 = GET_HINIB mins
    mins = merge tmpb1,tmpb2
    tmpb1 = GET_HINIB hrs
    hrs = merge $F, tmpb1
    
    



    Subs/Funcs:
    ' Use: bResult = GET_LONIB value
    ' -- returns high nibble of value
    
    FUNC GET_LONIB
      ASM
        AND   __param1, #$0F                         ' clear high nibble
      ENDASM
      RETURN
        ENDFUNC
    
    ' -------------------------------------------------------------------------
    ' Use: bResult = GET_HINIB value
    ' -- returns high nibble of value
    
    FUNC GET_HINIB
      ASM
        AND   __param1, #$F0                         ' clear low nibble
        SWAP  __param1
      ENDASM
      RETURN
        ENDFUNC
    
    ' -------------------------------------------------------------------------
    ' Use: bResult = MERGE value1, value2
    ' -- merge two 4-bit values into a byte
    ' -- value1 to high nibble, value2 to low nibble
    ' -- values truncated to four bits
    
    FUNC MERGE
      ASM
        AND   __param1, #$0F                        ' truncate to 4 bits
        SWAP  __param1                              ' move to high nibble
        AND   __param2, #$0F                        ' truncate to 4 bits
        OR    __param1, __param2                    ' merge
      ENDASM
      RETURN
      ENDFUNC
    
    




    Declarations:
    GET_LONIB   FUNC    1, 1, 1, byte
    GET_HINIB   FUNC    1, 1, 1, byte
    MERGE       FUNC    1, 2, 2, Byte, Byte, Byte
    
    

    Post Edited (skynugget) : 12/14/2009 10:08:18 PM GMT
  • JonnyMacJonnyMac Posts: 9,212
    edited 2009-12-15 04:48
    Does it work? Remember, none of us has your hardware -- you get to have the real fun running test code through your setup; we're limited to tossing spaghetti at the wall to see if any sticks!
  • skynuggetskynugget Posts: 172
    edited 2009-12-15 07:15
    o gash im sorry, yeah it works great, i guess i should have phrased that better.
Sign In or Register to comment.