Shop OBEX P1 Docs P2 Docs Learn Events
Separating a variable — Parallax Forums

Separating a variable

TCTC Posts: 1,019
edited 2013-12-08 16:37 in Propeller 1
Hello all,

Well the max7219 project is coming along, but I need to find a way to take a variable and split it into its individual digits. I know how to do it on the BS2, but I have never even tried it with the prop. Here is what I mean:

Counter = 12345

digit0 = 1
digit1 = 2
digit2 = 3
digit3 = 4
digit4 = 5

Here is the kicker, I don't want someone just to post a code and say here you go. How can I learn from that? I just want to know where should I look to figure it out. And any advice that would help.

Thanks
TC

Comments

  • Phil Pilgrim (PhiPi)Phil Pilgrim (PhiPi) Posts: 23,514
    edited 2013-12-06 14:14
    Here's a hint, then: a // 10 gives the remainder of a divided by 10, i.e. the last digit of a.

    -Phil
  • TCTC Posts: 1,019
    edited 2013-12-06 14:23
    Here's a hint, then: a // 10 gives the remainder of a divided by 10, i.e. the last digit of a.

    -Phil

    Ok, so you are saying:

    counter = 12345
    digit0 := counter//10 = 1
    digit1 := counter//100 = 2
    digit2 := counter//1000 = 3
    digit3 := counter//10000 = 4
    digit4 := counter//100000 = 5
  • Mike GreenMike Green Posts: 23,101
    edited 2013-12-06 14:27
    Nope. digit0 := counter // 10 gives 5 when counter is 12345. digit1 := counter // 100 gives 45 and digit2 := counter // 1000 gives 345. That's more hint. The rest is an "exercise for the reader". Even more hint: What happens when you use / and //?
  • TCTC Posts: 1,019
    edited 2013-12-06 14:31
    Mike Green wrote: »
    Nope. digit0 := counter // 10 gives 5 when counter is 12345. digit1 := counter // 100 gives 45 and digit2 := counter // 1000 gives 345. That's more hint. The rest is an "exercise for the reader". Even more hint: What happens when you use / and //?

    Cool, I will get back to you when I figure it out. Thank You
  • TCTC Posts: 1,019
    edited 2013-12-06 15:03
    I just want to make sure I am killing my brain for the correct way. the max7219 needs a digit placement, then the value of that digit.
    Repeat digit from 1 to 5
       "something gets value of counter's digit"
        "load the MAX7219
    

    let me know if that is still where I should look. Because I cant figure out how to do what I need to do, yet.
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-12-06 15:20
    If you're always using five digits you can start with a divisor of 10000. Run the loop five times, extracting each digit as shown above, then dividing the divisor by 10 at the end of the loop so that it's the correct value for the next digit.

    How can I learn from that?

    Your parents didn't tell you how to walk, they showed you! :) Programming can be same. Take the bits given to you and expand on them.
  • TCTC Posts: 1,019
    edited 2013-12-06 15:33
    JonnyMac wrote: »
    If you're always using five digits you can start with a divisor of 10000. Run the loop five times, extracting each digit as shown above, then dividing the divisor by 10 at the end of the loop so that it's the correct value for the next digit.




    Your parents didn't tell you how to walk, they showed you! :) Programming can be same. Take the bits given to you and expand on them.

    I thought of something like that right as the queen(wife) decided she wanted to go out and get something to eat. Once I get home I will try my idea.
  • TCTC Posts: 1,019
    edited 2013-12-06 16:39
    Ok, I think I got it
        repeat digit from 5 to 1
           numb := countr//10
           countr := countr/10
    
    JonnyMac wrote: »
    Your parents didn't tell you how to walk, they showed you! :) Programming can be same. Take the bits given to you and expand on them.

    I agree with you, but we all fell down, cried, then got back up and tried again...... then pooped... :smile:

    I had to throw that in there. I wanted to be shown just the tools, it works for me to figure out how to use those tools.
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-12-07 06:52
    Did your version work? Here's mine, with commentary after.
    pub extract(value, p_buf) | divisor, digit
    
    '' Extract (up to) 5-digit value to array at p_buf
    
      if (value =< 0)
        bytefill(p_buf, 0, 5)
        return
    
      if (value => 99999)
        bytefill(p_buf, 9, 5)
        return
    
      divisor := 10_000
    
      repeat digit from 0 to 4
        byte[p_buf][digit] := value / divisor                       ' extract digit
        value //= divisor                                           ' remove digit from value
        divisor /= 10                                               ' fix divisor for next digit
    


    Note that this routine will extract a 5-digit value to a byte array -- not directly to the MAX7219. Why? For flexibility. I would make a MAX7219 method which allows you to point at an array of bytes. That way you can point to DAT tables or calculated arrays (like we are using here). Again, the idea is flexibility. Let's say you had a byte array called digitsbuf; in your program you might have this:
    extract(somevalue, @digitsbuf)
      update_7219(@digitsbuf)
    


    Note that the extract() method looks for upper and lower boundary values -- no need to run the loop if a value is on or past a boundary. In the loop you see the correct order of things: extract a digit with division; update the value (which removes the digit) with modulus; then update the divisor before running again. This order is critical.

    Have fun!
  • TCTC Posts: 1,019
    edited 2013-12-07 08:08
    Yes, my way worked. This is what I have that works.
     repeat
          temp := counter 
          repeat digit from 3 to 1
            numb := temp//10
            temp := temp /10
            display.Load_7219(digit, numb)
    
        !outa[23]
        counter := counter + 1
    
    I only have 3 7-segment displays right now, will have 5 when digi-key order gets here.
    I have so much more to do, like being able to control the DP, and to be able to control LEDs also digi-key.

    I do like your way though, because the LEDs are going to have to do a pattern depending on a value. And it would be easy (I think) to make the pattern and just point to where it is at. I also like that the digits goes from 0 to 4, not like mine where I had to go backwards.
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-12-07 10:00
    You make a valid point vis-a-vis the order of digits in the buffer; it really ought to correspond to the the segment registers in the MAX7219. I added a byte array to my (yet to be tested) MAX7219 object and updated the method like this:
    pub extract(value) | divisor, digit
    
    '' Extract positive value to segments array
    
      if (value =< 0)
        bytefill(@segments, 0, 8)
        return
    
      if (value => 99_999_999)
        bytefill(@segments, 9, 8)
        return
    
      divisor := 10_000_000
    
      repeat digit from 7 to 0
        segments[digit] := value / divisor                          ' extract digit
        value //= divisor                                           ' remove digit from value
        divisor /= 10                                               ' fix divisor for next digit
    


    This only extracts the value so you don't have to worry about the size of the display you're using -- a separate method call moves the buffer to the display.
  • TCTC Posts: 1,019
    edited 2013-12-07 14:12
    JonnyMac wrote: »
    You make a valid point vis-a-vis the order of digits in the buffer; it really ought to correspond to the the segment registers in the MAX7219. I added a byte array to my (yet to be tested) MAX7219 object and updated the method like this:

    This only extracts the value so you don't have to worry about the size of the display you're using -- a separate method call moves the buffer to the display.

    Well, so far your object is working great for displaying numbers.
  • TCTC Posts: 1,019
    edited 2013-12-07 15:32
    I added decimal point control to your method, tell me what you think, and if there is something you would do different. I have not tried it yet, I am re-building a 7219 object.
      if DP => 0 and  DP =< 7
        byte[segments][DP] |= |< 7
    
      else
        repeat digit from 7 to 0
          byte[segments][digit] &= ! |< 7
    
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-12-08 08:08
    Assuming your display is setup in DECODE mode, you don't need the else clause as the digit extraction process will clear bit7 of all registers. Just add the if clause that sets the decimal point after the digits extraction.

    I like to keep things very flexible. Here's are the methods from the object I'm working on that handle the extraction, setting/clearing decimal point, and writing a buffer to any part of the the display. You may wonder why bothering with internal and external buffers. Well, this lets you setup multiple buffers that you can switch back and forth very quickly using the write_buf() method. And it's setup to be very flexible, too, allowing you to write a buffer to any (contiguous) portion of the display.
    pub out(reg, value) | bits
    
    '' Update register in MAX7219 with value
    
      bits.byte[3] := reg                                           ' set register
      bits.byte[2] := value                                         ' set value
    
      repeat 16                                                     ' shift out reg + value
        outa[mosi] := (bits <-= 1)
        outa[sck] := 1
        outa[sck] := 0
    
      outa[load] := 1                                               ' load into MAX7219
      outa[load] := 0
    
    
    pub extract(p_buf, value) | divisor, digit
    
    '' Extract positive value to array at p_buf
    '' -- if p_buf is zero, use internal segments array
    
      if (p_buf =< 0)
        p_buf := @segments                                          ' use internal array
    
      if (value =< 0)
        bytefill(p_buf, 0, 8)
        return
    
      if (value => 99_999_999)
        bytefill(p_buf, 9, 8)
        return
    
      divisor := 10_000_000
    
      repeat digit from 7 to 0
        byte[p_buf][digit] := value / divisor                       ' extract digit  
        value //= divisor                                           ' remove digit from value
        divisor /= 10                                               ' fix divisor for next digit
    
    
    pub set_dpoint(p_buf, digit)
    
    '' Sets decimal point segment for selected digit register
    '' -- if p_buf is zero, use internal segments array
    
      if (p_buf =< 0)
        byte[p_buf][digit] |= _DPOINT   
      else
        segments[digit] |= _DPOINT
    
    
    pub clear_dpoint(p_buf, digit)
    
    '' Clears decimal point segment for selected digit register
    '' -- if p_buf is zero, use internal segments array
    
      if (p_buf =< 0)
        byte[p_buf][digit] &= !_DPOINT  
      else
        segments[digit] &= !_DPOINT
    
    
    pub write_buf(p_buf, n, reg)
    
    '' Writes n (1 to 8) bytes at p_buf to MAX7219
    '' -- if p_buf is zero, use internal segments array
    '' -- reg (1..8) is first register to write
    '' -- uses existing register modes
    
      if (p_buf =< 0)
        p_buf := @segments                                          ' use internal array
    
      n <#= (9 - reg)                                               ' keep n legal
    
      repeat n                                                      ' write n registers
        out(reg++, byte[p_buf++])
    


    I've attached the full source of the object I'm working on. As I have no hardware setup at the moment, perhaps you could run it for me. :)

    08-DEC-2013 : Corrected error in code identified in post #16 (fix in #17).
  • TCTC Posts: 1,019
    edited 2013-12-08 13:58
    JonnyMac wrote: »
    I've attached the full source of the object I'm working on. As I have no hardware setup at the moment, perhaps you could run it for me. :)

    I would be honored to.

    everything works, but
    pub set_dpoint(p_buf, digit)
    
    '' Sets decimal point segment for selected digit register
    '' -- if p_buf is zero, use internal segments array
    
      if (p_buf := 0) '<----- had to remove"<" to get it to work 
        byte[p_buf][digit] |= _DPOINT   
      else
        segments[digit] |= _DPOINT
    

    I had to do the same thing to clear_dpoint

    I made a demo for it, and everything worked out great. If you are happy with it, please add it to the OBEX.

    Thanks for all your help

    Video of the demo
  • JonnyMacJonnyMac Posts: 9,107
    edited 2013-12-08 15:58
    Whoops... I had my statements in the wrong place -- it should have been this:
    pub set_dpoint(p_buf, digit)
    
    '' Sets decimal point segment for selected digit register
    '' -- if p_buf is zero, use internal segments array
    
      if (p_buf =< 0)
        segments[digit] |= _DPOINT                                  ' internal buffer   
      else
        byte[p_buf][digit] |= _DPOINT                               ' external buffer
    
    
    pub clear_dpoint(p_buf, digit)
    
    '' Clears decimal point segment for selected digit register
    '' -- if p_buf is zero, use internal segments array
    
      if (p_buf =< 0)
        segments[digit] &= !_DPOINT 
      else
        byte[p_buf][digit] &= !_DPOINT
    
  • TCTC Posts: 1,019
    edited 2013-12-08 16:37
    That did it, and the file is fixed as well. Again, if you would like, please upload it to OBEX so others can use it. I dont want to upload it because I feel you should get all the credit for it.
Sign In or Register to comment.