I wonder if the problem does not come from here:
if (ResistanceCompensated >= SWPkPAarray[74]) {}
Should it be not 16?
I wonder if the problem does not come from here:
if (ResistanceCompensated >= SWPkPAarray[74]) {}
Should it be not 16?
Dear hard-shovel,
I do not know if you are still around and if you can help me a bit.
I actually put into the soil a watermark at 20cm. I add some water to see the watermark measurement and I used your proposition (code)
I can not understand why I have a WRm of 518 and it retrun me a 200kPa It should be 0
Getting WM1 (SMX):
Frequency at 15: 6896Hz WRM: 518
WRM: 518
WRMc: 518
SWP: 200
Here si the code:
Note: sw.something. The sw is beacuse I use Seesaw Seesaw borad from Adafruit to have more DIO
// getting the swp.
// wm1_power_pin is pin which ppower smx
// wm1_power_pin is the pin read the value
// val is the return value
get_wmsmx(wm1_power_pin, wm1_read_pin, 1000000, val, true);
mesMesures[c_wm1][capteur_wm1_id].valeur = val; // The final SWP is store here
Dont pain attention at 'alternative'. It's alway true and I will clean the code.
void get_wmsmx(int powerPin, int pinRead, unsigned long timeout, int16_t &val, bool alternative)
{
sw.digitalWrite(powerPin, HIGH);
delay(1000); // Need to have the sensor "in equilibre" with the soil.
int highInput, lowInput; // Store high and low time of wave in microseconds
float totalInput; // Temp store of total time of duration for one cycle of high and low pulse
float frequency; // calculated freqency 1/total time of one cycle.
int16_t swp;
int percent=0;
int32_t wrm;
//float Tsoil=24; //temp
highInput = pulseIn(pinRead,HIGH);
lowInput = pulseIn(pinRead,LOW);
totalInput = highInput + lowInput;
frequency = 1000000 / totalInput;
if (highInput >0 && lowInput>0)
{
Si.sprint(F("Frequency at "),2); Si.sprint(pinRead,2); Si.sprint(F(": "),2); Si.sprint((int16_t)frequency,2); Si.sprint(F("Hz "),2);
}
else
{
Si.sprint(F("frequency: "),2);
Si.sprintln(F("Error"),2);
}
delay(500);
sw.digitalWrite(powerPin, LOW);
int16_t Tsoil = mesMesures[c_temperature_soil][capteur_temperature_soil_id].valeur;
if(alternative == false)
{
// That is my old code. I will remove it
wrm = map(frequency,48,13233,27950,550); // Must control the frequency for 440 and 27950
Si.sprint(F("WRM: "),2); Si.sprint(wrm,2); Si.sprintln(F(" Ohm"),2);
Si.sprintln(F("Calculate SWP"),2);
//kPa = (3.213 * kohms + 4.093) / (1 - 0.009733 * kohms - 0.01205 * Celsius)
swp = (int16_t)(3.213 * (wrm/1000) + 4.093) / (1 - 0.009733 * (wrm/1000) - 0.01205 * Tsoil);
Si.sprint(F("SWP: "),2); Si.sprint(swp,2); Si.sprint(F("kPa"),2);
Si.sprint(F(" for a soil temp of "),2); Si.sprintln(Tsoil,2);
//val = (int16_t)percent;
val = swp;
}
else
{
resistanceCalc(frequency, wrm);
Si.sprint(F("WRM: "),2);
Si.sprintln(wrm,2);
kPaCalc(wrm, Tsoil, swp);
val = swp;
}
Si.sprint(F("SWP: "),2); Si.sprintln(swp,2);
}
//---------------------------------------------------------------
void resistanceCalc(float frequencyInput, int32_t &wrm){
wrm=0;
// Convert from freqency to Resistance measurement
// From SMX.pdf datasheet, page 6
// 48 Hz = 10,000,000 Ohms
// 76 Hz = 262,144 Ohms
// 13233 Hz = 0 ohms
// using lookup table held in the array RESISTORarray
//frequencyInput = constrain(frequencyInput,50, 13233);
//float newVal;
if (frequencyInput <= RESISTORarray[0]) { // Minimum value
wrm = RESISTORarray[0+1];
}
if (frequencyInput >= RESISTORarray[74]) { // Maximum value
wrm = RESISTORarray[74+1];
}
for (int i=0; i<74; i=i+2) {
if ((frequencyInput >= RESISTORarray[i]) && (frequencyInput <= RESISTORarray[i+2]))
{
wrm = RESISTORarray[i+1] - ((RESISTORarray[i+1]-RESISTORarray[i+3]) * ((frequencyInput-RESISTORarray[i]) / (RESISTORarray[i+2]-RESISTORarray[i])));
break;
}
}
Si.sprint(F("WRM: "),2); Si.sprintln(wrm,2);
}
void kPaCalc(int32_t ResistanceInput, int16_t FTemperatureInput, int16_t &swp){
// Convert from Resistance to SWP kPa measurement
// From SMX.pdf datasheet, page 7
// 550 Ohms = 0 SWP kPa
// 6000 Ohms = 35 SWP kPa
// 28075 Ohms =200 SWP kPa
// using lookup table held in the array SWPkPAarray
// table valid for temperature of 75F, 24C
// for increase of 1°F increase resistance by 1%.
// ** this function accepts temperature in Fahrenheit units **
//float newVal;
// Adjust compensate resistance for temperature and cpnvert celculs to Fahrenheit
// per page 8 of SMX.pdf
swp=0;
float ResistanceCompensated = ResistanceInput *(1 + 0.001*((FTemperatureInput * 1.8 + 32)-75));
Si.sprint(F("WRMc: "),2); Si.sprintln((int16_t)ResistanceCompensated,2);
if (ResistanceCompensated <= SWPkPAarray[0]) { // Minimum value
swp = SWPkPAarray[0+1];
}
if (ResistanceCompensated >= SWPkPAarray[74]) { // Maximum value
swp = SWPkPAarray[16+1];
}
//for (int i=0; i<SWPkPAarray.length-2; i=i+2) {
for (int i=0; i<16; i=i+2) {
if ((ResistanceCompensated >= SWPkPAarray[i]) && (ResistanceCompensated <= SWPkPAarray[i+2])) {
swp = SWPkPAarray[i+1] - ((SWPkPAarray[i+1]-SWPkPAarray[i+3]) * ((ResistanceInput-SWPkPAarray[i]) / (SWPkPAarray[i+2]-SWPkPAarray[i])));
break;
}
}
//return newVal;
}
long RESISTORarray[76] = {
// Watermark Sensor SMX interface Hz to Resistance lookup table per SMX.pdf page 6.
48, 10000000,
76, 262144,
85, 196608,
103, 131072,
122, 98304,
157, 65536,
194, 49152,
264, 32768,
335, 24567,
476, 16384,
612, 12288,
874, 8192,
1135, 6144,
1623, 4096,
2071, 3072,
2862, 2048,
3557, 1536,
4697, 1024,
5596, 768,
6932, 512,
7878, 384,
9104, 256,
9882, 192,
10802, 128,
11312, 96,
11893, 64,
12200, 48,
12526, 32,
12708, 24,
12871, 16,
12962, 12,
13047, 8,
13092, 6,
13139, 4,
13162, 3,
13186, 2,
13209, 1,
13233, 0,
};
long SWPkPAarray[18]{
// Watermark Sensor SMX interface Resistance to SWP kPa lookup table per SMX.pdf page 7.
// this table is valid at temperature of 75F, 24C
550, 0,
1000, 9,
1100, 10,
2000, 15,
6000, 35,
9200, 55,
12200, 75,
15575, 100,
28075, 200,
};
Many thank!!
@hard-shovel
I think, now it's clearer for me.
First, SMX module has a range from 48hz to 13233hz
But the watermak sensor has a range from 550 to 27950 ohm
As we use watermark to measure the soil mostire, wehave to consier the range of 550 to 27950 which match with 6700Hz (more or less) and 310Hz. What is below or above is not relevant for moisture measurement with Wathermark.
Are you agree with me?
@hard-shovel
Hello,it's verry interresting what you shared.
Today I left the SMX input open. No sensor no resistance. I discovered, I get the same value when the sensor is in a fully dried soil. And I did not have the sensor with me.
Yes, I have a box that I fill up with soil of the crop where the sensors will be for the measurement.
We only want to monitor the soil moiture from June to Septembre and the result will be display in a graph.
Some week ago, I wrote a loop to simulate the watermark voltage. In your second table you show that KPA can be from -332 to -1300 and then immediately to a positif number. That difference make me souspicious. I am still souspicous when I look from 48Hz to 157Hz (the doc give a range of frequency from 48Hz to 13233Hz.)
But at the final, as I understood, what is relevant is from 1220Hz to +/- 310hz (from 550Ohm to 27950). From 27950 and above, the soil is fully dry, whatever if the kPa goes to -1300 or -352. And from 550Ohm or below, the soil is fully wet.
@hard-shovel
Thank a lot for your code, I tested it.
It's interresting but I finaly got the same values as I tested until now with untrustable function (wmsmx() )
I compared the return value of
//---------------------------------------------------------------
long kPaCalc(float ResistanceInput, float FTemperatureInput){
// Convert from Resistance to SWP kPa measurement
// From SMX.pdf datasheet, page 7
// 550 Ohms = 0 SWP kPa
// 6000 Ohms = 35 SWP kPa
// 28075 Ohms =200 SWP kPa
// using lookup table held in the array SWPkPAarray
// table valid for temperature of 75F, 24C
// for increase of 1°F increase resistance by 1%.
// ** this function accepts temperature in Fahrenheit units **
Serial.print(F("DEBUG: ResistanceInput: ")); Serial.println(ResistanceInput);
float newVal;
// Adjust compensate resistance for temperature.
// per page 8 of SMX.pdf
float ResistanceCompensated = ResistanceInput *(1 + 0.001*(FTemperatureInput-75));;
Serial.print(F("DEBUG: ResistanceCompensated: ")); Serial.println(ResistanceInput);
if (ResistanceCompensated <= SWPkPAarray[0]) { // Minimum value
newVal = SWPkPAarray[0+1];
}
if (ResistanceCompensated >= SWPkPAarray[74]) { // Maximum value
newVal = SWPkPAarray[16+1];
}
//for (int i=0; i<SWPkPAarray.length-2; i=i+2) {
for (int i=0; i<16; i=i+2) {
if ((ResistanceCompensated >= SWPkPAarray[i]) && (ResistanceCompensated <= SWPkPAarray[i+2])) {
newVal = SWPkPAarray[i+1] - ((SWPkPAarray[i+1]-SWPkPAarray[i+3]) * ((ResistanceInput-SWPkPAarray[i]) / (SWPkPAarray[i+2]-SWPkPAarray[i])));
break;
}
}
return newVal;
}
with my function I did not trust
void get_wmsmx(int powerPin, int pinRead, unsigned long timeout, int16_t &val)
{
/*
* Second soluion more precise
*/
int highInput, lowInput; // Store high and low time of wave in microseconds
float totalInput; // Temp store of total time of duration for one cycle of high and low pulse
float frequency; // calculated freqency 1/total time of one cycle.
float swp;
int wrm;
//float Tsoil=24; //temp
highInput = pulseIn(pinRead,HIGH);
lowInput = pulseIn(pinRead,LOW);
totalInput = highInput + lowInput;
frequency = 1000000 / totalInput;
percent = map(frequency,48,13233,0,100);
if (highInput >0 && lowInput>0)
{
Si.sprint(F("Frequency2 at "),2); Si.sprint(pinRead,2); Si.sprint(F(": "),2); Si.sprint(frequency,2); Si.sprint(F("Hz "),2);
Si.sprint(F("("),2); Si.sprint(percent,2); Si.sprintln(F("%)"),2);
}
else
{
Si.sprint(F("frequency: "),2);
Si.sprintln(F("Error"),2);
}
delay(500);
sw.digitalWrite(powerPin, LOW);
/*
* Calculate SWP (kPa)
*/
uint8_t Tsoil = mesMesures[c_temperature_soil][capteur_temperature_soil_id].valeur;
wrm = map(frequency,48,13233,27950,550);
Si.sprint(F("WRM: "),2); Si.sprint(wrm,2); Si.sprintln(F(" Ohm"),2);
Si.sprintln(F("Calculate SWP"),2);
//kPa = (3.213 * kohms + 4.093) / (1 - 0.009733 * kohms - 0.01205 * Celsius)
swp = (3.213 * (wrm/1000) + 4.093) / (1 - 0.009733 * (wrm/1000) - 0.01205 * Tsoil);
Si.sprint(F("SWP: "),2); Si.sprint(swp,2); Si.sprint(F("kPa"),2);
Si.sprint(F(" for a soil temp of "),2); Si.sprintln(Tsoil,2);
val = (int16_t)percent;
}
the return value with mine function
SWP: 202.77kPa for a soil temp of 24C
It's very close to yours
I also was very interrested about the return value of yours second function:
long kPaCalc2(float ResistanceInput, float CTemperatureInput){
// Second Method of conversion
// Convert from Resistance to SWP kPa measurement
// From SMX.pdf datasheet, page 9
// kPa = (3.213 * kohms + 4.093) / {1 - 0.009733 * kohms - 0.01205 * Celsius)
// ** this function accepts temperature in Celsius units **
ResistanceInput = ResistanceInput/1000; // ohms to Kohms
float newVal = (3.213 * ResistanceInput + 4.093) / (1 - 0.009733 * ResistanceInput - 0.01205 * CTemperatureInput);
return newVal;
}
because it displays -332.00kpa, and this was the result I always got before adding
wrm = map(frequency,48,13233,27950,550);
in my fonction wmsmx();
I always thout that -332 was a error as I was convinced that it could not exceed -200 and SWP is always negatif from 0 to -200.
I am still wondering why we got a value of -332 instead of -200 (or around -200)
So what is more relevent between kPaCalc and kPaCalc2?
This study also use the same formula as you, but they spoke about 0 -239kPa
According to the manufacturer’s sensor specifications, the rated range of measurement of the Watermark 200SS sensors is from 0 to −239 kPa, although the normal usable range is from 0 to −200 kPa, where a reading around 0 kPa would indicate that the soil is at or near saturation and a reading at or near −200 would indicate a very dry soil with little or no plant available water. There are several types of commercial loggers that can automatically read the Watermark 200SS sensors at specified time intervals and store the collected data, and a device to manually read these sensors is also available (Figure 1(b)).
Do you think they provide the formula but they do not say all about how the get -239? (otherwise they will have -324Kpa (or somethink about this...)
I conclude, the best way is to use your proposition kPaCalc() because you consider the manufacturer TABLE1 value (page6) but your value is positif.
Do you have idea about positif vs negatif kPa value (200 or -200)?
I also conclude that my result was not sur wrong, while I expected it as obsolete :).
What do you tink about how I calculate kPa in my function wmsmx(), as I am using the map function to get the Rwm (watermark sensor)
Should I better follow your example as your "hard coded" the table value?
long RESISTORarray[76]
long SWPkPAarray[18]
long resistanceCalc(float frequencyInput)
Now my main worries is about negatif SWP value vs positif SWP value.
Many thank!!!!
Cheers
@hard-shovel
It's a huge, great what you wrote!!!
I will test it tomorrow!!! and compare the two different to calculate kpa ( kPaCalc2() and kPaCalc() )
@hard-shovel
Ouha, your are a genius!!
I am going to look at this deeply. I keep you up to date!
Thaaank!!!!!!!
@hard-shovel said in How to read frequency output from watermark sensor:
That does not seem to make sense to me, as when i chart the numbers, it seems to me the most useful range according to the KPa numbers will not be very sensitive with your figures ranging from an intger of 9 down to 0.
I am sorry but I was busy with another problem that now I fixed.
First of all. The Analog (A1) has a pull-up resistance.
Secondely, you asked me why I do not use the kPa unit instead of percent.
The reason is I do not know how. In fact I know but I can not get a correct value. I followed your recommandation and I use pulseIN HIGH and LOW
HighInput = pulseIn(input_pin,HIGH);
LowInput = pulseIn(input_pin,LOW);
I tested it while the sensor is in dry, dry soil and it return me 48Hz. I have not add water into the soil, as I need to keep it dry for now. But I believe my code work fine to get Hz
/*
* Second soluion more precise
*/
int highInput, lowInput; // Store high and low time of wave in microseconds
float totalInput; // Temp store of total time of duration for one cycle of high and low pulse
float frequency; // calculated freqency 1/total time of one cycle.
float swp, wrm;
float Tsoil=24; //temp
highInput = pulseIn(pinRead,HIGH);
lowInput = pulseIn(pinRead,LOW);
totalInput = highInput + lowInput;
frequency = 1000000 / totalInput;
percent = map(frequency,48,13233,0,100);
if (highInput >0 && lowInput>0)
{
Si.sprint(F("Frequency2 at "),2); Si.sprint(pinRead,2); Si.sprint(F(": "),2); Si.sprint(frequency,2); Si.sprint(F("Hz "),2);
Si.sprint(F("("),2); Si.sprint(percent,2); Si.sprintln(F("%)"),2);
}
else
{
Si.sprint(F("frequency: "),2);
Si.sprintln(F("Error"),2);
}
delay(500);
Great, thank a lot!!!!!!!!!!
But I would like to get the value in kPa and when micro-controller is not connected to WM, my formul return me -332.58kPa while it should be -199kpa for fully dried and 0kpa for fully wet.I got the same result when I connect my micro-controller to my watermark sensor in a realy realy dry soil. (I have a large box with crop soil that I leave it drying)
The doc says:
The resistance ranges from 550 ohms in saturated soil, 0.0 kPa, to
27950 ohms in bone dry soil, 199 kPa
I wonder if I calculate correctly. The doc give a forumle to get the swp in kpa
kPa = (3.213 * kohms + 4.093) / {1 - 0.009733 * kohms - 0.01205 * Celsius)
and I need to know the value of 'kohms' which is the resistance of my watermark sensor when dry or wet.
I guess my mistake is here because, I actually a Watermark resistance of 10000000 ohm.
If you know the watermark sensor and still has the patience to help, I would like to understand the difference between the Table 1 and table 2 on page 6 and 7
As I wrote, I have box where I add crop soil and leave it dry until is really really dry. I measure the soil moisture with a watermark, and it return me 48Hz, which sound good as the soil is really really dry. Then the watermark resistance should be 10000000 accoring to table1, but I am confused because on page 9
The resistance ranges from 550 ohms in saturated soil, 0.0 kPa, to
27950 ohms in bone dry soil, 199 kPa. That is at 75 degrees Fahrenheit, 24 degrees Celsius
Then how can I get the right watermark resistance value from frequency and then use it with the following formul to get from 0 to -199kpa?
swp = (3.213 * (wrm/1000) + 4.093) / (1 - 0.009733 * (wrm/1000) - 0.01205 * Tsoil);
this return me -332.58kPa
Then How can I calculate wrm (Resistance of watermark)?
Thank a lot
Dear Hard-shovel.
Realy a great thank for your reply.It's too late now to answer of all of your obersvation (it's 1.30 am at my place), but I will take care of this tomrrow.
Just to answer for this
What is the purpose of the J6 connector, as i should think that connecting any cable or meter will effect the capacitance and change the output frequency.
I build the circuit myself and I was not sure about the Film capacitor C15_1. I juts add J6 in case I make a mistake about C15_1. In that case, I can add a different capacitor on J6. But it should remind open and remove it later unless C15_1 (SMD) does not match. I have a doubt about C15_1, but not about the no-SMD capacitor that I can place on J6 holes.
About Q3, yes of course
About Q2. Yes I thought to connect to PA15 instead of 3.3V. I though there is no impact if I keep RESET permanentely to 3.3, but I can have it to PA15, when the DIO of my processor is HIGH to power the SMX circuit.
About Q1: I didnot foresee a pull up resistor on A1 and Ido not know if my microcontroller has one (Adafruit Feather MO adalogger), but I will check it tomorrow.
I will better read your additonnal helpfully next comments
Great, thank a lot for your suggestion and comments
Cheers
Thank
Dear Hard-shovel
Thank a lot for your explication. That help!
I use freqency measures because the voltage output need to have an input pf 4.5V. My circuit worj with 3.3V even ifI believe it would work.
I created that schema
.
Watermark is connected to W15_2 and _1
On PA15, I power the watermark with DIO pin of my microcontroller, and then I take the frequency measure on A5 (work as digitalRead). In that way, I controll the power and power the watermark only when I need.
I have 3 time that circuit as I have 3 watermarks to measure at 3 different level.
I use that code to get the frequeny
/*
* GET Watermarksvalue
*/
unsigned long measureSMX(int powerPin, int pinRead, unsigned long timeout){
#ifdef ST2
unsigned long duration;
float percent=0.0;
sw.digitalWrite(powerPin, HIGH); // (sw = Seesaw board from Adafruit)
delay(1000);
//duration = pulseIn(pinRead, HIGH, timeout);
/*
while(1)
{
//Serial.println( digitalRead(pinRead));
//delay(1);
}
*/
duration = pulseIn(pinRead, HIGH);
sw.digitalWrite(powerPin, LOW);
//percent= map(duration,50,10000,0,100);
percent = duration*100/11000;
#ifdef DEBUG
Si.sprint(F("Frequency at "),2); Si.sprint(pinRead,2); Si.sprint(F(": "),2); Si.sprint(duration,2); Si.sprint(F("Hz "),2);
Si.sprint(F("("),2); Si.sprint(percent,2); Si.sprintln(F("%)"),2);
#endif
delay(2000);
return (int)percent;
#endif
}
and the measures look good. But my code is very simple in comparaison of your and I would happy to imporve it (and correct/remove error)
Your exemple look very interrestin but why do your need to mesure once with LOW and once with HIGH
HighInput = pulseIn(input_pin,HIGH);
LowInput = pulseIn(input_pin,LOW);
I suppose I should do as you demonstrated.
You also mentionned that the microcontroller should be 16Mhz. I supposed it's the minimum requiered?
My microcontroller is a 48Mhz. The micro-controller spped has an important on frequency result/calculation?
Thank for helping!