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);
}

 

LED Matrix Clock

This clock is made of 60 LEDs and the AtMega328 chip with Arduino bootloader. Video of clock in operation. https://www.youtube.com/watch?v=L1F2BAmQfWg

Here is schematics. Board has two button to adjust hours and minutes and Real-time clock ic to keep time accurate.

Back side is not perfect because of cheap soldering iron.

Program code is below.

#include "Wire.h"

boolean LEDarr[60];
unsigned long newMillis = 0;
unsigned long blinkMillis = 0;
int second = 0;
int minute = 0;
int hour = 1;

unsigned long debounceTimer;
boolean A2state = 1;
boolean A3state = 1;

void setup() {
  pinMode(0, OUTPUT); // matrix
  pinMode(1, OUTPUT);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);

  pinMode(8, OUTPUT); // matrix
  pinMode(9, OUTPUT);
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(13, OUTPUT);
  pinMode(A0, OUTPUT);
  pinMode(A1, OUTPUT);

  pinMode(A2, INPUT_PULLUP); // buttons
  pinMode(A3, INPUT_PULLUP);

  Wire.begin(); // A4,A5
  getRTC();
}

int ii = 0;

void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - newMillis >= 500) {  
    newMillis = currentMillis;
    getRTC();
  }
  if(!digitalRead(A2)) {
    if(A2state) {
      A2state = 0;
      debounceTimer = millis();
    }
    if(millis() - debounceTimer > 150) {
      A2state = 1;
      if(++hour == 13) hour = 1;
      newMillis = currentMillis;
      setRTC();
    }
  }
  if(!digitalRead(A3)) {
    if(A3state) {
      A3state = 0;
      debounceTimer = millis();
    }
    if(millis() - debounceTimer > 150) {
      A3state = 1;
      if(++minute == 60) minute = 0;
      newMillis = currentMillis;
      setRTC();
    }
  }
  for(int i = 0; i <= 59; i++) LEDarr[i] = 0;
  
  if(second == 59) {
    if (ii < 59) for(int i = 0; i <= ii; i++) LEDarr[i] = 1;
    ii = ii + 2;
  } else {
    ii = 0;
    LEDarr[second] = 1;
  }
  
  LEDarr[minute] = 1;
  LEDarr[(hour*5)-1] = 1;
  
  if(second == (hour*5)-1 && currentMillis - blinkMillis > 200) {
    blinkMillis = currentMillis;
    LEDarr[second] = !LEDarr[second];
  }
  if(second == minute && currentMillis - blinkMillis > 200) {
    blinkMillis = currentMillis;
    LEDarr[second] = !LEDarr[second];
  }
  if(minute == (hour*5)-1 && currentMillis - blinkMillis > 200) {
    blinkMillis = currentMillis;
    LEDarr[minute] = !LEDarr[minute];
  }
  LEDloop();
}

byte decToBcd(byte val) {
  return ((val/10*16) + (val%10));
}

byte bcdToDec(byte val) {
  return ((val/16*10) + (val%16));
}

void setRTC() {
  Wire.beginTransmission(0x51);
  Wire.write(0x03);
  //Wire.write(decToBcd(second));  
  Wire.write(decToBcd(minute));
  Wire.write(decToBcd(hour-1));
  Wire.endTransmission();
}

void getRTC() {
  Wire.beginTransmission(0x51);
  Wire.write(0x02);
  Wire.endTransmission();
  Wire.requestFrom(0x51, 3);
  second = bcdToDec(Wire.read() & B01111111); // remove VL error bit
  minute = bcdToDec(Wire.read() & B01111111); // remove unwanted bits from MSB
  hour = bcdToDec(Wire.read() & B00111111);
  if(hour >= 12) hour = hour - 12;
  hour = hour + 1;
}

void LEDloop() {
  int led = 0;
  for(int a = 8; a <= 15; a++) {
    if (a <= 13) digitalWrite(a, 1);
    else if(a == 14) digitalWrite(A0, 1);
    else if(a == 15) digitalWrite(A1, 1);
    if(a != 8) {
      for(int i = 4; i <= 7; i++) {
        digitalWrite(i, !LEDarr[led++]);
        delayMicroseconds(340);
        digitalWrite(i, 1);
      }
    }
    for(int i = 0; i <= 3; i++) {
      digitalWrite(i, !LEDarr[led++]);
      delayMicroseconds(340);
      digitalWrite(i, 1);
    }
    if (a <= 13) digitalWrite(a, 0);
    else if(a == 14) digitalWrite(A0, 0);
    else if(a == 15) digitalWrite(A1, 0);
  }
}

 

DMX Controlled Relay Board

Now automation is made easy. With this nifty module one can control four different application by using an computer with a DMX software installed. Module uses four DMX512 address. Starting address is selectable withing DIP switches. Relay is switched on by sending value over 138 and switched off by sending value under 118. Module remember last states during DMX signal loss.

Easy to solder. Arduino compatible and programmable. Can use BSD licensed free library for receiving DMX data. Example code is coming later.

With this and previously published USB-DMX Interface its very easy to build home automation or stage lightning effects.

All relays capable to drive 5A, 230V loads. Uses only one supply voltage of 5V.

Part list

All parts can be bought from www.taydaelectronics.com.

  • R1, R2, R4, R6, R8 – 10k resistor
  • R3, R5, R7, R9 – 200 ohm resistor
  • C1, C2 – 100nF ceramic disc capacitor
  • C3, C4 – 12pF ceramic disc capacitor
  • D1, D3, D5, D7 – 5mm red led
  • D2, D4, D6, D8 – 1N4004 diode
  • Q1-Q4 – BC547 or 2N3904 general purpose transistor
  • Y1 – 16MHz crystal
  • U1 – atMega328P-PU microcontroller ic
  • U5 – MAX485 line driver ic
  • U2, U3, U4, U6 – HJF-3FF relay
  • SW1 – DIP switch 9 positions
  • J3 – 4 pin header
  • J1 – 2 pin screw terminal
  • J2, J4-J8 – 3 pin screw terminal

USB/Ethernet Relay Card with 8 relays

 

Arduino compatible web server based relay card which also can be used with USB connection. No special soldering skills required. Easy to program with popular ENC28J60 Ethernet controller. All Arduino Ethernet libraries are compatible e.g. this ENC28J60 library. Only one +5V USB power supply needed. All relais can be controlled individually. Relais can drive 5A load from 230V.

Board uses FTDI USB i.c. Arduino bootloader natively supports USB and virtual serial port. Device is programmable via USB port with Arduino IDE or similar programs.

All parts can buy from http://www.taydaelectronics.com. Only exception is ethernet connector. It must include transformers and filter elements.

 

Multipurpose 7-segment Display System (Part 1.)

Here is my latest invention. Arduino compatible multipurpose 7-segment display driver. It can be used in many places. To mention few it can be used in gas station price display, score board display in sport and clock or temperature view on store roof to catch eye.

Controlling format can be any and connection is USB virtual serial port. Power supply needs to supply +12V and +5V. Amperage is in accordance with display count. One display draws max. about 240mA from +12V line when all segments are on.

Main board is populated with all components. Slave modules does not need the atMega328P-PU chip and its related components. Board is connected directly on back of a display element. Display height must be 100mm and connectors distance 106.68-107.00mm.

Data line from last display must connect to the feedback line. Then it is programmatically possible to count displays and it is not necessary to manually import display count to microcontroller. Displays are counted from right to left.

Here is schematics for revision 3.

Bill-Of-Material

All components except the display can buy from www.taydaelectronics.com.

Display, KW1-4003ASA, any similar will go and also with reversed polarity. Common pins 1,8 or 3,8. Select with J8.

Unregulated AC/DC power supply can be used with 12V and 5V voltage regulation kits from Tayda:

One 12V regulator is giving enough power for about four displays. 5V power consumption is much less and not need to worry about it. One 5V regulator is enough for most users.

Cable between modules contains 7 wires:

Last display data line and feedback line connection can be made with mini jumper.

Arduino compatible

On final product Arduino bootloader is preinstalled on to atMega328P-PU chip before installing it to board. First prototype works with Arduino Nano and has one display. Below is program code that supports multiple displays.

 

/* Multipurpose 7-segment Display Driver
 * 
 * Juvar's Electronics Corner
 * https://juvar.fi/
 * Juvar
 * juvar@mbnet.fi
 * Juha-Pekka Varjonen
 * 
 * version 1.4
 * 
 * 
 * Master unit is connected to last display in row
 * Leftmost display data output is connected to feedback line
 * 
 * bug in C language:
 * array[0] = cannot write
 * array is zero indexed but cannot save data in to zero position
 */

#define SER 2
#define FB 3
#define OE 4
#define CLK 5

int dispCount;
int pos = 1;

/*    
 *   _A_  
 * F|   |B
 *  |_G_|
 *  |   |
 * E|___|C
 *    D
 */


//DP,e,d,c,b,a,f,g
byte num[12] = {
  0b01111110, /* 0 */
  0b00011000, /* 1 */
  0b01101101, /* 2 */
  0b00111101, /* 3 */
  0b00011011, /* 4 */
  0b00110111, /* 5 */
  0b01110111, /* 6 */
  0b00011100, /* 7 */
  0b01111111, /* 8 */
  0b00111111, /* 9 */
  0b00000000  /* space */
  };
byte dataArr[20];

void setup() {
  // make the pins outputs
  pinMode(SER, OUTPUT); // serial data
  pinMode(OE, OUTPUT); // output enable
  pinMode(CLK, OUTPUT); // clock pulse
  // disable display output
  digitalWrite(OE, HIGH);
  // initialize serial
  Serial.begin(9600);

  // count displays
  int i = 0;
  byte temp;
  //set data
  digitalWrite(SER, HIGH);
  do {
    // toggle clock pulse
    digitalWrite(CLK, HIGH);
    digitalWrite(CLK, LOW);
    i++;
    bitWrite(temp, 0, digitalRead(FB));
    temp = temp << 1;
  } while (temp != 0b11111110);
  dispCount = (i+1)/8;
  // clear data
  digitalWrite(SER, LOW);
}

void loop() {
  // if there's any serial available, read it
  while (Serial.available() > 0) {
    // read the incoming byte
    char data = Serial.read();
    // if any numbers
    if (data >= 48 && data <= 57) dataArr[pos++] = num[data-48];
    // if space
    else if (data == 32) dataArr[pos++] = num[10];
    // if dot
    else if(data == 46) {
      if (pos > 1) bitSet(dataArr[pos-1], 7); 
        else bitSet(dataArr[pos], 7);
    } 
    // if carriage return
    else if (data == 13) updateDisp();
  }
}

void updateDisp() {
  //disable display output
  digitalWrite(OE, HIGH);
  //send data to displays
  int i = 1;
  do {

    for (int e = 0; e <= 7; e++) {
      // send segment data
      digitalWrite(SER, bitRead(dataArr[i],e));
      // toggle clock pulse
      digitalWrite(CLK, HIGH);
      digitalWrite(CLK, LOW);
    }

    dataArr[i] = 0; //fill with space
    i++;    
  } while (i <= dispCount);
  // clear data
  digitalWrite(SER, LOW);
  // toggle clock pulse
  digitalWrite(CLK, HIGH);
  digitalWrite(CLK, LOW);
  // enable display output
  digitalWrite(OE, LOW);
  pos = 1;
}

 

Prototypes accepts serial data from USB virtual serial port with following format. It mimics check point times from some sort of sport. Second prototype has two displays, so thats why data needs to be short. Otherwise data will be truncated.

1.1
2.2
4.5

Example picture with that data.

Data is displayed immediately after receiving it and stays on display until new data is arrived. It is possible to clear display temporarily by setting Output Enable pin to high state or clear display memory with sending empty character to all displays.

Selectors J6, J7 and J8

J6 and J7 selects display type between common anode and common cathode. They are solid jumper wires. If mode needs to change then must also change all transistors and reverse on board zener diode. When J6 is position 2-3 and J7 is position 1-2 then display is common anode. And when J6 is position 1-2 and J7 is position 2-3 then display is common cathode.

With J8 its possible to select whether connected display common pins are 1, 8 or 3, 8. Virtually all display modules are supported. Jumpers in position 1-3 and 2-4 means that 3, 8 is selected. When jumpers are in position 1-2 and 3-4 then 1, 8 is selected.

Speeding Up Arduino

This article tells how to overclock Arduino with AtMega328P microcontroller. It is necessary to load new bootloader to Arduino with parallel programmer. Clock speed must be set according the crystal frequency.

I have 22.1184 MHz crystal so I must first edit the Makefile for bootloader. It is located normally in this directory:

/usr/share/Arduino/hardware/arduino/avr/bootloaders/atmega/

Edit correct frequency to this line:

atmega328: AVR_FREQ = 22118400L

Find boards.txt file in the system and change frequency and save.

nano.build.f_cpu=22118400L

Next task is to create connection between computer and Arduino. To establish connection you need one parallel port on computer and two resistor in series with the lines.

LPT PORT – AVR (ARDUINO)

  • Pin 1 (STROBE), resistor 470 ohm, SCK
  • Pin 2 (D0), resistor 470 ohm, MOSI
  • Pin 11 (BUSY), MISO
  • Pin 16 (INIT), RESET
  • Pin 21 (GND), GND (Any GND will do)

Then open Arduino IDE. Select correct board (Nano in my case) and select Parallel Programmer and finally select “Burn bootloader”. You are ready. Arduino is now running at 22MHz. 🙂 You can program it normally by IDE and can use serial monitor like before.

Simple Four Channel Logic Analyzer/Oscilloscope

This simple program uses four pins of Arduino analog port. On version 0.3 there is about 4ms/division and about 400ms delay between measurements. Also measurements is made only when there is some signal on inputs. Old version 0.1 picture is below.

Version 0.2 image.

Version 0.3 image.

New version 0.3 code.

#include "SPI.h"
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9340.h"

#define _cs 10
#define _dc 9
#define _rst 8

Adafruit_ILI9340 tft = Adafruit_ILI9340(_cs, _dc, _rst);

volatile boolean measure = false;

void pciSetup(byte pin) {
  *digitalPinToPCMSK(pin) |= bit (digitalPinToPCMSKbit(pin));  // enable pin
  PCIFR  |= bit (digitalPinToPCICRbit(pin)); // clear any outstanding interrupt
  PCICR  |= bit (digitalPinToPCICRbit(pin)); // enable interrupt for the group
}

void setup() {
  
  pciSetup(A0);
  pciSetup(A1);
  pciSetup(A2);
  pciSetup(A3);
  
  tft.begin();
  tft.setRotation(3);
  tft.fillScreen(ILI9340_BLACK);

  tft.setTextColor(ILI9340_YELLOW);
  tft.setTextSize(2);

  tft.drawFastHLine(0,(tft.height()/5)*1, 320, tft.Color565(30,30,30));
  tft.drawFastHLine(0,(tft.height()/5)*2, 320, tft.Color565(30,30,30));
  tft.drawFastHLine(0,(tft.height()/5)*3, 320, tft.Color565(30,30,30));
  tft.drawFastHLine(0,(tft.height()/5)*4, 320, tft.Color565(30,30,30));
}

int xpos = 0;

  int pin0_state[161];
  int pin1_state[161];
  int pin2_state[161];
  int pin3_state[161];

void loop() { 
  if(!measure) return;
  measure = false;
  
  unsigned long start = 0;
  unsigned long end_time = 0;

  pin0_state[0]=0;
  pin1_state[0]=0;
  pin2_state[0]=0;
  pin3_state[0]=0;

  start = micros();
  for(int i = 0; i < 160; i++) {
    pin0_state[i] = analogRead(0);
    pin1_state[i] = analogRead(1);
    pin2_state[i] = analogRead(2);
    pin3_state[i] = analogRead(3);
  }
  
  end_time = micros() - start;

  for(int i = 0; i < 320; i=i+2) {
    //erase
    if(!(i%20)) tft.drawFastVLine(i, 17, tft.height(), tft.Color565(30,30,30));
    else tft.drawFastVLine(i, 17, tft.height(), ILI9340_BLACK);
    
    tft.drawPixel(i, ((tft.height()/5)*1)-(pin0_state[i/2]/32), ILI9340_YELLOW);
    tft.drawPixel(i, ((tft.height()/5)*2)-(pin1_state[i/2]/32), ILI9340_RED);
    tft.drawPixel(i, ((tft.height()/5)*3)-(pin2_state[i/2]/32), ILI9340_GREEN);
    tft.drawPixel(i, ((tft.height()/5)*4)-(pin3_state[i/2]/32), ILI9340_CYAN);
  }

  tft.setCursor(0, 0);
  tft.fillRect(0, 0, 320, 17, ILI9340_BLACK);
  tft.print((end_time/1000)/16); //one div is X milliseconds
  tft.print("ms/div, int:");
  tft.print((micros() - start)/1000); //interval time
}

ISR (PCINT1_vect) {
  measure = true;
}

Here is simple analog datalogger code. Analog value can be between zero and 127. It is viewable with external software.

void setup() {
pinMode(A3, INPUT); 
pinMode(A2, INPUT); 
pinMode(A1, INPUT); 
pinMode(A0, INPUT);

Serial.begin(9600);
}

void loop() {

  char testi[101] = {};
  char testi1[101] = {};
  char testi2[101] = {};
  char testi3[101] = {};
  
  for(byte i=0; i<100; i++) {
    int temp0 = analogRead(0);
    int temp1 = analogRead(1);
    int temp2 = analogRead(2);
    int temp3 = analogRead(3);
    testi[i] = (temp0/8)-1;
    testi1[i] = (temp1/8)-1;
    testi2[i] = (temp2/8)-1;
    testi3[i] = (temp3/8)-1;
  }

  Serial.println(testi);
  Serial.println(testi1);
  Serial.println(testi2);
  Serial.println(testi3);
  Serial.println("new");
}

Even simpler version that outputs data in CSV format.

void setup() {
pinMode(A3, INPUT);
pinMode(A2, INPUT);
pinMode(A1, INPUT);
pinMode(A0, INPUT);

Serial.begin(9600);
}

void loop() {

  char text[101] = {};
  
  for(byte i = 0; i < 93; i = i + 8) {
    int temp0 = analogRead(0);
    int temp1 = analogRead(1);
    int temp2 = analogRead(2);
    int temp3 = analogRead(3);
    text[i] = (temp0/8)-1;
    text[i+1] = ',';
    text[i+2] = (temp1/8)-1;
    text[i+3] = ',';
    text[i+4] = (temp2/8)-1;
    text[i+5] = ',';
    text[i+6] = (temp3/8)-1;
    text[i+7] = '\n';
  }
  Serial.print(text);
}

Now it’s possible to save and study data right from RTC circuit and motherboard.

Self made Cell Phone

I built a cellular phone. It has a touchpad from old laptop and small LCD display. GSM module is SIM800L. Heart of a phone is Arduino Nano. Next I’am going to write a program to it so I can make and receive calls. Touchpad is very unique user interface. Case is made from plastic from old laptop.

Touchpad uses PS2 protocol. GSM modem uses softwareSerial library and LCD display is HD44780 compatible.

 

 

 

There is a place for SIM card in side of a phone and micro USB connector for normal phone charger. Back door is easily removable. It is fixed with magnet.