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 пишется с нуля.
Альтернативных методов решения задачи, неизвестной решающему - мильярд. Попросите шведа посоветовать вам десерт - будете есть сюрстреминг с клюквенным соусом.