serial monitor to check duty cycle of 555 timer in astable mode

Hi, I'm new, and I read the intros and stickies. I'm an Arduino novice, but I'm not completely new to electronics nor computer science concepts. I'm a photocopier tech, so I do much more troubleshooting of robots using wiring diagrams and the DMM than thinking about electronics engineering theory and design, or coding. A long time ago I got an 2 year electronics based degree to repair office equipment, and I did at one point take the basic electricity, electronics, and digital electronics. I forgot most of it, but I never needed to use most of the theory, except Ohms Law. As far as coding, I've dabbled in Basic and C here and I'm good at it when I apply myself, but the idea of sitting in one place to make a living at it turned me off

That's more than you needed to know maybe, but I feel some need to somehow qualify my noob level, ha ha.

I dug out my Arduino Uno that I got years ago, but never used much to play around with. I have been furloughed from work and I am trying to keep my brain busy and my morale up by learning and doing stuff with electronics parts and Arduino Uno.

So, I got some semiconductors, etc. and took off on any random tangent in order to learn whatever.

So, one project was to wire up a basic astable multivibrator using a 555 timer IC. The simple way of doing this produces a square wave, but not at 50% duty cycle. The duration for on is longer than for off, that is.

Since I don't have a scope, I was wondering if I could leverage an Arduino input pin and the serial monitor or other code to time the duration of high (pulse width) and then compare to the duration of low, thus checking whether or not the duty cycle is exactly 50%. I realize this may shift slightly as the circuit heats up.

So, maybe use the micros() function perhaps?

I read this topic, "Demonstration code for several things at the same time." Demonstration code for several things at the same time - Project Guidance - Arduino Forum

This thread is a beast, but I appreciate the example code and concepts discussed. I have not fully understood the code yet, but I uploaded it to my Uno and wired up the circuit, except I left off the servo since I don't have one.

The LEDs attached to pins 11, 12, and 13 blink as intended, but the press of my momentary switch caused the LED on pin 10 to blink, not stay on or off. That being said, since that post was for newbies, a circuit diagram would be very helpful to ensure I wired it correctly.

Another thing I would suggest, and that has been suggested to me in programming classes, is to comment even more for the benefit of newbies. For example, it would be great to see comments when += is used for compound addition as to what is going on and why. Don't think more comments is overkill, and try to pretend a newbie doesn't know anything.

Now the 555 timer blinks an LED in my circuit, which I removed and then fed the output to the Arduino as an input instead of a switch in a 8 segment LED "rolling dice" demo. So, it rolls the die every time the waveform goes low on a CA 8 segment LED display.

I kept the resistor (220 ohm) on the output when I removed the LED. Should I make the input pin on the Arduino an input/pullup for this or just input?

Let me know if you need more information, and thanks for reading.'

Take care, and have a great day,

Thanks,

Leif

const byte pin = 3;
void setup()
{
  Serial.begin(115200);
  pinMode(pin, INPUT_PULLUP);
}
void loop()
{
  unsigned long high = pulseIn(pin, HIGH);
  unsigned long low = pulseIn(pin, LOW);
  unsigned long duration = high + low;
  if (high > 0 && low > 0)
  {
    Serial.print("Duration (uS): ");
    Serial.print(duration);
    Serial.print("\tFrequency (Hz): ");
    Serial.print(1000000.0 / duration);
    Serial.print("\tDutyCycle (%): ");
    Serial.println((high * 100.0) / duration);
  }
  else
  {
    Serial.println("No signal found.");
  }
  
  delay(3000);
}

You can use the serial plotter as a scope / logic analyser to monitor the waveform if the signal's frequency is low; I think that that is what you want.

Simply read the pin and use serial.println to send the pin state.

void setup()
{
  Serial.begin(57600);
  while (!Serial);
}

void loop()
{
  Serial.println(random(0, 2));
  delay(10);
}

Replace the random() by a digitalRead().

Hey thanks so much for both examples. I've been playing around with it and I really like the plotter. I need to experiment more because I seem to get either a constant 1 (high) or constant 0 (low) testing various things.

I wonder what the threshold for high and low is to set the state to be read as such. +5VDC and 0 VDC, or is it .7 for low?

I tried an Arduino example using an analog input on a pot., and that worked, so at least I know it works somewhat.

Looks like I will have to test with the voltmeter maybe to see.

I will try monitoring a different circuit now also. I may as well use the code that flashes LEDs at once and monitor the state. I will maybe also use an analog input to see how that looks.

Thanks!

// Monitor pin 3 state for high/low AKA 1/0

const int pin3 = 3;
int monPin = digitalRead(pin3);
void setup() {
  Serial.begin(115200);
  while (!Serial);
  pinMode(pin3, INPUT); }

void loop() {
  Serial.println("pin3");
  Serial.println(monPin);
  delay(10);
}

ooops... I just typed in a reply for a couple of hours, but something went wrong when I tried to submit, then the back button didn't help me get back to what I composed. I got a dreaded confirm form resubmission message. That of course didn't work. All that work lost.

Anyway, I played with it some more, and I can see a drop from 5vdc to 0vdc when I measure from the source voltage to the Arduino digital pin 3 (as input or as output/low). The 555 output needs the ground to run a load on its output pin (also named pin 3). The Arduino becomes the load in the absence of the LED. However, even though I can see a change of state on the volt meter, the Arduino doesn't see it. If I reset the Arduino it might report all zeros instead of all ones in the serial monitor or plotter.

I think the issue is how the digital pins work. I can't really get the 555 timer to work without a ground, but the Arduino as ground will light the LED, but not detect the state change. Or, if I pull the 555 to ground on the breadboard as usual, and monitor the 555 output, I also get the same constant either 1 or 0 on the serial monitor.

I had fun putting the output of the 555 timer into an Arduino digital pin, and using the Arduino attached to another project I tried - rolling dice on a 7 segment display. Now, instead of pressing the switch to roll, the 555 timer going low and high rolled the die. I combined 2 learning projects.

This works to have one LED blink if I put anode to 555 pin 3 and cathode to Arduino pin 3:

// Pull Arduino pin 3 to ground to light LED driven by 555 timer circuit

const byte pin3 = 3;
int monPin3 = digitalRead(pin3);
void setup() {
  Serial.begin(115200);
  while (!Serial);
  pinMode(pin3, OUTPUT);
// This ground is not common to breadboard ground,
// only 555 timer output is attached with a 220 ohm resistor
  digitalWrite(pin3, LOW); }

void loop() {
  Serial.println("pin3");
  Serial.println(monPin3);
  delay(10);
}

Don't read a pin before setup; there is no guarantee that the hardware is properly initialised.
Change

int monPin3 = digitalRead(pin3);

to

int monPin3;

and read the pin in loop().

Your misunderstanding is probably that you think that int monPin3 = digitalRead(pin3); will constantly monitor the pin, which it doesn't.

void loop() {
  Serial.println("pin3");
  Serial.println(digitalread(pin3));
  delay(10);
}

You will need to make a schematic how you have connected everything; photo of handdrawn is fine.

You will also have to better describe what you exactly want to achieve, your description of connecting a LED between the 555 and the Arduino does not quite make sense to me and using an Arduino pin as output does not quite make sense to me.

If you just want to measure the output of the 555, connect it directly to the Arduino pin (assuming it's a 5V signal. A led can still be connected to the output of the 555 (using a resistor, obviously).

Based on your code, the below will monitor the pin

// connect 555 output to arduino pin 3
const byte pin3 = 3;

void setup()
{
  Serial.begin(115200);
}

void loop()
{
  //Serial.println("pin3");
  Serial.println(digitalread(pin3));
  delay(10);
}

If you want better timing precision you could use the Input Capture Pin:

// Measures the HIGH width, LOW width, frequency and duty-cycle of a pulse train
// on Arduino UNO Pin 8 (ICP1 pin).


// Note: Since this uses Timer1, Pin 9 and Pin 10 can't be used for
// analogWrite().


void setup()
{
  Serial.begin(115200);
  while (!Serial);

  // For testing, uncomment one of these lines and connect
  // Pin 3 or Pin 5 to Pin 8
  //                         HIGH    LOW      PERIOD    DUTY   FREQUENCY
  // analogWrite(3, 64);  // 512.00, 1528.00, 2040.00, 25.10%, 490.20 Hz
  // analogWrite(5, 64);  // 260.00,  764.00, 1024.00, 25.39%, 976.56 Hz

  noInterrupts ();  // protected code
  // reset Timer 1
  TCCR1A = 0;
  TCCR1B = 0;
  TCNT1 = 0;
  TIMSK1 = 0;

  TIFR1 |= (1 << ICF1); // clear Input Capture Flag so we don't get a bogus interrupt
  TIFR1 |= (1 << TOV1); // clear Overflow Flag so we don't get a bogus interrupt

  TCCR1B = _BV(CS10) | // start Timer 1, no prescaler
           _BV(ICES1); // Input Capture Edge Select (1=Rising, 0=Falling)

  TIMSK1 |= _BV(ICIE1); // Enable Timer 1 Input Capture Interrupt
  TIMSK1 |= _BV(TOIE1); // Enable Timer 1 Overflow Interrupt
  interrupts ();
}

volatile uint32_t PulseHighTime = 0;
volatile uint32_t PulseLowTime = 0;
volatile uint16_t Overflows = 0;

ISR(TIMER1_OVF_vect)
{
  Overflows++;
}

ISR(TIMER1_CAPT_vect)
{
  static uint32_t firstRisingEdgeTime = 0;
  static uint32_t fallingEdgeTime = 0;
  static uint32_t secondRisingEdgeTime = 0;

  uint16_t overflows = Overflows;

  // If an overflow happened but has not been handled yet
  // and the timer count was close to zero, count the
  // overflow as part of this time.
  if ((TIFR1 & _BV(TOV1)) && (ICR1 < 1024))
    overflows++;

  if (PulseLowTime == 0)
  {
    if (TCCR1B & _BV(ICES1))
    {
      // Interrupted on Rising Edge
      if (firstRisingEdgeTime)  // Already have the first rising edge...
      {
        // ... so this is the second rising edge, ending the low part
        // of tghe cycle.
        secondRisingEdgeTime = overflows;
        secondRisingEdgeTime = (secondRisingEdgeTime << 16) | ICR1;
        PulseLowTime = secondRisingEdgeTime - fallingEdgeTime;
        firstRisingEdgeTime = 0;
      }
      else
      {
        firstRisingEdgeTime = overflows;
        firstRisingEdgeTime = (firstRisingEdgeTime << 16) | ICR1;
        TCCR1B &= ~_BV(ICES1); // Switch to Falling Edge
      }
    }
    else
    {
      // Interrupted on Falling Edge
      fallingEdgeTime = overflows;
      fallingEdgeTime = (fallingEdgeTime << 16) | ICR1;
      TCCR1B |= _BV(ICES1); // Switch to Rising Edge
      PulseHighTime = fallingEdgeTime - firstRisingEdgeTime;
    }
  }
}

void loop()
{
  noInterrupts();
  uint32_t pulseHighTime = PulseHighTime;
  uint32_t pulseLowTime = PulseLowTime;
  interrupts();

  // If a sample has been measured
  if (pulseLowTime)
  {
    // Display the pulse length in microseconds
    Serial.print("High time (microseconds): ");
    Serial.println(pulseHighTime / 16.0, 2);
    Serial.print("Low time (microseconds): ");
    Serial.println(pulseLowTime / 16.0, 2);

    uint32_t cycleTime = pulseHighTime + pulseLowTime;
    Serial.print("Cycle time (microseconds): ");
    Serial.println(cycleTime / 16.0, 2);

    float dutyCycle = pulseHighTime / (float)cycleTime;
    Serial.print("Duty cycle (%): ");
    Serial.println(dutyCycle * 100.0, 2);

    float frequency = (float)F_CPU / cycleTime;
    Serial.print("Frequency (Hz): ");
    Serial.println(frequency, 2);
    Serial.println();

    delay(1000);  // Slow down output

    // Request another sample
    noInterrupts();
    PulseLowTime = 0;
    interrupts();
  }
}

Thanks so much all! I will work on it. Yes, I was thinking of drawing the schematic.

What I found was a 555 timer has an output voltage of 3.5 volts and can drive TTL. So, I thought to add an NPN to the circuit. The NPN works, but I don't get the signal yet. So, I may used a digital pin OUTPUT high for the +5VCC

I used the transistor driver concept here: https://www.electronics-tutorials.ws/waveforms/555_timer.html

I will be away for a couple of days, so thanks again.

Thanks so much to both of you! Thanks for the help with the code, I missed a few details there to be sure.

This code works well with the serial plotter:

// pin on Arduino from 555 output

const byte pin3 = 3;

void setup() {
  Serial.begin(115200);
  while (!Serial);
  pinMode(pin3, INPUT_PULLUP);
}

void loop() {
  Serial.println("pin3");
  Serial.println(digitalRead(pin3));
  delay(10);
}

I made progress, but I had this mistake:

digitalRead(pin3);
  Serial.println("pin3");
  Serial.println(pin3);

Of course that always returned "3" because it was the value of the variable, not the input. I appreciate how you combined the digitalRead within the Serial.println, that makes a lot of sense and is efficient.

Both using INPUT or INPUT_PULLUP work to read the signal. I use the INPUT_PULLUP to be safe.

Thanks again, and I will attach a schematic of my specific setup at some point after I draw it. But my issue is resolved.

John Wasser, I tried your first code also and it was no signal mostly. I will try with the input pin 8 for fun also.

555pin3.png

leafybye:
Since I don't have a scope, I was wondering if I could leverage an Arduino input pin and the serial monitor or other code to time the duration of high (pulse width) and then compare to the duration of low, thus checking whether or not the duty cycle is exactly 50%.

leafybye:
This code works well with the serial plotter:

// pin on Arduino from 555 output

const byte pin3 = 3;

void setup() {
 Serial.begin(115200);
 while (!Serial);
 pinMode(pin3, INPUT_PULLUP);
}

void loop() {
 Serial.println("pin3");
 Serial.println(digitalRead(pin3));
 delay(10);
}

I suppose you could eyeball the Serial Plotter to see if the duty-cycle looked roughly 50% but I don't see how you could get much accuracy.

Agreed. To get the accuracy I need to try to leverage some code. I haven't yet tried your last code, but the basic Serial.println("text"); slows the reading down it seems as it needs time to display characters.

Here:

const byte pin = 3

Are we using that to save a little memory, because it is 8 bit and not 16 bit?

Instead of:

const int pin = 3

With this code, the serial monitor shows a stream of 1 then 0 with how many depending on the period. I wonder how much time each number is a slice of the low or high part of the pulse.

I'm happy to have at least made progress and see some usable input.

If I monitor at the output of the 555 I get the high and low showing on the serial plotter that matches my monitoring LED on the circuit. If I monitor after my NPN transistor it is an inverse pulse, of course.

Hi,

I drew out my schematic. I have not done the math as to what the period is using this combination of resistors and capacitor.

I got it working to where I can probe at the output pin of the LM555 and I see the graph that represents the high and low over time.

I need to re-wire it so it has a 50% duty cycle. Right now I'm using the 10k trim pot to change the blink rate, and eventually the serial plotter can't detect the lows, but hey, what can I expect, it is not a real probe, just an Arduino after all.

I double checked the connections with an Ohm meter, so the schematic should be correct.

I accidentally drew the potentiometer between pins 2 and 6 by mistake at first, then crossed it out. You can see my correction.

I have yet to try more code for the monitoring, but the circuit can also used to send an Arduino pin low instead of using a tactile switch.

Or connect something active high between the 555 output pin and the +5VDC supply to turn it on like the green LED in my example.

I took a photo of my schematic, and I used IrfanView to compress it to max for png, but it still was over 2 megabytes. So, please see the link above instead.

Photo for fun: Green LED on low pulse, Red LED on high pulse - Album on Imgur