Home
JAQForum Ver 20.06
Log In or Join  
Active Topics
Local Time 23:55 29 Apr 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 : Micromite to micromite communication

Author Message
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3015
Posted: 02:46pm 11 Jan 2017
Copy link to clipboard 
Print this post

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: Australia
Posts: 5905
Posted: 06:40pm 11 Jan 2017
Copy link to clipboard 
Print this post

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 States
Posts: 3015
Posted: 06:44pm 11 Jan 2017
Copy link to clipboard 
Print this post

"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: Australia
Posts: 5905
Posted: 07:18pm 11 Jan 2017
Copy link to clipboard 
Print this post

From the manual (Appendix A – Serial Communications Serial Communications):

  Quote  It has the form "COMn: baud, buf, int, intlevel, DE, 9BIT, INV, OC, S2" where:
‘n’ is the serial port number for either COM1: or COM2:.
‘baud’ is the baud rate – see Baud Rate below for the limits in the speed Default is 9600.
‘buf’ is the receive buffer size in bytes (default size is 256). The transmit buffer is fixed at 256 bytes.
‘int’ is a user defined subroutine which will be called when the serial port has received some data. The
default is no interrupt.
‘intlevel’ is the number of characters that must be waiting in the receive queue before the receive
interrupt subroutine is called. The default is 1 character.


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 Zealand
Posts: 9063
Posted: 03:02am 12 Jan 2017
Copy link to clipboard 
Print this post

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........

Edited by Grogster 2017-01-13
Smoke makes things work. When the smoke gets out, it stops!
 
lizby
Guru

Joined: 17/05/2016
Location: United States
Posts: 3015
Posted: 03:11am 12 Jan 2017
Copy link to clipboard 
Print this post

Ah, automatic background serial receive into a 256-byte buffer. Sweet.

Grogster--your technique looks perfect for my needs.

Thanks
Edited by lizby 2017-01-13
PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
Grogster

Admin Group

Joined: 31/12/2012
Location: New Zealand
Posts: 9063
Posted: 03:14am 12 Jan 2017
Copy link to clipboard 
Print this post

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 States
Posts: 3015
Posted: 03:15am 12 Jan 2017
Copy link to clipboard 
Print this post

Right. Got it.

PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
vegipete

Guru

Joined: 29/01/2013
Location: Canada
Posts: 1082
Posted: 08:39am 12 Jan 2017
Copy link to clipboard 
Print this post

  Grogster said  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.

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?Edited by vegipete 2017-01-13
Visit Vegipete's *Mite Library for cool programs.
 
Phil23
Guru

Joined: 27/03/2016
Location: Australia
Posts: 1664
Posted: 11:02am 12 Jan 2017
Copy link to clipboard 
Print this post

  Grogster said  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.


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 Zealand
Posts: 9063
Posted: 12:10pm 12 Jan 2017
Copy link to clipboard 
Print this post

@ 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: Australia
Posts: 5905
Posted: 12:18pm 12 Jan 2017
Copy link to clipboard 
Print this post

@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
  Quote   DO
k$=
INKEY$
IF k$<>"" THEN doKey
LOOP
END

SUB doKey
cmd$ =
""
DO
PAUSE 10
cmd$ = cmd$+k$
k$=
INKEY$
LOOP UNTIL k$="" OR k$ = CHR$(13)
DoCMD
END SUB

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 Zealand
Posts: 9063
Posted: 12:35pm 12 Jan 2017
Copy link to clipboard 
Print this post

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!Edited by Grogster 2017-01-13
Smoke makes things work. When the smoke gets out, it stops!
 
Phil23
Guru

Joined: 27/03/2016
Location: Australia
Posts: 1664
Posted: 12:39pm 12 Jan 2017
Copy link to clipboard 
Print this post

  Grogster said  At the end of the day, if the interrupt method you are using is working fine for you, I would leave it as-is.


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: Australia
Posts: 1664
Posted: 12:49pm 12 Jan 2017
Copy link to clipboard 
Print this post

  Grogster said   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......


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 Zealand
Posts: 9063
Posted: 01:13pm 12 Jan 2017
Copy link to clipboard 
Print this post

  Jim said  
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.


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.

  Phil23 said  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.


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 States
Posts: 3015
Posted: 05:05am 13 Jan 2017
Copy link to clipboard 
Print this post

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.
Edited by lizby 2017-01-14
PicoMite, Armmite F4, SensorKits, MMBasic Hardware, Games, etc. on fruitoftheshed
 
TassyJim

Guru

Joined: 07/08/2011
Location: Australia
Posts: 5905
Posted: 11:53am 13 Jan 2017
Copy link to clipboard 
Print this post

  lizby said  
check LOC(#2) until it is great enough that the whole message is available

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


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

© JAQ Software 2024