Go Down

Topic: Lampada RGB...Automatico--> Manuale (Read 821 times) previous topic - next topic

skizzo942

Buon giorno ragazzi, come ben descritto il mio piccolo progetto riguarda la costruzione di una lampada ad RGB che per ora si dovrebbe basare sulla duplice funzionalità "automatico" "manuale". Quest'ultima chiamata "gioco()" (l'automatica invece "gioco1()") non riesco proprio ad avviarla. Come si può ben notare dal codice ho voluto strutturare il tutto con uno switch dove al caso "0" corrisponde la versione manuale (con potenziometro) e al caso "1" corrisponde la versione automatica. Bene Primo problema non riesco a passare dalla versione in automatico a quella manuale al variare dello stato di un bottone e viceversa. Sapete aiutarmi.C'è qualcosa o forse anche tutto di sbagliato in quello che scrivo.
Ecco il codice:
Code: [Select]
int redpin=11;
int greenpin=9;
int blupin=10;
int potenziometro=0;
int lettura=0;
int gruppo;
int luminosita;
int bottone=7;
int stato=0;
int prestato=0;
int contatore=0;

void setup (){
pinMode(redpin,OUTPUT);
pinMode(greenpin,OUTPUT);
pinMode(blupin, OUTPUT);
analogReference(DEFAULT);
pinMode(bottone, INPUT);
Serial.begin(9600);
}
void loop(){
stato= digitalRead(bottone);

if (stato != prestato){
  if (stato == HIGH){
    delay(1
    00);
  contatore++;
  Serial.println(contatore);
  switch (contatore){
  case 1:
  gioco();
  break;
  case 2:
  gioco1();
  break;
}
}
}
prestato=stato;
}

void gioco(){
lettura= analogRead(potenziometro);

Serial.println(lettura);
gruppo=(lettura & 768)/256;
luminosita = (lettura & 255);

switch (gruppo){
case 0:
analogWrite(greenpin, luminosita);
analogWrite(redpin, luminosita);
analogWrite(blupin, luminosita);
break;
case 1:
analogWrite(greenpin, 255-luminosita);
analogWrite(blupin, luminosita);
analogWrite(redpin, 0);
break;
case 2:
analogWrite(blupin, 255-luminosita);
analogWrite(redpin, luminosita);
analogWrite(greenpin, 0);
break;
case 3:
analogWrite(redpin, 255-luminosita);
analogWrite(greenpin, luminosita);
analogWrite(blupin, 0);
break;
delay(10);
}
}
void gioco1(){

  for (int L=0; L<255; L++){
  analogWrite(greenpin, L);
  delay(50);
  }
  for(int L=0; L<255; L++){
  analogWrite(greenpin, 255-L);
  analogWrite(redpin, L);
  delay(50);
  }
  for(int L=0; L<255; L++){
  analogWrite(redpin, 255-L);
  analogWrite(blupin, L);
  delay(50);
  }
  for(int L=0; L<255; L++){
  analogWrite(blupin, 255-L);
  delay(50);
  }
  }

Grazie in Anticipo per l'aiuto e la disponibilità!

nid69ita

#1
Aug 23, 2013, 01:58 pm Last Edit: Aug 23, 2013, 02:10 pm by nid69ita Reason: 1
1. quando il programma sta eseguendo gioco() o gioco1() non sente niente altro e tu li dentro hai dei vari delay().

2. non mi pare giusta la logica del codice della loop(). La riposto indentandola correttamente.
Code: [Select]
void loop(){
 stato= digitalRead(bottone);
 if (stato != prestato)
 { if (stato == HIGH)
   { delay(100);
     contatore++;
     Serial.println(contatore);
     switch (contatore)
     { case 1: gioco();  break;
       case 2: gioco1(); break;
     }
   }
 }
 prestato=stato;
}


Prova a fare una tabella della verità. Scriviti su un foglio stato, prestato e contatore. Poi fai finta di essere arduino e prova a girare nel programma e calcolare i valori delle 3 variabili nel tempo.

Le 3 variabili partono da 0 perciò quando il tuo programma parte, sei in modalità manuale, giusto?
Poi premi il pulsante e passi a quella automatica. A questo punto contatore vale 2.
Se ripremi il pulsante (ed arduino riesce a sentirlo perchè in automatico Arduino è impegnato dentro a gioco1() ) allora contatore vale 3
ti manca, dopo contatore++;  un controllo del tipo se contatore>2 allora contatore=1

Ma poi quando sei a contatore 1 o 2 lo switch() non devi sempre farlo comunque? Allora lo switch() va fuori da quell'if (secondo me)

Code: [Select]
void loop(){
 stato=digitalRead(bottone);
 if (stato != prestato)
 { if (stato == HIGH)
   { delay(100);
     contatore++;
     Serial.println(contatore);
   }  
 }
 prestato=stato;
 switch(contatore)
 { case 1: gioco();  break;
   case 2: gioco1(); break;
  }
}


P.S. i valori dei pin li puoi mettere const e di tipo byte  ->             const byte redpin=11;
my name is IGOR, not AIGOR

skizzo942

Grazie davvero molto esauriente e chiaro!Grazie mille!!!
Solo una cosa rimane un problema Come faccio a far sentire ad arduino in qualunque momento anche quando sta eseguendo gioco() o gioco1() che il contatore è cambiato e quindi passare all'altra modalità?cioè si dovrà per esempio interrompere la versione automatica quando si pigia il bottone per farlo passare in manuale?

nid69ita

#3
Aug 23, 2013, 02:39 pm Last Edit: Aug 23, 2013, 02:44 pm by nid69ita Reason: 1
Bel casino. Per gioco() teoricamente non dovresti avere grossi problemi perchè non sembra bloccante.
Il problema è gioco1() che ha 4 cicli da 0-255 con delay(50).   4*50*256=51200 -> 5,12 secondi mi pare più il tempo delle istruzioi Arduino (anche quelle impiegano tempo).
Tecniche c'è ne sono molte. Usare varibili di stato, evitare la delay() e usare millis(), interrupt, etc.
Non molto semplice.

Inizia a vedere l'esempio di BlinkWithoutDelay.

Poi con gli Interrupt puoi sentire in ogni momento se il bottone viene premuto, ma la tecnica non è semplice
http://www.gammon.com.au/forum/?id=11488
my name is IGOR, not AIGOR

skizzo942

va bene grazie del grande aiuto mi limiterò a questo per ora :) gentilissimo!!!!! :) :) :) :) :)

paulus1969

Oppure, se vuoi una cosa molto più semplice... al posto del pulsante metti un interruttore ed avrai le due posizioni "AUTO" e "MAN", una porta il pin HI, l'altra porta il pin LOW.
A questo punto nel loop basta vedere se è HI o LOW.
Con questo sistema, dovrai attendere quei 5 secondi di cui ti dissero sopra prima di vedere la commutazione che avverrà a fine ciclo. Però è molto più semplice.
EDIT: Non è detto. Potresti anche non dovere attendere i 5 secondi, basta mettere una verifica nei cicli FOR e casomai tornare al loop!!!!

skizzo942

intendi 2 bottoni con uno l'automatico e con l'altro il manuale?

paulus1969

Intendo un interruttore, quelli ON-OFF.
L'interruttore ha due posizioni (Aperto e Chiuso), una sarà "Modalità AUTO" e l'altra "Modalità MAN". A seconda di come lo colleghi, il PIN a cui è connesso sarà HI oppure LOW quando l'interruttore è aperto o chiuso.
Se attivi il pullup interno e metti l'interruttore verso GND avrai HI quando è aperto e LOW quando è chiuso, se metti l'interruttore verso +5 V ed un resistore di pulldown dal pin a GND allora avrai LOW quando è aperto ed HI quando è chiuso. Ma questo credo che tu lo sappia già.
A questo punto ti basta vedere lo stato del pin a cui hai connesso l'interruttore per sapere se devi agire in modalità auto o in modalità man. Puoi mettere la verifica anche in diversi punti del programma, oltre che nel loop principale, se vuoi una risposta più o meno immediata puoi mettere la verifica anche all'interno dei cicli FOR ed avrai una commutazione di modalità in 50 ms quindi neanche te ne accorgi.


skizzo942

eccomi di nuovo da voi ragazzi! Volevo un attimo precisare che utilizzo lo switch proprio perchè ho in mente di costruire una lampada che abbia non solo automatico e manuale ma anche altre modalità di accensione dei led tipo luci da albero di natale. Detto questo Son un tipo abbastanza testardo quindi vorrei a tutti i costi capire per bene come funziona questo "INTERRUPT" che a dire il vero mi rende molto ma molto curioso. Ho cercato di riscrivere il codice immettendo questo interrupt con le giuste regole con le quali si deve far funzionare un interrupt. Ho verificato che al mio Arduino Leonardo il pin 7 corrisponde all'interrupt "4". Ho seguito una guida(http://www.maffucci.it/2012/06/11/appunti-su-arduino-interrupts/). e ho scritto di seguito. Il problema persiste: considerando la funzione "attachInterrupt(interrupt,funzione,modo)" non riesco a capire quale dei 4 modi possibili     (LOW l'interrupt viene eseguito quando il livello del segnale è basso CHANGE l'interrupt viene eseguito quando avviene un cambiamento di stato sul pin RISING l'interrupt viene eseguito quando si passa da un livello LOW ad un livello HIGH FALLING l'interrupt viene eseguito quando si passa da un livello HIGH ad un livello LOW)         devo usare nel mio caso e come arduino capisca che effetivamente sul quel pin si è avuto un FALLING o un CHANGE o se glielo devo far capire io???come?? Per quanto riguarda la funzione chiamata "funzionebottone" ho cercato di indicare che ogni volta che si pigia il tasto la variabile "stato" debba passare da LOW ad HIGH oppure se già HIGH a LOW. e quindi poi tutto il resto com'era...[premetto che il codice così scritto si comporta cosi: collego arduino appena pronto inizio a menaggiare il potenziometro e cambia tonalià, pigio il bottone e passa in modalità automatica, pigio un'altra volta e rimane sempre e comunque in automatico]
Code: [Select]

int redpin=11;
int greenpin=9;
int blupin=10;


volatile int stato= LOW;

int contatore=0;



void setup (){
pinMode(redpin,OUTPUT);
pinMode(greenpin,OUTPUT);
pinMode(blupin, OUTPUT);
analogReference(DEFAULT);

attachInterrupt(4,funzionebottone, CHANGE);



Serial.begin(9600);
}
void funzionebottone(){
if( stato == LOW){ stato = HIGH;}else{stato = LOW;}
}
void loop(){
if (stato == HIGH)
    {
      contatore++;
      if (contatore>1){contatore = 0;}
      Serial.println(contatore);
    }
switch(contatore)
  {
    case 0: gioco();  break;
    case 1: gioco1(); break;
  }
}


void gioco(){
delay(100);  //manuale//
int potenziometro=0;
int lettura=0;
int gruppo;
int luminosita;
lettura= analogRead(potenziometro);

gruppo=(lettura & 768)/256;
luminosita = (lettura & 255);

switch (gruppo){
case 0:
analogWrite(greenpin, luminosita);
analogWrite(redpin, luminosita);
analogWrite(blupin, luminosita);
break;
case 1:
analogWrite(greenpin, 255-luminosita);
analogWrite(blupin, luminosita);
analogWrite(redpin, 0);
break;
case 2:
analogWrite(blupin, 255-luminosita);
analogWrite(redpin, luminosita);
analogWrite(greenpin, 0);
break;
case 3:
analogWrite(redpin, 255-luminosita);
analogWrite(greenpin, luminosita);
analogWrite(blupin, 0);
break;
delay(10);
}
}

void gioco1(){ 
delay(100);  //AUTOMATICO//
 

  for (int L=0; L<255; L++){
  analogWrite(greenpin, L);
  delay(50);
   
  }
  for(int L=0; L<255; L++){
  analogWrite(greenpin, 255-L);
  analogWrite(redpin, L);
  delay(50);
 
  }
  for(int L=0; L<255; L++){
  analogWrite(redpin, 255-L);
  analogWrite(blupin, L);
  delay(50);
 
  }
  for(int L=0; L<255; L++){
  analogWrite(blupin, 255-L);
  delay(50);
 
  }
  }
 




Perfavore voi che ne sapete più di me datemi una mano!!!!Grazie Ragazzi!!!!:) :) :) :)

leo72

1) per poter leggere un cambio di stato di un pin, devi dargli tu uno stato predefinito, questo si fa con una resistenza di pull-up o pull-down. Ad esempio, se vuoi leggere un cambio di tipo FALLING, gli dai uno stato HIGH con una pull-up così che quando il pin va LOW l'interrupt venga sollevato
2) in linea di massima è sbagliato usare un interrupt per leggere un pulsante perché leggerai decine (anche centinaia) di impulsi su quel pin per via dei rimbalzi elettrici del contatto stesso del pulsante. E non puoi usare un debounce software perché in un interrupt non puoi farlo.

Go Up