Nixie-Projekt


von Lintner

Projekt Sommersemester 2011: Gasgefüllte Kaltkathoden-Anzeigeröhren

Nixie-Röhrentester

Projektdefinition

Das Testgerät soll die Funktionstüchtigkeit von Anzeigeröhren verifizieren. Die Zielsetzung beschränkt sich zunächst auf die Typen ZM1020 und ZM1108, eine Möglichkeit zur nachträglichen Erweiterung ist vorgesehen. Des weiteren sollen die üblichen Kenngrößen Zündspannung, Brennspannung und Anodenstrom bestimmbar sein.

Funktionen und Besonderheiten im Überblick:

Aufbau

Das Testgerät ist aus mehreren einzelnen Komponenten aufgebaut, welche im folgenden Aufgelist sind. Die einzelnen Komponenten wurden frei verdrahtet. Verwendete Vor- und Pulldown-Widerstände sind in der Auflistung nicht enthalten. Die Komponenten sind:

Benutzeranleitung

Vorgehensweise beim Testen

Das Anliegen der Eingangsspannung wird von Glimmlampe 1 angezeigt. Es empfiehlt sich, vor dem Anlegen der Eingangsspannung den Schalter 1 in die Position OFF zu bringen. Damit wird die Versorgungsspannung von den Anoden getrennt. Wenn sich Schalter 1 in Positon OFF befindet, so ist Glimmlampe 2 dunkel. Mit der Spannungsanzeige kann jetzt bereits die Versorgungsspannung geprüft werden (Stufenschalter in Position 1). Diese sollte zwischen 150 V und 200 V liegen.

Wird Schalter 1 in Position ON geschaltet, leuchtet Glimmlampe 2 auf. Es liegt nun Spannung an den Anzeigeröhren. Mit den Drehreglern können nun die Versorgungsspannung (Drehregler 1) und der Anodenvorwiderstand (Drehregler 2) variiert werden. Wenn die Versorgungsspannung die Zündspannung der Röhre überschreitet, beginnt diese zu leuchten.

Die von der Röhre anzeigbaren Werte - in der Regel die Ziffern 0 bis 9 - können mithilfe der Taster 1 und 2 sowie dem Schalter 2 gewechselt werden. Befindet sich Schalter 2 in Positon AUTO, so sind die Taster 1 und 2 ohne Funktion. Die von der Röhre angezeigten Werte wechseln in einem festen Zeitintervall von 2,5 Sek. automatisch. Befindet sich Schalter 2 in Position MANUELL wird der Anzeigewert mit Taster 1 (hochzählen) und Taster 2 (herrunterzählen) eingestellt.

Es wird ausdrücklich darauf hingewiesen, dass mit jeder zusätzlichen in den Tester eingesteckten Anzeigeröhre logischerweise eine höhere Belastung für den Spannungswandler entsteht und somit die Versorgungsspannung geringfügig reduziert wird.

Achtung: Es sollten aus Gründen der Strombelastung niemals mehr als zwei Anzeigeröhren gleichzeitig getestet werden!

Messung der Kenngrößen

Mit dem Stufenschalter kann die an der Spannungsanzeige angezeigte Größe ausgewählt werden:

Erklärung der Spannungsbezeichnungen

In diesem Dokument werden für die verschiedenen Spannungen folgende Bezeichnungen verwendet: Alle Spannungen verwenden Masse (GND) als Bezugspotenzial.

Programm für den Arduino

Das Programm kann auch hier heruntergeladen werden.
// DEFINES =======================================================
#define SAMPLING_PERIOD    26  // ms

#define INTERVALL_INIT   2500  // ms

/* Input Signal Pins          */
#define BUTTON1_PIN        5
#define BUTTON2_PIN        6
#define MODE_PIN           7

/* Input Singal Flags         */
#define BUTTON1_FLAG      (1 << 0)
#define BUTTON2_FLAG      (1 << 1)
#define MODE_FLAG         (1 << 2)


/* Output Pins                 */
#define BCD0_OUT_PIN       8
#define BCD1_OUT_PIN       9
#define BCD2_OUT_PIN      10
#define BCD3_OUT_PIN      11
#define LED               13

/* button states               */
enum button_state_t {
  wait,
  pressed,
  hold
};

/*  mode states                */
enum mode_state_t {   
    low,         //  if tow or more logic low were sampled contionusly     -  set state to low
    high,        //  if two or more logic high were sampled contionously   -  set state to high 
    low_wait,    //  if one logic low was sampled                          -  hold current state
    high_wait    //  if one logic high was sampled                         -  hold current state 
};

enum CounterState_t{
      up,
      down,
      idle
    };
    
struct counter_t {
    unsigned char        Value;
    unsigned int         TimeIntervall;
    enum CounterState_t  State;

  };

typedef unsigned int timeobject_t ;

// GLOBALS =======================================================
timeobject_t SampleTimerObj;    // used to store timing info for the Input-Signal sampling

timeobject_t CounterTimerObj;   // used to store timing info for the Counter     

enum button_state_t  Button1State = wait;
enum button_state_t  Button2State = wait;
enum mode_state_t    ModeState = low;

struct counter_t     Counter;

#define PRINT_COUNTER \   
  do { \
    Serial.print("counter: 0x"); \
    Serial.println(Counter.Value, HEX); \
  } while (0)

// FUNCTIONS =====================================================
int nonblocking_wait(unsigned int intervall, unsigned int *t_obj);
int button_pressed(void);
void set_BCD(unsigned int value);

void setup() {
  Serial.begin(9600);
  pinMode(BUTTON1_PIN, INPUT);
  pinMode(BUTTON2_PIN, INPUT);
  pinMode(MODE_PIN, INPUT);
  
  pinMode(BCD0_OUT_PIN, OUTPUT);
  pinMode(BCD1_OUT_PIN, OUTPUT);
  pinMode(BCD2_OUT_PIN, OUTPUT);
  pinMode(BCD3_OUT_PIN, OUTPUT);
  
  pinMode(LED, OUTPUT);             // on board led
    
  Counter.TimeIntervall = INTERVALL_INIT;
  Counter.State = up;
  
  Serial.print("start test"); // TODO: remove this line after debugging
}


void loop() {
  
  unsigned int iSignalFlags = 0;

  /* Signal Sampling */
  if (nonblocking_wait(SAMPLING_PERIOD, &SampleTimerObj)) { 
    /* check button 1 */
    if (1 == digitalRead(BUTTON1_PIN)) 
    { // BUTTON1 high
      switch (Button1State) {
         case wait:
          Button1State = pressed;
          break;
         case pressed:
          Button1State = hold;
          iSignalFlags |= BUTTON1_FLAG;
          break;
         case hold:
          break;
         default:
          Button1State = wait;
          break; 
      } // end switch (button1_state)
    } else 
    { // BUTTON low
      Button1State = wait;
    }                         
    /* check button 2 */
    if (1 == digitalRead(BUTTON2_PIN)) {       // check button 2
      switch (Button2State) {
         case wait:
          Button2State = pressed;
          break;
         case pressed:
          Button2State = hold;
          iSignalFlags |= BUTTON2_FLAG;
          break;
         case hold:
          break;
         default:
          Button2State = wait;
          break; 
      }
    } else {
      Button2State = wait;
    }
    /* check Mode */ 
    if (1 == digitalRead(MODE_PIN)) { // MODE high
      switch (ModeState) {      
        case high:
          iSignalFlags |= MODE_FLAG;
          break;
        case high_wait:
          ModeState = high;        
          iSignalFlags |= MODE_FLAG;
          break;
        case low_wait:
        case low:
        default:
          ModeState = high_wait;
          break;
      }
    } else { // MODE low
      switch (ModeState) {
        case low:
          break;
        case low_wait:
          ModeState = low;        
          break;
        case high_wait:
        case high:
        default:        
          iSignalFlags |= MODE_FLAG;
          ModeState = low_wait;
          break;        
      }
    }
  } 
  /* end input signal sampling */
  
  if (!(iSignalFlags & MODE_FLAG)) { // Manual Mode
  
    if (iSignalFlags & BUTTON1_FLAG) {
      ++Counter.Value;
      if (Counter.Value > 0x9) Counter.Value = 0;       
      set_BCD(Counter.Value);
      PRINT_COUNTER;
    }
    
    if (iSignalFlags & BUTTON2_FLAG) {
      --Counter.Value;
      if (Counter.Value > 0x9) Counter.Value = 9;
      set_BCD(Counter.Value);
      PRINT_COUNTER;
    }

  } else { // Auto Mode

    if (nonblocking_wait(Counter.TimeIntervall, &CounterTimerObj))
    {  
      /* counter routine */
      switch (Counter.State) {
        case up:
          ++Counter.Value;
          if (Counter.Value > 0x9) Counter.Value = 0; 
          break;
        case down:
          --Counter.Value;
          if (Counter.Value > 0x9) Counter.Value = 9;
          break;
        default:
          break;
       }
       
    set_BCD(Counter.Value);
    PRINT_COUNTER;
    }  
  }
} // end of loop

int nonblocking_wait(unsigned int intervall, unsigned int *t_obj)
{
  unsigned int t_temp = millis();
  if ( intervall < (t_temp - *t_obj))
  {
    *t_obj += intervall;
    if(*t_obj < millis()) *t_obj = millis();
    return 1; 
  }
  return 0;
}

void set_BCD(unsigned int value) {
  //if (value > 0x9) value = 0;
  digitalWrite(BCD0_OUT_PIN, (value & (1 << 0)) ? HIGH : LOW);
  digitalWrite(BCD1_OUT_PIN, (value & (1 << 1)) ? HIGH : LOW);  
  digitalWrite(BCD2_OUT_PIN, (value & (1 << 2)) ? HIGH : LOW);
  digitalWrite(BCD3_OUT_PIN, (value & (1 << 3)) ? HIGH : LOW);
}

Copyright © Hochschule München, FK 04, Prof. Jürgen Plate