Introdução à Programação de Arduino - Volume 1
Capítulo 2
Programar é para todos!
A atividade de programar já foi um ofício para bem poucos e nos primeiros tempos da programação muitos eram os obstáculos: pouca informação disponível, pouco intercâmbio entre os programadores, ambientes de programação - quando já havia algum - com poucos recursos. E poucas linguagens de programação, muitas nada amigáveis. O panorama é outro, bem diverso, hoje. Internet, help on line, ambientes de programação inteligentes, linguagens a cada dia mais amigáveis, inclusive gráficas, plataformas de desenvolvimento são alguns dos recursos disponíveis para quem se dedica à atividade. Mesmo assim, muitos conhecimentos ainda são exigidos por parte de quem se dispõe a criar programas e a gama e profundidade do preparo do programador ou da programadora estão diretamente relacionadas aos requisitos que o programa deve atender. Formalmente falando, antes de iniciar a programação de qualquer coisa, quem almeja tornar-se programador ou programadora deveria aprender uma ou mais linguagens, estudar algoritmos, estruturas de dados, fazer exercícios visando desenvolver raciocínio lógico, aprender um bocado de matemática. Teoricamente é assim, teoricamente esse é o método ideal. Teoricamente...
Como mencionei no início, a proposta do Arduino é possibilitar que pessoas com pouco ou nenhum treino em programação possam expressar ideias as mais variadas, inclusive artísticas, por meios interativos e se valendo da eletrônica e da programação de dispositivos. Mas isso não significa que seja possível criar algo em termos de programas sem, ao menos, um embasamento primário, mínimo, sobre a atividade de programação. Quer dizer, alguns conceitos básicos precisam ser compreendidos antes que as linhas de um programa possam fazer sentido para alguém, por mais simples que seja o programa. Temos dois caminhos possíveis aqui: o tradicional, que importaria numa série de capítulos envolvendo os tópicos usuais e comuns nos livros de programação ou, então, um menos ortodoxo, mais “à moda Arduino”, mais interativo, no qual os conceitos são colocados à medida em que são necessários. Essa será a nossa vereda, não apenas por apresentar uma afinidade evidente com o espírito com que a plataforma foi concebida, como pelo fato de que esse livro está dirigido a um público o mais amplo possível.
Quando você conectou a placa do seu Arduino à porta usb do seu computador, o led da placa começou a piscar, com intervalos de um segundo entre cada comutação. Naquele momento eu disse que havia um programa de demonstração, instalado pela fábrica, na memória de programa do microcontrolador que está alojado na placa. Em outro momento, quando eu descrevi os menus, mencionei um muito útil sobretudo a quem está começando a aprender. O submenu Exemplos, alojado no menu Arquivos. Lá, em 01.Basics, existe um exemplo chamado Blink. Pois bem, esse é o sketch que está carregado na memória de programa do seu Arduino e é por ele que iniciaremos o estudo de programção. Abra o seu IDE, clique em Arquivos, Exemplos, 01.Basics e por fim Blink. Observe como uma nova janela do Arduino se abre, exibindo o sketch correspondente ao Blink. A figura a seguir mostra a janela do editor do Arduino carregada com o sketch.
Antes de partirmos para a análise do código, vamos nos divertir e aprender ao mesmo tempo. Já sabemos que, de alguma forma, esse programa instrui o microcontrolador a mudar o estado do led da placa a intervalos de um segundo. Antes de entendermos como isso é feito, vamos mudar a frequência das piscadas. Que tal aumentar essa frequência, digamos para o dobro. Atualmente a frequência equivale a 0,5 Hertz e queremos aumentá-la para 1 Hz. Isso fará com que o led pisque com o dobro da velocidade. Ora, raciocinemos um pouco: aumentar a velocidade das piscadas significa reduzir o intervalo entre as mudanças de estado do led, de acordo? Se desejamos dobrar a velocidade, é razoável admitir que reduzir pela metade o tempo entre comutações deve levar ao resultado almejado. Veja abaixo o código do sketch, ainda na forma original. Aqui, traduzi os comentários ao programa para nosso idioma, de forma a facilitar o entendimento. E por falar em comentários, note que as linhas acima do código prórpiamente dito também são comentários usando o estilo /* e */ que permite comentar múltiplas linhas de código de uma só vez.
/*
Blink
Turns an LED on for one second, then off for one second, repeatedly. Liga um LED por um segundo, e o desliga por um segundo, repetidamente. Most Arduinos have an on-board LED you can control.
On the UNO, MEGA and ZERO it is attached
to digital pin 13, on MKR1000 on pin 6.
LED_BUILTIN is set to the correct LED pin
independent of which board is used.
If you want to know what pin the on-board LED
is connected to on your Arduino model,
check the Technical Specs of your board at:
https://www.arduino.cc/en/Main/Products
A maior parte dos Arduinos tem um LED on-board
que você pode controlar. NO UNO, MEGA e ZERO
ele está conectado ao pino digital 13, no MKR1000
ao pino 6. LED_BUILTIN está configurado para o led
correto independentemente de qual placa você está
usando. Se você quiser saber em que pino o LED está conectado em seu Arduino, verifique
as Especificações Técnicas de sua placa em:
https://www.arduino.cc/en/Main/Products
modified 8 May 2014
by Scott Fitzgerald
modified 2 Sep 2016
by Arturo Guadalupi
modified 8 Sep 2016
by Colby Newman
This example code is in the public domain.
Esse exemplo encontra-se em domínio público.
http://www.arduino.cc/en/Tutorial/Blink
*/
// the setup function runs once when
// you press reset or power the board
// a função setup roda sempre que há
// um reset ou energização da placa.
void setup() {
// initialize digital pin LED_BUILTIN as an output.
// inicializa o pino digital LED_BUILTIN como saída.
pinMode(LED_BUILTIN, OUTPUT);
}
// the loop function runs over and over again forever
// a função loop executa repetidamente sem parar.
void loop() {
// liga LED (HIGH - nível alto de tensão)
digitalWrite(LED_BUILTIN, HIGH);
// aguarda um segundo.
delay(1000);
// desliga LED tornando a voltagem LOW, baixa.
digitalWrite(LED_BUILTIN, LOW);
// aguarda um segundo.
delay(1000);
}
A chave para alterarmos o tempo entre comutações no estado do led está na função delay(). Ela recebe um valor para seu argumento, aquilo que vai entre parênteses, igual a 1000. Delay é atraso, em inglês. Como você provavelmente sabe, as linguagens de programação usam o idioma inglês e, embora uma função não faça parte das palavras reservadas da linguagem e possa ter qualquer nome, em qualquer idioma, aqui as funções também estão em inglês. Essa função promove um atraso, ou dizendo de outra forma, perde tempo.
— Mas quanto tempo ela perde? Mil? Mas mil o quê? Dias, semanas? — Mil milisegundos.
A função delay() está implementada para receber valores em milisegundos, guarde isso ou anote aí. Bem, 1000 milisegundos representam um segundo.
— Ahá! Então essa função faz com que o programa pare por um segundo, sem fazer nada?
Exato! Cada vez que o fluxo de programa atinge uma função delay(), o processamento entra num laço no qual nada acontece durante o tempo equivalente ao número de milisegundos que a função recebeu como argumento. Portanto, em nosso sketch, há duas paradas de um segundo cada. Numa delas o led está aceso e na outra está apagado. Daqui a pouco você vai entender porque ele muda de estado entre um delay() e outro, mas agora vamos alterar o código e ver o Arduino promover a mudança no comportamento do hardware. Edite o valor que está entre parêntes na função delay() para tornar-se 500. Faça isso nas duas ocorrências da função. Depois, com seu Arduino conectado ao seu computador via porta USB, vá ao menu Sketch e clique em Carregar, ou simplesmente use o atalho de teclado, Ctrl+U. Observe na placa do Arduino que os dois leds marcados com TX e RX vão mudar de estado rapidamente, várias vezes. Esses leds sinalizam troca de dados entre a placa e seu programa, significando que o programa na memória do microcontrolador está sendo atualizado. Não demorará e você verá o led L começar a piscar novamente e mais rapidamente do que antes, exatamente com o dobro da frequência, como determina o programa agora.
Parabéns! Ao realizar esses passos você completou uma rotina que irá se repetir muito daqui para frente, qual seja: editar um programa, carregá-lo na memória do microcontrolador e vê-lo entrar em funcionamento novamente, exibindo o novo comportamento.
Antes de prosseguirmos, altere novamente os valores dos argumentos que são passados ao parâmetro da função delay(). Note que os valores não necessariamente tem que ser iguais nas duas ocorrências da função, podendo ser diferentes. Experimente fazer com que o valor na primeira ocorrência seja o dobro do valor na segunda, por exemplo, 2000 para a primeira ocorrência e 1000 para a segunda. Edite o código, recarregue o programa e observe o comportamento do sistema. Pelo resultado, sem tornar a ler os comentários ao programa, você é capaz de dizer qual parte do código liga o led e qual parte desliga? Procure responder a esse desafio antes de prosseguir na leitura. E lembre-se: em programação, a atividade de pesquisa e análise é fundamental para o bom desempenho da função, mas você não deveria se angustiar caso não possa, ainda, chegar a uma conclusão. Peter Norwig, uma das maiores autoridades em inteligência artificial do nosso planeta, defende que aprender a programar com perícia não demanda menos do que 10 anos de estudo.
O fragmento do programa modificado está mostrado abaixo.
// liga LED (HIGH - nível alto de tensão)
digitalWrite(LED_BUILTIN, HIGH);
// aguarda dos segundos.
delay(2000);
// desliga LED tornando a voltagem LOW, baixa.
digitalWrite(LED_BUILTIN, LOW);
// aguarda um segundo.
delay(1000);
A função delay() recebe um argumento em milisegundos. Anote aí.
Se você fez a experiência percebeu que agora o led passa mais tempo aceso do que apagado. Na verdade, passa dois segundos aceso e um segundo apagado. Vamos analisar juntos o código, uma linha antes e uma depois da primeira ocorrência da função delay().
Note que fizemos o argumento da primeira ocorrência da função valer 2000, equivalendo a dois segundos de atraso. A linha de código imediatamente anterior ao primeiro delay() é:
// liga LED (HIGH - nível alto de tensão).
digitalWrite(LED_BUILTIN, HIGH);
digitalWrite() também é uma função, assim como delay(). Ambas são funções da biblioteca do Arduino. Note que digitalWrite() recebe dois argumentos em seus parâmetros funcionais, LED_BUILTIN e HIGH, porque essa função está implementada para receber o número de um dos pinos de I/O da placa e um estado para esse pino. O que ela faz então é comutar o pino correspondente para o estado passado para a função. Trocando em miúdos, quando essa instrução é executada o pino 13 da placa - 19 no microcontrolador - vai para estado alto, fornecendo 5 Volts para o que quer que esteja conectado ao pino. Nesse caso, o led, que então acende. Executada essa instrução, o programa passa à instrução seguinte, porque é dessa maneira que todo programa funciona, executando uma instrução após a outra. E a seguinte é um delay() que obriga o processamento a aguardar dois segundos. Ora, então significa dizer que o led, que acaba de ser ligado, vai passar dois segundos aceso, veja.
// aguarda dos segundos.
delay(2000);
Transcorrido esse tempo, o programa executa a instrução a seguinte:
// desliga LED (LOW - nível baixo de tensão).
digitalWrite(LED_BUILTIN, LOW);
Por analogia e sabendo que LOW significa baixo, já dá para imaginar o que essa instrução faz. Se você disse apaga o led, acertou, é isso mesmo. Mas não perca de vista o curso dos acontecimentos, vamos recapitular: o led foi aceso, transcorreram dois segundos e ele foi apagado. Vejamos o que acontece em seguida, analisando a próxima instrução:
// aguarda um segundo.
delay(1000);
Mais um atraso de um segundo, correto? Significa que o led fica apagado por um segundo. Mas e depois? O que você acredita que acontece? Você sabe, você viu o programa executando no seu Arduino. O processo recomeça, magicamente. Mas porque? Onde está a próxima instrução? Porque o procesamento não parou, já que atingimos a última instrução do programa? Observando novamente a listagem completa do programa, vemos que todas as instruções que acabamos de analisar estão encerradas num bloco de programa. Esse bloco começa com:
void loop( ) {
e termina com:
}
Acontece que loop() também é uma função e desempenha um papel crucial em todo programa, em parceria com setup(). São tão importantes que o Arduino já as coloca em cada novo sketch automaticamente, poupando nosso trabalho. Tudo o que estiver dentro da função loop(), entre o primeiro abre chaves e o último, será executado repetidamente, sem parar, enquanto o sistema estive energizado. E isso responde à nossa pergunta. Não parou porque, ao atingir a última instrução, a execução do programa é desviada para a primeira instrução dentro do bloco loop() e tudo recomeça. Por isso o led continua piscando sem parar, respeitando os tempos entre as comutações. Todo programa para microcontrolador roda dentro de um laço, ou loop() e isso não acontece apenas no Arduino, mas em qualquer programa para qualquer microcontrolador.
Estamos quase terminando a dissecação de nosso exemplo, falta falar sobre a função setup(). Veja o fragmento de código que mostra a função:
void setup() {
// initialize digital pin LED_BUILTIN as an output.
// inicializa o pino digital LED_BUILTIN como saída.
pinMode(LED_BUILTIN, OUTPUT);
}
Um microcontrolador é um circuito complexo, dotado de recursos variados. Internamente, um microcontrolador típico contém áreas de memória, circuitos dedicados que executam tarefas eletrônicas que são comuns nos projetos, como temporizadores, geradores de PWM etc. Além disso, todo microcontrolador tem um sistema de entrada e saída, comumente referido como I/O. As características variam de modelo para modelo e de fabricante para fabricante, mas todo microcontrolador tem um núcleo básico de recursos que está presente em qualquer modelo. Sistema de I/O é um exemplo, afinal de nada serviria um microcontrolador que não pudesse se comunicar com o exterior. Pois bem, em qualquer programa a primeira tarefa do programador é a de configurar os recursos do microcontrolador em questão. Isso inclui definir que pinos serão usados como pinos de entrada de dados e quais serão usados como pinos de saída de dados. Além disso, há pinos que podem ser usados com sinais digitais ou analógicos e isso também precisa ser definido. Essa é a tarefa da função setup(). Em seu bloco de código é que são feitas tais definições e é por essa razão que ela precisa estar presente em qualquer programa, sob pena de o sistema não funcionar, ou pior ainda, fazê-lo de forma errática. Note que, em alguns casos extremos, configurações incorretas podem até causar danos ao microcontrolador. Observe o código dentro do bloco da função setup(). O comentário já diz tudo:
//inicializa o pino digital LED_BUILTIN como saída.
Portanto, o autor do programa está, aqui, configurando o pino 13 como pino de saída - OUTPUT. O pino 13 só pode ser usado como pino digital, pela própria constituição do UNO. Note que usando a constante LED_BUILTIN você não precisa saber qual é o pino na placa que corresponde ao led on board. Quero aproveitar o ensejo para fazer uma observação: o pino 13 da placa do UNO não corresponde ao pino 13 do microcontrolador, mas ao 19. Isso é muito importante, não existe correspondencia numérica entre os pinos da placa e os pinos do microcontrolador. A figura a seguir ilustra, apenas a título de informação complementar, a correspondência entre os pinos do microcontrolador e a pinagem na placa. Note que, em geral, você não precisa se preocupar com a pinagem no chip, bastando se ater à pinagem na placa, mesmo quando utiliza leds ou outros periféricos externos porque eles estarão conectados à pinagem da placa e não diretamente ao chip.