Shop OBEX P1 Docs P2 Docs Learn Events
Two Serial Ports — Parallax Forums

Two Serial Ports

mynet43mynet43 Posts: 644
edited 2010-08-02 03:25 in Propeller 1
Would someone please post some code showing how to use two serial ports at the same time?

I have one port with Rx, Tx on pins P12 and P13.

The other port has Rx, Tx on pins P14 and P15.

I'm familiar with using the serial routines like FullDuplexSerialPlus, etc. I've just never done two ports at once.

Thank you for your help.

Jim

Comments

  • T ChapT Chap Posts: 4,223
    edited 2010-08-01 01:13
    You could just use the 4 port serial object, the run 4 simultaneous ports at the same time on 4 sets of pins.
  • mynet43mynet43 Posts: 644
    edited 2010-08-01 02:17
    Thanks!

    I'll check that out.

    It sounds like it's just what I'm looking for.

    Jim
  • Duane DegnDuane Degn Posts: 10,588
    edited 2010-08-01 06:52
    mynet43,
    I often have a serial connection monitored in a separate cog.· This isn't the most efficient way to do this but it's easy for me to understand what is going on.

    There are several refinements I left out for clarity.· In this example I left the names of the devices I use (barcode & balance).· This object only receives data from the serial connections and assumes data terminates with a carriage return.· You'd want to use a different solution if you also want to send data over the lines(such as FullDuplexSerial).

    I'm using simpleSerial since I am "watching" the serial line a separate dedicated cog.

    If you use FullDuplexSerial you wouldn't need to start new cogs to watch the serial ports since FullDuplexSerial·runs in·its own cog anyway.· Just use rxcheck in the main loop to check for new received bytes.
    Hopefully·some of this will be useful to you.
    {  Balance and Barcode Read and Display Object
       by Duane Degn
       August 1, 2010
       This is a simplified version of a datalogging object I use.  I removed the
       datalogging, wireless communication, and lots of other stuff.
       This objets assumes data from both serial connections send data terminating with
       a carriage return (ASCII 13).
    }
    CON
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
      
      _balanceBaud = 4800
      _barcodeBaud = 2400
      ' Pin assignments
      _barcodeData = 8                                      ' through 10KΩ resistor (My barcode reader is 5V device)
      _balanceData = 10
      
      _LargeBufferSize = 64
       
    VAR
      long barcodeStack[noparse][[/noparse]32], balanceStack[noparse][[/noparse]32]
      
      byte barcodeFlag, balanceFlag
      byte balanceBuffer[noparse][[/noparse]_LargeBufferSize], barcodeBuffer[noparse][[/noparse]_LargeBufferSize]
      
     
    OBJ
      Balance : "Simple_Serial"
      Barcode : "Simple_Serial"
      Tv : "tv_terminal"  
      
    PUB Main | temp
     
      barcodeFlag := 0
      balanceFlag := 0
     
      Tv.Start(12)
      Tv.str(@title)
      Tv.out(13)  
      
      temp := cognew(WatchBarcode, @barcodeStack)
      waitcnt(clkfreq/10 + cnt)
      Tv.str(string("Barcode cog = "))
      Tv.dec(temp)
      Tv.out(13)
      temp := cognew(WatchBalance, @balanceStack)
      waitcnt(clkfreq/10 + cnt)
      Tv.str(string("Balance cog = "))
      Tv.dec(temp)
      Tv.out(13)
      
      ' **** Main Program Loop ****
      repeat
         
        if barcodeFlag == 1
          Tv.str(string("Barcode = "))
          Tv.str(@barcodeBuffer)
          barcodeFlag := 0
          'Tv.out(13)               ' in this case the barcodeBuffer has a carriage return at the end its line already.
          
        if balanceFlag == 1
          Tv.str(string("Balance = "))
          Tv.str(@balanceBuffer)
          'Tv.out(13)
          balanceFlag := 0
          
        ' Do other stuff
    
    PUB WatchBarcode | localCharacter, localIndex
     
      Barcode.init( _barcodeData, -1, _barcodeBaud)
      repeat
        barcodeBuffer[noparse][[/noparse]localIndex++] := Barcode.rx
        if barcodeBuffer[noparse][[/noparse]localIndex - 1] == 13
          barcodeFlag := 1
          localIndex := 0
          repeat while (barcodeFlag == 1)                 ' wait for string to be displayed by main loop
          bytefill(@barcodeBuffer, 0, _LargeBufferSize)
        
    PUB WatchBalance | localCharacter, localIndex  
     
      Balance.init( _balanceData, -1, _balanceBaud)
      repeat
        balanceBuffer[noparse][[/noparse]localIndex++] := Balance.rx
        if balanceBuffer[noparse][[/noparse]localIndex - 1] == 13
          balanceFlag := 1
          localIndex := 0 
          repeat while (balanceFlag == 1)                 ' wait for string to be displayed by RecordData loop
          bytefill(@balanceBuffer, 0, _LargeBufferSize)
     
    DAT
     
      title   byte    "Balance and Barcode Read and Display Object",0
    
    

    I haven't been able to get the 4 port serial object to work for me.· I think one of the methods I was using wasn't behaving well and keep the 4 port object from working.

    Duane
  • mynet43mynet43 Posts: 644
    edited 2010-08-01 13:24
    Hi Duane,

    Thank you for the example and your note about the 4-port serial interface.

    I've downloaded the 4-port serial code and I plan to test it in the next couple of days.

    I plan to run a loopback test, something like his sertest.spin. If this works, I think I'll be OK.

    Thanks again for your help.

    Jim
  • TimmooreTimmoore Posts: 1,031
    edited 2010-08-01 16:43
    mynet43, Let me know if you have any problem with the 4 port serial object

    Duane, what was the problem you had? I do have an updated version but it adds a couple of advanced features rather than fixing any bugs.
  • mynet43mynet43 Posts: 644
    edited 2010-08-01 19:54
    Hi Tim,

    Thanks for checking in on this.

    A couple of questions, since I haven't tried it yet.

    1. In your sertest.spin program, you use the constant NOMODE for the input mode parameter. Is this the correct constant to use for standard serial output?

    2. In the same program you're using pcFullDuplexSerial as the debug serial program. This isn't included in your zip file. It looks like a single port version because the calls only have one argument. I'm using FullDuplexSerialPlus for the debug routine. Is there an advantage to using the 'pc' version?

    3. Do you have a routine like 'getstr' in FullDuplexSerialPlus, or do I need to supply my own?

    My goal is to support two standard RS-232 I/O ports for both input and output. It looks like this should work fine.

    Am I on the right track?

    Thank you for your help.

    Jim
  • TimmooreTimmoore Posts: 1,031
    edited 2010-08-01 20:14
    mynet43 said...
    A couple of questions, since I haven't tried it yet.

    1. In your sertest.spin program, you use the constant NOMODE for the input mode parameter. Is this the correct constant to use for standard serial output?

    Yes, most of the time that is what works

    2. In the same program you're using pcFullDuplexSerial as the debug serial program. This isn't included in your zip file. It looks like a single port version because the calls only have one argument. I'm using FullDuplexSerialPlus for the debug routine. Is there an advantage to using the 'pc' version?

    No, it just happened to be the single port version I used when I started and built the 4 port version from.

    3. Do you have a routine like 'getstr' in FullDuplexSerialPlus, or do I need to supply my own?

    No there isn't such a routine but something like this should work

    PUB getstr(port, stringptr) | index
    ··· '' Gets zero terminated string and stores it, starting at the stringptr memory address
    ··· index~
    ··· repeat until ((byte[noparse][[/noparse]stringptr][noparse][[/noparse]index++] := rx(port)) == 13)
    ··· byte[noparse][[/noparse]stringptr][noparse][[/noparse]--index]~


    My goal is to support two standard RS-232 I/O ports for both input and output. It looks like this should work fine.

    Am I on the right track?

    You have a couple of options depending on what the 2 ports are for. To get chars from a port you need to call a rx routine, the standard version rx blocks until a char is received so you can't do anything else such as check the other port unless you use a cog per port, the other option is to use rxcheck, it checks and returns the char or -1 if none exists. for example

    · repeat while (Rx := uarts.rxcheck(port)) <> -1
    ··· uarts.tx(0,Rx)

    the above loops while port has chars and transmitts them on port 0, when there are no more chars the loop exits and you can do something else, the serial port code has a buffer for up to 64chars so as long as you do the loop every so often you will not loss chars.
    ·
  • mynet43mynet43 Posts: 644
    edited 2010-08-01 22:08
    Hi Tim,

    Thanks for the great answers. I think I'm off and running.

    Do you plan to put the getstr( ) routine in the code? If not, I'll probably stick it in my copy of your program. Or it wouldn't be much trickier to put it in the calling program.

    I also noticed you have a getc( ) entry that does the same thing as 'rxcheck', so I may use that.

    Final question. In the sertest routines, I noticed you use a second object for the debug port. Would it also work to use one of your multi-ports and just assign it pins 31 and 30 in the AddPort call?

    Thanks again for all your help. You've made it much easier to get started.

    Jim
  • Duane DegnDuane Degn Posts: 10,588
    edited 2010-08-01 22:37
    Tim,

    I doubt my problems were do to your object.· I was using an early version of Kye's SD card object (Kye has since stated it was full of bugs) and I'm guessing it didn't play nice with your object.· I had other troubles with the early SD object but I got it to work (I had to move some of my variables declared in a DAT section to the VAR section).· I plan on trying the four port serial object again with Kye's updated object.· It would save me several cogs (I'm always running out of cogs).

    Duane
  • Dr_AculaDr_Acula Posts: 5,484
    edited 2010-08-02 02:33
    Tim's 4 port serial object in 1 cog works brilliantly. It is the core of comms in the zicog/qZ80 retro emulation. It sounds like things are working now, but sing out something still isn't clear.

    Re
    PUB getstr(port, stringptr) | index
        '' Gets zero terminated string and stores it, starting at the stringptr memory address
        index~
        repeat until ((byte[noparse][[/noparse]stringptr][noparse][[/noparse]index++] := rx(port)) == 13)
        byte[noparse][[/noparse]stringptr][noparse][[/noparse]--index]~
    
    



    shoud that be "== 0" if you are looking for a zero terminated string? Or are you looking for a zero terminated string that ends in 0,13?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    www.smarthome.viviti.com/propeller
  • TimmooreTimmoore Posts: 1,031
    edited 2010-08-02 02:51
    I copied getstr from FullDuplexSerialPlus and changed it for the 4 port driver. It looks as though it gets a string until 13 and replaces the 13 with a 0. I wasn't planning on adding it to the 4 port driver, its not something I would use. I tend to use rxcheck with a state machine for processing input.
  • mynet43mynet43 Posts: 644
    edited 2010-08-02 03:25
    Hi Tim,

    I've been playing with it.

    I added the code for getstr( ) to the driver and it works perfectly with the PST.

    I wrote a test case to input from and output to the PST, using port 2.

    I've attached the modified pcFullDulplexSerial4FC with the getstr( ) routine. I may remove this and put it in the calling routine.

    Anyway, here's the test case. I'm running it on a demo board with a mouse attached. Everything works great!

    Thanks for all the help.

    Jim
    CON
    
      _clkmode = xtal1 + pll16x
      _xinfreq = 5_000_000
    
      DisplayPort = 0               ' Uart Port Number for Display Interface
      Display_RX  = 12              ' Display RX Pin
      Display_TX  = 13              ' Display TX Pin
      
      Serial_Port = 1               ' Uart Port Number for 2nd Serial Port for Comm Interface
      Serial_RX   = 14              ' Serial RX Pin
      Serial_TX   = 15              ' Serial TX Pin
    
      Debug_Port  = 2               ' Uart Port Number for debug port to Prop Plug
      Debug_RX    = 31              ' Debug RX Pin
      Debug_TX    = 30              ' Debug TX Pin
    
    OBJ
      mouse : "mouse"               ' Mouse Control Routine
      uart  : "pcFullDuplexSerial4FC-getstr" '1 COG for 4 serial ports
      
    VAR
      long  mouse_x, mouse_y
      byte  strinp[noparse][[/noparse]128]
    
    PUB start
      ' start serial I/O routine
      uart.Init
      uart.AddPort(DisplayPort,Display_RX,Display_TX,UART#PINNOTUSED,UART#PINNOTUSED,UART#DEFAULTTHRESHOLD, {
    } UART#NOMODE,UART#BAUD115200)
      uart.AddPort(Serial_Port,Serial_RX, Serial_TX, UART#PINNOTUSED,UART#PINNOTUSED,UART#DEFAULTTHRESHOLD, {
    } UART#NOMODE,UART#BAUD115200)
      uart.AddPort(Debug_Port, Debug_RX,  Debug_TX,  UART#PINNOTUSED,UART#PINNOTUSED,UART#DEFAULTTHRESHOLD, {
    } UART#NOMODE,UART#BAUD115200)
      uart.Start                    'Start the ports
      waitcnt(clkfreq/4 + cnt)      ' wait to start up
    
      ' start mouse and set bound parameters
      mouse.start(24, 25)
      waitcnt(clkfreq/4 + cnt)      ' wait to start up
      mouse.bound_limits(0, 0, 0, 239, 319, 0)
      mouse.bound_scales(8, 8, 0)   ' 1,1,0 is default, 8,8,0 slows down mouse movement
      mouse.bound_preset(119, 159, 0)
      
      waitcnt(clkfreq*4 + cnt)      ' wait to start debug screen
    
      cls                           ' clear the screen
    
      repeat 2
        cursloc(10,10)
        str(string("Enter text: "))
        getstr(@strinp)
      
        cursloc(10,12)
        str(string("Print text: "))
        str(@strinp)
        tx(13)
        
        waitcnt(clkfreq*2 + cnt)
        cls
    
      ' now test the mouse movement
      cursloc(20,17)
      str(string("Mouse Position"))
      
      cursloc(20,19)
      str(string("X-Loc"))
    
      cursloc(30,19)
      str(string("Y_Loc"))
    
      repeat
        mouse_x := mouse.bound_x
        mouse_y := mouse.bound_y
    
        cursloc(20,20)
        dec(mouse_x)
        str(string("    "))         ' clear left over digits from last display
    
        cursloc(30,20)
        dec(mouse_y)
        str(string("    "))
    
    '' Display Output Routines
    PRI cls                         ' clear the debug screen
      tx(16)
      
    PRI cursloc(x, y)               ' position cursor to x, y location
      uart.tx(Debug_Port, 14)       ' position the cursor on X (indent from left)
      uart.tx(Debug_Port, x)
      uart.tx(Debug_Port, 15)       ' position the cursor on Y (down from top)
      uart.tx(Debug_Port, y)
                                        
    PRI dec(data)                   ' send decimal formatted data
      uart.dec(Debug_Port, data)
    
    PUB getstr(strptr)
       uart.getstr(Debug_Port,strptr)
        
    PRI hex(data,dig)               ' send hex data
      uart.hex(Debug_Port, data, dig)
     
    PRI str(strptr)                   ' send string data
      uart.str(Debug_Port, strptr)
    
    PRI rx
      uart.rx(Debug_Port)
    
    PRI tx(dbyte)
      uart.tx(Debug_Port, dbyte)
    
    
Sign In or Register to comment.