Nesta lição vamos aprender duas coisas novas:
- Como realizar uma sequência de ações repetidamente
- Como iterar com um loop for (por) utilizando periféricos distintos
Vamos necessitar do seguinte:
- Uma placa controladora da família Arduino
- Quatro LEDs
Controlo de fluxo
A programação sequencial consiste em executar uma série de ordens ou comandos, uns atrás dos outros. Estes comandos podem ler informação (através dos sensores), executar ações (por exemplo, mover um servo), ou simplesmente realizar uma operação interna (como por exemplo, realizar uma soma). Na lição anterior, vimos um exemplo em que se alterava a ordem de execução de um programa com a frase if-else (se-senão). Estas instruções chamam-se instruções de controlo de fluxo. Vejamos um exemplo: imaginemos um programa onde, se a leitura da quantidade de luz for menor de 300, acende um LED, e se não for, apaga-o. Em função de uma variável realizamos a acção de acender o LED ou a acção apagar o LED. Pode ver-se mais claramente na imagem seguinte:
Realizar tarefas repetidamente com o loop for (por)
O loop for (por) é outro modo de modificar o fluxo em que se executa um programa fazendo com que uma série de instruções se repitam, um determinado número de vezes. Por exemplo, poderíamos querer que um LED piscasse 10 vezes. O fluxo desse programa seria algo assim:
Vamos criar este último programa, explicando-o passo a passo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
int led_pin = 5; //pino onde se conecta o LED bool primeiraVez = true; //para saber quando é a primeira vez void setup() { pinMode(led_pin, OUTPUT); } void loop() { //a primeira vez que faremos piscar o LED 10 vezes if (primeiraVez){ primeiraVez = false; //já não será mais a primeira vez for (int i = 0; i<10; i=i+1){ digitalWrite(led_pin,HIGH); //acender o LED delay(1000); //pausar 1 segundo digitalWrite(led_pin,LOW); //apagar o LED delay(1000); //pausar 1 segundo } }else{ digitalWrite(led_pin,LOW); //apagar o LED } } |
Vamos analisar por blocos:
1 2 3 4 5 6 7 |
int led_pin = 5; //pino onde se conecta o LED bool primeiraVez = true; //para sabermos quando é a primeira vez void setup() { pinMode(led_pin, OUTPUT); } |
Neste bloco usamos variáveis globais para indicar o número do PINO em que está conectado o LED. Vamos também criar uma variável booleana (admite os valores verdadeiro e falso). Utilizaremos esta variável para saber se é a primeira vez que se executa o programa. É um recurso habitual em programação, ao executar uma função loop() uma e outra vez. Se quisermos que um programa apenas se execute uma vez, é necessário fazer isto ou algo parecido.
1 2 3 4 5 6 7 8 9 10 |
void loop() { // a primeira vez que faremos piscar o LED 10 vezes if (primeiraVez){ primeiraVez = false; //já não será mais a primeira vez ... }else{ digitalWrite(led_pin,LOW); //apagar o LED } } |
Na primeira vez que for executada a função loop(), a variável primeiraVez terá o valor true (verdadeiro). Por isso entramos no if, e executamos o que vem a seguir. A primeira instrução é atribuir à variável primeiraVez o valor false (falso). Na próxima vez que for executada a função loop(), a condição não será cumprida e será executado digitalWrite(led_pin, LOW) deixando o LED apagado indefinidamente. Agora vamos a entrar e analisar o loop for (por):
1 2 3 4 5 6 |
for (int i = 0; i<10; i++){ digitalWrite(led_pin,HIGH); //acender o LED delay(1000); //pausar 1 segundo digitalWrite(led_pin,LOW); //apagar o LED delay(1000); //pausar 1 segundo } |
Em primeiro lugar
1 |
for (int i = 0; i<10; i=i+1) |
O loop for tem três partes:
- A variável sobre a qual se itera, e o valor inicial, que neste caso int i=0. Iteramos com uma variável chamada i que é um inteiro e cujo valor inicial será 0.
- Condição de controlo, que significa que o loop for vai repetir-se enquanto esta condição continuar a ser verdadeira: i < 10 . Esta confirmação realizar-se-á no princípio de cada iteração, ou seja, se a condição for falsa a primeira vez, não se realiza nenhuma iteração.
- Acção a executar no final da iteração, neste caso i=i+1. Significa que, depois de cada iteração, i incrementa-se uma unidade (poderia ser qualquer outra operação). É importante relembrar que este procedimento realiza-se ao finalizar a iteração, e por isso, na primeira iteração, i vale 0.
Deste modo, a sequência de execução seria:
- i=0 … i < 10 ? … Sim … Pisco uma vez … Incremento i … Então i=1
- i=1 … i < 10 ? … Sim … Pisco uma vez … Incremento i … Então i=2
- i=2 … i < 10 ? … Sim … Pisco uma vez … Incremento i … Então i=3
- …
- i=9 … i < 10 ? … Sim … Pisco uma vez … Incremento i …Então i=10
- i=10 … i < 10 ? … Não … Saio do loop for.
Iterando com o loop for
Outro uso dos loops for é utilizar a variável de controlo, como por exemplo, no exemplo anterior, i realizar algum cálculo. Lembras-te das luzes do carro fantástico? Vamos fazer com que 5 LEDs se acendam em sequência, de modo a que em cada vez, fique aceso o primeiro, depois também o segundo depois o terceiro … até ao fim, onde se apaguem todos. Suponhamos que os LEDs estão conectados desde os pinos 2 até ao 6, a sequência seria:
- Todos apagados
- LED pino 2 aceso
- LEDs pino2 e pino3 acesos
- LEDs pino2 e pino3 e pino4 acesos
- LEDs pino2 e pino3 e pino4 e pino5 acesos
- LEDs pino2 e pino3 e pino4 e pino5 e pino6 acesos
… e isto repete-se continuamente. Como seria o código para este programa?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
void setup() { //utilizamos o loop for para colocar os pinos no modo OUTPUT for (int i=2;i<=6;i=i+1) pinMode(i, OUTPUT); } void loop() { //apagamos todos os LEDs for (int i=2;i<=6;i=i+1) digitalWrite(i, LOW); //apagamos o LED i delay(100); //pausamos 100 milissegundos //acendemos sequencialmente o LED pino2, pino3, pino4, pino5, pino6 for (int i=2;i<=6;i=i+1){ digitalWrite(i, HIGH); //acendemos LED i delay(200); //pausamos 200 milissegundos } } |
Na função setup(), colocamos todos os pinos onde os LEDs estão conectados, no modo OUTPUT. Em vez de o fazermos um a um, vamos fazê-lo com um loop for, poupando no código. Isto seria equivalente a fazer:
1 2 3 4 5 |
pinMode(2,OUTPUT); pinMode(3,OUTPUT); pinMode(4,OUTPUT); pinMode(5,OUTPUT); pinMode(6,OUTPUT); |
Na função loop(), primeiro apagamos todos os LEDs (do mesmo modo) e logo a seguir, pausamos 100 milissegundos. Posteriormente vamos acendendo, um a um com uma cadência de 200 milissegundos, conseguindo o efeito desejado. Uma vez que estejam todos acesos, voltamos a começar com o loop(), ou seja, voltamos a apagar e a acender um a seguir ao outro, indefinidamente.
Como seria um programa que em vez de apagá-los todos de uma só vez, os vá apagando sequencialmente, ou seja, acende-se um a um com uma cadência de 200 milissegundos e depois vai apagando-os pela ordem inversa?
Para obter mais informação sobre o programa for, consulta a referência do Arduino.
Exercício
Lembras-te do exercício proposto no final da entrada sobre as frases condicionais if-else (se-senão)? A seguir podes ver a solução. Não existe em contactar-nos se não entenderes algo.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
int ledPin; //variável global para o número do pino /** * Estas funções recebem um char como parâmetro * e acendem ou apagam o LED dependendo do seu valor */ void manageChar(int Pin, char c){ Pin -= 48; //se o char for igual a H if(c=='H'){ digitalWrite(Pin, HIGH); //switch LED on } //se o char for igual a L if(c=='L'){ digitalWrite(Pin,LOW); //switch LED off } } /** * Esta função pára a execução do program até * algo ser recebido através da porta série * Os chars recebidos são enviados para a função <em>manageChar</em> */ void waitForInput(){ //Enquanto não houver informação na entrada série while(Serial.available()==0){ delay(500); // espera 500 ms e verifica novamente } // Hey!! Chegou alguma coisa! // enquanto houver informação pendente while(Serial.available()>0){ int incomingPin = Serial.read(); char incomingChar = Serial.read(); manageChar(incomingPin, incomingChar); } // quando chegar, a porta série é limpa e recebemos alguma coisa // isso é o que queríamos! } void setup(){ Serial.begin(9600); //inicia a comunicação série a 9600 bauds. for (ledPin=0; ledPin<10; ledPin++){ pinMode(ledPin, OUTPUT); //coloca o pino do LED como saída } } void loop(){ waitForInput(); //aguarda por informação na porta série } |