Home
JAQForum Ver 24.01
Log In or Join  
Active Topics
Local Time 04:28 29 Nov 2024 Privacy Policy
Jump to

Notice. New forum software under development. It's going to miss a few functions and look a bit ugly for a while, but I'm working on it full time now as the old forum was too unstable. Couple days, all good. If you notice any issues, please contact me.

Forum Index : Microcontroller and PC projects : MM Serial problems

Author Message
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9308
Posted: 10:27pm 15 Mar 2014
Copy link to clipboard 
Print this post

This is the full-size MM, NOT the micro-mite chip which is all the rage at the moment...

I am having problems dealing with serial interrupts.
I have messed with buffer lengths etc, but I NEVER get the data I want, EXCEPT for the VERY FIRST instance.

With PICAXE, you could SERIN the data you wanted, and it would wait till this data arrived before it would do anything else. This is basically what I want, but I also need the interrupt ability - IE: Interrupt ONLY when the prescribed data has been received. DO NOT interrupt when any old data has been received(which could also be garbled comms or other rubbish)

The data ALWAYS sends a pre-requisite, which is ALWAYS the same - this is how the system knows that the message is for it's attention, so I guess I need more help with inputting the pre-requisite(qualifier).

Problem is, if I look only for the qualifier(which works in the PICAXE system), every message except the 1st one from power-up is totally ignored.

I will post some screenshots of my test code soon, but the basic problem is that I need to be able to do the interrupt thing ONLY if the pre-defined qualifier is in the buffer at that specific time - this is the bit which is knocking me sideways.

Any hints?
Drink recommendations?

EDIT: According to what I have been able to establish, the buffer is not continious. What I mean by that, is that the buffer is the buffer, and what it contains, UNTIL it is read. If you don't read all the contents of the buffer, it looks to me like the remaining part of the buffer(the bit you DON'T read), is discarded at that point.

Perhaps someone can clarify EXACTLY what happens when you read the serial buffer?
If there are 50 bytes waiting, and you only read 25, are the rest disposed of?

I will run some tests in the meantime.Edited by Grogster 2014-03-17
Smoke makes things work. When the smoke gets out, it stops!
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9308
Posted: 11:39am 16 Mar 2014
Copy link to clipboard 
Print this post

ADDITIONAL: The buffer IS continuous.

If I send 20 bytes to it, then read 10 of those, there is still 10 bytes left, so this is what is stuffing up my process - I will alter the code, so that EVERYTHING available in the buffer is read, once there is anything there at all, with the likes of N$=INPUT$(LOC(#1),#1) - that should totally empty the buffer in one operation.

I think I see where I was falling over last night - that and beer, which I was supposed to be giving up - case in point.Edited by Grogster 2014-03-17
Smoke makes things work. When the smoke gets out, it stops!
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9308
Posted: 12:08pm 16 Mar 2014
Copy link to clipboard 
Print this post

Serial input seems to be dropping the first two bytes - anyone else seen this?

If I send the 21-byte string: "[ABCD]000 TESTUNIT_A<cr>" to the port, the first two bytes are ALWAYS dropped - the rest of the message is there.

Whenever I check the length of the buffer, it is always 19 bytes - two bytes short.


open "com2:2400" as #1

cls
Print "Waiting for serial data..."

DO
if LOC(#1)>1 then
NET$=INPUT$(LOC(#1),#1)
print clr$(Green) "RXD: "; NET$
print clr$(Green) "QUALIFIER: "; mid$(NET$,1,6)
print clr$(Green) "MESSAGE: "; MID$(NET$,7,len(NET$))
print clr$(Green) "BUFFER: "; B
print:print:FLAG=0:PAUSE 500
Endif
loop

end


It makes no difference at all, if I change the serial port buffers, set or not an interrupt or just use the loc method above - in all experiments, the first two bytes are missed.

The test string is being sent by a PICAXE 14M2, running at 5v, and COM2 is 5v tolerant, so says the datasheets.

Both the MM and the PICXAXE share a common ground.

If I run the above code on the MM, then before sending anything, I CTRL-C to stop the code running, THEN press the button on the PICAXE to send the data, I then get the following:


> ? LOC(#1)
19
> NET$=INPUT$(LOC(#1),#1)
> ? NET$
BCD]000 TESTUNIT_A
> ? LEN(NET$)
19
> ? LOC(#1)
0


PICAXE sender code is:

T=500

DO
if one=1 then
high B.0
serout B.0,T2400,("[ABCD]000 TESTUNIT_A",CR)
pulsout ACK,T
pause T
endif


This is just for the tester button - there are other buttons which are programmed for different test messages in the same way.
The 'high B.0' in the picaxe code is there to make sure that the pin is in the correct state before serout - this is normal, and needs to be in place with PICAXE to make serout work right(in the firmwares I have anyway - they might have updated by now). I have tried with and without that set, but the results are still the same. As there is a total of 1-second pause between messages, I am NOT getting an overlap of the same message cos I hold the button too long, it's just that the MM is dropping the first two bytes.

Anyone know why that should be?

I might try COM1, but I would not expect it to be any better...
Smoke makes things work. When the smoke gets out, it stops!
 
Geoffg

Guru

Joined: 06/06/2011
Location: Australia
Posts: 3196
Posted: 01:16pm 16 Mar 2014
Copy link to clipboard 
Print this post

Hi Graeme,

I would be very surprised if there was an issue in MMBasic. Serial I/O has been tested many times and hundreds of people have projects running that use it.

It could be something like your serial line floating or noise. I think that you will have to dig out your oscilloscope for this one.

Geoff
Geoff Graham - http://geoffg.net
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6101
Posted: 01:17pm 16 Mar 2014
Copy link to clipboard 
Print this post

You are not waiting for the full message to arrive.
If the messages are being sent with a big gap between them and you are sure to process each message before the next one arrives, this code should do the trick.

open "com2:2400" as #1

cls
Print "Waiting for serial data..."

DO
if LOC(#1)>1 then
partNET$=INPUT$(LOC(#1),#1)
net$=net$+partNET$
if instr(NET$,chr$(13))>0 then ' we have the full line
print clr$(Green) "RXD: "; NET$
print clr$(Green) "QUALIFIER: "; mid$(NET$,1,6)
print clr$(Green) "MESSAGE: "; MID$(NET$,7,len(NET$))
print clr$(Green) "BUFFER: "; B
print:print:FLAG=0:PAUSE 500
net$="" ' flush ready for the next message
endif

Endif
loop

end


We simply keep adding data until a CR is received.
If the data comes too quickly, there might be data after the CR which will be lost with this code.

Jim

I didn't have a picaxe handy so I used a microMite to send the test strings.
Edited by TassyJim 2014-03-17
VK7JH
MMedit   MMBasic Help
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9308
Posted: 02:05pm 16 Mar 2014
Copy link to clipboard 
Print this post

@ Geoff - thanks for the confirmation. I might get a chance to play with my little Saelie logic analyzer...

@ Jim - will try that and let you know.

EDIT: Tried Jim's code, but still have the same issue - data received is not consistant - sometimes it is right, other times it is all out of sync. It also cycles twice for one keypress.

HOWEVER, Jim's byte-by-byte method does seem to read the correct message into NET$, so that's progress - BUT the length of net$ is now 42 bytes instead of 21 - seems there are 21 bytes of nothing on the end of the string, as ? net$ just shows what should be there. I will play around some more...

I will install a 4k7 pullup - I have not bothered with one, as I thought I could do that in the PICAXE code, but perhaps...

EDIT: OK, as A test, I hooked up the PICAXE via a 232 corrector to the PC serial port, and checked what was coming out of the PICAXE using TeraTerm.

It is EXACTLY what should be happening, and TT shows exactly the right data at exactly the right time(when any button is pressed), so there does not seem to be a problem with the data coming out of the PICAXE.

Using the exact same PICAXE, circuit, PSU and linking cables. Only difference is that rather then the MM at the end of the serial from the PICAXE, there is a 232 converter connected to the PC instead, but the messages are getting to the PC just fine.

The tinkering continues...Edited by Grogster 2014-03-18
Smoke makes things work. When the smoke gets out, it stops!
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9308
Posted: 02:55pm 16 Mar 2014
Copy link to clipboard 
Print this post

Progress.

New code:

open "com2:2400" as #1

cls
Print "Waiting for serial data..."

DO
if LOC(#1)<>0 then 'A byte needs to be processed
B$=INPUT$(1,#1) 'Suck byte out of buffer
net$=net$+B$ 'Add byte to message string
IF B$=chr$(13) then '<CR> received, so now show results
print clr$(Green) "RXD: "; NET$
print clr$(Green) "QUALIFIER: "; mid$(NET$,1,6)
print clr$(Green) "MESSAGE: "; MID$(NET$,7,len(NET$))
print clr$(Green) "BUFFER: "; loc(#1) 'Check that serial buffer is empty
print clr$(Red) "Pause...":print:FLAG=0:PAUSE 500 'Delay to prevent overlaps
print clr$(White) "Ready." 'Signal ready for next message
net$="" ' flush ready for the next message
endif
Endif
loop

end


Still tinkering, but this is working.

Note that in my original code, I was saying that IF LOC(#1)>1 THEN, but I expect that this was losing at least one byte...Edited by Grogster 2014-03-18
Smoke makes things work. When the smoke gets out, it stops!
 
viscomjim
Guru

Joined: 08/01/2014
Location: United States
Posts: 925
Posted: 08:16am 17 Mar 2014
Copy link to clipboard 
Print this post

Hi Grogster,

Have you used the line input command yet to see how it reacts with a CR or LF?
 
MicroBlocks

Guru

Joined: 12/05/2012
Location: Thailand
Posts: 2209
Posted: 09:09am 17 Mar 2014
Copy link to clipboard 
Print this post

I work with streams of data a lot and i found that using a STX and ETX character works best.
These characters were/are used to signal the Start Of Text and End Of Text.
You would then read characters from the serial port as fast as you can and scan it for the STX character.
When you find one you set a flag (or next state when using states) and process the next characters as being the text until you have an ETX.

I like to work with FSM (Finite State Machine) and these kinds of processes can be solved very efficiently with FSM

I did not test this so please forgive me if it doesn't work.
It is just to give you the idea of how you can do it with using an FSM.

It is no coincidence that working with IO pins you use a FSM often. It works just as well with only software.

[code]
WAITING = 1
COLLECTING = 2
Message = ""

open "com2:2400" as #1

CLS
STATE = WAITING
PRINT "Waiting for serial data..."

DO
IF LOC(#1) <> 0 THEN
B$=INPUT$(1,#1)

IF STATE = WAITING THEN
'Wait for STX character
IF B$ = chr$(2) then
Message$ = ""
STATE = COLLECTING
ENDIF

ELSEIF STATE = COLLECTING
'Collect characters and add them to Message$ until a ETX is detected
IF B$ <> chr$(3) then
Message$ = Message$ + B$
ELSE
ProcessMessage Message$
Message$ = ""
STATE = WAITING
ENDIF

ENDIF
LOOP

END

SUB ProcessMessage(Msg$)
PRINT clr$(Green) "RXD: "; Msg$
PRINT clr$(Green) "QUALIFIER: "; mid$(Msg$,1,6)
PRINT clr$(Green) "MESSAGE: "; MID$(Msg$,7)
END SUB
[/code]

Above code will need the sender of the message to be modified by starting each message with a STX and ending it with ETX.
The above code can work after modifying just as well with using a CR/LF for signalling the end of the text. I use the STX and ETX often because it also allows for the CR/LF to be part of the message and i can more easily detect the first message. Checking only for a CR/LF does not guarantee you that you get the whole message.
You also can do very fancy things by adding a header and a checksum if integrity of the message is vital.
Adding those features to the code is when using an FSM trivial.

Edited by TZAdvantage 2014-03-18
Microblocks. Build with logic.
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9308
Posted: 11:17am 17 Mar 2014
Copy link to clipboard 
Print this post

  viscomjim said   Hi Grogster,

Have you used the line input command yet to see how it reacts with a CR or LF?


Cannot use LINE INPUT on a serial port on the full size MM.
You can on the MicroMite, from what I can understand, by comparing the manuals.

@ TZA - Thanks for the example - I will tinker with it.Edited by Grogster 2014-03-18
Smoke makes things work. When the smoke gets out, it stops!
 
viscomjim
Guru

Joined: 08/01/2014
Location: United States
Posts: 925
Posted: 03:38pm 17 Mar 2014
Copy link to clipboard 
Print this post

Sorry Grogster,

I forgot you were using full size MM. I will keep trying on uMite.

 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9308
Posted: 08:21pm 17 Mar 2014
Copy link to clipboard 
Print this post

A variation of your code above is working fine, so everything is sorted as far as I am concerned.

Reading till I hit a <cr> is working a treat - as per your example, but I am not quite sure I understand why you used the INSTR command - perhaps you could elaborate?


Smoke makes things work. When the smoke gets out, it stops!
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 6101
Posted: 09:38pm 17 Mar 2014
Copy link to clipboard 
Print this post

  Grogster said   A variation of your code above is working fine, so everything is sorted as far as I am concerned.

Reading till I hit a <cr> is working a treat - as per your example, but I am not quite sure I understand why you used the INSTR command - perhaps you could elaborate?



I think the question was directed to me.
Maximite strings are limited to 255 bytes while the serial receive buffer can be made much bigger.
This is handy if your program is slow to process the data, provided that you don't overflow the buffer eventually.

So if you have more than 255 bytes likely to be stacked up for processing, reading one byte at a time from the comms buffer is good.

If you get a lot of data and are going to discard a fair amount of it eg GPS data when you are only interested in one type of sentence.
Logging AIS (shipping) data when you only want one ship out of dozens etc, another method of precessing may be better.
I often process this sort of data on the PC.
If you read all the available data from the buffer and add it to your current data and then use INSTR to find the first CR (or other end-of-message), you can then check if the message is one you want and discard if not needed.
You simply use MID$ to retain the remaining data and loop back to receiving any available data and looking for the first CR again.

This method should be faster than one character at a time but the big risk is keeping the working string down to 255 characters.

It usually depends on what sort of data you have and what you need to do with it.

Jim

VK7JH
MMedit   MMBasic Help
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9308
Posted: 10:34pm 17 Mar 2014
Copy link to clipboard 
Print this post

  Quote  I think the question was directed to me.


YES IT WAS - So sorry - there should be a rule that no more then one name on a forum is allowed!!!

  Quote  Maximite strings are limited to 255 bytes while the serial receive buffer can be made much bigger.
This is handy if your program is slow to process the data, provided that you don't overflow the buffer eventually. So if you have more than 255 bytes likely to be stacked up for processing, reading one byte at a time from the comms buffer is good.


YES - I discoverdd this purely by chance. Once I had the correct input of the bytes, the program then AUTO-QUEUED the extra messages, finishing one, then auto-looping(cos the serial buffer was NOT zero) to the next message - I have tested this with up to 8 messages in a row, and they are all systematically processed out of the buffer, until the serial buffer is zero - FAN-PHUCKING-TASTIC!

  Quote  If you read all the available data from the buffer and add it to your current data and then use INSTR to find the first CR (or other end-of-message), you can then check if the message is one you want and discard if not needed.
You simply use MID$ to retain the remaining data and loop back to receiving any available data and looking for the first CR again.

This method should be faster than one character at a time but the big risk is keeping the working string down to 255 characters.

It usually depends on what sort of data you have and what you need to do with it.

Jim


Yes indeed. However, reading the data with the "End of message" marker being a <cr> seems to be working BETTER THEN EXPECTED, now that I have it working, as the MM serial buffer is saving it all for me. I am REALLY happy. Edited by Grogster 2014-03-19
Smoke makes things work. When the smoke gets out, it stops!
 
Print this page


To reply to this topic, you need to log in.

© JAQ Software 2024