RtcDateTime' не называет тип

Я протестировал код, который успешно компилируется.

Но после того, как я объединил его с другим кодом, здесь отображается ошибка, в которой говорится, что RtcDateTime не называет тип.

Используемая библиотека: https://github.com/Makuna/Rtc

Некоторые примечания: - Экземпляры RtcDateTime без проблем используются в setup() и loop(). - Включен заголовочный файл RtcDS3231 (который включает в себя RtcDateTime.h). - Пытался включить RtcDateTime.h в свой скетч, не работает!

Код: (содержит комбинацию из 3 устройств: RTC, ультразвуковой I2C и тензодатчик HX711)

/*
Below, I define the SCL and SDA pins by their ATMEGA pins I have included links to common mappings below.
    UNO:  http://arduino.cc/en/Hacking/PinMapping168
    NANO: (matches UNO but has fewer pins)
    MEGA 2560: http://arduino.cc/en/Hacking/PinMapping2560
The current data matches the setup for the Arduino Uno -- they may need to be changed if the hardware changes.
You can also switch the I2C interface
to any of the tristate pins that you want (not just the SDA or SCL pins).
*/
#define SCL_PIN D2              // SDA по умолчанию — это Pin5 PORTC для UNO — вы можете установить его на любой контакт с тремя состояниями
#define SDA_PIN D1              // SCL по умолчанию — это Pin4 PORTC для UNO — вы можете установить его на любой контакт с тремя состояниями
#define I2C_TIMEOUT 100        //Определить тайм-аут в 100 мс -- не ждите, пока часы растянутся дольше, чем это время


#include "HX711.h"  //Вы должны иметь эту библиотеку в папке вашей библиотеки arduino

#define DOUT  D1
#define CLK  D2

HX711 scale(DOUT, CLK);
float calibration_factor = -10060; //-106600 работало для моих максимальных весов 40 кг

/*
I have included a couple of extra useful settings for easy reference.
//#define I2C_CPUFREQ (F_CPU/8)//Полезно, если вы планируете переключать часы
#define I2C_FASTMODE 1         //Запуск в быстром режиме (400 кГц)
#define I2C_SLOWMODE 1         //Если вы не определите режим, он будет работать на частоте 100 кГц, если для этого определения установлено значение 1, он будет работать на частоте 25 кГц
*/
#include <SlowSoftI2CMaster.h>     //Вам нужно будет установить эту библиотеку
// создаем новый экземпляр с A4 как SDA, A5 как SCL и разрешаем внутренние подтягивания
SlowSoftI2CMaster si = SlowSoftI2CMaster(SDA_PIN, SCL_PIN);



/*
 *  RTC Code starts here 
 */

#include <Wire.h> // здесь должно быть указано, чтобы ссылки на объектные файлы библиотеки Arduino работали
#include <RtcDS3231.h>
RtcDS3231<TwoWire> Rtc(Wire);
/*
 *  RTC Headers Ending
 */


void setup(){
  // Инициализируем последовательную шину и шину I2C
  Serial.begin(9600);
  Serial.println("Press T to tare");
  scale.set_scale(calibration_factor);  //Коэффициент калибровки, полученный из первого скетча
  scale.tare();             // Сброс масштаба до 0

if (!si.i2c_init()) // инициализируем модуль I2C
        Serial.println("I2C init failed");



    /*
     *  RTC Setup :
     */
     Rtc.Begin(SDA_PIN,SCL_PIN);

    RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);
    printDateTime(compiled);
    Serial.println();

    if (!Rtc.IsDateTimeValid()) 
    {
        // Общие причины:
        // 1) первый раз, когда вы запустились, а устройство еще не запустилось
        // 2) батарея на устройстве разряжена или вообще отсутствует

        Serial.println("RTC lost confidence in the DateTime!");

        // следующая строка устанавливает RTC на дату & время составления этого скетча
        // он также внутренне сбрасывает действительный флаг, если только устройство Rtc не
        // проблема

        Rtc.SetDateTime(compiled);
    }

    if (!Rtc.GetIsRunning())
    {
        Serial.println("RTC was not actively running, starting now");
        Rtc.SetIsRunning(true);
    }

    RtcDateTime now = Rtc.GetDateTime();
    if (now < compiled) 
    {
        Serial.println("RTC is older than compile time!  (Updating DateTime)");
        Rtc.SetDateTime(compiled);
    }
    else if (now > compiled) 
    {
        Serial.println("RTC is newer than compile time. (this is expected)");
    }
    else if (now == compiled) 
    {
        Serial.println("RTC is the same as compile time! (not expected but all is fine)");
    }

    // никогда не предполагайте, что последний раз Rtc был настроен вами, поэтому
    // просто очистите их до нужного вам состояния
    Rtc.Enable32kHzPin(false);
    Rtc.SetSquareWavePin(DS3231SquareWavePin_ModeNone); 

    /*
     *  RTC Setup Ending
     */
}
#define countof(a) (sizeof(a) / sizeof(a[0]))

void loop()
{
  if (!si.i2c_init()) // инициализируем модуль I2C
        Serial.println("I2C init failed");
  // (НЕОБЯЗАТЕЛЬНО) Чтение датчика по адресу по умолчанию
  read_the_sensor_example();

  scale.begin(SDA_PIN,SCL_PIN);
  Serial.print("Weight: ");
  Serial.print(scale.get_units(), 5);  //До 3 знаков после запятой
  Serial.println(" kg"); // Измените это значение на кг и повторно отрегулируйте коэффициент калибровки, если вы следуете фунтам

  if(Serial.available())
  {
    char temp = Serial.read();
    if(temp == 't' || temp == 'T')
      scale.tare();  // Сбрасываем шкалу на ноль
  }

  /*
   *  RTC Loop Start
   */
  if (!Rtc.IsDateTimeValid()) 
    {
        // Общие причины:
        // 1) батарея на устройстве разряжена или вообще отсутствует и линия питания была отключена
        Serial.println("RTC lost confidence in the DateTime!");
    }

    RtcDateTime now = Rtc.GetDateTime();


    Serial.println();
    // Дата строки = dateS(сейчас);
    // Строка time = timeS(сейчас);



  RtcTemperature temp = Rtc.GetTemperature();
  temp.Print(Serial);
  // вы также можете получить температуру в виде числа с плавающей запятой и распечатать ее
    // Serial.print(temp.AsFloatDegC());
    Serial.println("C");

  /*
   *    RTC loop Ending
   */
}

void printDateTime(const RtcDateTime& dt)
{
    char datestring[20];

    snprintf_P(datestring, 
            countof(datestring),
            PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
            dt.Month(),
            dt.Day(),
            dt.Year(),
            dt.Hour(),
            dt.Minute(),
            dt.Second() );
    Serial.print(datestring);
}

////////////////////////////////////////////////// /
// Функция: начать чтение диапазона на датчике //
////////////////////////////////////////////////// /
//Использует библиотеку I2C для запуска датчика по заданному адресу
// Собирает и сообщает бит ошибки, где: 1 = была ошибка или 0 = ошибки не было.
//INPUTS: byte bit8address = адрес датчика, которому мы хотим дать команду на чтение диапазона
//ВЫВОДЫ: битовый уровень ошибки = сообщает, успешно ли функция получила показания диапазона: 1 = функция
// произошла ошибка, 0 = функция выполнена успешно
boolean start_sensor(byte bit8address){
  boolean errorlevel = 0;
  bit8address = bit8address & B11111110;               // Выполняем побитовую операцию «и», чтобы последний бит был равен нулю — мы записываем по адресу.
  errorlevel = !si.i2c_start(bit8address) | errorlevel;   // Запускаем i2c_start(address), при этом собираем все ошибки, где 1 = ошибка.
  errorlevel = !si.i2c_write(81) | errorlevel;            // Отправляем команду «снять показания диапазона». (обратите внимание, что в библиотеке ошибка = 0, поэтому мне пришлось использовать "!" (не), чтобы инвертировать ошибку)
  si.i2c_stop();
  return errorlevel;
}



////////////////////////////////////////////////// //////////////////////
// Функция: Считать диапазон с датчика по указанному адресу //
////////////////////////////////////////////////// //////////////////////
//Использует библиотеку I2C для чтения датчика по заданному адресу
// Собирает ошибки и сообщает о недопустимом диапазоне «0», если возникла проблема.
//INPUTS: byte bit8address = адрес датчика для чтения
//ВЫВОДЫ: int range = расстояние в сантиметрах, о котором сообщил датчик; если "0" произошла ошибка связи
int read_sensor(byte bit8address){
  boolean errorlevel = 0;
  int range = 0;
  byte range_highbyte = 0;
  byte range_lowbyte = 0;
  bit8address = bit8address | B00000001;  // Выполняем побитовую операцию «или», чтобы последний бит был равен «единице» — мы читаем по адресу.
  errorlevel = !si.i2c_start(bit8address) | errorlevel;
  range_highbyte = si.i2c_read(0);           // Читаем байт и отправляем ACK (подтверждение)
  range_lowbyte  = si.i2c_read(1);           //Чтение байта и отправка NACK для завершения передачи
  si.i2c_stop();
  range = (range_highbyte * 256) + range_lowbyte;  // компилируем целое число диапазона из двух полученных байтов.
  if(errorlevel){
    return 0;
  }
  else{
    return range;
  }
}



//////////////////////////////////////////
// Функция: изменить адрес датчика //
//////////////////////////////////////////
//Использует библиотеку I2C для изменения адреса датчика по заданному адресу
// Собирает и сообщает бит ошибки, где: 1 = была ошибка или 0 = ошибки не было.
//INPUTS: byte oldaddress = текущий адрес датчика, который мы хотим изменить
//INPUTS: byte newddress = адрес, на который мы хотим изменить датчик
//ВЫВОДЫ: битовый уровень ошибки = сообщает, успешно ли функция изменила адрес: 1 = функция имела
// ошибка, 0 = функция выполнена успешно
boolean change_address(byte oldaddress,byte newaddress){
  // обратите внимание, что новый адрес будет работать только как четное число (нечетные числа будут округляться в меньшую сторону)
  boolean errorlevel = 0;
  oldaddress = oldaddress & B11111110;  // Выполняем побитовую операцию «и», чтобы последний бит был равен нулю — мы записываем по адресу.
  errorlevel = !si.i2c_start(oldaddress) | errorlevel; //Начать общение по новому адресу и отслеживать коды ошибок
  errorlevel = !si.i2c_write(170) | errorlevel;        // Отправляем код разблокировки и отслеживаем коды ошибок
  errorlevel = !si.i2c_write(165) | errorlevel;        // Отправляем код разблокировки и отслеживаем коды ошибок
  errorlevel = !si.i2c_write(newaddress) | errorlevel; //Отправляем новый адрес
// si.i2c_stop();
  return errorlevel;
}



////////////////////////////////////////////////// ////////
// Пример кода: чтение датчика по адресу по умолчанию //
////////////////////////////////////////////////// ////////
void read_the_sensor_example(){
  boolean error = 0;  // При необходимости создайте бит для проверки ошибок перехвата.
  int range;

  //Получить диапазон по адресу по умолчанию 224
  error = start_sensor(224);    //Запускаем датчик и собираем все коды ошибок.
  if (!error){                  //Если у вас возникла ошибка при запуске датчика, нет смысла читать ее, так как вы получите старые данные.
    delay(100);
    range = read_sensor(224);   //чтение датчика вернет целочисленное значение -- если это значение равно 0, произошла ошибка
    Serial.print("R:");Serial.println(range);
  }
}



////////////////////////////////////////////////// ///////////////
// Пример кода: опрос всех возможных адресов для поиска датчика //
////////////////////////////////////////////////// ///////////////
void address_polling_example(){
  boolean error = 0;  // При необходимости создайте бит для проверки ошибок перехвата.
  int range = 0;
  Serial.println("Polling addresses...");

  //Проходим по всем возможным адресам и проверяем устройство, которое может получить команду диапазона и будет
  // возвращаем два байта.
  for (byte i=2; i!=0; i+=2){   //начинаем с 2 и считаем на 2, пока не дойдем до 0. Проверяем все адреса (2-254), кроме 0 (который не может использоваться устройством )
    error = 0;
    error = start_sensor(i);    //Запускаем датчик и собираем все коды ошибок.
    if (!error){                //Если у вас возникла ошибка при запуске датчика, нет смысла ее читать.
      delay(100);
      range = read_sensor(i);   //чтение датчика вернет целочисленное значение -- если это значение равно 0, произошла ошибка
      Serial.println(i);
      if (range != 0){
        Serial.print("Device found at:");Serial.print(i);Serial.print(" Reported value of:");Serial.println(range);
      }  
    }
    else{
      Serial.print("Couldn't start:");Serial.println(i);
    }
  }

  Serial.println("Address polling complete.");
}



////////////////////////////////////////////////
// Пример кода: изменение адреса по умолчанию //
////////////////////////////////////////////////
void default_address_change_example(){
  boolean error = 0;  // При необходимости создайте бит для проверки ошибок перехвата.
  int range;

  Serial.println("Take a reading at the default address");

  //Получить диапазон по адресу по умолчанию 224
  error = start_sensor(224);    //Запускаем датчик и собираем все коды ошибок.
  if (!error){                  //Если у вас возникла ошибка при запуске датчика, нет смысла ее читать.
    delay(100);
    range = read_sensor(224);   //чтение датчика вернет целочисленное значение -- если это значение равно 0, произошла ошибка
    Serial.print("R:");Serial.println(range);
  }

   Serial.println("Change the sensor at the default address to 222");
  //Изменить адрес с 224 на 222
  error = 0;
  error = change_address(224,222);  // Изменяем адрес -- на данный момент я ничего не делаю с обработчиком ошибок, но вы можете, если хотите.
  delay(200);    // Подождите 125 мс, пока датчик сохранит новый адрес и сбросится

   Serial.println("Take a reading at the new address");

  //Считаем диапазон по новому адресу 222
  error = 0;
  error = start_sensor(222);     //То же, что и выше, но по новому адресу
  if (!error){
    delay(100);
    range = read_sensor(222);
    Serial.print("N:");Serial.println(range);
  }  

   Serial.println("Change the sensor back to the default address");  

  //Изменить адрес с 222 на 224
  error = 0;
  error = change_address(222,224);
  delay(200);    // Подождите 125 мс, пока датчик сохранит новый адрес и сбросится

}

Поэтому я понятия не имею, почему это происходит.

Любая помощь?

, 👍-1

Обсуждение

ОК, Я НАШЕЛ ОШИБКУ! Но что это за ошибка!? после многократной обрезки кода, обнаружившего, какое дополнение вызвало ошибку. это была строка 21 поплавковая калибровка_коэффициента = -10060; включение/выключение - это край появления ошибки !, @Hamzah Hajeir

Верь или не верь! комментарий вызывает ошибку [facepalm], @Hamzah Hajeir

Какую версию IDE вы используете? Я считаю, что проблема связана с расположением автоматически сгенерированных прототипов функций., @Majenko

Это 1.8.7 - Но это так странно, что комментарий может вызвать такое!, @Hamzah Hajeir

Это не комментарий. Это то лицо, которое находится перед включением, и именно в этом месте IDE размещает прототипы. Переместите включение для rtc перед этим поплавком., @Majenko

переместите все включения в начало файла. вы усложняете преобразование ino-to-cpp Arduino Builder своим стилем, @Juraj

@Majenko Спасибо за решение! Теперь компилируется без ошибок :) . Но самое странное, что удаление комментария также устраняло ошибку! хД, @Hamzah Hajeir

@Majenko Это ужасно, если я разделю свой скетч на несколько вспомогательных файлов .h в каталоге скетчей, а затем включу их все в свой файл .ino?, @Hamzah Hajeir

Странные вещи случаются с прототипами Arduino IDE, если вы не будете осторожны. Это одна из первых вещей, за которые я взялся в UECIDE, где прототипы всегда размещаются непосредственно перед первой фактической функцией в коде., @Majenko

Лучше разбить код на несколько файлов INO. Затем среда IDE объединяет их для вас — нет необходимости включать их вручную., @Majenko

Итак, INO не файлы h? между ними может быть какое-то взаимодействие., @Hamzah Hajeir

Файлы INO являются отдельными только для вас. Для кода это всего лишь один файл INO., @Majenko

Извините, я вас не понял. Я вижу, что между некоторыми файлами .h в папке скетча может быть 1 файл .ino, где они включены в файл .ino в качестве заголовка. Это то, что вы имели ввиду?, @Hamzah Hajeir

@Majenko Я только что прочитал ветку на форумах Arduino, теперь мне стало понятнее. Я разберусь с этим., @Hamzah Hajeir

@Majenko Привет, мистер, я пытался разбить свой код на несколько файлов INO. Но сообщение об ошибке снова появляется. Я проверил каждый файл INO: сначала библиотека включает, затем идет определение, затем идут глобальные экземпляры и переменные., @Hamzah Hajeir

Убедитесь, что включения идут только в начале «основного» файла .INO — того, что является именем скетча., @Majenko

Большое спасибо @Majenko, теперь все работает без проблем. Раньше я тоже разбивал включения на файлы. Теперь исправил это, и он компилируется (y), @Hamzah Hajeir


1 ответ


1

У меня тоже была такая же проблема, поместите функцию printDateTime на первую страницу или страницу, где доступны заголовки и объявления

функция ниже

#define countof(a) (sizeof(a) / sizeof(a[0]))
void printDateTime(const RtcDateTime& dt)
{
    char datestring[20];

    snprintf_P(datestring, 
            countof(datestring),
            PSTR("%02u/%02u/%04u %02u:%02u:%02u"),
            dt.Month(),
            dt.Day(),
            dt.Year(),
            dt.Hour(),
            dt.Minute(),
            dt.Second() );
    Serial.print(datestring);
}
,