Making an LED Strobe... Facing problems with the frequency

Hello there :slight_smile:

I am currently trying to develop an LED strobe using a high power led.

Here are my components:

  • Arduino Mega 2650 (yes, a bit oversized‚Ķ)
  • Encoder with button for adjusting the frequency and pulse width
  • 1 W LED controlled by transistor
  • 16x2 LCD display for displaying the frequency / pulse width

So far, so good :slight_smile: Here’s my code:

#include <Wire.h>                 
#include <LCD.h>                  
#include <LiquidCrystal_I2C.h> 
   
#include <ClickButton.h>
#include <Encoder_Polling.h>
#include <PWM.h>

// Definitions for 16x2 LCD
#define I2C_ADDR          0x27  
#define BACKLIGHT_PIN        3
#define En_pin               2
#define Rw_pin               1
#define Rs_pin               0
#define D4_pin               4
#define D5_pin               5
#define D6_pin               6
#define D7_pin               7

// More Definitions...
#define ledPin          11    // External Led Pin
#define ledPin2         13    // Internal LED 
#define buttonPin        2    // Pin Pushbutton
#define encoderPinA      3    // Encoder Pin A -> Pin A = White
#define encoderPinB      4    // Encoder Pin B -> Pin B = Brown      

unsigned long previousMillis = 0;   // Used for display
const long interval = 500;          // Refresh rate of display (500 ms)


//Pulse width in 1% steps. 100% = 255
int pulses[101] = {0, 3, 5, 8, 10, 13, 15, 18, 20, 23, 26, 28, 31, 33, 36, 38, 41, 43, 46, 48, 51,
                   54, 56, 59, 61, 64, 66, 69, 71, 74, 77, 79, 82, 84, 87, 89, 92, 94, 97, 99, 102,
                   105, 107, 110, 112, 115, 117, 120, 122, 125, 128, 130, 133, 135, 138, 140, 143, 
                   145, 148, 150, 153, 156, 158, 161, 163, 166, 168, 171, 173, 176, 179, 181, 184, 
                   186, 189, 191, 194, 196, 199, 201, 204, 207, 209, 212, 214, 217, 219, 222, 224,
                   227, 230, 232, 235, 237, 240, 242, 245, 247, 250, 252, 255};   

int frequency = 0;            // [Hz]
int oldfrequency = 0;         
int pulseWidth = 50;          // Defines pulse width. Initial value = 50%.
int oldpulseWidth = 50;       
int clicked = LOW;            

int ledState2 = LOW;          // Internal LED

// Init 16x2 LCD
LiquidCrystal_I2C  lcd(I2C_ADDR,En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin);

// Init Pushbutton; LOW = State, when button is pushed; Use internal pull up
ClickButton button1(buttonPin, LOW, CLICKBTN_PULLUP);     

void setup() {
  lcd.begin (16,2);                           // Define display size (16 x 2)
  
  lcd.setBacklightPin(BACKLIGHT_PIN,POSITIVE);  // Init Backlight of display
  lcd.setBacklight(HIGH);                     // Switch on display backlight
  lcd.home (); 

  // Initial message on display:
  lcd.print("Frequenz: ");
  lcd.print(frequency, DEC);
  lcd.print(" Hz");
  lcd.setCursor (0,1);
  lcd.print("Pulsbreite: ");
  lcd.print(pulseWidth, DEC);
  lcd.print("%");
  
  InitTimersSafe();                           // Used for PWM library
  encoder_begin(encoderPinA, encoderPinB);    // Init encoder
  digitalWrite(encoderPinA, HIGH);            // Use internal pull up for encoder
  digitalWrite(encoderPinB, HIGH);      
 
  button1.debounceTime = 20;                  // Button debounce time in [ms]
  pinMode(ledPin, OUTPUT);                   
  pinMode(ledPin2, OUTPUT);
}

// Print new values on display
void display_write(int frequency, int pulseWidth){
  // Only print values, if values changed...
  if (oldfrequency != frequency || oldpulseWidth != pulseWidth){
    oldfrequency = frequency;
    oldpulseWidth = pulseWidth;
    lcd.clear();                  

    // Print new values:
    lcd.print("Frequenz: ");
    lcd.print(frequency, DEC);
    lcd.print(" Hz");
    lcd.setCursor (0,1);
    lcd.print("Pulsbreite: ");
    lcd.print(pulseWidth, DEC);
    lcd.print("%");
  }
  
}
  
void loop() {
  unsigned long currentMillis = millis(); // Used for timing (display)
  int dir = encoder_data();               // Check encoder. Gives back 1 or -1.
  button1.Update();                       // Update button state.

  // Button is used, to differ between changing frequency or changing pulse width
  if (button1.clicks == 1) {              
    clicked = !clicked;
    ledState2 = !ledState2;
    digitalWrite(ledPin2, ledState2);     // Internal Led lights up, when pulse width is changed.
  }

  if (!clicked){                          // Frequency
    if (dir == 1 && frequency < 200) {    // Increment [maximum 200 Hz]
      frequency++;
      SetPinFrequencySafe(ledPin, frequency); // Set new frequency
      pwmWrite(ledPin, pulses[pulseWidth]);   // Required to activate new frequency on LED pin    
    }  
    if (dir == -1 && frequency > 0) {     // Decrement [minimum 0 Hz]
      frequency--;
      SetPinFrequencySafe(ledPin, frequency);
      pwmWrite(ledPin, pulses[pulseWidth]); 
    }
  }

  if (clicked) {                          // Pulse width
    if (dir == 1 && pulseWidth < 100) {   // increment [max. 100%]
      pulseWidth+= 1;
      pwmWrite(ledPin, pulses[pulseWidth]); // Set new pulse width on led pin
    }  
    if (dir == -1 && pulseWidth > 0) {    // decrement [min. 0%]
      pulseWidth-= 1;
      pwmWrite(ledPin, pulses[pulseWidth]);
    }     
  }

  // Update display only every 500 ms
  if (currentMillis - previousMillis >= interval) {           
    previousMillis = currentMillis;
    display_write(frequency, pulseWidth);
  }
}

I am using runnerups PWM library to control the frequency and pulse width:
click
Works perfectly so far, but… I am facing the following problem:

I’ve tested my led strobe with a fan and my washing machine. With both test appliances I am not able to get them to the point, where they should stand still… 1. test: fan:

click

I guess the fan is just not moving with a constant revolution speed. Second test: washing machine:

click

The washing machine has a constant revolution speed, BUT I cannot set the right frequency, as I can only set integer values for the frequency.

So here’s my question: Is there a way to change the frequency (using PWM) in smaller steps, like:
1 Hz ‚Üí 1,1 Hz ‚Üí 1,2 Hz and so on?

That would really help me out :smiley:

Thanks a lot.

Kind regards,

Niko

Basically no. The PWM can only be changed in large lumps and still have the full PWM range. Using PWM is the wrong way to control the speed of an LED. On a strobe why do you need a pulse width anyway.

The real way to control an LED like this is to use a timer set to fire an interrupt at a regular basis the in the interrupt service routine you increment an int and use the most significant bit of the int to fire the LED. The value you increment the int by sets the frequency of the LED.