Logging Data from serial port

#1
I've been using the Picaxe for simple digital and analog I/O, but I'm trying something new.

In my project I get a serial input that reads like:

000.0 00.0 119.9 60.0 0000 0000 000 206 13.37 000 100 0026 0000 001.7 00.00 00000 00010000 00 00 00000 0100 0000

Each value is separated by a space, and are consistent in their length (zeros replace no data). I only need SOME of the numbers to be manipulated.

My question is this: How do I take the data I need (say the 119.9 starting at character 12 ending at 16) and store it in W1 (yes, I can round the decimal)?

This kind of manipulation was easy with Visual Basic, but I can't figure out how to grab 'part' of a long value in the Picaxe editor. I'm sure it's something simple I'm missing.

Any help would be appreciated.
 

lbenson

Senior Member
#2
... easy with Visual Basic, but I can't figure out how to grab 'part' of a long value in the Picaxe editor
Can you specify more exactly what you want to do? Is the picaxe receiving this serial string, and you're wanting to parse it in picaxe basic, or is a picaxe outputting the string and you want to parse it on a PC?

If the former, it would be easiest with an X2 model with hserin background receive into the scratchpad. Then if you have a known terminating character that you have received, you can start parsing at your position 12 (11 beginning from 0) using the ptr variable (see and search for hsersetup and hserin). The hard part would be making it bulletproof.

If wishing to parse serial output from a picaxe on a PC, you can search for threads which address this process, and can read the serial from Visual Basic.

For the picaxe version, something like
Code:
hsersetup b9600_4, %00001001 ' no hserout, input idles high, n/a, background receive into scratchpad

if hserptr > 14 then
  ptr = 11
  w1 = @ptrinc - "0" ' get hundreds
  w1 = w1 * 10 + @ptrinc - "0" ' get tens
  w1 = w1 * 10 + @ptrinc - "0" ' get ones
  inc ptr ' move past decimal point
  if @ptr > "4" then : inc w1 : endif ' round up
endif
Then you have to identify the terminating character (or, say, hserptr > some number), and reset with: hserptr = 0

But the trick is in bulletproofing.
 
Last edited:
#3
Thanks for the reply. The data is coming from a power supply's serial port and is giving the picaxe important information (119.9 was AC voltage). The picaxe needs to pick the particular data and output on/off based on if the value is above or below the numbered value. Right now all of my experience is with the 08M2 and for size I'd like to stick with it.

If this is impossible, I'm not above stretching my known experience and package size...but ideally, I'd like to use the 08M2.
 
#4
I'd be trying may hand with a 20X2, because it is the smallest that has background serial reception. The data string appears in the scratchpad buffer and you can work your way through the data while it is stored there.

To validate the data, I presume the string is terminated with a character/pair (like Nul or CR/LF). So the new string would follow a terminator character. To extract the data you want, you would need to confirm that characters 11, 17 and 22 are spaces and that chars 15 and 20 are periods. The values could be read by reading each character into a word variable in turn and multiplying by ten, ignoring the decimal point - as lbenson has suggested, above.

For code that will receive and parse data through background serial, have a look at the GPS data receiver that I posted here.
 

hippy

Technical Support
Staff member
#5
It could be possible to do what you want on an 08M2 if the data is in fixed format and the data is not sent so fast that the PICAXE cannot keep up. For example to read the 119.9 value which starts at character 12 ...

Code:
; 123456789-123456
; 000.0 00.0 119.9 ...
You could use ...

Code:
;                1  2  3  4  5  6  7  8  9 10 11  12 13 14  15  16
SerIn Rx, BAUD, b0,b0,b0,b0,b0,b0,b0,b0,b0,b0,b0, b1,b2,b3, b0, b4
w1 = b1 - "0" * 10 + b2 - "0" * 10 + b3 - "0" * 10 + b4 - "0"
SerTxd( #w1, CR, LF )
That should print the value "1199".

Alternatively you could read per number, up to terminating spaces or periods ...

Code:
; 1__ 2 3_ 4 5__ 6
; 000.0 00.0 119.9 ...
Code:
;                1   2   3    4   5   6
SerIn Rx, BAUD, #w0,#w0,#w0,#w0, #w1,#w2
w1 = w1 * 10 + w2
SerTxd( #w1, CR, LF )
If the data is sent at a slow enough rate then it is possible to emulate a background serial receive into RAM using something like the following -

Code:
bPtr = 0
Do
  SerIn RX, BAUD, @bPtr
Loop Until @bPtrInc = CR
Or even

Code:
For bPtr = 0 To N
  SerIn RX, BAUD, @bPtr
Next
Whether any of that will work or not depends on what the baud rate is, how fast data is sent, and how well the PICAXE can keep up. Often the only way to find out is to try it.

There are possibly tricks which can be used to speed things up but that will also depend on the above factors. Baud rate in particular will determine how fast the PICAXE can run using SETFREQ because only a limited range of baud rates are available at each operating frequency.
 

AllyCat

Senior Member
#6
Hi,

I get a serial input that reads like:

000.0 00.0 119.9 60.0 0000 0000 000 206 13.37 000 100 0026 0000 001.7 00.00 00000 00010000 00 00 00000 0100 0000
As hippy says, I think it is probably possible to do with an 08M2, but there might be too many hoops to jump through. It rather depends on the baud rate and whether there are significant pauses between the bursts of data, etc.

First, I note that your data is around 110 characters, but the total RAM in an 08M2 is only 128 bytes so you will typically have only around b0 - b17 (or W0 - W8) for the program to use (if the data is buffered into RAM locations 18-127). But the S_W0-7 registers are generally available if you get desperate.

Depending on the baud rate, the best solution might be to use the program to grab all the bytes (perhaps from the HSERIN buffer) and then post-process the whole string. Alternatively, it is possible to use an interrupt to store individual bytes, but I had a long and complex story to tell. ;)

Cheers, Alan.
 
#7
Okay...Seems easy enough... If only I had the time to test/validate. Admittedly, my strength is is power supply design, not serial data communication.

The Baud rate is 2400, so speed doesn't seem to be an issue. Also, the incoming string is in response to a request serial message which reads as "0x5150494753B7A90D", So, constant monitoring is not necessary. I will send the request about every minute, then read the result. The rest of the time the port is silent. After receiving the request, the power supply responds with the longer string. Frankly, the ONLY data I need is the wattage value which is 4 digits in the middle of the string. The individual values are broken up with space characters as a delimiter, so that may help as well. The 4 digits I need are in bold below.

000.0 00.0 119.9 60.0 0000 0000 000 206 13.37 000 100 0026 0000 001.7 00.00 00000 00010000 00 00 00000 0100 0000

I'm not sure if this is allowed, but if someone could code this part up for me, I'd be happy to reciprocate with some kind of gift card (Amazon, Best Buy, etc.) valued at whatever is fair. I'm running out of time on this. PM me if interested.

Basically, I need:
Send request
Read Data
get Watts from Data
If Watts > 50 then
outuput x high
else
output x low
end if.

I'll worry about the actions inside the if statement. I just need that wattage to use as a word value (will never exceed 6000).

Any takers?
 

lbenson

Senior Member
#8
Reading a value from a fixed-format transmission which comes in response to a request is much easier than catching randomly occurring transmissions on the fly. This should do it.
Code:
#picaxe 08M2

do
  serout C.4,T2400_4,(cr)
  serin [2000,skip], C.3, T2400_4,#w1,#w1,#w1,#w1,#w1,#w1,#w1,#w1,#w1
  sertxd(#w1)
skip:
  pause 5000
loop
The first 8 "#w1"s in the serin statements are throwaways (you can replace them with other variables if you want to see what the values are). The "#" means "read numerals until a non-numeral is encountered" (space or "." in this case).

I tried in the simulator using variations on this string, and "954" was printed.

"1 2 3333.4 5.66 7 8 954 "

In the serout statement, replace "cr" with your own triggering string.

Regarding payment, all I can say is pay it forward when you get a chance to help somebody else.

(It's still possible that even with 2400 baud the characters will be so closely spaced that the picaxe can't catch them all. If that is the case, running at a faster speed may help (SETFREQ M8 or M16).)
 
Last edited:

AllyCat

Senior Member
#9
Hi,

Yes, it looks as if the SEROUT command just needs to contain ($51,$50,$49,$47,$53,$B7,$A9,CR) and as an alternative you might put a " " (space) qualifier in the SERIN command and drop the first two W1s.

If speed (data corruption) is a problem you could try SETFREQ M16 with T2400_16 and/or see if the power supply can be configured for two stop bits or adding a parity bit (ignored).

As for your pseudocode, you really only need to add a couple of SYMBOL declarations watts = w1 and outputx = port.pin ("output" is a reserved word) and swap around the lines to High outputx and Low outputx.

Cheers, Alan.
 
#10
This is SO great! I had to go out of town for a week, but started on this this morning, I am reading data this afternoon. I had to use a MAX232 chip to translate, but that's small potatoes if I can still use the 08M2.

I was not sure the function of the "skip" in the code, but I used:

Code:
do
  serout C.4,T2400_4,($51,$50,$49,$47,$53,$B7,$A9,CR)
  serin [2000], C.3, T2400_4,#w1,#w1,#w1,#w1,#w1,#w2,#w2,#w3,#w4,#w5,#w6,#w7,#w8,#w9,#w10,#w11,#w12,#w13
  sertxd(#w1)

  pause 5000
  debug
loop
and I'm reading values, though all I really needed was W1 and W2, the other values showed up in the debug window exactly as I understand it now.

One thing I learned:
The decimal point becomes a delimiter as well as the space character. Since I don't need that kind of resolution (it's AC voltage and Watts), I blew past them in the next memory position.

Again, THANKS! for the help. Also, if you could explain the skip, I'd appreciate it. I've got a couple of days to get the outputs right then it's on to using it.
 

lbenson

Senior Member
#11
"skip:" is a label to which program execution will jump if the serin "times out"--that is, within 2 seconds, fails to receive all of the input specified in the serin statement. Your SERIN has a timeout time but no jump label, so will fall through to the next statement (and your w1 value may not be valid).

If you had to translate with a MAX232 chip, it may be that your data was "inverted" (idle low--standard with PICAXE but not so common with external devices), so you might have been able to read straight from the device with "N2400" instead of "T2400".
 
#12
The label...duh! I should have caught on to that.

The MAX232 was implemented because the device voltage was too high (read somewhere that it was necessary for my type of signal)...and it's cheap...and the budget for this is high. However, I may sacrifice a chip and give it a try without the MAX232 chip just to see what happens.

Thanks again!
 
#13
Holy $&@# it WORKED!!!

Rule #549: Trust lbenson over some other random person on the internet...:p

The N2400 was the key to me saving $2 and 1" squared per board.

Thanks again!
 

lbenson

Senior Member
#14
... the key to me saving $2
Treat yourself to a coffee (but not at Starbucks, sorry).

If the MAX232 was also "level shifting" (of the voltage) in addition to inverting, at what voltage is your external device running? And the picaxe? The picaxe download circuit allows connection of traditional RS232 serial voltage levels (up to +/- 15V) but that level could/would damage the picaxe without the current-limiting 22K resistor.
 
#15
Alas, I could be done, and move on, but somebody's going to come across this...

Sure enough, the Picaxe ran for a while, then failed. Stopped reporting altogether...so I'm thinking the voltage levels of the device are too high. The device is RS232 and intended to connect to a PC for reporting.

So, if I just do a resistor array of 10K and 22K just like the download circuit, but on C.3, that should save my Picaxe rather than using the MAX232? Since C.4 is TX should not be affected, right?
 

Circuit

Senior Member
#16
Alas, I could be done, and move on, but somebody's going to come across this...

Sure enough, the Picaxe ran for a while, then failed. Stopped reporting altogether...so I'm thinking the voltage levels of the device are too high. The device is RS232 and intended to connect to a PC for reporting.

So, if I just do a resistor array of 10K and 22K just like the download circuit, but on C.3, that should save my Picaxe rather than using the MAX232? Since C.4 is TX should not be affected, right?
As a true RS232 signal swings +/-15 volts I would clamp the input voltage to the PICAXE Vcc with a couple of diodes and limit the current with a resistor as follows;
PICAXE RS232 INPUT.png

If you look in PICAXE manual 3 page 44 it shows the "PICAXE recommended" handling of RS232.
 

AllyCat

Senior Member
#17
Hi,

So, if I just do a resistor array of 10K and 22K just like the download circuit, but on C.3, that should save my Picaxe rather than using the MAX232? Since C.4 is TX should not be affected, right?
So you didn't put a resistor in series with the (c.3) input? :(

A series resistor is nearly always recommended to help the internal "electrostatic protection" diodes do their job. Particularly with PIC{axe} chips because nearly all inputs can be "accidentally" configured as an output by a software mistake; An output "talking" to another output is quite a good way to damage chips.

But c.3 (on an M2) is a rather "special" pin because it's the "base" PIC's MR and "high voltage" Programming input pin. So it doesn't have a clamping diode to the supply rail and can be pulled above the supply rail (tolerant up to about 9v IIRC). Therefore, if you want to use that as an "RS232" (voltage levels) input then you should use a 22k series resistor and a diode from the pin to the supply rail (the 10k is generally optional, but must be used for the PICAXE programming input pin).

To conclude, a MAX232 is only needed if a signal inversion is required (but there are cheaper methods) or if RS232 output levels are required (i.e. >5v and <0 volts), but in practice almost no systems actually need these now.

Cheers, Alan.
 
#18
Well, resistors in place. I didn't have diodes, but I designed it in the PCB, so I took a chance anyway. All night with the delays down to 1 second, so I sent the request and received a response around 50,000 times. In actual usage it will have the diodes and will message once a minute, so I think I have a winning solution.

I'm attaching an early schematic for those looking to try this. It's not up to date as far as diode values and R2 isn't right yet (I didn't have a 180 so I wondered about a 220, which I did have and it worked).

Anyway, thanks all for the help!
RS232 Picaxe.jpg
 
Top