Calculate Duty Cycle

I've had some serious issues trying to get a semi accurate % Duty Cycle Reading. When I was Testing the code, it was reading Duty Cycle from a square function generator but only on a very low frequencies (10-20Hz). Despite the fact %DC was far away from being accurate, was changing as function generator frequency was being increased and in certain cases it was going up to couple thousand... Hardware seems to work fine, I'm sure the problem is in my sloppy coding. I would like to make this code work for frequencies of at least 500-1000Hz Any help from more experienced coders will be greatly appreciated!

//~~~LED DRIVER~~~//
int ledPins [] = { 3, 5, 6, 9, 10 }; // PWM pints driving NPN Transistors

//~~~LED TIMERS~~~//
bool DriveIndividual= false; // true drives one LED at the time on intro. False keeps the whole row on
int timer1 = 130;  // LED time on
int timer1d = 40; // deley between different LED rows [only used when DriveIndividual==true]
int timer2 = 120; // blinks on shift light
int bright = 150; // LED brightness Value between 0 and 255

//~~~SIGNAL SETUP~~~//
int Signal_1 = 20; // Duty Cycle % required to turn led 1 on
int Signal_2 = 35; // PWM required to turn led 2 on
int Signal_3 = 50; // PWM required to turn led 3 on
int Signal_4 = 65; // PWM required to turn led 4 on
int Signal_5 = 75; // PWM required to turn led 5 on
int Signal_6 = 90; // PWM required to blink led 5 on
int Sig_buff = 6; //+/- from PWM

//~~~PWM SETUP~~~//
volatile unsigned long fall_Time = 0;                   // Placeholder for microsecond time when last falling edge occured.
volatile unsigned long rise_Time = 0;                   // Placeholder for microsecond time when last rising edge occured.
volatile byte dutyCycle = 0;                            // Duty Cycle %
volatile unsigned long lastRead = 0;                    // Last interrupt time (needed to determine interrupt lockup due to 0% and 100% duty cycle)

//~~~INTERRUPT~~~//
void PinChangeISR0() {                                  // Pin 2 (Interrupt 0) service routine
  lastRead = micros();                                  // Get current time
  if (digitalRead(2) == LOW) {
    // Falling edge
    fall_Time = lastRead;                               // Just store falling edge and calculate on rising edge
  }
  else{
    // Rising edge
    unsigned long total_Time = rise_Time - lastRead;    // Get total cycle time
    unsigned long on_Time = fall_Time - rise_Time;      // Get on time during this cycle
    total_Time = total_Time / on_Time;                  // Divide it down
    dutyCycle = (100 * on_Time) / total_Time;                       // Convert to a percentage
    rise_Time = lastRead;                               // Store rise time
  }
}

void Intro(){
  //~~~BLINK UP~~~//
  for(int i=0; i<4; i++){
    if (DriveIndividual == true){
      analogWrite(ledPins [i], bright);
      delay(timer1);
      analogWrite(ledPins [i], 0);
      delay(timer1d);
      }
    if (DriveIndividual == false){
      analogWrite(ledPins [i], bright);
      delay(timer1);
      }
    }
  //~~~TOP ROW BLINK~~~//
  for(int i=0; i<4; i++){
    analogWrite(ledPins [4], bright);
    delay(timer2);
    analogWrite(ledPins [4], 0);
    delay(timer2);
    }
  //~~~BLINK DOWN~~~//
  for(int i=4; i>=0; i--){
    analogWrite(ledPins [i], bright);
    delay(timer1);
    analogWrite(ledPins [i], 0);
    delay(timer1d);
    }
}

void RPM(){
  static unsigned long oldLastRead = lastRead;

  if (oldLastRead != lastRead) {
  Serial.print(" Duty Cycle =  ");
  Serial.print( dutyCycle );
  //Serial.print("\n");


    oldLastRead = lastRead;

    //DRIVE LEDS
      for(int i = 0; i<5; i++){
      analogWrite (ledPins [i], 0);
      }

        if(dutyCycle <= Signal_1){
            analogWrite(ledPins [0], bright);
            Serial.println("   Led 1 ON       ");
        }
         else if(dutyCycle <= Signal_2){
            analogWrite(ledPins [1], bright);
            Serial.println("   Led 2 ON       ");
        }
         else if (dutyCycle <= Signal_3){
            analogWrite(ledPins [2], bright);
            Serial.println("   Led 3 ON       ");
        }
         else if (dutyCycle <= Signal_4){
            analogWrite(ledPins [3], bright);
            Serial.println("   Led 4 ON       ");
        }
         else if (dutyCycle <= Signal_5){
            analogWrite(ledPins [4], bright);
            Serial.println("   Led 5 ON       ");
        }

         /*else if (dutyCycle <= Signal_6 ){
            do {
              unsigned long prevTime = 0;
              unsigned long Time = millis();

              int state = 0; //start from LOW State

                if((Time - prevTime) >= 200){
                prevTime = Time;
                  if(state == 0){
                    state = bright;
                    Serial.println("   BLINKING LED 5     ");
                  }
                  if(state == bright){
                    state = 0;
                  }
                }
              analogWrite(ledPins [4], bright);
            } while(dutyCycle <= Signal_6 && dutyCycle >Signal_5);
      }*/

  else { // No interrupt since last read so must be 0% or 100%
    if (digitalRead(2) == LOW) {
      Serial.print("0");
    }
    else {
      Serial.print("100");
    }
  }

 // delay(20); // Freeze microcontroller?
}
}

void setup(){

  for(int i=0; i<5; i++){
    pinMode(ledPins [i], OUTPUT);
    }

  Serial.begin(115200);

  //~~~INTERRUPT~~~//
  pinMode(2, INPUT);
  Serial.println(F("ISR Pin 2 Configured For Input."));
  attachInterrupt(0, PinChangeISR0, CHANGE);
  Serial.println(F("Pin 2 ISR Function Attached."));

  Intro(); // Drive all LEDs
}

void loop(){
  RPM();
}

How does this topic differ from Read Duty Cycle and Drive Leds

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