C'est une question que mon père me posait toujours. " Pourquoi ne passe-t-il pas par toutes les instructions et ne s'arrête-t-il pas à la fin? "
Jetons un coup d'œil à un exemple pathologique. Le code suivant a été compilé dans le compilateur C18 de Microchip pour le PIC18:
void main(void)
{
}
Il produit la sortie d'assembleur suivante:
addr opco instruction
---- ---- -----------
0000 EF63 GOTO 0xc6
0002 F000 NOP
0004 0012 RETURN 0
.
. some instructions removed for brevity
.
00C6 EE15 LFSR 0x1, 0x500
00C8 F000 NOP
00CA EE25 LFSR 0x2, 0x500
00CC F000 NOP
.
. some instructions removed for brevity
.
00D6 EC72 CALL 0xe4, 0 // Call the initialisation code
00D8 F000 NOP //
00DA EC71 CALL 0xe2, 0 // Here we call main()
00DC F000 NOP //
00DE D7FB BRA 0xd6 // Jump back to address 00D6
.
. some instructions removed for brevity
.
00E2 0012 RETURN 0 // This is main()
00E4 0012 RETURN 0 // This is the initialisation code
Comme vous pouvez le voir, main () est appelée et contient à la fin une déclaration de retour, bien que nous ne l'ayons pas explicitement placée là-bas. Lorsque principal revient, le CPU exécute l'instruction suivante qui est simplement un GOTO pour revenir au début du code. main () est simplement appelée maintes et maintes fois.
Cela dit, ce n'est pas ainsi que les gens font les choses habituellement. Je n'ai jamais écrit de code embarqué qui permettrait à main () de sortir comme ça. Généralement, mon code ressemblerait à ceci:
void main(void)
{
while(1)
{
wait_timer();
do_some_task();
}
}
Donc je ne laisserais jamais normalement main () sortir.
"OK ok" vous dites. Tout cela est très intéressant car le compilateur s'assure qu'il n'y a jamais de dernière déclaration de retour. Mais que se passe-t-il si nous forçons le problème? Et si je codais à la main mon assembleur et ne remettais pas au début?
Eh bien, évidemment, le CPU continuerait simplement d'exécuter les prochaines instructions. Cela ressemblerait à ceci:
addr opco instruction
---- ---- -----------
00E6 FFFF NOP
00E8 FFFF NOP
00EA FFFF NOP
00EB FFFF NOP
.
. some instructions removed for brevity
.
7EE8 FFFF NOP
7FFA FFFF NOP
7FFC FFFF NOP
7FFE FFFF NOP
L'adresse mémoire suivante après la dernière instruction dans main () est vide. Sur un microcontrôleur avec mémoire FLASH, une instruction vide contient la valeur 0xFFFF. Sur un PIC au moins, ce code op est interprété comme un «nop» ou «aucune opération». Cela ne fait tout simplement rien. Le CPU continuerait à exécuter ces nops jusqu'à la fin de la mémoire.
Qu'y a-t-il après ça?
À la dernière instruction, le pointeur d'instruction du CPU est 0x7FFe. Lorsque le CPU ajoute 2 à son pointeur d'instructions, il obtient 0x8000, ce qui est considéré comme un débordement sur un PIC avec seulement 32k FLASH, et il revient donc à 0x0000, et le CPU continue joyeusement à exécuter les instructions au début du code , comme s'il avait été réinitialisé.
Vous avez également demandé s'il fallait éteindre. Fondamentalement, vous pouvez faire ce que vous voulez et cela dépend de votre application.
Si vous aviez une application qui n'avait besoin que de faire une chose après la mise sous tension, puis de ne rien faire d'autre, vous pourriez simplement mettre un certain temps (1); à la fin de main () afin que le CPU cesse de faire quoi que ce soit de notable.
Si l'application nécessite la mise hors tension du CPU, alors, selon le CPU, il y aura probablement différents modes de veille disponibles. Cependant, les processeurs ont l'habitude de se réveiller à nouveau, vous devez donc vous assurer qu'il n'y a pas de limite de temps pour le sommeil, et qu'aucune horloge de surveillance n'est active, etc.
Vous pouvez même organiser des circuits externes qui permettraient au processeur de couper complètement sa propre alimentation une fois terminé. Voir cette question: Utilisation d'un bouton-poussoir momentané comme interrupteur à bascule on-off à verrouillage .