Arduino Workshop-– Interactive Traffic Lights

The Arduino will react when the button is pressed by changing the state of the lights to make the cars stop and allow the pedestrian to cross safely. For the first time, we will be able to interact with the Arduino and cause it to do something when we change the state of a button that the Arduino is watching (i.e., press the button to change the state from open to closed). In this project, we will also learn how to create our own functions in code

Parts Required
  • Arduino
  • 2 x Red Diffused LEDs Yellow Diffused LED
  • 2 x Green Diffused LEDs 
  • 10KΩ Resistor 
  • 5 x Current-Limiting Resistors 
  • Pushbutton 
This book will help you to gain more knowledge about Arduino
Beginning Arduino


Circuit diagram

Interactive Traffic Lights
Interactive Traffic Lights

Interactive Traffic Lights Code

Code Overview

Most of the code in this project you will understand and recognize from previous projects. However, let us take a look at a few new keywords and concepts that have been introduced in this sketch.
 unsigned long changeTime = 0; 
Here we have a new data type for a variable. Previously, we have created integer data types, which can store a number between the range −32,768 and 32,767. This time, we have created a data type of long, which can store a number from −2,147,483,648 to 2,147,483,647. However, we have specified an unsigned long, which means the variable cannot store negative numbers, which gives us a range from 0 to 4,294,967,295. If we were to use an integer to store the length of time since the last change of lights, we would only get a maximum time of 32 seconds before the integer variable reached a number higher than it could store. As a pedestrian crossing is unlikely to be used every 32 seconds, we don’t want our program misbehaving due to our variable “overflowing” when it tries to store a number too high for the variable data type. That is why we use an unsigned long data type as we now get a huge length of time in between button presses. The number is initialized with 0. 4,294,967,295 * 1ms = 4,294,967 seconds 4,294,967 seconds = 71,582 minutes 71,582 minutes = 1,193 hours 1,193 hours = 49 days As it is inevitable that a pedestrian crossing will get its button pressed at least once in 49 days, we shouldn’t have a problem with this data type. You may well ask why we don’t just have one data type that can store huge numbers all the time and be done with it. Well, the reason we don’t do that is that variables take up space in memory, and the larger the number the more memory is used up for storing variables. On your home PC or laptop, you won’t have to worry about that much at all, but on a small microcontroller like the Atmega328 that the Arduino uses, it is essential that we use only the smallest variable data type necessary for our purpose

Each data type uses up a certain amount of memory on the Arduino, as you can see on the chart
above. Some variables use only one byte of memory and others use four or more (don’t worry about
what a byte is for now as we will discuss this later). You cannot copy data from one data type to
another; for example, if x was int and y was a string, then x = y would not work as the two data
types are different.
The Atmega168 has 1kB(1024 bytes) and the Atmega328 has 2kB(2048 bytes) of SRAM. This is
not a lot, and in large programs with lots of variables, you could easily run out of memory if you do
not optimize your usage of the correct data types. From the list above, we can clearly see that our use
of the int data type is wasteful as it uses up two bytes and can store a number up to 32,767. As we
have used int to store the number of our digital pin, which will only go as high as 13 on our Arduino
(and up to 54 on the Arduino Mega), we have used up more memory than was necessary. We could
have saved memory by using the byte data type, which can store a number between 0 and 255, which
is more than enough to store the number of an I/O pin.
Next, we have
pinMode(button, INPUT);
This tells the Arduino that we want to use digital pin 2 (button = 2) as in INPUT. We are going to
use pin 2 to check for button presses, so its mode needs to be set to input.
In the main program loop, we check the state of digital pin 2 with this statement:-
int state = digitalRead(button);
This initializes an integer called “state” (yes, it’s wasteful and we should use a boolean), and then
sets the value of the state to be the value of the digital pin 2. The digitalRead statement reads the state of
the digital pin within the parenthesis and returns it to the integer we have assigned it to. We can then
check the value in state to see if the button has been pressed or not.

if (state == HIGH && (millis() - changeTime) > 5000) {
// Call the function to change the lights
changeLights();
}
The if the statement is an example of a control structure and its purpose is to check if a certain
condition has been met or not, and if so, to execute the code within its code block. For example, if we
wanted to turn an LED on if a variable called x rose above the value of 500, we could write
if (x>500) {digitalWrite(ledPin, HIGH);
When we read a digital pin using the digitalRead command, the state of the pin will either be
HIGH or LOW. So the if command in our sketch looks like this:
if (state == HIGH && (millis() - changeTime) > 5000)
What we are doing here is checking that two conditions have been met. The first is that the
variable called state is high. If the button has been pressed state will be high as we have already set it
to be the value read in from digital pin 2. We are also checking that the value of millis()-changeTime
is greater than 5,000 (using the logical AND operator &&). The millis() function is one built into the
Arduino language and it returns the number of milliseconds since the Arduino started to run the
current program. Our changeTime variable will initially hold no value, but after the changeLights()
function runs, you set it at the end of that function to the current millis() value.
By subtracting the value in the changeTime variable from the current millis() value, you can check
if five seconds have passed since changeTime was last set. The calculation of millis()-changeTime is
put inside its own set of parenthesis to ensure that you compare the value of state and the result of this
calculation, and not the value of millis() on its own.
The symbol && in between
state == HIGH
and the calculation is an example of a boolean operator. In this case, it means AND. To see what
we mean by that, let’s take a look at all of the boolean operators.

&& Logical AND
|| Logical OR
! NOT

These are logic statements and can be used to test various conditions in if statements.
&& means true if both operands are true, for example:
if (x==5 && y==10) {....

This if statement will run its code only if x is 5 and also if y is 10.
|| means true if either operand is true, e.g.:

if (x==5 || y==10) {.....
This will run if x is 5 or if y is 10.
The ! or NOT statement means true if the operand is false, for example:

if (!x) {.......
Will run if x is false, i.e., equals zero.
You can also “nest” conditions with parenthesis, for example
if (x==5 && (y==10 || z==25))

 Arduino Workshop-– Interactive Traffic Lights Hardware Overview


A logic circuit is one designed to give an output of either on or off. These are represented by the binary numbers 1 and 0. For Arduino inputs and outputs, the off (or zero) state is a voltage near to zero volts at the output and a state of on (or 1) is represented by a higher level, closer to the supply voltage. The simplest representation of a logic circuit is a switch

With a voltage going through the switch and the switch open, no current can flow through it and no voltage can be measured at the output. When you close the switch, the current can flow through it and a voltage can be measured at the output. The open state can be thought of as a zero and the closed state as a 1 in a logic circuit. In a logic circuit, if the expected voltage to represent the on (or 1) state is five volts, then it is important that when the circuit outputs a 1 that the voltage is as close to five volts as possible. Similarly, when the output is a zero (or off), then it is important that the voltage is as close to zero volts as possible. If you do not ensure that the states are close to the required voltages, then that part of the circuit may be considered to be “floating,” that is, it is neither in a high or low state. This is where pull-up or pull-down resistors can be used to ensure the state is high or low. If you let that node in the circuit “float,” then it may be interpreted as either a zero or a one, which is not desirable. Therefore, forcing it towards a desired state when it is inclined to float is desirable. The floating state is susceptible to electrical noise, and noise in a digital circuit may be interpreted as random 1s and 0s

Pull-Down Resistors
we have a schematic (a schematic is a conceptual rather than physical diagram of how the circuits are interconnected) in which a pull-down resistor being used. If the button is pressed, then the electricity takes the path of least resistance and moves between the five volts and the input pin, as there is a 100 ohm resistor on the input pin and a 10K ohm resistor on ground. However, when the button is not pressed, the input is connected to the 100K ohm resistor and is “pulled” towards ground. Without this pull to ground, the pin would not be connected to anything when the button was not depressed and would float in-between zero and five volts. In this circuit, the input will always be pulled to ground, or zero volts, when the button is not pressed and will be pulled towards five volts when the button is pressed. We have therefore made sure that in either state the pin is either reading zero or five volts and not floating in-between those two values

Pull-Up Resistors
In this circuit, we have swapped the pull-down resistor and the switch. The resistor now serves as
a pull-up resistor. Now you can see that when the button is not pressed, the input pin is pulled
towards the five volts and so will always be high. When the button is pressed, the path of least
resistance is towards the ground and so the pin is pulled to ground or the low state. Without the
resistor between five volts and ground it would be a short circuit which would damage your circuit or
power supply. But with the resistor it is no longer a short circuit as the resistor limits the amount of
current that can flow to a small amount. The pull-up resistor is used more commonly in digital
circuits.
With the use of simple pull-up or pull-down resistors, you can ensure that the state at an input pin
is always either high or low, depending on your application. In Project 4 we used a pull-down
resistor to ensure a button press could be registered correctly by the Arduino. Let’s take a look at the
pull-down resistor in that circuit again


The Arduino’s Internal Pull-Up Resistors
Conveniently, the Arduino happens to have pull-up resistors connected to the digital pins (the analog
pins have pull-up resistors also). These have a value of 20K ohms and need to be activated in
software to use them. To activate an internal pull-up resistor on a pin, you first need to change the
pinMode of the pin to an INPUT and then write a HIGH to that pin using a digitalWrite
command. For example:
pinMode(pin, INPUT);
digitalWrite(pin, HIGH);
If you change the pinMode from INPUT to OUTPUT after activating the internal pull-up resistors,
then the pin will remain in a HIGH state. This also works in reverse in that an output pin that was in a
HIGH state that is subsequently switched to an INPUT mode will have its internal pull-up resistors
enabled.
Now that you understand the use of pull-up and pull-down resistors, which will be used throughout
the book, let us move onto Project 5 and make some lighting effects with our LEDs.



No comments

Theme images by Dizzo. Powered by Blogger.