Arduino Shield NCS314 NIXIE Tubes Clock IN-14
Componentes e suprimentos
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 | ||||
| × | 1 |
Aplicativos e serviços online
|
Sobre este projeto
Visão geral
Inicialmente, depois de termos acesso a um suprimento quase inesgotável de tubos soviéticos Nixie de excelente qualidade IN-12, IN-14 e IN-18, íamos fazer uma exibição simples dos tubos Nixie como Escudo para Arduino. O Arduino naquela época já tínhamos, de modo que o case permaneceu por pequeno (assim pensamos na época). Naquela época, não sabíamos nada sobre como lidar com essas lâmpadas.
Rapidamente encontramos na internet um esquema para alimentar esses tubos:
SIM! Isso brilha! O fato de termos visto apenas nos surpreendeu é como um pequeno milagre, e percebemos que estamos no caminho certo. Imediatamente começou a sessão de fotos:
No dia seguinte, começou a discutir o conceito do futuro projeto:para simplificar e reduzir o custo, decidiu-se usar o esquema com um princípio de display dinâmico, mas posteriormente decidiu-se abandoná-lo em favor do esquema com um totalmente modo de exibição estático. Embora para as válvulas IN-14 Nixie a diferença visual não seja perceptível, mas para as lâmpadas IN-18 a diferença é perceptível - no modo dinâmico, elas funcionam não tão brilhantes que muitos deles aparecem, o chamado efeito de manchas azuis:
O modo de exibição dinâmica é um modo em que a cada momento nem todos os tubos estão acesos, e apenas um (de cada vez), também podem ser outras espécies quando iluminados simultaneamente, por exemplo, apenas duas lâmpadas.
Ao discutir o futuro do dispositivo, uma vez que tenha sido decidido implementar a capacidade de exibir informações nos tubos provenientes do computador, isso permitirá que os entusiastas criem seus próprios dispositivos que seriam exibidos nas lâmpadas, por exemplo, o número de mensagens não lidas ou o número de rodadas no jogo, como Fallout.
Em seguida, começou a seleção do hardware que poderia ser catodo de troca (números) nos tubos. A escolha era óbvia - os registros de deslocamento com SPI para salvar os pinos de MCU. Mas como a tensão de alimentação tubesis muito alta - até 200 volts, as opções não são tanto:HV513, HV5812, HV5122. E enquanto construímos o dispositivo em cada um desses chips, paramos no HV5812 (na nova versão do Shields NCS314 V2.X e NCS312 V1.X usava IC HV5122). Este chip é muito prático porque permite controlar simultaneamente duas lâmpadas, como um registro de 20 bits.
Para controlar 6 tubos, precisaremos de três desses circuitos conectados uns aos outros em série. Isso permite enviar o pacote uma vez sobre o SPI e não se preocupa em atualizar as informações nos tubos, como seria o caso com um algoritmo de exibição dinâmica. Ou seja, enquanto não precisarmos alterar as informações nas válvulas a MCU pode estar ocupada com outras tarefas, até mesmo dormir!
Gostaríamos de falar sobre a transferência de dados no SPI. Arudino pode transmitir por vez, apenas 8 bits. E precisamos de 60, o número inteiro superior mais próximo é divisível por 8 é 64 e, portanto, temos que aplicar um pouco de magia - para formar uma grande variável do tipo unsigned long long var64 bits para cada registro e passar 8 vezes 8 bits cada vez por deslocando todos os bits dentro da variável para a direita:
SPI.transfer (var64); SPI.transfer (var64>> 48); SPI.transfer (var64>> 40); SPI.transfer (var64>> 32); SPI.transfer (var64>> 24); SPI.transfer (var64>> 16); SPI.transfer (var64>> 8); SPI.transfer (iTmp);
Esses objetivos que foram definidos e alcançados foram implementados:
- Exibição estática baseada em registradores de deslocamento.
- Máquina caça-níqueis (envenenamento por Ani)
- Fornece as funções padrão para relógio, relógio, data, hora e despertador.
- RTC (Real Time Clock) com bateria CR1220. (A nova versão da placa V1.2-2.X usa um chip de tempo de alta precisão RTC DS3231).
- Medição de temperatura DS18B20 [Celsius ou Fahrenheit].
- Controle via porta de infravermelho TSOP4836 (Funciona apenas Mega). Verificado com controle remoto Sony RM-X151, mas é possível e outro controle remoto com uma frequência de 36kHz.
- Sincronização de tempo com GPS externo (só trabalho Mega)
- Menu fácil.
- Gestão separada do cólon (ponto inferior e superior)
- Cores de luz de fundo RGB com uma transfusão suave
- Toque RTTTL para o alarme (idioma de transferência do toque)
- Caça-níqueis (para evitar indicadores de envenenamento)
- No autoteste. (Verifique todos os números em cada tela de 0 a 9, para verificar todos os LEDs, um switch serial de cores azul, vermelho, verde, verificação de som (toques tocando)
Essas tarefas que não puderam ser realizadas totalmente.
- Sensor de luz
Código
- Arquivo sem título
Arquivo sem título C / C ++
const String FirmwareVersion ="010000"; // Formato _X.XX__ // NIXIE CLOCK SHIELD NCS314 por GRA &AFCH ([email protected]) // 25.05.2016 #include#include #include #include #include #include const byte LEpin =7; // pin Latch Dados habilitados são aceitos enquanto o nível HIconst byte DHVpin =5; // off / on MAX1771 Driver Hight Voltage (DHV) 110-220V const byte RedLedPin =9; // Saída MCU WDM para LEDs vermelhos 9-gconst byte GreenLedPin =6; // Saída MCU WDM para LEDs verdes 6-bconst byte BlueLedPin =3; // Saída MCU WDM para LEDs azuis 3-rconst byte pinSet =A0; const byte pinUp =A2; const byte pinDown =A1; const byte pinBuzzer =2; const byte pinUpperDots =12; // Valor ALTO acende um byte dotsconst pinLowerDots =8; // Valor ALTO acende uma palavra de pontosconst fpsLimit =16666; // 1/60 * 1.000.000 // limite a taxa de atualização máxima em 60 fpsString stringToDisplay ="000000"; // Conteúdo desta string será exibido em tubos (deve ter comprimento de 6 caracteres) int menuPosition =0; // 0 - hora // 1 - data // 2 - alarme // 3 - modo 12/24 horas byte blinkMask =B00000000; // máscara de bits para dígitos intermitentes (1 - intermitente, 0 - luz constante) // ------------------------- 0 ----- --1 ---------- 2 ---------- 3 --------- 4 -------- 5 ------ --- 6 --------- 7 --------- 8 --------- 9 ----- // byte lowBytesArray [] ={B11111110, B11111101 , B11111011, B11110111, B11101111, B11011111, B10111111, B01111111, B11111111, B11111111}; // byte highBytesArray [] ={B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111111, B11111110, B11111101}; byte dotpattern =B00000000; // máscara de bits para separar os pontos // B00000000 - desliga os pontos para cima e para baixo // B1100000 - desliga todos os pontos # define DS1307_ADDRESS 0x68byte zero =0x00; // solução alternativa para o problema # 527int RTC_hours, RTC_minutes, RTC_seconds, RTC_day, RTC_month, RTC_year, RTC_day_of_week; // - ------------ 0 -------- 1 --- ----- 2 ------- 3 -------- 4 -------- 5 -------- 6 -------- 7 -------- 8 -------- 9 -------- 10 ------- 11 ------- 12 ------- 13 ------- 14 // nomes:Hora, Data, Alarme, 12/24 horas, minutos, segundos, dia, mês, ano, hora, minuto, segundo alarme01 hora_formato // 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1int pai [15] ={0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 3, 4}; int firstChild [15] ={4, 7, 10, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; int lastChild [15] ={6, 9, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; valor int [15] ={0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 24}; int maxValue [15] ={0, 0, 0, 0, 23, 59, 59, 31, 12, 99, 23, 59, 59, 1, 24}; int minValue [ 15] ={0, 0, 0, 12, 00, 00, 00, 1, 1, 00, 00, 00, 00, 0, 12}; byte blinkPattern [15] ={B00000000, B00000000, B00000000, B00000000, B00000011, B00001100, B00110000, B00000011, B00001100, B00110000, B00000011, B00001100, B00110000, B110000 00, B00001100}; # define TimeIndex 0 #define DateIndex 1 #define AlarmIndex 2 #define hModeIndex 3 #define TimeHoursIndex 4 #define TimeMintuesIndex 5 # define TimeSecondsIndex 6 # define DateDayIndex # defineIndex # define DateMonthIndex 9 define AlarmMinuteIndex 11 # define AlarmSecondIndex 12 # define Alarm01 13 # define hModeValueIndex 14bool editMode =false; long downTime =0; long upTime =0; const long settingDelay =150; bool BlinkUp =false; bool BlinkDown =false;; bool RGBLedsOn =true; byte RGBLEDsEEPROMAddress =0; byte HourFormatEEPROMAddress =1; byte AlarmTimeEEPROMAddress =2; // 3,4,5byte AlarmArmedEEPROMAddress =6; // botões pins declarationsClickButton setButton (pinSet, LOW, CLICKBTN_PULLUP); ClickButton upButton (pinUp, LOW, CLICKBTN_PULLUP); ClickButton downButton (pinDown, LOW, CLICKBTN_PULLUP); //////////////// /// Tone tone1; #define isdigit (n) (n> ='0' &&n <='9') // char * song ="MissionImp:d =16, o =6, b =95:32d, 32d #, 32d, 32d #, 32d, 32d #, 32d, 32d #, 32d, 32d, 32d #, 32e, 32f, 32f #, 32g, g, 8p, g, 8p, a #, p, c7, p, g, 8p, g, 8p, f, p, f #, p, g, 8p, g, 8p, a #, p, c7, p, g, 8p, g, 8p, f, p, f #, p, a #, g, 2d, 32p, a #, g, 2c #, 32p, a #, g, 2c, a # 5,8c, 2p, 32p, a # 5, g5,2f #, 32p, a # 5, g5,2f, 32p, a # 5, g5,2e, d #, 8d "; char * song =" PinkPanther:d =4, o =5, b =160:8d #, 8e, 2p, 8f #, 8g, 2p, 8d # , 8e, 16p, 8f #, 8g, 16p, 8c6,8b, 16p, 8d #, 8e, 16p, 8b, 2a #, 2p, 16a, 16g, 16e, 16d, 2e "; // char * song =" VanessaMae:d =4, o =6, b =70:32c7,32b, 16c7,32g, 32p, 32g, 32p, 32d #, 32p, 32d #, 32p, 32c, 32p, 32c, 32p, 32c7,32b, 16c7,32g #, 32p, 32g #, 32p, 32f, 32p, 16f, 32c, 32p, 32c, 32p, 32c7,32b, 16c7,32g, 32p, 32g, 32p, 32d #, 32p, 32d #, 32p, 32c, 32p, 32c, 32p, 32g, 32f, 32d #, 32d, 32c, 32d, 32d #, 32c, 32d #, 32f, 16g, 8p, 16d7,32c7,32d7,32a #, 32d7,32a, 32d7, 32g, 32d7,32d7,32p, 32d7,3 2p, 32d7,32p, 16d7,32c7,32d7,32a #, 32d7,32a, 32d7,32g, 32d7,32d7,32p, 32d7,32p, 32d7,32p, 32g, 32f, 32d #, 32d, 32c, 32d, 32d #, 32c, 32d #, 32f, 16c "; // char * song =" DasBoot:d =4, o =5, b =100:d # .4,8d4,8c4,8d4,8d # 4,8g4, a # .4,8a4,8g4,8a4,8a # 4,8d, 2f., p, f.4,8e4,8d4,8e4,8f4,8a4, c., 8b4,8a4,8b4,8c, 8e, 2g. , 2p "; // char * song =" Scatman:d =4, o =5, b =200:8b, 16b, 32p, 8b, 16b, 32p, 8b, 2d6,16p, 16c # .6,16p. , 8d6,16p, 16c # 6,8b, 16p, 8f #, 2p., 16c # 6,8p, 16d.6,16p., 16c # 6,16b, 8p, 8f #, 2p, 32p, 2d6,16p , 16c # 6,8p, 16d.6,16p., 16c # 6,16a., 16p., 8e, 2p., 16c # 6,8p, 16d.6,16p., 16c # 6,16b, 8p, 8b, 16b, 32p, 8b, 16b, 32p, 8b, 2d6,16p, 16c # .6,16p., 8d6,16p, 16c # 6,8b, 16p, 8f #, 2p., 16c # 6,8p, 16d.6,16p., 16c # 6,16b, 8p, 8f #, 2p, 32p, 2d6,16p, 16c # 6,8p, 16d.6,16p., 16c # 6,16a., 16p., 8e , 2p., 16c # 6,8p, 16d.6,16p., 16c # 6,16a, 8p, 8e, 2p, 32p, 16f # .6,16p., 16b., 16p. "; // char * canção ="Pipoca:d =4, o =5, b =160:8c6,8a #, 8c6,8g, 8d #, 8g, c, 8c6,8a #, 8c6,8g, 8d #, 8g, c, 8c6 , 8d6,8d # 6,16c6,8d # 6,16c6,8d # 6,8d6,16a #, 8d6,16a #, 8d6,8c6,8a #, 8g, 8a #, c6 "; // char * song ="WeWishYou:d =4, o =5, b =200:d, g, 8g, 8a, 8g, 8f #, e, e, e, a, 8a, 8b, 8a, 8g, f #, d, d, b, 8b, 8c6,8b , 8a, g, e, d, e, a, f #, 2g, d, g, 8g, 8a, 8g, 8f #, e, e, e, a, 8a, 8b, 8a, 8g, f #, d, d, b, 8b, 8c6,8b, 8a, g, e, d, e, a, f #, 1g, d, g, g, g, 2f #, f #, g, f #, e, 2d, a, b , 8a, 8a, 8g, 8g, d6, d, d, e, a, f #, 2g "; # define OCTAVE_OFFSET 0char * p; int notas [] ={0, NOTE_C4, NOTE_CS4, NOTE_D4, NOTE_DS4, NOTE_E4, NOTE_F4 , NOTE_FS4, NOTE_G4, NOTE_GS4, NOTE_A4, NOTE_AS4, NOTE_B4, NOTE_C5, NOTE_CS5, NOTE_D5, NOTE_DS5, NOTE_E5, NOTE_F5, NOTE_FS5, NOTE_G5, NOTE_GS5, NOTE_A5, NOTE_AS5, NOTE_B5, NOTE_C6, NOTE_AS5, NOTE_B5, NOTE_C6, NOTE_D6, F6, , NOTE_G6, NOTE_GS6, NOTE_A6, NOTE_AS6, NOTE_B6, NOTE_C7, NOTE_CS7, NOTE_D7, NOTE_DS7, NOTE_E7, NOTE_F7, NOTE_FS7, NOTE_G7, NOTE_GS7, NOTE_A7, NOTE_AS7, NOTE_B7}; int fireforks [] ={0,0,1, // 1 -1,0,0, // 2 0,1,0, // 3 0,0, -1, // 4 1,0,0, // 5 0, -1,0}; // array com regras RGB (0 - não fazer nada, -1 - decréscimo, +1 - incresevoid setRTCDateTime (byte h, byte m, byte s, byte d, byte mon, byte y, byte w =1); int functionDownButton =0; int functionUpButton =0; / ******************************************* *************************************************** *********** Programa de inicialização ************************************* *************************************************** ***************** / void setup () {digitalWrite (DHVpin, LOW); // off MAX1771 Driver Hight Voltage (DHV) 110-220V Wire.begin (); // setRTCDateTime (23,40,00,25,7,15,1); Serial.begin (115200); Serial.println (""); if (EEPROM.read (HourFormatEEPROMAddress)! =12) valor [hModeValueIndex] =24; else value [hModeValueIndex] =12; if (EEPROM.read (RGBLEDsEEPROMAddress)! =0) RGBLedsOn =true; else RGBLedsOn =false; if (EEPROM.read (AlarmTimeEEPROMAddress) ==255) valor [AlarmHourIndex] =0 else; valor [AlarmHourIndex] =EEPROM.read (AlarmTimeEEPROMAddress); se (EEPROM.read (AlarmTimeEEPROMAddress + 1) ==255) valor [AlarmMinuteIndex] =0; e lse valor [AlarmMinuteIndex] =EEPROM.read (AlarmTimeEEPROMAddress + 1); if (EEPROM.read (AlarmTimeEEPROMAddress + 2) ==255) valor [AlarmSecondIndex] =0; else value [AlarmSecondIndex] =EEPROM.read (AlarmTimeEEPROMAddress + 2); if (EEPROM.read (AlarmArmedEEPROMAddress) ==255) valor [Alarm01] =0; else value [Alarm01] =EEPROM.read (AlarmArmedEEPROMAddress); tone1.begin (pinBuzzer); canção =parseSong (canção); pinMode (LEpin, OUTPUT); pinMode (DHVpin, OUTPUT); pinMode (RedLedPin, OUTPUT); pinMode (GreenLedPin, OUTPUT); pinMode (BlueLedPin, OUTPUT); // configuração do SPI SPI.begin (); // SPI.setDataMode (SPI_MODE3); // Modo 3 SPI SPI.setClockDivider (SPI_CLOCK_DIV128); // SCK =16MHz / 128 =125kHz // botões pins inits pinMode (pinSet, INPUT_PULLUP); pinMode (pinUp, INPUT_PULLUP); pinMode (pinDown, INPUT_PULLUP); //////////////////////////////// pinMode (pinBuzzer, OUTPUT); // objetos de botões inits setButton.debounceTime =20; // Cronômetro de depuração em ms setButton.multiclickTime =30; // Limite de tempo para cliques múltiplos setButton.longClickTime =2000; // tempo até que "cliques pressionados" registrem upButton.debounceTime =20; // Cronômetro de depuração em ms upButton.multiclickTime =30; // Limite de tempo para vários cliques upButton.longClickTime =2000; // tempo até que "cliques pressionados" registrem downButton.debounceTime =20; // Cronômetro de depuração em ms downButton.multiclickTime =30; // Limite de tempo para vários cliques downButton.longClickTime =2000; // tempo até que "cliques pressionados" registrem // digitalWrite (DHVpin, HIGH); // em MAX1771 Driver Hight Voltage (DHV) 110-220V // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! !!!!!!!!!!!!! // doTest (); // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! getRTCTime (); setTime (RTC_horas, RTC_minutos, RTC_segundos, RTC_dia, RTC_mês, RTC_ano); digitalWrite (DHVpin, LOW); // off MAX1771 Driver Hight Voltage (DHV) 110-220V setRTCDateTime (RTC_hours, RTC_minutes, RTC_seconds, RTC_day, RTC_month, RTC_year, 1); // ���������� ������ ��� ��������� ����� � RTC ����� �������� � ����� ���������� digitalWrite (DHVpin, HIGH); // em MAX1771 Driver Hight Voltage (DHV) 110-220V // p =song;} void rotateLeft (uint8_t &bits) {uint8_t high_bit =bits &(1 <<7)? 1:0; bits =(bits <<1) | high_bit;} rotador interno =0; // índice na matriz com "regras" RGB (incrementado por um a cada 255 ciclos) int cycle =0; // ciclos counterint RedLight =255; int GreenLight =0; int BlueLight =0; unsigned long prevTime =0; // o tempo do tubo lase foi aceso durante muito tempo prevTime4FireWorks =0; // hora da última alteração RGB // int minuteL =0; // ������� ����� ����� / ******************************** *************************************************** ******************************** Programa PRINCIPAL ****************** *************************************************** ********************************************** / void loop () { p =playmusic (p); if ((millis () - prevTime4FireWorks)> 5) {rotateFireWorks (); // muda a cor (em 1 passo) prevTime4FireWorks =millis (); } doIndication (); setButton.Update (); upButton.Update (); downButton.Update (); if (editMode ==false) {blinkMask =B00000000; } else if ((millis () - entrandoEditModeTime)> 60000) {editMode =false; menuPosition =firstChild [menuPosition]; blinkMask =blinkPattern [menuPosition]; } if (setButton.clicks> 0) // clique curto {p =0; // desligar a música))) tone1.play (1000,100); entrandoEditModeTime =millis (); menuPosition =menuPosition + 1; if (menuPosition ==hModeIndex + 1) menuPosition =TimeIndex; Serial.print (F ("menuPosition =")); Serial.println (menuPosition); Serial.print (F ("valor =")); Serial.println (valor [menuPosition]); blinkMask =blinkPattern [menuPosition]; if ((parent [menuPosition-1]! =0) e (lastChild [parent [menuPosition-1] -1] ==(menuPosition-1))) {if ((parent [menuPosition-1] -1 ==1 ) &&(! isValidDate ())) {menuPosition =DateDayIndex; Retorna; } editMode =false; menuPosition =pai [menuPosition-1] -1; if (menuPosition ==TimeIndex) setTime (valor [TimeHoursIndex], valor [TimeMintuesIndex], valor [TimeSecondsIndex], dia (), mês (), ano ()); if (menuPosition ==DateIndex) setTime (hora (), minuto (), second (), valor [DateDayIndex], valor [DateMonthIndex], 2000 + valor [DateYearIndex]); if (menuPosition ==AlarmIndex) {EEPROM.write (AlarmTimeEEPROMAddress, valor [AlarmHourIndex]); EEPROM.write (AlarmTimeEEPROMAddress + 1, valor [AlarmMinuteIndex]); EEPROM.write (AlarmTimeEEPROMAddress + 2, valor [AlarmSecondIndex]); EEPROM.write (AlarmArmedEEPROMAddress, valor [Alarm01]);}; if (menuPosition ==hModeIndex) EEPROM.write (HourFormatEEPROMAddress, value [hModeValueIndex]); digitalWrite (DHVpin, LOW); // desligado MAX1771 Driver Hight Voltage (DHV) 110-220V setRTCDateTime (hora (), minuto (), segundo (), dia (), mês (), ano ()% 1000,1); digitalWrite (DHVpin, HIGH); // em MAX1771 Driver Hight Voltage (DHV) 110-220V} valor [menuPosition] =extractDigits (blinkMask); } if (setButton.clicks <0) // clique longo {tone1.play (1000,100); if (! editMode) {entrandoEditModeTime =millis (); if (menuPosition ==TimeIndex) stringToDisplay =PreZero (hora ()) + PreZero (minuto ()) + PreZero (segundo ()); // formato de 24 horas habilitado temporariamente durante as configurações} menuPosition =firstChild [menuPosition]; if (menuPosition ==AlarmHourIndex) {value [Alarm01] =1; / * digitalWrite (pinUpperDots, HIGH); * / dotPattern =B10000000;} editMode =! editMode; blinkMask =blinkPattern [menuPosition]; valor [menuPosition] =extractDigits (blinkMask); } if (upButton.clicks! =0) functionUpButton =upButton.clicks; if (upButton.clicks> 0) {p =0; // desligar a música))) tone1.play (1000,100); incrementValue (); } if (functionUpButton ==-1 &&upButton.depressed ==true) {BlinkUp =false; if (editMode ==true) {if ((millis () - upTime)> settingDelay) {upTime =millis (); // + settingDelay; incrementValue (); }}} else BlinkUp =true; if (downButton.clicks! =0) functionDownButton =downButton.clicks; if (downButton.clicks> 0) {p =0; // desligar a música))) tone1.play (1000,100); dicrementValue (); } if (functionDownButton ==-1 &&downButton.depressed ==true) {BlinkDown =false; if (editMode ==true) {if ((millis () - downTime)> settingDelay) {downTime =millis (); // + settingDelay; dicrementValue (); }}} else BlinkDown =true; if (! editMode) {if (upButton.clicks <0) {tone1.play (1000,100); RGBLedsOn =verdadeiro; EEPROM.write (RGBLEDsEEPROMAddress, 1); Serial.println ("RGB =ativado"); } if (downButton.clicks <0) {tone1.play (1000,100); RGBLedsOn =falso; EEPROM.write (RGBLEDsEEPROMAddress, 0); Serial.println ("RGB =desligado"); }} bool estático updateDateTime =false; switch (menuPosition) {case TimeIndex:// modo de tempo stringToDisplay =updateDisplayString (); doDotBlink (); checkAlarmTime (); pausa; case DateIndex:// modo de data stringToDisplay =PreZero (dia ()) + PreZero (mês ()) + PreZero (ano ()% 1000); dotPattern =B01000000; // ativa os pontos inferiores / * digitalWrite (pinUpperDots, LOW); digitalWrite (pinLowerDots, HIGH); * / checkAlarmTime (); pausa; case AlarmIndex:// modo de alarme stringToDisplay =PreZero (valor [AlarmHourIndex]) + PreZero (valor [AlarmMinuteIndex]) + PreZero (valor [AlarmSecondIndex]); if (valor [Alarm01] ==1) / * digitalWrite (pinUpperDots, HIGH); * / dotPattern =B10000000; // ativa os pontos superiores else {/ * digitalWrite (pinUpperDots, LOW); digitalWrite (pinLowerDots, LOW); * / dotPattern =B00000000; // desativa os pontos superiores} checkAlarmTime (); pausa; case hModeIndex:// modo 12/24 horas stringToDisplay ="00" + String (value [hModeValueIndex]) + "00"; dotPattern =B00000000; // desativa todos os pontos / * digitalWrite (pinUpperDots, LOW); digitalWrite (pinLowerDots, LOW); * / checkAlarmTime (); pausa; }} String PreZero (dígito interno) {if (dígito <10) return String ("0") + String (dígito); else return String (dígito);} void rotateFireWorks () {if (! RGBLedsOn) {analogWrite (RedLedPin, 0); analogWrite (GreenLedPin, 0); analogWrite (BlueLedPin, 0); Retorna; } RedLight =RedLight + fireforks [rotador * 3]; GreenLight =GreenLight + fireforks [rotador * 3 + 1]; BlueLight =BlueLight + forquilhas de incêndio [rotador * 3 + 2]; analogWrite (RedLedPin, RedLight); analogWrite (GreenLedPin, GreenLight); analogWrite (BlueLedPin, BlueLight); ciclo =ciclo + 1; if (ciclo ==255) {rotador =rotador + 1; ciclo =0; } if (rotator> 5) rotator =0;} void doIndication () {// byte estático b =B00000001; static unsigned long lastTimeInterval1Started; if ((micros () - lastTimeInterval1Started) > 2; Var64 | =tmpVar64; Var64 =(Var64>> 4); sem sinal int iTmp =0; iTmp =Var64>> 56; SPI.transfer (iTmp); iTmp =Var64>> 48; SPI.transfer (iTmp); iTmp =Var64>> 40; SPI.transfer (iTmp); iTmp =Var64>> 32; SPI.transfer (iTmp); iTmp =Var64>> 24; SPI.transfer (iTmp); iTmp =Var64>> 16; SPI.transfer (iTmp); iTmp =Var64>> 8; SPI.transfer (iTmp); iTmp =Var64; SPI.transfer (iTmp); digitalWrite (LEpin, LOW); // travando dados} byte CheckButtonsState () {static boolean buttonsWasChecked; static unsigned long startBuzzTime; static unsigned long lastTimeButtonsPressed; if ((digitalRead (pinSet) ==0) || (digitalRead (pinUp) ==0) || (digitalRead (pinDown) ==0)) {if (buttonsWasChecked ==false) startBuzzTime =millis (); buttonsWasChecked =true; } else buttonsWasChecked =false; if (millis () - startBuzzTime <30) {digitalWrite (pinBuzzer, HIGH); } else {digitalWrite (pinBuzzer, LOW); }} String updateDisplayString () {static unsigned long lastTimeStringWasUpdated; if ((millis () - lastTimeStringWasUpdated)> 1000) {//Serial.println("doDotBlink "); // doDotBlink (); lastTimeStringWasUpdated =millis (); if (valor [hModeValueIndex] ==24) retornar PreZero (hora ()) + PreZero (minuto ()) + PreZero (segundo ()); senão retornar PreZero (horaFormato12 ()) + PreZero (minuto ()) + PreZero (segundo ()); } return stringToDisplay;} void doTest () {Serial.print (F ("Versão do firmware:")); Serial.println (FirmwareVersion.substring (1,2) + "." + FirmwareVersion.substring (2,4)); Serial.println (F ("Iniciar teste")); adc int =leitura analógica (A3); float Uinput =4,6 * (5,0 * adc) /1024,0+0,7; Serial.print (F ("entrada U =")); Serial.print (Uinput); p =música; parseSong (p); analogWrite (RedLedPin, 255); atraso (1000); analogWrite (RedLedPin, 0); analogWrite (GreenLedPin, 255); atraso (1000); analogWrite (GreenLedPin, 0); analogWrite (BlueLedPin, 255); atraso (1000); // enquanto (1); String testStringArray [12] ={"000000", "111111", "222222", "333333", "444444", "555555", "666666", "777777", "888888", "999999", "", ""}; if (Uinput <10) testStringArray [10] ="000" + String (int (Uinput * 100)); else testStringArray [10] ="00" + String (int (Uinput * 100)); testStringArray [11] =FirmwareVersion; int dlay =500; teste de bool =1; byte strIndex =0; startOfTest longo sem sinal =millis (); para (int i =0; i <12; i ++) {if ((millis () - startOfTest)> dlay) {startOfTest =millis (); strIndex =strIndex + 1; if (strIndex ==10) dlay =3000; if (strIndex ==12) test =0; switch (strIndex) {/ * case 10:SPI.transfer ((b | B01000000) &B11111100); pausa; caso 11:transferência de SPI ((b | B01000000) e B11001110); pausa; * / // padrão:SPI.transfer (b | B11000000); padrão:stringToDisplay =testStringArray [strIndex]; }} delayMicroseconds (2000); }; Serial.println (F ("Parar Teste")); } void doDotBlink () {static unsigned long lastTimeBlink =millis (); bool estático dotState =0; if ((millis () - lastTimeBlink)> 1000) {lastTimeBlink =millis (); dotState =! dotState; if (dotState) {dotPattern =B11000000; / * digitalWrite (pinUpperDots, HIGH); digitalWrite (pinLowerDots, HIGH); * /} else {dotPattern =B00000000; / * digitalWrite (pinUpperDots, LOW); digitalWrite (pinLowerDots, LOW); * /}}} void setRTCDateTime (byte h, byte m, byte s, byte d, byte mon, byte y, byte w) {Wire.beginTransmission (DS1307_ADDRESS); Wire.write (zero); // interrompe o Oscillator Wire.write (decToBcd (s)); Wire.write (decToBcd (m)); Wire.write (decToBcd (h)); Wire.write (decToBcd (w)); Wire.write (decToBcd (d)); Wire.write (decToBcd (mon)); Wire.write (decToBcd (y)); Wire.write (zero); // iniciar Wire.endTransmission ();} byte decToBcd (byte val) {// Converter números decimais normais em retorno decimal codificado binário ((val / 10 * 16) + (val% 10));} byte bcdToDec (byte val ) {// Converter decimal codificado em binário em números decimais normais return ((val / 16 * 10) + (val% 16));} void getRTCTime () {Wire.beginTransmission (DS1307_ADDRESS); Wire.write (zero); Wire.endTransmission (); Wire.requestFrom (DS1307_ADDRESS, 7); RTC_segundos =bcdToDec (Wire.read ()); RTC_minutes =bcdToDec (Wire.read ()); RTC_hours =bcdToDec (Wire.read () &0b111111); // tempo de 24 horas RTC_day_of_week =bcdToDec (Wire.read ()); // 0-6 -> domingo - sábado RTC_day =bcdToDec (Wire.read ()); RTC_month =bcdToDec (Wire.read ()); RTC_year =bcdToDec (Wire.read ());} palavra doEditBlink (int pos) {if (! BlinkUp) return 0; if (! BlinkDown) retorna 0; int lowBit =blinkMask>> pos; lowBit =lowBit &B00000001; estático não assinado long lastTimeEditBlink =millis (); bool estático blinkState =false; máscara de palavra =0; static int tmp =0; // blinkMask; if ((millis () - lastTimeEditBlink)> 300) {lastTimeEditBlink =millis (); blinkState =! blinkState; /*Serial.print("blinkpattern="); Serial.println (blinkPattern [menuPosition]); if (((blinkPattern [menuPosition]>> 8) &1 ==1) &&blinkState ==true) digitalWrite (pinLowerDots, HIGH); else digitalWrite (pinLowerDots, LOW); if (((blinkPattern [menuPosition]>> 7) &1 ==1) &&blinkState ==true) digitalWrite (pinUpperDots, HIGH); else digitalWrite (pinUpperDots, LOW); * / if (blinkState) tmp =0; else tmp =blinkMask; } if (((dotPattern &~ tmp)>> 6) &1 ==1) digitalWrite (pinLowerDots, HIGH); else digitalWrite (pinLowerDots, LOW); if (((dotPattern &~ tmp)>> 7) &1 ==1) digitalWrite (pinUpperDots, HIGH); else digitalWrite (pinUpperDots, LOW); if ((blinkState ==true) &&(lowBit ==1)) máscara =0xFFFF; // máscara =B11111111; máscara de retorno;} int extractDigits (byte b) {String tmp ="1"; /*Serial.print("blink pattern ="); Serial.println (b); Serial.print ("stringToDisplay ="); Serial.println (stringToDisplay); * / if (b ==B00000011) {tmp =stringToDisplay.substring (0,2); /*Serial.print("stringToDisplay1="); Serial.println (stringToDisplay); * /} if (b ==B00001100) {tmp =stringToDisplay.substring (2,4); /*Serial.print("stringToDisplay2="); Serial.println (stringToDisplay); * /} if (b ==B00110000) {tmp =stringToDisplay.substring (4); /*Serial.print("stringToDisplay3="); Serial.println (stringToDisplay); * /} /*Serial.print("stringToDisplay4="); Serial.println (stringToDisplay); * / return tmp.toInt ();} void injectDigits (byte b, valor int) {if (b ==B00000011) stringToDisplay =PreZero (valor) + stringToDisplay.substring (2); if (b==B00001100) stringToDisplay=stringToDisplay.substring(0,2)+PreZero(value)+stringToDisplay.substring(4); if (b==B00110000) stringToDisplay=stringToDisplay.substring(0,4)+PreZero(value);}bool isValidDate(){ int days[12]={31,28,31,30,31,30,31,31,30,31,30,31}; if (value[DateYearIndex]%4==0) days[1]=29; if (value[DateDayIndex]>days[value[DateMonthIndex]-1]) return false; else return true; }byte default_dur =4;byte default_oct =6;int bpm =63;int num;long wholenote;long duration;byte note;byte scale;char* parseSong(char *p){ // Absolutely no error checking in here // format:d=N,o=N,b=NNN:// find the start (skip name, etc) while(*p !=':') p++; // ignore name p++; // skip ':' // get default duration if(*p =='d') { p++; p++; // skip "d=" num =0; while(isdigit(*p)) { num =(num * 10) + (*p++ - '0'); } if(num> 0) default_dur =num; p++; // skip comma } // get default octave if(*p =='o') { p++; p++; // skip "o=" num =*p++ - '0'; if(num>=3 &&num <=7) default_oct =num; p++; // skip comma } // get BPM if(*p =='b') { p++; p++; // skip "b=" num =0; while(isdigit(*p)) { num =(num * 10) + (*p++ - '0'); } bpm =num; p++; // skip colon } // BPM usually expresses the number of quarter notes per minute wholenote =(60 * 1000L / bpm) * 4; // this is the time for whole note (in milliseconds) return p;} // now begin note loop static unsigned long lastTimeNotePlaying=0; char* playmusic(char *p) { if(*p==0) { return p; } if (millis()-lastTimeNotePlaying>duration) lastTimeNotePlaying=millis(); else return p; // first, get note duration, if available num =0; while(isdigit(*p)) { num =(num * 10) + (*p++ - '0'); } if(num) duration =wholenote / num; else duration =wholenote / default_dur; // we will need to check if we are a dotted note after // now get the note note =0; switch(*p) { case 'c':note =1; pausa; case 'd':note =3; pausa; case 'e':note =5; pausa; case 'f':note =6; pausa; case 'g':note =8; pausa; case 'a':note =10; pausa; case 'b':note =12; pausa; case 'p':default:note =0; } p++; // now, get optional '#' sharp if(*p =='#') { note++; p++; } // now, get optional '.' dotted note if(*p =='.') { duration +=duration/2; p++; } // now, get scale if(isdigit(*p)) { scale =*p - '0'; p++; } else { scale =default_oct; } scale +=OCTAVE_OFFSET; if(*p ==',') p++; // skip comma for next note (or we may be at the end) // now play the note if(note) { tone1.play(notes[(scale - 4) * 12 + note], duration); if (millis()-lastTimeNotePlaying>duration) lastTimeNotePlaying=millis(); else return p; tone1.stop(); } else { return p; } Serial.println(F("Incorrect Song Format!")); return 0; //error } void incrementValue() { enteringEditModeTime=millis(); if (editMode==true) { if(menuPosition!=hModeValueIndex) // 12/24 hour mode menu position value[menuPosition]=value[menuPosition]+1; else value[menuPosition]=value[menuPosition]+12; if (value[menuPosition]>maxValue[menuPosition]) value[menuPosition]=minValue[menuPosition]; if (menuPosition==Alarm01) { if (value[menuPosition]==1) /*digitalWrite(pinUpperDots, HIGH);*/dotPattern=B10000000;//turn on all dots /*else digitalWrite(pinUpperDots, LOW); */ dotPattern=B00000000; //turn off all dots } injectDigits(blinkMask, value[menuPosition]); } } void dicrementValue(){ enteringEditModeTime=millis(); if (editMode==true) { if (menuPosition!=hModeValueIndex) value[menuPosition]=value[menuPosition]-1; else value[menuPosition]=value[menuPosition]-12; if (value[menuPosition] 1000)) Alarm1SecondBlock=false; if (Alarm1SecondBlock==true) return; if ((hour()==value[AlarmHourIndex]) &&(minute()==value[AlarmMinuteIndex]) &&(second()==value[AlarmSecondIndex])) { lastTimeAlarmTriggired=millis(); Alarm1SecondBlock=true; Serial.println(F("Wake up, Neo!")); p=song; }}
Prog NIXIE Clock Tubes Shield NCS314
https://github.com/afch/NixeTubesShieldNCS314/Esquemas
Processo de manufatura
- Relógio de visão pov do Arduino
- Controlador DMX operado pela web
- Simple Word Clock (Arduino)
- Relógio Arduino com horas de oração islâmica
- Arduino Spybot
- Relógio mestre
- Faça Nixie Clock com Arduino em caixa de madeira MDF
- Relógio de matriz de 7 segmentos
- BLUE_P:Wireless Arduino Programming Shield
- Despertador simples com DS1302 RTC