29 novembre 18, 22:01 | #21 (permalink) Top |
User |
Prima del listato devo anticiparti che io da tempo uso un semplicissimo RTOS che a dire il vero è uno schedulatore a bassissima latenza, cioè ogni funzione viene eseguita ad intervalli regolari di x tempo, questo perchè in genere ho bisogno di precisione nel timing di misure od altro, anche eventuali routine di interrupt non creano problemi perchè vengono eseguite sempre in tempi ridottissimi. Il codice è in ANSI C e molto portatile, purtroppo uso pochissimo Arduino quindi quello che segue è per ARM o PIC. Codice: // Loop RTOS 12,5ms task, 100ms loop while (1) { switch(u8Tic & 7) { case 0: //TASK 0 break; case 1: //TASK 1 break; case 2: //TASK 2 break; case 3: //TASK 3 break; case 4: //TASK 4 break; case 5: //TASK 5 break; case 6: //TASK 6 break; case 7: //TASK 7 break; } ++u8Tic; WaitMain(); } /*******************************************************************************| | Function Name : WaitMain | | Description : Routine di ritardo 12,5ms per RTOS. | | Input : None | | Output : None | | Return : None | |*******************************************************************************/ void WaitMain(void) { while(__HAL_TIM_GET_FLAG(&htim6,TIM_FLAG_UPDATE) == RESET); __HAL_TIM_CLEAR_FLAG(&htim6, TIM_FLAG_UPDATE); } /*-----------------------------------------------------------------------------*/ /******************************************************************************| | Function Name : Read_Voltage | | Description : Routine lettura tensioni alimentazione e temperatura PIC. | | Input : None | | Output : None | | Return : None | |******************************************************************************/ void(Read_Voltage)(void) { u8PunMMV = (++u8PunMMV & 15); u16App_ADC = ADCC_GetSingleConversion(channel_Temp); // Temperatura PIC u32Acc_P_T = u32Acc_P_T - u16Tab_P_T[u8PunMMV] + u16App_ADC; u16Tab_P_T[u8PunMMV] = u16App_ADC; u16P_T = u32Acc_P_T >> 4; __delay_ms(10); u16App_ADC = ADCC_GetSingleConversion(P_12V); // Tensione 12V u32Acc_12V = u32Acc_12V - u16Tab_12V[u8PunMMV] + u16App_ADC; u16Tab_12V[u8PunMMV] = u16App_ADC; u16P_12V = u32Acc_12V >> 4; __delay_ms(10); u16App_ADC = ADCC_GetSingleConversion(P_5V); // Tensione 5V u32Acc_5V = u32Acc_5V - u16Tab_5V[u8PunMMV] + u16App_ADC; u16Tab_5V[u8PunMMV] = u16App_ADC; u16P_5V = u32Acc_5V >> 4; __delay_ms(10); u16App_ADC = ADCC_GetSingleConversion(P_3V); // Tensione 3V u32Acc_3V = u32Acc_3V - u16Tab_3V[u8PunMMV] + u16App_ADC; u16Tab_3V[u8PunMMV] = u16App_ADC; u16P_3V = u32Acc_3V >> 4; } /*-----------------------------------------------------------------------------*/
__________________ Peace & Love Fate le cose nel modo più semplice possibile, ma senza semplificare. (A. Einstein) Ultima modifica di ElNonino : 29 novembre 18 alle ore 22:06 |
29 novembre 18, 22:12 | #22 (permalink) Top |
User |
Dimenticavo, la media mobile che ho lincato include un ritardo di 10ms fra i vari canali perchè era per un applicazione assai lenta, togliendo i ritardi viene eseguita tutta in pochi ms (5ms per tutti i canali) con un PICF18..... con clock a 48MHz. Con un STM32F030... sempre a 48MHZ una media mobile su 8 campionamenti di un Array a 16 biti di dimensioni 2x8 impiega 2ms.
__________________ Peace & Love Fate le cose nel modo più semplice possibile, ma senza semplificare. (A. Einstein) |
30 novembre 18, 14:47 | #23 (permalink) Top |
User Data registr.: 13-09-2012
Messaggi: 4.687
|
Ciao ElNonino. Effettivamente ho diversi dubbi, ci sono delle parti del tuo codice che non so decifrare. Però mi sembra di capire che la porzione del codice che mi interessa, ovvero quella della virgola mobile, sia questa (per un canale): u8PunMMV = (++u8PunMMV & 15); u16App_ADC = ADCC_GetSingleConversion(channel_Temp); // Temperatura PIC u32Acc_P_T = u32Acc_P_T - u16Tab_P_T[u8PunMMV] + u16App_ADC; u16Tab_P_T[u8PunMMV] = u16App_ADC; u16P_T = u32Acc_P_T >> 4; Mi sembra uguale alla mia: sommadegMPU_0-=degMPU_0[i]; degMPU_0[i] = ((atan2(MPU_0_AcY, MPU_0_AcX )) * 180.0) / PI; sommadegMPU_0+=degMPU_0[i]; i++; if (i==k) {i=0;} poi, ogni 500 millisecondi eseguo: mediadegMPU_0 = sommadegMPU_0 / k dove k è la dimensione del vettore contenente l'angolo ricavato in pratica la variabile sommadegMPU_0 contiene la somma di tutti i valori delle letture che concorrono al calcolo della virgola mobile, tali valori sono contenuti nell'array degMPU_0[] e i è l'incremento che mi dice quale elemento del vettore degMPU_0[] devo sostituire. mediadegMPU_0 è la media. |
30 novembre 18, 22:44 | #24 (permalink) Top | |
User | Citazione:
Poi ti spiego alcuni trucchi: - usare una variabile di appoggio (u16App_ADC) dove memorizzare la lettura del sensore aiuta molto nel debug e velocizza il loop, - usare "u8PunMMV = (++u8PunMMV & 15)" anzichè "i++; if (i==k) {i=0;}" è più veloce, un & richiede in genere un solo ciclo di clock un if ne usa di più. quando un contatore incrementale ad 8 bit super 255 ritorna a 0 quindi con un & adatto ottieni automaticamente i valori da 0 a n. Chiaramente funziona se la dimensione dell'array è potenza di 2, cosa peraltro assai consigliabile. - il motivo per cui la tua routine è lenta e sicuramente occupa anche tanta memoria è che usi tutto in floating point e se il micro non ha una FPU ci mette un secolo a fare quei calcoli, inoltre per la velocità sarebbe meglio usare un #def 180 180.0 perchè il compilatore ne è felice... Se tu lavorassi con interi poi potresti usare un >> per la divisione (sempre se con esponenti di 2) che è enormemente più veloce di un / fra floating. In ultimo se usi una printf per stampare (o mettere in una stringa) un valore floating un micro ad 8 bit ci passa la notte.... Vedo di riesumare la mia routine per leggere l'elevazione dei pannelli FV completa di tabella di linearizzazione e poi la pubblico, girava su un PIC16F877 . Nei sistemi embedded è una regola d'oro usare sempre interi e convertirli in floating una sola volta, se possibile.
__________________ Peace & Love Fate le cose nel modo più semplice possibile, ma senza semplificare. (A. Einstein) | |
01 dicembre 18, 00:42 | #25 (permalink) Top | |
User Data registr.: 13-09-2012
Messaggi: 4.687
| Citazione:
| |
01 dicembre 18, 22:32 | #27 (permalink) Top |
User |
Allora per il punto #def k 180.0 è perchè in genere una costante (k) il compilatore la alloca in memoria statica e quando viene utilizzata viene richiamata in un solo ciclo, invece usare 180.0 obbliga il compilatore ad usare più cicli. Per le operazioni binarie devi sapere che un x >>1 equivale a dividere per 2 il valore di x ed un x <<2 equivale a moltiplicare per due, ora nella maggior parte dei compilatori questa operazione comporta un solo ciclo di clock, una / molti di più. Il tuo tempo di stabilizzazione può essere corretto, nel senso che se hai un ciclo di 80ms ed un array di 64 valori 0,08s x 64 = 5,12s contando che per avere un valore stabile all'accensione servono almeno due serie di campionamenti completi siamo sui 10,24s, decisamente lento. Io direi che se usi un array di 2 x 16 valori in cui inserisci le letture di X ed Y dell'accelerometro e calcoli l'angolo una sola volta a ciclo usando la media dei due canali velocizzi di molto il tempo di ciclo. Poi per il printf di float ci sono trucchetti semplici che lo velocizzano molto. Se hai un oscilloscopio, anche economicissimo, ti consiglierei di utilizzarlo per misurare con precisione il tempo impiegato da operazioni, funzioni, routine o loop: imposti un pin digitale come output e ti crei due macro in define che settino o resettino il pin e le chiami TEST_ON e TEST_OFF poi TEST_ON ...... ..... ..... TEST_OFF e sull'oscilloscopio vedrai esattamente la durata delle operazioni comprese far ON ed OFF, è un sistema che ho sempre usato in fase di scrittura e test di programmi time critical per microprocessori embedded.
__________________ Peace & Love Fate le cose nel modo più semplice possibile, ma senza semplificare. (A. Einstein) |
01 dicembre 18, 22:41 | #28 (permalink) Top |
User Data registr.: 13-09-2012
Messaggi: 4.687
|
Farò tesoro dei consigli. Per quanto riguarda la misura del tempo di ciclo un oscilloscopio rudimentale ce l'ho, però ho sempre fatto misurare il tempo di ciclo tramite la funzione millis() e facendo stampare a video il risultato; certamente il tempo di ciclo è sovrastimato, però credo che con buona approssimazione possa andare, o no? Inviato dal mio Mi A1 utilizzando Tapatalk |
02 dicembre 18, 10:59 | #29 (permalink) Top |
User |
Io non fido troppo delle misure sui tempi d'esecuzione ottenute dallo stesso micro su cui gira il programma, preferisco andare alla vecchia con l'oscilloscopio, l'unico errore introdotto dallo strumento è quello del tempo di salita e discesa dei fronti dell'impulso che in genere è di pochissimi ns.
__________________ Peace & Love Fate le cose nel modo più semplice possibile, ma senza semplificare. (A. Einstein) |
02 dicembre 18, 11:06 | #30 (permalink) Top | |
User Data registr.: 13-09-2012
Messaggi: 4.687
| Citazione:
Inviato dal mio Mi A1 utilizzando Tapatalk | |
Bookmarks |
| |
Discussioni simili | ||||
Discussione | Autore discussione | Forum | Commenti | Ultimo Commento |
Radiocomando 3 motori DC e 2 sensori di T con Arduino su trenino | spraity | Radiocomandi | 3 | 09 febbraio 17 15:07 |