Usando um Delay
Esta é a forma usada no exemplo Blink do Arduino:
void setup() { pinMode(LED_BUILTIN, OUTPUT); } void loop() { digitalWrite(LED_BUILTIN, HIGH); delay(500); digitalWrite(LED_BUILTIN, LOW); delay(500); }Simples, direto, mas fica difícil fazer outras coisas ao mesmo tempo.
A Solução por Hardware
Pulsar um sinal é trabalho para PWM!
O ATmega328 possui tês timers, cada um com dois canais de PWM, vamos usar aqui o Timer1. A programação é um pouco complicada, pois o timer pode trabalhar de diversas formas.
No código abaixo vamos usar um divisor de 1024 para o clock do Arduino (16MHz), o que significa que vamos contar passos de 1024/16000 milissegundos. O PMW é configurado para inverter o sinal de saída a cada 7812 passos (7812*1024/16000 = 500ms).
void setup() { pinMode(9, OUTPUT); TCCR1A = _BV(COM1A0); TCCR1B = _BV(WGM12)|_BV(CS12)|_BV(CS10); OCR1A = 7812; } void loop() { delay(100); // nada para fazer }Parece mágica, não é? A desvantagem é que a seleção de pinos é limitada, neste caso não dá para usar o LED da placa e precisei colocar o LED na saída digital 9.
Usando Tempos
Para não ficarmos com o Arduino parado no delay, podemos testar no loop() se está na hora de mudar o LED:
void setup() { pinMode(LED_BUILTIN, OUTPUT); } void loop() { static bool aceso = false; static unsigned long pisca = 0; if (millis() > pisca) { digitalWrite(LED_BUILTIN, aceso? LOW : HIGH); aceso = !aceso; pisca = millis() + 500L; } delay (50); // faz outras coisas }Obs: variáveis static em uma função mantém o valor de uma chamada para outra.
Embora este método libere o microcontrolador para fazer outras coisas, a piscada do LED fica sensível à duração destas outras coisas (experimente aumentar o delay(50) para delay(300)).
Usando Interrupção de Tempo
Este é o meu método preferido... Usando interrupção o processamento corre normalmente a maior parte do tempo. Vamos usar de novo o timer1, mas neste caso vou usar a biblioteca TimerOne (que você pode instalar direto da IDE do Arduino).
#includevoid setup() { pinMode(LED_BUILTIN, OUTPUT); Timer1.initialize(500000L); Timer1.attachInterrupt(piscaLED); } void loop() { delay(100); // nada para fazer } void piscaLED(void) { static bool aceso = false; digitalWrite(LED_BUILTIN, aceso? LOW : HIGH); aceso = !aceso; }
A desvantagem (tem que ter, não é?) é que o código fica um pouco mais complicado (a biblioteca TimerOne escondeu a maior parte). À medida que se coloca mais coisas na interrupção é preciso tomar cuidado com a concorrência no acesso a variáveis e não deixar a interrupção demorada demais.
Nenhum comentário:
Postar um comentário