Go Down

Topic: uscita immediata da un loop o un ciclo (Read 11087 times) previous topic - next topic

matt-korban

ciao ragazzi... ci sto provando già da un po' ma non riesco a risolvere il problema... vi spiego riassumendo:

il mio programma deve riprodurre una melodia da suspance (quella di fringe :) e fino a quì tutto ok... il punto è che la melodia dura un po', quindi prima che finisca passano alcuni secondi, durante i quali il programma rimane bloccato...

quello che vorrei fare è fermare immediatamente la riproduzione dela melodia al cambio di stato di un pulsante... come cappero faccio? cioè mentre la melodia suona, non riesco a leggere il cambio di stato del pulsante, e quindi non riesco a far "accendere il mio ipotetico led", se non alla fine della stessa... qualche idea? ho provato con while, e for, ma niente...

Code: [Select]

#include "pitches.h"

int ledRosso = 4;
int ledBlu = 5;
int pulsanteRosso = 2;
int pulsanteBlu = 3;
int sirena = 6;
int statoRosso = 0;
int statoBlu = 0;
int melody[] = {
  NOTE_C4, NOTE_G3,NOTE_G3, NOTE_A3, NOTE_G3,0, NOTE_B3, NOTE_C4};
int noteDurations[] = {
  4, 8, 8, 4,4,4,4,4 };




void setup(){
  pinMode (ledRosso, OUTPUT);
  pinMode (ledBlu, OUTPUT);
  pinMode (pulsanteRosso, INPUT);
  pinMode (pulsanteBlu, INPUT);
  pinMode (sirena, OUTPUT);
}



void loop() {
  statoRosso=digitalRead(pulsanteRosso);
  if (statoRosso==HIGH){
    digitalWrite(ledRosso, HIGH);
    for (int i=0; i<=5; i++){
    noTone(sirena);
    tone(sirena, 880, 200);
    delay(50);
    noTone(sirena);
    tone(sirena, 1000, 200);
    delay(50);
    noTone(sirena); 
    tone(sirena, 1400, 200);
    delay(50);
    }
    delay(1000);
    digitalWrite(ledRosso, LOW);
  }
  else if(statoRosso==LOW){
    melodia();
  }
}

void melodia(){
  for (int thisNote = 0; thisNote < 8; thisNote++) {

    // to calculate the note duration, take one second
    // divided by the note type.
    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
    int noteDuration = 1000/noteDurations[thisNote];
    tone(sirena, melody[thisNote],noteDuration);

    // to distinguish the notes, set a minimum time between them.
    // the note's duration + 30% seems to work well:
    int pauseBetweenNotes = noteDuration * 1.30;
    delay(pauseBetweenNotes);
    // stop the tone playing:
    noTone(sirena);
  }
}

Janos

Utilizza millis() invece dei delay()...

matt-korban

fatto... non funziona comunque... grazie lo stesso :)
qualche idea del perchè non funzioni?

pablos71

#3
Mar 21, 2013, 02:56 pm Last Edit: Mar 21, 2013, 02:59 pm by pablos Reason: 1

Utilizza millis() invece dei delay()...


cosa centra il delay con l'intercettare un evento durante il ciclo?

Prendi un pin che abbia l'interrupt, lo attivi, questo resterà in attesa di un cambio anche durante l'esecuzione di una funzione diversa dal loop.  

http://gonium.net/md/2006/12/20/handling-external-interrupts-with-arduino/
L'esperienza è il tipo di insegnante più difficile ....
Prima ti fa l'esame e poi ti spiega la lezione.

Janos

@Pablos
C'entra eccome. Il micro si blocca, fa esattamente quello che gli dici di fare. Il problema è: perché non riesci a leggere lo stato di un pin? Probabilmente perché sei bloccato dentro un delay a non fare niente, ovvero il micro sta li ad aspettare per un secondo.

@matt
Allora perché dentro il loop vedo alcuni delay(50) e un bel delay(1000)?

matt-korban

@janos

be, quello li sopra è sempre il vecchio codice... ho fatto la prova che mi hai detto e ho cambiato tutti i delay con i millis, ma non funziona...
ma poi scusa, millis non inizia a contare da quando la scheda inizia ad eseguire il programma? a me non serve quello, mi servono i delay per creare quel tipo di suono che voglio io... grazie dell'interessamento comunque! :)

matt-korban

@Pablos
ho visto il link che mi hai mandato, sembra buono... mi da un errore il codice che ha postato il tipo però... ho anche aggiunto la libreria che mi dice di aggiungere, ma non mi riconosce    GICR |= ( 1 < < INT0);   
forse perchè lui usa un atmega8... bo...

Janos

Mica li devi sostituire e basta... Sennò quale sarebbe la differenza?
Vedo di buttare giù una bozza, poi la smussi te...

Janos

#8
Mar 21, 2013, 04:02 pm Last Edit: Mar 21, 2013, 04:08 pm by Janos Reason: 1
Ti consiglio di leggere qui: http://arduino.cc/en/Tutorial/BlinkWithoutDelay

Scusami se il codice è diventato "largo" ma mi sta troppo sulle scatole che il programma di Arduino usi due spazi per le indentazioni, quindi ne uso uno esterno per scrivere il codice e uso i TAB, ma quando incolli il codice qui poi è un macello.... Ti consiglio di installarti Notepad++ (è gratuito) e incollare li il codice.

Code: [Select]
#include "pitches.h"

int ledRosso = 4;
int ledBlu = 5;
int pulsanteRosso = 2;
int pulsanteBlu = 3;
int sirena = 6;
int statoRosso = 0;
int statoBlu = 0;
int melody[] = {
NOTE_C4, NOTE_G3,NOTE_G3, NOTE_A3, NOTE_G3,0, NOTE_B3, NOTE_C4};
int noteDurations[] = {
4, 8, 8, 4,4,4,4,4 };




void setup(){
pinMode (ledRosso, OUTPUT);
pinMode (ledBlu, OUTPUT);
pinMode (pulsanteRosso, INPUT);
pinMode (pulsanteBlu, INPUT);
pinMode (sirena, OUTPUT);
}


unsigned long int inizioTimer;
byte stato;
bool toneImpostato;
byte contatore;
bool fineCiclo;

void loop() {
statoRosso=digitalRead(pulsanteRosso);
if (statoRosso==HIGH){
if (!fineCiclo) {
digitalWrite(ledRosso, HIGH);
if (contatore < 5) {
switch (stato) {
case 0:
if (!toneImpostato) {
tone(sirena, 880, 200);
toneImpostato = true;
inizioTimer = millis();
};
if (millis() - inizioTimer >= 50) {
stato++;
toneImpostato = false;
};
break;

case 1;
if (!toneImpostato) {
tone(sirena, 1000, 200);
toneImpostato = true;
inizioTimer = millis();
};
if (millis() - inizioTimer >= 50) {
stato++;
toneImpostato = false;
};
break;

case 2:
if (!toneImpostato) {
tone(sirena, 1400, 200);
toneImpostato = true;
inizioTimer = millis();
};
if (millis() - inizioTimer >= 50) {
stato = 0;
contatore++;
toneImpostato = false;
};
break;

default:
stato = 0;
contatore = 0;
toneImpostato = false;
break;

}
}
else {
if (!toneImpostato) { //Ho riciclato una variabile che in questa parte del codice non serve
inizioTimer = millis(); //Qui ne ho riciclata un'altra
toneImpostato = true;
}
if (toneImpostato && (millis() - inizioTimer >= 1000)) {
digitalWrite(ledRosso, LOW);
fineCiclo = true;
};
};
}
//Se non metti questa riga lui ti esegue a diritto
//Così invece fa un ciclo e prima di fare il successivo aspetta che tu alzi il tasto
else (!digitalWrite(ledRosso, HIGH)) fineCiclo = false; //Se non metti questa riga lui ti esegue a diritto
}
else {
melodia();
}
}

void melodia(){
 for (int thisNote = 0; thisNote < 8; thisNote++) {

   // to calculate the note duration, take one second
   // divided by the note type.
   //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
   int noteDuration = 1000/noteDurations[thisNote];
   tone(sirena, melody[thisNote],noteDuration);

   // to distinguish the notes, set a minimum time between them.
   // the note's duration + 30% seems to work well:
   int pauseBetweenNotes = noteDuration * 1.30;
   delay(pauseBetweenNotes);
   // stop the tone playing:
   noTone(sirena);
 }
}

pablos71

non centra perchè lui è dentro a una funzione quando ha bisogno di leggere la pressione del bottone che impegna il suo tempo, non ha  mica un delay da 10 minuti

loop()

Vai alla funzione 1()
Vai alla funzione 2()
Vai alla funzione 3()
Vai alla funzione 4()
leggi il pulsante

il pulsante lo legge solo quando ha terminato le 4 funzioni, ci vuole qualcosa che intercetti il pulsante interrompendo per un istante tutto quello che il micro sta facendo, questo lo fa solo attivando un interrupt
L'esperienza è il tipo di insegnante più difficile ....
Prima ti fa l'esame e poi ti spiega la lezione.

Janos

#10
Mar 21, 2013, 04:14 pm Last Edit: Mar 21, 2013, 04:24 pm by Janos Reason: 1
P.S. Per usare gli interrupt leggi qui:
http://arduino.cc/en/Reference/AttachInterrupt
http://arduino.cc/en/Reference/DetachInterrupt

@Pablos
Prima di dare suggerimenti agli altri ti consiglio di approfondire tu stesso le tue conoscenze in materia, visto che non sai la differenza fra delay() e millis() e che suggerisci improbabili esempi sulla gestione degli interrupt quando ci sono le apposite funzioni... Inoltre qui, anche usando l'interrupt, se sei bloccato in un dealy non ne esci.
P.S. Leggi per bene il mio codice e poi parla... Inoltre consiglio anche a te di leggere http://arduino.cc/en/Tutorial/BlinkWithoutDelay

pablos71

Si janos vado a studiare, intanto tu fagli usare un millis() per 50ms
L'esperienza è il tipo di insegnante più difficile ....
Prima ti fa l'esame e poi ti spiega la lezione.

Janos

Per te sono un'inezia 50ms ma nella realtà dell'elettronica 50ms sono un tempo abissale. Pensa che il processore esegue un'istruzione ogni 62ns, quindi con un delay(50) fai stare fermo il processore per ben 806.000 operazioni. Inoltre quello che conta di più è imparare il metodo, quando sai come usarlo poi decidi tu se e quando usarlo...

Madwriter


Si janos vado a studiare, intanto tu fagli usare un millis() per 50ms

ai fini pratici ha ragione pablos ai fini teorici ha ragione janos  :smiley-mr-green: ora non litigate o vi mando al quizzettone  ;)
"Due cose sono infinite: l'universo e la stupidità umana, ma riguardo l'universo ho ancora dei dubbi..." Albert Einstein

lestofante

#14
Mar 21, 2013, 04:38 pm Last Edit: Mar 21, 2013, 04:40 pm by lesto Reason: 1
ehm i delay NON bloccano gli interrupt, altrimentio non usciresti mai dalla delay visto che è basata su un interrupt del timer1 :)
Quote
Si janos vado a studiare, intanto tu fagli usare un millis() per 50ms

Quote
Per te sono un'inezia 50ms ma nella realtà dell'elettronica 50ms


ma un pulsante premuto (da un essere umano) per meno di 50ms è abbastanza impossibile nella realtà..

Il problema è che quei delay(50) sono in loop e seguiti anche da delay(1000), il che rende il tempo della funzione troppo alto.

Io sono d'accordo con janos di usare la millis() come per l'esempio blinkWithoutDelay;
in particolare , mio caro matt-korban, se non lo fai, finchè l'arduino suona NON legge i pulsanti.

il sistema consigliato da pablos non è errato, ma un'alternativa assai valida: l'uso della millis costringe a riscirvere buona parte del codice, con memorizzazione dello stato tra un loop e l'altro (macchina a stati), e permette di interrompere a metà l'esecuzione di una canzoncina per effettuarne un altra.
l'interrupt permette di sostituire la digitalRead con una variabile booleana settata dall'interrupt e azzerata dopo il suo uso nel loop(l'interrupt conterrà al suo interno un algoritmo anti-bounce, o un anti-bounce HardWare), ma essa non verrà usata finchè il loop corrente è finito, quindi la canzincina deve finire.

kiss
Guida per principianti http://playground.arduino.cc/Italiano/newbie
Unoffical Telegram group https://t.me/genuino

Go Up