Функции Delay() и millis() не работают во внешних файлах cpp

В настоящее время я сталкиваюсь с проблемой использования функций delay() и millis() во внешнем файле cpp. Проблема в том, что когда я использовал функцию delay() в своей основной программе (имеется в виду файл .ino), она работает хорошо, но когда я вызываю ту же функцию во внешнем файле cpp, я застреваю в функции delay. Что касается настройки, файл .hpp, связанный с используемым cpp, хорошо включен в файл .ino и в Arduino librairy.h включен в мой cpp. Я также попытался заменить задержку циклом с использованием миллиса, но значение, возвращаемое миллисом, всегда равно 0. Я использую Arduino mega2560 и датчик уровня воды в следующем примере. Версия Arduino IDE 1.8.16.

Вот выдержка из моего файла ino:

#include <Arduino.h>
#include "DS3231.h"
#include "MyGardenClock.hpp"
#include "sensors.hpp"
#include <LiquidCrystal.h>
#include "Keypad.h"
#include <Wire.h>

///Time object creation
DS3231 clock; //Clock object -> contains basic Real Time Clock functions
RTCDateTime dt; //Struct from DS3231 lib - contains date and time 
mG_RTC myClock; //Object that contains specific clock functions to my project like printing date and time on the lcd...

///LCD object creation
//--Pin allocation
const int rs = 2, en = 1, d4 = 4, d5 = 7, d6 = 8, d7 = 10;
//--LCD dynamic object creation
LiquidCrystal* pLCD = new LiquidCrystal(rs, en, d4, d5, d6, d7);


///Keypad parametrization and object creation
//Define col nb and row nb
const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns
//define the cymbols on the buttons of the keypads
char hexaKeys[ROWS][COLS] = {
  {'1','2','3','A'},
  {'4','5','6','B'},
  {'7','8','9','C'},
  {'*','0','#','D'}
};
byte rowPins[ROWS] = {52, 50, 48, 46}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {44, 42, 40, 38}; //connect to the column pinouts of the keypad
//Keypad dynamic object creation
Keypad* pKpd = new Keypad(makeKeymap(hexaKeys),rowPins,colPins,ROWS,COLS);
    
///Sensors object creation 
//WaterLvl Sensors
//--Pin allocation
const int WtrLvlAnalogPin = 8; //pin used to read value from water lvl sensor
const int WtrLvlPowerPin = 35; //pin used to power the sensor before reading a value
//--WaterLvl dynamic object creation
Water_Lvl_Sensor* pWtrLvlSens = new Water_Lvl_Sensor(WtrLvlAnalogPin,WtrLvlPowerPin); //contains the delay and millis functions that don't work

/////////// TEST FUNCTIONS ///////////
void testLCD_Kpd(Keypad*,LiquidCrystal*); //test lcd and keypad
void testWtrLvlSens(Water_Lvl_Sensor*,LiquidCrystal*); //test water lvl sensor

void setup()
{
    Serial.begin(9600);
    pLCD->begin(16,2);
    testLCD_Kpd(pKpd,pLCD);
    testWtrLvlSens(pWtrLvlSens,pLCD);  
   
}

void loop()
{
    
}
////////////////////// TEST FUNCTIONS ///////////////////////////
void testLCD_Kpd(Keypad* pKpd, LiquidCrystal* pLCD)
{
   char test;
   test ='i';
   
   pLCD->print("Hello");
   do
   {
    test = pKpd->waitForKey();
   }while(test=='i');
   pLCD->clear();
   delay(3000); //This one work well
   pLCD->print("test = ");
   pLCD->print(test);
   
}

void testWtrLvlSens(Water_Lvl_Sensor* pWLS,LiquidCrystal* plcd)
{
  int wtrLvl;
  wtrLvl = pWLS->getCurrentWaterLvlValue();
  plcd->setCursor(0,1);
  plcd->print("wtrLvl = ");
  plcd->print(wtrLvl);
  
}

Вот выдержка из моего файла cpp:

#include <Arduino.h>
#include "sensors.hpp"
    
/********************************************
*   CLASS WATER LvL SENSOR DESCRIPTION      *
********************************************/
///Constructor
//-- Assign pin number (analog & digital)
//-- Define pinMode for VCC + set to low
//-- read and store actual waterLevelValue as initial val
Water_Lvl_Sensor::Water_Lvl_Sensor(int anPinNb, int DigPinNb)
{
  //Variable used for millis 
  unsigned long prevTime;
  unsigned long currentTime;
  const unsigned long delayTime = 100;

  Serial.begin(9600); //to debug

  //Assign analog and digital pin numbers
  analogPinNumber = anPinNb;
  VCC_digitalPinNumber = DigPinNb;
  pinMode(VCC_digitalPinNumber, OUTPUT); //Digital pin to power the sensor
  digitalWrite(VCC_digitalPinNumber,HIGH);//Turn sensor ON before reading initial value
  
  //delay(100); //not working ???
  prevTime = millis(); //get and store actual time
  do
  {
    currentTime = millis(); //get actual time
    Serial.println(currentTime); //print actual time (debug only)
  }while(currentTime<(prevTime+delayTime)); //while time spent < 100
  
  currentValue = analogRead(analogPinNumber); //read analog value
  
  digitalWrite(VCC_digitalPinNumber,LOW); //turn sensor OFF
  historyValue = currentValue; //init history val
  minValue = 0; //default value - sensor dry
  maxValue = 520; //default value - sensor under water
}

У кого-нибудь есть решение?

Надеюсь, я рассказал достаточно подробностей. Если нет, пожалуйста, не стесняйтесь спрашивать.

Спасибо!

, 👍5


1 ответ


Лучший ответ:

10

Платформа Arduino выполняет некоторую инициализацию для вас, прежде чем перейти к настройке() и циклу (), например, правильно настраивает Timer0 для миллисов(), задержки() и братьев и сестер. Это делается в функции main (), которая затем после первой инициализации вызывает setup() и loop().

Но создание глобально определенных объектов (и, следовательно, выполнение их конструкторов) выполняется еще до функции main (). В это время ни millis(), ни delay() не будут работать, так как для их работы необходимо правильно настроить аппаратное время 0. Аппаратный таймер генерирует прерывания с определенной частотой, и в соответствующем ISR (Подпрограмма обслуживания прерываний) увеличивается переменная для millis (). Если Timer0 не настроен, его прерывание не может сработать, и, следовательно, функция millis() останется нулевой. Таким образом, вы не можете сделать все это в конструкторе объекта, или вам всегда нужно создавать объект в setup() или loop().

Именно по этой причине большинство библиотек Arduino, связанных с оборудованием, используют метод .begin() для инициализации материалов, связанных с оборудованием. Эта функция может быть вызвана для глобального объекта в функции setup (), когда все остальное уже настроено правильно.

Что теперь делать? Создайте метод .begin() для своего класса. Переместите весь код из конструктора (за исключением присвоения pin) в эту функцию .begin (). А затем вызовите эту функцию в setup().

,

Большое спасибо за ваш быстрый ответ. Это действительно имеет смысл, действительно. Я внесу изменения и скажу вам, сработает ли это, но я уверен., @Cyril_Ram

Привет, Крисл, просто чтобы ты знала, что твое решение работает хорошо. Большое спасибо., @Cyril_Ram