Apostila de Arduino
Apostila de Arduino
Apostila de Arduino
TUTORIAL
Experimentos e conceitos de programação computacional usando o
microcontrolador ARDUINO
SUMÁRIO
Conteúdo Pág.
Projeto 1: LED pisca pisca 1
Projeto 2: Código Morse 6
Projeto 3: Semáforo 9
Projeto 4: Semáforo interativo 10
Projeto 5: Perseguição de LEDs 12
Projeto 6: Efeito interativo de perseguição de LEDs 16
Projeto 7: Lâmpada pulsante 20
Projeto 8: Lâmpada de humor 22
Projeto 9: Efeito fogo de LED 21
Projeto 10: LEDs controlados 28
Projeto 11: Acionando um motor CC 35
Projeto 12: Atuador piezelétrico 38
Projeto 13: Sensor de temperatura com o CI LM35 31
Lorena, SP
2014
Projeto 1 - LED Pisca-Pisca protoboard for nova, o ajuste nos furos fará com
que a inserção dos componentes seja um pouco
Neste projeto vamos configurar e programar o mais dura. Deixar de inserir os componentes com
Arduino para fazer um LED piscar. Vamos usar cuidado pode resultar em danos. Verifique se o
LED vermelho para ensinar alguns conceitos de seu LED está ligado da maneira certa com a perna
eletrônica e de codificação em C ao longo do mais comprida conectada ao pino digital 10. A
caminho. perna longa do LED é o anodo (+) e deve sempre
ir para a alimentação de +5 V (neste caso, que sai
Componentes do pino digital 10) e a perna mais curta é o
catodo (-) e deve ir para o pino terra (GND).
Quando você estiver certo de que tudo está ligado
corretamente, conecte o Arduino ao computador
pelo cabo USB.
A seguir, abra o IDE Arduino e digite o seguinte
código:
Descrição do código
// Projeto 1 - LED Pisca-Pìsca
int ledPin = 10;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
digitalWrite(ledPin, HIGH);
delay(1000);
digitalWrite(ledPin, LOW);
delay(1000);
}
3
Em seguida, passamos à função setup() que O código Morse é um tipo de codificação que
simplesmente define o modo para o pino digital transmite letras e números usando padrões ON e
10 como saída (OUTPUT). OFF. Ele é, portanto, bem adequado para os
No laço principal do programa que estabelecemos nossos sistemas digitais como podemos
pino digital 10 HIGH, envio de 5 V. Então vamos transformar um LED ligado e fora do padrão
esperar por um segundo e, em seguida, desligar o necessário para soletrar uma palavra ou uma série
5 V do pino 10, antes de esperar outro 1 s. O laço, de caracteres.
em seguida, começa do início e o LED, portanto, Neste caso estaremos sinalizando S.O.S. que no
liga e desliga continuamente enquanto o Arduino alfabeto do código Morse é de três pontos (flash
estiver energizado. curto), seguido por três traços (flash de
Agora que você sabe isso, você pode modificar o comprimento longo), seguido por três pontos
código para ligar o LED em um período diferente novamente.
de tempo e também desligá-lo por um período de Podemos, portanto, agora com código do nosso
tempo diferente. esboço piscar o LED ON e fora deste padrão,
Por exemplo, se quisermos que o LED permaneça sinalizando SOS. Digite o código para criar uma
aceso por dois segundos, em seguida, desligado nova configuração. Verifique se o seu código é
meio segundo nós poderíamos fazer o seguinte: livre de erros e, em seguida, envie-o para o seu
Arduino.
void loop() { Se tudo correr bem você vai ver agora o LED em
digitalWrite(ledPin, HIGH);
delay(2000); flash o código sinal Morse SOS, aguarde 5
digitalWrite(ledPin, LOW); segundos, em seguida, repita. Então, vamos dar
delay(500);
} uma olhada neste código e descobrir como ele
funciona.
ou talvez você gostaria que o LED fique desligado
// Projeto 2 – Codigo Morse SOS
por 5 segundos e, em seguida, piscar rapidamente // LED connected to digital pin 10
(250 ms), como o LED indicador de um alarme de int ledPin = 10;
carro, então você poderia fazer isso: // run once, when the sketch starts
void setup()
void loop() { {
digitalWrite(ledPin, HIGH); // sets the digital pin as output
delay(250); pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, LOW); }
delay(5000); // run over and over again
} void loop()
{
ou fazer o LED ligar e desligar muito rápido: // 3 dits
for (int x=0; x<3; x++) {
void loop() { digitalWrite(ledPin, HIGH); // sets the
digitalWrite(ledPin, HIGH); LED on
delay(50); delay(150); // waits for 150ms
digitalWrite(ledPin, LOW); digitalWrite(ledPin, LOW); // sets the
delay(50); LED off
} delay(100); // waits for 100ms
}
Variando entre ligar e desligar o LED, você pode // 100ms delay to cause slight gap
criar qualquer efeito que desejar. between letters
delay(100);
// 3 traços
for (int x=0; x<3; x++) {
Projeto 2 - Código Morse SOS digitalWrite(ledPin, HIGH); // sets the
LED on
sinalizador delay(400); // waits for 400ms
digitalWrite(ledPin, LOW); // sets the
LED off
Para este projeto, vamos deixar o circuito
delay(100); // waits for 100ms
exatamente do mesmo jeito configurado como no }
Projeto 1, mas teremos algumas diferenças no // 100ms delay to cause slight gap
código para fazer o display LED emitir uma between letters
mensagem em código Morse. Neste caso, faremos delay(100);
// 3 dits again
com que o LED sinalize as letras S.O.S., que é o for (int x=0; x<3; x++) {
código Morse internacional de sinal de socorro. digitalWrite(ledPin, HIGH); // sets the
LED on
4
delay(150); // waits for 150ms Neste caso, o laço será executado enquanto x for
digitalWrite(ledPin, LOW); // sets the
LED off
menor do que (<) 3. O código dentro de um laço
delay(100); // waits for 100ms for será sempre executado uma vez e não
} importa como a condição é definida. O símbolo <
// wait 5 seconds before repeating the é conhecido como um operador de comparação.
SOS signal
delay(5000);
Eles são usados para tomar decisões dentro de seu
} código e comparar dois valores. Os símbolos
utilizados são:
Projeto 2 – Revisão do código
Assim, a primeira parte do código é idêntica ao
último projeto em que inicializa um pino variável
e define-se o pino 10 para ser uma saída. No
código principal, podemos ver o mesmo tipo de
declaração para transformar os LEDs ligados e
desligados por um período definido de tempo,
mas desta vez as declarações estão dentro de três No nosso código estamos comparando x com o
blocos de código separados. valor 3 para ver se é menor do que ele. Se x for
O primeiro bloco é o que gera três piscadas menor que 3, então o código do bloco será
repetido novamente. A declaração final é x++:
for (int x=0; x<3; x++) { esta é uma instrução para aumentar o valor de x
digitalWrite(ledPin, HIGH); em 1. Poderiamos ter digitado também x = x+1,
delay(150);
digitalWrite(ledPin, LOW); o que faria atribuir a x o valor de x + 1. Observe
delay(100); que não há necessidade de colocar um ponto e
} vírgula após esta declaração final, em loop. Você
pode fazer operações matemáticas simples,
Podemos ver que o LED é ligado por 150 ms e usando os símbolos +, -, * e / (adição, subtração,
então desligado 100 ms. Podemos ver que aquelas multiplicação e divisão). Por exemplo:
declarações que estão dentro de um conjunto de
chaves são, portanto, um bloco de código
separado. Mas, quando executamos o sketch,
podemos ver que a luz pisca três vezes e não
apenas uma vez. Isso é feito usando o laço for:
5
// Projeto 3 - Semáforo
Projeto 3 – Semáforo int ledDelay = 10000; // delay in between
changes
Agora vamos criar um conjunto de semáforos que int redPin = 10;
vai mudar de verde para amarelo e depois int yellowPin = 9;
int greenPin = 8;
vermelho e depois volta novamente, depois de um void setup() {
conjunto período de tempo utilizando os quatro pinMode(redPin, OUTPUT);
estados do sistema. Este projeto poderia ser pinMode(yellowPin, OUTPUT);
utilizado em uma estrada de ferro modelo ou para pinMode(greenPin, OUTPUT);
}
uma minicidade de brinquedo. void loop() {
// turn the red light on
Você precisará de: digitalWrite(redPin, HIGH);
delay(ledDelay); // wait 5 seconds
digitalWrite(yellowPin, HIGH); // turn on
yellow
delay(2000); // wait 2 seconds
digitalWrite(greenPin, HIGH); // turn
green on
digitalWrite(redPin, LOW); // turn red
off
digitalWrite(yellowPin, LOW); // turn
yellow off
delay(ledDelay); // wait ledDelay
milliseconds
digitalWrite(yellowPin, HIGH); // turn
yellow on
digitalWrite(greenPin, LOW); // turn
green off
delay(2000); // wait 2 seconds
digitalWrite(yellowPin, LOW); // turn
yellow off
// now our loop repeats
Montagem: }
void setup() {
pinMode(carRed, OUTPUT);
pinMode(carYellow, OUTPUT);
pinMode(carGreen, OUTPUT);
pinMode(pedRed, OUTPUT);
pinMode(pedGreen, OUTPUT);
pinMode(button, INPUT);
// Acende a luz verde para os carros
digitalWrite(carGreen, HIGH);
digitalWrite(pedRed, HIGH);
}
void loop() {
int state = digitalRead(button);
/* Verifica se o botao foi pressionado ha
mais de 5 s desde a ultima vez */
if (state == HIGH && (millis() -
changeTime) > 5000) {
// Chama a funcao para alterar as luzes
changeLights();
}
}
Quando lemos um pino digital usando o comando Será executado se x for falso, ou seja igual a zero.
digitalRead, o estado do pino irá ser HIGH ou Você pode também reunir condições com
LOW. Assim, o comando if em nosso sketch é: parênteses, por exemplo:
10
simplesmente se referir ao número de índice do No entanto, você tem que parar o programa e
elemento. No entanto, em nossa matriz de manualmente alterar o valor de ledDelay e então
elemento 10, o índice dos números são de 0 a 9. refazer o upload do código alterado para ver as
Neste caso, o 3º elemento (ledPin[2]) tem o alterações. Não seria mais agradável ser capaz de
valor de 6 e o 7º elemento (ledPin[6]) tem um ajustar a velocidade, enquanto o programa está
valor de 10. Você tem que dizer o tamanho da funcionando?
matriz, se não inicializar com os primeiros dados. Sim, seria. Então vamos fazer exatamente isso no
No nosso esboço não fizemos explicitamente a próximo projeto, através da introdução de uma
escolha de um tamanho, como o compilador é forma que interaja com o programa e ajuste a
capaz de contar os valores que já atribuídos para a velocidade usando um potenciômetro.
matriz e trabalhar com tamanho de 10 elementos.
Se tivéssemos declarado a matriz, mas não
inicializado com valores ao mesmo tempo, seria Projeto 6 – Efeito interativo de
preciso declarar uma dimensão, para exemplo,
poderíamos ter feito isso:
perseguição com LEDs
void changeLED() {
for (int x=0; x<10; x++) {
digitalWrite(ledPin[x], LOW);
}
digitalWrite(ledPin[currentLED], HIGH);
currentLED += direction;
if (currentLED == 9) {direction = -1;}
if (currentLED == 0) {direction = 1;}
}
ledVal = int(sinVal*255);
13
de tempo que a saída permanece elevada (on)
versus baixa (off). A duração do tempo é
conhecida como largura de pulso.
Por exemplo, se for enviado o valor 0 para o pino
11 usando analogWrite(), o período ON seria
zero, ou teria um ciclo de 0%. Se fosse enviado
um valor de 64 (correspondendo a 25% de 255) o
pino seria ON para 25% do tempo e OFF para o
restante 75% do tempo. O valor 191
corresponderia a um ciclo de trabalho de 75%,
enquanto que um valor de 255 corresponderia a
um ciclo de trabalho de 100%. Os impulsos
ocorrem a uma frequência de aproximadamente
500 Hz ou a duração de 2 ms cada.
Assim, podemos ver em nosso sketch que o LED
está sendo ligado e desligado muito rápido. Se o
ciclo de trabalho for de 50% (valor de 127), o
LED irá pulsar de forma ligado e desligado em
500 Hz e mostrará a metade do brilho máximo.
Basicamente é uma ilusão de ótica que podemos
usar a nosso favor, permitindo utilizar pinos
digitais para a saída de um valor simulando um
sinal analógico para o nosso LED.
Note que apesar de apenas seis dos pinos terem a
função PWM, você pode facilmente escrever um
programa para fornecer uma saída PWM a todos
os pinos digitais, se desejar.
Mais tarde, vamos revisitar a função PWM e
utilizá-la para criar tons audíveis usando uma
sirene piezelétrica. Conecte o LED RGB, que poderá formar diversas
cores, da forma que desejar apenas alternando a
intensidade luminosa de cada cor.
Projeto 8 – Lâmpada do humor // Projeto 8 – Lampada do humor
float RGB1[3];
No projeto anterior, vimos que podemos ajustar o float RGB2[3];
brilho de um LED utilizando as capacidades de float INC[3];
int red, green, blue;
PWM do chip Atmega. int RedPin = 11;
Vamos agora aproveitar essa capacidade int GreenPin = 10;
utilizando um LED vermelho, verde e azul (RGB) int BluePin = 9;
e pela mistura das cores criarmos qualquer cor void setup()
{
que desejarmos. Serial.begin(9600);
A partir disso, vamos criar uma lâmpada de randomSeed(analogRead(0));
humor semelhante ao tipo que você vê à venda em RGB1[0] = 0;
todo o lugar hoje em dia. RGB1[1] = 0;
RGB1[2] = 0;
RGB2[0] = random(256);
O que você precisa RGB2[1] = random(256);
RGB2[2] = random(256);
LED tricolor RGB }
void loop()
{
randomSeed(analogRead(0));
for (int x=0; x<3; x++) {
INC[x] = (RGB1[x] - RGB2[x])/256; }
3x220 Ω resistores for (int x=0; x<256; x++) {
red = int(RGB1[0]);
green = int(RGB1[1]);
blue = int(RGB1[2]);
Montagem: analogWrite (RedPin, red);
analogWrite (GreenPin, green);
14
analogWrite (BluePin, blue); variáveis inteiras que irão armazenar os nossos
delay(100); valores RGB, bem como um valor de incremento.
RGB1[0] -= INC[0];
RGB1[1] -= INC[1];
RGB1[2] -= INC[2]; float RGB1[3];
} float RGB2[3];
for (int x=0; x<3; x++) { float INC[3];
RGB2[x] = random(556)-300; int red, green, blue;
RGB2[x] = constrain(RGB2[x], 0, 255);
delay(1000); Na função de configuração temos
}
}
randomSeed(analogRead(0));
Quando você executar o programa, verá as cores
O comando randomSeed é utilizado para criar
mudarem lentamente. Pronto, você fez a sua
números aleatórios (na verdade, pseudo
própria lâmpada do humor.
aleatórios). Chips de computador não são capazes
de produzir números aleatórios de modo que
Descrição do código tendem a olhar para dados numa parte da sua
memória que podem ser diferentes ou olhar para
Os LEDs que constituem a lâmpada humor são de uma tabela de valores diferentes e utilizá-las como
cores vermelho, verde e azul. Da mesma forma um número pseudo-aleatório. Neste caso, o do
que o seu monitor de computador é feito de cores valor que será dado ao randomSeed é um valor
vermelho minúsculo, verde e (RGB) pontos azuis, lido a partir do pino analógico 0. Como nós não
o mapa pode gerar diferentes cores, ajustando o temos nada ligado ao pino analógico 0 tudo o que
brilho de cada um dos três LEDs de tal maneira será lido é um número aleatório criado pelo ruído
que nos dê um valor RGB e tons de cores analógico.
diferentes. Uma vez que tenhamos definido um início para o
Um valor RGB de “255,0,0” nos daria o vermelho nosso número aleatório, esse poderá criar outro
puro. O valor “0,255,0” daria verde puro e número usando a função random(). Em seguida,
“0,0,255” a cor azul pura. Ao misturar essas cores temos dois conjuntos de valores RGB
dos LEDs, podemos obter diversas cores. Você armazenados em um elemento de três matrizes.
ainda pode fazer diferentes cores, como nesta RGB1 são os valores RGB que queremos que a
tabela com alguns exemplos de combinação de lâmpada comece (neste caso, todos em zero ou
cores: desligados).
RGB1[0] = 0;
RGB1[1] = 0;
RGB1[2] = 0;
RGB2[0] = random(256);
RGB2[1] = random(256);
RGB2[2] = random(256);
16
int ledPin1 = 9;
int ledPin2 = 10;
int ledPin3 = 11;
pinMode(ledPin1, OUTPUT);
pinMode(ledPin2, OUTPUT);
Montagem pinMode(ledPin3, OUTPUT);
analogWrite(ledPin1, random(120)+135);
analogWrite(ledPin2, random(120)+135);
analogWrite(ledPin3, random(120)+135);
delay(random(100));
Abra o IDE Arduino e digite o seguinte código: O laço principal, em seguida, começa novamente
causando o efeito de luz que se pode ver.
// Projeto 9 – Efeito de LED de fogo Utilizando um cartão branco onde possa se refletir
int ledPin1 = 9;
int ledPin2 = 10; as luzes ou uma armação como um abajur você
int ledPin3 = 11; poderá ver um efeito de chama muito realista.
void setup()
{ Como a construção do hardware é bem simples,
pinMode(ledPin1, OUTPUT); vamos pular para o próximo Projeto.
pinMode(ledPin2, OUTPUT);
pinMode(ledPin3, OUTPUT);
}
void loop()
{ Projeto10 – LEDs controlados
analogWrite(ledPin1, random(120)+135);
analogWrite(ledPin2, random(120)+135); Para este projeto utilizaremos o mesmo circuito
analogWrite(ledPin3, random(120)+135);
delay(random(100)); anterior (Projeto 9), mas agora vamos mergulhar
} no mundo da comunicação serial e controlar a
nossa luz, enviando comandos a partir do PC para
Agora pressione o botão Verificar / Compilar no o Arduino usando o “Serial Monitor” no IDE
topo da IDE para se certificar de que não há erros Arduino, que é uma tela de interface com o
em seu código. Se este é bem sucedido agora você hardware do arduino. Este projeto também
pode clicar no botão Upload para carregar o introduz como manipular sequências de texto.
código para o Arduino. Então deixe a configuração do hardware do
Se tudo estiver certo poderemos ver agora os mesmo jeito de antes e introduza o novo código:
LEDs em cintilação de uma maneira aleatória para
simular uma chama ou efeito de fogo. // Projeto 10 – Lampada RGB controlada
Agora vamos dar uma olhada no código e char buffer[18];
hardware e descobrir como ambos trabalham. int red, green, blue;
int RedPin = 11;
int GreenPin = 10;
Descrição do código int BluePin = 9;
void setup()
Primeiro nós declaramos e inicializamos algumas {
variáveis inteiras que conterão os valores para os Serial.begin(9600);
pinos digitais que vamos conectar os nossos Serial.flush();
LEDs, como já foi realizado em projetos pinMode(RedPin, OUTPUT);
pinMode(GreenPin, OUTPUT);
anteriores.
17
pinMode(BluePin, OUTPUT); Na janela de texto “Serial Monitor” você pode
}
entrar com os valores de R, G e B para cada um
void loop() dos três LEDs manualmente e o brilho dos LEDs
{ será alterado e a cor de efeito resultante será a que
if (Serial.available() > 0) { você programar.
int index=0;
Por exemplo, Se você digitar R255 o LED
delay(100); // Aguarda encher o buffer
int numChar = Serial.available(); vermelho irá exibir pleno brilho.
if (numChar>15) { Se você digitar R255, G255, em seguida, os
numChar=15; LEDs vermelho e verde irão exibir brilho
} máximo.
while (numChar--) {
buffer[index++] = Serial.read(); Agora entre com os comandos R127, G100, B255,
} e você obterá uma cor aparentemente arroxeada.
splitString(buffer); Se você digitar, r0, g0, b0 todos os LEDs serão
} desligados.
}
O texto de entrada é projetado para aceitar tanto
void splitString(char* data) { uma letra minúscula ou maiúscula caso de R, G e
Serial.print("Data entered: "); B e, em seguida, um valor entre 0 e 255.
Serial.println(data); Quaisquer valores acima de 255 serão descartados
char* parameter;
parameter = strtok (data, " ,"); para no máximo 255. Você pode inserir uma
while (parameter != NULL) { vírgula ou um espaço entre os parâmetros e você
setLED(parameter); pode entrar 1, 2 ou 3 valores de LED em qualquer
parameter = strtok (NULL, " ,"); momento um. Por exemplo,
}
// Limpa o texto e os buffers seriais
for (int x=0; x<16; x++) { R255 b100, r127 b127 G127, G255 B0,
buffer[x]='\0'; B127, R0, G255 .
}
Serial.flush();
}
Descrição do código
void setLED(char* data) { Este projeto apresenta uma série de conceitos
if ((data[0] == 'r') || (data[0] == 'R')) novos, incluindo a comunicação serial, ponteiros e
{
int Ans = strtol(data+1, NULL, 10);
manipulação de textos. Então, mantenha-se
Ans = constrain(Ans,0,255); atento, pois teremos várias explicações.
analogWrite(RedPin, Ans); Primeiro vamos definir uma matriz de char
Serial.print("Red is set to: "); (caracteres) para manter nossa cadeia de texto.
Serial.println(Ans);
}
Fizemos de 18 caracteres, cujos são mais longos
if ((data[0] == 'g') || (data[0] == 'G')) do que o máximo de 16, o que nos permitirá
{ garantir que não teremos erros de sobrecargas ao
int Ans = strtol(data+1, NULL, 10); sistema.
Ans = constrain(Ans,0,255);
analogWrite(GreenPin, Ans);
char buffer[18];
Serial.print("Green is set to: ");
Serial.println(Ans);
} Em seguida, iremos configurar os números
if ((data[0] == 'b') || (data[0] == 'B')) inteiros para manter os valores das cores
{ vermelho, verde e azul, bem como os valores para
int Ans = strtol(data+1, NULL, 10);
Ans = constrain(Ans,0,255); os pinos digitais.
analogWrite(BluePin, Ans);
Serial.print("Blue is set to: "); int red, green, blue;
Serial.println(Ans); int RedPin = 11;
} int GreenPin = 10;
} int BluePin = 9;
Uma vez que você verificou o código, enviá-lo Na nossa configuração definiremos os três pinos
para o seu Arduino. digitais para serem saídas. Mas, antes disso temos
Agora, quando você carregar o programa nada o comando Serial.begin:
parece acontecer. Isto porque o programa está
esperando por sua entrada. Inicie o “Serial void setup()
{
Monitor” clicando no respectivo ícone na barra de Serial.begin(9600);
tarefas no IDE do Arduino.
18
Serial.flush(); função Serial.available terá imediatamente
pinMode(RedPin, OUTPUT);
pinMode(GreenPin, OUTPUT); um valor superior a zero e a função if começará
pinMode(BluePin, OUTPUT); a ser executada. Se não houvesse o atraso, o
} código dentro do if começaria a ser executado
antes de toda a informação de texto ter sido
Serial.begin diz ao Arduino para começar a recebida e o dados seriais poderiam ser apenas os
comunicação serial e o número dentro dos primeiros caracteres de texto inserido.
parêntesis, neste caso 9600, define a taxa de Depois de ter esperado 100 ms, para preencher o
transmissão (caracteres por segundo) que a linha buffer serial com os dados enviados, nós então
serial irá comunicar. declaramos e inicializamos o inteiro numChar
Obs.: Você deve alterar a taxa de transmissão no para ser o número de caracteres dentro do texto.
Serial Monitor para 9600 baud. Por exemplo, se enviamos este texto para o
O comando Serial.flush irá limpar qualquer monitor: R255, G255, B255.
caractere indevido na linha de série e deixá-lo Em seguida, o valor de numChar é 17 e não 16,
vazio e pronto para a entrada/saída de comandos. como no final de cada linha de texto, onde há um
A linha de comunicação serial é simplesmente caractere invisível chamado de “NULL” . Este é
uma forma de o Arduino se comunicar com o um símbolo de vazio e simplesmente diz ao
mundo exterior, neste caso através do PC e do Arduino que o fim da linha de texto foi atingido.
IDE Arduino Serial Monitor para o hardware A próxima instrução if verifica se o valor de
construído. numChar é superior a 15 ou não e se assim se
No circuito principal, temos uma instrução if. A define como sendo de 15. Isso garante que nós
condição é verificar não estouraremos o array char buffer [18];
Depois vem um comando while. É um comando
if (Serial.available() > 0) {
que nós ainda não nos deparamos antes, então
O comando Serial.available verifica se caracteres segue a explanação.
foram enviados para a linha do monitor serial. Se Nós já usamos o laço for, que irá percorrer um
qualquer caractere foi recebido, em seguida, as determinado número de vezes numa sequência. A
condição e declarações do código dentro do bloco instrução while é também um laço, mas que
if é executada. executa somente enquanto uma condição é
verdadeira.
if (Serial.available() > 0) { A sintaxe é:
int index=0;
delay(100); // let the buffer fill up while(expression) {
int numChar = Serial.available(); // statement(s)
if (numChar>15) { }
numChar=15;
}
while (numChar--) { Em nosso código ficou como:
buffer[index++] = Serial.read();
} while (numChar--) {
splitString(buffer); buffer[index++] = Serial.read();
} }
}
A condição é verificada simplesmente através do
Um inteiro chamado index é declarado e numChar, portanto, em outras palavras, é verificar
inicializado como zero. Este inteiro vai manter a se o valor armazenado no inteiro numChar não é
posição de um ponto para os caracteres dentro da zero. Isto é conhecido como um pós-decremento.
matriz de char, como uma referência. Em outras palavras, o valor é decrementado
Em seguida, define-se um atraso de 100. O depois que é usado. No nosso caso, o loop while
propósito disto é assegurar que o serial buffer (o verifica o valor de numChar e, em seguida,
lugar na memória onde os dados são recebidos e subtraí uma unidade a partir dele. Se o valor de
armazenados antes do processamento) está cheio numChar não era zero antes do decremento, então
antes de continuar o processo com os dados. Se executa o código. Está definido para o
não fizer isso, é possível que a função execute e comprimento da seqüência de texto que entraram
começe a processar o comando enviado, antes de na janela do Monitor Serial. Assim, o código
termos enviado todos os dados. A linha de dentro do loop while irá ser executado muitas
comunicação serial é muito lenta em comparação vezes. O código dentro do laço while é:
com a velocidade do resto do código de execução.
Quando você envia uma sequência de dados, a
19
buffer[index++] = Serial.read(); Assim, nós declaramos uma variável do tipo de
dados char e chamamos de dados, mas o
Que define cada elemento da matriz tampão para símbolo *, isso significa que está apontando para
cada caractere lido a partir da linha de série. Em o valor armazenado dentro do buffer.
outras palavras, ele enche o buffer array com os Quando chamamos splitString enviamos para
dados que inserimos na janela do Serial Monitor. o seu conteúdo o buffer (na verdade o parâmetro
O comando Serial.read() lê a série de dados para ele, como vimos acima).
de entrada, um byte de cada vez.
Portanto, agora que a nossa matriz de caracteres splitString(buffer);
foi preenchida com os dados que entraram no
Serial Monitor, o while terminará assim que Então nós chamamos a função e passamos para o
numChar chegar a zero. Depois temos: seu conteúdo a matriz de caracteres do buffer.
O primeiro comando é
splitString(buffer);
Serial.print("Data entered: ");
Que é uma chamada para uma das duas funções
que criamos e chamamos de splitString(). e esta é a nossa forma de enviar dados de volta do
Essa função é descrita a seguir: Arduino para o PC. Neste caso, o comando de
impressão envia o que está dentro do parêntese
void splitString(char* data) { para o PC, através do cabo USB, onde podemos
Serial.print("Data entered: "); ler no Serial Monitor.
Serial.println(data);
char* parameter; Neste caso, já enviámos as palavras "Data
parameter = strtok (data, " ,"); entered:". O texto deve ser colocado entre
while (parameter != NULL) { aspas " ". A linha seguinte é semelhante
setLED(parameter);
parameter = strtok (NULL, " ,");
} Serial.println(data);
for (int x=0; x<16; x++) {
buffer[x]='\0'; E mais uma vez, enviou dados para o PC. Por
} exemplo:
Serial.flush();
}
R255 G127 B56
Podemos ver que a função não retorna nenhum
tipo de dado, portanto podemos ver que seu tipo Em seguida,
foi criado para anular possíveis continuidades.
Serial.println(data);
Passamos o parâmetro de uma função que é um
tipo de char(caractere) e que trataremos como de
Este comando irá enviar essa sequência de texto
dados. No entanto, nas linguagens de
para o PC e imprimi-lo na janela do Serial
programação C e C++ você não tem permissão
Monitor, se algo for digitado na janela do Serial.
para enviar uma matriz de caracteres para uma
Desta vez, o comando de impressão tem “ln” no
função. Temos que contornar isso, usando um
fim torná-lo println. Isto simplesmente significa
parâmetro. Nosso parâmetro será um asterisco (*)
impressão/imprimir na linha do Serial Monitor.
e foi adicionada ao (*) o nome de dados variáveis.
Quando imprimir utilizando o comando print, o
Parâmetros são bastante avançados no C de modo
cursor (o ponto onde o símbolo irá aparecer)
que não vamos entrar em muitos detalhes sobre
permanece no final de tudo o que tenha
eles. Tudo que você precisa saber agora é que por
imprimido.
declaração de dados como um parâmetro,
Quando usamos o comando println um
simplesmente uma variável aponta para outra
variável. comando de avanço de linha é emitido ou em
Você pode apontá-lo para o endereço que a outras palavras, as impressões de texto e, em
variável é armazenada na memória usando o seguida, o cursor cai para a linha seguinte.
símbolo &, ou em nosso caso, para o valor
Serial.print("Data entered: ");
armazenado a esse endereço de memória usando o Serial.println(data);
símbolo *. Usaremos isso para enganar o sistema,
como nós não temos permissão para enviar um Se olharmos para os nossos dois comandos de
caractere à matriz para uma função. No entanto, impressão, o primeiro imprime "Os dados
estamos autorizados a enviar um indicador para inseridos:" e então o cursor permanece no final do
uma matriz de caracteres para a nossa função.
20
texto. A próxima impressão vai imprimir os seguida, daremos um comando de fim de
dados, ou em outras palavras, o conteúdo da comando.
matriz chamado tampão e depois emitir uma linha
de alimentação, ou deixar cair o cursor para a while(parameter != NULL) {
próxima linha. Isto significa que, se emitir outra
impressão ou declaração println após isso tudo Dentro do loop que chamamos de nossa segunda
que é impresso na janela do Serial Monitor será função
exibido na próxima linha por baixo da última.
Em seguida, criamos um novo tipo de dados setLED(parameter);
char chamado parâmetro.
Que veremos mais tarde. Em seguida, ele define o
Char* parameter; parâmetro variável para a próxima parte da
seqüência para o próximo espaço ou vírgula.
e como vamos usar essa variável para acessar Fazemos isso passando para strtok um parâmetro
elementos da matriz de dados, ele deve ser do NULL
mesmo tipo, portanto o símbolo *. Você não pode
parameter = strtok(NULL, " ,");
passar dados de um tipo de variável para outro
tipo de variável, os dados devem ser convertidos Isso informa ao programa para continuar de onde
em primeiro lugar. Esta variável é outro exemplo parou.
de alguém que tem o escopo local. Pode ser visto Então, temos toda essa parte da função:
apenas pelo código dentro dessa função. Se você
tentar acessa-la fora parâmetro da variável função char* parameter;
splitString você obterá um erro. parameter = strtok(data, " ,");
Em seguida, usamos um comando strtok, que é while (parameter != NULL) {
setLED(parameter);
um comando muito útil para nos capacitar para parameter = strtok(NULL, " ,");
manipular textos de comando. strtok é a junção }
do nome de string e Token e o seu objetivo é
dividir um texto usando símbolos. No nosso caso é simplesmente a cadeia de comandos que permite
o símbolo que estamos procurando é um espaço ajustar a próxima função chamada setLED().
ou uma vírgula. Ele é usado para dividir A parte final desta função simplesmente preenche
sequências de caracteres de texto em partes o buffer com conjunto dos caracteres, que é feito
menores e legíveis ao programa. Passamos a com o “/0” símbolo que nivela e em seguida, os
matriz de dados para o comando strtok como o dados de série estão prontos para o próximo
primeiro argumento e os símbolos (incluído o conjunto de dados que poderão ser inseridos.
dentro das aspas) como o segundo argumento. Por
isso: // Clear the text and serial buffers
for (int x=0; x<16; x++) {
buffer[x]='\0';
parameter ´strtok(data,”,“); }
Serial.flush();
E ele divide a sequência nesse ponto. Portanto,
estamos a usá-lo para ajustar o parâmetro a ser a A função setLED() vai identificar cada parte da
parte da cadeia até um espaço ou uma vírgula. sequência de texto e definir o LED
Então, se a nossa cadeia de texto foi correspondente à cor que se escolher. Assim, se a
sequência de texto é:
R127 G56 B98
G125 B55
Então, após esta declaração o valor do parâmetro
será A função splitString() divide o texto em dois
componentes separados
R127
G125
O comando strtok simplesmente divide a B55
sequência digitada para a primeira ocorrência de
um espaço ou de uma vírgula. e envia essa seqüência de texto abreviado para o
Depois de ter definido o parâmetro variável para a setLED() da função, que vai lê-lo, definir o LED
parte da cadeia de texto que queremos retirar (ou que escolhido e configurá-lo para o brilho
seja, o bit do primeiro espaço ou vírgula) em correspondente do valor.
21
Então vamos dar uma olhada na segunda função inteiro (NULL) e, em seguida, a base que, no
chamada setLED(): nosso caso é base igual a 10, como estamos
usando números decimais normais (ao contrário
void setLED(char* data) { de binário, octal ou hexadecimal que seriam de
if ((data[0] == 'r') || (data[0] == base 2, 8 e 16, respectivamente). Assim, em
'R'))
{ outras palavras, declaramos uma série de
int Ans = strtol(data+1, NULL, 10); comandos que identificarão um inteiro e irão
Ans = constrain(Ans,0,255); configurá-lo para o valor de brilho do led
analogWrite(RedPin, Ans); escolhido.
Serial.print("Red is set to: ");
Serial.println(Ans); Usamos o comando constrain (restringir) para
} certificar-se que o número em Ans vai de 0 a 255
if ((data[0] == 'g') || (data[0] == e não mais que isso. Em seguida, o comando
'G'))
{ analogWrite envia para o pino de saída e o
int Ans = strtol(data+1, NULL, 10); valor de Ans. As outras duas declarações if
Ans = constrain(Ans,0,255); executam comandos idênticos ao explicado.
analogWrite(GreenPin, Ans); É necessário que se estude mais a fundo os
Serial.print("Green is set to: ");
Serial.println(Ans); comandos citados até aqui, pois têm diversas
} outras aplicações e funções diferentes, além das
if ((data[0] == 'b') || (data[0] == utilizadas até agora. Tivemos uma introdução
'B'))
{ básica de novos conceitos nestes projetos.
int Ans = strtol(data+1, NULL, 10);
Ans = constrain(Ans,0,255);
analogWrite(BluePin, Ans);
Serial.print("Blue is set to: "); Projeto 11 – Acionamento de um
Serial.println(Ans); motor CC
}
}
Este projeto trabalhará com acessórios diferentes,
Podemos ver que esta função contém três como fontes, motores, diodos, etc.
comandos muito semelhantes de if. Por isso
vamos dar uma olhada em apenas um deles, pois O que você precisa
os outros dois são quase idênticos.
int potPin = 0;
int transistorPin = 11;
int potValue = 0;
void setup() {
pinMode(transistorPin, OUTPUT);
}
void loop() { O circuito é essencialmente dividido em duas
potValue = analogRead(potPin) / 4; seções: (a) A seção 1 é o nosso potenciômetro,
analogWrite(transistorPin, potValue); que está ligado à +3,3 V e ao terra com o pino
} central de entrada no pino analógico A0. Como o
potenciômetro é giratório, a variação de
Este código é muito simples. Declaramos 3 resistência permite tensões de 0 a 3,3 V, onde o
inteiros que armazenam os valores dos pinos que valor é lido usando o pino analógico A0. (b) A
se ligam ao nosso potenciômetro, ao pino que liga
23
segunda seção é a que controla o motor. Os pinos no diodo indica o lado que se liga no terra. Ele
digitais do Arduino fornecem um máximo de filtra o fluxo a partir do lado positivo para o lado
40 mA. O motor requer em torno de 500 mA para negativo. O diodo irá funcionar como uma válvula
funcionar em alta velocidade e isto é, obviamente para impedir refluxo de corrente. O diodo em
muito alto para o Arduino. Se fôssemos tentar nosso circuito é, portanto, inserido para proteger o
conduzir o motor diretamente a partir de um pino Arduino.
do Arduino um grave e permanente dano poderia
ocorrer. Portanto, precisamos encontrar uma
maneira de fazê-lo de maneira indireta.
Este projeto controla a velocidade do motor, por
isso precisamos de uma maneira de controlar essa
tensão para acelerar ou retardar o motor. Este é o
lugar onde o transistor TIP-120 atua.
Um transistor é essencialmente um comutador
digital. Ele também pode ser utilizado como um
amplificador de potência. O símbolo eletrônico
para um transistor bipolar é mostrado a seguir:
void playTone(int tone, int duration) { Outra matriz, desta vez de números inteiros, é
for (long i=0; i < duration*1000L; configurada para armazenar o comprimento de
i+=tone*2) { cada nota.
digitalWrite(speakerPin, HIGH);
delayMicroseconds(tone);
digitalWrite(speakerPin, LOW);
delayMicroseconds(tone);
}
} E, finalmente, definir um tempo para a música a
ser tocada:
void playNote(char note, int duration) {
char names[] = { 'c', 'd', 'e', 'f', 'g',
'a', 'b', 'C' };
int tones[] = { 1915, 1700, 1519, 1432,
1275, 1136, 1014, 956 }; Em seguida, você vai perceber que nós
// Toca o tom corresponde ao nome da nota declaramos duas funções antes do nosso setup() e
for (int i = 0; i < 8; i++) {
if (names[i] == note) {
loop() . Não importa se colocarmos nossas
playTone(tones[i], duration); próprias funções, antes ou depois setup () e loop
} (). Quando o programa é executado, o código
} dentro dessas duas funções não será executado
}
antes do setup () pois ainda não chamamos essas
void setup() { funções ainda.
pinMode(speakerPin, OUTPUT); Vamos olhar para as funções de configuração e
} loop antes de olharmos para o playTone e funções
playNote. Tudo o que acontece no setup () é que
void loop() {
for (int i = 0; i < length; i++) { atribuir o alto-falante no pino (9) como uma saída.
if (notes[i] == ' ') {
delay(beats[i] * tempo); // rest
} else {
playNote(notes[i], beats[i] * tempo);
}
// Pausa entre notas No loop principal do programa, temos um if / else
delay(tempo / 2); declaração dentro de um loop for.
}
}
26
entre vibrações para produzir a frequência
desejada) o loop será executado e a duração
multiplicada por 1000 e o incremento do loop é o
valor de tonalidade multiplicado por dois.
Dentro do loop podemos observar que
simplesmente o pino conectado ao ao piezo-
elétrico tem uma ordem de sinal de saída ALTO,
espera-se um curto período de tempo, em seguida,
é enviado um sinal BAIXO, então espera-se mais Exercícios
um curto período de tempo, depois o processo é 1. Alterar as notas e batidas para fazer outras
retomado. músicas, como feliz Aniversário ou Feliz Natal.
2. Escreva um programa para fazer um tom
digitalWrite(speakerPin, HIGH); subindo e descendo do piezo, semelhante a um
delayMicroseconds(tone); alarme de carro ou sirene da polícia.
digitalWrite(speakerPin, LOW);
delayMicroseconds(tone);
27
fornece uma saída de 1 mV/0,1ºC (ou 10 mV/ºC).
Assim, para determinar a temperatura em ºC deve-
se ler a tensão em mV do terminal 2 e dividir por
10 para ter o valor de temperatura em ºC. Por
exemplo, se o terminal 2 fornece uma leitura de
tensão de 315 mV corresponderá a temperatura de
31,5ºC.
Visão do hardware
Projeto 13 – Descrição do código
O terminal 1 do CI recebe a tensão +5 V e o
terminal 3 é aterrado no pino GND do Arduino. O // Define o pino de saída do CI LM35
int outpin= 0;
terminal 2 é conectado ao pino A0 de entrada
analógica do Arduino, conforme mostra a Figura void setup()
abaixo. {
Serial.begin(9600);
}
// Laço principal
void loop()
{
int rawvolt= analogRead(outpin);
float milivolt= (rawvolt/1024.0) * 5000;
float celsius= milivolt/10;
Serial.print(celsius);
Serial.print(" graus Celsius, ");
delay(5000);
}
Montagem
Termistores
Termistores são resistores termicamente sensíveis.
Os termistores são muito utilizados em aplicações
que necessitem de uma alta sensibilidade com
mudança à temperatura, pois eles são
extremamente sensíveis a mudanças relativamente
pequenas de temperaturas.
Todavia não são lineares. A resposta da variação
de temperatura não é linear à variação de sua
resistência, mas pode-se obter a relação entre a
resistência e a temperatura para faixas pequenas
de variação de temperatura através da equação de
Steinhart-Hart.
Existem dois tipos de termistores: o PTC Como a tensão de saída Vout = VR1, temos:
(Coeficiente Positivo de Temperatura) e o NTC
(Coeficiente Negativo de Temperatura), essa
distinção é devida ao material de sua construção.
Esses dispositivos são construídos a partir de
Como Vout do circuito é igual à Vin da entrada
misturas de óxidos semicondutores, como titanato
analógica do Arduino, pode-se adaptar a equação
de bário para os PTCs e óxidos de magnésio,
e inseri-la ao código do programa para determinar
níquel, cobalto, titânio, ferro e cobre para os
corretamente o valor da resistência do NTC. Este
NTCs.
valor de resistência será utilizado na equação de
Os termistores NTC são sensíveis a variações de
Steinhart-Hart:
temperatura. Sua resistência diminui à medida que
a temperatura aumenta. Desenvolvidos com
uma tecnologia que permite tolerância de variação
de 1%.
São usados principalmente para faixas de
medições entre -55º a 150ºC. Devido ao baixo
custo e ao excelente desempenho, o termistor
NTC possui uma ampla utilização nas indústrias,
seja para refrigeração, condicionamento de ar, em Equação de Steinhart-Hart
automóveis, controle de temperatura, sistemas de Analisando o gráfico da curva resistiva
detecção e alarmes contra incêndio, dentre outras. característica de um termistor NTC 10 kΩ,
A curva que define o comportamento da observa-se que a resposta do sensor à variação da
resistência em função da temperatura tem um temperatura medida não é linear, desta forma, a
29
interpretação do sinal de entrada injetado ao
microcontrolador precisar ser tratada através de
uma equação que torne precisa qualquer
temperatura medida.
A relação entre resistência e temperatura no NTC
é dada pela equação de Steinhart-Hart:
void setup()
{
Serial.begin(9600);
}
void loop()
{
float Valor = analogRead(sensorPin);
float Volt = 5*Valor/1024;
float Res=(10000*Volt/(5-Volt));
Serial.print("Resistencia = ");
Serial.print(Res,0);
Serial.print(" ohm\n");
// Constantes da equação de Steinhart-
Hart
float a = 0.0011224922;
float b = 0.0002359132;
float c = 0.000000074995733;
float X = b*(log(Res));
float Y =
c*(log(Res))*(log(Res))*(log(Res));
float Temp = 1.0/(a + X + Y) - 273;
Serial.print("Temperatura = ");
Serial.print(Temp,2);
Serial.print(" graus C\n");
Serial.print("\n");
delay(1000);
}
30
Referências
McROBERTS, M. R. Arduino starter kit manual.
A complete beginners guide to the Arduino.
Earthshine Design, 2009.
31
Projeto 15 – Controle de 8 LEDs The “ledCount” variable specifies how many
LEDs are connected, so you can use this same
usando dois laços de repetição sketch with fewer or more LEDs if you like.
The “ledPins” variable is an “array”, which you
can think of as being like a list: in this case it’s a
list of the pins that the LEDs are connected to.
Later in the sketch we’ll refer to the list to turn
different LEDs on and off.
The “ledDelay” variable just sets the number of
milliseconds to leave each LED on for. To make
the scanner run faster, make the number smaller.
To slow it down, make the number bigger.
The setup() function is where things get
interesting. It could alternatively have been
written with a series of eight nearly identical lines,
each one using pinMode() to set one of the LED
pins to OUTPUT mode, but that’s not a
convenient way to write longer programs. Instead
it uses a “for” loop, which runs pinMode() eight
times but with a different value each time.
The first argument passed to the “for” loop sets
the name of the variable that will be used as the
“loop counter”. In this example the loop counter is
a number called “thisLed”, and it’s given a
starting value of 0.
The second argument sets the terminating
condition so the “for” loop will know when it
should stop running. The loop will keep repeating
Descrição do código itself until the condition fails, so in this case the
loop will repeat until the value of “thisLed” is
int ledCount = 8; equal to the value of “ledCount”. We’ve set
int ledPins[] = { 6, 7, 8, 9, 10, 11, 12, ledCount to 8, so it will keep running until ledPin
13 }; is equal to 8.
int ledDelay = 300;
The third and final argument is an action that the
void setup() { loop will perform each time it runs. The “++”
for (int thisLed = 0; thisLed < operator is a shorthand way of saying to take a
ledCount; thisLed++) { variable and add 1 to it, so in this case the
pinMode(ledPins[thisLed], OUTPUT);
}
“thisLed” variable will get bigger by 1 every time
} the loop executes.
When you put those three arguments together, you
void loop() { have a loop that will behave in a certain
for (int thisLed = 0; thisLed <
ledCount-1; thisLed++) {
predictable way. It starts out with a variable with
digitalWrite(ledPins[thisLed], HIGH); a value of 0, increases that value by 1 each time it
delay(ledDelay); runs, and when the value reaches 8 it stops. It’s a
digitalWrite(ledPins[thisLed], LOW); very concise way of saying “do this particular
}
for (int thisLed = ledCount-1; thisLed thing 8 times, slightly differently each time”
> 0; thisLed--) { without having to write each one out individually.
digitalWrite(ledPins[thisLed], HIGH); The loop itself is interesting, but what’s happening
delay(ledDelay);
digitalWrite(ledPins[thisLed], LOW); inside it is also interesting. You’ll see it references
} “ledPins[thisLed]”, which looks a bit confusing.
} You’ll remember that the variable “ledPins” is an
array, or list, containing a series of values.
This sketch introduces a couple of important Referencing it this way allows us to look at
concepts in programming: arrays and loops. positions in the list without having to know what
happens to be on the list in that position. Imagine
32
you have a restaurant menu with a list of dishes, cryptic at first glance, but when you break it down
and each one has a number next to it: you don’t into its major sections it’s fairly simple.
need to state the name of the dish, you can just It’s really just two more “for” loops, one after the
say “I’ll have number 4, please” because the other, that operate just like the “for” loop we
position (or number) of the entry is an easy way to looked at a moment ago.
reference that item on the menu. The first loop increments a counter to step
In arrays, the position in the list is called the forwards through the list using the “++” operator
“array index”, and it’s a number that specifies explained previously. It begins at the start of the
what position in the array we want to examine. list of LEDs, and for each one it turns it on, waits
Unlike typical restaurant menus, though, array for a delay period, then turns it off again before
indices don’t start at 1: they start at 0, so the first moving on to the next one.
position in the array is referenced as index 0. The Once the first loop finishes, the second loop
second position is index 1, and so on. begins. The second loop is almost the same, but it
So when the value of “thisLed” is 0, it’s the same runs backwards! It starts at the last position in the
as referencing “ledPins[0]”, which is position 0 list of LEDs, and each time through it uses the “”
(the first item) on the list. The original code looks operator to decrease the position value by 1. It’s
like this: like reading the restaurant menu backwards,
starting at the last item.
pinMode(ledPins[thisLed], OUTPUT); When it reaches the start of the list, the second
loop finishes and the program jumps back to the
The value for thisLed is 0 on the first pass through start to begin the first loop all over again.
the loop, so to understand what’s going on we can
imagine the variable has been replaced by its
value, like this: Projeto 16 – Controle de 8 LEDs
pinMode(ledPins[0], OUTPUT); usando apenas um laço de repetição
But of course “ledPins[0]” is really just pointing
to the first position in the list. Looking back at the To help understand how the array works, try
definition of the ledPins array, we can see that the swapping some of the values in it around. You’ll
first item on the list has a value of “6”. That see that the counter will still faithfully step
means the command that is really being executed through the list in order, and the LEDs will turn
the first pass is this: on in the order you specify in the array.
Or you could consider other ways to structure this
pinMode(6, OUTPUT); sketch. For example, think about how you could
make it scan from side to side but only use one
Then on the next pass through the loop, the value “for” loop instead of two. At first glance that may
of “thisLed” has increased to 1, so we’re seem impossible, but by thinking about how the
referencing “ledPins[1]”, which is the second item array is used as a list to step through the LEDs in
on the list. Then if you look at the second item on sequence it’s actually quite easy. For example,
the list and substitute it in, the end result is that instead of having a simple list of pins and
what will really be executed on the second pass stepping through it first one way and then the
through the loop is this: other, you could make a longer array that specifies
the complete sequence for an upandback scan, and
pinMode(7, OUTPUT); just loop over it once, like this:
Sometimes eight outputs aren’t enough! You can Output Enable: Active LOW. When pulled HIGH,
connect multiple shift registers together in a row all outputs are disabled and placed in a high
(called a “daisy chain”) so that you can pass impedance state. When pulled LOW, all outputs
values down the chain to each of the modules are enabled. For minimal pin usage this can be
individually. That way you can control 16, 24, 32, tied to GND to permanently enable the outputs,
or even more separate outputs with the same three but this will have the effect that they may start in
outputs from your Arduino. an unknown state at powerup. Connect to a digital
To daisychain multiple shift registers, begin with I/O pin of your microcontroller if you want to
the simple example above. Then connect a second explicitly enable outputs from software, otherwise
shift register so that the VCC, GND, RST, OE, connect to GND.
CLK, and LCLK connections are all linked to the
same place as the first shift register. Finally, run a Reset: Active LOW. When pulled LOW, the shift
jumper wire from the OUT connection on the first register is cleared and all stored values are lost.
shift register to the IN connection on the second Pull HIGH for normal operation. For minimal pin
shift register. usage this can be permanently tied to 5V to
Once you have two shift registers daisychained disable reset, but this will require you to explicitly
together, setting their outputs is just as easy as set all 8 bits in order to reset the outputs if they
addressing a single register except that you have are not in a known state. Connect to a digital I/O
to send two bytes of data instead of one. The first pin of your microcontroller if you want to be able
byte sent will pass down the chain to the last to reset the state with a single pulse, but generally
register, and the second byte sent will then go to it's simplest to connect to 5V.
the first register: think of it as pushing messages
down a pipe. The first one you push in will go GND: Connect to GND (0V) on your
towards the end, and the second message will go microcontroller.
in right behind it.
Using three or more shift registers follows the VCC: Connect to 5V on your microcontroller.
exact same principle: simply daisychain more Outputs A to H: Outputs to your other devices.
together linking the OUT connection of each into Can be driven LOW, HIGH, or be set into a high
the IN connection of the next in the chain, and impedance state by setting Output Enable to
send as many bytes of data as you have shift LOW.
registers in the chain.
Addendum:
Understanding Shift Register Connections