Официальный сайт компании Arduino по адресу arduino.cc
Формирование строки
- Войдите или зарегистрируйтесь, чтобы получить возможность отправлять комментарии
Чт, 24/10/2019 - 14:22
#include <Arduino.h> #include <SPI.h> #include <Wire.h> #include <BME280I2C.h> #include <LiquidCrystal_I2C.h> #include <OneWire.h> #include <DallasTemperature.h> #include "Ethernet.h" #include <PubSubClient.h> #include "Button.h" const uint32_t BAUD_RATE = 115200; const uint8_t RESOLUTION = 12; // res in {9,10,11,12} const uint16_t ONE_SECOND = 1000; // Pin 0 -> Rx UART // Pin 1 -> Tx UART const uint8_t WATER_SENSOR_PIN = 2; const uint8_t BUTTON_PIN = 3; const uint8_t ONE_WIRE_BUS = 4; // Pin A4 -> SDA I2C // Pin A5 -> SCL I2C Button button(BUTTON_PIN); LiquidCrystal_I2C lcd(0x27, 16, 2); BME280I2C sensor; OneWire oneWire(ONE_WIRE_BUS); DallasTemperature wSensor(&oneWire); EthernetClient ethClient; PubSubClient client(ethClient); BME280::TempUnit tempUnit(BME280::TempUnit_Celsius); BME280::PresUnit presUnit(BME280::PresUnit_torr); struct Display { String name; float data; }; enum Menu { PRESSURE, TEMPERATURE_AIR, HUMIDITY, WATER_FLOW, WATER_TEMPERATURE }; Display display[]{ {"Pressure ", NAN}, {"Temp air ", NAN}, {"Humidity ", NAN}, {"Water flow ", NAN}, {"Water temp ", NAN}}; byte MAC[]{0xDE, 0xED, 0xBA, 0xFE, 0xFE, 0xE7}; const IPAddress IP(192, 168, 1, 177); const IPAddress SERVER(192, 168, 1, 1); const char *MQTT_NAME = "my"; const char *MQTT_PASSWORD = "YMS"; const char *MQTT_TOPIC = "outTopic"; uint8_t count = 0; volatile float pulseFreq; DeviceAddress tempDeviceAddress; uint16_t conversionTime; uint32_t previosTimeWS; uint32_t previosTimeShow; uint32_t previosTimeConversion; uint32_t previosTimeMQTT; typedef void (*Do)(); void timer(uint32_t &, uint32_t, Do); void show(); void onButton(); void WSinterrupt(); void reconnect(); void setup() { // Настройка UART Serial.begin(BAUD_RATE); // Настройка датчика потока воды pinMode(WATER_SENSOR_PIN, INPUT); attachInterrupt(digitalPinToInterrupt(WATER_SENSOR_PIN), WSinterrupt, RISING); previosTimeWS = millis(); // Настройка LCD дисплея lcd.init(); lcd.backlight(); lcd.home(); // Настройка BME280 I2C if (!sensor.begin()) { Serial.println("Could not find BME280 sensor!"); delay(1000); } // Настройка Button button.setHandler(onButton); // Настройка датчика температуры воды DallasTemperature conversionTime = 750 / (1 << (12 - RESOLUTION)); previosTimeConversion = millis(); wSensor.begin(); wSensor.getAddress(tempDeviceAddress, 0); wSensor.setResolution(tempDeviceAddress, RESOLUTION); wSensor.setWaitForConversion(false); // start the Ethernet connection: Ethernet.begin(MAC, IP); if (Ethernet.hardwareStatus() == EthernetNoHardware) Serial.println("Ethernet shield was not found."); else if (Ethernet.linkStatus() == LinkOFF) Serial.println("Ethernet cable is not connected."); // Настройка PubSubClient client.setServer(SERVER, 1883); randomSeed(micros()); } void publish() { if (!client.connected()) reconnect(); else { String bufer; bufer = "{\n\t\"Air temperature\" : " + (String)display[TEMPERATURE_AIR].data + ",\n\t\"Air pressure\" : " + (String)display[PRESSURE].data + ",\n\t\"Air humidity\" : " + (String)display[HUMIDITY].data + ",\n\t\"Water temperature\" :" + (String)display[WATER_TEMPERATURE].data + ",\n\t\"Water flow\" : " + (String)display[WATER_FLOW].data + ",\n}"; uint8_t msgLen = bufer.length(); Serial.print(bufer); client.beginPublish(MQTT_TOPIC, msgLen, false); client.print(bufer); client.endPublish(); } } void loop() { button.loop(); sensor.read(display[PRESSURE].data, display[TEMPERATURE_AIR].data, display[HUMIDITY].data, tempUnit, presUnit); timer(previosTimeConversion, conversionTime, [] { display[WATER_TEMPERATURE].data = wSensor.getTempCByIndex(0); wSensor.requestTemperatures(); }); timer(previosTimeWS, ONE_SECOND, [] { // Liter/hour display[WATER_FLOW].data = pulseFreq * 60 / 7.5; pulseFreq = 0; }); timer(previosTimeShow, ONE_SECOND, show); timer(previosTimeMQTT, 1000, publish); } void show() { uint8_t _count = count; lcd.clear(); lcd.setCursor(0, 0); lcd.print(display[_count].name + display[_count].data); if (++_count >= sizeof(display) / sizeof(display[0])) _count = 0; lcd.setCursor(0, 1); lcd.print(display[_count].name + display[_count].data); } /* Пересмотреть */ void reconnect() { static unsigned long previousTimeFailed; if (millis() - previousTimeFailed > 5000) { Serial.print(F("Attempting MQTT connection...")); // Создание произвольного имени клиента String clientId = "Ethernet-"; clientId += String(random(0xffff), HEX); // Попытка соединения с сервером if (client.connect(clientId.c_str(), MQTT_NAME, MQTT_PASSWORD)) { Serial.println(F(" connected!")); /* ................................................................. */ } else { Serial.print(F(" failed, ")); switch (client.state()) { case MQTT_CONNECTION_TIMEOUT: Serial.print(F("the server didn't respond within the keepalive time")); break; case MQTT_CONNECTION_LOST: Serial.print(F("the network connection was broken")); break; case MQTT_CONNECT_FAILED: Serial.print(F("the network connection failed")); break; case MQTT_CONNECT_BAD_PROTOCOL: Serial.print(F("the server doesn't support the requested version of MQTT")); break; case MQTT_CONNECT_BAD_CLIENT_ID: Serial.print(F("the server rejected the client identifier")); break; case MQTT_CONNECT_UNAVAILABLE: Serial.print(F("the server was unable to accept the connection")); break; case MQTT_CONNECT_BAD_CREDENTIALS: Serial.print(F("the username/password were rejected")); break; case MQTT_CONNECT_UNAUTHORIZED: Serial.print(F("the client was not authorized to connect")); break; default: break; } Serial.println(F(" try again in 5 seconds")); previousTimeFailed = millis(); } } } void onButton() { if (++count >= sizeof(display) / sizeof(display[0])) count = 0; } void WSinterrupt() { pulseFreq++; } void timer(uint32_t &previosTime, uint32_t interval, Do func) { if (millis() - previosTime >= interval) { func(); previosTime = millis(); } }
Если просто попробовать в loop(), все хорошо выводится в сериал.
String bufer; bufer = "{\n\t\"Air temperature\" : " + (String)display[TEMPERATURE_AIR].data + ",\n\t\"Air pressure\" : " + (String)display[PRESSURE].data + ",\n\t\"Air humidity\" : " + (String)display[HUMIDITY].data + ",\n\t\"Water temperature\" :" + (String)display[WATER_TEMPERATURE].data + ",\n\t\"Water flow\" : " + (String)display[WATER_FLOW].data + ",\n}"; Serial.println(burer);
Если пытаюсь создать строку внутри функции получается пустая строка. Иногда формируются огрызки.
Уже третий вечер сижу бьюсь ни чего сделать не могу :(
функцию в студию
Может банально места в памяти не хватает ?
функцию в студию
Так яж код весь выложил.
То что памяти не хватает уже задумывался.
и чо Serial.print(buffer) пишет?
При компиляции bufer это указатель на строку. А в момент работы - под строку выделяется реальная память и судя по всему не малого размера.
Как вариант вынести объявление bufer из функции и разу задать максимальный размер.
В функции ни чего, в лупе выводит.
Скорее всего, он несколько раз пытается перехапать память, ибо строка растёт, ты ж ей максимальное значение не задал, так она и перевыделяется кусками по X байт (не помню скока). А потом её не хватает....
При компиляции bufer это указатель на строку.
Хреналысого. Это сразу локальный (стековый) обьект.
DetSimen с размером указателя же.
Я про то, что в "DATA: [======= ] 69.7% (used 1427 bytes from 2048 bytes)" не учтен размер строки от слова СОВСЕМ.
anarch - вариант решения - переписать функцию без использования String - памяти нужно будет раз в 10 меньше
Урезал строку и все заработало
Не удивлен.
anarch - вариант решения - переписать функцию без использования String - памяти нужно будет раз в 10 меньше
Если решения со String не найдется буду переписывать.
А проверить вариант с объявлением вне функции и сразу достаточного размера ?
DetSimen с размером указателя же.
Нет. Размером класса сразу но на стеке. Он обьявлен не как
String *buffer;
Вкурил - String, это не string.
Если решения со String не найдется буду переписывать.
любое решение со String - временное, лучше сразу писать правильно
Вот так вот переписал
Выводит полностью. Но на выходе не получаю значений.
Как преобразовать поле структуры float в строку.
И о том что меньше занимает места я бы не сказал.
И о том что меньше занимает места я бы не сказал.
То что знамает меньше места - видно хотя бы по тому, что теперь строчка не теряется. А что ардуино показывает те же цифры - так и должно быть. Диагностика Ардуино учитывает в своих расчетах только глобальные переменные, а у вас тут работа с локальными.
значения теряются. потому что вы используете тип float. В ардуино sprintf с float не работает
dtostrf() наше все.
Всем спасибо!
Всем спасибо!
Я ах..еваю, дорогая редакция! ;))) Я вааще фигею от здорового аптимизьмуса!
Что бы куча не скучала ...
wdrakula,нормально.
wdrakula, готов выслушать ваши предложения по решению данного момента мне то же не нравиться.
wdrakula, готов выслушать ваши предложения по решению данного момента мне то же не нравиться.
Родное сердце! Если ты поймешь, почему я глумился, то это уже "путь к исцелению".
1. что, по твоему, делает строка:
char
*buf =
new
char
;
Вот четко опиши, основываясь не на своих домыслах, а на правилах языка.
2. Вообще кто, где и когда выделяет память под твои строки и где указывает потребный размер памяти?
Выделяет 1 байт памяти.
Тоды задам по другому вопрос. Как выделять память не зная размер строки?
Тоды задам по другому вопрос. Как выделять память не зная размер строки?
Вы сами-то себя услышали? "Как выделить кусок памяти, не зная какого размера кусок нужен?"
Вы сами-то себя услышали? "Как выделить кусок памяти, не зная какого размера кусок нужен?"
Похоже, существуют люди, уверенные, что компьютер умнее, чем они.
И возможно даже, они правы. (((((((((((
Т.е. если я не знаю какой длины у меня строка, я должен выделить кусок памяти с запасом, поработать с ним и очистить, а если не хватило попросить еще. На верном пути?
Вы выделили память под один байт, а пихаете туда ... Хвост строки живет своей жизнью. Вам просто повезло что под этим хвостом не оказались важные данные. В Вашем случае очень легко вычисляется необходимый размер буфера под всю строку плюс один байт под 0. И ещё первой командой должна быть не strcat, а strcpy.
весело тут у вас)) жду свою ардуинку и тоже буду вопросы глупые задавать)
baby_in_Arduin для старта плата даже не нужна - достаточно Proteus !
а для глупых вопросов не нужно ни того, ни другова.
Умные вопросы то же не стоит задавать :x
И так если я знаю размер буфера, что мне мешает сделать так:
после того как блок отработает переменная удалиться (или просто исчезнет из области видимости?).
Т.е. смысл или когда нужно выделять динамически память?
Если это локальная переменная функции - то удалица, если глобальная то нет.
Т.е. смысл или когда нужно выделять динамически память?
имеет смысл, если у вас потребности в памяти постоянно меняются. Например, в большинстве случаев вам хватает строчки в 30 символов, а раз в месяц проскакивает запрос в 400. В этом случае нет смысла всегда держать буфер в 400 символов.
Или вариант когда вы даже приблизительно не знаете, сколько понадобится - в этом случае при каждом новом запросе сначала вычисляете его длину и отводите нужное количество памяти.
Динамическая память для тех случаев, когда неизвестно количество даже близко (от 0 до ... размеров доступной памяти) ! У Вас же явно можно посчитать сколько символов в тексте и сколько позиций надо под цифры.
Умные вопросы то же не стоит задавать :x
И так если я знаю размер буфера, что мне мешает сделать так:
после того как блок отработает переменная удалиться (или просто исчезнет из области видимости?).
Т.е. смысл или когда нужно выделять динамически память?
так и надо делать если объем данных невелик это намного быстрее работы с динамической кучей
есть область памяти называемая "стек" она выделяется один раз при старте программы и все локальные переменные хранятся в ней, при входе в функцию место в стеке "выделяется"(по факту просто изменением одного регистра) чтоб вместить все локальные переменные а при выходе освобождается(опять же изменением одного регистра), таким образом все функции используют один и тот же многократно перезаписываемый клочок памяти для своих локальных переменных, поэтому то работа с локальными переменными намного быстрее чем с кучей
вопрос опытным ардуинщикам какой максимальный размер буфера на стеке? вообще каков размер стека? какая область памяти "за стеком"? что мы потрем в случае если превысим максимальный размер буфера?
Стек растет вниз и может переехать даже через порты IO. Если же локальная переменная в стеке "перерастет" свои границы, то первым делом наедет на адрес возврата (иногда это делают осознанно) и возврат будет ХЗ куда.
Динамическая память для тех случаев, когда неизвестно количество даже близко (от 0 до ... размеров доступной памяти) ! У Вас же явно можно посчитать сколько символов в тексте и сколько позиций надо под цифры.
так этож тогда ассемблер получается )))
У нас статистики такой нету. Те, у каво стек переполнился, получают психологическую травму, несовместимую с нормальным функционирование арганизма, и на форумах больше не пишуть.
DetSimen надо взять на заметку как способ отписаться от форумов !!!
Стек растет вниз и может переехать даже через порты IO. Если же переменная в стеке "перерастет" свои границы, то первым делом наедет на адрес возврата (иногда это делают осознанно) и возврат будет ХЗ куда.
вот про ардуино уно пишут ОЗУ 2КБ в этих 2КБ и стек и куча?
baby_in_Arduino плюс глобальные переменные :-)
Стек растет вниз и может переехать даже через порты IO. Если же переменная в стеке "перерастет" свои границы, то первым делом наедет на адрес возврата (иногда это делают осознанно) и возврат будет ХЗ куда.
вот про ардуино уно пишут ОЗУ 2КБ в этих 2КБ и стек и куча?
вот почему я за тебя искать должен? Ты ленив, или просто сын депутата?
http://robocraft.ru/blog/arduino/531.html
вот почему я за тебя искать должен? Ты ленив, или просто сын депутата?
http://robocraft.ru/blog/arduino/531.html
а нет какого метода прикрутить внешнюю память?
а нет какого метода прикрутить внешнюю память?
научиться писать софт при ограниченных ресурсах железа
а нет какого метода прикрутить внешнюю память?
Есть и даже на этом форуме описано. Великий как-то прикручивал. Доприкрутил ли - не помню, но постов было много.