Read Duty Cycle and Drive Leds

Hi all,

Recently I designed a PCB based on ATmega328P which supposed to read Duty Cycle coming in on input 2 through galvanic isolation and drive one of 5 segments of LEDs based on it's value. Circuit is to be used as a shift light on a drag racing bike. Electronically the circuit works, I'm able to see high/ low state of the input and drive any of the LEDs manually. Unfortunately I'm lacking basic coding skills to make it work the way I want it. So far the code can read either 0% or 100% duty cycle, therefore nothing is happening. I would greatly appreciate any feedback or constructive criticism form more experienced coders!

//~~~LED DRIVER
int led1 = 3;
int led2 = 5;
int led3 = 6;
int led4 = 9;
int led5 = 10;
int timer1 = 230;  // light on time leds
int timer1d = 15; // deley between different lights
int timer2 = 70;     // blinks on shift light
int bright = 150; // LED brightness Value between 0 and 255

//~~~SIGNAL SETUP
int Signal_1 = 40; // PWM required to turn led 1 on
int Signal_2 = 50; // PWM required to turn led 2 on
int Signal_3 = 60; // PWM required to turn led 3 on
int Signal_4 = 70; // PWM required to turn led 4 on
int Signal_5 = 80; // PWM required to turn led 5 on
int Signal_buff = 1; // threshold for PWM comming in

//~~~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)

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 / total_Time;                       // Convert to a percentage
    rise_Time = lastRead;                               // Store rise time
  }
}

void Intro()
{
  analogWrite(led1, bright);
  delay(timer1);
  analogWrite(led1, 0);
  delay(timer1d);
  //******
  analogWrite(led2, bright);
  delay(timer1);
  analogWrite(led2, 0);
  delay(timer1d);
  //******
  analogWrite(led3, bright);
  delay(timer1);
  analogWrite(led3, 0);
  delay(timer1d);
  //******
  analogWrite(led4, bright);
  delay(timer1);
  analogWrite(led4, 0);
  delay(timer1d);
  //******
  analogWrite(led5, bright);
  delay(timer2);
  analogWrite(led5, 0);
  delay(timer2);
  analogWrite(led5, bright);
  delay(timer2);
  analogWrite(led5, 0);
  delay(timer2);
  analogWrite(led5, bright);
  delay(timer2);
  analogWrite(led5, 0);
  delay(timer2);
  analogWrite(led5, bright);
  delay(timer2);
  analogWrite(led5, 0);
  delay(timer2);
  analogWrite(led5, bright);
  delay(timer2);
  analogWrite(led5, 0);
  delay(timer2);
  //******
  analogWrite(led4, bright);
  delay(timer1);
  analogWrite(led4, 0);
  delay(timer1d);
  //******
  analogWrite(led3, bright);
  delay(timer1);
  analogWrite(led3, 0);
  delay(timer1d);
  //******
  analogWrite(led2, bright);
  delay(timer1);
  analogWrite(led2, 0);
  delay(timer1d);
  //******
  analogWrite(led1, bright);
  delay(timer1);
  analogWrite(led1, 0);
  delay(timer1d);
  //******

}


void RPM()
{
  static unsigned long oldLastRead = lastRead;
  Serial.print("Duty Cycle = ");
  if (oldLastRead != lastRead) {
    Serial.print(dutyCycle);
    oldLastRead = lastRead;

    //~~~~~
    if ((dutyCycle <= Signal_1 + Signal_buff) && (dutyCycle >= Signal_1 - Signal_buff)) {
      analogWrite(led1, bright);
      Serial.print("Led 1 ON     ");
    }
    else {
      analogWrite(led1, 0 );
    }

    //~~~~~
    if ((dutyCycle <= Signal_2 + Signal_buff) && (dutyCycle >= Signal_2 - Signal_buff)) {
      analogWrite(led2, bright);
      Serial.print("Led 2 ON     ");
    }
    else {
      analogWrite(led2, 0 );
    }

    //~~~~~
    if ((dutyCycle <= Signal_3 + Signal_buff) && (dutyCycle >= Signal_3 - Signal_buff)) {
      analogWrite(led3, bright);
      Serial.print("Led 3 ON     ");
    }
    else {
      analogWrite(led3, 0 );
    }
    //~~~~~
    if ((dutyCycle <= Signal_4 + Signal_buff) && (dutyCycle >= Signal_4 - Signal_buff)) {
      analogWrite(led4, bright);
      Serial.print("Led 4 ON     ");
    }
    else {
      analogWrite(led4, 0 );
    }
    //~~~~~
    if ((dutyCycle <= Signal_5 + Signal_buff) && (dutyCycle >= Signal_5 - Signal_buff)) {
      analogWrite(led5, bright);
      Serial.print("Led 5 ON     ");
    }
    else {
      analogWrite(led5, 0 );
    }
  }
  else { // No interrupt since last read so must be 0% or 100%
    if (digitalRead(2) == LOW) {
      Serial.print("0");
    }
    else {
      Serial.print("100");
    }
  }
  Serial.println("%");
  delay(100);
}

void setup() {
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);
  pinMode(led4, OUTPUT);
  pinMode(led5, OUTPUT);

  Serial.begin(115200);
  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();

}


void loop() {
  RPM();

}

Your post was MOVED to its current location as it is more suitable.

Could you also take a few moments to Learn How To Use The Forum.

Other general help and troubleshooting advice can be found here.
It will help you get the best out of the forum in the future.

Please follow the advice given in the link below when posting code , use code tags and post the code here to make it easier to read and copy for examination

i suggest making the ISR simpler, just capture timestamps and defer performing any calculations in loop().

the ISR can capture the previous rising, falling and rising times. the ISR can increment a "count" one each rising event.

loop() can check "count" and recognize that a cycle is complete when "count" changes

i believe your calculations are incorrect. lastRead will always be the (unsigned greater value)

should be

total_Time = lastRead - rise_Time;

bear in mind that total_Time is an integer and that totalTime > on_Time. the computation is < 1.

i believe

dutyCycle = 100 * on_Time / total_Time;

is correct

if

byte ledPins [] = { 3, 5, 6, 9, 10 };

when checking for a value within ranges, the following approach works

        for (unsigned n = 0; n < sizeof(ledPins); n++)  {
            analogWrite (ledPins [n], 0);
        }


        if (dutyCycle <= Signal_1)  {
            analogWrite(led1, bright);
            Serial.print("Led 1 ON     ");
        }
        else if (dutyCycle <= Signal_2)  {
            analogWrite(led2, bright);
            Serial.print("Led 2 ON     ");
        }
        else if (dutyCycle <= Signal_3)  {
            analogWrite(led3, bright);
            Serial.print("Led 3 ON     ");
        }
        else if (dutyCycle <= Signal_4)  {
            analogWrite(led4, bright);
            Serial.print("Led 4 ON     ");
        }
        else if (dutyCycle <= Signal_5)  {
            analogWrite(led5, bright);
            Serial.print("Led 5 ON     ");
        }

Did you want Duty Cycle in percentage? You have the calculation inverted. You want "on_Time / total_Time", not "total_Time / on_Time". But since on_Time is less than total_Time and you are doing the math in integers you would almost always get 0. Multiply on_Time by 100 first and then divide by total_Time. That would be:

    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
    dutyCycle = (100 * on_Time) / total_Time;                       // Convert to a percentage
1 Like

Thank you so much for your input, of course you are right. I will test the code after work and see how it works!