|
Autore |
Messaggio |
opzioni |
picmicro675
postato il: 05.09.2018, alle ore 15:56 |
Mi piace !
Il concetto di milli_time è come quello di Arducoso. Una variabile che si incrementa in modo trasparente al ciclo principale. Da questo si usano dei calcoli per determinare il periodo trascorso.
Ora se mi metti altre 2 variabili da 32 bit hai qualche rallentamento che non si giustifica se alla fine non usi 4 miliardi di millisecondi di pausa. Converrebbe una misura a sufficienza per il periodo voluto. Ma il tuo ragionamento segue un altro percorso. Dovresti scegliere se prendere una variabile a cui tutti si riferiranno (come da esperienza di Arduino) oppure prendere una variabile per ogni singolo evento da temporizzare.
Quali di queste due varianti determina una soluzione ottimale?
Mi immagino quando ne hai 10 in ISR, forse diventa oneroso. Non è detto che fare in calcolo fuori ISR sia migliore, ma da considerare che conviene una ISR breve ed efficiente.
Il sorgente (non verificato) di seguito dimostra le due varianti. Del resto si calcola l' incremento di 4 bites.
#define LED1 PORTC.7
#define LED2 PORTC.6
#define u32 unsigned long
#define u16 unsigned int
#define u8 unsigned char
#define FIRST_MODE // definizione del metodo utilizzato
#ifdef FIRST_MODE // variabile di contatore unica
u32 milli_time = 0;
#else
u16 last_time; // variabile unica per ogni evento
u16 next_time;
#endif
INTCON.T0IE = true;
INTCON.GIE = true;
TRISA = 0;
PORTA = 0;
// calcolo ricavato da http://eng-serve.com/pic/pic_timer.html
//Timer0 Registers Prescaler= 64 - TMR0 Preset = 178 - Freq = 1001.60 Hz
// Period = 0.000998 seconds
// bit 5 TMR0 Clock Source Select bit...0 = Internal Clock (CLKO)
OPTION_REG.T0CS = 0;
//1 = Transition on T0CKI pin
// bit 4 TMR0 Source Edge Select bit 0 = low/high 1 = high/low
OPTION_REG.T0SE = 0;
// bit 3 Prescaler Assignment bit...0 = Prescaler is assigned to the Timer0
OPTION_REG.PSA = 0;
OPTION_REG.PS2 = 1; // bits 2-0 PS2:PS0: Prescaler Rate Select bits
OPTION_REG.PS1 = 0;
OPTION_REG.PS0 = 1;
TMR0 = 178; // preset for timer register
void delay(long time)
{
long mytime = milli_time + time;
while (mytime <= milli_time) {};
}
#ifdef FIRST_MODE
void ISR interrupt()
{
if (T0IF) {
++milli_time;
TMR0 = 178;
T0IF = false;
}
}
void main ()
{
// variabili locali
u16 last_time;
u16 next_time;
while (1) {
// controllo che se la differenza di conteggio e` superiore
if ((milli_time - last_time) >= 2000) {
// allora interviene l' operazione
LED1 = !LED1;
// riaggiorno per il ciclo successivo
last_time = milli_time;
}
// come quello sopra.
if ((milli_time - next_time) >= 700) {
LED1 = !LED1;
next_time = milli_time;
}
}
}
#else
void ISR interrupt()
{
if (T0IF) {
++last_time;
++next_time;
TMR0 = 178;
T0IF = false;
}
}
void main ()
{
// variabili locali
while (1) {
// controllo che se la differenza di conteggio e` superiore
if (last_time >= 2000) {
// allora interviene l' operazione
LED1 = !LED1;
// riaggiorno per il ciclo successivo
last_time = 0;
}
// come quello sopra.
if (next_time >= 700) {
LED1 = !LED1;
next_time = 0;
}
}
}
#endif
Le istruzioni del preprocessore, permettono una compilazione condizionale determinata dalla definizione FIRST_MODE. Se non esistesse allora si compilerà la seconda parte del sorgente contenuto tra #else e #endif
Da notare che un 16FF873A permette il debug in hardware. Se hai un pickit3 dovresti avere tale opzione, giusto da configurare i micro per lo scopo. Questo per dire che potresti verificare coi breakpoints i valori delle variabili o il loro contenuto in memoria.
Così fatto, non devi preoccuparti che l'evento avvenga con ritardi. Neppure dover verificare quanti cicli macchina passano. I timer0 scandisce i periodi in modo corretto.
Come è scritto, dovrebbe succedere che il ciclo principale si ripete all' incirca in 40 istruzioni (ad un microsecondo per istruzione). E di fatto il resto non fa nulla che lo impegni in un ciclo bloccante. Addirittura se l' evento non combina c'è solo la comparazione del tempo con il valore scelto. Ma per certezza lo puoi anche mettere a visualizzare all' oscilloscopio, quando termina il ciclo di while.
NOTA, vedo che di solito si usa una indentazione di 2 caratteri e per me non sembra sufficientemente visibile. Forse non esiste una regola che normalizzi come viene scritto un sorgente. A volte porta a difficoltà di lettura con solo 2 caratteri.
Poi se XC8 è una ciofega, perché non passare a mikroC?
Ha solo il limite di 2 kilowords di programma, versione free.
Il passo successivo sarebbe di aggiornare il display ogni secondo oppure a secondo se un evento ne determina la necessità di aggiornamento. Per quello si può usare un flag (che deve consumare solo un bit)
Anno nuovo, forum nuovo.
Mi sa che lascio. |
|
picmicro675
postato il: 05.09.2018, alle ore 16:08 |
agric: il tmr0 prosegue il suo compito.
Infatti una volta ricaricato il valore nuovo si incrementa di uno ad ogni ciclo macchina.
Del resto potrebbe aver raggiunto qualche decina quando esce dalla ISR.
Per questo si assume che la ISR deve durare il meno possibile, quando i tempi di interrupt sono frequenti. Altrimenti non sarebbe in grado di dare spazio al resto del programma.
Ovviamente con 1 millisecondo ci stanno 1000 istruzioni (qualcuna in meno), che possono essere fatte fuori da ISR.
Se invece si determina che è necessaria una cadenza più lasca, ben venga che l' ISR diventa meno disturbante sul resto del programma. Sono considerazioni da valutare a secondo delle necessità di impiego del micro.
Vista la AN736, che prevede la possibilità di asservire 12 dispositivi su I2C, penso che 5 sia fattibile. Dato che la frequenza è più bassa di 2 volte e mezza. Poi magari si valuta che gli eventi non sono così ricorrenti quindi la base di interrogazione potrebbe anche non essere i 100 millisecondi della AN736 ma qualcosa come il doppio.
Anno nuovo, forum nuovo.
Mi sa che lascio. |
|
picmicro675
postato il: 05.09.2018, alle ore 16:18 |
Ah! per esempio io preferisco una cadenza ogni 10 millisecondi, la quale impiega solo un ciclo macchina per aggiornare il conteggio. Infatti risulta solo di 99.
Anno nuovo, forum nuovo.
Mi sa che lascio. |
|
agric
postato il: 05.09.2018, alle ore 17:09 |
picmicro675: agric: il tmr0 prosegue il suo compito.
Infatti una volta ricaricato il valore nuovo si incrementa di uno ad ogni ciclo macchina.
...
...in base all'impostazione del prescaler.
meglio essere un granello di pepe che una cacca d'asino |
|
e.ferriani
postato il: 05.09.2018, alle ore 19:21 |
Questa è l'interrupt in assembler. E' una modifica del programma che ho messo prima, con una sola variabile incrementata e, come suggerito, il settaggio del timer prima di tutto.
Spero che Grix lo metta in ordine correttamente.
Quanti cicli macchina sono?
1245 0060 ;MASTER_T4_1_Interrupt_Interrupts.c: 34: if (T0IF)
1246 btfss (90/8),(90)&7 ;volatile
1247 0060 1D0B goto u7_21
1248 0061 2863 goto u7_20
1249 0062 2864 u7_21:
1250 0063 goto i1l171
1251 0063 286C u7_20:
1252 0064 line 49
1253
1254 i1l836:
1255 0064 ;MASTER_T4_1_Interrupt_Interrupts.c: 35: {;MASTER_T4_1_Interrupt_Interrupts.c: 49:
TMR0 = 195;
1256 movlw low(0C3h)
1257 0064 30C3 movwf (1) ;volatile
1258 0065 0081 line 54
1259
1260 i1l838:
1261 0066 ;MASTER_T4_1_Interrupt_Interrupts.c: 54: milli_sec++;
1262 movlw low(01h)
1263 0066 3001 movwf (??_ISR+0)+0
1264 0067 00B1 movf (??_ISR+0)+0,w
1265 0068 0831 addwf (_milli_sec),f
1266 0069 07AF line 58
1267
1268 i1l840:
1269 006A ;MASTER_T4_1_Interrupt_Interrupts.c: 58: T0IF=0;
1270 bcf (90/8),(90)&7 ;volatile
1271 006A 110B goto i1l171
1272 006B 286C line 59
1273 ;MASTER_T4_1_Interrupt_Interrupts.c: 59: }
Enea Ferriani |
|
agric
postato il: 05.09.2018, alle ore 20:42 |
Secondo me è incompleto dov'è l'etichetta i11171
meglio essere un granello di pepe che una cacca d'asino |
|
agric
postato il: 05.09.2018, alle ore 21:22 |
Se non sbaglio 12 fino all'ultimo goto i11171
meglio essere un granello di pepe che una cacca d'asino |
|
picmicro675
postato il: 06.09.2018, alle ore 08:17 |
A ma salta l' occhio ad un goto u7_21, anziché un salto diretto a goto i1l171. Ma questo è comprensibile dato che sono costrutti automatizzati il quale il primo passaggio definisce il salto fuori dallo stato condizionale ed il secondo viene scoperto quando sono stati calcolati il totale dei bytes allocati.
Secondo difetto, non calcola l' incremento di una long. Come è scritto è al quanto criptico capire l' esatta operazione che sta svolgendo.
Ho fatto un lavoro di conversione dei listati della AN736.
http://www.grix.it/UserFiles/picmicro675/File/TransitFiles/A…
Quei files che terminano in s sono riferiti allo slave, mentre quelli che terminano in m sono definiti per il master.
Ora ci saranno buoni spunti di studio che danno una idea come si può gestire in modo ordinato un certo numero di eventi. Ovvio che l' application note ha uno scopo leggermente diverso.
Rimane comunque un valido esempio per impostare come fa dialogare tra diversi circuiti integrati. Forse meno interessante quello di collegare una seriale.
Altro compilatore valido
http://www.sourceboost.com/Products/BoostC/BuyLicense/Licens…
Già con 70 USD hai un versione Full, manca solo il supporto per le librerie. Comparato ai 995 di microchip..... Oppure i 249 di mikroE
https://www.mikroe.com/mikroc-pic
Comunque ha le librerie, sebbene Boost lo da per 149 $
Tanto per avere un compilatore che fa il suo lavoro senza aggiunger trucchi.
Anno nuovo, forum nuovo.
Mi sa che lascio. |
|
agric
postato il: 06.09.2018, alle ore 10:22 |
picmicro675: A ma salta l' occhio ad un goto u7_21, anziché un salto diretto a goto i1l171. Ma questo è comprensibile dato che sono costrutti automatizzati il quale il primo passaggio definisce il salto fuori dallo stato condizionale ed il secondo viene scoperto quando sono stati calcolati il totale dei bytes allocati.
Secondo difetto, non calcola l' incremento di una long. Come è scritto è al quanto criptico capire l' esatta operazione che sta svolgendo.
.
la domanda e.ferriani: Quanti cicli macchina sono?
Credo di aver risposto per il codice cosi com'è, per quello che si vede con ottimizzazione del piffero, con tutta probabilità la goto i11171 prosegue con la chiusura dell'isr ripristinando i vari registri.
La parte da ottimizzare cmq è solo questa e a mio avviso in questo modo
;MASTER_T4_1_Interrupt_Interrupts.c: 34: if (T0IF)
btfss (90/8),(90)&7 ;volatile
goto i1l171 // TOIF =0 esco da isr
Btfss = Bit Test Flag Skip Set
tradotto - se TOIF = 1 salta (skip) l'istruzione successiva altrimenti eseguo la goto i11171 ed esco dall'isr senza incrementare nulla perchè l'interrupt non era del timer0.
per quanto riguarda l'incremento della long l'operazione è criptata dal software.
E forse Enea ha cambiato la LONG con INT
meglio essere un granello di pepe che una cacca d'asino |
|
e.ferriani
postato il: 06.09.2018, alle ore 10:49 |
Visto quanto mi fa arrabbiare la combinazione MPLABX5.05 e XC8v2.00 non mi meraviglierei se ci fossero dei bugs da qualche parte.
Confermo che anche al mio collega firmwarista usando questa combinazione la compilazione si blocca. Negli output sembra che vada a cercare picc nella cartella avr.
Lo stesso progetto compilato con MPLABX4 e XC8v2.00 funziona.
Agric, non credo dfi aver fatto quello che dici. Se ricordo bene i due LED1 e LED2 erano LONG è sempre stati LONG.
Enea Ferriani |
|
|