Nesta lição vamos dar uma vista de olhos ao uso das funções. Uma vez que aprendamos a programar funções e depois de termos estudado as comunicações via porta série e como utilizar variáveis em Arduino, estaremos preparados para criar programas de verdade interagindo com periféricos e comunicando com outros dispositivos.
Funções para quê?
As funções não são mais do que um conjunto de linhas de código que realizam uma determinada tarefa, à qual atribuímos um nome. Não são necessárias, uma vez que esse código poderia ser inserido em qualquer ponto do programa que necessite dele, contudo permitem desenvolver o código de um modo mais limpo e organizado.
O objectivo fundamental das funções é triplo:
- Realizar um código mais organizado, limpo e de fácil actualização
- Promover a reutilização do código, mediante bibliotecas de funções
- Promover o desenvolvimento e o crescimento do código
Efectivamente, as funções facilitam enormemente o trabalho do programador, não apenas quando desenvolve o seu próprio código, mas fundamentalmente quando pretende utilizar código que foi desenvolvido por outros.
A função “Olá Mundo”
Como seria a função mais básica, que se limita a imprimir através da porta série “Olá Mundo”?
1 2 3 |
void olamundo(){ Serial.println("Olá Mundo"); } |
Vamos a analisá-la
- void – Esta palavra utiliza-se porque a função não devolve nada, ou seja, não produz nenhum resultado. Verás mais claramente quando criarmos uma função que produza um resultado.
- olamundo – É o nome da função (poderíamos ter chamado o que quiséssemos)
- ( ) – Entre parêntesis colocamos parâmetros no caso de existirem. Neste caso não existem e por isso não se escreve nada. Isto ficará mais facíl de entender quando criarmos uma função que use parâmetros.
Como seria um programa que use a função olamundo?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
void olamundo(){ Serial.println("Olá Mundo"); } void setup() { Serial.begin(9600); } void loop() { olamundo(); delay(3000); } |
O que faz este programa? Experimenta tu mesmo. Mas repara que este programa seria idêntico a este:
1 2 3 4 5 6 7 8 9 10 |
void setup() { Serial.begin(9600); } void loop() { Serial.println("Olá Mundo"); delay(3000); } |
Utilizando parâmetros
Imaginemos agora uma função que queremos que nos envie pela porta série, o resultado de somar dois números a e b. Como no momento de programar, não sabemos quanto vale a e b, vamos passá-los como um parâmetro (que poderia ser a leitura de um sensor).
1 2 3 4 |
void somar(int a, int b){ int soma = a + b; Serial.println(String(soma)); } |
Vamos analizar:
- void – novamente, está função não devolve nada.
- somar – somar é o nome da função
- (int a, int b) – são os dois parâmetros que esta função toma, para fazer os cálculos . a e b … são variáveis locais da função e por isso não podem ser usadas fora dela.
Como seria um programa completo?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
void somar(int a, int b){ int soma = a + b; Serial.println(String(soma)); } void setup() { Serial.begin(9600); } void loop() { somar(4,5); delay(3000); } |
Esta função enviaria pela porta série, a cadeia 9.
Um uso INCORRECTO de variáveis em funciones
A seguir, vamos criar um código que compila e funciona, mas que não se deveria fazer nunca.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
int a,b; //declaramos <em>a</em> e <em>b</em> como variáveis globais void somar(){ int soma = a + b; //usamos as variáveis globais <em>a</em> e <em>b</em> Serial.println(String(soma)); } void setup() { Serial.begin(9600); a=5; //inicializamos a e b b=4; } void loop() { somar(); delay(3000); } |
Este programa compila e funciona, mas é uma prática errada na programação. Porquê? Porque estamos a declarar as variáveis globais a e b, e por serem globais, podem usar-se em qualquer parte do nosso programa. Logo declaramos a função somar, sem nenhum parâmetro, para somar a e b. Como são globais, utilizará todos os valores de a e b, em qualquer lado. Finalmente, atribuímos um valor a a e b, e fazemos a soma. Até aqui tudo bem! Contudo, não devemos usar variáveis globais dentro de funções. Na realidade, devemos passar os valores que necessite através de parâmetros (como fizemos anteriormente). Apesar de funcionar, não é correcto, uma vez que não cumpre com os objectivos de limpeza, reutilização, evolução e actualização do código que dissemos anteriormente.
Agora sim, devolvemos um valor
Finalmente, vamos criar uma função, que além de fazer coisas, devolva um valor, por exemplo, o producto de dois números. Como todos estariam à espera, a função e o programa que a utiliza seria assim:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
/** * Esta função multiplica dois números inteiros e devolve o resultado */ int multiplicar(int a, int b){ int producto = a*b; //multiplicamos ambos os parâmetros return producto; //devolvemos o producto, que é um número inteiro. } void setup() { Serial.begin(9600); } void loop() { int resultado = multiplicar(2,5); //guardamos o resultado devolvido pela função, na variável <em>resultado</em> Serial.println(String(resultado)); //enviamos o resultado através da porta série delay(3000); } |
Experimenta e verás como funciona.
Um exercício
Cria tu agora uma função que pare a execução de um programa até que receba algo através da porta série. Esta função será utilizada mais adiante. Básicamente deve deixar a função loop em espera até que chega algo pela porta série. Nesse momento, lê o comando (apesar de não fazer nada com ele) e continua a executar o programa normalmente. É útil, por exemplo, quando o nosso programa está à espera que cheguem comandos através do bluetooth para saber o que deve fazer. Ele até chegar o comando e age conforme esse comando.
No vídeo seguinte, mostramos uma possível solução: