Обработка, отправленная Arduino, не считывает целые массивы, если шнур не отключен и не подключен снова?
Я использую Arduino для считывания датчиков, а затем отправляю данные на последовательный порт для считывания Processing. Все работает отлично, когда я сначала загружаю код и запускаю программу Processing. Но если я останавливаю код Processing и затем снова запускаю его, то получаю ошибку ArrayIndexOutOfBounds. Я печатаю массив, который считывает Processing, и он имеет длину всего 3 индекса, хотя код Arduino должен отправлять массив длиной 7. Эта ошибка происходит, потому что я вызываю индекс, который не существует, но он должен существовать, Processing просто не получает весь массив. Если я отключу USB-кабель от Arduino и снова подключу его, эта ошибка не возникнет, и Processing получит весь массив. Я не понимаю, почему это происходит. Я пробовал использовать кнопку на Arduino, чтобы сбрасывать его каждый раз перед запуском кода Processing, но это не работает, мне на самом деле нужно отсоединить шнур и снова подключить его.
Если у вас есть какие-либо предложения, это было бы здорово! Спасибо заранее!
РЕДАКТИРОВАНИЕ: Я публикую код, потому что его запросили. В нем много ненужной информации о считывании показаний датчиков и создании графиков для Processing. Суть в том, что пользователь взаимодействует с программой Processing и нажимает кнопку, когда хочет сохранить данные, отправленные Arduino. Я говорил с кем-то о проблемах, с которыми я столкнулся, и они думают, что это может быть связано с последовательным буфером, и что мне нужно очистить его или подождать, пока он очистится. Я изучил это и не могу понять, как это сделать правильно. Я пробовал сбросить код Arduino с помощью библиотеки SoftRestart, но это не сработало.
Вот код Arduino:
//need to include these libraries to be able to read from serial and read the sensors
#include <SoftwareSerial.h>
#include <Wire.h>
#include "Adafruit_MCP9808.h"
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#include <AMS5915.h>
#include <AMS5812.h>
#include <Adafruit_ADS1015.h>
//Create sensor objects.
Adafruit_MCP9808 tempsensor18 = Adafruit_MCP9808(); //sensor with 0x18 address is Dry Bulb Temp
Adafruit_MCP9808 tempsensor19 = Adafruit_MCP9808(); //sensor with 0x19 address is Temp in chamber
Adafruit_BME280 bme; //pressure and humidity sensor
AMS5915 amsD; //sensor being used for reading differential pressure across the nozzle
AMS5812 amsS; //sensor being used to measure static pressure in the chamber
Adafruit_ADS1115 ads; //16-bit ADC sensor (actually 15-bit when used as a single-ended ADC)
//Initializing variables
float tableVals[]={0,0,0,0,0,0,0,0}; //an array that will hold sensor values. If more sensors or readings are added the size of the array needs to increase
float relHum=0;
float dryBulb=0;
float wetBulb=0;
float pressure=0;
float chamberTemp=0;
float pressureDiff;
float pressureStatic;
float rpm;
float correctedADC=0;
float correctedRPM;
float correctedADCx2=0;
float correctedRPMx2=0;
int counts=0;
const float AMS5915_0010_D_B_P_MIN = -10.0; // minimum pressure, millibar (for sensor reading differential pressure)
const float AMS5915_0010_D_B_P_MAX = 10.0; // maximum pressure, millibar (for sensor reading differential pressure)
const float AMS5812_0003_D_B_P_MIN = -0.3; // minimum pressure, PSI (for sensor reading static pressure)
const float AMS5812_0003_D_B_P_MAX = 0.3; // maximum pressure, PSI (for sensor reading static pressure)
const float AMS5812_0003_D_B_T_MIN = -25.0; // minimum temperature, C (for sensor reading static pressure)
const float AMS5812_0003_D_B_T_MAX = 85.0; // maximum temperature, C (for sensor reading static pressure)
//Setup function, will run one time. Initializes sensors
void setup() {
Serial.begin(9600); //set baud rate
amsD.getAddr_AMS5915(AMS5915_DEFAULT_ADDRESS); // 0x28
amsS.getAddr_AMS5812(AMS5812_DEFAULT_ADDRESS); // 0x78
ads.setGain(GAIN_ONE); //1x gain +/- 4.096V 1 bit = 0.125mV
ads.begin(); //starting sensors
amsD.begin();
amsD.begin();
if(!tempsensor18.begin(0x18) || !tempsensor19.begin(0x19)|| !bme.begin()) { //wait until these sensors are ready
while(1);
}
}
//loop function keeps repeating
void loop() {
if (counts >100){ //will only enter conditional if counts variable is over 100
readSensors(); //go to readSensors function below
tableVals[0]= pressure; //set pressure to the first index in array
tableVals[1]=relHum; //rel hum to the second index in array
tableVals[2]=wetBulb; //wet bulb to the third index in array
tableVals[3]=dryBulb; //dry bulb to the fourth index in array
tableVals[4]=chamberTemp; //chamber temperature to the fifth index in the array
tableVals[5]=pressureDiff; //differential pressure to the sixth index in the array
tableVals[6]=pressureStatic; //static pressure to the seventh index in the array
tableVals[7]=rpm; //RPM is the eighth index in the array
Serial.flush();
Serial.print(tableVals[0]); //sending all the values to Processing, need commas so Processing can split into different values (don't totally know why I put everything in an array first, that's just how I saw it done in an example)
Serial.print(",");
Serial.print(tableVals[1]);
Serial.print(",");
Serial.print(tableVals[2]);
Serial.print(",");
Serial.print(tableVals[3]);
Serial.print(",");
Serial.print(tableVals[4]);
Serial.print(",");
Serial.print(tableVals[5],4);
Serial.print(",");
Serial.print(tableVals[6],4);
Serial.print(",");
Serial.print(tableVals[7]);
Serial.println(","); //need this last comma for some reason or it gets messed up
counts=0; //reset counts variable to 0
}
counts++; //increment counts
}
//This function is called in the loop() function. It reads all of the sensors
void readSensors(){
dryBulb = tempsensor18.readTempC(); //read from temp sensor with 0x18 address
relHum = bme.readHumidity(); //read humidity from bme sensor
pressure = bme.readPressure()/100.0F; //read pressure, in hpa
pressure = pressure * 0.029529983071445; //convert pressure to inches of mercury
wetBulb = dryBulb*atan(0.151977*pow(relHum + 8.313659, 0.5)) + atan(dryBulb +relHum) - atan(relHum - 1.676331) + 0.00391838*pow(relHum,1.5)*atan(0.023101*relHum) - 4.686035; //equation finds approximate wet bulb temp from humidity and dry bulb temp
chamberTemp = tempsensor19.readTempC(); //read from temp sensor with 0x19 address
//this chunk of code gets the differential pressure reading and converts it to inches of water
byte errorDiff;
int8_t addressD;
addressD = amsD.ams_i2cAddress;
Wire.beginTransmission(addressD);
errorDiff = Wire.endTransmission();
if (errorDiff == 0){
amsD.Measure_PressureAndTemperature(AMS5915_0010_D_B_P_MIN, AMS5915_0010_D_B_P_MAX);
pressureDiff=amsD.getPressure();
pressureDiff = pressureDiff * 0.40146307866177;
}
//this chunk of code gets the static pressure reading and converts to inches of water
byte errorStatic;
int8_t addressS;
addressS = amsS.ams_i2cAddress;
Wire.beginTransmission(addressS);
errorStatic = Wire.endTransmission();
if(errorStatic == 0){
amsS.Measure_PressureAndTemperature(AMS5812_0003_D_B_P_MIN, AMS5812_0003_D_B_P_MAX, AMS5812_0003_D_B_T_MIN, AMS5812_0003_D_B_T_MAX);
pressureStatic = amsS.getPressure();
pressureStatic = pressureStatic*27.679904842545;
}
//the next chunk of code takes 300 readings from the ADC, averages them together. Applies two correction equations to the ADC and then converts it to the RPM that is sent to Processing
float ADCcount=0;
float ADCtotal=0;
float finalADC=0;
int16_t adc0;
while(ADCcount<100){ //taking 100 ADC readings and averaging them
adc0 = ads.readADC_SingleEnded(0);
ADCcount=ADCcount+1;
ADCtotal=ADCtotal+adc0;
}
finalADC=ADCtotal/ADCcount;
rpm = (40740.0/32767.0)*finalADC;
}
Код обработки:
//initializing variables
import processing.serial.*; //need this library to read serial data
Serial myPort;
int signal=0; //this will signal what part of the draw function to read
Table table;
int count =-1;
int lf = 10; //10 is the ASCII number that represents an enter key
String d_string;
String m_string;
String y_string;
float countVals[];
float pressureVals[];
String voltage=""; //these variables need to be blank strings since these are the variables that come from user input
String current=""; //they will be changed to floats before being saved in the table
String fileName="";
String COM ="";
float Pdiff;
float Pstatic;
//Set up
void setup(){
size(300,410); //creating the start graphics
background(255);
String s = "Click on the rectangle to start.";
textSize(20);
textAlign(CENTER);
fill(25);
text(s,10,10, 290, 150);
fill(255, 0, 0);
rectMode(CORNERS);
rect(115,85,195,160); //drawing rectangle 'button'
table = new Table(); //create new table
table.addColumn("Date"); //make a Date column
table.addColumn("Reading Number"); //make a Reading Number column
table.addColumn("Voltage V"); //Voltage column
table.addColumn("Current A"); //Current column
table.addColumn("Pressure inHg"); //Pressure column
table.addColumn("Humidity %"); //Relative Humidity column
table.addColumn("Wet Bulb Temp. *C"); //Wet Bulb Temp. column
table.addColumn("Dry Bulb Temp. *C"); //Dry Bulb temp. column
table.addColumn("Chamber Temp. *C"); //Chamber Temp column
table.addColumn("Static Pressure inH20"); //Static pressure column
table.addColumn("Differential Pressure inH2O"); //Differential Pressure column
table.addColumn("RPM"); //RPM column
int day = day(); //Find the day
int month = month(); //find the month
int year = year(); //find the year
d_string = str(day); //convert these integers to strings
m_string = str(month);
y_string = str(year);
}
//Draw function is continuously looping
void draw(){
if(signal==1){ //if signal is 1 (set in keyPressed) ask the user to enter the COM
background(255);
String f = "Enter what number in the list of COM Ports the Arduino is plugged into (This is not necessarily the COM number.) \nPress ENTER to continue.";
textAlign(CENTER); //center the text on the screen
fill(25); //setting fill color
stroke(0); //setting stroke color
textSize(14); //setting text size
text(f,10,10,290,200); //displaying the instructions in the graphics box
textSize(20); //resetting text size
text(COM,10,125,290,200); //displaying the COM the user is typing
}
else if (signal==2){ //if signal is 2 (set in keyPressed) ask the user to enter the name of the CSV file where the data will be saved
background(255);
String f = "Enter the name of the CSV file where the data will be saved. \nThis will be located in the folder called 'data' that is in the same folder as this application. \nPress ENTER to continue.";
textAlign(CENTER);
fill(25);
stroke(0);
textSize(12);
text(f,10,10,290,200); //displaying instructions to the user
textSize(20);
text(fileName,10,125,290,200); //displaying the user file name the user is typing
}
else if(signal==3){ //if signal is 3 (set in keyPressed) ask the user to input the voltage
background(255);
String f = "Enter the Voltage in Volts. Press ENTER to continue.";
textAlign(CENTER);
fill(25);
stroke(0);
textSize(20);
text(f,10,10,290,200); //displaying instructions to the user
text(voltage,10,125,290,200); //displaying the voltage the user is typing
}
else if(signal ==4){ //if signal variable is 5 (set in conditional above) ask the user to input the current
background(255);
String f = "Enter the Current in Amps. Press ENTER to continue.";
textAlign(CENTER);
fill(25);
stroke(0);
textSize(20);
text(f,10,10,290,200); //displaying instructions
text(current, 10,125,290,200); //displaying the current the user is typing
}
else if (signal ==5){ //if signal variable is 4 (set in mousePressed) then read the following chunk of code.
String val=null;
while (val==null){
val = myPort.readStringUntil('\n'); //read serial data sent by Arduino
}
val = trim(val); //trim off any white space
countVals = float(split(val, ',')); //split serial data into individual readings
delay(500);
signal =6; //set signal to 6 so next chunk of code will be read
}
else if (signal ==6){ //if signal is 6 (set in the above conditional) read the following chunk of code
TableRow newRow = table.addRow(); //add a row to the spreadsheet
newRow.setString("Date", m_string +"."+ d_string +"."+ y_string); //write data in the correct columns in the table
newRow.setInt("Reading Number", count);
newRow.setFloat("Pressure inHg", countVals[0]);
newRow.setFloat("Humidity %", countVals[1]);
newRow.setFloat("Wet Bulb Temp. *C", countVals[2]);
newRow.setFloat("Dry Bulb Temp. *C", countVals[3]);
newRow.setFloat("Chamber Temp. *C", countVals[4]);
newRow.setFloat("Differential Pressure inH2O", countVals[5]);
newRow.setFloat("Static Pressure inH20", countVals[6]);
newRow.setFloat("Voltage V", float(voltage)); //values that were strings are converted to floats
newRow.setFloat("Current A", float(current));
newRow.setFloat("RPM", round(countVals[7]));
saveTable(table, "data/"+fileName+".csv"); //saving the data in a folder called 'data' in a file with the user given name
signal = 7; //signal variable back to 7 to read the next conditional
}
if(signal ==7){ //if signal is 7 (set in conditional above or in keyPressed), read serial port data and display graphics Draw function will continue to loop through this conditional until box is clicked so pressures are always updated.
String pressures=null;
while(pressures==null){
pressures = myPort.readStringUntil('\n'); //read serial data sent by Arduino
}
pressures = trim(pressures); //trim off any white space
pressureVals = float(split(pressures, ',')); //split serial data into individual readings
println(pressureVals);
background(255); //reset graphics
String s = "Click on rectangle to take a data point. Exit out of this box when done.";
stroke(0);
textSize(15);
fill(25);
textAlign(CENTER);
text(s,10,10,290,100); //displaying instructions to user
fill(50, 255, 200);
rect(115,85,195,160);
fill(0);
textSize(12);
textAlign(LEFT); //next line will display the previous data point if it is not the first data reading (counts needs to be 1 or greater)
if (count>0) text("Previous Data Point: \n\t" +"Barometric Pressure inHg: " + str(countVals[0]) +"\n\tHumidity %: " +str(countVals[1]) + "\n\tWet Bulb Temp *C: " + str(countVals[2]) + "\n\tDry Bulb Temp *C: " +str(countVals[3]) +"\n\tChamber Temp *C: " + str(countVals[4])+"\n\tDifferential Pressure inH20: " + str(countVals[5]) +"\n\tStatic Pressure inH20: "+ str(countVals[6]) + "\n\tRevolutions Per Min: " + str(round(countVals[7])),10,190, 300,400);
textAlign(10, 400);
text("Static: " +str(pressureVals[6]) + " in.H20", 10,400); //display the static pressure on the bottom of graphics window
textAlign(150, 400);
text("Diff: "+ str(pressureVals[5]) + " in.H20", 150, 400); //display the differential pressure on the bottom of graphics window
}
}
//mousePressed function will run when mouse is clicked in box
void mousePressed(){
if(mouseX <= 195 && mouseX >= 115 && mouseY <=160 && mouseY >=85){ //if the mouse is clicked within the boundaries of the rectangle
if(count>=0){ //if counts is greater or equal to 0 (counts starts at -1, this was b/c there were some glitches with the first click being registered)
signal=5;
String d= "DATA TAKEN"; //display "DATA TAKEN" to signal that a data point was taken
textSize(15);
fill(255,0,50);
textAlign(LEFT);
text(d, 107, 180);
}
else{ //will run if counts is not greater than or equal to 0 (so this will just be on the first click before data is taken)
signal=1;
}
count++; //increment count
mousePressed = false; //set mousePressed to false to make sure this function doesn't run again.
}
}
//keyPressed will run when a key on the keyboard is pressed
void keyPressed() {
if(signal==1){ //if signal variable is 1...
if(key==BACKSPACE){ //if the key pressed is BACKSPACE
if(COM.length()>0){ //if length of what is being typed is greater than 0
COM = COM.substring(0,COM.length()-1); //then get rid of the last character
}
}
else if (textWidth(COM+key) < width && key != ENTER){ //if what is being typed is not greater than the width of the graphics window and the key pressed is not ENTER
COM = COM +key; //add the key pressed to the end of what is being typed
}
if(key ==ENTER){ //if ENTER is pressed
signal=2; //change signal variable
String portName = Serial.list()[int(COM)]; //COM is not necessarily the COM number the Arduino is plugged into. It's the number in the list of COMS that the COM is listed. I used trial and error to figure this out
myPort = new Serial(this, portName, 9600); //setting up baud rate
myPort.bufferUntil(lf); //I don't know if this is actually necessary
}
}
else if(signal==2){ //if signal variable is 2...
if(key ==BACKSPACE){ //these first two conditionals for this signal number are the same for all the signal number conditionals.
if(fileName.length()>0){
fileName = fileName.substring(0,fileName.length()-1);
}
}
else if (textWidth(fileName+key) < width && key !=ENTER) {
fileName = fileName +key;
}
if (key == ENTER) { //If key pressed is ENTER
signal=3; //change signal
}
}
else if(signal==3){ //If signal is 3...
if(key ==BACKSPACE){
if(voltage.length()>0){
voltage = voltage.substring(0,voltage.length()-1);
}
}
else if (textWidth(voltage+key) < width && key!=ENTER) {
voltage = voltage +key;
}
if (key == ENTER) {
signal=4;
}
}
else if(signal ==4){ //if signal is 4...
if(key == BACKSPACE){
if(current.length()>0){
current = current.substring(0,current.length()-1);
}
}
else if (textWidth(current+key) <width && key != ENTER) {
current = current + key;
}
if (key ==ENTER){
signal=7; //change signal to 7 and display graphics to take a data point
key = BACKSPACE;
background(255);
String s = "Click on rectangle to take a data point. Exit out of this box when done.";
stroke(0);
textSize(15);
fill(25);
text(s,10,10,290,100);
fill(50, 255, 200);
rect(115,85,195,160);
}
}
}
Извините, это, вероятно, очень сложно понять. У меня не так много опыта в кодировании, поэтому я уверен, что моя логика не очень хороша.
@Alison, 👍0
1 ответ
Лучший ответ:
Я бы предположил, что вы видите сброс-заикание от последовательного порта. В основном скетч работает и заполняет последовательный буфер данными. Затем вы подключаетесь, и плата сбрасывается, но некоторые данные все еще находятся в буфере чипа USB. Затем скетч снова начинает работать, и отправляются новые данные.
По сути, я предполагаю, что вы можете увидеть что-то вроде:
3.87,4.45,55.13,
19.44,43.12,14.56,1.01,23.87,4.45,55.13,
19.44,43.12,14.56,1.01,23.87,4.45,55.13,
19.44,43.12,14.56,1.01,23.87,4.45,55.13,
19.44,43.12,14.56,1.01,23.87,4.45,55.13,
где первая строка осталась от предыдущего выполнения перед сбросом. Вы не получите этого при полном отключении и повторном подключении, потому что в буфере USB нет «предыдущих» данных для отправки.
Самое простое решение — просто изящно с этим справиться. Взгляните на .length
вашего массива float и проверьте, правильный он или нет. Только если в нем достаточно записей, вы действительно хотите иметь дело с данными — в противном случае вы просто выбрасываете их и ждете прибытия следующей строки.
- AT-команда не отвечает на последовательный монитор
- Получить данные с сайта с помощью ESP8266 с помощью AT-команд
- Как отправить команду AT на sim800l с помощью SoftwareSerial
- SIM800L не регистрируется в сети
- Ардуино для чтения с преобразователя RS232 в последовательный модуль TTL
- Как читать и записывать на устройство rs232 с/на Arduino
- Чтение SMS с помощью Arduino Uno и SIM800L и печать на LCD (16x2 буквенно-цифровых) с использованием последовательного соединения
- Как изменить байт на целое число? - Arduino