🕒 11 min read

How would one be better at using the Arduino? The key is practice and applying what you learn! In this post, that would be 3 activities (with sub tasks) that you can try out, and the solutions will be covered after you have attempted the activities. Let’s begin!

Changelog

V1.0 (22/10/20)

  • Initial release

V1.1 (25/10/20)

  • Added more details for the questions
  • Split the sections up
  • Updated images, added graphs

V1.2 (27/10/20)

  • Updated solutions section

Overview

These activities serves as a quick way to practice prototyping and the concepts with the Arduino, and to learn a few new components and sensors! I have designed the activities with a few objectives in mind, and would be going through it in the solutions section later below.

  • For this practice, please use the Arduino Simulator in Tinkercad Circuit to try them out. (If you have the actual components, it would be recommended to use the actual hardware instead of the simulated one.)
  • Should take approximately 1 – 2h to complete all the activities, have fun coding!

If stuck or unsure on how to tackle the activity, the search engine is your good friend.

And now, to the 3 main activities! (The concepts covered and solutions would be posted in the Solutions section, please try out the activities before going through the solutions.)

Activities

Waving RGB Lighting

Fascinated with the LED strips on speakers or shopping more? Here’s your chance to create something similar! Let’s try out fading the RGB LED with some sine wave! Wire the schematics as shown.

Components

  • RGB LED x 1
  • 330 Ohm resistors x 3
  • Jumper wires x 4
  • Arduino Uno x 1

Task A

Turn On the LEDs one at a time for 2000ms, and then off in the following order: Red, Blue, Green. (It would start from Red again after green.)

Task B

Fade the LEDs in a half triangular waveform for 1000ms and then off using a while loop. It would follow this order: Blue, Red, Green. (It would start from Blue again after Green.)

  • Use a while loop to change the brightness. (Hint: You need 2!)
  • The maximum brightness would be set at 250.
  • Each LED would ramp up in brightness for 1s, and then ramp down for 1s. (Total of 2s)

Task C

Fade the LEDs in a half cycle sinusoidal waveform for 800ms and then off in the following order: Red, Green, Blue. (It would start from Red again after Blue.)

  • Use a for loop to change the brightness. (Hint: You need 1!)
  • The maximum brightness would be set at 255.
  • Each LED would ramp up in brightness for 0.51s, and then ramp down for 0.51s. (Total of 1.02s)

7 Segment Display (Common Anode)

Remember the traffic light digits counting down when we are crossing the road? We would be trying out this common anode 7 segment display, which activates the LED when the pin is grounded! Wire the schematics as shown.

Components

  • 7 segment display (Common Anode) x 1
  • 330 Ohm resistors x 1
  • Jumper wires x 7
  • Arduino Uno x 1

Task A

Turn On the segments one at a time for 500ms to test out which pin corresponds to which segments.

  • Note down which pins corresponds to which Arduino pin.
Diagram of a Common Anode 7 segment display [1]

Task B

Display the number ‘0’ once. (Hint: Determine which segments need to be ON, which are OFF)

Task C

Display the numbers 0 – 9 once.

  • You can use a 2D array to store the segments to be ON/OFF to display the different numbers.
  • for loop could be used to iterate this 2D array.
7 segment display of 0 – 9 [2]

Task D

Reverse the order and countdown the number from 9 to 0, after which it would repeat itself. Each number would be displayed for 1 s, just like an actual timer!

Task E

Code for A – F (a hexadecimal extension), and countdown from F to 0.

  • Hint: Just add the hexadecimal characters to the 2D array.
Hexadecimal digits 0 – F [3]

Motion Activated Light (MAL)

In order to save power, some lights in the public area are equipped with a PIR sensor to brighten the area when motion is detected, else it would be dim. For this activity, we would be doing something similar: Turn on the LED for 3 seconds! Wire the schematics as shown.

Components

  • PIR Motion Sensor x 1
  • LED x 1
  • 330 Ohm resistors x 1
  • Jumper wires x 5
  • Arduino Uno x 1

Task A

Read the values of the PIR Sensor every 0.1s via digitalRead(). Use the Serial monitor to display the PIR sensor value, and determine how long the PIR sensor remains active.

Triggering the sensor

The motion sensor can be triggered by shifting the blue circle when the simulation is running.

Task B

Trigger the LED (using the polling method) to turn on for 3 seconds when motion is detected.

  • Recall what is polling.
  • Write a function to trigger the LED for 3 seconds when motion is detected.
Polling vs Interrupt [4]

Task C

Trigger the LED (using the interrupt method) to turn on for 5 seconds when motion is detected.

  • Recall what is interrupt, and how is it implemented.
  • Write a function (that would be called via the Interrupt Service Routine, ISR) to update the state of the LED when motion is detected using attachInterrupt().
  • delay() and millis() does not work in the ISR, but micros() could be used. [5]
  • Hint: The for loop would be used for keeping track the time, the ISR would be used to set the state of the LED and record the current time with micros().

 

Solutions

And the moment you have been waiting for: the solutions! (Note: If you have not attempted the activities and jumped straight here, we strongly advise you to give the activities above a shot beforehand as this is part of the learning process, and you’ll have a greater sense of achievement if you manage to complete it by your own too!)

Waving RGB Lighting

Task A

Concepts

  • Usage of Macros via #define to replace values
  • Pin initialization in setup() function
  • Output signals via digitalWrite()

This is a rather straight forward task of initiallising the GPIO pins as output, and turning on the various LED via the for loop with digitalWrite(PIN, VAL). PIN is the pin to output the “write” signal to, and VAL is the signal value to be outputted.

/*
  Arduino Practice
  > By Cyaninfinite, 1487Quantum ( https://github.com/1487quantum )
  
  > Activity 1 (RGB LED), Task A
  > Turn each LED color ON & OFF with a time period of 4 seconds. (2s ON, 2s OFF) 
*/

#define DELAY 2000          //Define how long to delay LED
const int led_p[3] = {11, 10, 9}; //LED pins to be used: RED BLUE GREEN

void setup()
{
  for (int i = 0; i < 3; ++i) //Pin initialization
    pinMode(led_p[i], OUTPUT);
}

void setLED(int pin) {
  digitalWrite(pin, HIGH);
  delay(DELAY);
  digitalWrite(pin, LOW);
  delay(DELAY);
}

void loop()
{
  for (int i = 0; i < 3; ++i) //Run through the 3 colors
    setLED(led_p[i]);
}

Task B

Concepts

  • Using Serial Monitor to track values / debugging
  • Using while() loop for iteration
  • Output PWM signals via analogWrite()

For this activity, one is constrained to use the while loop to iterate through the brightness with a ramp with a maximum brightness of 250 as shown in the chart below.

So from some quick calculation, one could tell that to reach the brightness of 250 in 1 second, we would iterate 250 times and each iteration of the LED brightness increment should last for 4ms:

4ms x 250 = 1000ms

2 while loops would be used to increment and decrement the LED brightness as described in the runRamp function. After each iteration, we would assign this value to the LED via the analogWrite(PIN, VAL).

/*
  Arduino Practice
  > By Cyaninfinite, 1487Quantum ( https://github.com/1487quantum )
  
  > Activity 1 (RGB LED), Task B
  > Turn each LED color ON & OFF with a time period of 2 seconds. (1s UP, 1s DOWN)
*/

#define DELAY 4
#define MAX_BRIGHTNESS 250

const int led_p[3] = {10, 11, 9}; //Blue Red Green

void setup()
{
  Serial.begin(115200);        //Setup Serial Monitor, for debugging
  for (int i = 0; i < 3; ++i)
    pinMode(led_p[i], OUTPUT);
}

void runRamp(int pin) {
  int i{0};                       // Index tracker
  while (i < MAX_BRIGHTNESS) { //Ramp Up brightness 
       setLED(pin, i); 
       ++i; 
  } 
while (i > 0) {                 //Ramp Down Brightness
    setLED(pin, i);
    --i;
  }
}

void setLED(int pin, int val) {
  analogWrite(pin, val);
  Serial.println(val);    //Print LED Value
  delay(DELAY);
}

void loop()
{
  for (int i = 0; i < 3; ++i)
    runRamp(led_p[i]);
}

Task C

Concepts

  • Using for() loop for iteration.
  • Figuring out how to achieve the desired function as specified (half-sinewave).

For this activity, one is constrained to use the for loop to iterate through the brightness with a half sinewave with a maximum brightness of 255 as shown in the chart below.

To achieve this waveform, one would be using the first half of the sinewave: the positive cycle. As the entire time period of this wave is 2.04s, we would only be looking at the first 1.02s. With the sine equation 255*sin(θ), we would have to determine the value of theta. (255 is the maximum possible value with the constrains mentioned, hence it would be used as the amplitude.)

  • When θ = 0 or π rad, sin(θ) = 0.
  • When θ = π/2 rad, sin(θ) = 1. (At maximum)

So as seen above, we have to somehow insert the constrains into the sine equation. Let’s insert the time period (define it as t) into the equation:

Let θ = t*π;

This would not work out, as the theta value is not nomarlised or relative to anything, which does not correspond to our constrains. Lets tweak the equation abit by normalising it with the maximum brightness, 255:

Let θ = (t/255)*π;

This would make more sense, but the time period is off by a factor of 4! To expand the sinewave by a factor of 4, we could mulitply 1/4 or 0.25 in theta to “stretch” the graph:

Let θ = 0.25*(t/255)*π;

And with this, the function looks similar to the constrain given! Therefore, the final equation would be y = 255*sin(0.25*(t/255)*π), where y is the output value. Only 1 for loop would be needed as the sine function covers both the rising and falling value of the LED.

/*
  Arduino Practice
  > By Cyaninfinite, 1487Quantum ( https://github.com/1487quantum )
  
  > Activity 1 (RGB LED), Task C
  > Turn each LED color ON & OFF with a time period of 1.02 seconds. (0.51s UP, 0.51s DOWN)
*/

#define DELAY 1
#define PI 3.1415927
#define MAX_BRIGHTNESS 255
#define T_PERIOD 1020


const int led_p[3] = {11, 9, 10}; //Red Green Blue

void setup()
{
  Serial.begin(115200);
  for (int i = 0; i < 3; ++i)
    pinMode(led_p[i], OUTPUT);
}

void runRamp(int pin) {
  for(int i=0; i<T_PERIOD; ++i)
    setLED(pin, i);
}

void setLED(int pin, int val) {
  int x_wave = (int) MAX_BRIGHTNESS*sin(0.25*val/(1.0*MAX_BRIGHTNESS)*PI);
  analogWrite(pin, x_wave);
  Serial.println(x_wave);
  delay(DELAY);
}

void loop()
{
  for (int i = 0; i < 3; ++i)
    runRamp(led_p[i]);
}

7 Segment Display (Common Anode)

Task A

Concepts

  • Determine which pins corresponds to which segement via trial and error
  • Common Anode 7 segment display uses an inverted logic (1/HIGH would turn OFF the segement, 0/LOW would turn ON the segment.)
/*
  Arduino Practice
  > By Cyaninfinite, 1487Quantum ( https://github.com/1487quantum )
  
  > Activity 2 (7 segment display, common Anode), Task A
  > =====================================================
  > The common Anode 7 segment display uses a inverted logic: A LOW would turn on the segment,
  > whereas HIGH would turn it off. This task would be used to determine which pin corresponds
  > to which segment.
*/

void setup()
{
  for(int i=6; i<13; ++i){
    pinMode(i, OUTPUT);
    digitalWrite(i, HIGH);	//Turn off all the segment
  }
}

void loop()
{
  for(int i=6; i<13; ++i){
  digitalWrite(i, LOW);		//Turn on segment
  delay(500); 
  digitalWrite(i, HIGH);	//Turn off segment
  delay(500);
  }
}

Task B

Concepts

  • Using the table of digits to determine how to display the number ‘0’.
  • Running the function once: could be done so by placing the function in the setup() function.
/*
  Arduino Practice
  > By Cyaninfinite, 1487Quantum ( https://github.com/1487quantum )
  
 > Activity 2 (7 segment display, common Anode), Task B
  > =====================================================
  > Display the number 0 on the 7 segment display.
*/

void setup()
{
  for(int i=6; i<13; ++i){
    pinMode(i, OUTPUT);
    digitalWrite(i, LOW);	//Turn on all the segment
  }
  digitalWrite(12, HIGH);	//Turn off segment g to display zero
}

void loop(){}

Task C

Concepts

  • Usage of 2D integer arrays to store the various segments to be ON/OFF
  • Finding the corresponding segments to display the respective numbers
  • Usage of iterators (such as for loop) to run through the segments to be ON/OFF
  • Creating a function to display the number on the 7 segment display.
  • Display all the numbers only once, not repeat
/*
  Arduino Practice
  > By Cyaninfinite, 1487Quantum ( https://github.com/1487quantum )
  
  > Activity 2 (7 segment display, common Anode), Task C
  > =====================================================
  > Display the number 0 to 9 once on the 7 segment display.
*/

//Segment pins to turn off for the various numbers
const int dispNum[10][5] = {
  {12},				//Num 0: g
  {10,11,12,8,7},	//Num 1:a f g e d
  {11,6},			//Num 2:f c
  {11,8},			//Num 3:f e
  {10,8,7},			//Num 4:a e d
  {9,8},			//Num 5:b e
  {9,5},			//Num 6:b
  {11,12,8,7},		//Num 7:f g e d
  {0},				//Num 8:-NONE-
  {8}				//Num 9:e
};

void onAllSegments(){
 for(int i=6; i<13; ++i)
    digitalWrite(i, LOW);	//Turn on all the segment
}

void setNum(int num){
  onAllSegments();
  for(int j=0; j<5; ++j){
    //Serial.println(dispNum[num][j]);
    if(dispNum[num][j]==0)
      break;
    else{
      digitalWrite(dispNum[num][j], HIGH);	//Turn off segments
    }
  }
  delay(1000);
}

void setup()
{
  Serial.begin(115200);
  for(int i=6; i<13; ++i){
    pinMode(i, OUTPUT);
    digitalWrite(i, HIGH);	//Turn off all the segement
  }
  //Display 0 - 9
  for(int k=0; k<10; ++k){
    setNum(k);
  }
}

void loop(){}

Task D

Concepts

  • Porting the code from the previous activity to display the countdown forever instead of only once.
  • Flipping the order of the number display
  • Creating a function to display the number on the 7 segment display.
/*
  Arduino Practice
  > By Cyaninfinite, 1487Quantum ( https://github.com/1487quantum )
  
  > Activity 2 (7 segment display, common Anode), Task D
  > =====================================================
  > Display countdown of the numbers 9 to 0 on the 7 segment display.
*/

//Segment pins to turn off for the various numbers
const int dispNum[10][5] = {
  {12},				//Num 0: g
  {10,11,12,8,7},	//Num 1:a f g e d
  {11,6},			//Num 2:f c
  {11,8},			//Num 3:f e
  {10,8,7},			//Num 4:a e d
  {9,8},			//Num 5:b e
  {9,5},			//Num 6:b
  {11,12,8,7},		//Num 7:f g e d
  {0},				//Num 8:-NONE-
  {8}				//Num 9:e
};

void onAllSegments(){
 for(int i=6; i<13; ++i)
    digitalWrite(i, LOW);	//Turn on all the segment
}

void setNum(int num){
  onAllSegments();
  for(int j=0; j<5; ++j){
    Serial.println(dispNum[num][j]);
    if(dispNum[num][j]==0)
      break;
    else{
      digitalWrite(dispNum[num][j], HIGH);	//Turn off segments
    }
  }
  delay(1000);
}

void setup()
{
  Serial.begin(115200);
  for(int i=6; i<13; ++i){ 
pinMode(i, OUTPUT); 
digitalWrite(i, HIGH); //Turn off all the segment 
} } 

void loop(){ //Display 9 - 0 
for(int k=9; k>=0; --k){
    setNum(k);
  }
} 

Task E

Concepts

  • Appending to the 2D integer array to display the hexadeciamal extension of the countdown.
  • Modifying the iterator (for loop) to account for the extension.
/*
  Arduino Practice
  > By Cyaninfinite, 1487Quantum ( https://github.com/1487quantum )

  > Activity 2 (7 segment display, common Anode), Task E
  > =====================================================
  > Display countdown of the hexadecimal numbers F to 0 on the 7 segment display.
*/

//Segment pins to turn off for the various numbers
const int dispNum[10][5] = {
  {12},				//Num 0: g
  {10,11,12,8,7},	//Num 1:a f g e d
  {11,6},			//Num 2:f c
  {11,8},			//Num 3:f e
  {10,8,7},			//Num 4:a e d
  {9,8},			//Num 5:b e
  {9,5},			//Num 6:b
  {11,12,8,7},		//Num 7:f g e d
  {0},				//Num 8:-NONE-
  {8},				//Num 9:e
  {7},				//Num A:d
  {10,9},			//Num B:a b
  {9,12,6},			//Num C:b g c
  {10,11},			//Num D:a f
  {9,6},			//Num E:b c
  {9,6,7}			//Num F:b c d
};

void onAllSegments(){
 for(int i=6; i<13; ++i)
    digitalWrite(i, LOW);	//Turn on all the segment
}

void setNum(int num){
  onAllSegments();
  for(int j=0; j<5; ++j){
    Serial.println(dispNum[num][j]);
    if(dispNum[num][j]==0)
      break;
    else{
      digitalWrite(dispNum[num][j], HIGH);	//Turn off segments
    }
  }
  delay(1000);
}

void setup()
{
  Serial.begin(115200);
  for(int i=6; i<13; ++i){ pinMode(i, OUTPUT); digitalWrite(i, HIGH); //Turn off all the segment } } void loop(){ //Display F - 0 for(int k=15; k>=0; --k){
    setNum(k);
  }
}

Motion Activated Light (MAL)

Task A

Concepts

  • Reading digital signals via digitalRead()
/*
  Arduino Practice
  > By Cyaninfinite, 1487Quantum ( https://github.com/1487quantum )
  
  > Activity 3 (PIR Motion Sensor with LED), Task A
  > =====================================================
  > Read the value of the PIR Motion sensor.
*/

#define PIR_PIN 2

void setup()
{
  pinMode(PIR_PIN, INPUT);
  Serial.begin(115200);
}

int pRead=0;

void loop()
{
  pRead = digitalRead(PIR_PIN);
  Serial.println(pRead);
  delay(100); 
}

Task B

Concepts

  • Usage of function to enable the LED to be delayed for 3s.
  • Reading the PIR Motion Sensor Values via the Polling method.
/*
  Arduino Practice
  > By Cyaninfinite, 1487Quantum ( https://github.com/1487quantum )
  
  > Activity 3 (PIR Motion Sensor with LED), Task B
  > =====================================================
  > Trigger the LED ON for 3s when motion is detected via polling method.
*/

#define PIR_PIN 2
#define LED_PIN 5

int pRead=0;

void setup()
{
  pinMode(LED_PIN, OUTPUT);
  pinMode(PIR_PIN, INPUT);
}

void turnOnLED(){
  digitalWrite(LED_PIN,HIGH);
  delay(3000);
  digitalWrite(LED_PIN,LOW);
  delay(1);
}


void loop()
{
  pRead = digitalRead(PIR_PIN);
  if(pRead)
    turnOnLED();
  delay(100); 
}

Task C

Concepts

  • Usage of Interrupts to trigger the LED delay function with a RISING EDGE trigger.
  • Usage of micros() to keep track of the timing. (The duration to keep the LED ON after the interrupt has been triggered)
  • Creation of interrupt function to be excecuted when the interrupt is triggered.
  • Use of volatile variables such that the variables can be accessed in the Interrupt Service Routine (ISR).
/*
  Arduino Practice
  > By Cyaninfinite, 1487Quantum ( https://github.com/1487quantum )
  
  > Activity 3 (PIR Motion Sensor with LED), Task C
  > =====================================================
  > Trigger the LED ON for 3s when motion is detected via interrupt method.
*/

#define latch_t 3000000

const byte PIR_PIN = 2;
const byte LED_PIN = 5;
volatile byte state = LOW;
volatile unsigned long duration;

void turnOnLED(){
  state = HIGH;
  duration = micros();
}

void setup()
{
  Serial.begin(9600);
  pinMode(LED_PIN, OUTPUT);
  pinMode(PIR_PIN, INPUT);
  attachInterrupt(digitalPinToInterrupt(PIR_PIN), turnOnLED, RISING );
}

void loop()
{
  Serial.println(micros()-duration);
  if(state && micros()-duration<=latch_t){
    digitalWrite(LED_PIN,HIGH);
  }else{
    state = LOW;
    digitalWrite(LED_PIN,LOW);
  }
}

 

Conclusion

This marks the end of this Arduino practice (or Revision), hopefully this activities were a fun and interesting way to learn various new sensors or components, and a way to figure out how to seek answers online when in doubt. All the best for your future endeavours in prototyping and projects with arduino!

References

Leave a Reply

Your email address will not be published. Required fields are marked *