Часы на газоразрядных трубках под управлением Arduino

04 апреля 2017

В прошлой статье мы разбирались с тем, как контролировать газоразрядные трубки при помощи Arduino. Сегодня мы построим полноценный проект при использовании данных трубок. И это будут интересные и очень необычные часы, которые обращают на себя внимание с первого взгляда.

Проект будет работать под управлением Arduino Mega. Также наши часы имеют светодиодную подсветку и блок кнопок, при помощи которых можно будет производить настройку без подключения к ПК.

Материалы

  • 4 газоразрядные трубки;
  • 130-200V блок питания (уточните необходимое напряжение в спецификации ваших трубок);
  • 4 микросхемы K155ID1;
  • Микросхема часов DS3231;
  • 10 шт. 5.6K 3W резисторов (можно использовать 10к резисторы);
  • Плата Arduino Mega;
  • Макетная плата;
  • Соединительные провода;
  • 8-кнопочный блок;
  • Термоусадочная трубка.

Подключение газоразрядных трубок

Для начала прочитайте эту статью. Особенно обратите внимание на шаги 1-3. Из-за отсутствия 10К резисторов мне пришлось использовать по 2 5К резистора перед каждой трубкой.

Управление 4-мя трубками с помощью Arduino Mega




Снова обращаемся к прошлой статье. Здесь мы не будем подробно рассматривать подключение, а только лишь обозначим шаги для создания готовых часов.

Для управления трубками мы использовали микросхемы K155ID1.

Для подключения потребуется отдельный чип для каждой трубки и отдельный выход на плате Arduino. Именно поэтому нам и понадобилась именно плата Arduino Mega, у которой больше портов ввода/вывода, чем у обычной платы Uno. Да, при таком подключении нам понадобиться 16 контактов, что для платы Mega не проблема.

Для подключения блока кнопок необходимо соединить “G” с питанием, а остальные контакты с аналоговыми выходами на плате. Были выбраны именно аналоговые выводы в связи с тем, что цифровые часто распознавали нажатую кнопку, когда на самом деле это было не так. И только установив значение действительно нажатой клавиши на 1023 (максимальное значение) на аналоговом выводе, удалось избавиться от этой проблемы.

После подключения микросхемы DS3231, трубок и светодиодов приступаем к программированию.

Программирование


Прилагаю готовый код. «NixieJT1» - это полный код. «DS3231» поможет установить тактовый модуль.

#include <DS3231.h>
DS3231  rtc(SDA, SCL);
Time t;


#define A1   25
#define A2   24
#define A3   23
#define A4   22


#define B1   29
#define B2   28
#define B3   27
#define B4   26


#define C1   35
#define C2   34
#define C3   33
#define C4   32


#define D1   39
#define D2   38
#define D3   37
#define D4   36


int light4[] = {A1,A2,A3,A4};
int light3[] = {B1,B2,B3,B4};
int light2[] = {C1,C2,C3,C4};
int light1[] = {D1,D2,D3,D4};


#define bled 2
#define rled 3
#define gled 4  //The RGB LED lights


#define but1 0
#define but2 4
#define but3 1
#define but4 5
#define but5 2
#define but6 6
#define but7 3
#define but8 7


byte nowHour, nowMinute,nowSecond;
byte digA, digB, digC, digD, oldDigA;
byte modeNum = 0;
byte oldModeNum = 22;
int lightState = 0;
byte b1,b2,b3,b4,b5,b6,b7,b8;




void setup() {
  rtc.begin();
  pinMode(48,OUTPUT); digitalWrite(48,HIGH); //For the button matrix
  for(int i=0; i<4; i++)
  {
    pinMode(light1[i],OUTPUT);
    pinMode(light2[i],OUTPUT);
    pinMode(light3[i],OUTPUT);
    pinMode(light4[i],OUTPUT);
  }
  pinMode(rled,OUTPUT);pinMode(gled,OUTPUT);pinMode(bled,OUTPUT);
  digitalWrite(rled,HIGH); digitalWrite(gled,HIGH); digitalWrite(bled,HIGH);
  oldDigA = 11;
  Serial.begin(9600);


}


void loop() {
  //Serial.println("Starting Loop");
  ReadPins();
  CheckSubs();
  
  GetTime();
  DisplayTime();
  
  RunLED(modeNum);
  }
void ReadPins()
{
  if(analogRead(but1)>1020) b1=1; else b1=0;
  if(analogRead(but2)>1020) b2=1; else b2=0;
  if(analogRead(but3)>1020) b3=1; else b3=0;
  if(analogRead(but4)>1020) b4=1; else b4=0;
  if(analogRead(but5)>1020) b5=1; else b5=0;
  if(analogRead(but6)>1020) b6=1; else b6=0;
  if(analogRead(but7)>1020) b7=1; else b7=0;
  if(analogRead(but8)>1020) b8=1; else b8=0;
}


void CheckSubs()
{
  byte delayTime = 150;
  if(b1==1 || b2==1 || b3==1 || b4 == 1)
  {
    ChangeTime();
    delay(delayTime);
  }
  else if(b5 == 1|| b6==1 || b7==1)
  {
    ChangeLED();
    delay(delayTime+50);
  }


  else if(b8==1)
    Eleven();
}


void ChangeTime()
{
  byte prevHour = t.hour;
  byte prevMin = t.min;
  byte prevSec = t.sec;
  int newHour, newMin;
  newHour = prevHour;
  newMin = prevMin;
  if(b1==1)
  {//Hour up by 1
    newHour = prevHour+1;
    if(newHour>=24)  newHour=0; 
  }
  else if(b2==1)
  {//Hour down by one
    newHour=prevHour-1;
    if(newHour<=0) newHour=23;
  }
  if(b3==1)
  {//Minute up by one
    newMin = prevMin+1;
    if(newMin>59) newMin=0;
  }
  else if(b4==1)
  {//Minute down by one
    newMin=prevMin-1;
    if(newMin<0) newMin=59;
  }
  rtc.setTime(newHour,newMin,prevSec);
  GetTime();
  oldDigA = 11;
  DisplayTime();
}


void ChangeLED()
{
  if(b7==1)
    modeNum = 0;
  if(b6==1)
  {
    if(modeNum==0 || modeNum>=6)
      modeNum = 1;
    else
      modeNum+=1;
  }
  if(b5==1)
  {
    if(modeNum==7)
      modeNum = 8;
    else 
      modeNum = 7;
  }
}


void RunLED(byte modeNum)
{//Remember, LOW means ON!!
  if(oldModeNum!=modeNum || modeNum>6)
    switch(modeNum)
    {
      case 0:  //Lights off
        digitalWrite(rled,HIGH);
        digitalWrite(gled,HIGH);
        digitalWrite(bled,HIGH);
        break;
      case 1: //just red
        digitalWrite(rled,LOW);
        digitalWrite(gled,HIGH);
        digitalWrite(bled,HIGH);
        break;
      case 2: //green
        digitalWrite(rled,HIGH);
        digitalWrite(gled,LOW);
        digitalWrite(bled,HIGH);
        break;
      case 3:  //blue
        digitalWrite(rled,HIGH);
        digitalWrite(gled,HIGH);
        digitalWrite(bled,LOW);
        break;
      case 4: //purple
        analogWrite(rled,180);
        digitalWrite(gled,HIGH);
        digitalWrite(bled,LOW);
        break;
      case 5: //orange
        analogWrite(rled,0);
        analogWrite(gled,180);
        analogWrite(bled,255);
        break;
      case 6: //white
        digitalWrite(rled,LOW);
        digitalWrite(gled,LOW);
        digitalWrite(bled,LOW);
        break;
      case 7: //smooth fade through all colors
        {int rgbColor[3];
        rgbColor[0] = 0; rgbColor[1] = 255; rgbColor[2] = 255;  
        for (int decColor = 0; decColor < 3; decColor += 1) {
          ReadPins(); if(b1>0||b2>0||b3>0||b4>0||b5>0||b6>0||b7>0||b8>0) return;
          int incColor = decColor == 2 ? 0 : decColor + 1;
          // cross-fade the two colors.
          for(int i = 255; i >0; i -= 1) {
            rgbColor[decColor] += 1; //maybe flip these back
            rgbColor[incColor] -= 1;  
            setColorRgb(rgbColor[0], rgbColor[1], rgbColor[2]);
            ReadPins(); if(b1>0||b2>0||b3>0||b4>0||b5>0||b6>0||b7>0||b8>0) return; //if a button is pressed, quit this subroutine
            delay(15);
          }
        }}
        break;
        case 8: //fade orange/purple/orange/etc
        {analogWrite(rled,0);
        analogWrite(gled,180);
        analogWrite(bled,255);
        byte rnum = 0;
        byte gnum = 180;
        byte bnum = 255;
        byte delayNum = 7;
        for(int h = 0; h<255; h++)
        {
          rnum = h*.7;
          gnum = 179+h*.3;
          bnum = 255-h;
          analogWrite(rled,rnum);
          analogWrite(gled,gnum);
          analogWrite(bled,bnum);
          ReadPins(); if(b1>0||b2>0||b3>0||b4>0||b5>0||b6>0||b7>0||b8>0) return;
          delay(delayNum);  
        }
        for(int h = 0; h<255; h++)
        {
          rnum = 180-h*.7;
          gnum = 255-h*.3;
          bnum = h;
          analogWrite(rled,rnum);
          analogWrite(gled,gnum);
          analogWrite(bled,bnum);
          ReadPins(); if(b1>0||b2>0||b3>0||b4>0||b5>0||b6>0||b7>0||b8>0) return;
          delay(delayNum);  
        }
        ReadPins(); if(b1>0||b2>0||b3>0||b4>0||b5>0||b6>0||b7>0||b8>0) return;  }
          break;
        default:
        break;
        
         
    }
}


void setColorRgb(unsig
ned int red, unsigned int green, unsigned int blue) {
  analogWrite(rled, red);
  analogWrite(gled, green);
  analogWrite(bled, blue);
 }


void Eleven()
{
  DisplayNumber(1,light1);
  DisplayNumber(1,light2);
  DisplayNumber(1,light3);
  DisplayNumber(1,light4); 
  digitalWrite(gled,LOW);
  digitalWrite(rled,HIGH);
  digitalWrite(bled,HIGH);
  delay(3000);
  oldDigA = 11;
  GetTime();
  DisplayTime();
}


void GetTime()
{
 // Serial.print("Running GetTime... ");
  t=rtc.getTime();
  nowHour = t.hour;
  nowMinute = t.min;
  nowSecond = t.sec;
  if(nowHour>12) nowHour=nowHour-12;
  if(nowHour == 0) nowHour = 12;
  
 
  //Change these around if things aren't working.
  digC = nowHour%10; //Second digit of the hour. 
  digD = nowHour/10; //First digit of the hour (1 or 0)
  digA = nowMinute%10; //Second digit of the hour
  digB = nowMinute/10; //First digit of the hour (40, 30, 20 etc)


  if(digD==0) digD=3;  //So that the first digit just won't be lit up at all.
}


void DisplayTime()
{
  
  if(digA != oldDigA)
  {
    Serial.println("Changing Time!!\n\n\n\n");
    DisplayNumber(digA,light1);
    DisplayNumber(digB,light2);
    DisplayNumber(digC,light3);
    if(digD==0) digD=3;  //So that the first digit just won't be lit up at all.
    DisplayNumber(digD,light4);
  }
  oldDigA = digA;
  delay(50);
  
}


void DisplayNumber(int thisNum, int thesePins[4])
{
  switch(thisNum) 
  {
    case 0:
      digitalWrite(thesePins[0],LOW);
      digitalWrite(thesePins[1],LOW);
      digitalWrite(thesePins[2],LOW);
      digitalWrite(thesePins[3],LOW);
      break;
    case 1:
      digitalWrite(thesePins[0],LOW);
      digitalWrite(thesePins[1],LOW);
      digitalWrite(thesePins[2],LOW);
      digitalWrite(thesePins[3],HIGH);
      break;    
    case 2:
      digitalWrite(thesePins[0],LOW);
      digitalWrite(thesePins[1],LOW);
      digitalWrite(thesePins[2],HIGH);
      digitalWrite(thesePins[3],LOW);
      break;
    case 3:
      digitalWrite(thesePins[0],LOW);
      digitalWrite(thesePins[1],LOW);
      digitalWrite(thesePins[2],HIGH);
      digitalWrite(thesePins[3],HIGH);
      break;
    case 4:
      digitalWrite(thesePins[0],LOW);
      digitalWrite(thesePins[1],HIGH);
      digitalWrite(thesePins[2],LOW);
      digitalWrite(thesePins[3],LOW);
      break;    
    case 5:
      digitalWrite(thesePins[0],LOW);
      digitalWrite(thesePins[1],HIGH);
      digitalWrite(thesePins[2],LOW);
      digitalWrite(thesePins[3],HIGH);
      break;
    case 6:
      digitalWrite(thesePins[0],LOW);
      digitalWrite(thesePins[1],HIGH);
      digitalWrite(thesePins[2],HIGH);
      digitalWrite(thesePins[3],LOW);
      break;
    case 7:
      digitalWrite(thesePins[0],LOW);
      digitalWrite(thesePins[1],HIGH);
      digitalWrite(thesePins[2],HIGH);
      digitalWrite(thesePins[3],HIGH);
      break;    
    case 8:
      digitalWrite(thesePins[0],HIGH);
      digitalWrite(thesePins[1],LOW);
      digitalWrite(thesePins[2],LOW);
      digitalWrite(thesePins[3],LOW);
      break;
    case 9:
      digitalWrite(thesePins[0],HIGH);
      digitalWrite(thesePins[1],LOW);
      digitalWrite(thesePins[2],LOW);
      digitalWrite(thesePins[3],HIGH);
      break;
    default:
      digitalWrite(thesePins[0],HIGH);
      digitalWrite(thesePins[1],LOW);
      digitalWrite(thesePins[2],HIGH);
      digitalWrite(thesePins[3],LOW);
      break;
  }
  
}

Несколько советов:

  • Если сегменты часов зажигаются в случайном порядке, попробуйте изменить порядок выводов A / B / C / D. Нам пришлось подключать их в обратном порядке для правильной работы часов;
  • Для блока кнопок использовался аналоговый вывод из-за того, что цифровой часто ошибается, если касаться металлических частей часов.

Данная статья является авторским переводом с сайта instructables.com.


Данная статья является собственностью Amperkot.ru. При перепечатке данного материала активная ссылка на первоисточник, не закрытая для индексации поисковыми системами, обязательна.


Поделиться: