Essa é uma pergunta que meu pai sempre me perguntava. " Por que simplesmente não percorre todas as instruções e pára no final? "
Vamos dar uma olhada em um exemplo patológico. O código a seguir foi compilado no compilador C18 da Microchip para o PIC18:
void main(void)
{
}
Produz a seguinte saída do assembler:
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
Como você pode ver, main () é chamado e, no final, contém uma declaração de retorno, embora não tenhamos explicitamente colocado lá. Quando main retorna, a CPU executa a próxima instrução, que é simplesmente um GOTO para voltar ao início do código. main () é simplesmente chamado repetidamente.
Agora, tendo dito isso, não é assim que as pessoas costumam fazer as coisas. Eu nunca escrevi nenhum código incorporado que permita que o main () saia assim. Principalmente, meu código seria algo como isto:
void main(void)
{
while(1)
{
wait_timer();
do_some_task();
}
}
Então, eu normalmente nunca deixaria main () sair.
"OK ok" você está dizendo. Tudo isso é muito interessante que o compilador garante que nunca haja uma última declaração de retorno. Mas o que acontece se forçarmos o problema? E se eu codificasse manualmente meu montador e não voltasse ao começo?
Bem, obviamente, a CPU continuaria executando as próximas instruções. Aqueles seriam algo como isto:
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
O próximo endereço de memória após a última instrução em main () está vazio. Em um microcontrolador com memória FLASH, uma instrução vazia contém o valor 0xFFFF. Em um PIC, pelo menos, esse código operacional é interpretado como um 'nop' ou 'nenhuma operação'. Simplesmente não faz nada. A CPU continuaria executando esses nops por toda a memória até o fim.
O que é depois disso?
Na última instrução, o ponteiro de instrução da CPU é 0x7FFe. Quando a CPU adiciona 2 ao ponteiro de instruções, obtém 0x8000, que é considerado um estouro em uma PIC com apenas 32k FLASH, e volta para 0x0000, e a CPU continua felizmente executando as instruções no início do código , como se tivesse sido redefinido.
Você também perguntou sobre a necessidade de desligar. Basicamente, você pode fazer o que quiser, e isso depende da sua aplicação.
Se você tinha um aplicativo que só precisava fazer uma coisa depois de ligar, e não fazer mais nada, você poderia esperar um pouco (1); no final de main () para que a CPU pare de fazer qualquer coisa perceptível.
Se o aplicativo exigir que a CPU seja desligada, dependendo da CPU, provavelmente haverá vários modos de suspensão disponíveis. No entanto, as CPUs têm o hábito de acordar novamente, portanto, você deve garantir que não haja limite de tempo para dormir e que o Watch Dog Timer esteja ativo etc.
Você pode até organizar alguns circuitos externos que permitiriam à CPU cortar completamente sua própria energia quando ela terminasse. Veja esta pergunta: Usando um botão momentâneo como uma chave seletora liga / desliga .