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 ZealandPosts: 9308 |
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. Smoke makes things work. When the smoke gets out, it stops! |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9308 |
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. Smoke makes things work. When the smoke gets out, it stops! |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9308 |
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: AustraliaPosts: 3196 |
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: AustraliaPosts: 6101 |
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. VK7JH MMedit MMBasic Help |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9308 |
@ 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... Smoke makes things work. When the smoke gets out, it stops! |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9308 |
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... Smoke makes things work. When the smoke gets out, it stops! |
||||
viscomjim Guru Joined: 08/01/2014 Location: United StatesPosts: 925 |
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: ThailandPosts: 2209 |
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. Microblocks. Build with logic. |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9308 |
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. Smoke makes things work. When the smoke gets out, it stops! |
||||
viscomjim Guru Joined: 08/01/2014 Location: United StatesPosts: 925 |
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 ZealandPosts: 9308 |
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: AustraliaPosts: 6101 |
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 ZealandPosts: 9308 |
YES IT WAS - So sorry - there should be a rule that no more then one name on a forum is allowed!!! 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! 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. Smoke makes things work. When the smoke gets out, it stops! |
||||
Print this page |