The star of the show is the built-in 'pulseIn()' function, which gives the length of a low or high pulse. With these two measurements the calculation of duty cycle and frequency of the PWM signal is straightforward.
I have two different versions, simple and slightly longer.
The slightly longer code takes a user-specified time delay over which the maximum length is taken to help prevent truncation of a signal. For example, if an input pulse of 10 ms has already been running for 2 ms and the pulseIn function is called, it may return 8 ms. I am actually not sure if this is the way pulseIn works, but I tried both. With the default Arduino PWM frequency of approximately 490 Hz (http://arduino.cc/en/Reference/analogWrite), the slightly longer code returns 490 +/- 3 Hz, while the simple code returns 500 +/- 3 Hz. I tested this over low and high duty cycles. So it appears the slightly longer code has slightly better accuracy.
Simple code:
//Reads a PWM signal's duty cycle and frequency.#define READ_PIN 13#define PWM_OUTPUT 10static double duty;static double freq;static long highTime = 0;static long lowTime = 0;static long tempPulse;void setup(){pinMode(READ_PIN,INPUT);Serial.begin(9600);analogWrite(PWM_OUTPUT,230);}void loop(){readPWM(READ_PIN);Serial.println(freq);Serial.println(duty);}//Takes in reading pins and outputs pwm frequency and duty cycle.void readPWM(int readPin){highTime = 0;lowTime = 0;tempPulse = pulseIn(readPin,HIGH);if(tempPulse>highTime){highTime = tempPulse;}tempPulse = pulseIn(readPin,LOW);if(tempPulse>lowTime){lowTime = tempPulse;}freq = ((double) 1000000)/(double (lowTime+highTime));duty = (100*(highTime/(double (lowTime+highTime))));}
Slightly longer code:
//Reads a PWM signal's duty cycle and frequency.#define READ_PIN 13#define READ_DELAY 100#define PWM_OUTPUT 10static double duty;static double freq;static long highTime = 0;static long lowTime = 0;static long tempPulse;static long lastSeen;void setup(){pinMode(READ_PIN,INPUT);Serial.begin(9600);analogWrite(PWM_OUTPUT,230);}void loop(){readPWM(READ_PIN);Serial.println(freq);Serial.println(duty);}//Takes in reading pins and outputs pwm frequency and duty cycle.void readPWM(int readPin){highTime = 0;lowTime = 0;lastSeen = millis();while((millis()-lastSeen)<read_delay){< div="">tempPulse = pulseIn(readPin,HIGH);if(tempPulse>highTime){highTime = tempPulse;}}lastSeen = millis();while((millis()-lastSeen)<read_delay){< div="">tempPulse = pulseIn(readPin,LOW);if(tempPulse>lowTime){lowTime = tempPulse;}}freq = ((double) 1000000)/(double (lowTime+highTime));duty = (100*(highTime/(double (lowTime+highTime))));}
hello,
ReplyDeletei wanna measure the pWM of a motor controller.
do i have to connect pin 10 also?
or only pin 13?
i tried out the normal pulsein function. it gave me
9,3 millsec.
but i have to know the period cause i want to connect a NE555.
lastSeen does not name a type
ReplyDeleteHi
ReplyDeleteGreat code. I can't compile the longer code version because I get a error about expression ,,< div="">". It is necessary to propelrly works of program?
Thanks
Pawel