LEDs are a digital output, and as such can only be on or off. In order to make them appear less bright, it is necessary to switch them on and off very rapidly so that the human eye cannot see them flicker. This process is called Pulse Width Modulation (PWM).
The human eye can detect complete image changes at a frequency of about 25 per second, or 25 Hertz (Hz). To avoid flicker entirely, most TVs operate at 50Hz or 60Hz (region dependent) with some modern TVs operating at 100Hz or even 200Hz.
We will think of an LED switching ON and OFF at 100Hz. This gives a time period (T) of 10ms that the LED spends going through a cycle of ON and OFF. The proportion of the time it spends ON will determine how bright it appears.
For example:
If it were ON for 10ms and OFF for 0ms, it would appear to the eye as full bright.
If it were ON for 5ms and OFF for 5ms, it would appear to the eye as roughly half bright.
If it were ON for 0ms and OFF for 10ms it would appear to the eye as off.
This is because the average voltage (and hence energy) that the LED receives is proportional to the ratio of ON time (mark) to OFF time (space) as shown:
Hopefully you can see it is the changing (modulation) of the pulse width (relative to the total period) that affects the average voltage, hence the name pulse width modulation.
On the Arduino this is done in one of two ways:
Manually by turning the LED on and off rapidly with short delay commands in between, and by varying the delay after switching it on relative to the delay after switching it off. This will only work for the time that you are specifically controlling it, but is available on all pins.
More easily, using the analogWrite() command, which is only available on certain pins (3,5,6,9,10,11). This command essentially sets up the PWM for you, and continues to run in the background, keeping the LED at the same brightness until you tell it to do something else.
Copy your Ex1_1_Blink code into the Virtual Turorial Board, it will form the basis of Ex2_1_Throb.
Replace the digitalWrite() commands with analogWrite() commands.
Replace the HIGH with 255 to get maximum brightness and the LOW with 100 to get a lower brightness (0 would turn the LED completely off).
Change the first delay to 200ms.
Make sure it is pin 3 that you have declared as an output and sending the analogWrite() commands to.
LED 3 should now look like a heartbeat. Copy the program into your document "Lesson #2 programs" on the Google Classroom.
Modify your program Ex2_1_Throb to make Ex2_2_CrudeFade.
Write a program that will make the LED on pin 3 slowly increase in brightness (over say 10 levels, starting at level 0 then increasing up to the max level of 255) and then slowly dim again
When you run this program you will probably notice it is a bit jerky because this approach of sending commands to the chip is rather crude. We will learn how we can make it smoother in a future lesson.
Copy the program into your document "Lesson #2 programs" on the Google Classroom.
You may have also noticed in Crude Fade that if you wanted to change which LED you're working with, you have to change its value in the pinMode() command and in at least twenty analogWrite() commands. Imagine if you had even more commands acting on the same LED and you wanted to change which LED they act on; how annoying would it be to have to change the LED number in each command?
If you want to store a value that you use a lot during a program, but that doesn't change during the program, you want to create a constant integer. In this case, the constant integer represents the value of the LED you're working with so let's call it "ledPin" and give it a value of 3 since we're working with pin 3. The code will again go in a new line ABOVE the void setup(){} and look like this:
const int ledPin = 3;
You want to declare a variable outside of functions, otherwise it would only be available to the function inside which it is declared. In this case, you'll call on ledPin in both the setup(){} and loop(){}; if you create it in one or the other, the IDE will give you an error.
Again, const int specifies what you are creating, "ledPin" is its name, and 3 (in this case) is the value it takes.
Open up Ex2_2_CrudeFade
Change all the references throuout your code from pin 3 to ledPin. In the pinMode command this look like: pinMode (ledPin, OUTPUT);
make sure you change all the analogWrite commands as well.
You can now try changing the value of the ledPin constant integer to a 6 or 5 and see how that trickles down into the whole program when you run it.
save it as Ex2_3_ConstantFade. Make sure you've copied all your programs into your document "Lesson #2 programs" on the Google Classroom.
Eventually you may want to be able to switch the LED on and off by pressing the same button, in which case the chip needs to keep track of the state of the LED. You can create a variable that will store this information, which, as you may imagine, is generally incredibly useful in programing devices. There are many types of variable, which can store many different types of data, but the simplest type is an integer.
Start by opening Ex1_1_Blink, re-save it as Ex2_4_VariableBlink
Create a variable in a new line, above the setup(){} function. In this case you're going to have a variable be an integer and store the value of the delay time, so you want to call the variable "time". The code will look like this:
int time;
where the int part says what kind of variable you've created and the word after is the name of the variable. Just like with a const int, except that it's value can be changed throughout the program.
In the setup(){} you'll give it a starting value:
time = 500;
Now that you have a value for the delay and it's stored in the memory, go ahead and replace the 1000 ms inside each delay() with time, so the pauses between the LED turning on and off will be delay(time). You should test the program to make sure the delay command is using the variable you've created – the LED will blink faster.
After the second delay in the loop(){} and before the } closing the loop, add another line:
time = time - 20;
Run the program, save and copy/screenshot.
What happens with the LED as the program goes on, and why?
Write a program (Ex2_5_UpDown35) where LED 3 brightens while LED 5 dims (over 6 levels). You should use constant integers to refer to LEDs 3 and 5.
Adapt the program Ex2_5_UpDown35 to have LED 5 brighten while LED 6 dims. Save it in the Google Doc under Ex2_6_UpDown56.
With what you've learned so far, you could make some pretty fun lightshows. To make really useful systems, they need to be able to respond to the environment around them, or to a user. These are inputs to the system. With a PC the inputs are clear: the keyboard, the mouse as well as some other peripheral devices.
On the Arduino, there are two types of inputs, digital and analogue. Both work by measuring the voltage at the input pin of the chip. We will look at analogue inputs in a later lesson, but for this week we will focus on digital inputs. Digital inputs are inputs that can only be on or off and the chip can only determine if the voltage at the pin is high or low.
A perfect example of the digital input is a switch. It is either pressed or not pressed. There are two switches set up on the tutorial board, connected to pins A4 and A5.
The command to read from a digital input is fairly intuitively named digitalRead(), and is followed by the number of the pin you wish to read from, e.g. digitalRead(A5). This command will "return" a value, that means it will become equal to something, in this case either TRUE or FALSE, where TRUE would mean the voltage at pin A5 is high, and FALSE would mean it is low.
In order to do something useful with this, we need a command that can use the TRUE or FALSE: the if(){} command. Before we add this to a program, let's look at the if(){}, as this is one of the fundamental building blocks of computer programming.
The if(){} command looks at the statement inside the brackets (called the "condition") and evaluates it at that moment in time. If the statement is TRUE, then the program will run the code in the {} brackets immediately following the if() command. If the condition is FALSE, the program will not run this code, and will instead jump to the next line after the } belonging to the if(){}.
Start from the blank program.
Create a constant integer called ledPin with a value of 2.
Create a constant integer called button1 with a value of A5.
Define ledPin as an output in the setup(){}.
In the loop(){}, check if button1 has been pressed with a digitalRead() command inside an if(){}.
Have LED 2 turn on when the button has been pressed.
The complete code to turn on LED 2 in response to the button press is below:
if(digitalRead(button1)) {
digitalWrite(ledPin, HIGH);
}
save it under Ex2_7_ButtonCheck
Congratulations on programming both an input and output! You will notice that the LED stays on after pressing the button, so if you want to enjoy your hard work again, stop and restart the simulation (press the Reset (R) button on the tutorial board) so you can interact with the input again.
Write a program Ex2_8_OnOff where pressing button A4 turns LED 2 on and pressing button A5 turns it off. Your program should refer to the buttons as button1 and button2.
EXTENSION - optional if you have time
Write a program where one of the LED initially turns on and off every 0.5s, then every 0.1s if you press A4 or every 0.5s if you press A5.
Now move on to lesson 3: the for loop.