Propeller zone monitor system(zms)
Rsadeika
Posts: 3,837
in Propeller 1
In my other threads I did the test code for the DS1302, ADC0831, and CM2302. After verifying that the code works, I created a prototype concept, which the program below uses.
The prototype uses a breadboard that holds the FLiP module, WX module, DS1302, ADC0831, and CM2302. On a separate piece of stiff cardboard, I have two li-ion batteries connected in series(8V), voltage divider breakout, and a voltage regulator, which gets connected to the breadbord.
Now I can take the contraption to a specific location, and via a web browser I can get the temp, humidity, voltage, and set the RTC using the internet time. I guess I can say that this proof of concept works as expected.
The hard part is to get this contraption to do some data logging. I do not want to use an SD, takes up to much room on the breadboard, and the code to run it is way to big. Does anybody know if there is way to use the memory on the WX module for storing the data in a csv file. Or is there another easy method of doing data storage that I am not aware of.
I also thought about using the largest EEPROM I could find, placing it on the breadboard, and using that to hold the CSV file information. This I am not sure about. I would like to use the html program to access the csv file and download it to the device that I am running the html program on. Anybody have any other ideas?
Ray
mobTherm.c
mobTherm.html
The prototype uses a breadboard that holds the FLiP module, WX module, DS1302, ADC0831, and CM2302. On a separate piece of stiff cardboard, I have two li-ion batteries connected in series(8V), voltage divider breakout, and a voltage regulator, which gets connected to the breadbord.
Now I can take the contraption to a specific location, and via a web browser I can get the temp, humidity, voltage, and set the RTC using the internet time. I guess I can say that this proof of concept works as expected.
The hard part is to get this contraption to do some data logging. I do not want to use an SD, takes up to much room on the breadboard, and the code to run it is way to big. Does anybody know if there is way to use the memory on the WX module for storing the data in a csv file. Or is there another easy method of doing data storage that I am not aware of.
I also thought about using the largest EEPROM I could find, placing it on the breadboard, and using that to hold the CSV file information. This I am not sure about. I would like to use the html program to access the csv file and download it to the device that I am running the html program on. Anybody have any other ideas?
Ray
mobTherm.c
/* mobTherm.c September 17, 2018 Mobile thermometer project. Use CM2302, DS1302, and ADC0831. */ #include "simpletools.h" #include "wifi.h" #include "dht22.h" #define US_005 (80000000 / 1000000 * 5) int event, id, handle; int getFromPageId; char cmdStr[64]; char *path; /* CM2302 */ volatile float gtemp,ghumid; // Decimal point precision. /**********************/ /* ADC0831 */ volatile float gbatt; int cs, clk, dataOut; void init(int cspin, int clkpin, int dataOutpin) { cs = cspin; high(cs); set_direction(cs,1); clk = clkpin; low(clk); set_direction(clk,1); dataOut = dataOutpin; set_direction(dataOut,0); } int readADC() { int level = 0; low(cs); pause_ticks(US_005); level = 0; for(int i = 0; i < 9; i++) { high(clk); pause_ticks(US_005); low(clk); pause_ticks(US_005); level = (level << 1) | get_state(dataOut); } high(cs); return(level & 0xFF); } /**********************/ /* RTC */ /* Using pins 17,18,19 with the FLiP module.*/ #define ds1302cs 19 #define ds1302sclk 18 #define ds1302io 17 #define dsSec 0x80 #define dsMin 0x82 #define dsHour 0x84 #define dsDate 0x86 #define dsMon 0x88 #define dsDay 0x8A #define dsYear 0x8C #define dsWpa 0x8E #define dsTca 0x90 volatile int seconds,minutes,hours,date,month,day,year,prevSec; int day2,month2,year2; int hour2,minutes2,seconds2; int readDs1302(int myreg) { int readreg = myreg + 1; high(ds1302cs); shift_out(ds1302io, ds1302sclk, LSBFIRST, 8, readreg); int result = shift_in(ds1302io, ds1302sclk, LSBPRE, 8); low(ds1302cs); return result; } void writeDs1302(int myreg, int value) { high(ds1302cs); shift_out(ds1302io, ds1302sclk, LSBFIRST, 8, myreg); shift_out(ds1302io, ds1302sclk, LSBFIRST, 8, value); low(ds1302cs); } static int bcdToD(unsigned int byte, unsigned int mask) { unsigned int b1, b2; byte &= mask; b1 = byte & 0x0F; b2 = ((byte >> 4) & 0x0F) * 10; return b1 + b2; } static unsigned int dToBcd(unsigned int byte) { return((byte / 10) << 4) + (byte % 10); } /**********************/ void get_Time(); void get_Date(); /**********************/ /* COG 1*/ void unit_CM2302(); /* COG 0*/ int main() { // Add startup code here. cog_run(unit_CM2302, 128); pause(50); wifi_start(31, 30, 115200, WX_ALL_COM); // Start WiFi pause(50); getFromPageId = wifi_listen(HTTP, "/tpfm*"); while(1) { // Add main loop code here. wifi_poll(&event, &id, &handle); if(event == 'G') { if(id == getFromPageId) { memset(cmdStr, 0, sizeof(cmdStr)); sprint(cmdStr, "PATH:%d\r", handle); path = wifi_command(cmdStr); if(strstr(path, "/Temp1") !=0) { wifi_print(GET, handle, "%.2f", gtemp); } else if(strstr(path, "/Humid1") !=0) { wifi_print(GET, handle, "%.2f", ghumid); } else if(strstr(path, "Batt") !=0) { wifi_print(GET, handle, "%.2f", gbatt); } } } if(event == 'P') { memset(cmdStr, 0, sizeof(cmdStr)); sprint(cmdStr, "PATH:%d\r", handle); path = wifi_command(cmdStr); if(strstr(path,"/datetime") !=0) { wifi_scan(POST, handle, "month%d%d%d%d%d%d",&month2,&day2,&year2,&hour2,&minutes2,&seconds2); int year1 = dToBcd(year2); writeDs1302(dsYear,year1); int month1 = dToBcd(month2); writeDs1302(dsMon,month1); int date1 = dToBcd(day2); writeDs1302(dsDate,date1); int hour1 = dToBcd(hour2); writeDs1302(dsHour,hour1); int minutes1 = dToBcd(minutes2); writeDs1302(dsMin,minutes1); int seconds1 = dToBcd(seconds2); writeDs1302(dsSec,seconds1); //dt_set(dt); } } //get_Date(); // This shows in terminal screen. //get_Time(); // This shows in terminal screen. //pause(1000); pause(250); } } /**********************/ unit_CM2302() { float temp,humid; init(22,21,20); //22 - dopin, 21 - clkpin, 20 - cspin while(1) { dht22_read(16); pause(150); temp = dht22_getTemp(1); // 1 - Fahrenheit temp = (temp*.10); gtemp = temp; humid = dht22_getHumidity(); humid = (humid*.10); ghumid = humid; int level1 = readADC(); gbatt = ((((level1*4010256)+5000)/1000000)*.01); pause(300); } } void get_Time() { hours = readDs1302(dsHour); putHexLen(hours,2); putStr(":"); minutes = readDs1302(dsMin); putHexLen(minutes,2); putStr(":"); seconds = readDs1302(dsSec); putHexLen(seconds,2); putChar(NL); // New line } void get_Date() { month = readDs1302(dsMon); putHexLen(month,2); putStr("/"); day = readDs1302(dsDate); putHexLen(day,2); putStr("/"); year = readDs1302(dsYear); putHexLen(year,2); putChar(NL); // New line }
mobTherm.html
<!-- mobTherm.html --> <!DOCTYPE HTML> <html> <head> <style> a{ background-color:#637aad; color:white; font-size:23px; margin:5px; width:100px; height:55px; cursor:pointer; padding-top:4px; padding-bottom:4px; } a:hover{background-color:white;color:navy;} </style> </head> <body bgcolor=3b5898> <br> <br> <br> <font face="Arial" size=3 color="cyan"> <div> <a onclick="getFromMcu('Temp1')">Temp1</a> <a onclick="getFromMcu('Humid1')">Humid1</a> <a onclick="getFromMcu('Batt')">Battery</a> <br> <a onclick="datetimeBtn()">DateTime</a> -- Update RTC </div> <br> <br> <br> <font face="Arial" size=5 color="cyan"> <p id = "value">Wating...</p> </body> <script> var getPathExt; function useMcuReply(response) { if(getPathExt == 'Batt1') { var val = document.getElementById("value"); val.innerHTML = "Value: " + response; } else if(getPathExt == 'Temp1') { var val = document.getElementById("value"); val.innerHTML = "Value: " + response; } else if(getPathExt == 'Humid1') { var val = document.getElementById("value"); val.innerHTML = "Value: " + response; } else if(getPathExt == 'Batt') { var val = document.getElementById("value"); val.innerHTML = "Value: " + response; } } function getFromMcu(pathExt) { getPathExt = pathExt; httpGet("/tpfm/" + pathExt, useMcuReply); } function httpGet(path, callback) { var req = new XMLHttpRequest(); req.open("GET", path, true); req.onreadystatechange = function() { if(req.readyState == 4) if(req.status == 200) callback(req.responseText); else callback("Wating..."); } req.send(null); } function httpPost(path, param) { var req = new XMLHttpRequest(); req.open("POST", path, true); req.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); req.send(param); } function datetimeBtn() { var dt = new Date(); day = dt.getDate(); var dt1 = new Date(); month = dt1.getMonth(); month = month +1; var dt2 = new Date(); year = dt2.getFullYear(); var dt3 = new Date(); var hours = dt3.getHours(); var dt4 = new Date(); var minutes = dt4.getMinutes(); var dt5 = new Date(); var seconds = dt5.getSeconds(); var send = "month=" + month + "day=" + day + "year=" + year + "hour=" + hours + "minutes=" + minutes + "seconds=" + seconds; httpPost("/tpfm/datetime",send); } </script> </html>
Comments
I am now reconsidering the use of an SD, for the data logging part. I think I will just have make the SD socket fit somewhere. As for the SD code size, I will just have to make it fit, and work.
I am considering adding a couple more sensors, but I seem to be having trouble finding something I can work with. I want to add a CO2 and Oxygen sensors. The ones that I have seen, I will probably have trouble finding some example C code to make them work. Anybody know of some decent sensors that work with the FLiP module?
Ray
Would something like this SD card socket work, if you installed right-angle headers instead of the straight ones. Then you could plug it vertically into the breadboard to save space.
https://www.parallax.com/product/32313
ps. Any chance of sharing a photo of your breadboard setup? Always good to see pictures!
What will happen is the cardboard that is holding the batteries will get turned upside down and placed underneath the breadboard. Basically the unit will sit on the batteries. I will try to reduce the cardboard size to the size of the breadboard.
Since I am using two li-ion batteries, in series, I will probably remove the voltage regulator, and in that section I will maybe try to fit an SD assembly. I think I have an SD breakout board that was meant to be plugged into the breadboard.
My li-ion batteries are 3.6V 2600mAh, I still have to do some tests to see if they would be able to last a 24, maybe a 48 hour data logging session. Plus I plan to add a yellow LED as warning for a battery charge and with the addition of the CO2 and Oxygen sensors, that should be a substantial power draw, I would think.
Ray
Neat idea with the cardboard though. I like that, and will remember that in the future. It looks very practical for quick experiments and to get parts fixed in place that don't need to be on the breadboard.
Thanks for posting the pics.
I've never worked with oxygen sensing, but I'd have thought there must be some low-power way to sense, and if you can control the power to the sensor and only power it up once in a while, maybe that could extend the battery life. Just pondering aloud
I also did a test run of the SD, it works. I was able to open a file, fwrite() a txt line, and it showed up on the SD as expected. Now the bigger problem to deal with, since I plan to fwrite() global float values, anybody know how to do that. I tried:
and all I see in the file is strange chars. I did not see, in the Learn forum, anything about what can be done with fwrite(); Hopefully somebody has the answer.
Ray
Ray
The problem that I cannot solve is with the SD fwrite() function below. I started out with trying to write a float value to the SD, that did not work. Now, in the Learn forum, it shows an example of how to write a number value to the SD. Below I think I have basically replicated the code necessary, but I still get garbage chars, for the number, in the file, on the SD.
So, is it equipment failure? The function below writes the text string without any problem. It is just having a problem writing a number to the SD card. When I get some today, I will have to do stand alone program for testing the SD functionality. I hope it is not a short coming with the SD function itself, although Parallax was very good at minimizing bugs like that.
Yes, the snippet below runs as a COG, in the larger program.
Ray
Heck no but to save precious Prop cogs and code space, the MM is a useful peripheral device. The on-board BASIC interpreter is a breeze to use.
Yeah I looked at your breadboard and wondered if a bit of re-shuffling would be possible.
The below program basically follows the suggested guide lines for writing to the SD, which are presented on the Learn forum. The "int ubatt = 1049" shows up as garbage chars on the SD card, while the text portion shows up as expected. So, at this point I am not sure what is going on, and what the next step should be. Is it a PropGCC function problem, or is there some wiring connection that I am missing on the SD breakout board. Not even sure about what other test(s) I could try to narrow down the problem.
Ray
Edit: Oh but a text string is no problem....only just picked up on that.
Looks correct to me.
So saved as binary value rather than ascii digits.
So, I guess I need some guidance for the correct way to do what I am trying to accomplish. I wonder if other people have tried data logging in this method, and were getting a correct looking print out of the SD file.
Ray
Perhaps you could do the calculations using integers rather than floating point and then insert the decimal point after converting the result to ascii digits.
The other thing that I have to consider is the html program that goes with this. At the moment I feed the html with float values and it is a breeze to deal with that in the html. Now if I switch to non float values then I am not sure what sort of complexity I will run into in the html code. Boy, this was going so easily, and I just about hit the brick wall, concerning memory availability. I guess I have to re-think what I am doing here.
Ray
In your first post you mentioned that the log data would be stored as a .csv file. If the html program can handle floating point numbers from a .csv file then it does not matter if those numbers are produced by the floating point package and fprintf/sprintf or by integer math and insertion of the decimal point. In both cases they will appear as a string of ascii digits, possibly with an ascii decimal point. Both 123.45 and 678 would be valid floating point numbers to any software that deals with .csv files.
If the floating point software fits in the available space then by all means use it. If not, then doing the calculations with integers and converting them to decimal digits is not that difficult, and results in smaller and faster code. I use integer math almost exclusively for converting sensor and adc readings to logged or displayed output readings.
The project board is still useful, but it just does not have a working data logger component. Maybe in the near future, I will come across some idea as to how to make the data logging work, but not today. As for adding a couple of more sensors, and the corresponding support programs, not going to work, not enough memory available. Not sure what the next project will be, but I am more informed as to what the limitations of 32K memory are, with the Propeller chip and PropGCC.
I suppose I could try to learn PASM, and recode everything in that, but I am not sure that that would even reduce the size of the program code.
Ray
I have commercial Prop based dataloggers that do far more and include Ethernet servers and FAT32. I too encountered memory and speed limitations many years ago but I didn't accept that and stop there, which is why I developed the Tachyon "environment" for the Prop that runs on the Prop itself. You say you could learn PASM perhaps. Is PASM taught in colleges? No! Is it "popular" or "easy"? No, but it's not hard and neither is Tachyon. Now we even have it built into the ROM of the P2.
I do these things as a hobby, and this project was not intended to be for commercial value. I also do this to keep the mind active and agile, I am, after all 73 years of age, not an excuse, just a fact. So, as the popular saying goes, "I can see the light at the end of the tunnel".
As for Forth, I have known about that language for, what, about thirty years now. If it was more of a scripting format, I would probably be more interested. I have really gotten used to the idea of the structured program style, it seems like I have more control over what the program is going to look like and do.
Now as for the Tachyon "environment" , I am not so sure that you have all of the so called "functions" available to drive all the different components that I am using, and the primary one would be the WiFi. I also have the html component, which I use to get a quick glance as to what the components are reporting. True, that this would be a much better approach than using PASM, but …
At this point I am open to a different approach to get the project to a complete working solution. Not sure as to how much energy I have to accomplish this, but it could be a really good reason to get up in the morning. Yeah, you young people will get old and will be experiencing the same things.
Ray
I thought the WiFi stuff was just plain serial which in Tachyon is as easy as saying "921,600 SERBAUD 5 SERIAL PRINT" HELLO WORLD" and it does just that. However my Ethernet servers are way more complicated than that of course since they handle the protocols. As for HTML isn't that a matter of serving up a web page from a file as I do now but using "Forth Script" instead of javascript? I'm not sure of your exact requirements as I haven't seen your code.
As for knowing what you get, here I create a new demo function, test it, and then look at the code it produced. (bear in mind my simple HELP "decompiler")
Opening and accessing a file is easy too: The ... are the prompts.
As for the WiFi part, I was also referring to the convenience of being able to program the FLiP module at a remote location.
I was also considering PropBasic, but that language just simply does not have the language support that I would require. The requirements are just great, for me anyway, for it to be productive.
So, what is left, Spin, that I believe would run out of memory in quick order also. Besides, I get really messed up with that indentation stuff. I do some programming in Python, and I also curse it, whenever I get caught up with the indentation quagmire.
Back to Tachyon, does it have a scripting and then compile format? Or is it strictly an interactive format? I think I do not have to many more programing choices as to what can be done with the Propeller.
Ray
For instance, this "script" can be sent over serial and executed like this or you can save it with a name and then run it at any time with
Is this what you are getting at?
But it is very easy to try it, just download it and connect a terminal at 115200 baud etc.
I am not sure if I remember correctly, but I think the original forth was a compiled format, meaning you would write the code, in a file format, than you would compile it, and run it? Anyway, I am not a big fan of the interactive programming style.
Ray
Can your post a zipfile of your project? I suspect there are a few things that could be done to reduce the binary size. Did you try the fprintf that I posted? That should help.
Programming in C on the P1 is a challenge because of the 32K of RAM. The P2 will be a great chip for running C code because it doesn't have the same memory limitation. You could try using CSPIN to convert your C code to Spin. This should produce a smaller binary size. Or you could write it in Spin and used FSRW for the SD file driver.
Anyhow, if you could post a zipfile of your project I might be able to give you some tips on how to make it fit within 32K.
At the moment I am testing your fprintf() command, yes it is using a lot less code. I am testing the RTC data output, luckily it provides the output in a hex format, so fprintf() can deal with that using "%x".
It would be nice if your fprintf() had a "%f", to deal with the float numbers, then I would be all set, I think.
The other problem that I am seeing is how fprintf() is placing the data in the file. For instance, if I have this: it seems that in the file it shows up as, 60,70,14:14:14,09/29/18. What I really want is, 09/29/18,14:14:14,70,60. Something I am not catching on to with the way the data stream is working.
Since the gtemp and ghumid are float, when I use fprintf(), the values are showing up as a eight digit number that does not look like the float number at all.
Ray