November 13, 2024, 11:33:05 PM

News:

You can now use Vixen to program your Prop-1 and Prop-2 controllers!  Get started quickly and easily, without having to learn PBASIC.  Details in the Library forum.


Minor RS-485 Problem

Started by bsnut, February 03, 2013, 08:45:16 AM

Previous topic - Next topic

bsnut

February 03, 2013, 08:45:16 AM Last Edit: February 03, 2013, 08:48:44 AM by bsnut
Jon,

I was finally able to get part of this RS-485 to Spin code to work, which makes me a happy camper today by seeing Red/Green LED blink 8).   

pub main | id, pinSet

  setup_io                          ' setup HC-8+ IO pins

  if (ina[DMX_A8] == 1)             ' Set as a master
    set_rs485(TX)
    rs485com.start(RX2, TX2, %0000, BAUD)
  if (ina[DMX_A8] == 0)             ' Set as a slave
    set_rs485(RX)
    rs485com.start(RX2, TX2, %0000, BAUD) 
 
  pause(100)                        ' let line RX settle
  rs485com.rxflush                  ' remove garbage


  pinSet := %00000100             ' Starting bit pattern.
  repeat
    if (ina[DMX_A8] == 1)         ' run master code
      set_rgled(RED)
      repeat id from "A" to "C"   ' Cycle through ids A, B, C ; this code works
        rs485com.tx(id)           ' this code works
        pinSet := (pinSet << 2)
        rs485com.tx(pinSet) 
       
     
    if (ina[DMX_A8] == 0)         ' run slave code ; this code works
      id:= rs485com.rxtime(100)   ' this code works
       if (dmx_bit(0)== 1)        ' this code works
        if (id == "A")
          set_rgled(GRN)
        else
          set_rgled(OFF)
     
      if (dmx_bit(1)== 1)         ' this code works
        if (id ==  "B")
          set_rgled(GRN)
        else
          set_rgled(OFF)
       
      if (dmx_bit(2)== 1)         ' this code works
        if (id ==  "C") 
          set_rgled(GRN)
        else
          set_rgled(OFF)

      pinSet := rs485com.rxtime(100)         
      pinSet := pinSet & %11111100  ' Strip off two lowest bits of number.
      pinSet := outa[OUT0..OUT7]
     

    pause(1000)                        ' run loop every 1000ms

The code idea was form this Nut&Volts article Stamp Applications no. 28 Nifty Networking Chips Link Stamps Far and Wide by good old Scott Edwards back in June '97(attached). I also found out the hard way that it didn't work due do the RS-485 chip that is on the HC-8+ after I downloaded the datasheet for that RS-485 chip. So, I changed the code to match the chip on the HC-8+ But, I wasn't able to get the variable "pinSet" to pass over the RS-485 as Scott was showing and talking about in his article.   
William Stefan
The Basic Stamp Nut

JonnyMac

February 03, 2013, 09:44:06 AM #1 Last Edit: February 03, 2013, 10:09:43 AM by JonnyMac
With the sophistication of Propeller programs I'm at a disadvantage not having the actual listing to look at. For example, I don't know what object you're using for rs485com and that makes a difference. I will go on the assumption that you're using fullduplexserial or fullduplexserial64 (my update to fds).

Note 1: With advanced langagues like Spin it is always a good idea to break the program into very small parts. Having the master and slave code in the same loop is difficult to follow and, I think, could be hard to troubleshoot later.

Note 2: As ever, I will encourage you to use waitcnt instead of pause when you want something to happen on a specific period. Using waitcnt as I do below accounts for loop overhead and guarantees than the process runs at a fixed timing.

In the standard HC-8 firmware there are in fact three modes: 0) testing, 1) EFX-TEK mode, and 2) DMX mode.  On start-up the HC-8+ looks at the programming port for a special character that puts it into test mode. This allows us to check all the functions of the board. If that character is not received in a specific time then the program unloads that serial driver and looks at the SM switch; from there is will jump to the master routines for handling EFX-TEK serial input, or DMX serial input.

With that background, here's a suggestion for structuring your project.


pub main

  setup_io                                                      ' setup HC-8+ IO pins
  rs485com.start(RX2, TX2, %0000, BAUD)                         ' start RS-485 serial

  if (ina[DMX_A8] == 1)                                         ' run desired mode
    run_master
  else
    run_slave


pub run_master | t, idx, pattern

  set_rgled(GRN)                                                ' green for master
  set_rs485(TX)                                                 ' enable transmitter
  pause(50)                                                     ' let everything settle

  t := cnt
  repeat
    repeat idx from 0 to 6
      pattern := 1 << idx
      outa[OUT7..OUT0] := pattern
      rs485com.tx(pattern)
      waitcnt(t += (125 * MS_001))                              ' set loop timing
     
    repeat idx from 7 to 1
      pattern := 1 << idx
      outa[OUT7..OUT0] := pattern
      rs485com.tx(pattern)
      waitcnt(t += (125 * MS_001))                              ' set loop timing


pub run_slave | pattern

  set_rgled(RED)                                                ' red for slave
  set_rs485(RX)                                                 ' enable receiver
  pause(25)                                                     ' let line settle
  rs485com.rxflush                                              ' clear trash from buffer

  repeat
    repeat
      pattern := rs485com.rxcheck                               ' wait for input
    until (pattern > -1)
    outa[OUT7..OUT0] := pattern                                 ' display on outputs



With the highlighting feature of the Propeller tool this will be far easier to follow.


Jon McPhalen
EFX-TEK Hollywood Office

JonnyMac

Just a note on this bit:

      pinSet := rs485com.rxtime(100)         
      pinSet := pinSet & %11111100  ' Strip off two lowest bits of number.
      pinSet := outa[OUT0..OUT7]


If nothing shows up in the specified period, .rxtime will return -1 which is all bits set.  You should probably check for this before using it to update anything. Also, the last line is taking what's sitting on the outputs and putting it into the variable you just mainpulated -- if you wanted to display what's in pinSet then you have to reverse those elements

      outa[OUT7..OUT0] := pinSet

Also note that the order inside the brackets is important; in your code you're flipping the LSB/MSB positions.
Jon McPhalen
EFX-TEK Hollywood Office

bsnut

QuoteWith the sophistication of Propeller programs I'm at a disadvantage not having the actual listing to look at. For example, I don't know what object you're using for rs485com and that makes a difference. I will go on the assumption that you're using fullduplexserial or fullduplexserial64 (my update to fds).
That is correct , I ended up using your updated fullduplexserial64 for "rs485com", my mistake for not adding it into the posted code for you and others to see.
Quote
Note 1: With advanced langagues like Spin it is always a good idea to break the program into very small parts. Having the master and slave code in the same loop is difficult to follow and, I think, could be hard to troubleshoot later.
I normally break my programs into small parts, that's what I was trying to do.
Quote
Note 2: As ever, I will encourage you to use waitcnt instead of pause when you want something to happen on a specific period. Using waitcnt as I do below accounts for loop overhead and guarantees than the process runs at a fixed timing.
I noticed that when I ran the code below how everything was in time with the other board. As they say bad habits die hard, that's why you rule  ;). I just need to get in the habit of doing so and you're not the only one saying this. The Propeller book that I have says this to.

Also thanks for catching this as well. The goal was to see the variable "piSet" on the outputs.

pinSet := outa[OUT0..OUT7]

 
William Stefan
The Basic Stamp Nut

JonnyMac

William (and others following this thread): I found a bug in my half-duplex RS-485 code that may have been getting in your way. Sorry about that. I've attached my updated driver to this post. It works a lot like FullDuplexSerial, but some of the method names are different. It also allows for receiving formatted numeric values if they are expected in the stream.

I hope this object is useful. Networking HC-8s is a lot of fun -- it opens up all kinds of possibilities for prop and show control.
Jon McPhalen
EFX-TEK Hollywood Office

bsnut

Jon, thanks for the updated driver and will try it out before the end of the middle of the week, since I will be going to Cedar Point for the coaster event on Friday and MWHC on the following day to grab some goodies from you guys.
William Stefan
The Basic Stamp Nut

bsnut

Ok, I tried out the your new updated RS485 driver with  my HC-8 that you posted and noticed this small problem with this code in the driver itself

pub start(rxd, txd, txe, txled, baud)

'' Half-duplex, true mode UART
'' -- rxd is rx pin (in)
'' -- txd is tx pin (out)
'' -- txe is tx enable pin (out)
'' -- txled  is tx enabled led (out, -1 if not used)
'' -- baud is baud rate for coms
or was this mint for something else another setup.

The code I used on the HC-8 (sorry for not saying this in the first place at the beginning of this thread) was the code that you posted on your second post of this thread.
William Stefan
The Basic Stamp Nut

JonnyMac

I believe those early posts were using FullDuplexSerial and manually manipulating the TX_EN line for transmitting. This is where my object makes things easy: it handles the transmit enable pin automatically.

Here's a little transmitter demo I have running on my desk

obj

  rs485com : "jm_hd485"
   

pub main | ch

  setup_io

  rs485com.start(RX2, TX2, TX2_EN, G_LED, BAUD)           
  pause(1)

  repeat
    repeat ch from 0 to 6
      outa[OUT7..OUT0] := 1 << ch
      rs485com.tx(outa[OUT7..OUT0])
      pause(125)
    repeat ch from 7 to 1
      outa[OUT7..OUT0] := 1 << ch
      rs485com.tx(outa[OUT7..OUT0])
      pause(125)


This plays a little Larsen Scanner (Cylon, Kit Car, etc.) on the outputs and broadcasts the pattern on the RS-485 transmit pins (T- and T+).

On the other HC-8+ is a program that is waiting for a byte on the RS-485 inputs (R- and R+) and when a byte is received, it moves it to the outputs.

obj

  rs485com : "jm_hd485"


pub main | outs

  setup_io

  rs485com.start(RX2, TX2, TX2_EN, G_LED, BAUD)           
  pause(1)

  repeat
    outs := rs485com.rx_time(1000)
    if (outs => 0)
      outa[OUT7..OUT0] := outs
    else
      outa[OUT7..OUT0] := %00000000
 


Just a note about using RS-485 on the HC-8+. Many of my templates disable the RS-485 circuit using a NOCON value in the set_rs485() method. You need to change this to RX to default the circuitry to recieve mode. When using the half-duplex driver the UART cannot listen while it is broadcasting so you don't have to worry about the RX_EN (RX enable) pin.
Jon McPhalen
EFX-TEK Hollywood Office

bsnut

Jon did you know you rule 8). I just tested both demo code and everything is working great.

QuoteHere's a little transmitter demo I have running on my desk
But, I noticed that the "G_LED" (on pin 17 bi-color led) was flashing dimly and was wondering if this was same that you had running your desk.

QuoteI believe those early posts were using FullDuplexSerial and manually manipulating the TX_EN line for transmitting
I was using FullDuplexSerial64 but close enough.
William Stefan
The Basic Stamp Nut

JonnyMac

QuoteBut, I noticed that the "G_LED" (on pin 17 bi-color led) was flashing dimly and was wondering if this was same that you had running your desk.

Yes. If you look in the .start() method of the object you'll see that it allows you to specify an LED to light when transmitting -- that's what's going on. It's dimly flashing because it's only sending one byte at a time. If you were transmitting a large block of data it would be on longer and appear brighter.
Jon McPhalen
EFX-TEK Hollywood Office