Shop OBEX P1 Docs P2 Docs Learn Events
First time using UART - Using PST and FullDuplexSerial - Not working? — Parallax Forums

First time using UART - Using PST and FullDuplexSerial - Not working?

Hey guys,
This is my first time using UART and I can't seem to get it to work. I am interfacing the propeller with a MH-Z14 CO2 sensor:
http://www.thaieasyelec.com/downloads/ESEN185/MH-Z14_CO2.pdf

I am using the "Parallax Serial Terminal" library to display information to the terminal, and I am using the "FullDuplexSerial" library for the UART communication with the sensor. This is something that I am not sure about.

I send commands to the sensor but I never receive anything back from the Rx read... it locks up and waits forever for data to come but it never comes.

I tried swapping the Rx and Tx lines around, and like this I constantly receive 0's.

I have the Rx of the propeller connected to the Tx of the sensor, and the Tx of the propeller connected to the Rx of the sensor.

I made a quick sample SPIN program just to try and test it, but it does not work.

Would someone mind taking a peek and letting me know what I am doing wrong? Thanks and any help is greatly appreciated.

Here is my SPIN program:
CON
        _clkmode = xtal1 + pll16x                                               'Standard clock mode * crystal frequency = 80 MHz
        _xinfreq = 5_000_000


OBJ
  PST     : "Parallax Serial Terminal"                    ''Used ONLY For DEBUGGING
  UART    : "FullDuplexSerial" 
  

VAR
  byte buffer
   

PUB Main
  PST.Start(115200)                                     'Used ONLY For DEBUGGING
  waitcnt(clkfreq / 2 + cnt)                            'Allow device time to power up fully
  PST.Clear

  PST.Str(string("Parallax Serial Terminal Initialized",13))
  
  UART.start(16, 17, %0000, 9_600)
  waitcnt(clkfreq + cnt)                            'Allow device time to power up fully

  PST.Str(string("UART Initialized",13))

  UART.RxFlush
  
  UART.Hex($FF,2)
  UART.Hex($01,2)
  UART.Hex($86,2)
  UART.Hex($00,2)
  UART.Hex($00,2)
  UART.Hex($00,2)
  UART.Hex($00,2)
  UART.Hex($00,2)
  UART.Hex($79,2)

  buffer := UART.Rx
  PST.Hex(buffer,2)
  PST.Str(string(13))

  buffer := UART.Rx
  PST.Hex(buffer,2)
  PST.Str(string(13))

  buffer := UART.Rx
  PST.Hex(buffer,2)
  PST.Str(string(13))

  buffer := UART.Rx
  PST.Hex(buffer,2)
  PST.Str(string(13))

  buffer := UART.Rx
  PST.Hex(buffer,2)
  PST.Str(string(13))

  buffer := UART.Rx
  PST.Hex(buffer,2)
  PST.Str(string(13))

  buffer := UART.Rx
  PST.Hex(buffer,2)
  PST.Str(string(13))

  buffer := UART.Rx
  PST.Hex(buffer,2)
  PST.Str(string(13))

  buffer := UART.Rx
  PST.Hex(buffer,2)
  PST.Str(string(13))


Comments

  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2016-09-02 19:02
    I don't believe the device is expecting ASCII HEX values like you're sending. It just needs 9 bytes and lists the values in HEX.

    You're sending 18 bytes to a device expecting 9. Just send the binary values without converting them to strings.

    A second look also indicates you must calculate a checksum byte at the end.
  • JonnyMacJonnyMac Posts: 9,104
    edited 2016-09-03 14:09
    Chris is right -- and this is a common mistake made by newcomers with serial coms. What's important to remember is that hex notation is for humans; under-the-hood, it's all binary.

    Here's the [tested] translation of the checksum calculation; I did my best to make it very verbose so you can compare the Spin to C.
    char getCheckSum(char *packet)
    {
      char i, checksum;
    
      for( i = 1; i < 8; i++) {
        checksum += packet[i];
      }
      checksum = 0xff – checksum;
      checksum += 1;
    
      return checksum;
    }
    
    pub get_checksum(p_packet) | idx, checksum
    
      checksum := 0
      
      repeat idx from 1 to 7
        checksum += byte[p_packet][idx]
    
      checksum := $FF - checksum.byte[0]
      checksum += 1
    
      return checksum
    
    The reason for using checksum.byte[0] after the loop is to isolate just the lower eight bits. In the C implementation, checksum is defined as a char (8 bits). In Spin, all local variables are longs (32 bits).

    There are no pointer variables in Spin, so I preface a variable that is to hold a pointer with "p_".

    As you gain more experiece you can start to cut the fat out of programs. Here's a version of get_checksum that doesn't require local variables (other than built in result).

    EDITED:
    pub get_checksum(p_packet) : checksum
    
      repeat 7
        checksum += byte[++p_packet]
    
      checksum := $FF - checksum.byte[0]
      checksum += 1
    
    I tested it (the original version) on the same data sets from the sensor docs. It works fine -- because I got lucky (see my post below).
  • Thanks guys, much appreciated!

    I changed the UART.Hex($FF,2) over to UART.Tx($FF) and now everything works. Thanks for the checksum code as well!
  • I got a note from a friend that there is a possible error condition in my cleaned-up checksum calculation -- he's absolutely correct. Use this instead:
    pub get_checksum(p_packet) : checksum
    
      repeat 7
        checksum += byte[++p_packet]
    
      checksum := $FF - checksum.byte[0]
      checksum += 1
    
    As he pointed out, if the low byte of the sum of the packet is zero, the other version would return $100 which is a 2-byte value. Silly me. Sorry for steering you wrong and grateful for my friend who pointed out a very subtle error.

Sign In or Register to comment.