Read and display PWM

Hello. I have a need to measure the pwm value of a couple pins on a furnace. I understand that it is possible to measure pwm using an Arduino, and I have several variations of arduinos kicking around. Is there a sketch around that will do this for me, as it is a little beyond my knowledge.

I need to know the pwm value to know the position of the gas valve in a modulating furnace.

If you can help me, thank you in advance.

Yes, it is possible to use an arduino to measure pulse lengths and repeat periods.

Do you have the furnace specifications, or can you get an oscilloscope on the pins you want to measure?

What is the voltage of the signal you wish to read?
What is the frequency of the signal you wish to read?
What is the minumum/maximum pulse widths of the high and low periods?

Hi,
Can you post the make and model and spec of the modulator that is fed the PWM and controls the position of the gas valve.

What information have you got about the PWM, what is its frequency?
What device is supplying the PWM signal?

Tom... :slight_smile:

On the other hand a resistor and capacitor onto the PWM and then into an analogue input pin and simply read it.

cattledog:
Yes, it is possible to use an arduino to measure pulse lengths and repeat periods.

Do you have the furnace specifications, or can you get an oscilloscope on the pins you want to measure?

What is the voltage of the signal you wish to read?
What is the frequency of the signal you wish to read?
What is the minumum/maximum pulse widths of the high and low periods?

Voltage is 5vdc

0-95%

I don't know the pulse width

Is this the info we're looking for?

I'd go with Mike's suggestion - smooth then read it as an analogue voltage.

I would use pulseIn() to measure the PWM. It's a pretty crude function that has no place in medium to advanced Arduino programs but for something simple just measuring one thing, it's great.

Measure the high pulse, then measure the low pulse. Assume that the output didn't change much between your two measurements. Print the results to serial 5 times per second.

MorganS:
I would use pulseIn() to measure the PWM. It's a pretty crude function that has no place in medium to advanced Arduino programs but for something simple just measuring one thing, it's great.

Measure the high pulse, then measure the low pulse. Assume that the output didn't change much between your two measurements. Print the results to serial 5 times per second.

Where could I find some code for this?

What I want to do is read the pulse PWM value, and display it on a 16x2 LCD and have it update as the PWM value changes.

1 Like

Attached is a program I wrote to display frequency & duty cycle of a PWM signal.
The signal needs connecting to pin 2 of your UNO/MEGA (suitably conditioned to be 0-5V only) and it is currently setup to output a test tone on pin 9 so you can link pin 9 to pin 2 and see it working.

Frequency_Counter.ino (2.74 KB)

michaeli:
Where could I find some code for this?

You know this attitude saddens me and we are seeing it increasingly often in this forum.

You do not find code you write it, especially something as trivial as this.

The main reason I post here is to help people learn, not to do work for them.

1 Like

Grumpy_Mike:
You know this attitude saddens me and we are seeing it increasingly often in this forum.

You do not find code you write it, especially something as trivial as this.

The main reason I post here is to help people learn, not to do work for them.

Mike, I think that is an unfair statement, and a lousy attitude. What I did was come in here with a problem I didn't know how to solve, got some pointers, and an example how to solve it. Now I will take all this info, adapt it, rework it, play with it, change it some more, and make it into a useful device.

This is how new stuff gets created all the time, not everything is a ground breaking discovery. I just don't have the knowledge of the more senior programmers here, so I get pointed in the right direction by someone that knows more than me.

I didn't come in here and ask someone to make me a finished product, I asked for some help, and some very helpful people have helped me. I appreciate their help, and I also appreciate that people don't just say rtfm, or google it.

Settle down Mike, we're obviously not all you.

Michael

1 Like

and a lousy attitude.

So you think this is lousy?

Grumpy_Mike:
The main reason I post here is to help people learn, not to do work for them.

Grumpy_Mike:
So you think this is lousy?

Maybe "unnecessary" would have been a better choice.

The other reason I ask a question like I did was simple, why reinvent the wheel? That's why I asked where I may find some sample code.

I didn't say sample, as I read it again, but that on my part was implied.

Most forums chase people away with comments like that, hence unnecessary.

M

There is a reason that the IDE comes with hundreds of example sketches, to learn by seeing how something is done.

Often when I am trying to do something, I see how someone has previously done something similarly. Take their process and make it your own by adding my own creativity.

Sometimes they create new life entirely, other times the may turn into a collaboration. Sometimes they fizzle.

This, like for many others is my process. I learn by watching, and then doing.

Pwm outputs are something I understand how to do, but not the reading and converting part.

Let's work together, M.

1 Like

why reinvent the wheel?

Because unless you can reinvent the wheel, you will never be able to invent anything else. You will be forever begging for code.

What you want to do is not even difficult, it is just one instruction that measures the pulse.

I was not getting at you specifically and I would never want to chase away anyone with a genuine desire to learn. Look at how many posts I have made. Look at all the webpages on my site devoted to tutorials and teaching basics, all the projects you can take inspiration from. I only said that it saddened me, not made me angry or cross.

I understand how to do, but not the reading and converting part.

But you were told:-

I would use pulseIn() to measure the PWM.

For further information about this pulse function look it up in the reference section of the IDEs help file.

OK go on its here:-
https://www.arduino.cc/en/Reference/PulseIn

Had some time tonight to test this out. I added an lcd to facilitate portability.

I hooked it up to the furnace and the numbers are all over the place. What I'm having a lot of trouble understanding is that the numbers appear to be all over the place going into the hundreds and sometimes even momentarily into the thousands how can a duty cycle go into the tens of thousands? The only consistent thing with the duty reading is that it is not consistent. From what I saw,always over 100. More like 300-700 but higher too.

The frequency seems too hop between around 15 and 35 to 37 but generally stays fairly low, but the other number is all over the place.

I don't have access to. Real scope. The only scope I have is the laughable Arduino 2560 touch screen example. And even there I'm not really sure how to use it. What could make the duty cycle to above 100? Is it noise? Something else?

Thanks for your ideas and input. Should I post my code?

michaeli:
Thanks for your ideas and input. Should I post my code?

That's probably a good idea. Of course, a duty-cycle can never be higher than 100%.
Please use code tags to enclose your code. The </> button in the "Reply" dialog window.

See reply 13 and read the rest:

To get help, you must show us your complete sketch. Attach your code using the </> icon on the left side of the posting menu.

Ok, heres the code I am using currently.

I used the sample from above and added the LCD output. I had to change some pin values, as they conflicted with my LCD Interupt.
The lcd is showing the numbers and refreshing ok, just the numbers are all over the place. When I use the tone function to generate a square wave, it reads the freq and duty cycle perfectly

I can't take my PC to the furnace to test with serial output, but the output 'should' be the same as what im seeing on the LCD.

I have a call into the manufacturer of the furnace I am trying to read the value from, but I haven't heard back yet.

The LCD i'm using is the 6 button LCD Keypad Shield. (no brand name on it) Also, at this time I am not using any one the buttons, which is why there is no button reading code, not sure that I have a use for them anyways.

any help is appreciated.

-M-

#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);                                      // select the pins used on the LCD panel

// Min about 40Hz Max about 6000Hz but this may be due to problems with tone() used to test it.

// Interrupt variables
unsigned long fall_Time;                                                  // Placeholder for microsecond time when last falling edge occured.
unsigned long rise_Time;                                                  // Placeholder for microsecond time when last rising edge occured.
volatile int frequency = 0;                                               // Calculated frequency.
volatile byte dutyCycle = 0;                                              // Duty Cycle %
volatile byte isr0Tick = 0;                                               // Increments every ISR call (used to know if ISR fired since last read)

void PinChangeISR0(){                                                     // Pin 2 (Interrupt 0) service routine
  unsigned long total_Time;
  unsigned long on_Time;
  unsigned long lastRead = micros();                                      // Get current time
  isr0Tick++;                                                             // Kick the tires to say we have been here
  if (digitalRead(2) == LOW) {
    // Falling edge
    fall_Time = lastRead;                                                 // Just store falling edge and calculate on rising edge
  }
  else {
    // Rising edge
    total_Time = lastRead - rise_Time;                                    // Get total cycle time
    frequency = 1000000 / total_Time;                                     // Calulate frequency and store
    on_Time = fall_Time - rise_Time;                                      // Get on time during this cycle
    dutyCycle = 100 / ((float)total_Time / on_Time);                      // Convert to a percentage
    rise_Time = lastRead;                                                 // Store rise time
  }
}

void setup() {                                                            // Start setup
  lcd.begin(16, 2);                                                       // start the library
  lcd.setCursor(0,0);
  lcd.print(" York YP9C Gen2 ");                                          // Model designed for
  lcd.setCursor(0,2);
  lcd.print(" Mod Valve Disp ");                                          // Part Designed to test
  delay(1000);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("   Belongs to   ");                                          // if lost or stolen
  lcd.setCursor(0,2);
  lcd.print("Michael Illingby");                                          // belongs to
  delay(1000);
  lcd.clear();
  lcd.setCursor(0,0);
  lcd.print("michael.i@me.com");                                          // email
  lcd.setCursor(0,2);
  lcd.print(" Vernon, BC CA ");                                           // where I live
  delay(1000);
  lcd.clear();
  Serial.begin(115200);
  pinMode(2,INPUT);                                                       // Interrupt Pin
  Serial.println(F("ISR Pin 2 Configured For Input."));
  attachInterrupt(0,PinChangeISR0,CHANGE);                                // Attach interrupt handler
  Serial.println(F("Pin 2 ISR Function Attached."));
  
  // For testing                                                          // Connect pin D2 to D11
  // pinMode(11,OUTPUT);                                                  // Change 11 to Output
  // analogWrite(11,192);                                                 // Establish square Wave 
  tone(11,52);                                                            // Generate 52hz tone at 50% duty cycle to test input
}

void loop() {                                                             // Start Loop
  static byte oldisr0Tick = isr0Tick;
    Serial.print(F("Frequency / Duty Cycle = "));
    lcd.setCursor(0,0);
    lcd.print(F("Fq / Duty"));
    delay(1000);
  if (oldisr0Tick != isr0Tick) {                                          // ISR has fired so use it's values
    Serial.print(frequency);
    Serial.print(F(" / "));
    Serial.print(dutyCycle);
    lcd.clear();
    lcd.setCursor(0,1);
    lcd.print(frequency);
    lcd.print(F(" / "));
    lcd.print(dutyCycle);
    oldisr0Tick = isr0Tick;
  }
  else { // No interrupt since last read so must be 0% or 100%
    if (digitalRead(2) == LOW){
      lcd.clear();
      Serial.print(F("??? / 0x"));
      lcd.setCursor(0,1);
      lcd.print(F("??? / 0x"));
    }
    else {
      lcd.clear();
      Serial.print(F("??? / 100x"));
      lcd.print(F("                "));
    }
  }
  Serial.println();
}

You could try making 'frequency' 'an unsigned long', then rewriting this line:-frequency = 1000000 / total_Time;
for unsigned long maths:-

frequency = 1000000UL / total_Time;