Shop OBEX P1 Docs P2 Docs Learn Events
Generic Prop programming question — Parallax Forums

Generic Prop programming question

sylvie369sylvie369 Posts: 1,622
edited 2010-04-24 17:16 in Propeller 1
Here's a question I have that's probably pretty commonplace. I have a project that has one cog receiving data constantly while other cogs do things like update an LCD screen. That's working fine.

I've recently added indicator lights and a buzzer, all controlled by simply making I/O pins high or low. The lights are "set and forget", so they're no problem. That's all working fine already. But the buzzer pin needs to be set high for a certain amount of time, and then taken low again (that is, I don't want the buzzer buzzing constantly - just for a second or so, and then off again). The other cogs need to be continuing to read data and control the LCD screen while I'm using the buzzer. Clear?

So it seems like I should write a simple method that turns on the buzzer for a certain amount of time, and then off again, and run that method in a new cog each time I run it (so that the other cogs can continue to do their things):

Pub Buzz(Duration)
  OUTA[noparse][[/noparse]Buzzpin] := 1
  Delay(Duration)
  OUTA[noparse][[/noparse]Buzzpin] := 0
 
Pub Main
  Some stuff before I want to sound the buzzer
  Cognew(Buzz(1000), @Buzzstack)
  Some other stuff, and then I want to sound the buzzer again
  Cognew(Buzz(1500), @Buzzstack)


The problem - if I understand things correctly, each time I run the Buzz method in a new cog, I "use up" (as it were) that cog, so after buzzing a couple of times, it's going to stop working, right?

So I assume the answer is to identify the cog that was started when I called the Buzz method, and explicitly release that cog after I'm done buzzing, so it's available again the next time I want to call Buzz.

Am I making this far more complicated than it needs to be?

But if I do something like this

Pub Buzz(Duration)
  OUTA[noparse][[/noparse]Buzzpin] := 1
  Delay(Duration)
  OUTA[noparse][[/noparse]Buzzpin] := 0

Pub Main
  Some stuff before I want to sound the buzzer
  BuzzCog := Cognew(Buzz(1000), @Buzzstack)
  Cogstop(BuzzCog)
  Some other stuff, and then I want to sound the buzzer again
  BuzzCog := Cognew(Buzz(1500), @Buzzstack)
  Cogstop(BuzzCog)


I'd think it would try to stop the cog while the buzzer was still sounding. And if·I put the Cogstop inside of Buzz, how is it going to know the ID of the cog it's trying to stop?

I'll bet there's some straightforward way of doing this, and I'm just missing it, right?

Comments

  • kwinnkwinn Posts: 8,697
    edited 2010-04-13 22:21
    I would not use a separate cog just to turn a buzzer on and off. You must have a loop somewhere in the cog that decides when the buzzer needs to be on where you could set a variable to "cnt + buzzer_on_time" and check to see if "cnt" exceeds that variable to turn the buzzer off.

    Is the main routine you show above is repeated constantly ? If so set the pin on and initialize the timer variable where you now start a cog and compare "cnt" to the variable where you now stop the cog and set the pin to off if "cnt" is equal or greater.
  • kuronekokuroneko Posts: 3,623
    edited 2010-04-13 23:29
    sylvie369 said...
    I'd think it would try to stop the cog while the buzzer was still sounding. And if I put the Cogstop inside of Buzz, how is it going to know the ID of the cog it's trying to stop?

    cogstop(cogid)
    
  • localrogerlocalroger Posts: 3,452
    edited 2010-04-14 00:00
    If you cogstop a cog, its DIRA and OUTA revert to zero, so the buzzer will stop. But you might still stop it in mid-buzz, which would sound funny. Another approach would be to have the other cog monitor INA on the same pin; it can read whether the buzzer is buzzing and only stop the buzzer cog if it's off.
  • kuronekokuroneko Posts: 3,623
    edited 2010-04-14 00:01
    kuroneko said...
    sylvie369 said...
    I'd think it would try to stop the cog while the buzzer was still sounding. And if I put the Cogstop inside of Buzz, how is it going to know the ID of the cog it's trying to stop?

    cogstop(cogid)
    

    Having said that - and getting half way through my coffee - once the Buzz() method finishes, the buzzing cog stops automatically.
  • w8anw8an Posts: 176
    edited 2010-04-14 00:26
    If you have a cog you want to devote to the buzzer, you can just give it the task of buzzing for a moment when a global flag is set true.

    Here's an example:

    CON
           _clkmode = xtal1+pll16x
           _xinfreq = 5_000_000
           BUZZER_PIN  = 24            'pin the buzzer is hooked to
    
    VAR
            long stack[noparse][[/noparse]10]
            long sound_the_buzzer
    
    PUB MainProgram
      cognew(BuzzerProcess, @stack[noparse][[/noparse]0]) 'start the buzzer processor
      sound_the_buzzer := true         'make the buzzer buzz
      waitcnt(clkfreq*4+cnt)           'delay 4 seconds
      sound_the_buzzer := true         'make the buzzer buzz again
      repeat 'forever                  'end
      
    PUB BuzzerProcess                      
      dira[noparse][[/noparse]BUZZER_PIN]~~               'set pin as output
      repeat
        if sound_the_buzzer            'make some sound?
          sound_the_buzzer := false    'clear flag
          outa[noparse][[/noparse]BUZZER_PIN]~~           'turn on the buzzer
          waitcnt(clkfreq + cnt)       'wait one second
          outa[noparse][[/noparse]BUZZER_PIN]~            'turn off the buzzer
    
    



    Steve
  • DavidMDavidM Posts: 630
    edited 2010-04-14 01:14
    While we are all sharing "BUZZER" code here's mine..

    '' Controls a Piezo Buzzer  via a transistor using 1 pin.
    '' Uses a COG so as not to halt system
    '' BuzzerState = 0  = Not Running
    '' BuzzerState = >0 = Running
    
    VAR
    
        LONG BeeperStack[noparse][[/noparse]20]
        LONG BuzzerStatus
        LONG BuzzerPin
    
    PUB Init ( vBuzzerPin )
    
        BuzzerPin    := vBuzzerPin
        BuzzerStatus := 0
    
    PUB BeepFast          
    
        Beeper ( 25, 1, 1 )
              
    PUB Beep          
    
        Beeper ( 200, 1, 1 )
        
    PUB BeepShort          
    
        Beeper ( 50, 1, 1 )
    
    PUB BeepError    
    
        Beeper ( 100, 50, 3 )
    
    PUB BeepSave
    
        Beeper ( 500, 100, 2 )
     
    PRI Beeper ( OnDuration, OffDuration, NoOfBeeps )
    
        IF BuzzerStatus == 0    
           BuzzerStatus := COGNEW( BeepRun( OnDuration, OffDuration, NoOfBeeps ) , @BeeperStack )       
           
    PRI BeepRun ( OnDuration, OffDuration, NoOfBeeps )
        
        DIRA[noparse][[/noparse]BuzzerPin]  := 1
              
        REPEAT NoOfBeeps
        
          OUTA[noparse][[/noparse]BuzzerPin] := 1 
          WAITCNT((CLKFREQ/1000)*OnDuration+CNT)
          OUTA[noparse][[/noparse]BuzzerPin] := 0
          WAITCNT((CLKFREQ/1000)*OffDuration+CNT) 
    
        BuzzerStatus := 0
    
    
    



    In your main loop, first call

    Buzzer.Init(@BuzzerPin)


    Then, when you need to do a "BEEP" just use any of the PUB methods with preset durations and timings,

    eg

    BeepFast
    Beep
    BeepShort
    BeepError

    etc

    You can make up as many "beeps" as you like, I believe this is a waste of a cog, but if you have spare cogs , then keep it simple, But I am planning to do this different in the future with a global timer and Watch routine, As I have other things like LEDS that need to "BLINK" or stay on for short periods of time.


    Dave M
  • w8anw8an Posts: 176
    edited 2010-04-14 02:22
    A "wasted cog" is a cog that has nothing to do. smilewinkgrin.gif
  • DavidMDavidM Posts: 630
    edited 2010-04-14 03:17
    Hi wBAN,

    Yep you are 100% correct!, Thats a good way of thinking, But A cog can be under-utilised as well!

    by the way , my code to init the buzzer should be called as follows

    Buzzer.Init(BuzzerPin)

    NOT - Buzzer.Init(@BuzzerPin)

    Dave m
  • Cluso99Cluso99 Posts: 18,069
    edited 2010-04-14 03:37
    If you have a spare cog that can do the buzzing when required, then you could do the following
    • load the buz cog and put it in a waitpeq loop for the buz pin to go high. This takes minimal power.
    • When you want to buz, just pulse the buz pin from another cog.
    • The first cog will then buz and go back to waitpeq again.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Links to other interesting threads:

    · Home of the MultiBladeProps: TriBlade,·RamBlade,·SixBlade, website
    · Single Board Computer:·3 Propeller ICs·and a·TriBladeProp board (ZiCog Z80 Emulator)
    · Prop Tools under Development or Completed (Index)
    · Emulators: CPUs Z80 etc; Micros Altair etc;· Terminals·VT100 etc; (Index) ZiCog (Z80) , MoCog (6809)·
    · Prop OS: SphinxOS·, PropDos , PropCmd··· Search the Propeller forums·(uses advanced Google search)
    My cruising website is: ·www.bluemagic.biz·· MultiBlade Props: www.cluso.bluemagic.biz
  • MagIO2MagIO2 Posts: 2,243
    edited 2010-04-14 05:36
    I think this sentence of the original post has been totally ignored:

    "The problem - if I understand things correctly, each time I run the Buzz method in a new cog, I "use up" (as it were) that cog, so after buzzing a couple of times, it's going to stop working, right? "

    As far as I understand you, you believe that the COG will still be in use, even if the SPIN code has been finished. That's at least what explains the cogstop in the second code snippet of the original post.

    First of all:
    COGSTOP would stop the COG before it had a chance to run. Doing a COGNEW with a SPIN function means that a SPIN interpreter has to be loaded into the COG. This takes several thousand clocks while the COG which did the COGNEW can continue with the next instruction. From COGNEW to COGSTOP it will only need a few hundred clocks.

    When SPIN finishes a function (either by calling return or by implicit return because there are no more instructions) the last return in the call-stack will free the COG. The only reason for eating up COGs in your code is that you call COGNEW without waiting for it to finish (first code snippet). If you do this 7 times no more COGs will be free. And you have the problem that all 7 COGs use the same pin. So the Buzz function looks like not doing the right thing. Oh ... and your buzz function does not set dira. Each COG has it's own copy of dira which is defaulted to 0 when doing a COGNEW.

    Have a look at DavidM's code. He uses beepstatus to make sure that beep will only start one COG.
  • DavidMDavidM Posts: 630
    edited 2010-04-14 07:19
    HI MagIO2,

    Yes, My code works because the COG is release when when its finished, the status variable handles this.


    I use this code in several of my products it works!


    Also, I have many BEEP calls thought my designs, the advantage of my code is that ..

    a) You Call the BEEPER as much as you like, It won't hold up your main loop, use simple one line calls.
    b) You can call the beeper even if its running, but nothing will happen, but there are no hang ups!

    You can make up unique beep sounds and then give them simple meaningful names ( refer to my PUB Methods), that way you get consistency. but you don't need to type in any parameters ( i.e repeat, on time, or off time etc,) makes coding a lot simpler.


    Thanks
    Dave M
  • sylvie369sylvie369 Posts: 1,622
    edited 2010-04-14 22:42
    Thanks, all. I'm absorbing all of this.
    If I can get it to work I'll post how I wound up doing it. No luck so far, but I think I've got some good stuff here.

    BTW, I've got 5 cogs just sitting here looking for work. I'm trying to find them something to do before they start applying for unemployment.
  • sylvie369sylvie369 Posts: 1,622
    edited 2010-04-14 22:49
    MagIO2 said...
    Oh ... and your buzz function does not set dira. Each COG has it's own copy of dira which is defaulted to 0 when doing a COGNEW.
    Okay, now that explains a LOT of my problems. This is particularly good stuff. I was under the impression that I could set DIRA once at the start of my entire program, and all of the cogs would know that the pins controlling the lights and buzzer were outputs.

    You're saying that's not the case - that I should set DIRA inside the same method·that's trying to buzz the buzzer, right? (so that it's set for the cog running that method)
  • DavidMDavidM Posts: 630
    edited 2010-04-14 23:40
    HI Silvie,


    If your not getting anything working, Just try out my code I posted earlier.

    Make a new object called Buzzer.Spin

    Set this in your MAIN (TOP) Object, in the OBJ Block

    OBJ                   
     Buzzer        : "Buzzer.Spin"
    




    Then initialize the buzzer object.. ( just once )
    PUB Main
    Buzzer.Init (BuzzerPin)
    
    



    Then Somewhere in your main loop call your Beeper to run it

    Beep
    
    



    How are you hooking up your buzzer ? Do you have a schematic?


    Regards

    Dave M
  • sylvie369sylvie369 Posts: 1,622
    edited 2010-04-15 02:38
    David -

    I will try your code, per your instructions. It looks promising - maybe I'll get to it tomorrow. Thanks for the clear directions.

    My hookup to the buzzer is straightforward - it works fine when I'm just running a simple program, so I'm sure my issues are all programming, not wiring. When I take pin 16 high, the buzzer starts, and when I bring it low again, it stops. No problem there.
  • DavidMDavidM Posts: 630
    edited 2010-04-15 03:56
    Hi Sylvie,

    Are you using a transistor?

    I use a LOGIC LEVEL Mosfet, By buzzer I use is 6-15V ( run at 12V) Self Oscillating.

    In a previous post I have a schematic & PCB Layout that shows this if you wish to look at it.

    Dave M
  • MagIO2MagIO2 Posts: 2,243
    edited 2010-04-15 05:47
    sylvie369 said...
    You're saying that's not the case - that I should set DIRA inside the same method·that's trying to buzz the buzzer, right? (so that it's set for the cog running that method)
    Each COG has it's own set of special function registers. Two of these are DIRA and OUTA. If you set a value there in one COG the others won't see that. The way DIRA works is, that only the bits that are set there will allow to change the output state of the corresponding PINs via OUTA. As all SFR's are initialized with 0 during COGNEW/COGINIT, changing OUTA will have no effect when you forget to set DIRA correctly.

    And please keep in mind, that all OUTA of all COGs that use the same pins as output are OR ed together. Usually each COG should use a different set of PINs.

    So, yes ... in your case the buzz method should set DIRA before buzzing.
  • sylvie369sylvie369 Posts: 1,622
    edited 2010-04-15 09:06
    David -

    I'm using one of these:

    http://www.learn-c.com/tip120.pdf

    My buzzer is self oscillating as well: when I set the I/O pin high, it buzzes until I set it low again. Your code would work just fine, and in fact your BEEPRUN method is essentially what I've already been using to make it buzz.

    MagIO2 -

    Somehow I knew that the OUTAs were ORed together, but didn't realize that each cog had its own OUTA and DIRA. Still there's something else going on.
  • DavidMDavidM Posts: 630
    edited 2010-04-15 09:27
    Hi Sylvie,

    Did you try my code, I would like you to test out the different beep sounds, as I said it make you code easier to read and you will get consistent sounds.

    Also,

    That TIP120 Is overkill for a buzzer!

    Use something smaller like a BC337 if you want to use a transistor, You will need a series resistor!


    But Ideally you should use a MOSFET, like ZVN2106A

    A mosfet will not consume any Amperage from the prop pin, and you can drive the mosfet harder, you will not need a series resistor, But you may need a pull down resistor (10K) for start up reasons if you are fussy and depending on the mosfet.

    There are plenty of LOGIC LEVEL MOSFET'S that are inexpensive in both through-hole & SMD
    Regards

    Dave M
  • MagIO2MagIO2 Posts: 2,243
    edited 2010-04-15 11:16
    @Sylvie:

    give us your latest code and we can have a look.
  • ElectricAyeElectricAye Posts: 4,561
    edited 2010-04-15 13:28
    sylvie369 said...
    ....
    Somehow I knew that the OUTAs were ORed together, but didn't realize that each cog had its own OUTA and DIRA. Still there's something else going on.


    Take a look at pages 26-27 of the Propeller Manual. There are some simple rules provided that help clarify how the cogs handle the dira and outa details and this ORing business.

    smile.gif

    Prop Manual said...


    After boot up, any I/O pins can be used by any cogs at any time since I/O pins are one of the common resources. It is up to the application developer to ensure that no two cogs try to use the same I/O pin for conflicting purposes during run-time.

    The result of this I/O pin wiring configuration can easily be described in the following simple rules:
    A. A pin is an input only if no active cog sets it to an output.
    B. A pin outputs low only if all active cogs that set it to output also set it to low.
    C. A pin outputs high if any active cog sets it to an output and also sets it high.


    Any cog that is shut down has its Direction Register and output states cleared to zero, effectively removing it from influencing the final state of the I/O pins that the remaining active cogs are controlling.
    Each cog also has its own 32-bit Input Register. This input register is really a pseudo-register; every time it is read, the actual states of the I/O pins are read, regardless of their input or output direction.



    Post Edited (ElectricAye) : 4/15/2010 1:35:27 PM GMT
  • sylvie369sylvie369 Posts: 1,622
    edited 2010-04-18 22:01
    Update -

    I haven't had the time to work on the buzzer part of this, because the launch was this weekend (did I mention that my project is the receiver for my rocket telemetry thingie?). I discovered in setting up and testing on Wednesday that I had a bad power switch on the rocket, so fixing that took priority, and then I needed to get down to the rest of the wiring for the rocket.

    The good news - I flew the thing today, all-up, and it worked perfectly, and it wasn't nearly as cumbersome as I'd thought it might be. I had good altitude readout on an LCD screen during the flight, and a separate cog monitoring XBee pins set up for digital line passing responded quickly to report the deployments of the drogue and main parachutes. I flew low, and fortunately landed right in front of where I was standing, so I had the chance to see chutes come out and my green indicator lights go on immediately with each chute deployment. I did have the buzzer report landing, since there's no need to be concerned about losing data after that point, and that worked perfectly as well. The lights I used were visible in the direct noon sunlight, so I feel like it was worth the trouble of setting up the 12V system.

    I believe this is the 9th time I've flown with altitude telemetry, and the second time using a Prop as the receiver (the first 7 all used a BS2px board with the LCD Appmod that I still have set up right here). All of those flights were successful. This is also the second flight with pull-pins for reporting parachute deployment, and that worked perfectly both times as well. These last two flights were the only two that used the same altimeter for altitude reporting and for controlling the ejection charges - I was a little worried that something about sending down the data by radio might interfere with the ejection charges, but that just hasn't happened.

    I won't have the chance to get back to work on the buzzer thing until next week, but there's a while before the next launch anyway. The Prop is really shining in this use - it's really helpful to be able to do more than one thing at a time.
  • sylvie369sylvie369 Posts: 1,622
    edited 2010-04-24 17:16
    Okay, I added David M's code, and it works fine.

    http://s282.photobucket.com/albums/kk265/psmithalverno/?action=view&current=XMTelemetry14.flv

    For the fun of it, here's the code:

    ''**  XBee-MAWD Receiver with pull-pins   **
    ''**  and 12v-controlled indicator lights **
    ''**  and buzzer.                         **
    ''**  Paul C. Smith, April 24th, 2010     **
    ''XBee RX on pin 0
    ''XBee TX on pin 1
    ''LCD connected to pin 8. Parallax 4x20 LCD. 
    ''Pull-pins from XBee DIO0 to Prop pin 22, XBee DIO1 to Prop pin 23
    ''Event
    ''      Buzzer : Pin 16
    ''Lights for Event 1:
    ''      Red    : Pin 17
    ''      Green  : Pin 18 
    ''Lights for Event 2:
    ''      Red    : Pin 19
    ''      Green  : Pin 20
    {{ XBee Settings:
    Transmitter:
      Channel C                                             Can be any channel, but must match receiver
      PAN ID  3332                                          Can be any PAN ID, but must match receiver
      DH      0                                             Must be 0, to match receiver. 
      DL      0                                             Must be 0, to match receiver. 
      MY      1                                             Must be 1 so that I/O line data are properly bound
      NI      XM TX 0                                       This can be anything, but may be used specifically in later revisions
      D0      3 (DI)                                        Must be 3, to read I/O line pull-pin status
      D1      3 (DI)                                        Must be 3, to read I/O line pull-pin status
      IU      1 (ENABLE)                                    Doesn't really matter, as onboard UART not being used. Could be used for other functions, though. 
      IT      2 (Samples before TX)                         The IT and IR settings mean that the pull-pins are checked and reported...
      IR      1F4 (=500 msec sample rate)                   ...once every second (sample twice/second, transmit after two samples). This could be adjusted to taste. 
    Receiver:
      Channel C                                             Can be any channel, but must match transmitter
      PAN ID  3332                                          Can be any PAN ID, but must match transmitter
      DH      0                                             Doesn't really matter as this XBee is only being used to receive
      DL      0                                             Ditto
      MY      6 (Set by program to 0)                       Doesn't matter where it starts - program sets it properly. 
      NI      XM RECEIVER 6                                 This can be anything, but may be used specifically in later revisions
      D0      (Set by program to 5: DO HIGH)
      D1      (Set by program to 5: DO HIGH)
      IA      (Set by program to 1: Input Address 1, bind input to Module 1)
      IU      (Set by program to 0: Prevent I/O line data from going out UART)
    }}
    CON 
        _clkmode = xtal1 + pll16x      '80MHz operating frequency.
        _xinfreq = 5_000_000                      
        Hz    = 100
    OBJ 
      XB   : "XBee_Object"       
      Comm : "FullDuplexSerialPlus"  
      Num  : "Numbers"
      LCD  : "Debug_LCD"
      BS2  : "BS2_Functions"
      Buzz : "Buzzer"
    VAR     byte          Alt[noparse][[/noparse]6]       ' Variable to hold the first 6 bytes of altitude data from MAWD. First 5 bytes are 5 digits of altitude, then CR (then LF, unread).
            word          AltN         ' Variable to hold numerical value of altitude, after conversion from string. 
            word          MaxAlt       ' Variable to hold maximum altitude
            byte          Event1       ' Has pull-pin 0 pulled?
            byte          Event2       ' Has pull-pin 1 pulled?
            long          PinStack[noparse][[/noparse]65] ' Stack for cog running PinsCheck (stack size set by trial and error: 9 is too small, and overwrites E1).
            long          LCDStack[noparse][[/noparse]65] ' Stack for cog running LCDUpdate
            word          LCDBuffer[noparse][[/noparse]8] ' Variable to hold values to be displayed on the LCD.
                          { 0 - AltN
                            1 - MaxAlt
                            2 - Flight status: 0 = Ready, 1 = In flight, 2 = Landed
                            3 - Event 1: 0 = No event, 1 = Event
                            4 - Event 2: 0 = No event, 1 = Event
                            5 - Data received: 0 = No, 1 = Yes
                            6-7 (reserved)
                          }
            word          LCDBufOld[noparse][[/noparse]8] ' Temporary buffer to be compared with current contents to determine whether or not to update LCD.
            byte          temp, flag   ' General purpose variables
            byte          LandingFlag             ' Flags for landing detect, event 1 and event 2 status. 
            byte          Event1Flag, Event2Flag  ' Flags: False = event has not occurred.
                                                  '        True  = event has occurred.  
    Pub Start 
        XB.start(0,1,0,9600)           ' XBee Comms - RX,TX, Mode, Baud
        XB.AT_init
        XB.AT_Config(String("ATMY 0")) ' Config to receive as Module 0 to match XBee-MAWD telemetry output DL setting.
        DIRA[noparse][[/noparse]22..23]~                  ' Set pins 22 and 23 as inputs from the XBee I/O pins 0 and 1
        XB.AT_Config(String("ATD0 5")) ' Config to use XBee DIO pin 0 as a digital output, default HIGH
        XB.AT_Config(String("ATD1 5")) ' Config to use XBee DIO pin 1 as a digital output, default HIGH
        XB.AT_Config(String("ATIA 1")) ' Config to receive DIO data from module whose MY = 1. 
        XB.AT_Config(String("ATIU 0")) ' Config so that DIO pin states are not sent out UART, where they would interfere with alt data
        
        Num.init                       ' Initialize Numbers object used to convert alt input string to a number
        BS2.start (31,30)              ' Initialize BS2 object used to receive serial data from XBee
        Buzz.init(16)                  ' Initialize Buzzer object with output pin to buzzer
    ' Zero out the LCD buffers 
        temp := 0                       
        repeat while temp < 8
          LCDBuffer[noparse][[/noparse]temp] := 0         
          LCDBufOld[noparse][[/noparse]temp] := 0         
          temp := temp + 1  
        Cognew(LCDUpdate, @LCDStack)   ' Start the LCD updating method continuously in a separate cog. 
    ' Initialize Flight Variables
        AltN   := 0                    ' Start at 0 altitude
        MaxAlt := 0                    ' Set max altitude to 0 as well. 
        Event1 := %00000000            ' Clear the pull-pin variables 
        Event2 := %00000000            ' Event1 and Event2
                                       ' Clear flags for... 
        LandingFlag := False           '                 - Landing
        Event1Flag  := False           '                 - Event1  
        Event2Flag  := False           '                 - Event2 
         
        Cognew(PinsCheck, @PinStack)   ' Run the PinsCheck method continuously in a separate cog.
        Repeat while LCDBuffer[noparse][[/noparse]2] <> 3 ' While not "Landed"...
          If XMCheck                   ' If data received
            XMReceive                  ' Get and display the data
          Else
            XMBadData    
    Pub LCDUpdate                      ' Method to initialize LCD, display splash screen, screen labels, and then update the LCD display data. 
        LCD.init(8, 9600, 4)           ' Initialize LCD
        Pause(1500)                    ' Let the LCD settle in
        LCD.cls                        ' Clear the screen
        Splash                         ' Show startup screens
        LCD.cls
        Screenlabels                   ' Label the values
        LCD.gotoxy(9,2)
        LCD.str(String("Ready     "))
    ' Set up Indicator Lights and Buzzer
        DIRA[noparse][[/noparse]16..20]~~                 ' Set pins 16 through 20 as outputs to control lights and buzzer
        OUTA[noparse][[/noparse]16] := 0                  ' Turn off buzzer and green lights
        OUTA[noparse][[/noparse]18] := 0
        OUTA[noparse][[/noparse]20] := 0          
        OUTA[noparse][[/noparse]17] := 1                  ' Turn on red lights
        OUTA[noparse][[/noparse]19] := 1
        Repeat 4
          OUTA[noparse][[/noparse]16] := 1                ' Buzz four times, blink all lights to indicate ready.
          Pause(200)                    
          !OUTA[noparse][[/noparse]17..20]                ' Toggle indicator lights each time.
          OUTA[noparse][[/noparse]16] := 0
          Pause(200)                   ' Leave indicator lights at reds on, greens off.
    
        Repeat                         ' Repeat this part continuously...
         ' See if the LCD Buffer status has changed
          Flag := 0                    ' Clear change flag
          temp := 0                    ' Start with LCDBuffer[noparse][[/noparse]0]
          repeat while temp <  8       ' Step through the buffer locations
            if LCDBuffer[noparse][[/noparse]temp] <> LCDBufOld[noparse][[/noparse]temp]  ' If there is a change
              Flag := 1                ' Set the change flag
            temp := temp + 1
          ' If the LCD Buffer status has changed, update the LCD     
          If Flag                      ' If the change flag is set
            LCD.gotoxy(10,0)           ' Write the AltN variable to LCD
            LCD.decf(LCDBuffer[noparse][[/noparse]0],5)
            LCD.gotoxy(10,1)           ' Write the MaxAlt variable to LCD
            LCD.decf(LCDBuffer[noparse][[/noparse]1],5)
            LCD.gotoxy(9,2)            ' Write the flight status
            case LCDBuffer[noparse][[/noparse]2]
              0 : LCD.str(String("Ready     "))
              1 : LCD.str(String("Ascending "))
              2 : LCD.str(String("Descending")) 
              3 :
                LCD.str(String("Landed    "))
                If not LandingFlag      ' If Landing just detected, sound beeper to indicate landing 
                  Buzz.BeepLanding
                LandingFlag := True     ' Set LandingFlag so that Beep does not continue
            LCD.gotoxy(9,3)
            case LCDBuffer[noparse][[/noparse]3]           ' Write the value of pull-pin Event 1
              0 :
                LCD.str(String("No "))
                OUTA[noparse][[/noparse]17] := 1           ' Set the Event 1 indicator lights to red on, green off
                OUTA[noparse][[/noparse]18] := 0
              1 :
                LCD.str(String("Yes"))
                OUTA[noparse][[/noparse]17] := 0           ' Set the Event 1 indicator lights to red off, green on 
                OUTA[noparse][[/noparse]18] := 1
                If not Event1Flag       ' If Event1 just detected, sound beeper to indicate Event 1. 
                 Buzz.BeepEvent1
                Event1Flag := True      ' Set Event1Flag so that Beep does not continue. 
            LCD.gotoxy(15,3)
            case LCDBuffer[noparse][[/noparse]4]           ' Write the value of pull-pin Event 2
              0 :
                LCD.str(String("No "))
                OUTA[noparse][[/noparse]19] := 1           ' Set the Event 2 indicator lights to red on, green off 
                OUTA[noparse][[/noparse]20] := 0
              1 :
                LCD.str(String("Yes"))
                OUTA[noparse][[/noparse]19] := 0           ' Set the Event 2 indicator lights to red off, green on  
                OUTA[noparse][[/noparse]20] := 1
                If not Event2Flag       ' If Event2 just detected, sound beeper to indicate Event 2. 
                  Buzz.BeepEvent2
               Event2Flag := True       ' Set Event2Flag so that Beep does not continue. 
            temp := 0
            repeat while temp < 8
              LCDBufOld[noparse][[/noparse]temp] := LCDBuffer[noparse][[/noparse]temp]     ' Set the temporary buffer to reflect the current data
              temp := temp + 1
    Pub XMCheck : Success              ' Check to see if receiving data
      Success := XB.RxCheck
    Pub XMReceive                      ' Uses BS2 function to receive simply because I couldn't get the XBee object working
        BS2.SERIN_STR(0, @Alt, 9600, 1, 8)      ' Receive a CR-terminated string to Alt through pin 0
        Alt[noparse][[/noparse]5] := 0                             ' Convert to z-string for use by LCD and Num objects
        AltN := Num.FromStr(@Alt, %000_000_000_0_0_000110_01010 ) ' Convert to 5-digit number for use by MaxAlt
        if (AltN > MaxAlt) & (AltN < 50000)                       ' < 50000 check is to avoid bad data at landing
          MaxAlt := AltN
        LCDBuffer[noparse][[/noparse]0] := AltN                    ' Update the LCD buffer
        LCDBuffer[noparse][[/noparse]1] := MaxAlt                  '      with the new values
        If MaxAlt > 0                           ' If the rocket has launched...
          If AltN < 1                           ' Sometimes the Alt drops below 0 after landing - this accounts for that. 
            LCDBuffer[noparse][[/noparse]2] := 3                   ' Change flight status to "Landed".
          else
            If MaxAlt > AltN 
              LCDBuffer[noparse][[/noparse]2] := 2                 ' "Descending"
            else
              LCDBuffer[noparse][[/noparse]2] := 1                 ' "Ascending"
    Pub XMBadData
      LCDBuffer[noparse][[/noparse]5] := 0                         ' Set to indicate no reception
    Pub PinsCheck                                ' This will have to go into a different cog to run at the same time at the altitude data receiver.
      Repeat 
        Event1 := INA[noparse][[/noparse]22]                        ' Get value of input pin 22 
        Event2 := INA[noparse][[/noparse]23]                        ' Get value of input pin 23
        If Event1 <> %00000001                   ' Default is pulled high to 1
          LCDBuffer[noparse][[/noparse]3] := 1                      ' If it's not pulled high, flag that the event has occurred 
        else
          LCDBuffer[noparse][[/noparse]3] := 0                      ' Otherwise continue to indicate no event
        If Event2 <> %00000001                   ' Same for the other pull-pin
          LCDBuffer[noparse][[/noparse]4] := 1
        else
          LCDBuffer[noparse][[/noparse]4] := 0
    Pub Splash                         ' Display startup screen
      LCD.home
      LCD.backlight(TRUE)
      LCD.gotoxy(0,0)
      LCD.str(@Splash1)
      LCD.gotoxy(0,1)
      LCD.str(@Splash2)
      LCD.gotoxy(0,2)
      LCD.str(@Splash3)
      LCD.gotoxy(0,3)
      LCD.str(@Splash4)
      Pause(1000)
    '  LCD.backlight(FALSE)            ' Uncomment to turn off backlight after startup. 
    Pub Screenlabels
      LCD.gotoxy(0,0)
      LCD.str(String("Alt   : "))
      LCD.gotoxy(0,1)
      LCD.str(String("MaxAlt: "))
      LCD.gotoxy(0,2)
      LCD.str(String("Status: "))
      LCD.gotoxy(0,3)
      LCD.str(String("Events 1:    2:   "))
    PUB Pause(mS)
      waitcnt(clkFreq/1000 * ms + cnt)
    DAT                
      Splash1 byte "XM Telemetry ",0
      Splash2 byte "Version 1.4  ",0
      Splash3 byte "Paul C. Smith",0
      Splash4 byte "Apr 24, 2010 ",0
    





    Post Edited (sylvie369) : 4/24/2010 5:40:41 PM GMT
Sign In or Register to comment.