Ciao ragazzi,
ho ripreso in mano il progetto che avevo iniziato per generare un impulso ritardato rispetto il fronte del segnale d'ingresso (ard UNO).
Vorrei invece che tirare su un output qualsiasi quando il timer1 arriva a OCR1A con il valore di TCNT1, si alzi direttamente l'uscita collegata a quel timer, tipo il pin 9.
Allora ho scritto questo codice ma non funziona come vorrei.
Quello che succede è che sul fronte di discesa del segnale d'ingresso mi si alza l'uscita 9 con durata (500us=1000*0.5, con prescaler=8).
Io vorrei invece che dopo 500us che ho avuto il fronte mi si alza l'uscita.
Molto semplicemente sul fronte di discesa del segnale di ingresso (o di salita non importa) vorrei che dopo per es. 500us grazie al CTC del timer1 mi andasse alta l'uscita collegata (PD9) e che poi spengo io quando voglio.
Lo sketch che ho messo per ultimo è una cosa simile a quella che vorrei e che ho trovato in rete. Se si riesce a far funzionare anche quello può andare bene. Lui sfrutta Input capture e io invece uso attachInterrupt.
A me serve valutare i tempi di risposta dei metodi, sarebbe bello provarli entrambi.
Se agganci un'uscita ad un timer, è il timer che poi pilota quel pin.
Io capisco che tu hai questo ambiente:
un pin collegato ad un segnale
un pin collegato ad un led
quando ti arriva il segnale sul pin 1), devi accendere il led sul pin 2) dopo 500 us
Giusto?
Perché allora non fare semplicemente che nella ISR di intercettazione del segnale sul pin 1) fai allora partire il timer (TCNT1 = 0), agganciando il pin 9, programmato per tirare su l'uscita dopo 500 us? Agganci poi un'altra ISR ad esempio sul matching con OCR1A e dentro quella ISR scolleghi il timer dal pin.
Guarda il primo codice che ho postato è proprio così che va.
Cioè, arriva il segnale sul pin 2, sul fronte di discesa chiama la SensorINPUT() routine e li dentro faccio partire il timer1 e aggancio il pin 9 (uscita).
Il timer è configurato in CTC nel setup.
Quando finisce di contare mi chiama la sua routine dove azzero TCCR1A , cioè scollego il pin di uscita.
Il problema è che invece di mandare alto il pin 9 dopo 500us, lo manda alto subito (sul fronte di discesa di pin2) e dopo 500us lo tira giu.
Questo è il problema. Spero sia più chiaro ora.
Fammi sapere.
Grazie
Ovviamente utilizzavo l'uscita 4 che poi nel loop abbassavo quando volevo.
Ora vorrei solamente che il timer alzasse la sua uscita che è la 9 in modo da risparmiare tempo.
Ekjk, ho mangiato, sono andato a riprendere i figlioli a scuola, li ho fatti pranzare, poi mi sono riposato ed ho dato un'occhiata ad altre cose mie (che sono dei grossi cosi nel posteriore....)
Ho dato dei suggerimenti, sinceramente non mi sono messo ad analizzare né il problema né cosa facevano i tuoi sketch...
Sorry
Insomma, se è una questione di vita o di morte, gli darò un'occhiata
azzero TCCR1A , cioè scollego il pin di uscita.
Per scollegare un pin, basta metterlo in input. Il timer continua a girare ma lo stato non viene più cambiato.
Prova con questo codice. Non ho controllato la corrispondenza di alcuni setup, ho preso per buono ciò che era scritto nei commenti del tuo 1° sketch.
void setup() {
setTimer1(); //set the timer 1
attachInterrupt(0, SensorINPUT, FALLING);
DDRB &= ~(1 << PB1); //pin D9 as input
}
void loop() {
}
// initialize Timer1
void setTimer1() {
SREG &= ~(1 << SREG_I); // disable global interrupts
// set compare match register to desired timer count:
// turn on CTC mode:
TCCR1A = ((1<<COM1A1) | (1<<COM1A0));
TCCR1B = (1 << WGM12);
TCCR1B &= ~((1 << WGM10) | (1 << WGM11));
SREG |= (1 << SREG_I);// enable global interrupts:
}
void SensorINPUT() {
TCCR1B &= ~(1 << CS11); //stop the timer
TCNT1 = 0; //reset the timer counter
OCR1A=1000; //set OCR1A
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
TCCR1B |= (1 << CS11); //restart the timer
DDRB |= (1 << PB1); //set D9 as output
}
//Interrupt Service Routine called on OCR1A COMPARE MATCH
ISR(TIMER1_COMPA_vect) {
TCCR1B &= ~(1 << CS11); //stop the timer
TIMSK1 &= ~(1 << OCIE1A); //disable interrupt
}
Avviato il programma, esso setta il timer 1 per funziona così com'era nello sketch iniziale, ma non fa partire il timer (non gli dà il clock). Poi attacca l'interrupt al pin 2. Quando arriva il segnale, resetto sia il contatore del timer che imposto a 1000 OCR1A (ritolgo il clock al timer perché si presuppone che esso possa stare girando, se viene chiamata un'altra volta l'ISR prima che venga chiamata la ISR "TIMER1_COMPA") e metto il pin D9 in output. Quando TCNT1 raggiunge il valore di OCR1A il timer dovrebbe settare in automatico il pin (ma ricontrolla le impostazioni in setTimer1 perché non le ho controllate, che venga messo su High il pin) dato che è stato precedentemente agganciato fisicamente al timer. Poi viene chiamata la corrispondente ISR che provvede a disattivare il segnale di interrupt ed a fermare il timer togliendogli il clock.
Ricopia il codice ora, avevo commesso 2 errori nella sua scrittura di cui non mi ero accorto.
Ah, ovviamente non so se funziona oppure no, non l'ho provato
Leo non funziona.
Praticamente mi da una uscita instabile che si alterna al segnale d'ingresso in maniera complementare.
Se invece aggiungo TCCR1A=0 nella ISR compare allora ritorno al mio caso: uscita 9 che va su sul fronte di discesa di pin2 con durata 500us e poi va bassa.
Io sono convinto che la prima volta che entra nella ISR compare lui manda su l'uscita e poi ricomincia a contare tipo downcounting e quando arriva a 0 mette a 0 l'uscita......helppP!
void setup() {
setTimer1(); //set the timer 1
attachInterrupt(0, SensorINPUT, FALLING);
DDRB &= ~(1 << PB1); //pin D9 as input
}
void loop() {
}
// initialize Timer1
void setTimer1() {
SREG &= ~(1 << SREG_I); // disable global interrupts
// set compare match register to desired timer count:
// turn on CTC mode:
TCCR1A = 0; //disconnect outputs
TCCR1B = (1 << WGM12);
TCCR1B &= ~((1 << WGM10) | (1 << WGM11));
SREG |= (1 << SREG_I);// enable global interrupts:
}
void SensorINPUT() {
TCCR1B &= ~(1 << CS11); //stop the timer
TCNT1 = 0; //reset the timer counter
OCR1A=1000; //set OCR1A
TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
TCCR1A = ((1<<COM1A1) | (1<<COM1A0)); //set OCR1A on compare
TCCR1B |= (1 << CS11); //restart the timer
DDRB |= (1 << PB1); //set D9 as output
PORTB &= ~(1 << PB1)); //low on output
}
//Interrupt Service Routine called on OCR1A COMPARE MATCH
ISR(TIMER1_COMPA_vect) {
TCCR1A = 0; //disconnect the timer
TCCR1B &= ~(1 << CS11); //stop the timer
TIMSK1 &= ~(1 << OCIE1A); //disable interrupt
}
E' simile al precedente, solo che ho aggiunto l'azzeramento di TCCR1A dentro alla ISR ed in più ho messo l'impostazione del pin D9 a LOW nel momento in cui scatta l'interrupt. A questo punto, dovrebbe contare 500 us e poi alzare il pin D9 (lo fa il timer in automatico).
Se anche così non va, si prova una strada molto più semplice, manipolando direttamente il pin in entrambi i cambi di stato.
Ciao Leo,
non ho ancora provato l'ultima soluzione, e nel frattempo ho contattato un tizio americano che ne sa su i timer e che mi aiuto a fare un push pull pwm con il timer 2, quando nessuno diceva che era possibile farlo.
Lui mi ha spiegato come farebbe per il mio problema, ma ha detto che non mi aiuta a meno che non lo paghi $)
Questo è ciò che mi ha scritto,
I think you can do that with a single timer, but it requires two interrupt handlers:
External event triggers “Handler A” to start the timer and possibly set the output bit
Timer triggers “Handler B” at end of pulse to stop the timer and reset for next external event
You (almost certainly) want phase-and-frequency-correct PWM mode, not CTC mode, for this function, so that you can set the delay and width. The timers normally run continuously, so you must manually preset, start, and stop the timers to get the result you want.
The trick is to preload the TCNT register with the delay value relative to the TOP value in ICR. When the external event starts the timer (through Handler A), it counts upward during the initial delay time. When it hits TOP, the COM configuration sets the output bit and the timer counts downward toward BOTTOM (0×0000) during the pulse width. You’ve set the TOP value in ICR so that the delay from TOP to BOTTOM determines the pulse width. When TCNT hits BOTTOM, it clears the output bit and triggers Handler B, which stops the timer and prepares everything for the next external pulse.
Te ne intendi di phase and frequency correct pwm? io no...
No, anzi non sei da meno (se non ti fai pagare perchè fai più bella figura :D)
Da quello che lui descrive vorrei capire come intercettare tramite la routine ISR(TIMER1_compa_vect) quando il TCNT1 è downcounting da TOP a BOTTOM invece che viceversa.
Perchè, penso che tale isr venga lanciata ogni volta che TCNT eguaglia OCR1A, quindi esiste un flag che mi dice che il contatore ha raggiunto lo 0? Cioè da TOP (ICR1) a BOTTOM (0).
Lui sta descrivendo una situazione differente rispetto a quella che avevi descritto tu inizialmente.
Tu dicevi che usai un segnale per attivare il timer che usavi per far portare alto un pin dopo un certo lasso di tempo e che poi era cura del codice principale rimettere basso questo pin.
Lui invece ti descrive una situazione in cui fai partire il timer, questo poi mette alto il pin raggiunto TOP e dopo tiene il pin alto finché non arriva a BOTTOM, quando lo rimette basso.