arduino: delaymicroseconds ()

8

Comment fonctionne la fonction delayMicroseconds (). D'après ce que j'ai compris, le prédécaleur de timer0 est réglé sur 64. Pour une horloge de 16 MHz, 4,0 uS par compte. Je suis un peu confus sur les mathématiques pour arriver à un intervalle de 1 uS?

Hawk_08
la source
4
La documentation indique "Cette fonction fonctionne très précisément dans la plage de 3 microsecondes et plus. Nous ne pouvons pas garantir que delayMicroseconds fonctionnera précisément pour des temps de retard plus petits." La documentation pour micros()dit "Sur les cartes Arduino 16 MHz (par exemple Duemilanove et Nano), cette fonction a une résolution de quatre microsecondes (c'est-à-dire que la valeur renvoyée est toujours un multiple de quatre)."
RedGrittyBrick
Voir aussi electronics.stackexchange.com/q/22584/2191
RedGrittyBrick

Réponses:

9

Le code source de cette fonction est assez bien documenté et se trouve dans /usr/share/arduino/hardware/arduino/cores/arduino/wiring.c sur les systèmes Linux. Les systèmes Windows auront un chemin similaire au fichier de câblage.c. Prenez la peine de trouver le fichier et de le parcourir. Pour l'instant, concentrez-vous sur cette seule fonction, elle ne dépend d'aucune autre fonction.

En inspectant le code, vous remarquerez qu'il ne s'agit pas de minuteries, mais de cycles d'instructions. Le code repose fortement sur l'optimisation du compilateur étant exactement la même pour vous que pour le développeur de la bibliothèque. C'est une supposition de l'auteur! Le nombre de cycles CPU "brûlés" par chaque instruction est bien documenté dans le document du jeu d'instructions d'Atmel AVR .

Tout d'abord, la valeur de retard est vérifiée pour être égale à 1, dans ce cas, le retour de la routine déjà passée sur une microseconde de temps CPU.

Ensuite, la valeur du retard est multipliée par quatre ( <<=2). La __asm__boucle se compile en une boucle de 4 cycles CPU. 4 cycles × 4 = 16 cycles. 16 MHz / (4 × 4) = 1 MHz, ce qui prend 1 us de temps de cycle, la résolution que nous recherchons.

Les -2 dernières microsecondes (avant le coup d'envoi de la boucle) sont à nouveau une correction sur le compilateur introduite au-dessus. L'appel de __asm__-code à partir de C nécessite quelques instructions supplémentaires pour enregistrer les registres du processeur.

Pour un Arduino normal à 16 MHz, seul le code suivant sera compilé:

/* Delay for the given number of microseconds.  Assumes a 8 or 16 MHz clock. */
void delayMicroseconds(unsigned int us)
{
        // calling avrlib's delay_us() function with low values (e.g. 1 or
        // 2 microseconds) gives delays longer than desired.
        //delay_us(us);
        // for the 16 MHz clock on most Arduino boards

        // for a one-microsecond delay, simply return.  the overhead
        // of the function call yields a delay of approximately 1 1/8 us.
        if (--us == 0)
                return;

        // the following loop takes a quarter of a microsecond (4 cycles)
        // per iteration, so execute it four times for each microsecond of
        // delay requested.
        us <<= 2;

        // account for the time taken in the preceeding commands.
        us -= 2;

        // busy wait
        __asm__ __volatile__ (
                "1: sbiw %0,1" "\n\t" // 2 cycles
                "brne 1b" : "=w" (us) : "0" (us) // 2 cycles
        );
}

BTW: Le code compilé est assez précis, mais sachez ce qui suit: Sur Arduino, il y a des interruptions chronométrées configurées que la plupart ignorent. Lorsqu'une interruption est reçue pendant l'exécution de la delayMicroseconds(), le timing de delayMicroseconds()sera incorrect. Vous pouvez bien sûr arrêter les interruptions avant d'appeler delayMicroseconds()et les activer par la suite, mais cela affecte à nouveau la précision de la synchronisation par la durée du code compilé pour l'activation / la désactivation.

jippie
la source
Ou si vous n'avez pas installé l'IDE Arduino, ce fichier est disponible sur github.com/arduino/Arduino/blob/master/hardware/arduino/cores/…
microtherion