myPort.readString() читает не все.
- Войдите на сайт для отправки комментариев
Здравствуйте!
только начинаю разбираться в arduino и в processing
попробовал прочитать многострадальный dht11 и по показаниям построить гарфик. Наловил всяких странных косяков:
1) процессинг довольно часто счтывает строку не польностью, из случайного места - т.е. не только начало, а может любой фрагмент
2)какието непонятки с прямоугольником, которым я стираю старую линию графика - он становится шире к ближе к концу.
3)иногда вылетает в месте, которое по идее должно разбирать строку на куски и выделить оттуда значение влажности, говорит короткаястрока хотя я граблями подпер - если строка короче ожидаемой то просто проскакивать по идее должно.
Где я накосячил?
Привожу весь код целиком - его не много, а вдруг я чего не так объявил
1) ардуина
#include "DHT.h"
#define DHTPIN 2 // what pin we're connected to
// Uncomment whatever type you're using!
#define DHTTYPE DHT11 // DHT 11
//#define DHTTYPE DHT22 // DHT 22 (AM2302)
//#define DHTTYPE DHT21 // DHT 21 (AM2301)
// Connect pin 1 (on the left) of the sensor to +5V
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor
DHT dht(DHTPIN, DHTTYPE);
int led = 13;
void setup() {
Serial.begin(38400);
//Serial.println("DHTxx test!");
pinMode(led, OUTPUT);
dht.begin();
}
void loop() {
// Reading temperature or humidity takes about 250 milliseconds!
// Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
float h = dht.readHumidity();
float t = dht.readTemperature();
// check if returns are valid, if they are NaN (not a number) then something went wrong!
digitalWrite(led,HIGH);
if (isnan(t) || isnan(h)) {
Serial.println("Failed to read from DHT");
}
else {
Serial.print("Humidity: ");
Serial.print(h);
Serial.print("% Temperature: ");
Serial.print(t);
Serial.println("*C ");
digitalWrite(led,HIGH);
delay(20);
digitalWrite(led,LOW);
}
digitalWrite(led,LOW);
delay(480);
digitalWrite(led,HIGH);
delay(40);
digitalWrite(led,LOW);
delay(480);
}
2)Процесссинг
import processing.serial.*;
Serial myPort; // Create object from Serial class
int xn=0, yn=0, xk=0, yk=0, yz=0, yt=0;
float val, val1;
String portName, myString;
void setup()
{
size(640, 360);
textFont(createFont("Arial-BoldMT", 36));
background(0);
portName = Serial.list()[0];
println("Now slave device present on "+portName+" port");
myPort = new Serial(this, portName, 38400);
}
void draw()
{
textSize(14);
while (myPort.available () > 0)
{
myString = myPort.readString();
//print(myString);//test line show myString content
int LTest = myString.length();
if (LTest < 37)
{
//это если мы всякую фигню прочли то ее только показать - при неправильном преобразовании вылетает.
}
else
{
int SerchVal = myString.indexOf("Humidity:");
if (myString.indexOf("Humidity:")>=0) {
val = parseFloat(myString.substring(myString.indexOf("Humidity:")+10, myString.indexOf("% ")));// откуда ошибка StringIndexOutOfBoundsExeption:string index out of range:-36
}
if (myString.indexOf("Temperature:")>=0) {
val1 = parseFloat(myString.substring(myString.indexOf("Temperature:")+13, myString.indexOf("*C")));
println((val)+" hum");
println((val1)+" temp");
}
}
fill(0);
noStroke();
rect(0, 0, 640, 50);//прямоугольник
fill(255);
text("myString is: " + myString, 5, 20);
stroke(50);
line (0, 300, 640, 300);//опорная линия temp
line (0, 200, 640, 200);//опорная линия hud
yk=(int)val;//temp
fill(0);
noStroke();
rect (xn+3,50,xn+6,298);//почему становится шире?
stroke(190);
line (xn, 300-yn, xk, 300-yk);
yn=yk;
yz=(int)val1;//hud
stroke(220);
line (xn, 200-yt, xk, 200-yz);
xn=xk;
yt=yz;
xk++;
if (xk > 635) {xn=0;xk = 1;}
}
}
Версия processing 2.0.1 Mac
Версия Arduino IDE 1.0.5 Mac
arduino nano v3 китайская на 328 меге, кормится от USB
Заранее спасибо.
Зачем в строке передавать имена ваших переменных ? Исключить за ненадобностью !)
Вот мой код процессинга:
import processing.serial.*; float H ; float T ; int lf = 10; Serial myPort; void setup() { size(640, 480); textSize(24); myPort = new Serial(this, "COM11", 9600); myPort.bufferUntil(lf); } void draw() { smooth(); background(20); textSize(24); fill(250); text("Влажность " + H + " %", 2, 50); text("Температура " + T + " °С", 2, 80); } void serialEvent(Serial myPort) { String myString = myPort.readStringUntil('\n'); if (myString != null) { myString = trim(myString); float sensors[] = float(split(myString, ',')); H = sensors[0]; T = sensors[1]; // далее по мере добавления переменных в передаваемой стороке добавляем аналогично ,т.е. например // следующая переменная будет X= sensors[2]; ( где sensors[2] приходящая третья переменная в строке) } }А это с ардуины:
#include <DHT.h> DHT dht(5, DHT21); void setup(void) { Serial.begin(9600); dht.begin(); } void loop(void) { float h = dht.readHumidity(); float t = dht.readTemperature(); Serial.print(h); Serial.print(","); Serial.println(t); }По моей идее должно быть можно обычным терминалом посмотреть в понятнлм человеку виде... Опять же данных может быть существенно больше и не только однотипно понятных - например передать на комп смску считанную с gsm-модуля Завтра буду внимательно с компа смотреть Ваши примеры. То что у меня код индийский я знаю-не программист я совсем.
Передавать имеет смысл толко данные, разделенные условным знаком.
например в таком виде
Serial.println (";"+H+";"+T);А принимать в таком
Поясню. Ардуино передает показания, которые начинаются с ";".
Процессинг ловит их и записывает в переменную типа String str_data[]
Ну а далее переводишь из String в float и строишь график.
мне хочется чтобы человеку тоже понятно было, да и тут в основном задача не темпиратуру-влажность прочитать, а понять как взаимодействовать.
Сейчас попробую перепилить пачку print`ов в 1 строчку - по идее должно стать лучше.
Заменил в ардуине
Serial.print("Humidity: "); Serial.print(h); digitalWrite(led,HIGH); delay(1); digitalWrite(led,LOW); //Serial.print("/n"); Serial.print("% Temperature: "); Serial.print(t); Serial.println("*C ");на
String hi=String(int (h)); String ti=String(int (t)); String outpotline = "Humidity: "+hi+".00% Temperature: "+ti+".00*C "; Serial.println(outpotline);стало намного лучше, но все равно не редко строку не целиком считывает... думаю дальше
Заменил в ардуине
Serial.print("Humidity: "); Serial.print(h); digitalWrite(led,HIGH); delay(1); digitalWrite(led,LOW); //Serial.print("/n"); Serial.print("% Temperature: "); Serial.print(t); Serial.println("*C ");на
String hi=String(int (h)); String ti=String(int (t)); String outpotline = "Humidity: "+hi+".00% Temperature: "+ti+".00*C "; Serial.println(outpotline);стало намного лучше, но все равно не редко строку не целиком считывает... думаю дальше
убери из кавычек слова, остаавь одинаковый условный символ , например ; и работай с ним. Смотри пост выше.
а длинное текстовое сообщение как передавать тогда? про то что чем короче сторока тем реже она приходит не полностью то понятно. не понятно почему длинная не читается.
убери из кавычек слова, остаавь одинаковый условный символ , например ; и работай с ним. Смотри пост выше.
а длинное текстовое сообщение как передавать тогда? про то что чем короче сторока тем реже она приходит не полностью то понятно. не понятно почему длинная не читается.
У компа буду пример постараюсь развернутей написать. Сам недавно все это проходил. Спасибо форуму, дали направление.
а текст передавать на случай если у нас того что на процессинге наваяли нет можно было без плясок понять что у нас там твориться или воткнуть во что-нибулдь типа консольного порта циски и посмотреть потом издалека...
ну или же у нам к ардуине gsm-шилд прикручен и там СМС-ка, которую парсить вообще не надо а просто передать на комп и показать...
в переспективе будет недологер 4-шт температуры-влажности-состояния 4-х концевиков который будет жаловаться\сбрасываться по смс и на комп показывать график влажность-темпиратуры и под этим всем последняя пришедшая смс-ка. Причем графики вторичны.
А что за текст ты собрался передавать в смс?
1) запрос на состояние датчиков
2)сброс тревог + кто сбросил соответственно.
3)сообщение для того кто первый прдет проверять все и посмотрит на консоль типа "сделай некое действие"
Если вопрос еще актуален могу скинуть реализацию протокола для ардуины и процессина для кидания между ними любого текста.
Актуален с аккадимической точки зрения. Пока я проблему решли тем что строю график в консоли псевдографикой на cgi.
Ардуинка
boolean sp_packetAvailable; // Флаг завершения приема пакета String sp_startMarker; // Переменная, содержащая маркер начала пакета String sp_stopMarker; // Переменная, содержащая маркер конца пакета String sp_dataString; // Здесь будут храниться принимаемые данные int sp_startMarkerStatus; // Флаг состояния маркера начала пакета int sp_stopMarkerStatus; // Флаг состояния маркера конца пакета int sp_dataLength; // Флаг состояния принимаемых данных // Процедура инициализация протокола sp_SetUP задает маркеры начала и конца пакета и обнуляет протокол void sp_SetUp() { sp_startMarker = "<bspm>"; // Так будет выглядеть маркер начала пакета sp_stopMarker = "<espm>"; // Так будет выглядеть маркер конца пакета sp_ResetAll(); // Полный сброс протокола } //Процедура полного сброса протокола void sp_ResetAll() { sp_dataString = ""; // Обнуляем буфер приема данных sp_Reset(); // Частичный сброс протокола } //процедура частичного сброса протокола void sp_Reset() { sp_startMarkerStatus = 0; // Сброс флага маркера начала пакета sp_stopMarkerStatus = 0; // Сброс флага маркера конца пакета sp_dataLength = 0; // Сброс флага принимаемых данных sp_packetAvailable = false; // Сброс флага завершения приема пакета } void sp_Send(String data) //отправка данных на ПК { delay(10); Serial.write("<bspm>"); // Отправляем маркер начала пакета Serial.write(data.length()); // Отправляем длину передаваемых данных for (int i=0; i < data.length(); i++){ Serial.write(byte(data.charAt(i))); } Serial.write("<espm>"); } void sp_Read() { while(Serial.available() > 0 && sp_packetAvailable==false) // Пока в буфере есть что читать и пакет не является принятым { int bufferChar = Serial.read(); // Читаем очередной байт из буфера if(sp_startMarkerStatus < sp_startMarker.length()) // Если стартовый маркер не сформирован (его длинна меньше той, которая должна быть) { if(sp_startMarker[sp_startMarkerStatus] == bufferChar) // Если очередной байт из буфера совпадает с очередным байтом в маркере { sp_startMarkerStatus++; // Увеличиваем счетчик совпавших байт маркера } else { sp_ResetAll(); // Если байты не совпали, то это не маркер. Нас нае****, расходимся. } } else { // Стартовый маркер прочитан полностью if(sp_dataLength <= 0) // Если длинна пакета на установлена { sp_dataLength = int (bufferChar); // Значит этот байт содержит длину пакета данных } else // Если прочитанная из буфера длинна пакета больше нуля { if(sp_dataLength > sp_dataString.length()) // Если длинна пакета данных меньше той, которая должна быть { sp_dataString =sp_dataString+ (char)bufferChar; // прибавляем полученный байт к строке пакета } else // Если с длинной пакета данных все нормально { if(sp_stopMarkerStatus < sp_stopMarker.length()) // Если принятая длинна маркера конца пакета меньше фактической { if(sp_stopMarker[sp_stopMarkerStatus] == bufferChar) // Если очередной байт из буфера совпадает с очередным байтом маркера { sp_stopMarkerStatus++; // Увеличиваем счетчик удачно найденных байт маркера if(sp_stopMarkerStatus == sp_stopMarker.length()) { // Если после прочтения очередного байта маркера, длинна маркера совпала, то сбрасываем все флаги (готовимся к приему нового пакета) sp_Reset(); sp_packetAvailable = true; // и устанавливаем флаг готовности пакета } } else { sp_ResetAll(); // Иначе это не маркер, а х.з. что. Полный ресет. } } // } } } } }sp_Read - читает возвращает значение sp_datastring
sp_Send - отправляет на комп или любое другое устройство например на ту же Ардуинку
Processing
boolean sp_packetAvailable; // Флаг завершения приема пакета String sp_startMarker; // Переменная, содержащая маркер начала пакета String sp_stopMarker; // Переменная, содержащая маркер конца пакета String sp_dataString; // Здесь будут храниться принимаемые данные int sp_startMarkerStatus; // Флаг состояния маркера начала пакета int sp_stopMarkerStatus; // Флаг состояния маркера конца пакета int sp_dataLength; // Флаг состояния принимаемых данных // Процедура инициализация протокола sp_SetUP задает маркеры начала и конца пакета и обнуляет протокол void sp_SetUp() { sp_startMarker = "<bspm>"; // Так будет выглядеть маркер начала пакета sp_stopMarker = "<espm>"; // Так будет выглядеть маркер конца пакета sp_ResetAll(); // Полный сброс протокола } // Процедура полного сброса протокола void sp_ResetAll() { sp_dataString = ""; // Обнуляем буфер приема данных sp_Reset(); // Частичный сброс протокола } //Процедура частичного сброса протокола void sp_Reset() { sp_startMarkerStatus = 0; // Сброс флага маркера начала пакета sp_stopMarkerStatus = 0; // Сброс флага маркера конца пакета sp_dataLength = 0; // Сброс флага принимаемых данных sp_packetAvailable = false; // Сброс флага завершения приема пакета } //Процедура отправки данных роботу, отправка идет по байтово связано с особенностями библиотеки void sp_Send(String data) { //отправляем маркер начала пакета по байтам for (int i=0; i < sp_startMarker.length(); i++){ server.write(byte(sp_startMarker.charAt(i))); } // Отправляем длину передаваемых данных server.write(byte(data.length())); // Отправляем сами данные for (int i=0; i < data.length(); i++){ server.write(byte(data.charAt(i))); } //отправляем маркер конца пакета for (int i=0; i < sp_stopMarker.length(); i++){ server.write(byte(sp_stopMarker.charAt(i))); } } //Процедура чтения полученных данных от робота void sp_Read() { while(sp_packetAvailable==false) // Пока пакет не является принятым { byte bufferChar = byte (server.read()); // Читаем очередной байт из буфера if(sp_startMarkerStatus < sp_startMarker.length()) // Если стартовый маркер не сформирован (его длинна меньше той, которая должна быть) { if(sp_startMarker.charAt(sp_startMarkerStatus) == char(bufferChar)) // Если очередной байт из буфера совпадает с очередным байтом в маркере { sp_startMarkerStatus++; // Увеличиваем счетчик совпавших байт маркера } else { sp_ResetAll(); // Если байты не совпали, выходим нафиг, это не маркер. Нас нае**** } } else { // Стартовый маркер прочитан полностью if(sp_dataLength <= 0) // Если длинна пакета на установлена { sp_dataLength = int (bufferChar); // Значит этот байт содержит длину пакета данных } else // Если прочитанная из буфера длинна пакета больше нуля { if(sp_dataLength > sp_dataString.length()) // Если длинна пакета данных меньше той, которая должна быть { sp_dataString = sp_dataString + char(bufferChar); // прибавляем полученный байт к строке пакета } else // Если с длинной пакета данных все нормально { if(sp_stopMarkerStatus < sp_stopMarker.length()) // Если принятая длинна маркера конца пакета меньше фактической { if(sp_stopMarker.charAt(sp_stopMarkerStatus) == char(bufferChar)) // Если очередной байт из буфера совпадает с очередным байтом маркера { sp_stopMarkerStatus++; // Увеличиваем счетчик удачно найденных байт маркера if(sp_stopMarkerStatus == sp_stopMarker.length()) { // Если после прочтения очередного байта маркера, длинна маркера совпала, то сбрасываем все флаги (готовимся к приему нового пакета) sp_Reset(); sp_packetAvailable = true; // и устанавливаем флаг готовности пакета break; } } else { sp_ResetAll(); // Иначе это не маркер, а х.з. что. Полный ресет. } } } } } } }Все то же самое ! только проверь sp_Read и sp_Send, так как я использую bluetoothDesktop поэтому без Serial
А можно для процессинга дополнить пример, как реагировать на эти данные?