Relógio LED Shadowplay na plataforma Arduino Uno

Em vez de se juntar




Portanto, nossa equipe de três pessoas teve a tarefa: montar um pequeno projeto de hardware em um tempo muito curto, de preferência na plataforma Arduino. Vale ressaltar que até aquele momento estávamos familiarizados com os circuitos, em grande parte, em teoria. E isso significa - nem experiência com um ferro de solda (praticamente), nem, principalmente, experiência com o Arduino.

De repente, deparamos com um artigodedicado ao projeto Shadowplay Clock. Este é um relógio de parede projetado por uma equipe de designers vienenses, a hora em que você pode ver tocando um dedo no centro. Os LEDs acendem de forma que a sombra do dedo no centro mostre a hora. Foi decidido criar o mesmo (ou muito semelhante), mas em casa. O artigo acima, como você pode ver, não contém uma descrição detalhada do projeto. De tudo isso, seguimos que nós mesmos tivemos que descobrir como esse dispositivo funciona e dar vida a ele. O que nós, de fato, fizemos.

Materiais


Para criar um relógio, você precisa:

  • espaços em branco do painel de fibras
  • Tira de diodo de 60 LED
  • Arduino uno
  • RTC DS1307 Módulo de relógio em tempo real
  • botão
  • tábua de pão
  • registrador de mudança 74HC595 (x2)
  • Trava de registro de 8 bits 74HC573N (x8)
  • decodificador 4-16 K155ID3
  • inversor de dreno aberto IN74HC05AN (x10)
  • unidade de potência

Vamos começar


Então, o algoritmo do dispositivo:

  1. Quando a energia é aplicada, os LEDs acendem em uma combinação predeterminada. No Shadowplay original, todos os LEDs acenderam, mas pareceu-nos que seria mais interessante lançar alguma combinação como protetor de tela.
  2. Quando o botão é pressionado (sim, também nos afastamos do original e inserimos um pequeno botão no centro), a hora é lida no módulo RTC.
  3. O tempo de leitura é convertido em código binário (máscara) e inserido nos registros.
  4. Dependendo da máscara, o diodo necessário é ativado.

Hardware


Quando finalmente decidimos a idéia do projeto, a primeira coisa que tentamos foi esboçar mentalmente versões aproximadas dos esquemas para sua implementação. A questão principal era como lidar com 60 LEDs. De fato, a resposta a essa pergunta determinou o método de construção de quase todo o esquema.

A primeira opção que veio à mente foi o uso de decodificadores. O circuito compilado era uma cascata de quatro decodificadores 4-16 e um decodificador 2-4, ambos com entradas de descriptografia. Essa cascata permitia endereçar a 64 saídas, o que era mais que suficiente para conectar 60 LEDs.

No entanto, surgiu a questão de como fazer mais de um LED funcionar (endereço) ao mesmo tempo (afinal, precisávamos fornecer ao relógio pelo menos os minutos e ponteiros do relógio). Aqui, a principal desvantagem desse esquema foi manifestada - o decodificador não pode, por definição, endereçar mais de uma saída por vez.

Essa falha nos forçou a abandonar a idéia com uma cascata de decodificadores. Além disso, agora temos outro requisito para o futuro circuito - suporte para a operação simultânea de um número diferente de LEDs.

Para atender a esse requisito, pensamos que é possível permitir que cada LED armazene seu estado. Os registros são adequados para essa finalidade, onde cada descarga individual corresponde ao estado de um dos LEDs. Decidimos usar registros de 8 bits, pois eles são mais comuns e mais práticos. Assim, em nosso circuito, precisaremos de 8 registros para fornecer suporte a 60 LEDs.

Em seguida, pensamos em como controlar o status dos LEDs com o Arduino por meio de registros. Cada registro para operação normal deve receber todos os 8 bits na sua totalidade. O Arduino Uno, é claro, fornece saídas suficientes para transmitir vários bits por vez, mas essa abordagem não será racional. Além disso, o esquema contém apenas 8 registros, o que significa que você precisa abordá-los de alguma forma. Para esse fim, adicionamos um decodificador e dois registradores de deslocamento de 8 bits conectados em cascata ao circuito. Um registro de deslocamento armazena uma máscara de estado de 8 bits, que será carregada em um dos 8 registros regulares, cujo número é armazenado no segundo registro de deslocamento. Consequentemente, um decodificador é conectado ao segundo registrador de deslocamento. Para esses propósitos, um decodificador de 3 por 8 é suficiente.

Para remover a inversão do número necessário de saídas, usamos dois circuitos do inversor KR1533LN1. Isso, é claro, complicou um pouco o esquema.

Outra tarefa foi a tensão de trabalho dos LEDs igual a 12 volts em comparação com 5 volts de circuitos lógicos. A solução proposta foi usar um inversor de dreno aberto. Esse microcircuito desempenha o papel de uma tecla que fecha (com lógico 1) ou abre (com 0 lógico) um dos contatos do LED com o terra, ativando ou desativando o LED. O circuito assume operação de 12 volts, de acordo com a tensão de operação dos LEDs; portanto, para obter 5 volts para circuitos lógicos, o estabilizador KR142EN5A com dois capacitores foi adicionado ao circuito.

Algumas entradas de certos microcircuitos implicam um valor constante na entrada, portanto elas foram conectadas ao terra ou a uma fonte de energia. Nesse caso, estas são as seguintes entradas:

  • A entrada inversa de reset MR nos dois registros de deslocamento é conectada através do registro de carga à saída do estabilizador em 5 volts.
  • A entrada de ativação de saída OE inversa nos dois registros de deslocamento é conectada diretamente ao terra.
  • O decodificador inverso habilita a entrada E0 conectada ao terra




O circuito é controlado por quatro entradas (E1, SH, ST, DS). A finalidade e os níveis de sinal de cada um deles são discutidos em mais detalhes abaixo:

A entrada E1 foi projetada para ativar o decodificador. No nosso caso, inicialmente no decodificador, existem duas entradas de controle E1, E0, e ambas são inversas. Haverá uma saída suficiente para que a segunda (E0) possa ser trazida para o chão. O estado do decodificador "padrão" fica operacional até que um nível alto de sinal seja aplicado a E1. Para fazer o oposto, conectamos esta entrada ao inversor. Sem isso, o decodificador pode emitir sinais de controle incorretos para os registros, por exemplo, no momento da atualização dos dados no registro de deslocamento. Como já mencionado, um decodificador de 3 por 8 pode ser usado no circuito, que pode ter uma entrada de controle não inversa, o que facilitará a solução de todos os problemas descritos acima sem fios extras e ferro de soldar.

Quando um nível de sinal único é aplicado a E1, o decodificador decodifica o endereço de registro localizado no registro de deslocamento correspondente e envia um sinal para a saída desejada. Depois disso, o decodificador desliga novamente aplicando um nível de sinal baixo em E1. Tal comutador do decodificador gera um sinal na saída desejada, cuja borda e decaimento serve como um pulso de clock de registro para capturar em si os dados armazenados no barramento.

As próximas três entradas já se destinam ao controle de registros de turno. Vale a pena começar com a coisa mais simples - entrada de dados do DS. Esta entrada, como o nome indica, é destinada à transmissão de dados. Como os registros de deslocamento no circuito são conectados em cascata, o DS representa a saída correspondente de um deles. A entrada do segundo registro de deslocamento está conectada à saída do último bit do primeiro registro. O resultado é um registro de turno para 16 bits, dos quais apenas 12 bits são usados.

Entrada SH é uma entrada de relógio. Uma onda quadrada é alimentada nessa entrada, responsável por carregar e alterar dados em cada um dos registros, respectivamente, esse contato do circuito é conectado aos pinos SHCP de ambos os registros.

O último pino ST serve como uma trava de dados nas saídas do registro. Um impulso é dado a esta entrada, no entanto, ela é fornecida apenas quando os dados no registro de deslocamento são finalmente carregados e é necessário corrigi-los na saída dos registros. Somente depois de dar esse sinal, os dados baixados dentro do registro na primeira linha de gatilhos entram na segunda linha de gatilhos e ficam disponíveis no barramento. ST é um pino conectado aos pinos STcp de ambos os registradores.

Resta explicar a fiação dos dois pinos dos registros de deslocamento MR e OE. A primeira entrada (MR) é responsável por despejar dados dentro do registro. Nesse circuito, essa oportunidade não é necessária; portanto, um alto nível de sinal é fornecido a esta saída através da carga.

A segunda entrada de registro (OE) é responsável por desconectar a segunda linha de gatilhos dentro do registro de deslocamento do barramento, ou seja, a entrada de habilitação. Esta função também não é necessária, portanto, a saída é enrolada no chão.

Outro contato não descrito acima é projetado para remover o nível de sinal do botão no centro do relógio; o diagrama do botão é típico e representa uma carga e uma chave, dependendo da posição em que um nível de sinal baixo ou alto é enviado ao Arduino. Dependendo do estado do botão, o relógio funciona no modo de proteção de tela ou no modo de exibição da hora.
A conexão com o Arduino não possui recursos especiais, exceto que o pino SH está idealmente conectado ao pino digital SCK. O restante das saídas do circuito pode ser conectado a qualquer uma das entradas digitais de uso geral disponíveis. No nosso caso, a conexão tem a seguinte forma:

  • Arduino pin13 (SCK) – SH
  • Arduino pin 11 – ST Arduino pin 8 – DS Arduino pin 5 – E1 Arduino pin 3 – Arduino pin GND – ( )
    , .

    : 36 — ; 36 ( ) \ 26 ( ) — . Shadowplay 72 , 36. , 60 ( + ). . , , , .



    , . , . , . , «» 50 — 60, . , 60 . : — .



    , , , . — . , , . , — .

    .


    -, .

    Shadowplay. , , . , , . , .. . , , 100% . , . . , . , .

    , ( ), , — . , , ! . , - - . , , . , , . , , , . ., - . , , , , , .



    , . . .. , , ( , , ), .


    , (). Arduino. , RTC, — . DS1307, — I2C. 2100 . . RTC Arduino, . RTC.



    , RTC, .

    #include <Time.h>
    #include <DS1307RTC.h>
    
    char REG [8];
    tmElements_t te;
    int c,reset=1;
    
    void setup() {
      pinMode(13, OUTPUT); 
      pinMode(11, OUTPUT); 
      pinMode(8, OUTPUT);  
      pinMode(5, OUTPUT);  
      pinMode(3, INPUT);   
      Serial.begin(57600);
      
      //      RTC  
      //te.Hour = 18;
      //te.Minute = 50;
      //te.Second = 0;
      //te.Day = 20; //
      //te.Month = 4; // 
      //te.Year = CalendarYrToTm(2016); 
      //RTC.write(te);
    }
    
    void loop()
    { 
    if(digitalRead(3))                    // ,     
      {RTC.read(te);
       SetShadowTime(te.Hour,te.Minute,te.Second,2);        //         
       delay(900);
       reset=1;
      }
    
    else                                   //    ,  
      {wait1();
       reset=1;
      }
                                             //  
      for(int j = 0; j<8 ; j++) SetUpLightByMask(j,0); 
       
     
    }
    
    
    //======================================================================= 
    
    void SetUpLightByMask(int RegNum, char LightMask) //         
    {
      
      digitalWrite(5, LOW);
      digitalWrite(11, LOW);
      shiftOut(8, 13, MSBFIRST, LightMask);
      shiftOut(8, 13, LSBFIRST, RegNum);
      digitalWrite(11, HIGH);
      digitalWrite(5, HIGH);
    }
    
    void digitalClockDisplay() {  //    RTC  ,    RTC  
      RTC.read(te);
      Serial.print(te.Hour);
      Serial.print(" : ");
      Serial.print(te.Minute);
      Serial.print(" :");
      Serial.print(te.Second);
      Serial.print(" ");
      Serial.print(te.Day);
      Serial.print(" ");
      Serial.print(te.Month);
      Serial.print(" ");
      Serial.print(tmYearToCalendar(te.Year));
      Serial.println();
    }
    
    //     ,     , ,        :
    //0 -  ,1 -   , 2 -    
    
    void SetShadowTime(int Hours, int Minutes, int Seconds, int param){   
      int h,hshift,m,s;
      for(int j = 0; j<8 ; j++) REG[j] = 0;
    
      if(Hours >= 12) Hours -= 12;
      h = Hours + 6;
      if(h >= 12) h -= 12;
        
      hshift = (int) Minutes / 12;
      
      REG[(int)(((h*5)+hshift)/8)] = REG[(int)(((h*5)+hshift)/8)] | 1<<(((h*5)+hshift)%8);
                 
       
      if(param == 1)
      {m = Minutes + 30;
       if(m >= 60) m -= 60;
       REG[(int)(m/8)] = REG[(int)(m/8)] | 1<<(m%8);
       }
    
      if(param == 2)
      {m = Minutes + 30;
       if(m >= 60) m -= 60;
       REG[(int)(m/8)] = REG[(int)(m/8)] | 1<<(m%8);
         
       s = Seconds + 30;
       if(s >= 60) s -= 60;
       REG[(int)(s/8)] = REG[(int)(s/8)] | 1<<(s%8);
      }
    
      for(int j = 0; j<8 ; j++) SetUpLightByMask(j,REG[j]);
      }
      
    void wait1() //    
    {for(int a = 0; a < 8; a++)
        {c=0;
         for(int b = 0; b < 8; b++)
          {c = c << 1;
           c = c | 1;
           SetUpLightByMask(a, c);  
           delay(10);   
          }
       }
      for(int a = 0; a < 8; a++)
        {c=255;
          for(int b = 0; b < 8; b++)
          {c = c << 1;
           SetUpLightByMask(a, c);
           delay(10);     
          }
        }  
    }
    



    . . (Arduino, RTC) . , . , «- ». — . :

    .



    , «»:



    , , :



    , , , .

    , , . , ? . : ( , , ..). , , , . . , .


    ?

    • , , .
    • .
    • A capacidade de alterar programaticamente facilmente a sequência de LEDs piscando, o que fornece uma variedade infinita de combinações.

    Não reivindicamos a exatidão absoluta de nossas soluções de circuitos e software. Como já mencionado, a experiência negativa também é experiência. Talvez este artigo ajude alguém a evitar nossos erros.

    Obrigado pela atenção!

Source: https://habr.com/ru/post/pt394107/


All Articles