Shop OBEX P1 Docs P2 Docs Learn Events
Xbee AT commands — Parallax Forums

Xbee AT commands

dermotdermot Posts: 26
edited 2012-01-11 07:57 in Accessories
Hi,

I'm using Xbee Series1 devices controlled by the Prop. I want to change the ATDL quickly in spin. How can I do this as fast as possible?? Currently I use "XB.AT_ConfigVAL(string("ATDL"),$11)" for example. I find this too slow.

What I am trying to do is accept a value to a base and send a value to a remote device as a response but the information is coming in to the base too quickly. I cannot keep configuring the Xbee DL value fast enough.

Any help will be great

Thanks

Comments

  • Roger LeeRoger Lee Posts: 339
    edited 2011-12-30 20:15
    Hello dermot,

    It looks like you are using "XBee Object Library" by Martin Hebel.
    That is an excellent program and has helped me very much.

    Did you follow the instructions to use XB.AT_Init at start to allow fast configuration?

    You ask
    How can I do this as fast as possible??
    What kind of speed are you looking for?

    Roger.
  • dermotdermot Posts: 26
    edited 2011-12-31 07:49
    I current use Martin Helbel Xbee Object. I use the command AT_Init once at the start of the program. I then use the AT_ConfigVal routine to change the destination address. But this requires almost 300mS to execute, as seen from the routine in the object below.
    PUB AT_ConfigVal(stringptr,val)
    {{
      Send a configuration string for AT Mode with a value
      XB.AT_Config(string("ATMY"), My_Addr)
      FOR Transparent (Non-API) MODE USE
      Be sure to issue XB.AT_Init once at startup
    }}
        delay(100)
        str(string("+++"))
        delay(100)
        rxflush
        str(stringptr)
        hex(val,4)
        tx(13)
        str(string("ATCN"))
        tx(13)
        delay(10)
    
    

    I wish to execute this entire routine in under 100mS, preferable around 50mS. Is this possible?? Can I reliably change the destination address that quickly????
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2011-12-31 11:38
    Use API mode. The destination address is included without having to go to command mode.

    E.g.
    XB.API_Str(2,string("Hello number 2")) ' Send data to destination address 2
  • dermotdermot Posts: 26
    edited 2012-01-02 10:25
    I have tried changing all the program over to API mode instead of AT mode. This has prooved more difficult than anticipated. I have implemented it onto the main controller and one end device to begin. I reset both XBee modems to their Default configuration.

    The following is the code for the controller. This is ment to activate an Led on the end device but it does nothing!!
    XB.start(XB_Rx, XB_Tx, 0, XB_Baud) ' Initialize comms for XBee
      XB.AT_Init
      XB.AT_Config(string("ATAP 1",13))  ' Configure XBee for API Mode
    
      XB.API_Str(0,num.ToStr(2,num#DEC))
    

    I send a decimal value of number 2 to destination address 0. The end device has the following code
    XB.start(XB_Rx, XB_Tx, 0, XB_Baud) ' Initialize comms for XBee
    XB.AT_Init
    
    XB.AT_Config(string("ATAP 1",13))  ' Configure XBee for API Mode
    
    
    Begin
       
    
    
    Pub Begin
    
     repeat
      DataIn := XB.ParseDec(XB.RxData,1)             ' Wait for and accept decimal value
    
      If DataIn == 2                 ' Check input  (Turn on red light strip)
          outa[red]~~
          outa[orange]~
          outa[green]~
          outa[blue]~
    

    Can anyone see why this will not work??
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-01-03 10:22
    dermot,

    I received your PM. Sorry but my XBees are the ZigBee version (Series 2). I doubt they would work the same as your Series 1 XBees.

    One thing I often do when debugging wireless connections to send lots of data to a serial terminal from both devices. And instead of use the normal tx, char or out method, I use a method that checks to see if the character is a printable character before sending it to the terminal. If it's not printable, I have it display the hexadecimal value in the terminal window.
    PRI TbugTx(localCharacter)
      if (localCharacter > 31 and localCharacter < 127)' or localCharacter == 13
        'Tv.out(localCharacter)
        'Pst.char(34)
        Pst.char(localCharacter)
        'Pst.char(34)
        'Pst.char(32)
        
      else
        'Tv.out(60)
        'Tv.out(36)
        Pst.char(60)
        Pst.char(36)
       
        TbugHex(localCharacter, 2)
        'Tv.out(62)
        Pst.char( 62)
       
        
    PRI TbugHex(localHex, localSize)
     
      'Tv.hex(localHex, localSize)
      Pst.hex(localHex, localSize)
     
    

    You'll notice I have calls to a "TV" object that are presently commented out. The above methods make it easy to switch between a TV and terminal window as a debug screen.

    I used the name Tbug because I originally used it with a TV screen as a debug window.
  • Tracy AllenTracy Allen Posts: 6,664
    edited 2012-01-04 11:57
    Dermot, I too received your PM. Nothing jumps out at me that is wrong with your code. With the default settings, that means that DL and MY are both zero and the channels and pan IDs match--but it always deserves a recheck. If your XBee carriers have activity lights, you can see if something, anything is happening.

    I've not used the decimal parsing within the XBee object. With a single byte command such as you have, it should be possible to use the single byte commands, rather than going to the trouble of string conversion on one end and parsing on the other. KISS:

    transmit:
    XB.API_tx(0, 2) ' send one byte, ascii code 2, to DL=0.

    receive:
    if byte[XB.RxData][0] == 2 ' receive one byte, test if it is ascii code 2.

    It is extremely useful to be able to visualize the data received on a serial terminal, at least during development. If you have a XBee/USB adapter, then use X-CTU terminal mode to see HEX API packets being received, to get sense of how they are structured and to see if your transmitted packet is what you expect. On the Prop, open another serial port for debugging to the terminal screen. In API mode, Martin's object also parses out items such as the packet length, the RSSI and the sender's origin address. From a troubleshoooting standpoint, you asked the question of whether a "2" command is making it through, but step back and ask if anything at all is coming through.

    Another approach if you want to fall back to transparent mode, would be to cut the delay in AT_ConfigVal down from 100ms to say 10ms or 20ms. You should be able to do that, because the AT_Init command had set the guard time to a squeaky thin 3 milliseconds. That should allow you to meet your 50ms criterion. You had this working in transparent mode, right, but it was just too slow?
  • dermotdermot Posts: 26
    edited 2012-01-10 09:16
    Thanks for the help almost have the API configured just one sticky point.

    The main controller will transmit in API and the remote devices will receive in API. This all takes place in the main cog.

    I am running another cog in the remote devices to transmit back to the controller in API. However this does not work at all!!!! The cog is definitely been activated but no communication! Does anyone know why this might be??
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-01-10 09:56
    You'll get into a lot of trouble trying to communicate with the same device from multiple cogs. The two different cogs are likely to leave the pins in a state where the other cog can't use them. It's better to have the other cog set a flag to tell the communication cog to send the message. Use a buffer both cogs know the location to store the outgoing message.
  • dermotdermot Posts: 26
    edited 2012-01-10 11:28
    Duane Degn wrote: »
    You'll get into a lot of trouble trying to communicate with the same device from multiple cogs. The two different cogs are likely to leave the pins in a state where the other cog can't use them. It's better to have the other cog set a flag to tell the communication cog to send the message. Use a buffer both cogs know the location to store the outgoing message.

    2 Cogs confusing the XBee does make since. I'll try using the flag method. What exactly do you mean by "Use a buffer both cogs know the location to store the outgoing message. ".
  • Duane DegnDuane Degn Posts: 10,588
    edited 2012-01-11 07:57
    dermot,

    I tried to find a simple example of using flags as a signal between cogs. All the code I found was really complicated so I wrote a small example program to show what I mean.
    CON
      _Clkmode = xtal1 + pll16x
      _Xinfreq = 5_000_000
      _DebugBaud = 57600
      _RedLed = 16 ' I'm using the QuickStart LEDs for testing.
      _OrangeLed = 17
      _GreenLed = 18
      _BlueLed = 19
      
    VAR
      long stack[32]
     
      word txPointer
      
    OBJ
      Com : "FullDuplexSerial"
    PUB Setup
      
      ' Make LED pins outputs, they will start out in the off (low state)
      dira[_RedLed]~~ 
      dira[_OrangeLed]~~
      dira[_GreenLed]~~
      dira[_BlueLed]~~
      Com.Start(31, 30, 0, _DebugBaud)
      waitcnt(clkfreq * 4 + cnt) ' time to open serial terminal
      cognew(Output, @stack) 
      MainLoop
       
    
    PUB MainLoop | DataIn
     repeat
      DataIn := Com.rxCheck
      if DataIn <> -1
        case DataIn
          "r", "R": outa[_RedLed]~~
          "o", "O": outa[_OrangeLed]~~
          "g", "G": outa[_GreenLed]~~
          "b", "B": outa[_BlueLed]~~
          "x", "X": 
            outa[_RedLed]~
            outa[_OrangeLed]~
            outa[_GreenLed]~
            outa[_BlueLed]~
          other: Com.str(@menuText)
      if txPointer <> 0
        Com.str(txPointer)
        txPointer := 0 
        
    PUB Output | secondsTime, menuTime, tenInterval, menuInterval
      txPointer := @menuText        ' display menu right away
      tenInterval := clkfreq * 10
      menuInterval := clkfreq * 13 ' 13 seconds
      secondsTime := cnt
      menuTime := cnt
      repeat
        ' check to see if ten seconds has passed
        if cnt - secondsTime > tenInterval  
          secondsTime += tenInterval  ' Add ten more seconds
          repeat while txPointer <> 0 ' optional, to make sure last message was displayed
          txPointer := @tenSeconds
        ' check to see if menuInterval (13 seconds) has passed  
        if cnt - menuTime > menuInterval   
          menuTime += menuInterval
          repeat while txPointer <> 0 ' optional, to make sure last message was displayed
          txPointer := @menuText
    
          
    DAT
    menuText      byte 13, 13, "  Please Enter Selection", 13
                  byte 13, "  Enter ", 34, "r", 34, " to turn on red LED."
                  byte 13, "  Enter ", 34, "o", 34, " to turn on orange LED."
                  byte 13, "  Enter ", 34, "g", 34, " to turn on green LED."
                  byte 13, "  Enter ", 34, "b", 34, " to turn on blue LED."
                  byte 13, "  Enter ", 34, "x", 34, " to turn off all LEDs.", 0 ' this final zero terminates the string
    tenSeconds    byte 13, 13, "Ten seconds have passed since this was last displayed.", 0              
                  
    

    In this case I used a pointer as a flag. When the pointer "txPointer" equals zero the first cog (cog 0) knows there's nothing to transmit. If "txPointer" doesn't equal zero, it uses the value stored in "txPointer" to locate the string to send.

    Sending output from two cog mainly causes trouble when they both send the output at the same time. The two transmissions end getting merged into one garbled message. There are other ways around this problem. Locks can be used to tell the other cogs some resource is presently being use.
Sign In or Register to comment.