Using Optocoupler to Read PWM (Duty Cycle) Value from 12 V Circuit - Issue

I am having a puzzling time trying to figure out my issue here. Hopefully someone can help me out.

I have the following circuit: Octo is a PC817 (SHARP)

Using a multimeter on the arduino side, i have no issues reading Duty Cycle. So i know the octo and circuit is working.

When i try to read the value Via a digital pin, i receive "nan". Which would point to a calculation error, (i believe).

Interesting thing, is if i replace the 12v side and feed both sides of the octo from Arduino, (input side using a PWM output from a digital pin) (input side same as picture above) it works perfectly.
You will see this fuction edited out in the following code"//".

const int PWMInPin=3;
//const int PWMOutPin=6; //Used to verify circuit with 5V into octo

float PWMIn;
int pulseHigh; // Integer variable to capture High time of the incoming pulse
int pulseLow; // Integer variable to capture Low time of the incoming pulse
float pulseTotal; // Float variable to capture Total time of the incoming pulse
float frequency; // Calculated Frequency
float DC; // Calculated Duty Cycle


void setup() 
{
  // put your setup code here, to run once:
  Serial.begin(9600);
  pinMode(PWMOutPin,OUTPUT);
  pinMode(PWMInPin, INPUT);
  delay(5000);
}

void loop() {
  // put your main code here, to run repeatedly:
  //analogWrite(PWMOutPin,200); //Used to verify circuit with 5V into octo
  pulseHigh = pulseIn(PWMInPin,HIGH);
  pulseLow = pulseIn(PWMInPin,LOW);    
  pulseTotal = pulseHigh + pulseLow; // Time period of the pulse in microseconds
  frequency=1000000/pulseTotal; // Frequency in Hertz (Hz)
  DC=pulseHigh/pulseTotal*100; // Duty Cycle (%)
  Serial.print("Frequency: ");
  Serial.print(frequency);
  Serial.println(" Hz");
  Serial.print("Duty Cycle: ");
  Serial.print(DC);
  Serial.println(" %");
  Serial.println();
  delay(500); //Delay in order to read Serial Write
}

I have also tried using the pulseIn function, but i can't have blocking in this particular application.

Where do you receive that error?

What is the frequency of the PWM you are trying to read?

How can you tell from just a meter, you need to look at an oscilloscope to know what sort of signal you are getting from the opto coupler. The one you are using is not a particular fast one. This is probably the cause of your problem.

But the code you are posting is blocking in this respect because you have two pulseIn calls.

1 Like

to ready PWM you need something more responsitive IMHO... ie better to make use of interrupts.

so something like this maybe:

//PWM read using External Interrupts. Following code measures the time a PWM pulse is HIGH
#define INTR_2 2
#define MAX_SIZE 16 //"power of 2" buffer size is recommended to dramatically optimize all the modulo operations for ring buffers.

volatile uint32_t t_rise;
volatile uint8_t tail = 0;
uint32_t pwm_buf[MAX_SIZE];
uint8_t head = 0;

void rising() {
  t_rise = micros();
  attachInterrupt(digitalPinToInterrupt(INTR_2), falling, FALLING);
}

void falling() {
  pwm_buf[tail] = micros() - t_rise;
  tail = (tail + 1) % MAX_SIZE;
  attachInterrupt(digitalPinToInterrupt(INTR_2), rising, RISING);
}

void setup() {
  Serial.begin(115200);
  // when pin D2 goes LOW->HIGH, call the rising function
  attachInterrupt(digitalPinToInterrupt(INTR_2), rising, RISING);
}

void loop() {
  if (head != tail) {
    
	noInterrupts(); //to avoid corruption uint32_t value
	uint32_t pwm_value = pwm_buf[head];
	interrupts();
	
    head = (head + 1) % MAX_SIZE;

    Serial.print("pulse width: ");
    Serial.print(pwm_value);
    Serial.println("us");
  }
}

hope that helps....

1 Like

Thanks for the Reply Grumpy, @Grumpy_Mike

The error is received during the Serial.print, but i believe, its either an issue with the calculation/float during the calculation (putting in a number to divide by 0 or similar), or more likely that the ardrino is not getting usable data it can use for the calculation. I believe it is timing out, and spitting out nan "Not a Number".

Please bare with me, i am a machnical guy, not electric guy.

Putting my MM on the feed to the input side of the Octo is giving me 16 kHZ. - Unfortunally i do not have a oscilloscope at the moment, but it might come down to either buying or barrowing one soon. For some reason i didn't think to try the "output" side of the octo. But i will tonight.

My MM does read Duty Cycle %, and is giving me the same % before and after the Octocoupler, so i would think the Octo is fast enough to handle the pulse. (If i read it correctly the limit on this Octo is 80 kHZ)

Thank you for picking up the blocking, the plan was to just get data and then work on the Interrupts similar to @sherzaad 's reply below.

-Chris

Well it certainly cant go any faster, but where you have to be careful is that manufacturers want to present the data that shows their product in the best possible light. So while that figure was derived from the time to respond, that is not saying that the shape of the output at that speed will be sufficient to drive an output pin in a digital setting to be able to read the pulse width. Digital signals should be sharp, that is they must have fast edges in order to trigger correctly.

Now the internal pins on an Arduino Uno have bit of a circuit to sharpen up the edges internally when a pin is an input but it is not always enough. That is why you must actually see it on a scope.

That is very probably the case and could be caused by the numbers in the calculations being wrongly specified. By default all numbers you put in are integer types. so something like

Is trying to put the number 1000000 into an integer which has the range of
to quote

On the Arduino Uno (and other ATmega based boards) an int stores a 16-bit (2-byte) value. This yields a range of -32,768 to 32,767

frequency=1000000UL/pulseTotal

To see if it will treat this number as an unsigned long.

1 Like

Thanks @sherzaad , @Grumpy_Mike !

I was finally able to get the interrupts and read the pulse/duty cycle.

I have a working sketch, but i am having an issue with the interrupt incorporation.

This is a cut down version of my sketch, so its a little messy, but its a decent example of what i am trying to do. Basically i am reading pulse/duty cycle from a circuit and using a switch to start and stop datalogging to an SD card. Each one of these work separately but not together.

The pulse reading with the intrupt is working perfect, but when i press the push button to start the data log process the prg. gets hung up. Could you help point me in a direction to take this?

//    FILE: freqCounter06.ino
//  AUTHOR: Rob Tillaart
//    DATE: 2013-04-13
// PURPOSE: freq counter

#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include "RTClib.h"

#define DISPLAY_INTERVAL   1000000L
#define IRQPIN             3

//LCD Address
LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x3F for a 16 chars and 2 line display

volatile unsigned int count = 0;
volatile unsigned int ovf = 0;

const int PWMOutPin=6; //Used to verify circuit with 5V into octo


unsigned long frequency = 0;
unsigned long highCount = 0; 
unsigned long totalCount = 0;
float dutyCycle = 0;
unsigned long lastDisplay = 0;

  // Data Logging setup
    #define LOG_INTERVAL  200 // mills between entries (reduce to take more/faster data)
    #define SYNC_INTERVAL 1000 // mills between calls to flush() - to write data to the card
    #define ECHO_TO_SERIAL   1 // echo data to serial port
    #define WAIT_TO_START    0 // Wait for serial input in setup()
    uint32_t syncTime = 0; // time of last sync()
    unsigned long DataCurrent, DataPrevious, TimeOutPrevious=0;
    int DataLEDPin= 7;
    const int chipSelect = 10;

    RTC_DS1307 RTC; // define the Real Time Clock object
    File logfile;

    void error(char *str){
    Serial.print("error: ");
    Serial.println(str);
    while(1);
    }

  //Datalog Start Screen 
    void DataLogStart(){
    lcd.clear();
    lcd.setCursor(1,0);
    lcd.print("DATALOGGING ON");
    delay(300);
    lcd.clear();
    }

    //Datalog Stop Screen
    void DataLogStop(){
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("DATALOGGING OFF");
    lcd.clear();
    }

//No SD Screen
    void NoSD(){
    lcd.clear();
    lcd.setCursor(3,0);
    lcd.print("NO SD CARD");
    lcd.setCursor(0,1);
    lcd.print("DATALOGGING N/A");
    delay(500);
    lcd.clear();
    }

  //Datalog Available Screen
    void DataOK(){
    lcd.clear();
    lcd.setCursor(3,0);
    lcd.print("DATALOGGING");
    lcd.setCursor(4,1);
    lcd.print("AVAILABLE");
    delay(500);
    lcd.clear();
    }  

// DataLog File Create
    void FileCreate(){
    char filename[] = "LOGGER00.CSV";
    for (uint8_t i = 0; i < 100; i++) {
    filename[6] = i/10 + '0';
    filename[7] = i%10 + '0';
    if (! SD.exists(filename)) {
    // only open a new file if it doesn't exist
    logfile = SD.open(filename, FILE_WRITE); 
    break;  // leave the loop!
    }}
    if (! logfile) {
    error("couldnt create file");
    }
    Serial.print("Logging to: ");
    Serial.println(filename);
    delay(1000);
        //connect to RTC
    Wire.begin();  
    if (!RTC.begin()) {
    logfile.println("RTC failed");
    #if ECHO_TO_SERIAL
    Serial.println("RTC failed");
    #endif  //ECHO_TO_SERIAL
    }
    logfile.println("millis,stamp,PSI,DC");    
    #if ECHO_TO_SERIAL
    Serial.println("millis,stamp,PSI,DC");
    #endif //ECHO_TO_SERIAL;
    }

    void pulse(){
  if (PIND & 0x04)
  {
    TCNT1 = 0x0000;
    ovf = 0;
  }
  else
  {
    highCount += TCNT1;
    highCount += ovf*65536L;
  }
  count++;
    }


  // Push Button & Datalog_Start/Stop
    int ButtonIn=4, ButtonNew, ButtonOld=1, ButtonSta=0;
    unsigned long ButtonPrevious, ButtonCurrent;
    // Variables will change:

  //
    int buttonState = 1,lastButtonState = 1,startPressed = 0,endPressed = 0,holdTime = 0,idleTime = 0,DataPause=3000, DataState;

void setup()
  {
  lcd.init(); //LCD initiate 
  lcd.clear(); //Clear Screen         
  lcd.backlight(); // Make sure backlight is on

  Serial.begin(9600);
  Serial.println("* Frequency Counter 0.6 *");
  Serial.println(" ");
  Serial.println("Connect pulse TTL to Arduino pin 2");
  Serial.println("Connect pulse GND to Arduino GND");

  pinMode(IRQPIN, INPUT);
  attachInterrupt(0, pulse, CHANGE);
  pinMode(PWMOutPin,OUTPUT);

  pinMode(ButtonIn, INPUT_PULLUP); //Setup button (ground-Digital input using internal pull-up)

  TIMSK1 = (1 << TOIE1); // timer overflow interrupt enabled
  TCCR1A = 0x00; // 
  TCCR1B = 1; // prescaler == 1 => timer runs at clock speed: 16 MHz

    pinMode(10, OUTPUT);

  }

void loop()
{

  analogWrite(PWMOutPin,150); //Used to verify circuit with 5V into octo

  if(digitalRead(ButtonIn)==0){
    FileCreate();
    lcd.clear();
    Serial.println("DataLog ON");
    DataLogStart();
     DateTime now;
    unsigned long DataCurrent= millis();
    if (DataState==1 && DataCurrent - DataPrevious > 250){
    // fetch the time
    now = RTC.now();
    // log time
    logfile.print(now.unixtime()); // seconds since 2000
    logfile.print(", ");
    logfile.print(now.year(), DEC);
    logfile.print("/");
    logfile.print(now.month(), DEC);
    logfile.print("/");
    logfile.print(now.day(), DEC);
    logfile.print(" ");
    logfile.print(now.hour(), DEC);
    logfile.print(":");
    logfile.print(now.minute(), DEC);
    logfile.print(":");
    logfile.print(now.second(), DEC);
    #if ECHO_TO_SERIAL
    Serial.print(now.unixtime()); // seconds since 2000
    Serial.print(", ");
    Serial.print(now.year(), DEC);
    Serial.print("/");
    Serial.print(now.month(), DEC);
    Serial.print("/");
    Serial.print(now.day(), DEC);
    Serial.print(" ");
    Serial.print(now.hour(), DEC);
    Serial.print(":");
    Serial.print(now.minute(), DEC);
    Serial.print(":");
    Serial.print(now.second(), DEC);
    #endif //ECHO_TO_SERIAL    
    logfile.println(dutyCycle);
    #if ECHO_TO_SERIAL   
    Serial.println(dutyCycle);
    #endif //ECHO_TO_SERIAL
    DataPrevious=DataCurrent;
    }
    // Now we write data to disk! Don't sync too often - requires 2048 bytes of I/O to SD card
    // which uses a bunch of power and takes time
    if ((millis() - syncTime) < SYNC_INTERVAL) return;
    syncTime = millis();
    logfile.flush();
    }
    if(digitalRead(ButtonIn)==1){
    lcd.clear();
    Serial.println("DataLog Off");
    DataLogStop();
    }

  uint32_t now = micros();
  if (now - lastDisplay > DISPLAY_INTERVAL)
  { 
    lastDisplay = now;

    cli();
    {
      frequency = count;
      count = 0;
      totalCount = highCount;
      highCount = 0;
    }
    sei();

    frequency /= 2;
    dutyCycle = totalCount/160000.0;

    Serial.print(frequency);
    Serial.print(" Hz. - ");
    Serial.print(dutyCycle, 1);
    Serial.println(" %");
  }
}


ISR(TIMER1_OVF_vect) 
{
  ovf++;
}



I've commented out line 175 and it seems to work ...

Just as a side note to the original problem:

If you do 1000000 / pulseTotal or
1000000UL/pulseTotal
you do floating point caculations, which result in nan if pulseTotal is zero.

1 Like

Awesome. Unfortunately i need that code- similar as it is now, as i only want to create a file once datalogging is issued. But that gives me where to start. Appreciate it!!

-Chris

Well, commenting out the FileCreate(); function gets it to work in Wokwi, so perhaps try this on your setup. If this get's your display to work, then the issue is in this function or the hardware or connections relating to the SD ... good luck!

Strange enough... this one works... Not sure what i did between them though....

//    FILE: freqCounter06.ino
//  AUTHOR: Rob Tillaart
//    DATE: 2013-04-13
// PURPOSE: freq counter

#include <LiquidCrystal_I2C.h>
#include <SPI.h>
#include <SD.h>
#include <Wire.h>
#include "RTClib.h"

#define DISPLAY_INTERVAL   1000000L
#define IRQPIN             3

//LCD Address
LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x3F for a 16 chars and 2 line display

volatile unsigned int count = 0;
volatile unsigned int ovf = 0;

const int PWMOutPin=6; //Used to verify circuit with 5V into octo


unsigned long frequency = 0;
unsigned long highCount = 0; 
unsigned long totalCount = 0;
float dutyCycle = 0;
unsigned long lastDisplay = 0;

  // Data Logging setup
    #define LOG_INTERVAL  200 // mills between entries (reduce to take more/faster data)
    #define SYNC_INTERVAL 1000 // mills between calls to flush() - to write data to the card
    #define ECHO_TO_SERIAL   1 // echo data to serial port
    #define WAIT_TO_START    0 // Wait for serial input in setup()
    uint32_t syncTime = 0; // time of last sync()
    unsigned long DataCurrent, DataPrevious, TimeOutPrevious=0;
    int DataLEDPin= 7;
    const int chipSelect = 10;

    RTC_DS1307 RTC; // define the Real Time Clock object
    File logfile;

    void error(char *str){
    Serial.print("error: ");
    Serial.println(str);
    while(1);
    }

  //Datalog Start Screen 
    void DataLogStart(){
    lcd.clear();
    lcd.setCursor(1,0);
    lcd.print("DATALOGGING ON");
    delay(300);
    lcd.clear();
    }

    //Datalog Stop Screen
    void DataLogStop(){
    lcd.clear();
    lcd.setCursor(0,0);
    lcd.print("DATALOGGING OFF");
    lcd.clear();
    }

//No SD Screen
    void NoSD(){
    lcd.clear();
    lcd.setCursor(3,0);
    lcd.print("NO SD CARD");
    lcd.setCursor(0,1);
    lcd.print("DATALOGGING N/A");
    delay(500);
    lcd.clear();
    }

  //Datalog Available Screen
    void DataOK(){
    lcd.clear();
    lcd.setCursor(3,0);
    lcd.print("DATALOGGING");
    lcd.setCursor(4,1);
    lcd.print("AVAILABLE");
    delay(500);
    lcd.clear();
    }  

// DataLog File Create
    void FileCreate(){
    char filename[] = "LOGGER00.CSV";
    for (uint8_t i = 0; i < 100; i++) {
    filename[6] = i/10 + '0';
    filename[7] = i%10 + '0';
    if (! SD.exists(filename)) {
    // only open a new file if it doesn't exist
    logfile = SD.open(filename, FILE_WRITE); 
    break;  // leave the loop!
    }}
    if (! logfile) {
    error("couldnt create file");
    }
    Serial.print("Logging to: ");
    Serial.println(filename);
    delay(1000);
        //connect to RTC
    Wire.begin();  
    if (!RTC.begin()) {
    logfile.println("RTC failed");
    #if ECHO_TO_SERIAL
    Serial.println("RTC failed");
    #endif  //ECHO_TO_SERIAL
    }
    logfile.println("millis,stamp,PSI,DC");    
    #if ECHO_TO_SERIAL
    Serial.println("millis,stamp,PSI,DC");
    #endif //ECHO_TO_SERIAL;
    }

    void pulse(){
  if (PIND & 0x04)
  {
    TCNT1 = 0x0000;
    ovf = 0;
  }
  else
  {
    highCount += TCNT1;
    highCount += ovf*65536L;
  }
  count++;
    }


  // Push Button & Datalog_Start/Stop
    int ButtonIn=4, ButtonNew, ButtonOld=1, ButtonSta=0;
    unsigned long ButtonPrevious, ButtonCurrent;
    // Variables will change:

  //
    int buttonState = 1,lastButtonState = 1,startPressed = 0,endPressed = 0,holdTime = 0,idleTime = 0,DataPause=3000, DataState;

void setup()
  {
  lcd.init(); //LCD initiate 
  lcd.clear(); //Clear Screen         
  lcd.backlight(); // Make sure backlight is on

  Serial.begin(9600);
  Serial.println("* Frequency Counter 0.6 *");
  Serial.println(" ");
  Serial.println("Connect pulse TTL to Arduino pin 2");
  Serial.println("Connect pulse GND to Arduino GND");

  pinMode(IRQPIN, INPUT);
  attachInterrupt(0, pulse, CHANGE);
  pinMode(PWMOutPin,OUTPUT);

  pinMode(ButtonIn, INPUT_PULLUP); //Setup button (ground-Digital input using internal pull-up)

  TIMSK1 = (1 << TOIE1); // timer overflow interrupt enabled
  TCCR1A = 0x00; // 
  TCCR1B = 1; // prescaler == 1 => timer runs at clock speed: 16 MHz

    pinMode(10, OUTPUT);
        if (!SD.begin(chipSelect)) {
    Serial.println("Card failed, or not present");
    NoSD();
    }
    if (SD.begin(chipSelect)){
    DataOK();
    }

  }

void loop()
{

  analogWrite(PWMOutPin,150); //Used to verify circuit with 5V into octo

  if(digitalRead(ButtonIn)==0){
    FileCreate();
    lcd.clear();
    Serial.println("DataLog ON");
    DataLogStart();
     DateTime now;
    unsigned long DataCurrent= millis();
    if (DataState==1 && DataCurrent - DataPrevious > 250){
    // fetch the time
    now = RTC.now();
    // log time
    logfile.print(now.unixtime()); // seconds since 2000
    logfile.print(", ");
    logfile.print(now.year(), DEC);
    logfile.print("/");
    logfile.print(now.month(), DEC);
    logfile.print("/");
    logfile.print(now.day(), DEC);
    logfile.print(" ");
    logfile.print(now.hour(), DEC);
    logfile.print(":");
    logfile.print(now.minute(), DEC);
    logfile.print(":");
    logfile.print(now.second(), DEC);
    #if ECHO_TO_SERIAL
    Serial.print(now.unixtime()); // seconds since 2000
    Serial.print(", ");
    Serial.print(now.year(), DEC);
    Serial.print("/");
    Serial.print(now.month(), DEC);
    Serial.print("/");
    Serial.print(now.day(), DEC);
    Serial.print(" ");
    Serial.print(now.hour(), DEC);
    Serial.print(":");
    Serial.print(now.minute(), DEC);
    Serial.print(":");
    Serial.print(now.second(), DEC);
    #endif //ECHO_TO_SERIAL    
    logfile.println(dutyCycle);
    #if ECHO_TO_SERIAL   
    Serial.println(dutyCycle);
    #endif //ECHO_TO_SERIAL
    DataPrevious=DataCurrent;
    }

    // Now we write data to disk! Don't sync too often - requires 2048 bytes of I/O to SD card
    // which uses a bunch of power and takes time
    if ((millis() - syncTime) < SYNC_INTERVAL) return;
    syncTime = millis();
    logfile.flush();
    }
    if(digitalRead(ButtonIn)==1){
    lcd.clear();
    Serial.println("DataLog Off");
    DataLogStop();
    }

  uint32_t now = micros();
  if (now - lastDisplay > DISPLAY_INTERVAL)
  { 
    lastDisplay = now;

    cli();
    {
      frequency = count;
      count = 0;
      totalCount = highCount;
      highCount = 0;
    }
    sei();

    frequency /= 2;
    dutyCycle = totalCount/160000.0;

    Serial.print(frequency);
    Serial.print(" Hz. - ");
    Serial.print(dutyCycle, 1);
    Serial.println(" %");
  }
}


ISR(TIMER1_OVF_vect) 
{
  ovf++;
}


Just an update, i do seem to have a working sketch.
I believe it was a order or operation and a mistaken "}" in the wrong place.

Interesting note:
-Using the circuit above (12V/5V), i use a 330 in leu of the 10K pull down resistor.
-Using the Arduino (3.3V/5V) circuit i used a 10K pull down resistor.

I appreciate those who help. I will probably be back shortly. LOL

-Chris

I am not sure why you think this is interesting?
Pull up and pull down resistors can be virtually any value. Like all things in electronics the value you use is a compromise. In this case between current draw and the level of immunity to interference.

The higher the resistance the less current is drawn but the more susceptible that input becomes to interference. So while in a noisy environment you would want to use smaller resistors and in a quite electromagnetic environment you can afford to use a higher resistor value.

The internal pull up resistors on Arduino Uno and other AVR processors are 30 to 50K and these are considered weak, but good enough for a quite environment. A value of 1K or below is considered strong.

Below 330R then the current becomes an important factor if this current passes through a push button's contacts.

Most engineers have a favorite value based on experience and can provoke hours of debate without reaching any consensus.

1 Like

Does anyone have a link to a "simple" working code that reads and calculates frequency and duty cycle using interrupts, using a Nano/Uno.

I have been doing a bunch of research on trying to figure it out on my own, but there is just too much info out there. I find it easier for me to back track an exisiting code, then trying to write it from scratch when i am venturing into un-known territory .

Can someone explain what this is in this code.

ISR(TIMER1_OVF_vect) 
{
  ovf++;
}
//
//    FILE: freqCounter06.ino
//  AUTHOR: Rob Tillaart
//    DATE: 2013-04-13
//
// PURPOSE: freq counter
//
// tested working range
//
// FREQ   MIN DC   MAX DC
// -----------------------
// 5       1%      98%
// 10      1%      98%
// 50      1%      98%
// 100     1%      98%
// 250     1%      98%
// 500     1%      98%   
// 1000    1%      98%
// 2500    3%      96%
//  5K     6%      94%
// 10K    12%      88%
// 15K    17%      82%
// 20K    23%      77%
// 25K    29%      70%
// 30K    35%      65%
//

#define DISPLAY_INTERVAL   1000000L
#define IRQPIN             2

volatile unsigned int count = 0;
volatile unsigned int ovf = 0;

unsigned long frequency = 0;
unsigned long highCount = 0; 
unsigned long totalCount = 0;
float dutyCycle = 0;
unsigned long lastDisplay = 0;

void setup()
{
  Serial.begin(115200);
  Serial.println("* Frequency Counter 0.6 *");
  Serial.println(" ");
  Serial.println("Connect pulse TTL to Arduino pin 2");
  Serial.println("Connect pulse GND to Arduino GND");

  pinMode(IRQPIN, INPUT);
  attachInterrupt(0, pulse, CHANGE);

  TIMSK1 = (1 << TOIE1); // timer overflow interrupt enabled
  TCCR1A = 0x00; // 
  TCCR1B = 1; // prescaler == 1 => timer runs at clock speed: 16 MHz
}

void loop()
{
  uint32_t now = micros();
  if (now - lastDisplay > DISPLAY_INTERVAL)
  { 
    lastDisplay = now;

    cli();
    {
      frequency = count;
      count = 0;
      totalCount = highCount;
      highCount = 0;
    }
    sei();

    frequency /= 2;
    dutyCycle = totalCount/160000.0;

    Serial.print(frequency);
    Serial.print(" Hz. - ");
    Serial.print(dutyCycle, 1);
    Serial.println(" %");
  }
}


ISR(TIMER1_OVF_vect) 
{
  ovf++;
}

void pulse()
{
  if (PIND & 0x04)
  {
    TCNT1 = 0x0000;
    ovf = 0;
  }
  else
  {
    highCount += TCNT1;
    highCount += ovf*65536L;
  }
  count++;
}

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.