Shop OBEX P1 Docs P2 Docs Learn Events
SPIN "VAR" Theory Question — Parallax Forums

SPIN "VAR" Theory Question

I have been tinkering with Mr. McPhalen's "jm_sled4c_demo". I have a ten LED bar graph connected to the MC14489BPE chip. I started typing the program again so I would always have the original for when I screw it up trying to figure out how to program the chip through the Propeller. I came across my first issue... I ran the program after completion of typing it. The LEDs did not perform in the same manner as Mr. McPhalen's program.

I found the VAR section I copied, by me typing, was not the same. I had put the "disp1, disp2,..." in numbered order instead of "disp5, disp4,...".

Question: Why would reversing the declaration of variables affect the program from the original?

I thought the variables got declared and the programming didn't care in what order, just as long as they were there.

Comments

  • JonnyMacJonnyMac Posts: 8,912
    edited 2017-11-13 01:41
    I thought the variables got declared and the programming didn't care in what order, just as long as they were there.
    Most of the time that is true, but in some cases we use a block of variables as an implicit array and the order of declaration matters. It does in this program. I should have put a comment in the VAR section to warn not to do this. If you look at the code you'll see this:
      bytefill(@dpctrl, 0, 6)
    
    This line fills dpctrl and the next five bytes with 0 -- if you changed the order variables are declared you could be fouling other variables, or even the top of your code.

    To update the display, we manipulate the display registers and then do this:
      shiftout(@dpctrl, 6, 4)
    
    Note that we're passing the address of dpctrl and telling the method that we want to send six bytes (dpctrl plus the next five bytes in RAM). The display expects those bytes to arrive in a specific order -- if you change the order of declaration you will foul the display.

    You could, of course, call shiftout() six times with the individual byte in the order the display wants, but that would be clunky:
      shiftout(@dpctrl, 1, 4)
      shiftout(@disp5, 1, 4)
      shiftout(@disp4, 1, 4)
      shiftout(@disp3, 1, 4)
      shiftout(@disp2, 1, 4)
      shiftout(@disp1, 1, 4)
    
    You'd also have to change the code that sets all display registers to zero.

    I wrote shiftout() the way I did so an address and the number of bytes are passed so that a display update call can be handled in a single line. The requirement for this is that the display register variables appear in a specific order.
  • Jon,

    Thank you for responding so quickly and for the little theory class. I learn alot better by understanding the underlying theory about why something was wrote the way it was. I am trying to do the Science_Fiction LED program that is in the Stamp Works Manual that you authored. I have no idea even where to begin to transpose BASIC into SPIN due to I am still learning how to use SPIN. I completed the PE Kit Lab Manual but even that material still has me scratching my head...missing some of the theory about why the program was written the way it was.

    I got the below code to look like the Science_fiction LEDs,,,I think. Remember the LEDs on the black Trans Am 80's TV show? Trying to do that with the MC14489. Works straight off the Propeller, but I think there is a better way. I'm having trouble seeing past this code.

    repeat
    repeat 10

    if outa[0..9] == 0
    outa[0..9] := %1000000000

    waitcnt(clkfreq/16 + cnt) ' Looks better with divide by 32
    outa[0..9] >>= 1

    repeat 10

    if outa[0..9] == 0
    outa[0..9] := %0000000001

    waitcnt(clkfreq/16 + cnt) ' Looks better with divide by 32
    outa[0..9] <<= 1

    I'm not asking to write you to write the code but could you provide me a more efficient programming path to take? In addition, could you and other members suggest which keywords and direction to take to program the MC14489 to do the same thing; the Science_Fiction LEDs. Thank you.
  • JonnyMacJonnyMac Posts: 8,912
    edited 2017-11-13 18:39
    Gunny (May I call you that? -- I was a SSgt in the USAF/R),

    I started learning BASIC in 1980 and in 1994 bought my first BASIC Stamp. You don't always have to do things the direct Spin way -- you can use objects to make the code a bit more "comfortable." That's part of the point of objects and libraries. The display you're talking about is called a Larsen scanner, named for Glen A. Larson who created Battlestar Galactica (Cylons) and the Knightrider (Kitt car) that used this display. I live and work in Hollywood, so I have lots of practice with the Larson scanner.

    Using my io and time objects, I can make the code more like PBASIC. Here's how I would rewrite your basic scanner:
      repeat
        repeat 10
          repeat pin from 0 to 8
            io.high(pin)
            time.pause(60)
            io.low(pin)
          repeat pin from 9 to 1
            io.high(pin)
            time.pause(60)
            io.low(pin)
    
    For people coming from PBASIC, this is pretty easy to understand.

    Note that I use offset groups for the back and forth motion -- this keeps the ends from having an undesirable bounce delay.

    Creating a Larsen scanner on discrete outputs is easy; it's going to be a pain-in-the-backside using the MC14489. Why? Because the "No Decode" mode -- that you need for individual bit control -- only controls segments A..D, E..G are turned off, H (decimal point is quirky to control). You might want to reconsider using this chip for Larsen scanners.

    Since it may be all you have, for giggles I did a quick review of the MC14489 data sheet and came up with this. Given the limits of the MC14489, you max out a 20 individual LEDs for the Larsen scanner.
    pub main | bit, reg                                                   
                                                                     
      setup
    
      config := %00111111                                           ' set config byte (no decode on all)
      shiftout(@config, 1, 8)                                         ' send it
    
      bytefill(@dpctrl, 0, 6)                                       ' initialize array
    
      repeat
        repeat bit from 0 to 18                                     ' forward
          larsen := 1 << bit                                        '  update bit position
          repeat reg from 0 to 4                                    '  loop thru display regs
            disp1[reg] := larsen & %1111                            '   get nibble from larsen bits
            larsen >>= 4                                            '   adjust for next nibble
          shiftout(@dpctrl, 6, 4)                                   '  update outputs
          time.pause(60)                                            '  hold  
          
        repeat bit from 19 to 1
          larsen := 1 << bit               
          repeat reg from 0 to 4           
            disp1[reg] := larsen & %1111   
            larsen >>= 4                    
          shiftout(@dpctrl, 6, 4)          
          time.pause(60)
    

    For fun, you can see a different take on a Larsen scanner in this picture of artist and cosplayer Shea Standefer wearing a Cylon dress at San Diego Comic Con a few years ago. This uses smart LEDs (WS2812) so I was able to create a blended effect for a larger "eye" spot that fades off at the edges. Shea was able to control the animation of the Cylon display during her stroll down the catwalk. We also had an "up close" mode (dim) for the after party that would not blind the guests.

    17a765b41e3d0ff145695bab115299a7.jpg

    You can see of the pictures of my "Hollywood" stuff on my Pinterest page:
    -- https://www.pinterest.com/jonmcphalen/techno-art/

    Notice that it's all about very fancy control of LEDs -- sometimes a whole lot of them. Almost all of the project on the page are controlled with the Propeller (sometimes multiples), all coded in Spin.

    I've attached a couple archives with the code ideas so you have access to my io and time objects. They're very simple, and I use them in every program I write.
  • Jon,

    Sure! You can call me Gunny! Once a Marine, Always a Marine!

    Thank you for sending me your program code for the io and time objects. I do recall seeing these before and how they were used. I should be able to implement them easy enough.
  • HBD 242, Gunny
  • OOH RAH!!

    Thank you, MrBi11!!
  • TheTech69TheTech69 Posts: 51
    edited 2019-06-15 11:21
    Jon,

    I still haven't been able to get the code to work for the MC14489 chip. I think I will work on getting one LED to light on the bar graph to hopefully understand programming the MC14489 through the Propeller. Interpreting the data sheet is fairly easy. Creating the SPIN code to speak the other IC's language is another matter all together.

    I'll post the code on here of my attempt when I'm settled in up in Stockholm, Sweden. There for a business trip. Thank you.

    Edited: June 15, 2019 - Changed "I still have..." to "I still haven't..." Only 4 LEDs perform the Larsen Scan. Verified wiring twice but will check again.
  • JonnyMacJonnyMac Posts: 8,912
    edited 2017-11-25 14:54
    Well, I don't have an loose MC14489 to play with -- and I'm on the road this week as well. I'll see if I can get a chip sent to my home so that I can work with it next weekend.
    Creating the SPIN code to speak the other IC's language is another matter all together.
    That's not been my experience. I find Spin an simple and elegant language and I have been able to connect to any chip I want. Everything seems easier once it's working.

    Are you connecting the LEDs correctly? Do you have a contrast resistor connected between pin Rx (8) and ground?

    I just came across this doc. I has C code for running the MC14489 -- maybe it will help.
    http://www.echelon.com/assets/blt85b95ec26736d95c/005-0014-01C.pdf
  • Just out of curiosity, why use the MC14489 for a Bar Graph? This chip seems more suited for a 7-segment display.

    The LM3914N-1 would be a much better choice for a Bar Graph or LED Chaser display.
  • Hello from Stockholm!

    JonnyMac

    I do have the contrast resistor connected between the pin 8 and ground. I know how mush you emphasize studying the data sheet. So I ensure I do that. The third time through the data sheet I realized I had some connections to pins that were not going to be used in no-decode mode. When I run your "jm_sled4c_demo" the bar graph LED works just fine. I'm still tinkering with the code to try to send a command to turn on one of the LEDs in the bar graph.

    JonM,

    I had the MC14489 as an extra component in my extra parts box from my time in the Marine Corps. I saw the exercise in Stamp Works using the MC14489 so I thought I would try it. Yeah, this chip is for 7-segment displays but I thought I try a bar graph because I had one in the extra parts box.

    Thank you for responding and taking interest so I may learn how SPIN works.
  • Ok, I finally was able to get one LED to turn on using the MC14489 connected to a 10 LED Bar Graph. I figured out that I needed to send 24 bits of data (3 bytes) to the MC14489.

    However... I can only get 8 of the LEDs to work. I do not know yet the issue is. It could be:

    1. Wiring sequence needs to be redesigned
    2. 24 bits of data isn't correct to turn on the last 2 LEDs.

    OBJ

    VAR

    byte config
    byte dpctrl
    byte larsen

    pub main | bit, reg

    dira[D_PIN] := 1 ' set pins
    dira[C_PIN] := 1
    outa[E_PIN] := 1
    dira[E_PIN] := 1


    config := %00111111 ' set config byte (no decode on all)
    shiftout(@config, 1, 8) ' send it

    ' bytefill(@dpctrl, 0, 6) ' initialize array

    repeat
    larsen := %000000000000000010000000
    shiftout(@config, 3, 8)

    pub shiftout(pntr, count, bits) | work

    '' pntr : address of byte(s) to shift out
    '' count : number of bytes to shift out
    '' bits : number of bits per byte to shift out
    ''
    '' assumes E_PIN, C_PIN, and D_PIN are set as outputs

    bits := 1 #> bits <# 8 ' fix if out of bounds

    outa[E_PIN] := 0 ' enable
    repeat count
    work := byte[pntr++] ' get a byte
    repeat bits
    outa[D_PIN] := (work >> (bits-1)) & %1 ' MSB first
    work <<= 1 ' next bit
    outa[C_PIN] := 1 ' clock the bit
    outa[C_PIN] := 0

    outa[E_PIN] := 1 ' disable

    I am working on drawing the schematic in CAD program. Also, the LED flickers instead of appearing steady sometimes. Not sure what is happening there. I was wondering if it had something to do with the system clock settings.

    As you all can tell I have not figured out how to exactly use the
    
    
    Thank you.
  • Jason,
    In the top bar of the leave a comment, there ie a Capital "C". If you click on that, and put your code in between the tags it will retain its formatting and we will be able to see if there are any formatting errors.
    Jim
  • Let's try the code entry...
    CON
    
    _xinfreq = 5_000_000
    _clkmode = xtal1 + pll16x
    
      CLK_FREQ = ((_clkmode - xtal1) >> 6) * _xinfreq
      MS_001   = CLK_FREQ / 1_000
      US_001   = CLK_FREQ / 1_000_000
    
      RX1   = 31
      TX1   = 30
      SDA   = 29
      SCL   = 28
    
      D_PIN =  12
      C_PIN =  14
      E_PIN =  13
    
    OBJ
    
    VAR
    
      byte  config
      byte  dpctrl
      byte  larsen
    
    pub main | bit, reg                                                   
    
      dira[D_PIN] := 1                                              ' set pins
      dira[C_PIN] := 1
      outa[E_PIN] := 1
      dira[E_PIN] := 1
                                                                     
      
      config := %00111111                                           ' set config byte (no decode on all)
      shiftout(@config, 1, 8)                                         ' send it
    
    '  bytefill(@dpctrl, 0, 6)                                       ' initialize array
    
    repeat
      larsen := %000000000000000010000000
      shiftout(@config, 3, 8)
    
    pub shiftout(pntr, count, bits) | work
    
    '' pntr  : address of byte(s) to shift out
    '' count : number of bytes to shift out
    '' bits  : number of bits per byte to shift out
    ''
    '' assumes E_PIN, C_PIN, and D_PIN are set as outputs
    
      bits := 1 #> bits <# 8                                        ' fix if out of bounds
    
      outa[E_PIN] := 0                                              ' enable 
      repeat count
        work := byte[pntr++]                                        ' get a byte
        repeat bits
          outa[D_PIN] := (work >> (bits-1)) & %1                    ' MSB first
          work <<= 1                                                ' next bit
          outa[C_PIN] := 1                                          ' clock the bit
          outa[C_PIN] := 0
            
      outa[E_PIN] := 1                                              ' disable
    

    The main code that this is based off of was written by JonnyMac.

    Thank you
  • PublisonPublison Posts: 12,366
    edited 2017-12-04 16:23
    Looks much better! :) Those Code tags make a big difference.
  • In VAR you have a "byte larsen", but in your "repeat you are trying to put 24 bit in larsen".
    A byte is only 8 bit, so something weird can happen!
  • Frida,

    True I list Larsen as a byte. I am still learning SPIN so I do not know where to start, to try and create a QWORD (4-bytes) type of method. Even though there is flickering of the LEDs, I am still able to get 8 of the 10 LEDs to turn on. I really believe the issue is in wiring the a, b, c, d outputs of the MC14489 to the 10 LED bar graph.
  • I'm thinking that larsen is the data you are trying to send to the 14489. If so, your second call to shift out() is
    shiftout(@config, 3, 8)
    

    but it should be:
    shiftout @larsen, 3, 8
    

    Also, frida is correct in that you should define larsen as
    long larsen
    

    Who or what is larsen?
  • Jeff HaasJeff Haas Posts: 416
    edited 2017-12-05 00:26
    A "Larsen Scanner" is the visual effect of lights bouncing back-and-forth, as popularized by two TV shows: Knight Rider and Battlestar Galactica (both produced by Glen A. Larsen). Here's a quick video of the front of the car on YouTube:

  • Tom Crawford,

    I had tried changing my shiftout statement that you pointed out to read @Larsen vice @config. No LEDs turned on when I did that. When I changed it back to @config the LEDs worked fine again. I just tried changing byte larsen to long larsen AND changed the shiftout statement. The LEDs do not work. I tried leaving "long larsen" and changed the shiftout statement to @config and the LEDs do not work.

    I think larsen has to be declared as a byte due to the shiftout method asking how many bytes to shift and the number of bits at a time to shift also. Just a theory I really wish I knew.

    Thank you all for assisting me with this. I'll keep plugging away.
  • The code is going to shift out the top three bytes of larsen. Try setting larsen to all ones.

    tom

    SSGT E6 over 6 P2 (1967)
  • JonnyMac's example is really byte-oriented, which could be confusing in this case. Here is a sample that might be easier to get your head around.

    Note that you have to change the pin assignments (D_Pin, etc) back to what you are using. I changed them to match pins I already had connected to a logic analyzer (I did check the code and it certainly shifts the bits out). I cannot tell you for sure what the MC14489 will do because I don't have one wired up.
    {Object_Title_and_Purpose}
    
    
    CON
            _clkmode = xtal1 + pll16x       'Standard clock mode * crystal frequency = 80 MHz
            _xinfreq = 5_000_000
            D_Pin = 1, C_Pin = 2, E_Pin = 3
    
    VAR
      long larsen
      
    PUB main
        dira[d_pin] := 1
        dira[c_pin] := 1
        outa[e_pin] := 1     'make this come up high
        dira[e_pin] := 1
    
        shift(%00111111, 8)    'send the control byte
        larsen := 1
        repeat 24
          shift(larsen, 24)             'send larsen
          larsen := Larsen << 1         'go to next LED
          waitcnt(clkfreq/100 + cnt)    'pause for effect
          
    
    {{Shift(value,count) shifts out #count# bits.  Count must be equal to or less than
    32.  The bits are right-aligned in #value#.  Most Significant First}}      
    
    PUB Shift(value, count)
        outa[E_Pin] := 0      'enable
        value := value << (32-count)    'align first bit at 31
        repeat count                    'however many bits we need to shift
          outa[D_Pin] := 0
           if (value & $8000_0000) <> 0  'test high bit
              outa[D_Pin] := 1           'set data pin if needful
           outa[C_Pin] := 1              'clock the bit into the mc14489
           outa[C_Pin] := 0   
           value := value << 1           'align next bit
        outa[D_Pin] := 0                 'cosmetic   
        outa[E_Pin] := 1                 'disable
    
           
              
    
    
            
    
  • JonnyMac's example is really byte-oriented, which could be confusing in this case. Here is a sample that might be easier to get your head around.
    In my demo code -- which the OP said works -- the Larsen value is declared as a long and its bytes are moved to the display registers that are generic to the component.
Sign In or Register to comment.