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 : Micromite to micromite communication
Author | Message | ||||
lizby Guru Joined: 17/05/2016 Location: United StatesPosts: 3015 |
I searched for answers, but the hits are not very specific with "micromite to micromite". I'm wondering about the best way to send a few bytes from one micromite to another over a distance of up to 10 meters (wired). I'm familiar with the picaxe. You have two good choices there--background serial receive and i2c slave mode (with i2c extenders for the distance). Does micromite have either of those (I know it can be an i2c master.) Failing that, would serial with handshaking be best? Checksum assumed in any case. PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed |
||||
TassyJim Guru Joined: 07/08/2011 Location: AustraliaPosts: 5905 |
Either would work OK If one is going to be the slave, serial with an interrupt when data is available works well. I2C receive works in much the same way but for 10 metres I would use serial. If you have a noisy environment, use RS232 with MAX3232's or RS485 with SP3485's or similar. Jim VK7JH MMedit  MMBasic Help |
||||
lizby Guru Joined: 17/05/2016 Location: United StatesPosts: 3015 |
"serial with an interrupt when data is available works well" Are you saying that background serial receive is available? How is this set up? PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed |
||||
TassyJim Guru Joined: 07/08/2011 Location: AustraliaPosts: 5905 |
From the manual (Appendix A – Serial Communications Serial Communications): So, have a subroutine (int) to handle the received data. Whenever ‘intlevel’ bytes are received, the sub 'int' will be called. While you are waiting, your program can be doing other things. You might have to put a small delay at the start of the sub to allow time for the rest of the data to arrive. That is the usual problem users have - not waiting for all the data to arrive. Jim VK7JH MMedit  MMBasic Help |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9063 |
Welcome to the forums. You can use an interrupt as Jim is saying, or you can just check the serial port buffer at any time you like with the LOC function: If LOC(#1)<>0 Then..... That's how I prefer to do it, but the interrupt works just as well. By default, the serial ports are buffered and this is all done for you in the background - you need not do ANYTHING to deal with that in your program, other then reading the receive buffer, or not overflowing the transmit buffer. Unlike the PICAXE, the MM will NOT wait for qualifiers like the SERIN command on the PICAXE does. If there is serial to be had at the correct baud-rate, and the MM COM port is open, that data will automatically be saved into the buffer without the main MM program even being aware that it is there at all - unless you have setup the interrupt, or manually check the buffer with the LOC function. The serial-port buffers are awesome once you get the hang of using them, and they make receiving serial data a breeze - especially when that data could arrive at any time, and your program might miss that data if it happened to be busy at the very time the serial arrives. EDIT: I actually use the MM serial-port buffer as my message queue, meaning that I don't have to deal with managing a message queue in the main program - the serial-port buffer does it all for me. You need one unique end-of-message marker byte, but I just use CR(13 decimal or 0x0D HEX). Read message from buffer till you run into 0x0D, hop out of loop, do whatever has to be done. Check buffer again, if more data there, do it again. Do that over and over till the buffer is cleared, and this all happens automatically one message after another, if you have it all setup right. If you want an example or two, reply here and I can show you have I do it - this being only MY method, and by no means claiming that my way is best or suitable for you or others, but just for an example of how you handle serial data in your MM code, and reading the buffer etc........ Smoke makes things work. When the smoke gets out, it stops! |
||||
lizby Guru Joined: 17/05/2016 Location: United StatesPosts: 3015 |
Ah, automatic background serial receive into a 256-byte buffer. Sweet. Grogster--your technique looks perfect for my needs. Thanks PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9063 |
Yep, but you can increase that receive buffer size if you want. Only the transmit buffer is fixed at 256 bytes. So you could have a 1K receive buffer if you wanted. Smoke makes things work. When the smoke gets out, it stops! |
||||
lizby Guru Joined: 17/05/2016 Location: United StatesPosts: 3015 |
Right. Got it. PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed |
||||
vegipete Guru Joined: 29/01/2013 Location: CanadaPosts: 1082 |
Does this deal gracefully with a message that is not yet complete? If, say, half of an unknown length message has been received when you check the buffer, do you save the characters so far in your own buffer and return a bit later to see if the rest of the message is there? Or do you get a notification when the end-of-message marker byte is received and hence a complete message is waiting? Visit Vegipete's *Mite Library for cool programs. |
||||
Phil23 Guru Joined: 27/03/2016 Location: AustraliaPosts: 1664 |
I'm using the interrupt method in my current HC-12 coms. Can you elaborate a little on the pros & cons of the method you are using? I've got no reason to be using the interrupt method if there's a better/simpler/more reliable/whatever option that will make life easier. Thanks Phil. |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9063 |
@ vegipete - No. Incomplete messages are ignored. Corrupted messages(such as half of one or two bit of two different ones) are also ignored. This is just how I have MY stuff setup, but there is no reason at all why you could not further test the data received AFTER detecting the end-of-message byte, using MID$ and LEFT$ and RIGHT$ etc to validate the message. @ phil23 - no real pros and cons of EITHER, I just prefer to use the LOC function test method, as that worked for me. I am not sure if serial interrupts were even around when I was using the LOC method I still use now. I have a feeling that the serial interrupt was added to the serial port command at some point. I might be totally wrong on that too! However, LOC works for me, so....... At the end of the day, if the interrupt method you are using is working fine for you, I would leave it as-is. I just prefer to manually decide when to check the buffer - as part of the main loop - rather then allowing an interrupt to force a jump out of another routine right when I might be writing or working on changing something in the SD card database - then you lose all that and have to do it again. That is probably why I still like and use the LOC method, as the beautiful serial port buffer will hold any data received, till the program can get back to the main loop, then it just starts dealing with it automatically.(when the main loop checks the buffer) Smoke makes things work. When the smoke gets out, it stops! |
||||
TassyJim Guru Joined: 07/08/2011 Location: AustraliaPosts: 5905 |
@Phil, There is no best method. Either way works and the best method depends on your program flow. If you want to have control over when the serial data is checked, use Grogster's method. If the serial data needs attention immediately and the rest of the program can wait, use interrupts. @vegipete, It is up to you to scan the incoming data to look for the 'end of data' It is also up to you to cater for the possibility of data transmission to get interrupted part way through and no 'end of data' received. It depends on how reliable the data link is. One method I use when using the consloe is Using a COM port could be similar. Once data has started, keep checking for 'end of data' or no more data after a reasonable time. I am using the console so I can use the same data link for program updates. Otherwise, I would use COM1 and RS485. One other reminder, if you are trying to talk to a picaxe from a micromite, use two stop bits one the micromite to give the picaxe time to think. Jim VK7JH MMedit  MMBasic Help |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9063 |
My buffer sucking method is this kind of thing: If LOC(#1)<>0 then MsgRxd .... Sub MsgRxd Pause 250 Do D$=INPUT$(1,#1) 'Suck out one byte from buffer RXD$=RXD$+D$ 'Add byte to message string IF D$=CHR$(13) THEN EXIT DO 'End of message Loop End Sub The PASUE 250 is needed to ensure that there is actually enough data in the buffer to work with past the first byte. Naturally, you could change the IF LOC<>0 line to something else along the lines of IF LOC(#1)>10 THEN... - that kind of idea. This does absolutely no testing for a valid message, it just sucks out bytes from the buffer till it runs into a CR, then it exits with what it has so far. Further testing for an authentic message has to be done in the main program, or, you could certainly have it all inside this sub - once you jump out of the loop that is sucking the bytes out of the buffer. The beauty of this concept is that the serial port buffer does all your message queuing for you, and all you have to do, is deal with each message one after another, as the buffer will queue any messages for you - one less thing to deal with in your main code. EDIT: Fixed formatting mistakes! Smoke makes things work. When the smoke gets out, it stops! |
||||
Phil23 Guru Joined: 27/03/2016 Location: AustraliaPosts: 1664 |
The main concern I have is that maybe my interrupt string is too long, searching & pulling the string apart & checking it a bit & assigning things to variables. Not sure how far I'm pushing the rule of keeping interrupt subs short. |
||||
Phil23 Guru Joined: 27/03/2016 Location: AustraliaPosts: 1664 |
I did a slightly different thing to try & minimise the pause... [Code]OPEN "COM1:9600,,RecComs,120" AS #1[/code].. .. .. [Code]Sub RecComs Local Integer HdrLoc,BufLen=0 Local String HdrFnd If LOC(#1)>100 then 'If COM1 serial port buffer is NOT empty.... DO WHILE BufLen<> LOC(#1) PAUSE 10 BufLen=LOC(#1) LOOP .. .. ..[/code] Mainly because the strings from different devices vary from 130 for one to 160ish for the others. Again, maybe no better methods, but good to hear alternate ideas. Phil. |
||||
Grogster Admin Group Joined: 31/12/2012 Location: New ZealandPosts: 9063 |
This is the key statement from Jim, and particularly accurate in terms of HOW you want to deal with the serial port buffer. As far as serial port interrupts, just like any other interrupt, you really should not be putting any serious code inside the interrupt, as it will slow things down and make your program less effecient overall. Geoff and others(myself included) say to use flags, and set and clear these in the interrupt, then test the flags in the main loop. An example from my latest GUI thing I am trying to finish: SUB EXIT_OK 'Touch interrupt for EXIT and OK buttons on any page LCD_EXIT=0:LCD_OK=0 'Clear flags Select Case Touch(REF) Case BU_EXIT 'EXIT button touched LCD_EXIT=1 Case BU_OK 'OK button touched LCD_OK=1 End Select End SUb Note that all that we ever do, is set a flag, then exit back to the main program. The main program looks at the flags and decides if something needs to be done. This interrupt is VERY fast and the delay inside it is negligible. NOT trying to suggest you should re-write your code - if it works for you, that's fine. I'm just trying to show how flags can be your friend. If it makes you feel any better, I too was pretty confused with the logic of interrupts and how to use them for a start, and I too used to put ALL my code for any interrupt, inside the interrupt, but that is a bad habit to get into, so I forced myself to change. The general rule of thumb in the MMBASIC Bible, is: "Thou shalt not hang about in interrupts." Smoke makes things work. When the smoke gets out, it stops! |
||||
lizby Guru Joined: 17/05/2016 Location: United StatesPosts: 3015 |
So between two Micromites, you might rely on the background serial receive buffers and use a messaging system like the following. [code] STX (0x02 ASCII Start of Text) LEN (Length in bytes of message) MSGNUM (arbitrary message number) MSGTYPE (type of message) DATA (byte of data) [DATA] (optional additional bytes of data) CHECKSUM ETX (0x03 ASCII End of Text) [/code] Then (pseudocode) [code] If LOC(#2) > 1 then ' message length available get STX get LEN check LOC(#2) until it is great enough that the whole message is available read message, calculating checksum Compare calculated checksum to CHECKSUM If checksums equal, send ACK message STX LEN sameMSGNUM ACK (ASCII 0x06) newCHECKSUM ETX If not equal, send NAK STX LEN sameMSGNUM NAK (ASCII 0x15) newCHECKSUM ETX process data received continue [/code] Check LOC(#2) after initial read of message length can be a once-per-loop process. If sender receives a NAK, resend & report; if no ACK received, resend & report. This would provide an asynchronous method of communicating without interrupts. Note: STX and ETX are arbitrary--any (rare) bytes would suit. PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed |
||||
TassyJim Guru Joined: 07/08/2011 Location: AustraliaPosts: 5905 |
If transmission is lost part way through, the receiving micromite will go into an infinite loop. This might be a problem. Can the sending micromite be relied on to detect the lack of <ack> and work out why? I would usually have a timeout in the receiving routine to cover loss of transmission and send a number of <nac>s before ending gracefully. Jim VK7JH MMedit  MMBasic Help |
||||
Print this page |