Ошибки в PlatformIO
- Войдите на сайт для отправки комментариев
Добрый день.
Пытаюсь сделать многофайловый проект.
файл main.cpp
#include "config.h" void setup() { Serial.begin(115200); WiFiManager wifiManager; //wifiManager.resetSettings(); //wifiManager.setAPStaticIPConfig(IPAddress(10,0,1,1), IPAddress(10,0,1,1), IPAddress(255,255,255,0)); wifiManager.autoConnect("AutoConnectAP"); //or use this for auto generated name ESP + ChipID //wifiManager.autoConnect(); Serial.println("connected... :)"); init_mqtt(); } void loop() { mqttClient.loop(); if (!mqttClient.connected()) { if (millis() - lastReconnectAttempt > 5000) { lastReconnectAttempt = millis(); // Attempt to reconnect if (reconnect()) { lastReconnectAttempt = 0; } } } }
файл mqtt.cpp
#ifndef MQTT_H #define MQTT_H #include "config.h" const char *mqtt_server = "m20.cloudmqtt.com"; // Имя сервера MQTT const int mqtt_port = 17301; // Порт для подключения к серверу MQTT const char *mqtt_user = "***********"; // Логи от сервер const char *mqtt_pass = "******"; // Пароль от сервера void callback(char* topic, byte* payload, unsigned int length); void init_mqtt() { mqttClient.setServer(mqtt_server, mqtt_port); mqttClient.setCallback(callback); } void callback(char* topic, byte* payload, unsigned int length) { // Функция получения данных от сервера } boolean reconnect() { Serial.print("Attempting MQTT connection..."); // Attempt to connect if (mqttClient.connect("ESP8266Client", mqtt_user, mqtt_pass)) { Serial.println("connected"); // Once connected, publish an announcement... mqttClient.publish("outTopic", "hello world");//************************************************************* // ... and resubscribe mqttClient.subscribe("pg1/led1"); // подписывааемся по топик с данными для светодиода mqttClient.subscribe("pg1/led2"); // подписывааемся по топик с данными для светодиода mqttClient.subscribe("pg1/stopres"); // подписывааемся по топик с запретом на реакцию на фоторезистор mqttClient.subscribe("pg1/lightlevel"); // подписывааемся по топик с порогом освещенности mqttClient.subscribe("pg1/timezone"); // подписывааемся по топик с timezone } else { Serial.print("failed, rc="); Serial.print(mqttClient.state()); Serial.println(" try again in 5 seconds"); } return mqttClient.connected(); } #endif
файл config.h
#ifndef GLOBAL_H #define GLOBAL_H #include <Arduino.h> #include <DNSServer.h> #include <ESP8266WebServer.h> #include <WiFiManager.h> #include <PubSubClient.h> //"https://github.com/knolleary/pubsubclient.git" #define LED_PIN_1 5 // 1 LED #define LED_PIN_2 12 //2 LED #define REL_PIN_1 13 //1 relay #define REL_PIN_2 14 //2 relay #define SENSOR_PIN A0 // выберите входной контакт,к которому подключен фоторезистор (2) #define TEMPHUM_PIN 4 // выберите входной контакт,к которому подключен датчик unsigned long lastReconnectAttempt = 0; WiFiClient espClient; PubSubClient mqttClient(espClient); void init_mqtt(); boolean reconnect(); #endif
На этапе компиляции получаю ошибку
.pioenvs\esp12e\src\mqtt.cpp.o:(.bss.mqttClient+0x0): multiple definition of `mqttClient'
.pioenvs\esp12e\src\main.cpp.o:(.bss.mqttClient+0x0): first defined here
.pioenvs\esp12e\src\mqtt.cpp.o:(.bss.espClient+0x0): multiple definition of `espClient'
.pioenvs\esp12e\src\main.cpp.o:(.bss.espClient+0x0): first defined here
.pioenvs\esp12e\src\mqtt.cpp.o:(.bss.lastReconnectAttempt+0x0): multiple definition of `lastReconnectAttempt'
.pioenvs\esp12e\src\main.cpp.o:(.bss.lastReconnectAttempt+0x0): first defined here
collect2.exe: error: ld returned 1 exit status
Подскажите что я делаю не так
не так делаешь многофайловый праэкт
Все. Прежде всего в ардуино IDE основной файл проекта ОБЯЗАН иметь расширение .ino и содержать процедуры setup() и loop(). Все остальные файлы ОБЯЗАНЫ иметь стандартные сишные расширения в имени файлов и находится в одном дирректории с основным файлом проекта. Название дирректория ОБЯЗЯНО быть копией имени основного файла проекта, но без расширения.
А как?
Все. Прежде всего в ардуино IDE основной файл проекта ОБЯЗАН иметь расширение .ino и содержать процедуры setup() и loop(). Все остальные файлы ОБЯЗАНЫ иметь стандартные сишные расширения в имени файлов и находится в одном дирректории с основным файлом проекта. Название дирректория ОБЯЗЯНО быть копией имени основного файла проекта, но без расширения.
Это PlatformIO. Там все делается именно как я написал. В смысле именования файлов.
Все. Прежде всего в ардуино IDE ...bla-bla-bla...
1. Брукли, Уважаемый! Перечитай название темыю Там не про ИДЕ $)))
Подскажите что я делаю не так
2. Но частично Брукли прав. Платформио повторяет дуйствия АрдуиноИДЕ для совместимости. То есть сливает все файлы каталога в один. А ты два раза инклюдишь config.h. Вот и причина малтипл дефинишн. Отдельно только библиотеки компилируются.
Но ведь я указываю
#ifndef GLOBAL_H
02
#define GLOBAL_H
почему это не работает?
Лично я не понимаю зачем в config.h определять переменные и экземпляры класса! Зачем? В чём смысел?
Но ведь я указываю
#ifndef GLOBAL_H
02
#define GLOBAL_H
почему это не работает?
Разреши поинтересоваться: а как, по твоему, это должно работать?
Разреши поинтересоваться: а как, по твоему, это должно работать?
примерна, как
#pragma once
Но ведь я указываю
#ifndef GLOBAL_H
02
#define GLOBAL_H
почему это не работает?
почему не работает? - работает.
Эта конструкция обеспечивает, чтобы ваш config.h не включался дважды в один и тот же компилируемый модуль. Но модуля-то у вас два - mqtt.cpp и main.cpp! поэтому config.h включается в программу дважды и все переменные, в нем описанные - получают двойное описание, о чем вам компилятор и сообщает.
Чтобы такого не было, глобальные переменные следует описывать только в .cpp файлах, а чтобы использовать их в других модулях программы - пользоваться квалификатором EXTERN
И как он ДВАЖДЫ включится в ОДИН И ТОТ ЖЕ МОДУЛЬ? Хоть с
#ifndef GLOBAL_H
02
#define GLOBAL_H
хоть без?
Лично я не понимаю зачем в config.h определять переменные и экземпляры класса! Зачем? В чём смысел?
Чтобы все в одном месте было. А как правильно?
И как он ДВАЖДЫ включится в ОДИН И ТОТ ЖЕ МОДУЛЬ?
а кто сказал что он в один модуль включился?
Спасибо, с переменными понятно.
Но как быть с
Они используются в двух файлах.
Разреши поинтересоваться: а как, по твоему, это должно работать?
примерна, как
#pragma once
виноват. не заметил, что все правильно написано, #endif в конце файла.
И ощибки у линковщика - значит я был неправ и платформио, все-таки, компилирует отдельно. Следовательно правильный ответ у Б707.
1. Брукли, Уважаемый! Перечитай название темыю Там не про ИДЕ $)))
Да да да да... да..
Извините, может я глупые вопросы задаю, но все же как быть с Но как быть с
Извините, может я глупые вопросы задаю, но все же как быть с Но как быть с
Вам же ответили !
Чтобы такого не было, глобальные переменные следует описывать только в .cpp файлах, а чтобы использовать их в других модулях программы - пользоваться квалификатором EXTERN
Други, уже весь инет перерыл, в общем и целом понял, как разбить код на файлы, но не получается, выдает ошибку при компиляции, умом понимаю, что где-то "запятую" пропустил, но не пойму где. Помогите, пожалуйста, разбить следующий код из примера на два файла main.cpp и server.cpp
убрать в server.cpp
void handleRoot();
void handleNotFound();
Сделал так, что не правильно?
Main.cpp
cfg.h
server.cpp
server.h
Получаю ошибки:
Building in release mode
Compiling .pio\build\nodemcuv2\src\main.cpp.o
Compiling .pio\build\nodemcuv2\src\server.cpp.o
Compiling .pio\build\nodemcuv2\lib5aa\ESP8266WiFi\ESP8266WiFiMulti.cpp.o
Compiling .pio\build\nodemcuv2\lib5aa\ESP8266WiFi\ESP8266WiFiSTA-WPS.cpp.o
In file included from C:\users\global\.platformio\packages\framework-arduinoespressif8266\libraries\ESP8266WiFi\src/ESP8266WiFi.h:40:0,
from src\cfg.h:3,
from src\server.cpp:1:
C:\users\global\.platformio\packages\framework-arduinoespressif8266\libraries\ESP8266WiFi\src/WiFiServer.h:68:34: error: expected class-name before '{' token
class WiFiServer : public Server {
^
C:\users\global\.platformio\packages\framework-arduinoespressif8266\libraries\ESP8266WiFi\src/WiFiServer.h:97:16: error: type 'Print' is not a base type for type 'WiFiServer'
using Print::write;
^
In file included from C:\users\global\.platformio\packages\framework-arduinoespressif8266\libraries\ESP8266WiFi\src/ESP8266WiFi.h:40:0,
from src\cfg.h:3,
from src\main.cpp:1:
C:\users\global\.platformio\packages\framework-arduinoespressif8266\libraries\ESP8266WiFi\src/WiFiServer.h:68:34: error: expected class-name before '{' token
class WiFiServer : public Server {
^
C:\users\global\.platformio\packages\framework-arduinoespressif8266\libraries\ESP8266WiFi\src/WiFiServer.h:97:16: error: type 'Print' is not a base type for type 'WiFiServer'
Compiling .pio\build\nodemcuv2\lib5aa\ESP8266WiFi\ESP8266WiFiSTA.cpp.o
using Print::write;
^
*** [.pio\build\nodemcuv2\src\server.cpp.o] Error 1
*** [.pio\build\nodemcuv2\src\main.cpp.o] Error 1
================================================================================================== [FAILED] Took 5.56 seconds ==================================================================================================
The terminal process "C:\Users\Global\.platformio\penv\Scripts\pio.exe 'run'" terminated with exit code: 1.
И где результат эксперимента с пропущенной запятой? Или как всегда: "ничего не делал, покажите как надо, а я копипастой дальше"...
Про заголовочные файлы читали? Рекомендую.
Не очень понял вопрос. В первом сообщении, что хочу сделать. Во втором, как я это сделал и ругань компилятора. Что еще необходимо, подскажите?
Второе сообщение появилось, пока я писал реплику.
Сделал так, что не правильно?
обьект
обьявлен дважды - один раз в main.cpp. другой раз в server.cpp
Собственно, ошибка та же самая, что у начального топикстартера . И как ее избежать - уже обьяснено выше.
Не ругается на дублирование.
Как я его уже не писал и в .h выносил и в main прописывал, потом
в server.cpp
все одно.
Если знаете, напишите просто как правильно объявить, всем следующим вопрошающим тоже будет понятно.
для начала давайте разберемся, где ошибка.
Если две процедуры из server.cpp
банально вставить в main.cpp примерно на 13 строку - ошибки пропадут?
Естесственно, при этом server.cpp и server.h вообще выкинуть из проекта
Посмотрите мое первое сообщение, где файл один. Он отлично компилируется. Как только я его разбиваю на два - ошибки.
Я бы server по ссылке в функции передавал. А так - нужно экстерны везде ставить, по-моему.
Ну значит ошибка все-таки в двойном описании. Сообщения об ошибках не всегда выражают источник ошибки, иногда только следствия.
А если вообще не использовать глобальную переменную server в других модулях, а лишь передавать ссылку на нее? попробуйте. в вашем коде пару строчек всего поправить.
Не мудрите, пальцем покажите, это быстрее ;)
во и я о том же :)
Более того, при разбиении кода на файлы я бы вообще все, что связано с сервером - вынес в один файл. И обьект описал бы только там.
Признак правильного разбиения - это когда все библиотеки "ESPWiFi*" не требуются в основном коде вовсе
Маааатььььь.....
Убрал вообще хедер. В основе прописал
все скомпилилось!!!!
Нахрена этот хедер тогда вообще нужен!!!????
Маааатььььь.....
Убрал вообще хедер. В основе прописал
все скомпилилось!!!!
Нахрена этот хедер тогда вообще нужен!!!????
выложите все полностью
Признак правильного разбиения - это когда все библиотеки "ESPWiFi*" не требуются в основном коде вовсе
Т.е. лучше сетап тоже в server вынести? или в сетапе просто ссылку на функцию в server?
main.cpp
server.cpp
Т.е. лучше сетап тоже в server вынести? или в сетапе просто ссылку на функцию в server?
да, я обычно так и делаю.
то что вы выложили выше - два .cpp файла, никак формально не связанные между собой - это полная бредятина с точки зрения С++ :)
Вы еще проверьте, будет ли это работать. С формальной точки зрения у вас в коде два СОВЕРШЕННО ОТДЕЛЬНЫХ обьекта server, поэтому совершенно не факт, что server из server.cpp будет обрабатывать запросы для того server. что в main
b707, sadman41 - спасибо большое. Мучился долго. Начитался про эти хедеры и хотел все по феншуй, но...
Скомпилировалось и залилось нормально.
Как правильно?
Получается я в майне просто объявил
void handleRoot();
void handleNotFound();
и server сам подсосался
Не сочтите за труд, поправьте код, пожалуйста, чтобы правильно было. Мы так можем ооочень долго разговаривать стоя на месте. А один пример все разложит по полочкам.
Скомпилировалось и залилось нормально.
Как правильно?
так выше вроде написали. Выносите абсолютно весь код. связанный с сервером - в отдельный файл. Из основного main вызываете только свои собственный функции, описанные в server.h и реализованные в server.cpp
Смысл в том, чтобы пару server.h server.cpp можно было перенести в другой проект, вообще не редактируя. А у вас сейчас половина кода сервера в отдельном файле. половина в main. Это и нелогично и, скорее. только запутывает.
Это стиль гайвера :). он именно так раскладывает свои проекты на файлы... типа в каталоге 20 исходных файлов, из которых в десяти используются кнопки...
Чем так "разбивать" - лучше уж одну общую "портянку" на 2 тыс строк
Не сочтите за труд, поправьте код, пожалуйста, чтобы правильно было.
нет, это Ваш проект
так я сейчас вообще server.h удалил и тогда скомпилировалось. Обратно надо?
нет, это Ваш проект
Тогда, уж простите, все ваши хорошие советы БЕСПОЛЕЗНЫ, к великому сожалению.
Тогда, уж простите, все ваши хорошие советы БЕСПОЛЕЗНЫ, к великому сожалению.
ну это проблема всех советов... кому-то они помогают. а кому-то нет
Я уже разъяснял неоднократно. Такого рода советы полезны может быть только профессионалам. А на этом сайте общаются люди, которые пишут под Ардуино - в массе своей "hello world".
Для такого рода людей, лучшая подсказка - пример, тогда все понятно и встает на свои места. Я неоднократно так попадал, что мудохаешься день, а потом пример пришлют, а там запятая стоит вместо точки или == вместо =. Никто не будет ради "помигать лампочкой" осваивать Си с нуля, достаточно нахватать блоков, собрать их в одну программу и радоваться, что все работает.
Поэтому всегда и призываю - не надо умных слов, дайте пример или конкретную подсказку. Вам не сложно, а остальным гораздо проще все это понять. В любом случае спасибо за то, что уже подсказали. Буду опять думать и мучиться, теперь с подсказкой.
Профессионал обидится, если ему такие советы давать будут.
Этот форум, вообще говоря, ориентирован на людей, для которых Ардуино - это хобби, а не способ получить конкретную вещь. И, соответственно, для них выбор между "научиться" и "получить готовое" всегда склоняется в пользу первого.
Так что Ваше "никто не будет" относится, слава Богу, не ко всем, а только к Вам и Вам подобным. Т.е. по сути - к людям, которые на этом форуме лишние. И людям, для которых главное "нахватать блоков, собрать их в одну программу и радоваться, что все работает", вряд ли следует навязывать свое мнение завсегдатаям форума.
Не нравится - идите на другой форум, этот форум - не для вас.
Не нравится - идите на другой форум, этот форум - не для вас.
Ну я-то тут подольше вашего. И скорее ваше мнение относится к таким, как вы и им подобным. Я вас не помню, но уже по вашему тексту примерно представляю, что вы из себя представляете и вот таким тут точно не рады. На будущее - хобби, это и есть НЕ профессионалы и выбор для ардуинщиков ВСЕГДА склоняется в сторону собрать из работающих кусков, а не изучить язык с нуля.
Так что не надо меня никуда посылать, без вас разберусь. А не можете помочь - проходите мимо и не пустозвоньте. И так уже тему загадили.
PAV, показать человеку правильную дорогу - любезность, а довести его до порога нужного дома - уже труд.
Тут точно так же. Я знаю, как делать правильно. И обьяснить В ОБЩИХ ЧЕРТАХ мне не сложно. Но написать Вам конкретный пример точно под ваши исходные данные, чтобы он без ошибок собрался в Платформио, которой я в глаза не видел - это уже работа. Там вполне могут велезти нюансы, которые могут оказаться неожиданными. Я думаю, что в итоге разберусь, но... скажите, почему с этим должен разбираться я. если проект - ваш?
Существует некий разумный предел помощи, за которым любезность превращается в обязанность. Я вам ничем не обязан и потому для меня написание для вас примеров - это перебор.