The topic of the assignment is the realization of New Year's LED lighting that will have certain light effects (in this case LED flicker) while the user is enabled to control the brightness intensity in the range from 0 to 100% with two push buttons. Here you will find detailed instructions and explanations of the program. I started with the 6th task from the collection, and there will be more similar texts soon. The practice so far has been to make a video clip and explain the task through text on the blog, and now a document will be available for download.

It should be noted that the task requires that the flicker effect runs smoothly, regardless of whether one of the keys is pressed or not. We achieve this by using interrupts. In short, interrupts are a mechanism for listening to expected events. The moment an event occurs (an interrupt occurs), the execution of the main program is interrupted and the interrupt routine or interrupt function is executed for a moment. After the interrupt function is executed, the execution of the main program continues from the line of code where the interrupt occurred. The intensity of the diode lighting changes in the interrupt functions, while in the main program the effect of diode flicker is realized.

Electrical scheme and wiring diagram


Necessary components for the realization of the assembly

  • Arduino UNO
  • Breadboard
  • LED - 3 pcs.
  • Resistor220Ω – 3 pcs.
  • Push button - 2 pcs.
  • Resistor 1kΩ – 2 pcs.

About Interrupts

In order to enable the diodes to flicker uninterruptedly, it is necessary to use the mechanism of "listening" to the expected events. The event in question is pressing the "Umanji" or "Uvećaj" buttons. The mechanism that makes this possible is called an interrupt.

The essence of the interrupts is that during the "listening" of the event, the program is continuously executed. When one of the keys is pressed during code execution, the code execution is interrupted in the loop section and a subroutine / function related to a particular interrupt is executed. After that, the execution of the code in the loop continues from the place (line) of the code where the execution was interrupted. Of course, as the code executes quickly, the user will not notice that there was any interrupt, but it will look like everything is happening at the same time - executing code from the loop section and the part from the function called with the interrupt. Functions that are called when an interrupt occurs are called ISRs, Interrupt Service Routines. In the following text, this abbreviation will be used when talking about these functions.

Video tutorial


The program - sketch

// pinovi na koje su povezane diode, obavezno moraju da podrzavaju PWM
const int led1 = 9;
const int led2 = 10;
const int led3 = 11;

// pinovi na koje su povezani tasteri, moraju da budu 2 i 3 zbog koriscenja 
// prekida  (interrupt-a)
const int tasterUvecaj = 3;
const int tasterUmanji = 2;

// pocetni intenzitet osvetljaja dioda
// volatile - jer se vrednost menja u funkcijama prekida
volatile int osvetljenjeProc = 0;
int osvetljenjePWM;

void setup() {
  // Pinovi na koje su povezane diode se definisu da rade kao izlazi
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);

  // Pinovi na koje su povezani tasteri se definisu da rade kao ulazi
  // i to realizovani preko pullup otpornika
  pinMode(tasterUvecaj, INPUT);
  pinMode(tasterUmanji, INPUT);

  // pocetno stanje dioda - iskljucene (ne svetle);
  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW);
  digitalWrite(led3, LOW);

  // Osluskivanje stanja tastera - pritisak bilo kog tastera poziva odgovarajucu 
  // funckiju [povecajNivoOsvetljenosti ili smanjiNivoOsvetljenosti]
  attachInterrupt(digitalPinToInterrupt(tasterUvecaj), povecajNivoOsvetljenosti, RISING);
  attachInterrupt(digitalPinToInterrupt(tasterUmanji), smanjiNivoOsvetljenosti, RISING);

}

void loop()
{
  osvetljenjePWM = map(osvetljenjeProc, 0, 100, 0, 255);
  diodeTrepere();
}

void povecajNivoOsvetljenosti() {
  if (osvetljenjeProc < 100) osvetljenjeProc += 10;
}

void smanjiNivoOsvetljenosti() {
  if (osvetljenjeProc > 0) osvetljenjeProc -= 10;
}

void diodeTrepere() {
  analogWrite(led1, osvetljenjePWM);
  analogWrite(led2, osvetljenjePWM);
  analogWrite(led3, osvetljenjePWM);
  delay(200);
  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW);
  digitalWrite(led3, LOW);
  delay(200);
}
// pinovi na koje su povezane diode, obavezno moraju da podrzavaju PWM
const int led1 = 9;
const int led2 = 10;
const int led3 = 11;

// pinovi na koje su povezani tasteri, moraju da budu 2 i 3 zbog koriscenja prekida  (interrupt-a)
const int tasterUvecaj = 3;
const int tasterUmanji = 2;

// pocetno stanje osvetljaja dioda
// volatile - jer se vrednost menja u funkcijama prekida
volatile int ukljuci = LOW;

void setup() {
  // Pinovi na koje su povezane diode se definisu da rade kao izlazi
  pinMode(led1, OUTPUT);
  pinMode(led2, OUTPUT);
  pinMode(led3, OUTPUT);

  // Pinovi na koje su povezani tasteri se definisu da rade kao ulazi
  // i to realizovani preko pullup otpornika
  pinMode(tasterUvecaj, INPUT);
  pinMode(tasterUmanji, INPUT);

  // pocetno stanje dioda - iskljucene (ne svetle);
  digitalWrite(led1, LOW);
  digitalWrite(led2, LOW);
  digitalWrite(led3, LOW);

  // Osluskivanje stanja tastera - pritisak bilo kog tastera poziva odgovarajucu funckiju
  attachInterrupt(digitalPinToInterrupt(tasterUvecaj), ukljuciDiode, RISING);
  attachInterrupt(digitalPinToInterrupt(tasterUmanji), iskljuciDiode, RISING);
}

void loop()
{
  digitalWrite(led1, ukljuci);
  digitalWrite(led2, ukljuci);
  digitalWrite(led3, ukljuci);
}

void ukljuciDiode() {
  ukljuci = HIGH;
}

void iskljuciDiode() {
  ukljuci = LOW;
}

Sketch (program) explained

Definition section

const int led1 = 9;
const int led2 = 10;
const int led3 = 11;

The diodes are connected to pins 9, 10 and 11 and these values are stored in variables. Pins 9, 10 and 11 were deliberately chosen because they support pulse width modulation that allows the light intensity of the diodes to be gradually increased and decreased. Such pins are marked with a "~" sign (tilda). Variables are of integer type and their value cannot be changed during code execution due to the use of the keyword "const", so they can be called integer constants.

const int dugmeUvecaj = 3;
const int dugmeUmanji = 2;

Also the pins to which the keys are connected are defined as integer constants with values 2 and 3. This is also important because pins 2 and 3 on the Arduino UNO board have the ability to work with interrupts!

volatile int osvetljenjeProc = 0;
int osvetljenjePWM;

A variable whose value will change in ISRs is defined as "volatile". This step is important, otherwise the program will not work properly! An "volatile" variable of integer type is defined - osvetljenjeProc which will contain information on the percentage of brightness of the diode (possible values from 0 to 100). Another integer variable osvetljenjePWM will be used as an auxiliary, to translate the range from 0 to 100% of the brightness to the range from 0 to 255 which will be used when adjusting the brightness of the diode (in other words, this is the allowable range of the analogWrite function).

Setup section

pinMode(led1, OUTPUT);
pinMode(led2, OUTPUT);
pinMode(led3, OUTPUT);

Digital pins 9, 10 and 11 to which the diodes are connected led1, led2 and led3 are configured to work as outputs.

pinMode(tasterUvecaj, INPUT);
pinMode(tasterUmanji, INPUT);

The digital pins 2 and 3 to which the "Uvećaj" and "Umanji" buttons are connected are configured to work as output.

digitalWrite(led1, LOW);
digitalWrite(led2, LOW);
digitalWrite(led3, LOW);

Pins led1, led2 and led3 are set to a low voltage level (at the beginning of program execution, the diodes will be turned off)

attachInterrupt(digitalPinToInterrupt(tasterUvecaj), povecajNivoOsvetljenosti, RISING);
attachInterrupt(digitalPinToInterrupt(tasterUmanji), smanjiNivoOsvetljenosti, RISING);

This is a key part of the program when it comes to working with interrupts and using the function attachInterrupt which has three parameters:

  • digitalPinToInterrupt - this is the recommended way to connect the digital pin to the number of the interrupt. Digital pin 2 is connected to interrupt INT.0, and digital pin 3 is connected to interrupt INT.1;
  • increaseBrightness level - ISR function that is called when an interruption occurs; only the function name is specified;
  • RISING - the third parameter defines the triggering of the interrupt (change of the voltage signal on the digital pin). Possible values are:
    • LOW - to start an interrupt whenever the pin is at low voltage level - 0,
    • CHANGE - to trigger an interrupt whenever the pin changes state,
    • RISING - to trigger an interrupt when the pin switches from low to high voltage level,
    • FALLING - to start interrupt when the pin changes from high to low voltage level,

The same goes for the other attachInterrupt function

Loop section

Using interrupts significantly improves the readability of the program and its execution speed, but also simplifies its structure.

So there are only two lines of code in the loop section:

osvetljenjePWM = map(osvetljenjeProc, 0, 100, 0, 255);

diodeTrepere();

Variable osvetljenjePWM an appropriate value from the range 0 to 255 will be assigned depending on the value of the osvetljenjeProc whose possible range is 0 to 100 (representing the percentage value of the brightness of the diode) using the map function in the specified format.

A function diodoTrepere call follows diodeTrepere.

ISR functions

These two functions will be performed the moment the expected event takes place. In this case, pressing the "Uvećaj" button when the function povecajNivoOsvetljenosti is performed, or smanjiNivoOsvetljenosti when the "Umanji" button is pressed. As defined by the assignment, to increase or decrease the brightness of the diode in jumps of 10%, so these functions will increase and decrease the value of the variable osvetljenjeProc by 10%. Of course, there is also a logical control in the form of an "if" block that keeps the value of the variable in the range between 0 and 100.

Function diodeTrepere

Задатком је такође дефинисано да постоји одређени светлосни ефекат код диода. У овом случају је то треперење (наизменично укључивање и искључивање). Зато што се у задатку тражи да кориснику буде омогућено повећавање и смањивање јачине осветљености диоде, тако диоде морају најпре бити повезане на пинове који имају могућност Модулације ширине импулса. Други корак у решавању је коришћење функције analogWrite која омогућава да на дигиталном пину контролишемо напон у опсегу од 0 до 5V те ће диода светлети тачно одређеном јачином, коју одређује корисник. Диоде свелте одређени временски интервал (у овом случају је 200ms) након чега се диоде искључују функцијом digitalWrite на 200ms.