DIY Electronics

Site visitors: 14537
Updated: 15 May 2024

Microcontroller
Simple circuits
Explanation
Diagrams

Simple electronics as a hobby

Projects

Arduino Atmega328p
Arduino tachometer - 555 PWM - IR sensor - ATmega328p oled - sketch
Arduino "Simon says" - Arduino sketch
Distance measurement with temperature correction - Arduino code
Dec Hex Binary game - Arduino code for the hex game
pms5003 sensor circuit - Arduino code
Logic gates game - Arduino code
Op Amp
Brushless motor with IR sensor - brushless motor with reed switch
Clap switch
Game based on shift register IC - Arduino code for the shift register game
555 timer
Build your own 555 timer with transistors
Build a 555 timer with op-amp and NOR logic gates
Police LED strobe lights
Monostable 555 with touch plate
ESP32
ESP32 Web Server using WiFi AP or WiFi client -Arduino sketch - MIT App inventor
ESP32 Web Server with 4x4 keyboard - Source sketch
esp32cam with PIR sensor - esp32cam write to sd-card
PIC microcontrollers
Scare the neighbours' cat - Source code
Voltmeter pic12f675 i2c - Pic12f675 code (XC8 compiler)
PIC12F629 PWM in MPASM assembler - MPASM code
PIC12F629 dice in MPASM assembler - MPASM code
PIC12F629 button interrupt in MPASM assembler - MPASM code
PIC10F200 rolling die in MPASM assembler - MPASM code
Linear feedback shift register - PIC 16F684 code - LFSR code in C
Random flasher number generator - PIC 16F690 code
Seeeduino xiao
Animation using a Seeeduino xiao and Oled 128x64 - Source code - Convert BMP to HEX using c#
Arduino Attiny
Program ATtiny85 using Arduino UNO
Raspberry Pi
Raspberry Pi LCD 20x4 - RSS feed - lcd_display.service - aqi.sh - read_aqi.c - read_rss.c
MIT app Inventor
Score Card using MIT App Inventor - Code in block mode
65c02
AT28C256 EEPROM programmer with sd_card - code for Arduino NANO
Microbit
Micro:bit as slot-machine - Code for slot machine in Javascript
Miscellaneous
16x2 LCD display - 16x2 commands
8 queens problem in Python
Explanation of 15 small electronic circuits - DC boost converter - Park assist - Astable multivibrator 555 timer - Heart rate sensor - JK flip flops - 1 bit full adder - Key code comparator - VU meter - Oscillator - DC boost converter with load - Clap switch - 7-segments counter - Quad oscillator - Tone burst generator - Ultrasonic distance measurement

Arduino tachometer

For this project I used a small DC motor. A sandpaper nail file is hot-glued to its shaft as a makeshift propeller. There are three distinct circuits to this project. The first one is to control the speed of the motor. A ne555 timer is used and PWM (pulse width modulation) for that purpose. PWM works like a switch, turning the motor on and off very quickly. Image The second circuit is an IR sensor. Every time the propeller passes the IR-LED and photodiode a signal is generated and the output goes high. The third circuit comprises of an ATmega328p chip and an OLED 128x64 display. It takes the signal from the IR circuit as input and calculates the rotation speed and shows the results on the display.
Click here to see the video.

Image Image  Image Image

NE555 Pulse Width Modulation

ImageThis circuit controls the speed of the motor by turning the potentiometer (P1). When the power is turned on the voltage on pin 2 and 6 will be below 1/3 of the 5 volt, because of the discharged capacitor (C1). This results in pin 3 going high. Very quickly the capacitor gets charged and the voltage on pin 2 and 6 reaches 2/3 of the voltage and this makes pin 3 to go low and turn on the discharge pin 7. The open pin 7 discharges the capacitor, dropping the voltage below 1/3 again. Pin 3 shows a square wave output. The percentage of the power turned on in relation to the complete cycle (period on + period off ) is called duty cycle. The duty cycle is controlled by the pot (P1).

Image When the resistance on both fixed ends (behind the diodes D1 & D2) are equal (the wiper is in the middle) the duty cycle is about 50%. The frequency should stay the same no matter the duty cycle. It's around 282 Hertz. Good explanation is found here!

IR sensor

IR sensor circuit consist of an Infrared emitting LED and a photodiode. The IR Led is turned on all the time. The light can be seen using the camera of a smart phone. The photodiode resistance changes according to the amount of IR light falling on it, therefor the voltage drop across it also changes and by using a voltage comparator (like LM358) the output changes accordingly. A photodiode has a P-N junction and is reversed biased. The cathode (shorter lead) should be attached to the supply voltage and the anode (longer lead) towards ground. Image The LM358 is an op-amp and it turns the output high when the non-inverting terminal (+) has a higher voltage than the inverting terminal (-).
In my project I used a micropic 12F675 as comparator and it is programmed to turn GP2 (pin 5) high when input pin GP0 (pin 7) has a higher voltage than GP1 (pin 6). The potentiometer is used for fine tuning. When the propeller of the motor passes by it reflects the IR, the photodiode starts to conduct and the comparator turns the output high. The red LED is an indicator of that event. The output signal is input for the third circuit.

ATmega328p

Image

The ATmega328p chip receives the input signal on pin 2 (physical pin 4). Pin 2 is one of the two interrupt pins. In the Arduino sketch an interrupt routine is called on the rising edge (when pin 2 goes from low to high). A counter is incremented. After 3 seconds the interrupt routine is halted (detached) and the counter is used for the calculation of hertz and rpm. The result is written to the oled 128x64 display and the interrupt routine is restarted (attached). A variable used in an interrupt routine must be declared as volatile and do not do any calculations with this variable. It messes up the routine. Just copy it into another variable.

Arduino sketch

#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels

// Declaration for an SSD1306 display connected to I2C (SDA, SCL pins)
#define OLED_RESET     -1 // Reset pin 4 (or -1 if sharing Arduino reset pin)
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);

#define interrupt_pin 2

unsigned int rpm;
volatile unsigned int counter = 0;
unsigned long passedtime = 0;

void draw(unsigned int _rpm) {
  unsigned int cnt;
  cnt = counter / 6;
  display.clearDisplay();
  display.setTextSize(2);             // Normal 1:1 pixel scale
  display.setTextColor(WHITE);        // Draw white text
  display.setCursor(0,0);             // Start at top-left corner
  display.print("RPM:");
  display.setCursor(0,16);
  display.print(_rpm, DEC);
  display.setCursor(0,32);
  display.print("Hz:");
  display.setCursor(0,48);
  display.print(cnt, DEC); 
  display.display();  
}

void isr() {
      counter++;
 }

void setup() {

    display.begin(SSD1306_SWITCHCAPVCC, 0x3C);

    display.clearDisplay();
    display.setTextSize(2);             // Normal 1:1 pixel scale
    display.setTextColor(WHITE);        // Draw white text
    display.setCursor(0,0);             // Start at top-left corner
    display.print("START");
    display.display();
    attachInterrupt(digitalPinToInterrupt(interrupt_pin), isr, RISING);
    passedtime = millis();
}

void loop() {
  if ((millis() - passedtime) > 2999){   
    detachInterrupt(digitalPinToInterrupt(interrupt_pin)); //Interrupts are disabled
  //  noInterrupts();  no working
   rpm = 10 * counter;   //   60 * counter(12) / 2 / 3  
   draw(rpm);
   counter = 0;   
   passedtime = millis(); 
   attachInterrupt(digitalPinToInterrupt(interrupt_pin), isr, RISING);
  } 
}


Brushless motor with IR sensor

image The fidget spinner has a magnet in each of its 3 arms. The electromagnet is made out of a plastic spindle from a sewing machine and the wire used to wind onto the spindle is coated copper with an enamel coating that must be removed from the ends to make an electrical connection. The wire is 34 AWG and a drilling machine with variable speed is used to wind the coil. Turning the electromagnet on and off is done by an IR sensor circuit, the same circuit as for the tachometer. Rotation direction depends on the positioning of the IR-pair as demonstrated in the video. To power the coil 9 volt is applied, but the IR-sensor circuit has a maximum of 5 volt. An LM7805 voltage regulator brings the 9 volt down to 5. imageThere are 4 bypass capacitors, 2 on the input and 2 on the output. Their function is to smoothen out any spikes in the voltage.
Click here to see the video.image

ImageElectromagnet       IR sensor

Brushless motor with reed switch

Image The electromagnet is turned on when a magnet is near the reed switch. The contacts inside the switch close the circuit. The reed switch is also used as a clock signal for the decade counter 4017. Only 5 of the 10 possible LEDs are used. The 22 uF capacitor is necessary to smoothen the voltage spikes or the 4017 IC goes bonkers. The rotation speed is about 40 Hz using a strobe light app.

Image
Click here to see the video.


Simon says

"Simon says" is a memory game with 4 buttons, 4 LEDs and a speaker. Follow the pattern of lights and sounds and repeat the same combination. It starts with one light (+sound), then 2 and so on, until it reaches 10 and the game is over. As a player you have to memorize the series of lights and sounds and than reproduce it by pushing the buttons in the same order. The challenge was to write the Arduino sketch for this game. Click here to see the video.

imageimage

Arduino sketch

#define NOTE_A4  440
#define NOTE_F4  349
#define NOTE_C5  523
#define NOTE_E5  659
#define NOTE_F3  175
#define NOTE_E3  165
#define NOTE_B2  123
#define NOTE_B4  494
#define NOTE_F5  698

#define startbutton 12
#define mic 13

  int buttons[] = {0,1,2,3};
  int segment7[]  = {4,5,6,7};
  int leds[] ={8,9,10,11};
  int button_notes[] = {NOTE_A4,NOTE_F4,NOTE_C5,NOTE_E5};
  
  int starttune[] = {NOTE_A4, NOTE_A4, NOTE_A4, NOTE_F4, NOTE_C5, NOTE_A4, NOTE_F4, NOTE_C5, NOTE_A4, NOTE_E5, NOTE_E5,
NOTE_E5, NOTE_F5, NOTE_C5, NOTE_A4, NOTE_F4, NOTE_C5, NOTE_A4}; 
  // Array with the note durations: a quarter note has a duration of 4, half note 2 etc.
  int startdurations[]  = {4, 4, 4, 5, 16, 4, 5, 16, 2, 4, 4, 4, 5, 16, 4, 5, 16, 2};
  int startleds[] = {8,8,8,9,10,8,8,9,8,11,11,11,9,10,8,9,10,8 };
//  int starttempo = 120;
  int failtune[] = {  NOTE_F3, NOTE_E3, NOTE_F3, NOTE_E3, NOTE_B2};
  int faildurations[] = {  8, 8, 4, 4, 1};
  int failleds[] = { 11,10,11,10,8 };
//    
  int wintune[] = {  NOTE_B4, NOTE_E5, NOTE_F5, NOTE_B4, NOTE_E5, NOTE_F5};
  int windurations[] = {  8, 8, 8, 4, 4, 1};
  int winleds[] = { 8,10,11,8,10,11 };

    
int turn;  // 0 = first turn  
long old = 5;
int random_array[10]; 
int input_array[10];  
boolean failed = false;

void setup() 
{

  for (int i=0; i < 4; i++) {
    pinMode(buttons[i], INPUT);
    digitalWrite(buttons[i], HIGH);  // 20K pull-up    
    pinMode(segment7[i], OUTPUT);
    digitalWrite(segment7[i],LOW);
    pinMode(leds[i], OUTPUT);
  }

  pinMode(mic, OUTPUT);
  pinMode(startbutton, INPUT);
  digitalWrite(startbutton, HIGH);
      
   
  playTune(starttune,startdurations,startleds, 18);
  delay(1000);
}

void playTune(int notes[], int durations[], int _leds[], int _size) {

     for (int thisNote = 0; thisNote < _size; thisNote++) {
     int _duration = 1000 / durations[thisNote];     //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
     digitalWrite(_leds[thisNote], HIGH);
     tone(mic, notes[thisNote], _duration);
     int pauseBetweenNotes = _duration * 0.65;   // to distinguish the notes, set a minimum time between them.
     delay(pauseBetweenNotes);
     digitalWrite(_leds[thisNote], LOW);
     delay(pauseBetweenNotes);
     // stop the tone playing:
     noTone(mic);
   } 
}

void show_random(int act) {  // 0 1 2 3 4 5 
  long val;
  // show what has been recorded so far
  for (int i=0; i < act; i++) {
    val = random_array[i];
    digitalWrite(leds[val],HIGH);
    tone(mic,button_notes[val], 500);    
    delay(700);
    digitalWrite(leds[val],LOW);
    delay(500);
  }
  // add one memory to the array
    val = random(0,4);  // I don't like too many doubles
    if (val == old) {
      val = random(0,4);
    } else {
      old = val;
    }
    random_array[act] = val;
    digitalWrite(leds[val],HIGH);
    tone(mic,button_notes[val], 500);    
    delay(500);
    digitalWrite(leds[val],LOW);
  
  delay(500);
}

void update_7seg(int round) {
  round++;
  for (int i=0; i<4; i++) {
    digitalWrite(segment7[i], LOW);
  }
  switch (round) {
  case 1:
    digitalWrite(segment7[0], HIGH);
    break;
  case 2:
   digitalWrite(segment7[1], HIGH);
    break;
  case 3:
    digitalWrite(segment7[0], HIGH);
    digitalWrite(segment7[1], HIGH);    
    break;
  case 4:
   digitalWrite(segment7[2], HIGH);
    break;
  case 5:
   digitalWrite(segment7[0], HIGH);
   digitalWrite(segment7[2], HIGH);   
    break;
  case 6:
    digitalWrite(segment7[1], HIGH);  
    digitalWrite(segment7[2], HIGH);
    break;
  case 7:
   digitalWrite(segment7[0], HIGH);
   digitalWrite(segment7[1], HIGH);  
   digitalWrite(segment7[2], HIGH);
    break;
  case 8:
    digitalWrite(segment7[3], HIGH);
    break;
  case 9:
   digitalWrite(segment7[0], HIGH);
   digitalWrite(segment7[3], HIGH);
    break;
  default:
    break;
	}
}

void get_input(int act) {

  //   act = 0 1 2 3 4 5
  //   from 0 to 0 or from 0 to 1
  for (int i=0; i <= act; i++) {
    int k = 0;
    boolean button_pressed = false;
  
    while (button_pressed == false) {
      if (digitalRead(buttons[k]) == LOW) {

           button_pressed = true;
            if (random_array[i] == k) {
              digitalWrite(leds[k],HIGH);
              tone(mic,button_notes[k], 300);    
              delay(500);
              digitalWrite(leds[k],LOW);

            } else {
              user_failed();
              return;
              
            }
            while (digitalRead(buttons[k]) == LOW) { 
            //  wait for the release of this button
           }                     
      }
      k++;
      if (k == 4) k=0;
    } // while
  } // for loop
  update_7seg(act); 
}

void user_failed() {
  failed = true;
  playTune(failtune, faildurations, failleds, 5);
}

 
void loop() {   
  update_7seg(10);
  randomSeed(analogRead(0));  
  turn = 0;
  failed = false;
  while(digitalRead(startbutton) == HIGH) {
      // wait
    }
  while (failed == false) {
    delay(2000);
    show_random(turn);
    get_input(turn);
    
    turn++;
    if (turn == 10) {     
      if (failed == false) {
        playTune(wintune, windurations, winleds, 6);
      }
      failed = true; // actually it's a win
    }
  }
}
image