Cathode Ray Tube (CRT) Display

The most complex project ever, but now it works. You can use Arduino to enter text and graphics on the screen.

The power supply makes a ±350 volt DC voltage. Deflection circuitry works with positive voltage and blanking circuit works with negative voltage. Before connecting CRT tube adjust the voltages according to the circuit diagram. Anode voltage is about +300V. Cathode voltage is about -290V. Focus voltage is about -200V and brightness voltage is about -320V. This circuit works for most small picture tubes found in eBay. I use 6LO1i. I will try others later.

The cathode voltage must be less (closer to zero) than brightness voltage otherwise blanking circuit does not work. First disconnect DAC from deflection circuit and adjust the dot in the center of the screen. Then adjust focus and anode voltage (astigmatism) so that dot is as sharp as possible. Be careful not to burn the phosphor coating of the CRT tube. Decrease brightness if necessary.

Digital to Analog Converter (DAC) circuit is commonly used R-2R resistor ladder network. The same circuit to horizontal and vertical deflection. Differential amplifier is used to amplify result.

Arduino example code:

static const byte ASCII[][5] =
{
 {0x00, 0x00, 0x00, 0x00, 0x00} // 20  
,{0x00, 0x00, 0x5f, 0x00, 0x00} // 21 !
,{0x00, 0x07, 0x00, 0x07, 0x00} // 22 "
,{0x14, 0x7f, 0x14, 0x7f, 0x14} // 23 #
,{0x24, 0x2a, 0x7f, 0x2a, 0x12} // 24 $
,{0x23, 0x13, 0x08, 0x64, 0x62} // 25 %
,{0x36, 0x49, 0x55, 0x22, 0x50} // 26 &
,{0x00, 0x05, 0x03, 0x00, 0x00} // 27 '
,{0x00, 0x1c, 0x22, 0x41, 0x00} // 28 (
,{0x00, 0x41, 0x22, 0x1c, 0x00} // 29 )
,{0x14, 0x08, 0x3e, 0x08, 0x14} // 2a *
,{0x08, 0x08, 0x3e, 0x08, 0x08} // 2b +
,{0x00, 0x50, 0x30, 0x00, 0x00} // 2c ,
,{0x08, 0x08, 0x08, 0x08, 0x08} // 2d -
,{0x00, 0x60, 0x60, 0x00, 0x00} // 2e .
,{0x20, 0x10, 0x08, 0x04, 0x02} // 2f /
,{0x3e, 0x51, 0x49, 0x45, 0x3e} // 30 0
,{0x00, 0x42, 0x7f, 0x40, 0x00} // 31 1
,{0x42, 0x61, 0x51, 0x49, 0x46} // 32 2
,{0x21, 0x41, 0x45, 0x4b, 0x31} // 33 3
,{0x18, 0x14, 0x12, 0x7f, 0x10} // 34 4
,{0x27, 0x45, 0x45, 0x45, 0x39} // 35 5
,{0x3c, 0x4a, 0x49, 0x49, 0x30} // 36 6
,{0x01, 0x71, 0x09, 0x05, 0x03} // 37 7
,{0x36, 0x49, 0x49, 0x49, 0x36} // 38 8
,{0x06, 0x49, 0x49, 0x29, 0x1e} // 39 9
,{0x00, 0x36, 0x36, 0x00, 0x00} // 3a :
,{0x00, 0x56, 0x36, 0x00, 0x00} // 3b ;
,{0x08, 0x14, 0x22, 0x41, 0x00} // 3c <
,{0x14, 0x14, 0x14, 0x14, 0x14} // 3d =
,{0x00, 0x41, 0x22, 0x14, 0x08} // 3e >
,{0x02, 0x01, 0x51, 0x09, 0x06} // 3f ?
,{0x32, 0x49, 0x79, 0x41, 0x3e} // 40 @
,{0x7e, 0x11, 0x11, 0x11, 0x7e} // 41 A
,{0x7f, 0x49, 0x49, 0x49, 0x36} // 42 B
,{0x3e, 0x41, 0x41, 0x41, 0x22} // 43 C
,{0x7f, 0x41, 0x41, 0x22, 0x1c} // 44 D
,{0x7f, 0x49, 0x49, 0x49, 0x41} // 45 E
,{0x7f, 0x09, 0x09, 0x09, 0x01} // 46 F
,{0x3e, 0x41, 0x49, 0x49, 0x7a} // 47 G
,{0x7f, 0x08, 0x08, 0x08, 0x7f} // 48 H
,{0x00, 0x41, 0x7f, 0x41, 0x00} // 49 I
,{0x20, 0x40, 0x41, 0x3f, 0x01} // 4a J
,{0x7f, 0x08, 0x14, 0x22, 0x41} // 4b K
,{0x7f, 0x40, 0x40, 0x40, 0x40} // 4c L
,{0x7f, 0x02, 0x0c, 0x02, 0x7f} // 4d M
,{0x7f, 0x04, 0x08, 0x10, 0x7f} // 4e N
,{0x3e, 0x41, 0x41, 0x41, 0x3e} // 4f O
,{0x7f, 0x09, 0x09, 0x09, 0x06} // 50 P
,{0x3e, 0x41, 0x51, 0x21, 0x5e} // 51 Q
,{0x7f, 0x09, 0x19, 0x29, 0x46} // 52 R
,{0x46, 0x49, 0x49, 0x49, 0x31} // 53 S
,{0x01, 0x01, 0x7f, 0x01, 0x01} // 54 T
,{0x3f, 0x40, 0x40, 0x40, 0x3f} // 55 U
,{0x1f, 0x20, 0x40, 0x20, 0x1f} // 56 V
,{0x3f, 0x40, 0x38, 0x40, 0x3f} // 57 W
,{0x63, 0x14, 0x08, 0x14, 0x63} // 58 X
,{0x07, 0x08, 0x70, 0x08, 0x07} // 59 Y
,{0x61, 0x51, 0x49, 0x45, 0x43} // 5a Z
,{0x00, 0x7f, 0x41, 0x41, 0x00} // 5b [
,{0x02, 0x04, 0x08, 0x10, 0x20} // 5c ¥
,{0x00, 0x41, 0x41, 0x7f, 0x00} // 5d ]
,{0x04, 0x02, 0x01, 0x02, 0x04} // 5e ^
,{0x40, 0x40, 0x40, 0x40, 0x40} // 5f _
,{0x00, 0x01, 0x02, 0x04, 0x00} // 60 `
,{0x20, 0x54, 0x54, 0x54, 0x78} // 61 a
,{0x7f, 0x48, 0x44, 0x44, 0x38} // 62 b
,{0x38, 0x44, 0x44, 0x44, 0x20} // 63 c
,{0x38, 0x44, 0x44, 0x48, 0x7f} // 64 d
,{0x38, 0x54, 0x54, 0x54, 0x18} // 65 e
,{0x08, 0x7e, 0x09, 0x01, 0x02} // 66 f
,{0x0c, 0x52, 0x52, 0x52, 0x3e} // 67 g
,{0x7f, 0x08, 0x04, 0x04, 0x78} // 68 h
,{0x00, 0x44, 0x7d, 0x40, 0x00} // 69 i
,{0x20, 0x40, 0x44, 0x3d, 0x00} // 6a j 
,{0x7f, 0x10, 0x28, 0x44, 0x00} // 6b k
,{0x00, 0x41, 0x7f, 0x40, 0x00} // 6c l
,{0x7c, 0x04, 0x18, 0x04, 0x78} // 6d m
,{0x7c, 0x08, 0x04, 0x04, 0x78} // 6e n
,{0x38, 0x44, 0x44, 0x44, 0x38} // 6f o
,{0x7c, 0x14, 0x14, 0x14, 0x08} // 70 p
,{0x08, 0x14, 0x14, 0x18, 0x7c} // 71 q
,{0x7c, 0x08, 0x04, 0x04, 0x08} // 72 r
,{0x48, 0x54, 0x54, 0x54, 0x20} // 73 s
,{0x04, 0x3f, 0x44, 0x40, 0x20} // 74 t
,{0x3c, 0x40, 0x40, 0x20, 0x7c} // 75 u
,{0x1c, 0x20, 0x40, 0x20, 0x1c} // 76 v
,{0x3c, 0x40, 0x30, 0x40, 0x3c} // 77 w
,{0x44, 0x28, 0x10, 0x28, 0x44} // 78 x
,{0x0c, 0x50, 0x50, 0x50, 0x3c} // 79 y
,{0x44, 0x64, 0x54, 0x4c, 0x44} // 7a z
,{0x00, 0x08, 0x36, 0x41, 0x00} // 7b {
,{0x00, 0x00, 0x7f, 0x00, 0x00} // 7c |
,{0x00, 0x41, 0x36, 0x08, 0x00} // 7d }
,{0x10, 0x08, 0x08, 0x10, 0x08} // 7e ←
,{0x78, 0x46, 0x41, 0x46, 0x78} // 7f →
};

unsigned long newMillis = 0;
unsigned long clockMillis = 0;
int second = 30;
int minute = 16;
int hour = 18;

long rndX=30, rndY=20;

void setup() {
  pinMode(2, OUTPUT); // 1 serial  D2   1 = vertical deflection
  pinMode(3, OUTPUT); // 1 OE      D3
  pinMode(4, OUTPUT); // 1 CLK     D4
  pinMode(5, OUTPUT); // 1 clear   D5
  
  pinMode(6, OUTPUT); // 2 serial  D6   2 = horizontal deflection
  pinMode(7, OUTPUT); // 2 OE      D7
  pinMode(8, OUTPUT); // 2 CLK     B0
  pinMode(9, OUTPUT); // 2 clear   B1

  pinMode(11, OUTPUT); // blanking B3

  digitalWrite(5, 1); // disable clear
  digitalWrite(9, 1);

  randomSeed(analogRead(0));
}

void loop() {
  
  drawDot(0,0);
  drawDot(0,255);
  drawDot(255,0);
  drawDot(255,255);

  unsigned long currentMillis = millis();
  
  if (currentMillis - newMillis >= 5000) {  
    newMillis = currentMillis;
    rndX = random(28,35);
    rndY = random(18,23);
  }

  if (currentMillis - clockMillis >= 1000) {  
    clockMillis = currentMillis;
    second++;
    if (second >= 60) {
      second = 0;
      minute++;
      if (minute >= 60) {
        minute = 0;
        hour++;
        if (hour >= 24) {
          hour = 0;
        }
      }
    }
  }

  int upperHour = hour/10;
  int lowerHour = hour - (upperHour*10);
  
  int upperMin = minute/10;
  int lowerMin = minute - (upperMin*10);

  int upperSec = second/10;
  int lowerSec = second - (upperSec*10);
  
  byte text[] = {(0x30 + upperHour),
    (0x30 + lowerHour),
    (0x3a),
    (0x30 + upperMin),
    (0x30 + lowerMin),
    (0x3a),
    (0x30 + upperSec),
    (0x30 + lowerSec)};

  printText(text,8,rndY,rndX);
}

void printText(byte arr[], int len, int line, int col) {
  for (int i = 0; i < len; i++) {
    printASCII(arr[i], 6*(col+i),9*line);
  }
}

void printASCII(int e, int x, int y) {
  for (int i = 0; i < 5; i++) {
    for (int ii = 0; ii <= 7; ii++) {
      if (bitRead(ASCII[e-32][i],ii)) drawDot(x+i,y+ii);
    }
  }
}

void drawDot(int x, int y) {

  if (x > 255 || y > 255) return;

  for (int i = 7; i >= 0; i--) {
    
    // send data
    (bitRead(y,i)) ? (PORTD |= (1 << 2)) : (PORTD &=~(1 << 2));
    (bitRead(x,i)) ? (PORTD |= (1 << 6)) : (PORTD &=~(1 << 6));

    PORTD |= (1 << 4); // toggle clock
    PORTD &=~(1 << 4);
    PORTB |= (1 << 0);
    PORTB &=~(1 << 0);
  }

  PORTD |= (1 << 4); // toggle clock
  PORTD &=~(1 << 4);
  PORTB |= (1 << 0);
  PORTB &=~(1 << 0);

  delayMicroseconds(150);
  PORTB |= (1 << 3); // blanking 1
  delayMicroseconds(150);
  PORTB &=~(1 << 3); // blanking 0
  
  PORTD &=~(1 << 5); // toggle clear
  PORTD |= (1 << 5);
  PORTB &=~(1 << 1);
  PORTB |= (1 << 1);
}