inizio timer al cambiamento della variabile

Ciao a tutti, ho provato a cercare nel forum ma non sono riuscito a trovare qualche esempio. Dovrei far partire un timer quando una variabile superi un certo valore x e si azzera quando la variabile è uguale o minore di x. Potete darmi qualche idea? Non chiedo il codice pronto, ma il metodo corretto.

Vi ringrazio

unsigned long Start;
int primavolta=0;
...
if(variabile > x && primavolta==0)
{
 Start = millis();
primavolta =1;
}
if( variabile < x && primavolta==1)
{
tempo = millis()-Start;
primavolta =0;
}

Ciao Uwe

Dipende da come viene integrato nel resto del software, da quale precisione vuoi, da quanto sia rilevante un ritardo di attivazione e disattivazione, da cosa deve fare mentre il timer è attivo, da cosa deve fare quando viene attivato e disattivato ripetutamente...

A prima vista, ma senza sapere tutte quelle cose, il metodo più pulito e semplice consiste nel partire con timer=0, mettere un IF all'inizio del loop per vedere se variabile > x, se lo è allora incrementa il timer, altrimenti azzera il timer.

Di quanto incrementarlo? Del numero di millisecondi trascorso dall'ultima verifica.

Come faccio a sapere quanti millisecondi sono trascorsi? Usando millis, che ti fornisce il numero di millisecondi dall'accensione.

Come faccio a passare dai millisecondi dall'accensione ai millisecondi dall'ultima verifica? Hai memorizzato il precedente valore di millis in una variabile PreviousMillis e fai la differenza.

intanto vi ringrazio :slight_smile:

sto simulando con arduino il contatore dell’energia elettrica, per far si che mi avverta di aver superato la soglia dei 3300 watt e di conseguenza inizia un timer , se entro 3 sec watt non scende sotto i 3300 watt mi avverte.
per il test ho impostato la soglia di 1900 watt (per non fare staccare il contatore).

mi basta e avanza la precisione in secondi .

questo è il codice che ho scritto:

  if (watt > 1900 && start == 0) 
    {   
    mtime = millis(); // tempo di inizio conteggio
    start=1; 
     } 
   
 if (watt > 1900 && start == 1) 
    { 
    time = (millis() - mtime);
 
     if (time > 3000) 
	{
          Serial.println("Attenzione !!! limite MAX superato");
          lcd.setCursor(1, 0); 
          lcd.print("Attenzione !!!");
	}
	
	if (watt < 1900) 
        { 
		start = 0;
              lcd.clear();
               
        }
    }

ma mi succede che quando accendo arduino (o reset) due variabili prendono questi valori:
mtime=3011
start=1

sballandomi il timer…

... e che valore ti aspettavi invece ??? :astonished: :astonished: :astonished:

Quando accendi o fai reset, il contatore di mllis() parte da zero [u]e si incrementa di 1 ogni millisecondo[/u] ...

Guglielmo

E’ start = 1 all’inizio che è strano… a meno che tu inizi già con watt > 1900.
Ricordati inoltre che le variabili che usano i millis vanno inizializzate unsigned long.
Inoltre, quando watt < 1900 dovresti resettare il contatore time altrimenti ti rimane sull’ultimo valore.

Potresti iniziare con una cosa diversa, in modo da avere sott’occhio le variabili, falle stampare sull’LCD…
così vedi cosa sta succedendo. Fai stampare time, watt e start.

il valore di watt all’accensione è 0 l’ho controllato con il monitor.
per questo non capisco come start = 1 e mtime=3011 anche se watt è < di 1900.
posto il codice, sicuramente mi sfugge qualcosa…

#include "EmonLib.h"                   
#include <LiquidCrystal.h>
#include <LcdBarGraph.h>

#define ledV 7
#define ledG 8
#define ledR 9
#define LCD_LIGHT_PIN 10
#define LCD_LIGHT_ON_TIME 10000 // tempo accensione backlight (in millisecondi)

// buzzer
int freq = 2000;
int pinbuzz =6;



unsigned int currentLcdLightOnTime = 0;

// For calculating the lcd light on time.
unsigned long lcdLightOn_StartMillis;
boolean isLcdLightOn;
 
// For checking push-button state.
int buttonState = 0;

char bufferString[25];
char * floatToString(char *, float, int, int=0, bool=false);

//int count_let = 0;
//int somma = 0; 
int testresult=0;
int countCharY = 1;
int countCharX = 0;
//Calibrations
const int volt = 224;
const float ct_calibration = 30.17;
int watt;
int start;

//Sensor pins
const int currentSensorPin = A2;

unsigned long lettura_watt;
unsigned long timer_lcd;
unsigned long timer_accendi_led;
unsigned long mtime;
unsigned long time;

float Irms = 0;
// Create an Emon instance
EnergyMonitor emon1;                   

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
LcdBarGraph lbg(&lcd, 10, 3, 1);  // -- creating a 4 char wide baraph in the end of second column (column 1)


void setup() {
  pinMode(ledV, OUTPUT);
  pinMode(ledG, OUTPUT);
  pinMode(ledR, OUTPUT);

  pinMode(LCD_LIGHT_PIN, OUTPUT);
  // Set the lcd display backlight anode pin to low - lcd light off.
  digitalWrite(LCD_LIGHT_PIN, LOW);
  isLcdLightOn = false;
  time=0;
  mtime=0;
  start=0;
  watt=0;
  lettura_watt=millis();
  timer_lcd=millis();
  timer_accendi_led=millis();

  lcd.begin(2,16);
  lcd.clear();
  delay(100);
  
  Serial.begin(9600);
  Serial.println("watt");
    Serial.print(watt);
  //initialize Emon instance
  emon1.current(currentSensorPin, ct_calibration); 
  //  test();
}

void loop() {

  if (millis() > lettura_watt + 500) { //lettura sensore ogni 500ms
    watt=readWatt();
   
    lettura_watt = millis();
  }  

  if (millis() > timer_lcd + 1000) { //aggiornamento lcd ognni 1000 ms
    LCDmenu();
    timer_lcd = millis();
  }  

  if (millis() > timer_accendi_led + 1000) { //aggiornamento accensione led 1000ms
    accendi_led();
    timer_accendi_led = millis();
  }
  getButtonPush();
}




void accendi_led()
{

  if ( watt <= 800) // ( watt < 2700)
  {
    digitalWrite(ledV, HIGH);
    digitalWrite(ledG, LOW);
    digitalWrite(ledR, LOW);
  }
  else if ((watt > 800 ) &&  (watt <= 1800)) //((watt > 2699 ) &&  (watt < 3000))
  {
    digitalWrite(ledV, HIGH);
    digitalWrite(ledG, HIGH);
    digitalWrite(ledR, LOW);
  }
  else if ((watt > 1800 ) &&  (watt <=1960)) // ((watt > 2999 ) &&  (watt < 3250))
  {
    Serial.println("ROSSO");
    digitalWrite(ledV, HIGH);
    digitalWrite(ledG, HIGH);
    digitalWrite(ledR, HIGH);
  }
   if (watt > 1900 && start == 0) 
    { // Se valore di watt è > 3300 ed il segnale viene per la prima volta    
    mtime = millis(); // tempo di inizio conteggio
    start=1; 
    Serial.print("mtime=");   
    Serial.println(mtime);
    Serial.print("start=");
    Serial.println(start);
    } 
    if (watt > 1900 && start == 1) 
    { 
    time = (millis() - mtime);// fa la differenza e converte in centesimi di secondi
    Serial.print("Tempo=");   
    Serial.println(time);
    Serial.print("start=");
    Serial.println(start);
    
    Serial.println(time, DEC);// mostra sul pc il tempo
     if (time > 3000) // (time > 9000000) se la varialbile watt supera il valore di 3300 per più di 2 ore e 30  minuti  visualizza il msg
	{
          Serial.println("Attenzione !!! limite MAX superato");
          lcd.setCursor(1, 0); 
          lcd.print("Attenzione !!!");
	}
	
	if (watt < 1900) 
        { 
		start = 0;
              lcd.clear();
               Serial.print("Tempo=");   
    Serial.println(time);
    Serial.print("start=");
    Serial.println(start);	
        }
    }
//  if (watt > 3249)
//  {
//    tone(pinbuzz, freq);
//  }
//  else
//  {
//    noTone(pinbuzz);
//  }
}


void mainlcd()
{

  lcd.setCursor(1, 0); 
  lcd.print("Monitor");
  lcd.setCursor(1, 1); 
  lcd.print("Watt");  
  delay(2000);
  lcd.clear();
}


float readWatt()
{

  Irms = (emon1.calcIrms(1480)-0.05); // -0.04 è per tarare il sensore( avvicinare Irms allo zero senza carico, 
//  Serial.println(Irms);
  if (Irms*volt > 5){
     return (Irms*volt);
  }
  else
  {
     return 0;
  }
}


void LCDmenu()

{
  float ampere;
  if (Irms < 0){
    ampere = 0;
  }  
  else{
    ampere=Irms;
  }
  if (testresult == 0) {
    mainlcd();
    testresult = 1;
  }
  else    
  {
    lcd.setCursor(1, 0); 
    lcd.print("W:");
    lcd.setCursor(4, 0); 
    lcd.print(floatToString(bufferString, watt, 0, 5,true));
    //    lcd.print(watt);
    lcd.setCursor(10, 0);
    lcd.print(ampere,1);
    lcd.setCursor(2, 1); 
    lcd.print("[");
    lcd.setCursor(13, 1); 
    lcd.print("]");
    lbg.drawValue( watt, 3000);
  }
}



void getButtonPush()
{
  int data = analogRead(0);
//  Serial.println(data);
  if (data < 1023)  
  {
     // Button pressed.
    Serial.println("Button pressed - HIGH");
 
    lcdLightOn_StartMillis = millis();
    currentLcdLightOnTime = 0;
    isLcdLightOn = true;
    digitalWrite(LCD_LIGHT_PIN, HIGH);
    
    

    LCDmenu();	
    delay(200);
  }
   else{
    // Button not pressed.
    //Serial.println("Button not pressed - LOW");
 
    if(isLcdLightOn){
      currentLcdLightOnTime = millis() - lcdLightOn_StartMillis;
      if(currentLcdLightOnTime > LCD_LIGHT_ON_TIME){
        isLcdLightOn = false;
        digitalWrite(LCD_LIGHT_PIN, LOW);
      }
    }
  }
} 

char * floatToString(char * outstr, float value, int places, int minwidth, bool rightjustify) {
  // this is used to write a float value to string, outstr.  oustr is also the return value.
  int digit;
  float tens = 0.1;
  int tenscount = 0;
  int i;
  float tempfloat = value;
  int c = 0;
  int charcount = 1;
  int extra = 0;
  // make sure we round properly. this could use pow from <math.h>, but doesn't seem worth the import
  // if this rounding step isn't here, the value  54.321 prints as 54.3209

  // calculate rounding term d:   0.5/pow(10,places)  
  float d = 0.5;
  if (value < 0)
    d *= -1.0;
  // divide by ten for each decimal place
  for (i = 0; i < places; i++)
    d/= 10.0;    
  // this small addition, combined with truncation will round our values properly 
  tempfloat +=  d;

  // first get value tens to be the large power of ten less than value    
  if (value < 0)
    tempfloat *= -1.0;
  while ((tens * 10.0) <= tempfloat) {
    tens *= 10.0;
    tenscount += 1;
  }

  if (tenscount > 0)
    charcount += tenscount;
  else
    charcount += 1;

  if (value < 0)
    charcount += 1;
  charcount += 1 + places;

  minwidth += 1; // both count the null final character
  if (minwidth > charcount){        
    extra = minwidth - charcount;
    charcount = minwidth;
  }

  if (extra > 0 and rightjustify) {
    for (int i = 0; i< extra; i++) {
      outstr[c++] = ' ';
    }
  }

  // write out the negative if needed
  if (value < 0)
    outstr[c++] = '-';

  if (tenscount == 0) 
    outstr[c++] = '0';

  for (i=0; i< tenscount; i++) {
    digit = (int) (tempfloat/tens);
    itoa(digit, &outstr[c++], 10);
    tempfloat = tempfloat - ((float)digit * tens);
    tens /= 10.0;
  }

  // if no places after decimal, stop now and return

  // otherwise, write the point and continue on
  if (places > 0)
    outstr[c++] = '.';


  // now write out each decimal place by shifting digits one by one into the ones place and writing the truncated value
  for (i = 0; i < places; i++) {
    tempfloat *= 10.0; 
    digit = (int) tempfloat;
    itoa(digit, &outstr[c++], 10);
    // once written, subtract off that digit
    tempfloat = tempfloat - (float) digit; 
  }
  if (extra > 0 and not rightjustify) {
    for (int i = 0; i< extra; i++) {
      outstr[c++] = ' ';
    }
  }


  outstr[c++] = '\0';
  return outstr;
}

Inoltre, quando watt < 1900 dovresti resettare il contatore time altrimenti ti rimane sull’ultimo valore.

il contatore viene resettato di nuovo con questa if…

if (watt > 1900 && start == 0) 
    {   
    mtime = millis(); // tempo di inizio conteggio
    start=1; 
     }