Routine di delay su dsPIC / PIC24
Il compilatore MPLAB C30, noto per essere uno dei migliori compilatori in giro e completamente ANSI, è fornito di serie con numerose librerie. Analizziamo le funzioni per eseguire i ritardi.
Con l’Hitech-C per utilizzare le funzioni di ritardo sui PIC16 bisognava dichiarare una macro _XTAL_FREQ con il valore di frequenza espresso in hertz del cristallo utilizzato, per contro le funzioni di ritardo disponibili ( __delay_us e __delay_ms) potevano accettare unicamente una costante come argomento, per cui non era lecito scrivere una cosa del genere:
unsigned char a=200; __delay_ms(a); |
per cui, con l’Hitech-C, volendo utilizzare le routine di delay incluse con il compilatore (molto precise) era necessario scendere a questo compromesso, oppure utilizzare librerie di delay alternative più o meno precise.
Con il C30 il “problema” dei delay è stato risolto.
Innanzitutto va dichiarata una macro FCY che rappresenta la frequenza del ciclo istruzioni, che sui pic a 16 bit vale FOSC/2. Supponiamo quindi di stare utilizzando un PIC24F che gira a 32MHz. Il valore di FCY è quindi 32000000/2 = 16000000, per cui andremo a dichiarare:
#define FCY 16000000UL //Unsigned Long |
Solo successivamente possiamo includere la libreria che contiene, tra le altre, le funzioni di ritardo:
#include <libpic30.h> |
Bene. Ora abbiamo a disposizione 3 funzioni di ritardo:
void __delay32(unsigned long cycles); |
Esegue un ritardo pari al numero di cicli istruzioni specificato. Il numero minimo di cicli di ritardo eseguibili è pari a 12, se viene immesso un numero inferiore a 12 verrà utilizzato 12. Rimanendo nel mio esempio in cui abbiamo un FCY pari a 16MHz, il tempo in cui un’istruzione viene eseguita è pari a 1/FCY = 62.5nS, per cui il minimo ritardo che possiamo avere è di 62.5nS * 12 = 750nS
void __delay_us(unsigned int time); |
Facile capire che questa serve per eseguire un ritardo espresso in microsecondi. Anche in questo caso non possiamo ottenere un ritardo inferiore a 12 cicli di istruzioni.
void __delay_ms(unsigned int time); |
Ritardo in millisecondi, nessun limite minimo.
Entrambe le ultime due funzioni di ritardo convertono il valore passato come argomento per poter poi richiamare la __delay32.
Le routine sono abbastanza precise. Scrivendo un semplice programma che contiene il classico led lampeggiante:
int a=10; while (1) { LED=1; __delay_ms(a); LED=0; __delay_ms(a); } |
andando a variare il valore del ritardo e controllando con l’oscilloscopio ho i seguenti risultati:
Ritardo di 1uS (periodo: 2μS, frequenza: 500KHz)
Viene prodotto un ritardo di 1.24μS (errore relativo del +24%):
Ritardo di 10μS (periodo: 20μS, frequenza: 50KHz)
Viene prodotto un ritardo di 10.3μS (errore relativo del +3%):
Ritardo di 100μS (periodo: 200μS, frequenza: 5KHz)
Viene prodotto un ritardo preciso.
Ritardo di 65000μS (periodo: 130mS, frequenza: 7.69Hz)
Perchè 65000μS ? Giusto per vedere se davvero si poteva utilizzare un unsigned int come argomento :D
Ritardo di 1mS (periodo: 2mS, frequenza: 500Hz)
Viene prodotto un ritardo di 1.020mS (errore relativo: +2%):
Ritardo di 10mS (periodo: 20mS, frequenza: 50Hz)
Viene prodotto un ritardo preciso, da questo punto in poi non si registrano più errori salendo col valore.