Postagem em destaque

Controle PID de Potência em Corrente Alternada - Arduino e TRIAC - Parte I

Este post é o primeiro de uma série de seis que escrevi tratando de controle de potência e PID (controle proporcional, integral e derivativo...

sábado, 28 de julho de 2012

Arduino & Educação - O início

Cumprindo quarentena depois de ter vendido minha empresa a uma multinacional, resolvi fazer uma experiência e me iniciar como professor de ensino superior. Já tinha muita experiência como instrutor, e mesmo como professor em cursos de extensão na Universidade Federal de Viçosa. Também trabalhei como técnico pesquisador na Universidade, num órgão onde havia intensa atividade de extensão rural, e onde dei alguns cursos.

Em julho de 2011 assumi a disciplina Instrumentação Industrial na FATESF, uma faculdade particular de engenharia em Jacareí. O curso forma Engenheiros de Controle e Automação. De cara vi que precisava criar práticas específicas para a turma, dado que não havia um laboratório específico para a disciplina.

Pesquisa daqui, dali, cheguei no Arduino. Bolei um kit bem versátil, que possibilitasse o desenvolvimento de diferentes práticas de instrumentação e controle, e que coubesse num orçamento que fosse aceitável para a escola.
Montei um protótipo e consegui que a escola topasse comprar 5 deles.

A partir daí, preparei um roteiro para que eu pudesse fazer com que os alunos praticassem conceitos de automação usando o kit. Uma restrição importante era que o programa do curso era bastante extenso, e, claro, Arduino não estava nesse programa, ou seja, tinha pouco tempo em classe para implementar a iniciativa.

O roteiro foi o seguinte:

- Aula teórica sobre Arduino (o que é, origem, como instalar e usar)
- Aula 01 de laboratório
  • Conexão do Arduino e uso da IDE (ambiente de programação)
  • Uso do Fritzing (software para desenho de circuitos)
  • Pisca-LED (Alô Mundo do Arduíno, Blink)
  • Semáforo de veículo com LEDs
  • Semáforo de pedestre integrado ao de veículo
- Aula 02 de laboratório
  • Sensores (temperatura e luminosidade, do kit, mais alguns que tenho)
  • Atuadores (buzzer e motor de passo)
  • Outros componentes (potenciômetro, controle remoto)
  • Comunicação serial
Nessa segunda aula, fiz diferentes roteiros, cada um numa bancada, e os alunos iam "girando", alternando entre as diferentes práticas.

Com esse roteiro, trabalhei TODOS os conceitos do programa da matéria. Cada aluno teve que apresentar um relatório de cada prática. Ao final, apliquei um exercício de avaliação, para meu controle, sem valer nota. Foram usadas 12 horas/aula, quatro horas por aula.

Os resultados que obtive foram os seguintes:
  • Presença de 100% dos alunos em todas as aulas (claro, anunciei com bastante antecedência e algum estardalhaço o que haveria)
  • Participação na aula bastante adequada, com níveis de atenção muito superiores aos das aulas teóricas
  • Todos os relatórios foram entregues por todos os alunos
  • As notas da avaliação específica foram acima de 8.
Pode parecer esquisito apresentar como resultado positivo a presença dos alunos em sala de aula. Acontece que a realidade da classe é a seguinte: faculdade paga, alunos acima dos 25, às vezes até 30 anos, que ficaram algum tempo longe da escola e estão retomando os estudos. Todos trabalham durante o dia, muitos em serviço pesado como técnicos em indústrias, a maioria com família. Ou seja, ir à aula é realmente um fardo... prá um sujeito como eu que morou dentro da universidade e ficou 5 anos por conta disso sem gastar  quase nada para estudar, morar e comer, os caras são uns heróis.

Uma outra estimativa que tomei nesse mesmo semestre foi preparar uma palestra para a Semana da Engenharia, evento promovido pela FATESF com a participação de palestrantes de lugaras como ITA e INPE.

Apresentei a palestra em dois momentos do evento, de maneira a "pegar"  tanto os alunos que estudam pela manhã quanto os da noite. Fiz uma apresentação absolutamente prática (e algo caótica, devo confessar), onde ia fazendo montagens na hora e testando junto com o público. Ao final apresentava o Massinha, um carrinho de controle remoto que, uma vez feito um trajeto, ele volta sozinho ao ponto de origem. 

Aqui, no meu outro blog, um post que fiz a respeito do evento.

O que conclui dessas duas experiências foi que o potencial do uso do Arduino como suporte para implementação de práticas de educação é enorme, e pesquisando net afora, conclui também que é muito pouco explorado, no Brasil e mundo afora. Talvez por ser uma criação relativamente recente (2007), ou por falta de iniciativas nesse sentido, o fato é que me motivei bastante a investir nesse segmento, Arduino & educação.

De lá para cá implementei outras iniciativas, como usar o Arduino em outra disciplina (Programação Estruturada para turma de engenheiros), o Arduino no Parque, fiz outras palestras em eventos e escolas etc. Mas isso é assunto para outros posts.


domingo, 22 de julho de 2012

Comandando displays de LEDs com 74HC595 - parte II

Agora, vamos ver como foi feito o software para "domar" os displays. Para isso, criei uma library do Arduino e disponibilizei, free as usual, no Google Code, é só clicar.

É uma biblioteca baseada numa outra que fiz para LEDs RGB, que também está no GC e pode ser visualizada aqui. Para saber como criar uma lib, em português, clique . Já no idioma de sir Mick Jagger, clique .

Não se esqueça de renomear os arquivos da lib, retirando o número da versão do nome. Ou então baixe o arquivo .zip da última versão.

Aqui vai a interface da lib, devidamente comentada:


class LED8SegDisplay595
{

public:

// Constructor

//   int _displayCount: number of 8 segment displays to be managed

//   int _clockPin: number of Arduino port that´s connected the clock pin of the first 595 CI (CI pin 12)

//   int _latchPin: number of Arduino port that´s connected the latch pin of the first 595 CI (CI pin 11)

//   int _dataPin: number of Arduino port that´s connected the data pin of the first 595 CI (CI pin 14)

     LED8SegDisplay595(int _displayCount, int _clockPin, int _latchPin, int _dataPin);

//   set the corresponding display mask (from now on, it will be considered common cathod)

     void setDisplayMask(byte display);

//   clear display mask

     void clearDisplayMask(byte display);    

//   show error message Er.     

     void errorMessage(int millissecs);

//   write a value in the displays

     void write(byte value);

     void write(float value, int decimalPlaces);

     int debug;    //Indicates debug mode 

     byte displayMask[8]; //=  {B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000};       

     char buf[33];

     long errMilissecs;

   private:

     int displayCount;  //Number of LEDs to manage 

     int clockPin;  //Pin connected to Pin 11 of 74HC595 (Clock)

     int latchPin;  //Pin connected to Pin 12 of 74HC595 (Latch)

     int dataPin;   //Pin connected to Pin 14 of 74HC595 (Data)

     void shiftOut(byte dataOut);

};

O uso é muito simples, abaixo um exemplo "b-a-bá":


// Exemplo b-a-bá do display de oito segmentos.



#include <Arduino.h>

// inclui a lib

#include <LED8SegDisplay595.h>



// define o display: 2 é o número de displays, 12 é o pino clock do primeiro 595, que

// está ligado ao Arduino, 8 é o pino latch do mesmo CI e o 11 é o pino dados.

LED8SegDisplay595 ls(2,12,8,11);



void setup() {

}



void loop()

{

// dããããã... 

  ls.write(1);

  delay(1000);

  ls.write(2);

  delay(1000);

  ls.write(3.1,2);

  delay(1000);

}



O método mais importante é o write, em duas versões, uma para números inteiros, e uma para float, onde vc indica o número de casas decimais que o display irá mostrar. Nesse caso, se vc especificar mais casas do que cabe no display, ele vai limitar ao número de casas que couber. Em ambos os métodos, se vc fornecer um número que não caiba no display, ele vai mostrar a mensagem 'Er.' no display. Vamos agora analisar os outros métodos importantes:
// Construtor, já explicado.

LED8SegDisplay595(int _displayCount, int _clockPin, int _latchPin, int _dataPin);

// se vc tiver displays com catodo comum em vez de anodo comum, basta chamar 
// esse método para cada display com essa característica e a lib vai considerar
// isso. Claro que a ligação será diferente, vc terá que ligar o comum desses 
// displays ao positivo do seu circuito. Quanto quiser acionar um segmento,
// o display vai "aterrar" o pino correspondente, fazendo o display funcionar.

     void setDisplayMask(byte display);

// Desliga o indicador de catodo comum
     void clearDisplayMask(byte display);    

// Mostra a mensagem "Er." durante millisecs milissegundos.

     void errorMessage(int millissecs);

// escreve um valor inteiro nos displays

     void write(byte value);

// escreve um valor float nos displays, com decimalPlaces casas decimais.
     

     void write(float value, int decimalPlaces);

Abaixo, um vídeo demostrando as várias features funcionando, para melhor entendimento do potencial do uso da lib.
Se vc montar o circuito com o sensor de temperatura indicado na segunda montagem da parte I desse post, o demo vai funcionar totalmente. Porém, se vc só ligar dois displays, sem sensor nem campainha o circuito vai funcionar da mesma forma, sem a rotina de mostrar a temperatura.

As funcionalidades são as seguintes:


  // escreve alguns números inteiros no display

  writeSomeNumbers();

  // faz uma contagem regressiva de 100 até 0, em décimos de segundo  

  reverseCounter();

  // escreve alguns números como se o display fosse catodo (+) comum. Como o display é anodo comum,

  // os números aparecem "negativos", quer dizer, vc lê o número na parte apagada do display

  reverseNumbers();

  //  escreve alguns números com ponto decimal

  writeFloat();

  // exibe a mensagem de erro.

  errorMessageOverflow();

  //  inicia a rotina de medir temperatura. Fica nela até que o circuito seja resetado ou desligado.

  temperatureAlarm();



É isso, galera. Uma limitação? A lib por enquanto só trabalha com números positivos. Alguém se habilita a "pegar daí"?

Abracadabraço!




sábado, 21 de julho de 2012

Comandando displays de LEDs com 74HC595 - parte I

A partir de uma solicitação de um frequentador do Lab de Garagem, resolvi criar um exemplo de como usar o 74HC595 para controlar, com apenas 3 portas, "infinitos" displays LED de oito segmentos. Então, hoje pela manhã no Arduino no Parque fiz o circuito e o software que descrevo a seguir.

O display é muito semelhante a esse aí do lado. Ele é é meio grandão, então tive que usar duas protoboards emendadas para conectá-lo. Usei dois displays porque só  tinha 2, mas podem ser usados até 10, ou mais se a biblioteca for alterada. O código dele é MLS-12101AHR1.
Para ligá-lo, achei um esquema na net. que segue abaixo.
Os diferentes segmentos são "numerados" de A a G. o ponto decimal, dot point, é o DP.
Vc deve ficar atento à pinagem do seu display, que varia de modelo a modelo.
Outra coisa que vc deve observar é se o seu display é anodo (-) comum ou catodo (+) comum. O meu exemplo é para anodo comum. Se for catodo comum, este deve ser ligado no (+) e não no terra como está no exemplo. A biblioteca que vou apresentar funciona com ambos os tipos de displays.



Na hora de ligar o display no CI, adote a seguinte convenção: o segmento A deve ser ligado no pino de dados Q0 do CI, o segmento B no pino Q1 e assim por diante. O ponto decimal deve ser ligado no pino Q8 do chip.
Abaixo o esquema de ligação para 2 chips, 2 displays:


Vocês podem observar que eu não liguei resistores em série com os LEDs. Eu deveria ter feito isso, para proteger os LEDs e até o Arduino, mas eu não tinha tantos resistores assim, então... mas você pode colocar, resistores e caldo de galinha não fazem mal a ninguém...
Para testar o bicho, resolvi montar um termômetro com alarme. Esquema, abaixo:


O capacitor azul tá fazendo o papel de um PT100, que foi calibrado para dar uma leitura de temperatura em graus Celsius nos displays.
Quando a temperatura passa de 30 oC, o sistema toca a campainha.

Abaixo, a foto do circuito montado.


E, por fim, o vídeo da bagaça funcionando. No próximo post, o software.






domingo, 15 de julho de 2012

O milagre da multiplicação das portas analógicas

No projeto da mesa da Mariana havia a necessidade de colocarmos sensores que permitissem que o usuário (?!?) da mesa conseguisse intervir na música e nos efeitos visuais.
Decidimos usar sensores de luminosidade (LDR-Light Dependent Resistor). São sensores baratos e eficientes, que captam a movimentação das mãos dos usuários sobre eles. Como o nome diz, eles são resistores cuja resistência à passagem da corrente varia em função da quantidade de luz que atinge a sua superfície. É encontrado em qualquer boa casa de componentes eletrônicos.



Esse é o LDR. Instalamos seis desses sensores na mesa.
Como o nosso pobre Arduino Uno não tem portas disponíveis, resolvi multiplexar também as portas analógicas, de maneira a liberar algumas delas para uso em outros circuitos.
Para isso, usei o CI CD4051, que é também fácil de encontrar e muito barato.



Abaixo o esquema do bicho:

Os pinos y0 a y7 podem ser conectados a entradas (ou saídas, ele pode também ser usado para demux, mas não é o nosso caso) analógicas ou digitais. O pino z é o pino de saída, foi conectado a alguma porta analógica do Arduino. Os pinos S0, S1 e S2 servem para selecionarmos qual porta será lida pelo pino z.
Os pinos E, Vee, gnd devem ser conectados ao terra do Arduino, e o pino Vcc ao +5V da plaquinha.

Ligando o LDR

 Como o LDR é um sensor que varia resistência e o Arduino "mede" (capta) variação de tensão, é necessário criar um circuito que transforme a variação de resistência em variação de tensão. Para isso, montou-se um  circuito divisor de tensão. Abaixo, o esquema que usaríamos se ligássemos o sensor direto no Arduíno:



Observe o circuito. Veja que o LDR é ligado em série com um outro resistor, cujo valor nem importa tanto (pode ser algo entre 220 e 10k ohms), e as extremidades dessa ligação em série são ligadas ao terra e a 5V, respectivamente. Isso significa que a queda de tensão será de 5V entre os pontos A e B.
E entre A e C? Nesse caso, a variação depende da razão entre os resistores R1 e R2.

Vac = Vab * R2 / (R1+R2)

Ex: se R1 = R2 = R temos:

Vac = Vab * R / (R+R)
Vac = 5 * 0.5 = 2.5 V

Se  R1=2R2, temos:

Vac=Vab * 2R2 / (2R2+R2)
Vac=5 * 2/3 = 3.33V

Ou seja, quanto maior o valor de R1, maior a queda de tensão Vac. Como R2 é fixo e R1 varia em função da luminosidade, teremos uma leitura tensão variando em função da luminosidade, bastando ligar o ponto C a uma porta analógica do Arduino para termos uma leitura numérica da variação de luminosidade.
A única diferença entre esse e o nosso circuito é que o sinal do ponto C dos sensores é ligado ao CI de multiplexação.

Montei então o seguinte circuito:




















O exemplo tem somente 5 sensores por facilidade no desenho da protoboard.
Para a multiplexação basta, através dos pinos s0 a s2, selecionar o sensor a ser lido em um determinado momento. A ideia é enviar ao chip usando 3 bits o número do sensor a ser lido, em seguida ler o valor da porta A5, onde está ligado o pino z do CI.

Usando esse CI vc pode multiplexar "n" portas de Arduino, ligando outros chips, como mostra a figura abaixo, onde podemos obter 64 portas analógicas sendo lidas por somente um pino analógico, usando 9 4051.



Abaixo, o código, devidamente comentado:
int r0 = 0;      //valor do pino select s0 no 4051
int r1 = 0;      //valor do pino select s1 no 4051
int r2 = 0;      //valor do pino select s2 no 4051

int sensorValue;

#define ps0 7
#define ps1 6
#define ps2 5

void setup()
{
  Serial.begin(9600);
// seta os pinos select como saída
  pinMode(ps0,OUTPUT);    
  pinMode(ps1,OUTPUT);    
  pinMode(ps2,OUTPUT);    
}

void loop()
{
  for (int i=0; i<5; i++)
  {
// pega os bits do contador e coloca nas variáveis a serem enviadas. 
    r0=bitRead(i,0);
    r1=bitRead(i,1);
    r2=bitRead(i,2);
// envia os bits para as respectivas portas select (s0 a s3 no CI)
    digitalWrite(ps0,r0);
    digitalWrite(ps1,r1);
    digitalWrite(ps2,r2);
//  em seguida, lê o valor do sensor correspondente, que vai estar disponível no pino A5    
    sensorValue=analogRead(5);
//  exibe os valores lidos, por sensor
    Serial.print(i);
    Serial.print(',');
    Serial.print(r0 | (r1 << 1) | (r2 << 2),BIN);
    Serial.print(',');
    Serial.print(sensorValue);         
    Serial.print(',');    
    delay(1000);
  }
  Serial.println("");
}

sábado, 14 de julho de 2012

Genius comentado

Tempos atrás eu fiz um Genius (game dos anos 80, vc pode conferir o bicho funcionando aqui embaixo):


A ideia é repetir uma sequência de sons e cores criadas aleatoriamente pelo jogo. Como ele tem muitas coisas interessantes em termos de software, vou fazer um post mais detalhado aqui
Esse é o circuito montado. Usei um tweeter velho desses de carro para fazer o som, ficou legal, bem alto. Um LED de cada cor, um botão correspondente a cada cor e som.

Aqui mais de perto:

E o esquema no Fritzing:












Fazer games tem os seus desafios: tem que levar em conta a ergonomia, quer dizer, montar o circuito de maneira que o jogador consiga ter acesso aos comandos. Depois, o programa tem que ser rápido e consistente, de maneira a fazer o jogador ter uma experiência adequada. Acho que ficou legal.

Vc pode ver no vídeo o "meu" Genius funcionando:



Abaixo, como prometido, o código comentado:

// biblioteca que define as frequências das notas musicais
#include <Piches.h>

// pino onde está conectado o buzzer (ou auto-falante)
#define buzzer 3

// o programa foi feito como uma máquina de estados, estes são os estados possíveis
#define waitingStart   0 // esperando o jogo começar
#define playingSeq     1 // tocando a sequencia pro usuário repetir
#define userTyping     3 // lendo a sequencia que o cara tá teclando
#define validatingSeq  4 // validando

// pinos onde estáo ligadas as teclas. Devem ser em sequencia, a menor o vermelho.
#define kred    11 
#define kyellow 10
#define kgreen  9
#define kwhite  8

//pinos onde estão ligados os LEDs. Devem ser em sequencia, o menor o vermelho.
#define lred    7
#define lyellow 6
#define lgreen  5
#define lwhite  4 

// define modo debug (=1)
#define debugging 0

// duração da nota
int interval = 500;
// intervalo entre as notas
int noSound = 200;
// guarda a sequência atual
int seq[50];
// indexador da sequência tocada
int posSeq = 0;
// indexador da sequência digitada
int posType = 0;

// estado corrente
int state = waitingStart; 

// tecla pressionada
int key = 0; 

void setup() 
{                
// seta modo dos pinos
  pinMode(lred, OUTPUT);     
  pinMode(lyellow, OUTPUT);     
  pinMode(lgreen, OUTPUT);     
  pinMode(lwhite, OUTPUT);   
  pinMode(kred, INPUT);  
  pinMode(kyellow, INPUT);  
  pinMode(kgreen, INPUT);  
  pinMode(kwhite, INPUT);  
  noSound = 0;
// inicializa gerador de números aleatórios do Arduino:
// eu uso o valor lido de uma porta analógica desconectada,
// que tem sempre algum valor devido à alta impedância dessas
// portas
  randomSeed(analogRead(0));
// faz uma "gracinha"
  demo();

  noSound = 50;
  Serial.begin(9600); 
// cria a prmeira sequência
  generateSeq();
}

void loop() {
// máquina de estados: processa os diferentes estados do programa
  switch(state)
  {
    case waitingStart:   
// reseta o intervalo
      interval = 500;
      if (debugging)
        Serial.println("waitingStart");  
// espera o usuário digitar algo        
      key = readKey(false);
// quando isso ocorre, muda o estado para o próximo
      state = playingSeq;
      return;  

    case playingSeq:
      if (debugging)
        Serial.println("playingSeq");  
// toca a sequência e seta o próximo estado
      playSeq();
      posType = 0;
      state = userTyping;
      return;
    case userTyping:
      if (debugging)
        Serial.println("userTyping");  
      key = 1;
      int ok = true;
// enquanto o usuário estiver digitando certo, fica nesse estado
      while(ok)
      {
          key = readKey(true);
// se o usuário não digitou nada, dançou          
          if (key == 0)
            break;
// toca a nota digitada pelo usuário
          play(key-(lred-kred));
// valida a tecla digitada
          ok = validateSeq(key);
          if (debugging)
          {
            Serial.print("ok=");
            Serial.println(ok);
          }
 // se ok...
          if (ok)
          {
// se o usuário terminou a sequência...
            if (posType == posSeq)
            {
// dá um intervalo de um segundo...
              delay(1000);
// aumenta o tamanho da próxima sequência 
              posSeq++;
// agora o intervalo é 5% menor
              interval = interval * 0.95;
// volta o estado para playingSeq
              state = playingSeq;
              return;
            }  
            else
            {
// usuário ainda não terminou.
              posType++;
            }            
          }
      } 
// se chegou aqui, o usuário teclou errado.
      playWrong();
      Serial.print("Voce fez ");
      Serial.println(posSeq);
// gera nova sequência
      generateSeq();
// volta o estado para o inicial
      state = waitingStart;
      return;      
  }
}

int validateSeq(int key)
{
  return (key-(lred-kred)) == seq[posType]; // (key-3) = key to LED
}

// espera e lê a tecla digitada pelo usuário. Se vallidateMilis = 1,
// retorna 0 após 3 segundos
int readKey(int validateMilis)
{
   unsigned long ms = millis();
   int value = LOW;
   while(value == LOW)
   {
     for (int i = kred; i >= kwhite; i--)
     {
       if (validateMilis)
         if ((millis() - ms) > 3000)
         {
           if (debugging)
             Serial.println("Timeout"); 
           return 0;
         }
       value = digitalRead(i);
       if (value == HIGH)
       {
         return i;
       }
     }
  }
}

// toca uma determinada nota (pitch), com uma determinada duração (duration)
void playPich(int pich, int duration)
{
  tone(buzzer, pich);
  delay(duration);
  noTone(buzzer);
}

// toca a Imperial March (tema do Darth Vader no StarWars)
void playWrong()
{
    int ritym = 500;
    for(int i = 0; i < 2; i++)
    {
      digitalWrite(lred, HIGH);
      digitalWrite(lyellow, HIGH);
      digitalWrite(lgreen, HIGH);
      digitalWrite(lwhite, HIGH);
      playPich(NOTE_A3, ritym);
      playPich(NOTE_A3, ritym);
      playPich(NOTE_A3, ritym);
      playPich(NOTE_F3, ritym * 3 / 4);
      playPich(NOTE_C4, ritym * 1 / 4);
      playPich(NOTE_A3, ritym);
      playPich(NOTE_F3, ritym * 3 / 4);
      playPich(NOTE_C4, ritym * 1 / 4);
      playPich(NOTE_A3, ritym * 2);
      playPich(NOTE_E4, ritym);
      playPich(NOTE_E4, ritym);
      playPich(NOTE_E4, ritym);
      playPich(NOTE_F4, ritym * 3 / 4);
      playPich(NOTE_C4, ritym * 1 / 4);
      playPich(NOTE_GS3, ritym);
      playPich(NOTE_F3, ritym * 3 / 4);
      playPich(NOTE_C4, ritym * 1 / 4);
      playPich(NOTE_A3, ritym * 2);
      digitalWrite(lred, LOW);
      digitalWrite(lyellow, LOW);
      digitalWrite(lgreen, LOW);
      digitalWrite(lwhite, LOW);
      noTone(buzzer);
      delay(500);
    }
}

// toca a demo
void demo()
{
  interval = 500;
  while(interval > 5)
  {
    play(lred);
    play(lyellow);
    play(lgreen);
    play(lwhite);
    interval = interval / 1.5;
  }
}

// toca uma nota, pisca o LED correspondente
void blink(int led, int pich)
{
  tone(buzzer,pich);
  digitalWrite(led, HIGH);
  delay(interval);
  digitalWrite(led, LOW);
  noTone(buzzer);
  delay(noSound);
}

// toca uma nota
void play(int pich)
{
  switch(pich)
  {
    case lred:
      blink(lred,NOTE_C4);
      break;
    case lyellow:
      blink(lyellow,NOTE_E4);
      break;
    case lgreen:
      blink(lgreen,NOTE_G4);
      break;
    case lwhite:
      blink(lwhite,NOTE_AS4);
      break;
  }  
}

// gera a sequência de notas, aleatória
void generateSeq()
{
  posSeq = 0;
  if (debugging)
    Serial.println("generateSeq");
  int note;
  for (int i = 0; i < 50; i++)
  {
    seq[i] = random(4) + 4;
    if (debugging)
      Serial.println(seq[i]);
  }
}

// toca a sequência
void playSeq()
{
  for (int i = 0; i <= posSeq; i++)
  {
    play(seq[i]);
  }
}


Controlando “infinitos” LEDs com Arduino III



Abaixo, a imagem das protoboards (foi necessário usar 2) com os CI conectados aos LEDs. Estou elaborando o projeto de uma placa para substituir as protoboards.


Os fios dos LEDs foram escolhidos conforme as cores destes. Existem também alguns outros fios de outros sensores que eu usei, falarei sobre eles em um outro post.

Uma outra coisa interessante a respeito desse CI é que ele pode operar muito rápido, até 100 Mhz. Isso é muito mais rápido do que o Arduino pode fazer, o que significa que, usando PWM, a gente poderia até controlar a intensidade de brilho dos LEDs. A lib que eu vou descrever abaixo não tem essa feature, mas é fácil de fazer. Numa versão 2.0 eu pretendo implementar isso. Se alguém quiser contribuir, é só me avisar e eu compartilho o projeto lá no Google Code.

O Software

Para gerenciar os LEDs, criei uma lib do Arduino.Para saber como criar uma, clique aqui para maiores detalhes em português ou aqui para texto em inglês do site do Arduino.

O projeto está hospedado no Google Code e vc pode pegar a última versão por aqui.

A interface (parte pública da lib) é a seguinte:

class LEDMatrix595  
 {  
   public:  
 // Constructor  
 //  int _LEDCount: number of LEDs to be managed  
 //  int _clockPin: number of Arduino port that´s connected the clock pin of the first 595 CI (CI pin 12)  
 //  int _latchPin: number of Arduino port that´s connected the latch pin of the first 595 CI (CI pin 11)  
 //  int _dataPin: number of Arduino port that´s connected the data pin of the first 595 CI (CI pin 14)  
    LEDMatrix595(int _LEDCount, int _clockPin, int _latchPin, int _dataPin);  
 //  color constants   
    int red;  
    int green;  
    int blue;  
 //  set the corresponding LED mask (from now on, it will be considered common cathod)  
    void setLEDMask(byte LED);  
 //  switch on the RGB LED corresponding colors     
    void LEDOn(byte LED, byte color);  
 //  switch off the RGB LED corresponding colors     
    void LEDOff(byte LED);  
 //  send LEDs to CIs  
    void sendLEDs();  
 //  switch off all LEDs  
    void allLEDsOff();  
 //  print LED Matriz to the serial port in binary mode, in a way to debug  
    void printMatrix();  
 //  print LED Mask to the serial port in binary mode, in a way to debug  
    void printLEDMask();  
 //  if true, it wil print matrix in serial port  
    int debug;  //Indicates debug mode        
 // Keep led values  
 //           LED mask: each number indicates where the corresponding LED data will be stored  
 //                    0 1 2 3    4  5  6    7  8    9  0  1    2  3  4    5  6    7  8  9    0  1  2    3  4  5    6  
byte matrix[10]; //= {B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000};  
 // Stores a mask indicting when a LED is common-positive (000) or common-negative (111)  
    byte LEDMask[10];//= {B00000000,B00000000,B00111111,B11111100,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000};  
   private:  
    int LEDCount; //Number of LEDs to manage   
    int CI595Count;//Number of 74HC595 necessary to manage the LEDs    
    int clockPin; //Pin connected to Pin 11 of 74HC595 (Clock)  
    int latchPin; //Pin connected to Pin 12 of 74HC595 (Latch)  
    int dataPin;  //Pin connected to Pin 14 of 74HC595 (Data)   
    void shiftOut(byte dataOut);  
    void internalPrintMatrix(byte _matrix[]);  
    void internalLEDOn(byte _matrix[], byte ledNo, byte color);  
    void internalLEDOff(byte _matrix[], byte ledNo);  
    void clearMatrix(byte _matrix[]);  
 };  

segunda-feira, 9 de julho de 2012

Controlando “infinitos” LEDs com Arduino II

A ideia deste CI é a gente mandar os dados para ele em uma forma chamada serial (um bit por vez) e ele converter para paralelo, ou seja, eu "escrevo" nele o estado de cada cor dos LED um a um e quando eu disser que acabei de mandar ele envia todos os estados de uma só vez, um para cada pino de saída (ele tem oito, então com um chip dá para controlar dois LEDs RGB mais as cores vermelha e verde do terceiro LED. O azul fica com o pino Q0 do próximo chip.

Abaixo, o esquema de ligação do 74HC595 (595 para os íntimos, que já já seremos):


Os pinos do chip, como é padrão, são numerados da forma descrita, a partir da esquerda do chanfro descendo e subindo do outro lado. Os pinos 1 a 7 são os pinos de dados Q1 a Q7. O pino Q0 é o 15. Porque será que os pinos de dados não são os de 1 a 8? Vai saber...
O pino 16 é o Vcc. Como vamos alimentar os LEDs com 3,3V, ele deve ser conectado ao 3V3 do Arduino através do barramento da protoboard. O pino 10 deve também ser ao Vcc  e o 13 ao terra.

O pino Latch ("tranca", numa tradução literal, que aliás é péssima) deve ser mantido LOW (0V) enquanto os dados estão sendo enviados. Quando terminamos de enviar os dados, deve ser mudado prá HIGH. É o pino 11 do chip; Já pino 12 é o pino Clock. Ele marca uma espécie de "batimento cardíaco" do circuito. Deve ser ligado e desligado a cada envio de dados ao CI.
O pino 14 é o pino de dados.
A conexão entre Arduino e CI fica da seguinte forma:


Arduino 595 Descrição
13 14 Serial
12 11 Clock
11 12 Latch


E o pino 9? Ele é usado para conectar um chip em outro. A ideia é que os dados são enviados ao primeiro CI e ele passa os dados ao seguinte, usando o pino 9 como saída. Este é conectado ao pino 14 do segundo CI. Os pinos 12 e 11 dos dois CI são conectados, de maneira ao latch e clock serem os mesmos para os dois CIs. Assim, podemos ter "n" CIs conectados uns aos outros, comandados por apenas 3 portas do Arduino.

Abaixo, um zoom das conexões dos CIs descritas acima.

Eu adotei as cores dos LEDs RGB para os fios ligados aos pinos  Q0 a Q8. O laranja foi usado no lugar do vermelho, prá não confundir com Vcc.










quinta-feira, 5 de julho de 2012

Controlando “infinitos” LEDs com Arduino I


Como parte de um projeto de automação de uma mesa concebida pela Mariana Lourenço, aluna de design da UNESP-Bauru, foi necessário ligar 24 LEDs RGB num Arduino Duemillanove. Para isso, precisaria de 72 portas, já que cada LED tem quatro pinos, um para cada cor e o comum, que ainda por cima pode ser positivo (catodo) ou negativo (anodo), dependendo do fabricante. Como esse Arduino tem apenas 14 portas digitais (19, se contarmos as analógicas, que podem ser usadas como digitais) e eu tinha ainda que ligar um shield MP3, seis sensores de luminosidade (LDR) e três sonares, nem se eu usasse um Arduino Mega seria possível ligar tudo nele.
Ou seja, teria que usar multiplexação.
No excelente livro Arduino Básico, capítulo 6, Contadores Binários, tem uma implementação de multiplexação para controlar LEDs usando o 74HC595, um CI barato e fácil de encontrar. A partir dos exemplos do livro, que usam um e dois desse CI para controlar 8 e 16 LEDs monocromáticos, eu construí uma lib do Arduino para controlar os LEDs RGB. Essa biblioteca pode ser facilmente adaptada para controlar LEDs monocromáticos tb.

O CI 74HC595

Esse CI permite que você, com apenas três pinos digitais do Arduino, controle até oito portas distintas. E ainda pode-se ligar mais de um em série (em tese, “infinitos”), de maneira a controlar as portas de LED que eu preciso. Abaixo, esquema do circuito com cinco LED ligados. 

Observe que os dois primeiros LED são catodo comum e os três últimos, anodo comum. Os dois resistores funcionam como limitadores de corrente para os LED.

Alguns posts interessantes...

Abaixo, alguns links para posts de Arduino do meu outro blog: