Продолжение
статьи В процессе эксплуатации обнаружены ошибки и проведены некоторые доработки. Данные передаются в реальном времени и отображаются на экране компьютера, а также сохраняются в таблице. Недоработок и пожеланий еще полно, надо сделать панорамирование графика мышью, автоподстройку данных -перерисовку при превышении параметров, изменение интервала опроса и т.д., но сейчас все проекты заморожены по причине переезда.
Коротко о результатах - датчик из предыдущих постов провел в земле больше чем полгода, проект пришлось свернуть. Выглядит он нормально, дефекты есть, но вполне рабочий. Позже на месяц воткнул в землю штырь от палатки, он похоже хромированный, на нем образовалась коррозия.
Росла у меня малина и листья у нее с коричневой бахромой, возможно что то с почвой(но она у меня однородная, но в разных мешках, где что то могло попасть), хотя китайский PHметр показывает норму. Правда он всегда показывает одно и тоже, больше нечего было проверить, кроме воды.
Фотки пока разместить не могу.
Код Arduino
#include "Timer.h"
#include
#include
#include
#include
#define AM2315_I2C_ADDRESS 0x69
#define NUM_READS 2 // Number of sensor reads for filtering
DS3231 clock;
RTCDateTime dt;
Adafruit_AM2315 am2315;
LiquidCrystal_I2C lcd(0x27,20,4); //
long buffer[NUM_READS];
long sensor1;
int ind;
int inByte = 0; // incoming serial byte
typedef struct { // Structure to be used in percentage and resistance values matrix to be filtered (have to be in pairs)
int moisture;
long resistance;
} values;
const long knownResistor = 1500; // Constant value of known resistor in Ohms
int supplyVoltage; // Measured supply voltage
int sensorVoltage; // Measured sensor voltage
values valueOf[NUM_READS]; // Calculated moisture percentages and resistances to be sorted and filtered
int i; // Simple index variable
unsigned long previousMillis = 0; /
const long interval = 100;
Timer t;
void setup()
{
Serial.begin(9600);
lcd.init();
lcd.backlight();
clock.begin();
int tickEvent = t.every(30000, graf); // период опроса датчиков - 30 сек
int tickInd = t.every(1000, Ind); // период опроса датчика AM2315 - 1 сек, иначе ошибка
// Pin 6,7 is for sensor 1
pinMode(6, OUTPUT);
pinMode(7, OUTPUT);
establishContact(); // send a byte to establish contact until receiver responds
}
void loop()
{
t.update();
};
void Ind()
{
dt = clock.getDateTime();
lcd.setCursor(0, 0); //
lcd.print(dt.month); lcd.print("/");
lcd.print(dt.day); lcd.print(" ");
lcd.print(dt.hour); lcd.print(":");
lcd.print(dt.minute); lcd.print(":");
lcd.print(dt.second);lcd.print(" T:"); lcd.print(clock.readTemperature());
lcd.setCursor(0, 3); // 1 строка
lcd.print("Hum: "); lcd.print(am2315.readHumidity());
lcd.print(" T: "); lcd.print(am2315.readTemperature());
};
void graf()
{
measure(1,6,7,1);
long read1 = average();
measure(1,7,6,0);
long read2= average();
sensor1 = (read2 + read1)/2;
lcd.setCursor(0,1);
lcd.print ("R1=" ); lcd.print (read1); lcd.print ("R2=" );lcd.print (read2);
lcd.setCursor(0,2);
lcd.print ("sensor = ");lcd.print (sensor1);
float Hum = (am2315.readHumidity());
float Tem =(am2315.readTemperature());
if (Serial.available() > 0) {
writeInt(576);//sensor1
writeFloat (Tem);
writeFloat(Hum);
}
}
void measure (int sensor, int phase_b, int phase_a, int analog_input)
{
for (i=0; i // Read 1 pair of voltage values
digitalWrite(phase_a, HIGH); // set the voltage supply on
delayMicroseconds(25);
supplyVoltage = analogRead(analog_input); // read the supply voltage
delayMicroseconds(25);
digitalWrite(phase_a, LOW); // set the voltage supply off
delay(1);
digitalWrite(phase_b, HIGH); // set the voltage supply on
delayMicroseconds(25);
sensorVoltage = analogRead(analog_input); // read the sensor voltage
delayMicroseconds(25);
digitalWrite(phase_b, LOW); // set the voltage supply off
// Calculate resistance
// the 0.5 add-term is used to round to the nearest integer
// Tip: no need to transform 0-1023 voltage value to 0-5 range, due to following fraction
long resistance = (knownResistor * (supplyVoltage - sensorVoltage ) / sensorVoltage) ;
delay(1);
addReading(resistance);
}
}
// Averaging algorithm
void addReading(long resistance){
buffer[ind] = resistance;
ind++;
if (ind >= NUM_READS) ind = 0;
}
long average(){
long sum = 0;
for (int i = 0; i < NUM_READS; i++){
sum += buffer[i];
}
return (long)(sum / NUM_READS);
}
void establishContact() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
Serial.print('A'); // символ начала передачи данных
}
}
void writeInt(int reg) //преобразование int to byte
{
byte ch=byte(reg>>8);
byte cl=byte(reg & 0xFF);
Serial.write(cl);
Serial.write(ch);
}
void writeFloat (float val) //преобразование float to byte
{
union u_tag {
byte x[4];
float fval;
} u;
byte *x = (byte *)&val;
for (int i=0; i<4; i++) {
Serial.write(x[i]);
}
}
Программа Processing
import processing.serial.*;
import grafica.*;
import java.util.Date;
Serial myPort; //
int[] serialInArray = new int[10]; // байт приема
int serialCount = 0;
boolean firstContact = false;
int l, li =0;
int min, max,min1, max1, min2, max2;
float minH, maxH,minT, maxT;
int MinY, MaxY;
GPlot plot, plot1, plot2 , plot_Right;
String received; // данные, получаемые с последовательного порта
int points = 2900; // число точек в графике
int totalPoints = 3000; // число точек в графике
// параметры фильтра Калмана
float P = 1.0; //gladkost 0.2
float varP = pow(0.1, 1);
float varM = pow(0.5, 1);
float K = 1.0;
float Kalman = 20.0;
float KalmanPlot=0.0;
float Hum, Tem, Sval, Humut, Temper ;
int val;
Table table;
int readingCounter = 0;
String file, filename ;
void setup() {
frameRate(2);
size (1200,900);
MinY=400;
MaxY=900;
println(Serial.list());
String portName = "COM10";
//Serial.list()[2];
myPort = new Serial(this, portName, 9600);
GPointsArray pTem = new GPointsArray(points);
GPointsArray pVlag = new GPointsArray(points);
GPointsArray pR = new GPointsArray(points);
plot = new GPlot(this);
plot.setPos(25, 25); // set the position of to left corner of plot
plot.setDim(1000, 700); // set plot size
plot.setXLim(0, totalPoints); // set x limits
plot.setYLim(MinY, MaxY); // set y limits
plot.setPointColor(color(0, 0, 255));
plot.setTitleText("Датчик влажности почвы");
plot.getXAxis().setAxisLabelText("время");
plot.getYAxis().setAxisLabelText("влажность");
plot.getXAxis().setNTicks(15);
plot.setPoints(pTem);
plot.setPointSize(4.0);
plot.addLayer("Kalman", pTem);
plot1 = new GPlot(this);
plot1.setPos(plot.getPos());
plot1.setDim(plot.getDim());
plot1.setXLim(0, totalPoints); // set x limits
plot1.setYLim(MinY, MaxY); // set y limits
plot1.setPointColor(color(255, 0, 0));
plot1.setPoints(pVlag);
plot1.setPointSize(2.0);
plot2 = new GPlot(this);
plot2.setPos(plot.getPos());
plot2.setMar(plot.getMar());
plot2.setDim(plot.getDim());
plot2.setXLim(0, totalPoints); // set x limits
plot2.setYLim(MinY, MaxY); // set y limits
plot2.setPointColor(color(0 , 255, 0));
plot2.setPoints(pR);
plot2.setPointSize(4.0);
plot_Right = new GPlot(this);
plot_Right.setPos(plot.getPos());
plot_Right.setMar(plot.getMar());
plot_Right.setDim(plot.getDim());
plot_Right.setAxesOffset(4);
plot_Right.getYAxis().setNTicks(10);
plot_Right.getRightAxis().setAxisLabelText("Температура");
plot_Right.getRightAxis().setDrawTickLabels(true);
//plot.activatePanning();
int s = second();
int m = minute();
int h = hour();
int d = day();
int mo = month();
int y = year();
String filename = str(d)+ "_" + str(mo) + "_" + str(y) + ("_") + str(h) + ("_") + str(m);
table = new Table();
table.addColumn("Date");
table.addColumn("R");// SENSOR
table.addColumn("T1");// TEMPER AC
table.addColumn("V1");// VLAG AC
file = ("data/" +filename + ".csv"); //имя таблицы
}
void draw() {
background(255);
if (li==1) {noLoop(); } //запрет обновления
if (li==0) {redraw(); // очередное обновление
//распаковка данных
val = serialInArray[1]*256 + serialInArray[0];
int asInt = (serialInArray[2] & 0xFF)
| ((serialInArray[3] & 0xFF) << 8)
| ((serialInArray[4] & 0xFF) << 16)
| ((serialInArray[5] & 0xFF) << 24);
Tem = Float.intBitsToFloat(asInt);
asInt = (serialInArray[6] & 0xFF)
| ((serialInArray[7] & 0xFF) << 8)
| ((serialInArray[8] & 0xFF) << 16)
| ((serialInArray[9] & 0xFF) << 24);
Hum = Float.intBitsToFloat(asInt);
//локальные /максимумы, минимумы
if (val>max) max=val;
if (l == 3) { min=max; }
if (valif (Hum>maxH) maxH=Hum;
if (l == 2) minH=maxH;
if (Hum
P = P + varP; //сглаживание
K = P / (P + varM);
Kalman = K * val + (1 - K) * Kalman;
P = (1 - K) * P;
KalmanPlot = map(Kalman, 18, 30, 0, height); //масштабирование графика - пока руками
float MinYF = MinY;
float MaxYF = MaxY;
Temper= map (Tem, 0, 40, MinYF, MaxYF);
Humut= map (Hum, 0, 80, MinYF, MaxYF);
plot.beginDraw();
plot.drawBackground();
plot.drawBox();
plot.drawXAxis();
plot.drawYAxis();
plot.drawTopAxis();
plot.drawRightAxis();
plot.drawTitle();
//график левая ось
plot.drawPoints();
plot.getLayer("Kalman").drawPoints();
plot.drawLegend(new String[] {("Температура ="+ Tem), ("Влажность = "+ Hum)}, new float[] {0.12, 0.4}, new float[] {0.92, 0.92});
plot.drawLegend(new String[] {("Max ="+ max), ("Min = "+ min)}, new float[] {0.12, 0.4}, new float[] {0.87, 0.87});
plot.drawGridLines(GPlot.BOTH);//линии клетки
//plot.activatePanning();
//plot.activateZooming(1.1, CENTER, CENTER);// центрирование данных
plot.endDraw();
plot1.beginDraw();
plot1.drawPoints();
plot1.endDraw();
//правая ось
plot2.beginDraw();
plot2.drawPoints();
plot2.endDraw();
//plot_Right.setYLim(calc(plot.getYLim()));
plot_Right.setYLim(3.0,40.0);
plot_Right.beginDraw();
plot_Right.drawRightAxis();
plot_Right.endDraw();
l++;
plot.addPoint(l,Temper);
plot1.addPoint(l, val);
plot.addPoint(l, Kalman,"Kalman");
plot2.addPoint(l, Humut);
int s = second();
int m = minute();
int h = hour();
int d = day();
int mo = month();
int y = year();
//запись в таблицу
TableRow newRow = table.addRow();
newRow.setInt("R",val);
String DateTab = str(d)+ "." + str(mo) + "." + str(y) + (" ") + str(h) + (":") + str(m) + (":") + str(s);
newRow.setString("Date",DateTab);
newRow.setFloat ("T1", Tem);
newRow.setFloat ("V1", Hum);
readingCounter++;
saveTable(table, file );
noLoop();
}
}
//взаимодействие с COM портом
void serialEvent(Serial myPort) {
int inByte = myPort.read();
if (firstContact == false) {
if (inByte == 'A') {
myPort.clear(); // clear the serial port buffer
firstContact = true; // you've had first contact from the microcontroller
myPort.write('A'); // ask for more
}
myPort.clear(); // clear the serial port buffer
myPort.write('B');
myPort.write("600");// изменить
}
else {
serialInArray[serialCount] = inByte;
//println(serialInArray[serialCount]+ " " + serialCount);
serialCount++;
if (serialCount > 9 ) {
li=0;
loop();
myPort.write('A');
serialCount = 0;
}
}
}