Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Creative DIY Microcontroller Projects with TinyGo and WebAssembly

You're reading from   Creative DIY Microcontroller Projects with TinyGo and WebAssembly A practical guide to building embedded applications for low-powered devices, IoT, and home automation

Arrow left icon
Product type Paperback
Published in May 2021
Publisher Packt
ISBN-13 9781800560208
Length 322 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
Tobias Theel Tobias Theel
Author Profile Icon Tobias Theel
Tobias Theel
Arrow right icon
View More author details
Toc

Table of Contents (13) Chapters Close

Preface 1. Chapter 1: Getting Started with TinyGo 2. Chapter 2: Building a Traffic Lights Control System FREE CHAPTER 3. Chapter 3: Building a Safety Lock Using a Keypad 4. Chapter 4: Building a Plant Watering System 5. Chapter 5: Building a Touchless Handwash Timer 6. Chapter 6: Building Displays for Communication using I2C and SPI Interfaces 7. Chapter 7: Displaying Weather Alerts on the TinyGo Wasm Dashboard 8. Chapter 8: Automating and Monitoring Your Home through the TinyGo Wasm Dashboard 9. Assessments 10. Afterword 11. Other Books You May Enjoy Appendix – "Go"ing Ahead

Building traffic lights with pedestrian lights

We will now combine everything we have learned and done in this chapter to create an even more realistic traffic lights system. We will do so by assembling a circuit that contains the three-bulb traffic lights from the previous step and adding pedestrian lights with two bulbs that are controlled by a button.

Assembling the circuit

For our final project in this chapter, we need the following:

  • Five LEDs: preferably two red, one yellow, and two green
  • Five 220 Ohm resistors, one for each LED
  • One 10K Ohm resistor as a pull-up resistor for our push button
  • One 4-pin push button
  • 14 jumper wires

We start by setting up the three-bulb traffic lights using the following steps:

  1. Place the first LED (red) with the cathode on G12 and the anode on G13.
  2. Place the second LED (yellow) with the cathode on G15 and the anode on G16.
  3. Place the third LED (green) with the cathode on G18 and the anode on G19.
  4. Use a 220 Ohm resistor to connect F13 with D13.
  5. Use a 220 Ohm resistor to connect F16 with D16.
  6. Use a 220 Ohm resistor to connect F19 with D19.
  7. Connect pin D13 with A13 using a jumper wire.
  8. Connect pin D12 with A16 using a jumper wire.
  9. Connect pin D11 with A10 using a jumper wire.
  10. Connect F12 with Ground on the power bus using a jumper wire.
  11. Connect F15 with Ground on the power bus using a jumper wire.
  12. Connect F18 with Ground on the power bus using a jumper wire.

Now assemble the pedestrian lights using the following steps:

  1. Place the fourth LED (red) with the cathode on G22 and the anode on G23.
  2. Place the fifth LED (green) with the cathode on G25 and the anode on G26.
  3. Use a 220 Ohm resistor to connect F23 with D23.
  4. Use a 220 Ohm resistor to connect F26 with D26.
  5. Connect pin D5 with A23 using a jumper wire.
  6. Connect pin D4 with A26 using a jumper wire.
  7. Connect F22 with Ground on the power bus using a jumper wire.
  8. Connect F24 with Ground on the power bus using a jumper wire.

Now we only need to assemble the button and connect the power bus:

  1. Place a push button with the left pins in E29 and F29 and the right pins on E31 and F31.
  2. Use a 10K Ohm resistor to connect the Ground from the power bus with B29.
  3. Connect pin D2 with C29 using a jumper wire.
  4. Connect A31 with the positive lane on the power bus using a jumper wire.
  5. Connect the positive lane on the power bus with the 5V port on the Arduino UNO using a jumper wire.
  6. Connect the ground lane on the power bus with a ground port on the Arduino UNO using a jumper wire.

When you've finished assembling, your circuit should look like this:

Figure 2.8 – Circuit for the traffic lights with pedestrian lights controlled by 
a button – image taken from Fritzing

Figure 2.8 – Circuit for the traffic lights with pedestrian lights controlled by a button – image taken from Fritzing

Great, we have now completely assembled our final project for this chapter. We can now write some code to bring this project to life.

Setting up the project structure

We start off by creating a new folder named traffic-lights-pedestrian inside the Chapter02 folder. Inside the new folder, we create a new main.go file with an empty main function.

Our project structure should now look like the following:

Figure 2.9 - Project structure for the project

Figure 2.9 - Project structure for the project

Writing the logic

We are going to split the program into three parts:

  • Initialization logic
  • Main logic
  • trafficLights logic

Initializing the logic

We need to initialize a stopTraffic variable and configure the pins for the LEDs as output pins using the following steps:

  1. We start off by declaring a bool variable named stopTraffic at the package level. This variable is going to be used as a communication channel between our two logic parts:
    var stopTraffic bool
  2. The first thing we do in the main method is set the value of stopTraffic to false:
    stopTraffic = false
  3. We declare and initialize a new variable named outputConfig with PinConfig in PinOutput mode. We are going to pass this config to all LED pins:
    outputConfig := machine.PinConfig{Mode: machine.
                    PinOutput}
  4. We initialize some new variables: greenLED with the value machine.D11, yellowLED with the value machine.D12, and redLED with the value machine.D13. Then, we configure each LED variable as output pins:
    greenLED := machine.D11
    greenLED.Configure(outputConfig)
    yellowLED := machine.D12
    yellowLED.Configure(outputConfig)
    redLED := machine.D13
    redLED.Configure(outputConfig)
  5. We initialize some new variables: pedestrianGreen with the value machine.D4 and pedestrianRed with the value machine.D5. Then, we configure each LED variable as output pins:
    pedestrianGreen := machine.D4
    pedestrianGreen.Configure(outputConfig)
    pedestrianRed := machine.D5
    pedestrianRed.Configure(outputConfig)
  6. We declare and initialize a new variable named inputConfig with PinConfig in PinInput mode. Then, we declare and initialize a new variable named buttonInput with the value machine.D2 and configure buttonInput as the input pin:
    inputConfig := machine.PinConfig{Mode: machine.PinInput}
    buttonInput := machine.D2
    buttonInput.Configure(inputConfig)

That's it for the initialization. We have set up all pins and a Boolean variable at the package level.

Note

The pin constants, such as machine.D13, are of the machine.Pin type.

Writing the trafficLights logic

We will now write the complete logic to control all the LEDs in our circuit. This is going to be the first time that we have to move some parts of the code into other functions.

To do that, we start by writing a new function named trafficLights that takes all five LED pins as parameters and has no return value. Inside the function, we start off with an empty, endless loop. Our function should now look like the following:

func trafficLights(redLED, greenLED, yellowLED, pedestrianRED, 
    pedestrianGreen machine.Pin) {
      for {
      }
}

All the logic will be placed inside the for loop. The actual logic in the loop consists of two parts:

  • Handling signals from the button to stop the traffic and control the pedestrian lights
  • Controlling the normal traffic lights flow

We start off with handling the signals from the button. To do that, we check for stopTraffic in the if, and also have an empty else branch. It looks like the following:

        if stopTraffic {
    } else {
}

So, when stopTraffic is true, we want to set our traffic lights phase to be red. Also, we want to set the pedestrian lights phase to green for 3 seconds and then back to red and set stopTraffic to false afterward, as we handled the signal one time.

Let's implement this logic using the following steps:

  1. Set traffic lights phase to red:
    redLED.High()
    yellowLED.Low()
    greenLED.Low()
  2. Set the pedestrian lights phase to green for 3 seconds:
    pedestrianGreen.High()
    pedestrianRED.Low()
    time.Sleep(3 * time.Second)
  3. Set the pedestrian lights phase to red:
    pedestrianGreen.Low()
    pedestrianRED.High()
  4. Set stopTraffic to false, as we have handled the signal:
    stopTraffic = false
  5. In the else block, we just reset the pedestrian lights state to red:
    pedestrianGreen.Low()
    pedestrianRED.High()

Okay, that is the part that reacts to stopTraffic signals. Underneath that if-else block, we are going to implement the actual logic to control the traffic lights flow, which is the same as done earlier. So, we start with the red phase, transit to the red-yellow phase, then to green, then to yellow, and then reset yellow to be able to start clean again, as follows:

redLED.High()
time.Sleep(time.Second)
yellowLED.High()
time.Sleep(time.Second)
redLED.Low()
yellowLED.Low()
greenLED.High()
time.Sleep(time.Second)
greenLED.Low()
yellowLED.High()
time.Sleep(time.Second)
yellowLED.Low()

That is all that we have to do in the trafficLights function.

Implementing the main logic

Now we only need to run the trafficLights function and handle the button input at the same time. This is where goroutines come in. As microcontrollers only have one processor core, which works with a single thread, we cannot have real parallel execution of tasks. As we use goroutines on an Arduino UNO, we will need some additional build parameters. We are going to learn about these parameters later, when we flash the program. In our case, we want to have a listener on the button, while still being able to step through the traffic lights process. The logic consists of three steps:

  1. Initialize the pedestrian lights with the red phase.
  2. Run the trafficLights function in a goroutine.
  3. Handle the button input.

For the first part, we only have to set the pedestrianRED LED to High and the pedestrianGreen LED to Low:

pedestrianRed.High()
pedestrianGreen.Low()

Now we just call trafficLights and pass all necessary parameters using a goroutine:

go trafficLights(redLED, greenLED, yellowLED, pedestrianRed, pedestrianGreen)

For the last step, we need an endless loop that checks for buttonInput and to set stopTraffic to true if the button is pressed. We also need it to sleep for 50 milliseconds afterward:

for {
  if buttonInput.Get() {
    stopTraffic = true
  }
  time.Sleep(50 * time.Millisecond)
}

Note

It is necessary to add a sleep time to the loop that handles the button input because the scheduler needs time to run the goroutine. The goroutine is being handled in the time that the main function is sleeping. Also, other blocking functions, such as reading from a channel, can be used to give the scheduler time to work on other tasks.

As we now have completed our logic, it is time to flash the program onto the controller. As we are using goroutines in this project, we need to pass additional parameters to the tinygo flash command:

tinygo flash -scheduler tasks -target=arduino Chapter02/traffic-lights-pedestrian/main.go

As the ATmega328p has very limited resources, the scheduler is deactivated by default on boards that use this microcontroller. The Arduino UNO is such a board. When using other microcontrollers, we would normally not need to override the default scheduler by setting this parameter.

We have now successfully flashed our program to the Arduino Uno. The traffic lights should start looping all phases and the pedestrian lights should remain in the red phase. When clicking the button, the traffic lights should end their loop and then the pedestrian lights should switch to the green phase, while the traffic lights remain on the red phase for 3 seconds.

Note

Due to the very limited memory on the Arduino Uno, working with goroutines might only work in projects that are not very complex, such as this one.

You have been reading a chapter from
Creative DIY Microcontroller Projects with TinyGo and WebAssembly
Published in: May 2021
Publisher: Packt
ISBN-13: 9781800560208
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image