Arduino. Запись данных и вывод на сервер
- Войдите на сайт для отправки комментариев
Добрый день, уважаемые форумчане!
Я работаю над проектом: запись данных акселерометра на micro SD карту и отправка данных на web server. Использую arduino uno и Ethernet Shield + micro SD
Застрял на этапе объединения транслирования данных с карты на сервер и записи показателей
Ниже представлен мой код, я пока только начинающий так что готов к критике и предложениям!)
А вопрос такой, как объединить постоянную запись данных и выкладку файлов (Я сохраняю данные в CSV формат) списком на сервер например раз в 15 минут или постоянно.
Мой код сейчас создает каждый раз новый файл с новым именем, из setup вносит в файл Gx, Gy, Gz
и далее как раз и нужны показания подряд: то есть я по отдельности сделал это и нужно как-то интегрировать в loop это: file = SD.open(fileName, FILE_WRITE);
#include <SD.h>
#include <SPI.h>
#include <Ethernet.h>
#define FILE_BASE_NAME "Data_"
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // change if necessary
byte ip[] = { 192, 168, 1, 177 }; // change if necessary
EthernetServer server(80);
int CS_pin = 10;
int pow_pin = 8;
int xPin = A0;
int yPin = A1;
int zPin = A2;
float Vmax = 5.0;
float x0 = 1.71;
float y0 = 1.69;
float z0 = 1.68;
float sens_x = 0.35;
float sens_y = 0.35;
float sens_z = 0.35;
#define SDCARD_CS 4
File file;
const uint8_t BASE_NAME_SIZE = sizeof(FILE_BASE_NAME) - 1;
char fileName[] = FILE_BASE_NAME "00.csv";
//long id = 1;
#if defined(ESP8266)
// default for ESPressif
#define WIZ_CS 15
#elif defined(ESP32)
#define WIZ_CS 33
#elif defined(ARDUINO_STM32_FEATHER)
// default for WICED
#define WIZ_CS PB4
#elif defined(TEENSYDUINO)
#define WIZ_CS 10
#elif defined(ARDUINO_FEATHER52)
#define WIZ_CS 11
#else // default for 328p, 32u4 and m0
#define WIZ_CS 10
#endif
// store error strings in flash to save RAM
#define error(s) error_P(PSTR(s))
void error_P(const char* str) {
Serial.print(F("error: "));
Serial.println(str);
while (1);
}
void setup() {
Serial.begin(9600);
Serial.println("Распознавание SD карты");
pinMode(CS_pin, OUTPUT);
pinMode(pow_pin, HIGH);
if (!SD.begin(SDCARD_CS)) {
error("card.init failed!");
}
Serial.println("Card ready");
Ethernet.init(WIZ_CS);
// give the ethernet module time to boot up
delay(1000);
// start the Ethernet connection
// Use the fixed IP specified. If you want to use DHCP first
// then switch the Ethernet.begin statements
Ethernet.begin(mac, ip);
// try to congifure using DHCP address instead of IP:
// Ethernet.begin(mac);
// print the Ethernet board/shield's IP address to Serial monitor
Serial.print(F("My IP address: "));
Serial.println(Ethernet.localIP());
server.begin();
while (SD.exists(fileName)) {
if (fileName[BASE_NAME_SIZE + 1] != '9') {
fileName[BASE_NAME_SIZE + 1]++;
} else if (fileName[BASE_NAME_SIZE] != '9') {
fileName[BASE_NAME_SIZE + 1] = '0';
fileName[BASE_NAME_SIZE]++;
} else {
Serial.println(F("Can't create file name"));
return;
}
}
file = SD.open(fileName, FILE_WRITE);
if (file)
{
String header = ("Gx, Gy, Gz");
file.println(header);
Serial.print(F("opened: "));
Serial.println(fileName);
file.close();
Serial.println(header);
}
else
{
Serial.println("EROR111");
}
}
void ListFiles(EthernetClient client, uint8_t flags, File dir) {
client.println("<ul>");
while (true) {
File entry = dir.openNextFile();
// done if past last used entry
if (! entry) {
// no more files
break;
}
// print any indent spaces
client.print("<li><a href=\"");
client.print(entry.name());
if (entry.isDirectory()) {
client.println("/");
}
client.print("\">");
// print file name with possible blank fill
client.print(entry.name());
if (entry.isDirectory()) {
client.println("/");
}
client.print("</a>");
/*
// print modify date/time if requested
if (flags & LS_DATE) {
dir.printFatDate(p.lastWriteDate);
client.print(' ');
dir.printFatTime(p.lastWriteTime);
}
// print size if requested
if (!DIR_IS_SUBDIR(&p) && (flags & LS_SIZE)) {
client.print(' ');
client.print(p.fileSize);
}
*/
client.println("</li>");
entry.close();
}
client.println("</ul>");
}
// How big our line buffer should be. 100 is plenty!
#define BUFSIZ 100
void loop()
{
char clientline[BUFSIZ];
char name[17];
int index = 0;
int value_x = analogRead(xPin);
int value_y = analogRead(yPin);
int value_z = analogRead(zPin);
float Gx = (value_x * Vmax / 1024.0 - x0) / sens_x;
float Gy = (value_y * Vmax / 1024.0 - y0) / sens_y;
float Gz = (value_z * Vmax / 1024.0 - z0) / sens_z;
EthernetClient client = server.available();
if (client) {
// an http request ends with a blank line
boolean current_line_is_blank = true;
// reset the input buffer
index = 0;
while (client.connected()) {
if (client.available()) {
char c = client.read();
// If it isn't a new line, add the character to the buffer
if (c != '\n' && c != '\r') {
clientline[index] = c;
index++;
// are we too big for the buffer? start tossing out data
if (index >= BUFSIZ)
index = BUFSIZ - 1;
// continue to read more data!
continue;
}
// got a \n or \r new line, which means the string is done
clientline[index] = 0;
// Print it out for debugging
Serial.println(clientline);
// Look for substring such as a request to get the file
if (strstr(clientline, "GET /") != 0) {
// this time no space after the /, so a sub-file!
char *filename;
filename = clientline + 5; // look after the "GET /" (5 chars) *******
// a little trick, look for the " HTTP/1.1" string and
// turn the first character of the substring into a 0 to clear it out.
(strstr(clientline, " HTTP"))[0] = 0;
if (filename[strlen(filename) - 1] == '/') { // Trim a directory filename
filename[strlen(filename) - 1] = 0; // as Open throws error with trailing /
}
Serial.print(F("Web request for: ")); Serial.println(filename); // print the file we want
File file = SD.open(filename, O_READ);
if ( file == 0 ) { // Opening the file with return code of 0 is an error in SDFile.open
client.println("HTTP/1.1 404 Not Found");
client.println("Content-Type: text/html");
client.println();
client.println("<h2>File Not Found!</h2>");
client.println("<br><h3>Couldn't open the File!</h3>");
break;
}
Serial.println("File Opened!");
client.println("HTTP/1.1 200 OK");
if (file.isDirectory()) {
Serial.println("is a directory");
//file.close();
client.println("Content-Type: text/html");
client.println();
client.print("<h2>Files in /");
client.print(filename);
client.println(":</h2>");
ListFiles(client, LS_SIZE, file);
file.close();
} else { // Any non-directory clicked, server will send file to client for download
client.println("Content-Type: application/octet-stream");
client.println();
char file_buffer[16];
int avail;
while (avail = file.available()) {
int to_read = min(avail, 16);
if (to_read != file.read(file_buffer, to_read)) {
break;
}
// uncomment the serial to debug (slow!)
//Serial.write((char)c);
client.write(file_buffer, to_read);
}
file.close();
}
} else {
// everything else is a 404
client.println("HTTP/1.1 404 Not Found");
client.println("Content-Type: text/html");
client.println();
client.println("<h2>File Not Found!</h2>");
}
break;
}
}
// give the web browser time to receive the data
delay(20);
client.stop();
}
}
void printDirectory(File dir, int numTabs) {
while (true) {
File entry = dir.openNextFile();
if (! entry) {
// no more files
break;
}
for (uint8_t i = 0; i < numTabs; i++) {
Serial.print('\t');
}
Serial.print(entry.name());
if (entry.isDirectory()) {
Serial.println("/");
printDirectory(entry, numTabs + 1);
} else {
// files have sizes, directories do not
Serial.print("\t\t");
Serial.println(entry.size(), DEC);
}
entry.close();
}
}
Вывод COM порта
Какого типа помощи Вы ожидаете? Совета? Вот совет: выделите нужный фрагмент кода, скопируйте в loop()
Вот в этом и проблема, когда данную часть кода вставляю в loop, то программа начинает некоректно работать, все время создавая новый файл и помещая туда заголовки, при этом сервер перестает работать
то программа начинает некоректно работать, все время создавая новый файл и помещая туда заголовки,
Как же Вы представляете себе корректную работу?
Файл должен создаваться и заголовки должны быть, но потом он должен не закрываться,а принимать входные значения и записывать в этот файл Gx, Gy, Gz. Я могу скинуть корректный скетч просто акселерометра, где все это реализовано, но без сервера.
Грубо говоря у меня по отдельности все работает: и сервер, и данные пишутся как надо, а вот при объединении начинаются проблемы
Лично мне не нужен "скетч просто акселерометра".
Сначала определитесь при каких условиях должен открываться и закрываться файл. А потом уже в готовый код вписывайте фрагменты, открывающие и закрывающие (или не закрывающие) файл.
После загрузки скетча на ардуино должно происходить следующее: Создаваться файл CSV, туда пишутся заголовки Gx, Gy, Gz, далее в этот файл записываются показания акселерометра по каждой из осей до тех пор, пока программа работает и должна быть параллельно отправка на сервер. Как только перестает или сбой, будет создаваться новый файл. Я так понимаю, что из-за моей этой бесконечной записи в файл показаний, как раз и не получается объединить это
Если файл закрывать не надо, значит в setup() не следует вызывать функцию file.close() - логично?
Если в loop() необходимо писать данные, то нужно в нем вызывать file.close() - тоже логично?
Насчёт отправки на сервер я ничего не понял, т.к. в коде ничего подобного не наблюдаю.
А про сервер: С помощью Ethernet Shield подключаюсь локальному серверу 192.168.1.177 и там показываются данные SD карты, при этом в моем скетче при открывании монитора порта создается новый файл и на сервере при обновлении страницы он появляется
Задумка такова, чтобы поставить ардуино и она писала данные на sd карту, параллельно транслируя на сервер и чтобы можно было их скачать
А про сервер: С помощью Ethernet Shield подключаюсь локальному серверу 192.168.1.177 и там показываются данные SD карты,
Это не так. Код говорит о том, что с помощью Ethernet Shield вы на Arduino создаете Web-сервер и обслуживаете подключающихся к Arduino клиентов, отдавая им файлы с SD.
Да, вы очень хорошо сформулировали, именно так, спасибо
И вот объединить этот процесс и запись показаний не удается
У меня они по отдельности отлично работают
Если файл закрывать не надо, значит в setup() не следует вызывать функцию file.close() - логично?
Если в loop() необходимо писать данные, то нужно в нем вызывать file.close() - тоже логично?
Насчёт отправки на сервер я ничего не понял, т.к. в коде ничего подобного не наблюдаю.
Если в setup убрать file.close(), то на сервере будет писаться "Файлы не найдены"
Да, вы очень хорошо сформулировали, именно так, спасибо
И вот объединить этот процесс и запись показаний не удается
Мне кажется, это потому, что Вы сами не понимаете, как у Вас должна работать программа.
Постарайтесь то, что Вы описали в сообщении №7, записать в виде последовательных шагов алгоритма. По-русски.
Да, вы очень хорошо сформулировали, именно так, спасибо
И вот объединить этот процесс и запись показаний не удается
Мне кажется, это потому, что Вы сами не понимаете, как у Вас должна работать программа.
Постарайтесь то, что Вы описали в сообщении №7, записать в виде последовательных шагов алгоритма. По-русски.
Я так и делал, и я считаю, что когда это подставлял в loop все выглядело логично, но не работает и я не понимаю причины
Я так и делал, и я считаю, что когда это подставлял в loop все выглядело логично, но не работает и я не понимаю причины
Мы не видели, что именно Вы делали, поэтому тоже не понимаем причины.
Я так и делал, и я считаю, что когда это подставлял в loop все выглядело логично, но не работает и я не понимаю причины
Мы не видели, что именно Вы делали, поэтому тоже не понимаем причины.
А, Вы. проверьте что он делал и доложите о результатах проверки здесь.
И вот нужно как-то объединить, но не выходит
Ардуина не является устройством, осуществляющим за полчаса любые фантазии людей без подготовки. Некоторым так и не удается осуществить желаемое в экономически оправданные сроки.
Так что учтите - простая, на первый взгляд, вещь может выливаться написание сотен и тысяч строк кода, дни самостоятельной отладки и т.п.
В данном случае, с вашим алгоритмом, видимо придется каждый раз при обслуживании клиента закрывать файл, а потом открывать его заново.
Может есть какой-то альтернативный метод/идея?
И вот нужно как-то объединить, но не выходит
А если нужно объединить функции двух скетчей, то это делается следующим образом:
1. Выясняется алгоритм работы каждого из скетчей.
2. Записывается алгоритм для решения требуемой задачи.
3. Код на основании 2 пишется с нуля.
Альтернативных методов решения задачи, неизвестной решающему - мильярд. Попросите шведа посоветовать вам десерт - будете есть сюрстреминг с клюквенным соусом.