quinta-feira, 22 de dezembro de 2011

ESC com relés e controle remoto 2.4 GHz em carro infantil

-->

Minha filha mais nova tem um ano e meio. Comprei para ela um carrinho que tinha uns pedais péssimos de pedalar. Decidi remove-los e o carrinho ficou como o dos flintstones. Em seguida coloquei um lastro pra que ela apoiasse os pés e pudesse ser empurrada no carrinho. Depois  resolvi colocar um motor com todos os acessórios necessários pra transformá-lo num carro elétrico. Por ultimo adaptei um controle remoto.


O controle remoto

-->
-->
O controle remoto 2,4 Ghz de três canais para carros. Na verdade eu montei o projeto baseado no controle remoto que eu já tinha em casa. Nada impede que seja usado um controle remoto mais simples tipo aqueles de carrinhos baratos 49Khz fazendo-se é claro as devidas alterações.

O ESC 

O sinal de saída do receptor controla diretamente servomotores para controlar o motor da tração precisaria de um ESC (electronic speed control), controlador eletrônico de velocidade, tipo os usados em modelismo. O ESC recebe o sinal do receptor e o aplica através de uma etapa de potencia ao motor permitindo assim controlar a velocidade de rotação e, no caso dos carros também o sentido.




--> Como não tinha um ESC para motor escovado construí uma espécie de ESC com um microcontrolador picaxe 08M, dois relés, um mosfet e um punhado de outros componentes eletrônicos básicos. O diagrama pode ser visto ao lado.
O funcionamento é simples o picaxe, através da função pulsin lê o sinal do receptor como um valor que varia entre aproximadamente 100 e 200. O valor será zero caso o transmissor esteja desligado ou fora do alcance. Com a alavanca do controle no meio o valor lido pelo picaxe  é de aproximadamente 150 devendo, neste caso, os dois reles serem desativados. Caso o valor seja menor que 145 o picaxe aciona o rele que faz o motor girar num determinado sentido que eu vou arbitrar como anti horário, apenas para facilitar o entendimento. Se o valor for maior que 155 o outro rele é acionado fazendo o motor girar no sentido horário. O sentido de rotação correto pode ser acertado pela alteração do programa, inversão dos terminais do motor ou pela inversão da ação no transmissor.

Estrutura e motor

-->
O motor usado é de vidro elétrico reaproveitado de um antigo robô lutador de sumo. Ele foi aberto e teve seu pino removido. Foi feito um furo na tampa metálica para permitir a passagem do eixo e um corte, com o auxilio de uma serra copo, no lado onde estava o pino de modo a deixar solto o guia do pino.


-->
Uma barra roscada foi adaptada no lugar do eixo traseiro (foto ao lado). Essa barra é presa ao conjunto engrenagem e antigo guia do pino por quatro porcas em contra pressão. O motor foi então preso ao carro com uma abraçadeira em alumínio.


-->
Para controlar a direção do carro foram usados dois servos ligados em paralelo, por um a extensão em 'Y', diretamente ao receptor do controle.


 

O pequeno código pode ser visto abaixo:

symbol frente_Pin = 1  ' pino para o rele frente
symbol re_Pin = 4  ' pino para o rele re
symbol pwm_pin = 2

main: 'laco principal

 'pwmout pwm_pin,255,555

'le  pulso no piuno 4 e armazena na palavra w0
    pulsin 3,1,w1
     
    
    'debug w1 'usado para testes
 
 ' se o controle estiver desligado e valor em w1 ser zero
 ' o carro deve ficar parado
if w1 = 0  then  

     low frente_Pin
     low re_Pin
   
 'se o valor lido for menor que 140 vai para frente
 else if w1 < 145 then
 
 'ajusta o valor de w1 para a escala do pwm

    w2 = 145-w1
    w2= w2 * 45/2
    
     pwmout pwm_pin,255,w2 ' aplica o pwm ao motor
     high frente_Pin 
     low re_Pin
     
 'se o valor lido for maior que 170 vai para traz      
 else if w1 > 155 then
 
 'ajusta o valor de w1 para a escala do pwm

    w2 = w1-155
    w2= w2 * 45/2
     
     pwmout pwm_pin,255,w2 ' aplica o pwm ao motor   
     high re_Pin
     low frente_Pi
     
 'se o valor lido for estiver entre 140 e 170 para o carro 
else

     low re_Pin
     low frente_Pin
 
 endif  

goto main ' retorna para main

segunda-feira, 27 de junho de 2011

Arduino cubo LED




Cubo led não é nenhuma novidade, existem muitos tutoriais e vídeos na internet mostrando cubos 3x3x3, 4x4x4, 5x5x5, 8x8x8 e até maiores. Como me interessei pelo assunto há pouco tempo decidi começar com o 3x3x3 que é mais simples e barato apesar de, obviamente, ser mais limitado por ter menor definição.

Dois projetos postados no instructables me deram subsídio para montar meu primeiro cubo led : O 3x3x3 LED Cube (autor: portreathbeach) e o  LED Cube 8x8x8 (autor: chr) . O primeiro é montado com pic. No post o autor disponibiliza um programa em VB que pode ser usado para gerar os bytes para acionamento do cubo. Para ser usado com o arduino é preciso adaptar o programa ou  usar apenas os bytes do código gerado pelo programa. O segundo projeto, um cubo 8x8, é muito interessante e muito trabalhoso também. Nele o autor mostra passo a passo a construção tanto física como eletrônica do cubo de 512 leds, incluindo lista de componentes e a técnica usada para soldar simetricamente os leds.

Funcionameto

No cubo os leds são organizados em camadas horizontais, de modo que em uma mesma camada todos os catodos sejam unidos, e em colunas, formados pela união dos anodos três a três pelos anodos. Ligando o catodo comum de uma camada ao negativo e o anodo comum de uma coluna ao positivo o led que estiver simultaneamente na camada e na coluna escolhida acenderá.

Como cada coluna (anodos) de três leds é ligada a um pino do arduino (9 pinos) e cada camada (catodos) ligada, através de um transistor a um pino do arduino (3 pinos). Temos a seguinte dinâmica no cubo:

1- Coloca em nível alto o pino do arduino que liga ao GND, através do transistor correspondente, os catodos da camada inferior (camada 0);
2- Colocam-se em nível alto os pinos do arduino ligados aos leds da camada 0 que devem ser acesos;
3- Aguarda o tempo de exibição da camada;
4- Apaga todos os leds;
5- Repetem-se os passos anteriores para as camadas media (camada 1) e superior (camada 2).
Esse processo acontece em velocidade suficiente para parecer que leds de camadas distintas estão acesos simultaneamente.

Se chamarmos frame uma imagem "estática" exibida no cubo que seguida de outras imagens causa o efeito de movimento. O tempo de exibição desse frame é determinado pelo número de vezes que o ciclo citado acima se repete acendendo os mesmos leds nas mesmas camadas. Analisando o programa fica mais fácil entender.

Montagem

Soldar os leds é a parte que requer maior paciência para que fique o mais simétrico possível. Eu usei a técnica mostrada no segundo post mencionado acima. Ele traz muitas fotos que facilitam o entendimento.

O circuito é simples. Na matriz de contatos foram montados os 12 resistores e os 3 transistores BC548. O projeto usa 12 portas do arduino sendo 3 para polarizar os transistores responsáveis pelo GND de cada camada e 9 para as nove linhas verticais de leds.
O circuito completo pode ser visto ao lado. Os resistores ligados às bases dos transistores são de 330R e os demais são de 120R.

O Programa

O programa comentado pode ser visto abaixo.

 int camada[3] ={13,12,11};
int ledPin[9] = {1,2,3,5,6,7,8,9,10};// pinos de dados

byte aux[4] = {B00000000, B00000000, B00000000, B00000000};

                   // camada 0   camada 1  camada 2       
                                                     //012  camada
               //led  01234567   01234567   01234567   888 ultimo led de cada camada
byte efeito1[16] = { B10010010, B01000001, B00100100, B00100000,
                     B00000000, B11110111, B00000000, B01000000,
                     B00100100, B01000001, B10010010, B10000000,
                     B01001001, B01000001, B01001001, B00000000};
                     
byte efeito2[12] = { B11111111, B00000000, B00000000, B10000000,
                     B00000000, B11111111, B00000000, B01000000,
                     B00000000, B00000000, B11111111, B00100000};
                     
byte efeito3[8] = { B01011101, B01011101, B01011101, B00000000,
                    B10101010, B10101010, B10101010, B11100000};
                    
byte efeito4[16] = {B00011011, B00011011, B00011011, B00000000,
                    B11011000, B11011000, B11011000, B00000000,
                    B01101100, B01101100, B01101100, B00000000,
                    B00001101, B00001101, B00001101, B11100000};
                    
byte efeito5[32] = {B11100000, B11100000, B11100000, B00000000,
                    B11100000, B00011100, B00000011, B00100000,
                    B11111111, B00000000, B00000000, B10000000,
                    B00000011, B00011100, B11100000, B10000000,
                    B00000011, B00000011, B00000011, B11100000,
                    B00000011, B00011100, B11100000, B10000000,
                    B11111111, B00000000, B00000000, B10000000,
                    B11100000, B00011100, B00000011, B00100000};
                    
                    
byte efeito6[40] ={B00000011, B00010100, B11100000, B10000000,
                   B10010010, B01000001, B00100100, B00100000,
                   B00000000, B11110111, B00000000, B01000000,
                   B00100100, B01000001, B10010010, B10000000,
                   B01000001, B01000001, B01001001, B00000000,
                   B11100000, B00010100, B00000011, B00100000,
                   B10010010, B01000001, B00100100, B00100000,
                   B00000000, B11110111, B00000000, B01000000,
                   B00100100, B01000001, B10010010, B10000000,
                   B01000001, B01000001, B01001001, B00000000};
                   
byte efeito7[64] ={B10010000,B10010000,B10010000,B00000000,
                   B10001000,B10001000,B10001000,B00000000,
                   B11000000,B11000000,B11000000,B00000000,
                   B01001000,B01001000,B01001000,B00000000,
                   B01100000,B01100000,B01100000,B00000000,
                   B00101000,B00101000,B00101000,B00000000,
                   B00100100,B00100100,B00100100,B00000000,
                   B00001100,B00001100,B00001100,B00000000,
                   B00000100,B00000100,B00000100,B11100000,
                   B00001000,B00001000,B00001000,B11100000,
                   B00000001,B00000001,B00000001,B11100000,
                   B00001001,B00001001,B00001001,B00000000,
                   B00000011,B00000011,B00000011,B00000000,
                   B00001010,B00001010,B00001010,B00000000,
                   B00010010,B00010010,B00010010,B00000000,
                   B00011000,B00011000,B00011000,B00000000};
                    
int i =0;
int j=0;
int a =0;
int frame_time = 10;   // quantidade de iteracoes da cada frame
                                                           
void setup()                   
{
  int i;
  for(i=0;i<3;i++)
  pinMode(camada[i], OUTPUT);  // pinos como saida
  
  for(i=0;i<9;i++)
  pinMode(ledPin[i], OUTPUT);  // pinos como saida

}


void loop() // laço principal
{ 
 cubo(efeito1, 16, 10);  // vetor de efeito, qtd de bytes, numero de repeticoes de exibicao
 cubo(efeito2, 12, 10);
 cubo(efeito3, 8, 10);
 cubo(efeito4, 16, 10); 
 cubo(efeito5, 32, 10);
 cubo(efeito6, 40, 5);
 cubo(efeito7, 64, 10);
 
}  // fim do laço principal

   
 void cubo(byte *efeito, int tamanho, int repet)
 {
    while(repet > 0)
    {
         /* copia os bytes 4 a 4 para o vetor auxilias 
         na primeira iteração copia os 4 primeiros bytes do vetor efeito escolhido
         na segunda os 4 bytes seguintes
         repete até o final do vetor */
         
     for(int cnt1 =0; cnt1 < tamanho;)
      {   
       for(int cnt2 =0; cnt2 < 4; cnt2 ++)  // copia 4 bytes 
        {                                   
         aux[cnt2] = efeito[cnt1];          
         cnt1 ++;                           
        }                           
      mostra_frame();//acende os leds correspondentes aos 4 bytes         
     } 
     repet --;
   }                     
 }
 
                      
  void mostra_frame()
  {
    for(int cnt=0; cnt< frame_time; cnt++)
    {
       for(j=0; j< 3; j++) // seleciona a camada
       {
         digitalWrite(camada[j], HIGH); // polariza o transistor correspondente a camada j 
                                        // o que liga os catodos desta camadaao GND
         for(a=0; a< 8; a++) // verifica bit a bit o byte correspondente a camada ativa 
         {
           if(bitRead(aux[j] , a) == 1)  // se o bit for 1 
             digitalWrite( ledPin[7-a], HIGH); //acende o led correspondente
           else
             digitalWrite( ledPin[7-a], LOW); // se for 0 apaga
    
           if(bitRead(aux[3] , 7-j) == 1)  // verifica o bit do nono led que está no quarto byte
             digitalWrite( ledPin[8], HIGH);
           else
            digitalWrite( ledPin[8], LOW); 
        }
        delay(7);
        digitalWrite(camada[j], LOW);
      }
   }             
 }

segunda-feira, 25 de abril de 2011

Picaxe Triac





Seguindo a linha de circuitos básicos. Esta postagem trata do controle de dispositivos alimentados por tensão da rede domestica 110v ou 220v através de  um microcontrolador. Neste caso o picaxe 08M. Um triac é o componente principal da etapa de corrente alternada. Uma lâmpada é usada no exemplo mas nada impede o acionamento de outros dipositivos AC, como motores monofásicos, respeitando-se o limite de corrente no triac usado.

O circuito de força utilizado não foi concebido por mim, foi montado a partir destas informações publicadas no fórum do Arduino, onde é possível ver detalhe inclusive do layout da placa. Este circuito não controla a intensidade luminosa.


A idéia da montagem é bem simples Um potenciômetro, ligado a uma entrada analógica do picaxe, é usado para determinar o intervalo entre as piscadas de uma lâmpada incandescente comum. O desenho do circuito pode ser visto ao lado. Abaixo é mostrado o código fonte.


symbol pot_value = w1
symbol lamp_pin =  2


main: 'loop principal

READADC10 4, pot_value    ' le o valor do potenciometro ligado 
                  ' ao pino 2 e armazena em pot_value
    
high lamp_pin    'acende a lampada

pause pot_value  ' aguarda o tempo determinado pelo potenciometro

low lamp_pin     'apaga a lampada

pause pot_value  ' aguarda o tempo determinado pelo potenciometro

goto main        'fim do loop principal, retorna ao inicio


quarta-feira, 6 de abril de 2011

Arduino 8x8 leds




Existe muita coisa na internet sobre matriz de leds 8x8. Inclusive com o arduino. Mesmo assim , partindo da idéia de que quanto mais, melhor, decidi criar esta postagem que descreve a ligação de uma destas matrizes ao arduino com o auxilio de um contador  4017.
Newton C. Braga  neste artigo explica o funcionamento do contador 4017 incluindo exemplos de utilização, vale a pena.

Como o nome diz é uma matriz, naturalmente composta de linhas e colunas, cujos elementos são os leds. Numa matriz unicolor o "endereço" do led é dado por sua linha e coluna na bicolor e  na RGB é preciso determinar além da linha e coluna a cor do led. Para acendermos um determinado led(linha, coluna), julgando que o anodo está ligado ao pino linha e o catodo ao coluna, devemos ligar a linha correspondente ao positivo e a coluna ao negativo da fonte.

Nesta montagem foi usada uma matriz bicolor, entretanto o código só usa a cor vermelha. Numa outra oportunidade postarei algo que use duas cores.


Funcionamento


O 4017 tem 10 saídas. Assim que ele é ligado b0  é colocado em nível alto (+5V) e a cada pulso de clock uma das saídas subsequentes é colocada em nível alto. O ciclo se repete depois que a décima saída é colocada em nível alto, ou que o reset seja acionado, reiniciando a contagem. Aqui o 4017 é responsável pelo +5 de cada linha de led. A cada pulso de clock enviado pelo arduino ele alimenta os anodos dos diodos de uma das linhas da matriz, começando de cima.

As colunas são ligadas diretamente ao arduino que deve colocar a saída correspondente em nível baixo (0V) para acender o led cuja linha esteja sendo alimentada, com 5V, pelo 4017, conforme figura acima.
Cada caractere é armazenado em um vetor de oito bytes onde cada byte corresponde a uma linha da matriz, sempre de cima para baixo. Neste vetor '0' representa led apagado e '1' aceso.
Por exemplo, para a letra A:
  B0      0 0 1 1 1 1 1 0 0   
B1      0 1 1 1 1 1 1 1
B2      1 1 0 0 0 0 0 1 1
B3      1 1 0 0 0 0 0 1 1
B4      1 1 1 1 1 1 1 1 1
B5      1 1 0 0 0 0 0 1 1
B6      1 1 0 0 0 0 0 1 1
B7      1 1 0 0 0 0 0 1 1

Teremos o vertor: A[8] = {B00111100, B01111110, B110000011, B110000011, B111111111, B110000011, B110000011, B110000011}
 
O programa

A dinâmica do programa é a seguinte:
1.    O texto é armazenado em um vetor;

2.    O programa pega caractere por caractere compara com os caracteres disponíveis e  armazena o vetor   correspondente em uma vetor auxiliar;

3.    Cada byte, bit a bit, é armazenado em uma linha da matriz "aux" ; 

4.    A matriz aux é passada para a função que imprime no display;

5.    Para dar a idéia de deslocamento a primeira coluna da matriz aux copia a segunda, a segunda copia a terceira isso até que oitava coluna seja copiada pela sétima e receba a primeira coluna do próximo caractere ou colunas em branco enviadas pela função "apaga_coluna(n° de colunas)".  Existe, também a possibilidade de mostrar, sem deslocamento, o caractere no display atravéz do parametro modo da função escreve.
O código fonte pode ser visto abaixo.
#include <string.h>

              //  0 1 2 3 4 5 6 7
 int aux[8][8]= {0,0,0,0,0,0,0,0, //0     //poderia ter usado dois laços um para colunas outro para linhas pra fazer o mesmo
     /*  k  m */ 0,0,0,0,0,0,0,0, //1     //mas assim parece mais didatico
                 0,0,0,0,0,0,0,0,         // k linha    m columa
                 0,0,0,0,0,0,0,0,
                 0,0,0,0,0,0,0,0,
                 0,0,0,0,0,0,0,0,
                 0,0,0,0,0,0,0,0,
                 0,0,0,0,0,0,0,0};

int aux2[8][8];    // cada byte corresponde a uma linha da letra de cima para baixo        
             // linha 1          2          3           4          5          6          7          8
     byte A[8] = {B00111100, B01111110, B11000011, B11000011, B11111111, B11111111, B11000011, B11000011};            
     byte B[8] = {B11111110, B11111111, B11000111, B11111110, B11111110, B11000111, B11111111, B11111110};               
     byte C[8] = {B11111111, B11111111, B11000000, B11000000, B11000000, B11000000, B11111111, B11111111};               
     byte D[8] = {B11111100, B11111110, B11000111, B11000011, B11000011, B11000111, B11111110, B11111100};      
     byte E[8] = {B11111111, B11111111, B11000000, B11111100, B11111100, B11000000, B11111111, B11111111};                
     byte F[8] = {B11111111, B11111111, B11000000, B11111100, B11111100, B11000000, B11000000, B11000000};
     byte G[8] = {B11111111, B11111111, B11000001, B11000000, B11001111, B11000011, B11111111, B11111111};
     byte H[8] = {B11000011, B11000011, B11000011, B11111011, B11111111, B11000011, B11000011, B11000011}; 
     byte I[8] = {B11111111, B11111111, B00011000, B00011000, B00011000, B00011000, B11111111, B11111111};
     byte J[8] = {B01111111, B01111111, B00001100, B00001100, B11001100, B11001100, B11111100, B01111000};                                    
     byte K[8] = {B11000011, B11000111, B11001110, B11111100, B11111100, B11001100, B11000111, B11000011};         
     byte L[8] = {B11000000, B11000000, B11000000, B11000000, B11000000, B11000000, B11111111, B11111111};
     byte M[8] = {B11000011, B11100111, B11111111, B11011011, B11011011, B11000011, B11000011, B11000011};  
     byte N[8] = {B11000011, B11100011, B11110011, B11111011, B11011111, B11001111, B11000111, B11000011};  
     byte O[8] = {B01111110, B11111111, B11000011, B11000011, B11000011, B11000011, B11111111, B01111110};
     byte P[8] = {B11111110, B11111111, B11000011, B11111111, B11111110, B11000000, B11000000, B11000000};           
     byte Q[8] = {B01111110, B11111111, B11000011, B11000011, B11001011, B11000111, B11111110, B01111101};      
     byte R[8] = {B11111110, B11111111, B11000011, B11000010, B11111100, B11111110, B11000111, B11000111};     
     byte S[8] = {B11111111, B11111111, B11000000, B11111111, B11111111, B00000011, B11111111, B11111111};
     byte T[8] = {B11111111, B11111111, B00011000, B00011000, B00011000, B00011000, B00011000, B00011000};
     byte U[8] = {B11000011, B11000011, B11000011, B11000011, B11000011, B11000011, B11111111, B01111110};
     byte V[8] = {B11000011, B11000011, B11000011, B11000011, B11000011, B01100110, B00111100, B00011000};
     byte X[8] = {B11000011, B11100111, B01100110, B00011000, B00011000, B01100110, B11100111, B11000011};
byte ponto[8] =  {B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00011000, B00011000};
byte coracao[8]= {B01100110, B11111111, B11111111, B11111111, B11111111, B01111110, B00111100, B00011000}; 
byte espaco[8] = {B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000, B00000000}; 


int cont = 0;

int ckPin = 13;                // clock para o contador
int displayPin[8] = {12,11,10,9,8,7,6,5};// pinos de dados
int rstPin = 3;    // reset contador

void setup()                   
{
  int i;
  
  pinMode(ckPin, OUTPUT);      
  pinMode(rstPin, OUTPUT);
  
  for(i=0;i<8;i++)
  pinMode(displayPin[i], OUTPUT);  // pinos com saida

}
char *frase ={"TECNOMELQUE.BLOGSPOT.COM  "};  // texto a ser mostrado  {"AABBCC"};
int t =0;
void loop()                     //inicio programa principal     n
{
 t =0;
 while(t < strlen(frase))
  {                            // envia letra por letra da frase para funcao escreve
  escreve(frase[t], 1, 100);  // caracte, modo 0 apenas mostra 1 desloca, tempo 
  
  apaga_coluna(2); // espaco entre letras passa quantidade de colunas
  t++;
  }
  apaga_coluna(8);
  escreve('~',0,1000);
  delay(500);
  escreve('~',0,1000);
  delay(500);
  escreve(' ',0,100);

  
 
}  //fim da funcao principal

//////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

  void escreve(char letra, int modo, int tmp){
  int k;
  byte *Lt;
  
  switch(letra)   // compara a letra e armazena o vetor correspondente em Lt 
  {
  case 'A':
  Lt=A;
  break;
  
  case 'B':
  Lt=B;
  break;
  
 case 'C':
 Lt=C;
 break;

  case 'D':
 Lt=D;
  break;
  
  case 'E':
Lt=E;
  break;
  
  case 'F':
Lt=F;
  break;
  
  case 'G':
Lt=G;
  break;
  
  case 'H':
Lt=H;
  break;
  
  case 'I':
 Lt=I;
  break;
  
  case 'J':
Lt=J;
  break;
  
  case 'K':
Lt=K;
  break;

  case 'L':
 Lt=L;
  break;
  
  case 'M':
  Lt=M;
  break;
  
  case 'N':
  Lt=N;
  break;
 
  case 'O':
  Lt=O;
  break;
  
  case 'P':
  Lt=P;
  break;
  
  case 'Q':
Lt=Q;
  break;


  case 'R':
Lt=R;
  break;

  case 'S':
Lt=S;
  break;
  
  case 'T':
Lt=T;
  break;
  
  case 'U':
Lt=U;
  break;
  
  case 'V':
Lt=V;
  break;
  
 case 'X':
Lt=X;
  break;

  case '.':
  Lt=ponto;
  break;
  
  case '~':
 Lt=coracao;
  break;
  

 case ' ':
 Lt=espaco;
  break;

 }
  

 //copia o caracter para aux
 // bit por bit é armazenado na matriz aux
   for(int i=0; i<8;i++)
   {
     for(int j=0; j<8;j++)
     {
      if(modo == 0)
      aux[i][j] = bitRead(Lt[i], 7-j); 
      else
       aux2[i][j] = bitRead(Lt[i], 7-j); 
     }
   }

  if ( modo == 0)  // mostra ccaracter
 {
    imprime(tmp);
  }
  else if( modo == 1)  // modo 1 desloca caracter anterior
  {
    
  cont = 0;
   
  for (int passo =0; passo <8; passo++)
  {
    
  for(k=0; k<8; k++)  // linhas
  {
    
  for(int m=0; m < 7;  m++)   
  {
    
   aux[k][m] = aux[k][m+1];

  }
   aux[k][7] = aux2[k][cont];   // ultima coluna de aux recebe a primeira coluna de  E
  }
  
  cont ++; 

  imprime(tmp);  // mostra no display

  } //fim da contagem de passos
} // fim de escreve letra

  }
  
 
   

//////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

void apaga_coluna(int qtd)
{
 int k;
  
for (int passo =0; passo <qtd; passo++)
  {
    
  for(k=0; k<8; k++)  // linhas
  {
    
  for(int m=0; m < 7;  m++)   
  {
    
   aux[k][m] = aux[k][m+1];

  }
   aux[k][7] = 0;   // ultima coluna de aux recebe a primeira coluna de  E
  }
  
  cont ++;
 
  imprime(100);  // mostra no display

 } //fim da contagem de passos

} //fim apaga coluna

//////////////////////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////////////

 void imprime(int tmp)
 {
 // int tmp = 100;

  for(int a=0; a < tmp; a++)   // tmp representa a quantidades de vezes que cada caracter é exibido
  {     
  digitalWrite(rstPin, LOW); // prepara para reset do contador
  
    for(int i =0; i<8; i++) // linhas
    {
     digitalWrite(ckPin, LOW); // como a mudança ocorre na descida do clock esta linha so faz sentido no segund ciclo
  
   for(int j=0;j<8;j++)   // colunas
  {
      if(aux[i][j] == 1) 
      {
       digitalWrite(displayPin[j], LOW);
      }
     else
     {
     digitalWrite(displayPin[j], HIGH);
     }
  }
    
  delay (0.5); // entre linhas
  
   for(int i=0;i<8;i++)                    // apaga a linha
   digitalWrite(displayPin[i], HIGH);
 
  digitalWrite(ckPin, HIGH); 
   
 }
 
  digitalWrite(rstPin, HIGH);  // reset do contador
 
 }  
 }
 

quinta-feira, 10 de março de 2011

Picaxe 08M - Display de sete segmentos

Se preferir assista no youtube.

O display de sete segmentos é muito usado em circuito com microcntroladores. Esta postagem mostra como ligá-lo ao picaxe 08M com o auxilio do shift register 74hc595, já que este picaxe possui apenas quatro pinos que podem ser usados como saída.

A postagem "Arduino dimmer com display de sete segmentos" traz alguns detalhes sobre o display de sete segmentos que serão úteis nesta montagem. Os dígitos serão formados a partir da mesma tabela, acrescentando-se um zero à direita do bit menos significativo de cada número da tabela para completar o byte. 

O 08M envia cada byte, bit a bit, para o 7495 que tem suas oito saídas ligadas ao display. A saída Q7 foi ligada ao pino correspondente ao ponto. Um bom tutorial sobre o shift register pode ser encontrado no site do arduino. Basicamente para usá-lo é preciso três sinais: um clock para o shift, um clock para o latch e o terceiro deve conter o bit de dado.

O Programa

Para formar um número no display são enviados oito bits através do pino "out0" do picaxe, denominado aqui como dataPin. Por exemplo, para formar o número zero, considerando 1 para segmento aceso e 0 para apagado, temos que enviar o byte "11111100" que corresponde, em decimal, a 252. O programa  segue a sequência abaixo:

1 - Armazena o byte em "b0" que começa no bit 0 e termina no bit 7;
2 - Coloca o clock do latch em nível baixo;
3 - Coloca o clock do shift em nível baixo. Preparando-o para a passagem do bit que acontece na mudança   do clock do nível baixo para o alto (0 para 1);
4 - Verifica o estado do bit0, que neste caso é 0 colocando o dataPin em nível baixo;
5 - Coloca o clock do shift em nível alto. O bit0 vai para a saída do primeiro registrador do shift que também é a entrada do segundo;
6 - Os paços 3 , 4 e 5 se repetem para os outros sete bits. Cada vez que um bit é adicionado os outros são "empurrados" para o registrador seguinte;
7 - Após completar o envio dos oito bits coloca o clock do latch em nível alto fazendo com que todos os bits apareçam na saída do CI, mostrando assim o dígito no display.


symbol dataPin = 0  ' pino do dados seriais

symbol latchPin = 2  ' clock do latch apos ter todos os dado vai a nivel alto para mostrar na saida

symbol shiftPin = 1  ' clock do registrador de deslocamento

symbol cnt1 = b1

symbol dados = b0


main: 'laco principal


   for b4=0 to 9
   
'lookup armazena o numero que esta na posicao b4 na variavel "dados"

             '0   1  2   3   4   5   6   7   8   9
   lookup b4,(252,96,218,242,102,182,190,224,254,246),dados
   
   low latchPin 'clock do latch em nivel baixo

      for cnt1 =0 to 7 
    
        low shiftPin   'clk do shift em nivel baixo 
        
    
  ' a cada passagem verifica se o bit correspondente
  ' é zero ou um e coloca a saida em nivel alto ou baixo respectivamente  
  
      select cnt1
    
    case 0
    {
     if bit0 = 1 then
         
        high dataPin
     else
       low dataPin
     endif 
    }
    
    case 1
    {
     if bit1 = 1 then
         
        high dataPin
     else
       low dataPin
     endif 
    }
    
    
    case 2
    {
     if bit2 = 1 then
         
        high dataPin
     else
       low dataPin
     endif 
    }
    
    
    case 3
    {
     if bit3 = 1 then
         
        high dataPin
     else
       low dataPin
     endif 
    }
   
    case 4
    {
     if bit4 = 1 then
         
        high dataPin
     else
       low dataPin
     endif 
    }
    
    case 5
    {
     if bit5 = 1 then
         
        high dataPin
     else
       low dataPin
     endif 
    }
    
    case 6
    {
     if bit6 = 1 then
         
        high dataPin
     else
       low dataPin
     endif 
    }
    
    case 7
    {
     if bit7 = 1 then
         
        high dataPin
     else
       low dataPin
     endif 
    }
    
    endselect
        
      
       high shiftPin 'clk shift pin em nivel alto envia o bit para o proximo registrador
    
      next cnt1

   high latchPin 'clock do latch apos ter todos os dado (8 bits)
                'vai a nivel alto para mostrar na saida do 7495
                
    pause 945   'entre numeros
    
    next b4     ' fim do laco for

    
goto main ' fim do laco pricipal

terça-feira, 8 de março de 2011

Picaxe PWM



Se preferir assista no youtube.

Alguns circuitos são básicos para muitas montagens mecatrônicas, controlar a velocidade de rotação de um motor de corrente continua por PWM é um deles. O circuito mostrado aqui usa um potenciômetro ligado a uma entrada analógica de um Picaxe 08M (conversor AD de 10 bits), como usado na montagem com servomotor, para controlar a rotação de um motor DC.


O sinal PWM gerado no picaxe é aplicado ao gate do MOSFET IRF540, através do acoplador óptico 4n25. O diagrama completo do circuito é mostrado ao lado. Um resistor de 330R é usado para limitar a corrente no led do 4n25. O resistor ligado entre  o gate do mosfet e o GND é de 10k. O potenciômetro pode ser de qualquer valor.

Para testar o circuito foi usada uma pequena furadeira que em 12V tem corrente,  à vazio,  menor  que  1A, mas o mosfet usado pode suportar correntes superiores a 10A respeitando-se, é claro, as recomendações do datashet para limite de corrente que além das características eletrônicas do componente é influenciado pelo tipo de dissipador adotado.

O programa

No código, mostrado abaixo, o valor do potenciômetro é lido  0 - 1023 e aplicado ao pino 4 através da função "pwmout" que precisa de três parâmetros: pino (pino de saída do sinal), período (período do sinal, 0 a 255) e ciclo de trabalho  (grosseiramente falando é o valor do PWM, 0 a 1023).

symbol pot_value = w1

symbol motor_pin =  2

main: 'loop principal

READADC10 4, pot_value ' le o valor do potenciometro 

pwmout motor_pin,255,pot_value ' envia o valor para o pino 2

goto main 'fim do loop principal

sábado, 26 de fevereiro de 2011

Wii Nunchuk, arduino e labirinto de madeira





Visitando o site instructables  que, diga-se de passagem, é um site muito bom, encontrei o projeto Servo Controlled Labyrinth by nivini . Decidi então, tendo como referência a ideia do autor, montar o jogo usando o arduino e o nunchunk para controlar o tabuleiro. Como não tinha  o jogo tradicional montei meu próprio tabuleiro usando duas caixas em mdf e quatro pedaços de compensado 4mm além de outras pequenas peças adaptadas de matérias disponíveis em casa, o que rendeu um pouco mais de trabalho, mas nada exagerado. Se você já tiver o labirinto pode montar toda a parte física como no projeto original, o que torna as coisas mais fáceis.

O labirinto
 
Para a confecção do labirinto usei uma caixa em MDF de 25cm x 25cm e a  tampa de outra caixa em MDF  20cm x 20cm, onde foi montado o labirinto propriamente dito com  pedaços das peças de um pega varetas "gigante" (5mm de diâmetro), um brinquedo abandonado por minha filha de três anos. Quatro pedaços de compensado serviram para fazer o quadro intermediário. Neste quadro foi fixado o primeiro servo que tem seu eixo preso no centro de uma das laterais da tampa 20x20 e é responsável pelo movimento no eixo Y. O segundo servo, que é  responsável pelo movimento no eixo X, é fixado à caixa maior e tem seu eixo preso em uma das laterais do quadro intermediário de modo a ficar perpendicular ao primeiro servo.

O código

O código, que pode ser visto abaixo, foi adaptado do código encontrado neste site: http://www.windmeadow.com/node/42 .
Eu substitui a parte do código que imprime os valores na tela pelo controle dos servos. Pra melhora a estabilidade o código faz uma media dos últimos 20 valores lidos, ajusta a escala e aplica os resultados aos servos.


 /*  
  * NunchuckPrint  
  *  
  * 2007 Tod E. Kurt, http://todbot.com/blog/  
 BRANCO------ GND  
 AZUL-------- SCL pino analogico 5  
 VERMELHO---- +3.3V  
 VERDE------- SDA pino analogico 4  
  */  
 #include <Wire.h>  
 #include <Servo.h>   
 Servo servo_y; // create servo object to control a servo   
 Servo servo_x; // create servo object to control a servo   
 #define m_movel 20 // quantidade de leituras para media  
 int media_leit_y =0;   
 int media_y_aux =0;  
 int aux_soma_y = 0;  
 int aux_m_y[m_movel];  
 int media_leit_x =0;   
 int media_x_aux =0;  
 int aux_soma_x = 0;  
 int aux_m_x[m_movel];  
 void setup()  
 {  
  servo_x.attach(9); // attaches the servo on pin 9 to the servo object   
  servo_y.attach(10);  
  Serial.begin(19200);  
  nunchuck_setpowerpins(); // use analog pins 2&3 as fake gnd & pwr  
  nunchuck_init(); // send the initilization handshake  
  Serial.print ("Finished setup\n");  
  for(int i=0; i < m_movel; i++)  
  {  
  aux_m_y[i] =0;  
  aux_m_x[i] =0;  
  }  
 }  
 void loop()  
 {  
  nunchuck_get_data(); // lê dados   
  aciona_servos();   // envia-os para os servos  
  delay(5);  
 }  
 //  
 // Nunchuck functions  
 //  
 static uint8_t nunchuck_buf[6];  // array to store nunchuck data,  
 // Uses port C (analog in) pins as power & ground for Nunchuck  
 static void nunchuck_setpowerpins()  
 {  
 #define pwrpin PORTC3  
 #define gndpin PORTC2  
   DDRC |= _BV(pwrpin) | _BV(gndpin);  
   PORTC &=~ _BV(gndpin);  
   PORTC |= _BV(pwrpin);  
   delay(100); // wait for things to stabilize      
 }  
 // initialize the I2C system, join the I2C bus,  
 // and tell the nunchuck we're talking to it  
 void nunchuck_init()  
 {   
  Wire.begin();             // join i2c bus as master  
  Wire.beginTransmission(0x52);     // transmit to device 0x52  
  Wire.send(0x40);          // sends memory address  
  Wire.send(0x00);          // sends sent a zero.   
  Wire.endTransmission();     // stop transmitting  
 }  
 // Send a request for data to the nunchuck  
 // was "send_zero()"  
 void nunchuck_send_request()  
 {  
  Wire.beginTransmission(0x52);     // transmit to device 0x52  
  Wire.send(0x00);          // sends one byte  
  Wire.endTransmission();     // stop transmitting  
 }  
 // Receive data back from the nunchuck,   
 int nunchuck_get_data()  
 {  
   int cnt=0;  
   Wire.requestFrom (0x52, 6);     // request data from nunchuck  
   while (Wire.available ()) {  
    // receive byte as an integer  
    nunchuck_buf[cnt] = nunchuk_decode_byte(Wire.receive());  
    cnt++;  
   }  
   nunchuck_send_request(); // send request for next data payload  
   // If we recieved the 6 bytes, then go print them  
   if (cnt >= 5) {  
    return 1;  // success  
   }  
   return 0; //failure  
 }  
 void aciona_servos()  
 {   
  for(int cnt = m_movel-1; cnt > 0; cnt --)  
  {  
  aux_m_y[cnt] = aux_m_y[cnt-1];  
  aux_soma_y = aux_soma_y + aux_m_y[cnt];  
  aux_m_x[cnt] = aux_m_x[cnt-1];  
  aux_soma_x = aux_soma_x + aux_m_x[cnt];  
  }  
  int joy_x_axis = nunchuck_buf[0];  
  int joy_y_axis = nunchuck_buf[1];  
  int z_button = nunchuck_buf[5] & 1;  
  int c_button = nunchuck_buf[5] >> 1 & 1;  
  int accel_x_axis = (nunchuck_buf[2] << 2) + ((nunchuck_buf[5] >> 2) & 0x03);  
  int accel_y_axis = (nunchuck_buf[3] << 2) + ((nunchuck_buf[5] >> 4) & 0x03);  
  int accel_z_axis = (nunchuck_buf[4] << 2) + ((nunchuck_buf[5] >> 6) & 0x03);  
  // media eixo Y ////  
  aux_m_y[0] = accel_y_axis;  
  aux_soma_y = aux_soma_y + aux_m_y[0];   
  media_y_aux = aux_soma_y /m_movel;  
  aux_soma_y = 0;  
  media_leit_y = constrain(media_y_aux, 375, 595);  
  media_leit_y = map(media_leit_y, 375, 595, 110, 70);  
  // media eixo X ////  
  aux_m_x[0] = accel_x_axis;  
  aux_soma_x = aux_soma_x + aux_m_x[0];   
  media_x_aux = aux_soma_x /m_movel;  
  aux_soma_x = 0;  
  media_leit_x = constrain(media_x_aux, 375, 595);  
  media_leit_x = map(media_leit_x, 375, 595, 70, 110);  
  servo_y.write(media_leit_y);       // tell servo to go to position in variable 'pos'   
  servo_x.write(media_leit_x);   
   }  
 char nunchuk_decode_byte (char x)  
 {  
  x = (x ^ 0x17) + 0x17;  
  return x;  
 }  



segunda-feira, 14 de fevereiro de 2011

Picaxe, Servo e potenciômetro



Na ultima postagem sobre o Picaxe comentei que pretendia compra um para testá-lo e aprender sobre ele. Pois bem, comprei um 08M, o mais simples de todos com exceção do picaxe 08.

A montagem que descrevo aqui é bastante simples, mas não deixa de ser útil para aqueles, que como eu, estão começando a programar o picaxe. A idéia é receber o sinal 0 a 5v de um potenciômetro através de uma entrada analógica que em 10 bits  retorna um valor de 0 a 1023  (2^10 = 1024 valores possíveis), mudar esse valor para uma escala de 75 a 225 e  usando a função  "servopos  pino, valor”,  aplicá-lo ao servo  ligado ao pino 4 do picaxe através de um resistor de 330R, recomendado pelo manual.

O diagrama é mostrado no vídeo. Dependendo da marca do servo utilizado existe uma variação das cores dos fios de conexão. O positivo normalmente é vermelho o negativo preto ou marrom e o fio de sinal amarelo ou branco. Pra garantir é melhor pesquisar pelo modelo do servo. O potenciômetro pode ser de qualquer valor.
Um cuidado especial deve ser tomado com a alimentação do picaxe. Inverter positivo e negativo significa queimá-lo. Não é aconselhável, também, usar tensões acima de 5v.

O código:


symbol pot_value = w1
symbol servo_value = w2

init: servo 4,75 ; inicializa o servo

main: 'loop principal

READADC10 2, pot_value    ' le o valor do potenciometro ligado ao pino 2 e armazena em pot_value

pot_value = pot_value * 5 / 34  ' mudando da escala lida no pot 0 - 1023 para 75 a 225 aprox

servo_value = pot_value + 75 
   
servopos 4,servo_value 'manda o valor para o servo no saida 4 do picaxe (pino 3 do CI)

goto main 'fim do loop principal

quarta-feira, 26 de janeiro de 2011

Robô bípede com arduino


Se preferir assista no youtube.

Assistindo vídeos no Youtube encontrei muitos robôs feitos com servomotores. Alguns mais simples outros muito sofisticados como o BIOLOID e o I-SOBOT que, são  produzidos por empresas e vendidos por  preços que giram em torno dos US$1500, passando facilmente disto dependendo do modelo e dos assessórios. Os modelos comerciais aparentam ser bastante flexível principalmente o BIOLOID que pode assumir diversas formas dependendo da criatividade do dono. Dos aparentemente caseiros, este me chamou a atenção. A estrutura física do que eu construí foi baseada no robô deste video.


A estrutura física foi o que deu mais trabalho. Basicamente a peça é desenhada  impressa e colada numa chapa fina de alumínio, cortada e dobrada. Os servos foram fixados com parafusos. As partes articuladas usam parafuso, porca e contra porca para manter a folga.








 O código, que foi feito apenas para ver o "bicho" funcionando, é mostrado abaixo. Ele  faz o robô andar para frente, retorna à direita, anda novamente para frente e anda para traz. A idéia básica para fazé-lo andar para frente é mandar o mesmo sinal para servos paralelos em cada perna. Por exemplo: servo 1 da perna um e servo 1 da perna 2 recebendo o mesmo sinal simultaneamente.

O manual da shield incluindo a biblioteca pode ser visto neste site.

Estou pretendendo acrescentar mais servos e alguns sensores. Se tudo der certo eu posto os resultados.
Vou tentar também fazer um passo-a-passo para auxiliar alguém que queira montar  o robô.

int pe1 = 14; // motor 1 da perna esquerda ( de baixo para cima)  
 int pd1 = 15; // motor 1 da perna direita ( de baixo para cima)  
 int pe2 = 13; // motor 2 da perna esquerda ( de baixo para cima)  
 int pd2 = 12; // motor 2 da perna direita ( de baixo para cima)  
 int i = 1500;  
 int a = 1500;  
 #include <ServoShield.h>  // inclui a biblioteca ServoShield que deve ser baixada e adicionada a pasta libraries do arduino  
 ServoShield servos;  //Cria um objeto ServoShield  
 void setup()  
 {  
  servos.start();   
  for (int servo = 0; servo < 16; servo++)//inicializa todos os servos  
  {  
   servos.setbounds(servo, 500, 2500); //seta a faixa de pulso maximo e minimo  
   servos.setposition(servo, 1500);  // todos os servos na posição central  
  }  
  delay(2000);  
 }  
 void loop() // laco pricipal  
 {  
  for(int a = 0; a < 7; a ++) //frente  
  {  
 inclina_esq();  
 pd_frente();  
 inclina_dir();  
 pe_frente();  
  }  
  descansar();  
 for(int a = 0; a < 10; a ++) //roda a direita  
  {  
 inclina_esq();  
 pd_frente();  
 desenclina_esq();  
 pe_frente();  
  }  
 for(int a = 0; a < 7; a ++) //frente  
  {  
 inclina_esq();  
 pd_frente();  
 inclina_dir();  
 pe_frente();  
  }  
  descansar();  
 for(int a = 0; a < 7; a ++) //re  
  {  
 inclina_esq();  
 pe_frente();  
 inclina_dir();  
 pd_frente();  
  }  
  descansar();  
 } // fim do laco pricipal  
 void inclina_esq() // inclina para esquerda  
 {  
 for(; i <= 1730; i++)    
 {  
  servos.setposition(pe1, i);  
  servos.setposition(pd1, i);  
  delay(1);  
 }  
 }  
 void desenclina_esq()  
 {  
 for(; i >= 1500; i--)   
 {  
  servos.setposition(pe1, i);  
  servos.setposition(pd1, i);  
  delay(1);  
 }  
 }  
 void inclina_dir()  // inclina para direita  
 {  
 for(; i >= 1270; i--)   
 {  
  servos.setposition(pe1, i);  
  servos.setposition(pd1, i);  
  delay(1);  
 }  
 }  
 void pd_frente() // pe direito a frente   
 {  
  int aux = a + 700;  
  if (aux > 1900)  
  aux = 1900;  
  for(; a <= aux ; a++)    
 {  
  servos.setposition(pe2, a);  
  servos.setposition(pd2, a);  
  delay(1);  
 }  
 }  
 void pe_frente() // pe esquerdo a frente  
 {  
  int aux = a - 700;  
  if (aux < 1100)  
  aux = 1100;  
  for(; a >= aux; a--)   
 {  
  servos.setposition(pe2, a);  
  servos.setposition(pd2, a);  
  delay(1);  
 }  
 }  
 void descansar() // coloca suavemente todos os servor na posicao central 1500  
 {   
  int pos;  
  int cnt = 0;  
  int aux[16]= {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};  
  while(cnt != 16)  
  {  
  for (int servo = 0; servo < 16; servo++)  
  {  
  pos = servos.getposition(servo); // pos recebe a posicao atual do servo   
  if(pos > 1500)  
   pos--;  
  else if(pos < 1500)  
   pos++;  
  else if(aux[servo] != 1)  
  {  
  aux[servo] = 1;  
  cnt ++;  
  }  
  servos.setposition(servo, pos);  
  }  
  delay(1); // determina o qual lento é o movimento de retorno a posicao inicial  
 }  
  i = pos;  
  a = pos;  
 }  

quarta-feira, 5 de janeiro de 2011

Arduino dimmer com display de sete segmentos



A idéia é controlar o brilho de uma lâmpada com um potenciômetro ligado ao arduino mostrando o nível de luminosidade numa escala de zero a nove num display de sete segmentos. O display deve ficar aceso apenas enquanto estiver sendo feito ajuste pelo potenciômetro, apagando alguns segundos depois.

O display de sete segmentos

O funcionamento do display é bem simples. Os sete segmentos são formados por leds e para formar o caractere desejado basta acender os leds correspondentes. Em alguns displays existe um oitavo led que é um ponto na extremidade inferior esquerda. Existem displays com anodo comum ou catodo comum, lembrando que para acender um led o catodo deve ser ligado no negativo e o anodo no positivo. O que quer dizer que no caso do catodo comum este deve ser ligado ao pólo negativo e, logicamente, para acender o segmento desejado a saída correspondente do arduino deve ser colocada em nível alto. O inverso vale para o display de anodo comum.
A tabela ao lado mostra a relação entre o número formado e os segmentos que devem ser acesos.

O programa não tem nada de complicado.
Cada conjunto que representa um número foi armazenado em um vetor de bytes "sete_seg".
O potenciômetro é lido através da entrada analógica 0, o valor é armazenado na variável "val" que tem sua escala alterada para que seja compatível com PWM (0 a 255) e é aplicado ao pino 10 no qual esta ligado o circuito de acionamento da lâmpada A função escreve() é chamada passando um número de 0 a 9 proporcional ao PWM. A função escreve() pega o byte correspondente no vetor "sete_seg" lê bit a bit colocando em nível alto ou baixo o pino do segmento correspondente conforme os uns e zeros lidos respectivamente.

O circuito de acionamento da lâmpada dicróica 12V, 50W,  é formado basicamente por um MOSFET  IRF540 e um opto isolador 4N25, foi montado a partir do diagrama  deste site.

O código usado pode ser visto abaixo.
Se quizer pode baixa-lo aqui.

//     __a__
//   f|     |b
//    |__g__|
//   e|     |c
//    |__d__|
 
  
int sete_seg[7] = {8,7,6,5,4,3,2};  // pinos ligados ao display de 7 segmentos 
int lamp_Pin = 11;  // pino de saida
int potPin = 1;     // pino potenciometro
float val, val2 = 0;
unsigned long time = 10000;
unsigned long preview;


// cada byte abaixo corresponde a um numero no display. Desprezando o primeiro 0 cada bit corresponde a um segmento (a,b,c,d,e,f,g) respectivamente.
//  Bit 1 significa segmento correspondente aceso. Bit 0 significa segmento correspondente apagado
                      //    0         1         2           3         4           5         6           7          8          9      
byte     numero[10] = {B01111110, B00110000, B01101101, B01111001, B00110011, B01011011, B01011111, B01110000, B01111111, B01111011};


void setup()
{
  for(int i = 0; i<7; i++)
  pinMode (sete_seg[i], OUTPUT);
  
  pinMode ( lamp_Pin, OUTPUT);
  pinMode ( potPin, INPUT);
  preview = millis();

}

void loop()
{
val = analogRead (potPin);    // le o potenciometro
val = map(val,0,1024,0,255);  // ajusta a escala do valor lido 
analogWrite(lamp_Pin, val);  // manda o valor do PWM para a lampada

delay(50);

if((val2 < val - 1) || (val2 > val +1) )
{

escreve(val/25.5);     // escreve o valo de o a 9 no display
preview = millis();
}
else if ( time <  millis() - preview )
{
apaga();
}

val2 = val;

}


void escreve(int num)
{
 byte aux;
 aux = numero[num];
 
 for(int i= 7; i >= 0; i --)     // laco despresa o bit mais significativo
 {
 if(bitRead(aux,i )==1)         // le bit a bit
 {

 digitalWrite(sete_seg[i] , HIGH); 
 } 
 else
 {
 digitalWrite(sete_seg[i] , LOW);

 }
   
 }

}

void apaga()
{
  for(int i = 7; i >= 0; i --)
  digitalWrite(sete_seg[i] , LOW);

}