![]() |
Forum Index : Microcontroller and PC projects : Newie got a few questions
![]() ![]() ![]() ![]() |
|||||
Author | Message | ||||
lew247![]() Guru ![]() Joined: 23/12/2015 Location: United KingdomPosts: 1702 |
Thanks, I'll be able to sort it out with that help |
||||
lew247![]() Guru ![]() Joined: 23/12/2015 Location: United KingdomPosts: 1702 |
I spoke too soon What I want to do is this [code] Open "COM1:19200" As #2 'Open port for HC-12 TX/RX 'OPEN "COM3:9200" AS #3 If LOC(#2) <> 0 then SERIALFLUSH 'If COM1 serial port buffer is NOT empty.... if LOC(#3) <> 0 then SERIALFLUSH1 DO clock routine and other bits go here LOOP End Sub SERIALFLUSH Local D$ 'Define D$ only for use by this subroutine(ignores any D$ in main code) D$ = Input$(40, #2) 'Suck everything in buffer out Print D$; End Sub Sub SERIALFLUSH1 Local F$ 'Define D$ only for use by this subroutine(ignores any D$ in main code) D$ = Input$(80, #3) 'Suck everything in buffer out Print F$; End Sub The only way I've got part of it working is this [quote] Open "COM1:19200" As #2 'Open port for HC-12 TX/RX 'OPEN "COM3:9200" AS #3 If LOC(#2)<>0 then LOOP 'If COM1 serial port buffer is NOT empty.... DO IF LOC(#2)>1 THEN SERIALFLUSH SERIALFLUSH pause 500 LOOP End Sub SERIALFLUSH Local D$ 'Define D$ only for use by this subroutine(ignores any D$ in main code) D$ = Input$(40, #2) 'Suck everything in buffer out Print D$; End Sub [/quote] |
||||
Zonker![]() Guru ![]() Joined: 18/08/2012 Location: United StatesPosts: 767 |
Lew.. Sub SERIALFLUSH1
Local F$ 'Define D$ only for use by this subroutine(ignores any D$ in main code) D$ = Input$(80, #3) 'Suck everything in buffer out Print F$; End Sub This one has the data going back into D$ (not F$) Prints nothing... ![]() This is easy to do, and I have done it many times... ![]() Easy fix... Also, you open #3 at 9200 baud...? not 9600... I notice also, you hit the action subs if ANY amount of data is collected... Usually, you would wait for a small number of characters to build up first. If you know how many are expected, then set the LOC on a few less... If you know what the termination character is (like cr/lf) then you can also check for this... Data is usually collected from the RX buffer one character at a time, and then "added" to the D$ or F$ holding variable... While doing this with a simple DO loop, you can also be checking for the termination character... |
||||
Grogster![]() Admin Group ![]() Joined: 31/12/2012 Location: New ZealandPosts: 9493 |
Yes, as Zonker says.... Note my examples are just examples, and I have not tried it with an HC-12 module. However, it should work as commented. In your subs, you are sucking 40 bytes out of the buffer in SERIALFLUSH and 80 bytes in SERIALFLUSH1. Please note that if there is NOT 40 or 80 bytes in there to suck out, you will get that "Error: Number out of bounds." error again, as you would be trying to read what is not there. ![]() Writing code is fun, eh?! ![]() ![]() I also agree with Zonker on the CR or LF idea. This is how I detect all my serial coms, but that is in MY case, which is specific to my serial devices and needs. Smoke makes things work. When the smoke gets out, it stops! |
||||
lew247![]() Guru ![]() Joined: 23/12/2015 Location: United KingdomPosts: 1702 |
Now I#'m back in the country again I can start working on this again I'm "slightly" (very) confused over input$ and character length If I use D$ = Input$(80, #3) 'Suck everything in buffer out That assumes there are 80 characters coming in via the com port However does characters mean each letter and space, or each comma seperated item? for instance how many characters are there in this string send to the serial port? [quote]{"city":{"id":2651357,"name":"Denton","coord":{"lon":-2.11822,"lat":53.456779},"country":"GB","population":0},"cod":"200 ","message":0.0092,"cnt":7,"list":[{"dt":1472385600,"temp":{"day":20.82,"min":15.1,"max":20.82,"night":15.1,"eve":18.07,"morn":20.82},"pressure":1000.23,"humidity":91,"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10d"}] ,"speed":2.01,"deg":7,"clouds":92,"rain":2.54},{"dt":1472472000,"temp":{"day":18.7,"min":11.34,"max":19.24,"night":11.34 ,"eve":17.68,"morn":14.1},"pressure":1009.58,"humidity":77,"weather": [{"id":800,"main":"Clear","description":"clear sky","icon":"01d"}] ,"speed":4.82,"deg":284,"clouds":0},{"dt":1472558400,"temp":{"day":22.25,"min":8.84,"max":23.07,"night":14.47,"eve":21.2 2,"morn":8.84},"pressure":1010.56,"humidity":67,"weather":[{"id":800,"main":"Clear","description":"clear sky","icon":"01d"}] ,"speed":3.61,"deg":218,"clouds":0},{"dt":1472644800,"temp":{"day":20.04,"min":11.67,"max":20.04,"night":13.12,"eve":18. 19,"morn":11.67},"pressure":1003.72,"humidity":70,"weather":[{"id":500,"main":"Rain","description":"light rain","icon":"10d"}] ,"speed":4.41,"deg":226,"clouds":0,"rain":1.44},{"dt":1472731200,"temp":{"day":16.42,"min":8.1,"max":18.15,"night":8.1," eve":16.97,"morn":11.79},"pressure":1010.7,"humidity":75,"weather": [{"id":500,"main":"Rain","description":"light rain","icon":"10d"}] ,"speed":2.62,"deg":293,"clouds":8,"rain":0.22},{"dt":1472817600,"temp":{"day":20.17,"min":11.54,"max":20.17,"night":11. 54,"eve":18.96,"morn":16.62},"pressure":1012.65,"humidity":0,"weather": [{"id":500,"main":"Rain","description":"light rain","icon":"10d"}] ,"speed":5.94,"deg":239,"clouds":61,"rain":0.87},{"dt":1472904000,"temp":{"day":23.21,"min":10.51,"max":23.5,"night":14. 51,"eve":23.5,"morn":10.51},"pressure":1013.14,"humidity":0,"weather": [{"id":800,"main":"Clear","description":"clear sky","icon":"01d"}],"speed":3.89,"deg":140,"clouds":0}]}[/quote] Edit: or if thats too many to count How many are in this string?[quote]{"coord":{"lon":-2.12,"lat":53.46},"weather":[{"id":802,"main":"Clouds","description":"scattered clouds","icon":"03d"}] ,"base":"stations","main":{"temp":17.99,"pressure":1013,"humidity":68,"temp_min":16,"temp_max":20},"visibility":10000,"w ind":{"speed":5.1,"deg":300},"clouds":{"all":40},"dt":1472403905,"sys":{"type":1,"id":5060,"message":0.0305,"country":"G B","sunrise":1472361153,"sunset":1472411099},"id":2651357,"name":"Denton","cod":200} [/quote] And am I right in assuming that If I use D$ = Input$(80, #3) If there are less than 80 characters the string is still received correctly and will work, but if there are more than 80 characters then the string received will be ignored by the program and it would appear on first glance the com port isn't working? |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 3999 |
I think it's: Fewer than 80 and it will wait until there are 80. Forever, if needs be. So, if you expect 80 but there is a tiny chance one will be corrupted your program may hang forever. (It may be wise to assume this can happen and program differently.) It counts each char (byte), so any commas are not special just more char(s). More than 80 and you get the 80 you asked for with the rest still in the buffer. John |
||||
Phil23 Guru ![]() Joined: 27/03/2016 Location: AustraliaPosts: 1667 |
Yes, Every Single ASCII chatacter counts. [Code]{"This is",50 Characters:of text, etc, etc, "etc".[/code] If it was Printed Without a semi colon, Ie [Code]Data$="{"This is",15 Characters:of text, etc, etc, "etc"." Print#1, Data$ Vs Print#1, Data$;[/code] It would be 52 characters long as the string would have a CR & LF at the end. The two strings you show above are 1928 & 446 characters long according to Excel. Phil. |
||||
lew247![]() Guru ![]() Joined: 23/12/2015 Location: United KingdomPosts: 1702 |
Thanks you Phil and JohnS I understand it fine now ![]() However what do I use IF the serial port is going to have 2 different sets of data coming in, one set is 1928 characters, and the other set is 446 characters? If I want to pick out words that are comma seperated like this [quote]mmrain "," , mmrain2 "," , hightemp "," , hightemp2 "," ,[/quote] Would I be correct in assuming that I use arg$ ie arg$(0) would select mmrain and arg$(3) would select hightemp? |
||||
WhiteWizzard Guru ![]() Joined: 05/04/2013 Location: United KingdomPosts: 2927 |
I don't believe ARG$ is a function (or at least its not in the manual!). You may want to use INSTR to search for the position of the words (if the words are known), and then read the subsequent data with MID$ WW |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6221 |
Before you get too carried away, strings in MMBasic are limited to 255 characters. The com buffer can be configured to hold more so I would read the port in bite sized chunks and search them for your keywords before getting the next chunk. Someone here did a program for scraping weather data. Jim VK7JH MMedit |
||||
lew247![]() Guru ![]() Joined: 23/12/2015 Location: United KingdomPosts: 1702 |
Thanks Phil I can see a problem so, while I know what "words" will be sent the actual character length can vary, for instance the pressure might at one time be 948.34 another time it might be 1024.87 for example That's why it would be better to be able to select specific "words" which are a number of comma's apart, that way I wouldn't need to know the exact character length or what the actual "word" will be an example of what I mean The serial port will be receiving these "words?" "Today," & desc & "," & icon & "," & temp & "," & press &"," & speed & "," & dir & "," & humid BUT the actual words received will vary each time for example desc one time might be "light clouds" but another time might be "sunny" dir could be 1 or it could be 360 and so on |
||||
lew247![]() Guru ![]() Joined: 23/12/2015 Location: United KingdomPosts: 1702 |
Thanks TassyJim I actualy made an error above It's the ESP8266 that will be receiving all those characters and parsing them, then it will be transmitting only the data I actually want on it's serial port to the Micromite But as a result I won't know the exact number of characters coming into the serial port at any one time (but it will be less than 255) and each item of data will have a comma separating them |
||||
TassyJim![]() Guru ![]() Joined: 07/08/2011 Location: AustraliaPosts: 6221 |
If the data is being sent in one burst, 1. read the data 2. add it onto the end of a bugger string 3. wait a brief while 4. go back and get the next chunk and add it onto the end of your buffer string. If there is no data available after a suitable length wait, you can assume that the sending has finished and you have all the data to play with. Another option. You know the maximum amount of data that gets send in one event so you can work out the time it takes to send (depends on the baud rate and number of characters. When you get the interrupt signalling the data has started to arrive, wait the maximum time before retrieving the data. That way you know you have got it all in one chunk. If you know the number of fields arriving, you know the number of commas so you can count them. If you have control over the sending, add a CR to the end so you know you have it all. And there are lots of other ways to do the task. AS long as the sending system and the receiving system know what the other is doing. Jim VK7JH MMedit |
||||
WhiteWizzard Guru ![]() Joined: 05/04/2013 Location: United KingdomPosts: 2927 |
From the data samples you send, the 'word' is always in speech marks, then there is a colon, then there is the 'data'. Any more 'chunks' of information are separated by a comma; but they follow the same pattern above. Note the 'data' can be numeric (not in speech marks), or wording (in speech marks). So an example from your data: "id":800,"main":"Clear","description":"clear sky" Are you trying to read the data 'between' commas (i.e. "id":800) or are you trying to read the 'word headings' (i.e. ID) so you can then 'extract' the data (800)? |
||||
lew247![]() Guru ![]() Joined: 23/12/2015 Location: United KingdomPosts: 1702 |
Basically I'm going to get the ESP to send the data as follows "Start", data1,data2, data3 and so on then "end" That way there will be a start and an end to pick out valid data EACH item will be seperated by a comma what I need to do is check there is a start and end being received by the micromite THEN once there is valid data in the Serial buffer be able to pick out sections of data for example I might want to PRINT data1 but I might want to do something different Data3 Hope that made sense |
||||
matherp Guru ![]() Joined: 11/12/2012 Location: United KingdomPosts: 10071 |
The data is in JSON format, see wikipedia I can't find a full JSON parser written in Basic although MikeO has done some great work on this |
||||
JohnS Guru ![]() Joined: 18/11/2011 Location: United KingdomPosts: 3999 |
I'd work on the basis that you need to build up a string char by char from the serial buffer (LOC will tell you if there's at least one) because you have functions that can work on a string. Then you need to allow for errors such as inserted/corrupted chars. So you need to allow for things such as a start but no end, two starts etc. If each item has a trailing comma you can separate the items using that (INSTR can find a comma, for example). If it's something else then use that. Then you need to allow for each item possibly being corrupted. And so on. Just think logically. (You can't program anything robust otherwise.) It might be simpler to write the code if you don't care if it crashes / hangs / is unreliable from time to time. The code itself may be about the same length if you make it robust but may well need harder thought... John |
||||
jman![]() Guru ![]() Joined: 12/06/2011 Location: New ZealandPosts: 711 |
Hi Looks like you are trying parse some weather information. Not sure if this helps but they way I do it is use a web server running PHP (Most Web Servers can do this) This downloads and does a parse on the json and then sends the results in nice linefeed delimited format to the MM. As I know none of the lines are more than 255 characters and I know how many lines to expect reading the data from the com port via the ESP8266 is easy Do Line Input #1, C$ If echo Then Print c$ Loop While C$ <> "START" Print "Start found ";C$ Do I=I+1 Line Input #1, WData$(I) Print WData$(I) Loop While WData$(I) <> "END" Print "End Found ";WData$(I) End Sub Below is the output from the PHP script of course you can customize it to suit your needs and taste START Mon Time 21:40:06 29-08-2016 Temperature 08 Humidity 76 Pressure 1008 Mon 29-08-2016 Max : 19 Min : 07 mostlycloudy Sunrise : 07:01 Sunset : 17:59 Wind SPD : 4 Mostly cloudy. Low 7C. Tue 30-08-2016 Max : 14 Min : 03 partlycloudy Sunrise : 06:59 Sunset : 18:01 Wind SPD : 13 Some clouds in the morning will give way to mainly sunny skies for the afternoon. High 14C. Winds ESE at 10 to 15 km/h. Wed 31-08-2016 Max : 13 Min : 02 clear Sunrise : 06:58 Sunset : 18:02 Wind SPD : 23 Sunny. High 13C. Winds ENE at 15 to 30 km/h. Thu 01-09-2016 Max : 16 Min : 07 mostlycloudy Sunrise : 06:56 Sunset : 18:03 Wind SPD : 23 Partly cloudy. High 16C. Winds NNW at 15 to 30 km/h. Fri 02-09-2016 Max : 19 Min : 06 clear Sunrise : 06:54 Sunset : 18:04 Wind SPD : 19 Sunshine. High 19C. Winds NNW at 15 to 25 km/h. Sat 03-09-2016 Max : 13 Min : 06 partlycloudy Sunrise : 06:52 Sunset : 18:05 Wind SPD : 14 Partly cloudy. High 14C. Winds SE at 10 to 15 km/h. Christchurch END To use the PHP use the following format http://your-url-here/test.php?Key=xxxxxx&Location=NZCH This uses https://www.wunderground.com/ to obtain the weather data you will need to get an API key from them (There are free). 2016-08-29_093449_Weather.zip Please note I am no PHP expert so the PHP is not very pretty but it does work Hope this helps Regards Jman |
||||
WhiteWizzard Guru ![]() Joined: 05/04/2013 Location: United KingdomPosts: 2927 |
If data1 always reprints the same data item, then this will be fine, but what if data1 is a different data item? This is why I should think the word (header, call it whatever) is relevant so that you know what the subsequent data represent. Anyway, if you just want to extract the 'characters' between commas then here is a little demo program for you. I am simply looking for the first comma in a string (with INSTR), then looking if there is another comma, then if so, print the characters between the commas with the MID$ function. Keep going until no more commas, in which case just finally print out the characters after the last comma. DIM a$ = "Start,123,456,hello,test,1a2s3,,test2, end" 'populate our test string PRINT a$ 'display our test string p1 = INSTR(1,a$,",") 'look for position of first comma ww: 'a label which we will jump back to continually until we see no more commas IF p1<> 0 AND p1 <> LEN(a$) THEN 'check there is a comma and its position isn't at the end of the string p2 = INSTR(p1+1,a$,",") 'look for next comma AFTER current comma (i.e. from p1+1) IF p2 THEN 'if we found another comma then now extract data between commas.... PRINT MID$(a$,p1+1,p2-p1-1) 'for now just print data 'Want data between commas hence start at p1+1, and for number of characters up to second comma i.e. p2-p1-1 p1=p2 'so we can loop through string, set new p1 as p2 and look for next comma (into p2 if comma exists) GOTO ww 'go loop through until no more commas ELSE PRINT MID$(a$,p1+1,LEN(a$)-p1) 'no more commas so print remaining characters ENDIF ENDIF |
||||
lew247![]() Guru ![]() Joined: 23/12/2015 Location: United KingdomPosts: 1702 |
WW that is what I needed thanks, I can work from that to get mine to do what I want. Thanks everyone else for the help, yes the ESP gets JSON and iv'e already got it parsing only the actual information I need sent to the Micromite. |
||||
![]() ![]() ![]() ![]() |
![]() |
![]() |
The Back Shed's forum code is written, and hosted, in Australia. | © JAQ Software 2025 |