Tachimetro auto (ex computer di bordo)

Francesco Sacchi ha scritto:

Io ho disabilitato il pull-up sia per gli ingressi che per le uscite, così sono sicuro che c'è 0 di default su ogni linea. Se in ingresso ho

5V il micro leggerà 1 logico, se ci sono 0V leggerà 0 logico. Lo stesso vale per le uscite.

Ho sperimentato questo con il convertitore buck che utilizza il diodo di ricircolo per evitare che sul transistore in parallelo all'induttore vadano spikes di extratensione. Risultato: cambia il duty cycle (l'ho anche simulato).

Provare per credere.

A presto

Artemis

PS: Ora il problema più ingente è che devo gestire i 3 timer counter:

1) Misure iniettore 2) Misura velocità 3) Misura 1 secondo per il refresh

il micro ha solo 2 timer counter... che sfiga! Se usi normali external interrupt comunque devo sempre attivare un timer per la misura. Dite che dovrei inserire un qualche oscillatore esterno su qualche pin a frequenza 1 Hz che mi attiva l'interrupt? Magari con un monostabile...

Reply to
Artemis
Loading thread data ...

Il giorno Tue, 17 Jul 2007 18:59:25 +0200, Artemis ha scritto:

AtMega8535 ha 3 TIMERS

Non ti sei letto il datasheet. Riposto:

formatting link

pag 71 e seguenti

8-bit Timer/Counter0 with PWM

16-bit Timer/Counter1

8-bit Timer/Counter2 with PWM and Asynchronous Operation

Si potrebbe probabilmente fare tutto anche con solo 2 timers usando la differenza tra le letture fatte con un ingresso INT, ma hai 3 timers a disposizione.

-- ciao Stefano

Reply to
SB

SB ha scritto:

Cacchio mi sono fidato del posto (non ricordo di chi) dove c'era scritto che di timer ce n'erano 2. Grazie 1000 SB!

Interessante! Mi dici come però?

Reply to
Artemis

Il giorno Tue, 17 Jul 2007 20:08:20 +0200, Artemis ha scritto:

Quando si vuole usare un µC bisogna leggere attentamente il datasheet per poter sfruttare a fondo tutte le risorse.

Facendo due letture successive del timer free running con l' INTe poi la loro differenza.

-- ciao Stefano

Reply to
SB

SB ha scritto:

Ah ecco, quello che sto facendo per calcolare la velocità. La cosa però che ancora non riesco a fare è utilizzare l'interrupt capture del timer1. Voglio che quando vi sia una variazione di uno stato logico sollevi un int e da lì attivi il timer. Quando vi è un'altra variazione si fermi. Ma non riesco ancora ad utilizzarlo, devo finire il progetto (software) assolutamente entro oggi.

Un'informazione: ma il display, se imposto il carattere da scrivere, l'indirizzo e tutto, con un segnale di enable di 1 ciclo di clock riesce a scrivere? Il clock è a 3.69 MHz, quindi 271 ns.

A presto

Artemis

Reply to
Artemis

Il giorno Wed, 18 Jul 2007 10:08:58 +0200, Artemis ha scritto:

L' Input Capture Unit mette in ICRH - ICRL il valore del timer quando hai una variazione del trigger, non può attivare il timer. Invece dopo setta un flag inTIFR, il Bit 5 - ICF1: Timer/Counter1 Input Capture Flag -, che puoi anche usare come sorgente di un interrupt per leggere successivamente il valore in ICRH - ICRL, memorizzare la lettura e sul successivo fronte fare la differenza.

Se il controller del display è il classico HD44780 compatibile direi di si, in ogni caso puoi inserire dei NOP per aumentare le temporizzazioni.

-- ciao Stefano

Reply to
SB

SB ha scritto:

Sono riuscito ad attivare l'input capture (con un fronte) e il programma mi salta correttamente nella routine dell'iniettore (e copia il valore del timer in ICR1H-ICR1L, ma è 0). Qui faccio partire il timer, che conta correttamente, dunque mi aspetto al successivo interrupt dell'input capture il valore del timer corretto mi venga copiato in ICR1H-ICR1L... ma ciò non avviene. Il valore del TCNT1H-TCNT1L è diverso da 0, ma ICR1H-ICR1L rimane a 0 per tutte le istruzioni successive. Non è normale...

Si il controller è questo qui. Volevo saperlo per evitare di mettere nop e allungare il programma, visto che per ogni carattere ci sono una sfilza di operazioni che ho racchiuso in una call, e gli passo l'indirizzo e il carattere nei registri ax e bx (che sono poi r16 ed r18).

Ciao

Artemis

Reply to
Artemis

Il giorno Wed, 18 Jul 2007 12:16:58 +0200, Artemis ha scritto:

Usi correttemente il pin Input Capture (ICP1) ? Hai programmato correttemente l'edge per sincronizzarlo con il fronte? Quando qualcosa non funziona l'errore è sempre di che ha settato male la periferica. Rileggiti attentamente il datasheet dove spiega i registri da settare.

beh, basta che tu metta il nop dopo il set dell' enable.

Ad esempio se ENABLE è sulla Porta B: sbi PortB,EN nop ... cbi PortB,EN

Se voi aumentare il ritardo senza aumentare la lunghezza del programma, un trucco è quello di mettere un salto che usa 2 cicli di clock invece del NOP che ne usa 1 sbi PortB,EN rjmp $+2 ... cbi PortB,EN

-- ciao Stefano

Reply to
SB

SB ha scritto:

Aggiungo che il modo in cui Artemis usa il timer non è proprio ortodosso. Basta che il timer venga acceso all'inizializzazione, e programmato per fare il capture. Il tempo tra 2 eventi può essere misurarto semplicemente facendo la differenza tra 2 capture successivi.

Ciao

Reply to
Francesco Sacchi

Il giorno Wed, 18 Jul 2007 14:11:04 +0200, Francesco Sacchi ha scritto:

una

E' quello che gli ho detto anch'io. Non ho letto tutto il thread e non so come usa lui il timer, ma la cosa è molto semplice da implementare.

Ad esempio io uso l' Input Capture per misurare con precisione la velocità di rotazione, quando con un sensore al giro (es. vite e proximity) se girano lentamente è più conveniente fare misure di periodo che di frequenza.

Non ricordo particolari problemi a configurare il timer.

-- ciao Stefano

Reply to
SB

SB ha scritto:

Ho risolto! Il problema non era nel cattivo settaggio, ma si trattava di simulatore. Infatti io settavo ICF1 e l'interrupt avveniva, ma senza sapere di che fronte si tratta, quindi il timer non veniva salvato. Ponendo il PIND6 a 1, ICF1 non avveniva (infatti avevo impostato fronte di discesa), mentre portandolo da 1 a 0, ecco che il timer veniva salvato!!!

Toccando solo il flag non poteva salvarlo, non conosceva quale fronte lo aveva generato.

Quindi con 271 ns non ce la fa?

Ora mi rimane il problema dei numeri con la virgola! Come faccio ad utilizzarli?

Ciauz

Artemis

Reply to
Artemis

Francesco Sacchi ha scritto:

C'è però un problema di cui non tieni conto:

se dopo molti eventi il timer si trova a FF12, e l'altro evento è più grande di FF, il timer ricomincia da 0 arrivando a 78 (esempio), la tua misura sarà:

0012 - FF12

misura errata. La soluzione che ho scelto è la seguente:

inject: sbrs flags, 0 rjmp fall ldi ax, 19 out TCCR1B, ax ldi ax, 0b10000000 out TCCR1A, ax ;attiva il timer cbr flags, 1 ;imposta il flag a 0 sei reti

fall: ldi ax, 80 out TCCR1B, ax ;disattiva il timer in dx, ICR1L in dh, ICR1H ;salva la misura stato ON clr ax out ICR1L, ax ;azzera Input Capture Register out ICR1H, ax out TCNT1L, ax ;azzera il contatore del timer out TCNT1H, ax sbr flags, 1 ;imposta il flag a 1 sei reti

INJECT è la routine dell'interrupt del timer/counter1. Nel main ho settato il rilevamento del fronte di salita. Appena avviene un fronte di salita, si va a finire in INJECT che fa questo:

- attiva il timer

- imposta fronte di discesa

- imposta flag a 0

- riattiva interrupt

e si ritorna nel main. Appena avviene un fronte di discesa, si va in INJECT e grazie al flags si andrà in FALL:

- preleva valore timer

- azzera e disattiva timer

- imposta fronte di salita

- imposta flag a 1

- riattiva interrupt

poi qui in FALL inserirò le call che andranno alla lookup table etc. etc.

A presto

Artemis

Reply to
Artemis

Il giorno Wed, 18 Jul 2007 16:18:42 +0200, Artemis ha scritto:

In che senso con la virgola?

Comunque in assembler è meglio lavorare in virgola fissa, cioè 100,00 = 10000 = 2710H, altrimenti devi usare linguaggi + evoluti come il C che supportano i FLOAT.

Una buona regola è anche lavorare nei calcoli sempre con dati binari e convertirli in BCD solo al momento della visualizzazione, ti eviti un sacco di problemi anche perchè gli AVR non hanno istruzioni tipo la DAA per i dati BCD.

-- ciao Stefano

Reply to
SB

Artemis ha scritto:

Proprio perchè ne ho tenuto conto ti ho suggerito di fare così. Se fai la sottrazione indicata (in complemento a 2 su 16 bit) vedrai che otterrai proprio il valore richiesto, cioè 0x100.

Che è sbagliata. Se sei in attesa del fronte di salita il timer è fermo e quindi ti perdi il capture automatico. Attiverai il timer con una latenza casuale, a seconda del ritardo con cui servirai l'interrupt.

Perchè il capture funzioni a dovere il timer deve essere attivo, altrimenti non hai nessun vantaggio rispetto alla soluzione che avevi implementato precedentemente.

Ciao

Reply to
Francesco Sacchi

Francesco Sacchi ha scritto:

Non so come fare, trattare i numeri a 16 bit con questi micro sembra una cosa proibitiva... devo trattarli per forza ad 8 ad 8... se puoi aiutarmi te ne sarei grato. Ho perso 1 ora e mezza per fare la lookup table, molto molto lunga.

Il timer lo attiva con circa 2 us di ritardo... considera che però il conteggio è a tratti di 17,7 us =) Ho scelto di contare così, altrimenti non bastavano 16 bit per campionare aperture da 16.05 ms.

Dimmi tu come posso fare, perché devo poter misurare soltanto fronte il livello logico alto dell'onda quadra, e posso impostare solo un fronte (o salita o discesa). Quindi l'unica soluzione sarebbe:

- attendere inizialmente che il segnale sia 0 (se eventualmente c'è già un'apertura in corso)

- Appena il segnale è 0, attivo il timer e lo rendo sensibile al fronte di salita.

Loop:

- Avviene un interrupt sul fronte di salita, viene salvato il contatore e setto il fronte di discesa.

- Appena il fronte di discesa avviene, setto il sense sul fronte di salita ed eseguo la differenza delle misure -> Loop

Rimane dunque da capire questa differenza di misure come va fatta, per il resto, il trucco sta nel far oscillare la sensibilità ai fronti.

A presto

Artemis

Reply to
Artemis

SB ha scritto:

Devo eseguire moltiplicazioni tra numero di impulsi e portata, somme etc. quindi 10.86 ul * 200 impulsi (esempio), oppure (15.8 m/s)/(0.02 l) non è facile con i numeri normali. Così ho pensato di scrivere una call (non so usare le macro) che a seconda dell'operazione, tratta i numeri prima della virgola su un registro (a 8 bit) e i numeri dopo la virgola su un altro (sempre da 8 bit). Non riesco a trattare i numeri a 16 bit con questo micro, ho provato con i registri x, y, e z ma... il compilatore dà sempre errore.

che

Sembra un'ottima idea... se riuscissi a lavorare con registri a 16 bit.

A presto

Artemis

Reply to
Artemis

Sono riuscito nella famosa sottrazione! Ma come sempre, ad una soluzione si aggiunge un problema (a parte quello della lookup table che nel linguaggio non esiste un "salta se è strettamente maggiore"): non riesco ad usare ad 8 bit neppure i registri da r0 ad r15, e mi servono perché il programma non può lavorare solo con i registri da r16 a r31, con tutti quei calcoli è un'impresa. Non permette neppure di definire variabili, che cacca...

Artemis

Reply to
Artemis

Artemis ha scritto:

Sai com'è, sono micro a 8 bit e quindi fanno calcoli a ... 8bit! :-) Scherzi a parte vedo dopo che hai trovato la soluzione, comunque se qualcun'altro fosse interessato devi semplicemente usare prima l'istruzione sub e poi l'sbc che esegue una sottrazione con carry.

Va bene la risoluzione, quello che non va bene è attivare il timer dentro l'interrupt. Il meccanismo del capture serve per slegare la memorizzazione del valore in ICR1 dall'esecuzione dell'ISR. Se ti leghi nuovamente alla latenza non hai nessun miglioramento rispetto alla soluzione che avevi adottato all'inizio. Quindi il timer lo accendi e programmi una volta per tutte all'inizio dell'applicazione.

Più o meno è ok, ma non c'è bisogno di aspettare che il segnale sia a 0 per attivare il timer. Io farei semplicemente così:

Inizio applicazione:

- Programmo il timer alla velocità che voglio, attivo l'interrupt del capture sul fronte di salita.

- Avviene un interrupt sul fronte di salita, viene salvato il contatore e setto il fronte di discesa.

- Avviene un interrupt sul fronte di discesa, setto il sense sul fronte di salita ed eseguo la differenza delle misure e salvo i dati

Ciao

Reply to
Francesco Sacchi

Il giorno Wed, 18 Jul 2007 19:22:47 +0200, Artemis ha scritto:

Ma dai, si fanno calcoli anche a 32 o 64 bits con gli AVR, esempio:

add R17,R19 adc R16,R18

ti fa la somma di 2 numeri a 16 bits

Qui trovi altri esempi:

formatting link
formatting link

e qui un sacco di routines già fatte, tra cui la FLOAT128.

formatting link

Puoi aumentare il prescaler del timer/counter, ma dipende anche dal quarzo usato

Non serve, lo puoi rendere sensibile al fronte di salita anche se è a 1, non devi per forza aspettare lo 0.

Questo va bene, e lo puoi facilmente gestire dall'interrupt dell' ICP

Semplicemente con una sottrazione a 16 bits e se hai il Carry dopo la sottrazione devi complementare il risultato.

Semplicissimo.

-- ciao Stefano

Reply to
SB

Artemis ha scritto:

Bhe, basta che inverti il senso della comparazione e il senso del salto.

Se il codice che volevi scrivere era:

cmp a,b se > salta a X Y: codice... X: codice...

diventa

cmp b,a se >= salta a Y: X: codice... Y: codice

Sarà forse necessario qualche rjmp per riaggiustare le cose, ma di solito è sempre possibile riprogettare il codice anche senza sprechi.

non riesco

Mi sa che fai un po' di confusione. E' vero, per alcune operazioni sono richiesti registri alti o bassi, ma in totale ne hai 32, non mi sembrano pochi. E poi di variabli ne puoi definire quante ne vuoi, almeno finchè c'è RAM. Per accedere alla RAM però devi usare le istruzioni apposite, non ci puoi lavorare direttamente come se fosse un registro. Guardati l'instruction set, tutta la serie di LD (load) e ST (store).

Ciao

Reply to
Francesco Sacchi

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.