Até agora temos visto estruturas de controlo, variáveis, funções, entre outras coisas. Na segunda lição deste curso vimos como efectuar uma comunicação através da porta série, e agora, vamos levar esse conhecimento um passo mais à frente. Não só vamos utilizar a porta série para fazer o debug do nosso programa e conhecer informação, mas também… vamos ser capazes de dar ordens à nossa placa ZUM BT-328, ou qualquer outra placa Arduino, através do monitor série. Com isto poderemos, por exemplo, enviar um vector ao nosso robot indicando a direcção e a velocidade a que tem que mover-se. Vamos também aprender a fazê-lo com um sinal analógico através dos pinos PWM do Arduino, os quais utilizaremos para modificar a cor do LED RGB. A função PWM das placas Arduino, permitem-nos gerar um sinal analógico através de sinais digitais. Se quiseres aprender mais sobre o PWM podes aceder à página de referência do PWM.
Lista de materiais
- ZUM BT-328, placa Arduino ou compatível.
- Breadboard (ou placa de testes ou protoboard).
- LED RGB de cátodo comum, neste caso.
- Cabos Jumper.
Conexões eléctricas
Ao utilizar uma breadboard, se estamos no início de um projecto ou se o projecto for pequeno, pode não ter muita importância, mas quando o tamanho vai aumentando, é importante utilizar cablagem colorida para facilitar a compreensão do circuito, visualmente. Por exemplo, no caso do LED RGB podemos facilitar as conexões se utilizarmos, por exemplo, um cabo vermelho para o pino que controlará a cor vermelha do LED RGB. É comum marcar a alimentação do circuito com um cabo de cor vermelha e a conexão à terra ou GND (do Inglês Ground) com um cabo de cor negra ou castanha. O módulo LED que utilizamos no exemplo, inclui resistências para limitar a corrente no próprio módulo, mas se o módulo que fores utilizar não dispõe das ditas resistências, assegura-te de conectar uma resistência por cada cor, para evitar queimar o LED. Podes encontrar um exemplo de como conectar um LED sem resistências integradas na imagem seguinte: No caso deste projecto, conectaremos o LED RGB e a placa ZUM BT-328 da seguinte forma:
ZUM BT-328 | LED RGB |
GND | GND |
6 | R |
5 | G |
3 | B |
O código
Como sempre, vamos começar por declarar as variáveis dos pinos:
1 |
int redPin = 6, greenPin = 5, bluePin = 3; |
Além disso, vamos também declarar outras variáveis que utilizaremos ao longo do sketch:
1 2 3 |
int delayLed = 10; // Tempo que passará entre cada alteração do LED (ms) // Variáveis que armazenarão a última cor de cada um dos LED int red_old = 0, green_old = 0, blue_old = 0; |
Na variável delayLed, armazenaremos o tempo, em milissegundos, que passará nas transições entre um valor do LED para o seguinte. É recomendável utilizar um valor muito baixo, já que é um delay que se utiliza para com que a transição seja mais suave, e por isso há que ter em conta que quanto maior for o valor, mais aumentará o tempo que tardará em realizar-se a transição. Por exemplo, para o valor de 10 ms, a transição de “preto” (no caso de um LED sem iluminação) para branco, ou desde (0,0,0) até (255,255,255), demora 7,6 segundos a completar-se. A mesma transição com 5 ms demora 3,8 segundos a completar-se. A seguir, utilizaremos a função setup para inicializar o nosso programa:
1 2 3 4 5 6 7 8 9 10 11 |
void setup() { // Iniciar a porta série. Serial.begin(9600); // Marcamos como saídas, os pinos utilizados. pinMode(redPin, OUTPUT); pinMode(greenPin, OUTPUT); pinMode(bluePin, OUTPUT); Serial.println("Pronto!"); } |
No setup, iniciamos a porta série, que utilizaremos para realizar a comunicação entre o Arduino e o computador. Vamos também, estabelecer como saída, os diferentes pinos utilizados para cada uma das cores. Dentro do loop, encontramos um par de processos que não conhecíamos até agora: parseInt e constrain. O processo parseInt utiliza-se em conjunto com Serial no comando Serial.parseInt(). Ele procura na informação que recebe (através da porta série) a próxima cadeia de números inteiros até encontrar uma vírgula. Podes consultar a referencia aqui. A função constrain utiliza-se para “obrigar” um valor a um intervalo entre dois outros valores, ou seja, se o valor estiver entre o intervalo A-B, tomará o seu valor. Se for menor tomará o valor de A. Se for maior, tomará o valor de B. Podes consultar a referência aqui. O código do loop é o seguinte:
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 56 57 58 59 |
void setup() { // Iniciar a porta série. Serial.begin(9600); // Marcamos como saídas, os pinos utilizados. pinMode(redPin, OUTPUT); pinMode(greenPin, OUTPUT); pinMode(bluePin, OUTPUT); Serial.println("Pronto!"); } void loop() { // se existir informação disponível na porta série, vamos utilizá-la while (Serial.available() > 0) { int red = 0, green = 0, blue = 0; // procura a próxima cadeia de números inteiros válida e // atribui o valor convertido para um número inteiro, à variável correspondente red = Serial.parseInt(); // volta a procurar. green = Serial.parseInt(); // volta a procurar: blue = Serial.parseInt(); // procura o caractere de fim de linha. Indica ao programa que já terminou a introdução de dados. // Se utilizares o IDE do Arduino ou outro IDE que permita incluir o formato // de nova linha ao enviar dados através do monitor série, elimina o comentário // da linha 33 e comenta na linha 34. // if (Serial.read() == 'n'){ if (Serial.read() == '*'){ // Com <em>constrain,</em> asseguramos que o valor fica no intervalo do PWM // Para LEDs de anodo comúm, utiliza para o vermelho, por exemplo: red = 255 - constrain(red, 0, 255); red = constrain(red, 0, 255); green = constrain(green, 0, 255); blue = constrain(blue, 0, 255); // imprime os três números numa string como hexadecimal: Serial.print(red, HEX); Serial.print(green, HEX); Serial.println(blue, HEX); //Modificamos a cor do LED RGB fade(redPin, red, red_old); fade(greenPin, green, green_old); fade(bluePin, blue, blue_old); Serial.println("Cor alterada"); //Armazenamos os dados das cores anteriores red_old = red; green_old = green; blue_old = blue; } } } |
Dentro do loop, podemos ver que se utiliza fade, que é uma função criada para nos permitir, através de uma transição suave, mudar da cor actual para a nova cor. A função fade é definida depois do loop e fica assim:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
void fade(int pin, int newValue, int aktValue) { // Esta função encarrega-se de levar cada cor desde o seu valor actual, até ao seguinte // Podemos distinguir entre dois casos: // 1 - O novo valor é maior que o valor actual, e por isso é necessário aumentá-lo // 2 - O novo valor é menor que o valor actual, e por isso é necessário reduzi-lo if (newValue < aktValue) { for (int i = aktValue; i <= newValue; i++) { analogWrite(pin, i); delay(delayLed); } } else if (newValue > aktValue) { for (int i = aktValue; i >= newValue; i--) { analogWrite(pin, i); delay(delayLed); } } } |
Nesta função distinguimos dois casos:
- O valor seguinte é maior do que o valor actual, por isso temos que incrementar o valor do LED.
- O valor seguinte é menor do que o valor actual, por isso temos que diminuir o valor do LED.
Nesta função aparece também um novo comando que não tínhamos visto até agora: analogWrite, que se encarrega de utilizar as capacidades PWM (do Inglês Pulse Width Modulation, ou Modulação da Largura de Impulsos) da nossa placa. O PWM simula um sinal analógico mediante impulsos discretos de um sinal digital. Na página de referência do PWM podes encontrar mais informação.