Semáforo num Arduino Uno
Um Uno controla um semáforo de pedestres com botão, com um 74HC04 acendendo a lâmpada WAIT direto pelo botão. A montagem inteira, um Arduino Uno e mais 12 componentes, roda aqui no seu navegador com o firmware abaixo; abra no editor para mudar a ligação ou o código e rodar de novo.
Dá aula? Passe para a sua turma com um clique.
Intermediário About 30 minutes to build and run. Roda no seu navegador. Grátis, e não precisa de conta.
Os componentes custam cerca de $33 nas lojas. No Mokxi eles são grátis.
Passo a passo, com a ligação e os erros comuns: Código de semáforo no Arduino com botão de pedestre
What you'll learn
- Interrupts that catch a press during
delay - Minimum and maximum timing for a phase
- A traffic light sequence
- Using a logic chip instead of code
- Pull-up inputs and active low buttons
- Difficulty: Intermediário
- Time: About 30 minutes
- Board: Arduino Uno R3
- Parts: 14
Como funciona
The Uno runs a pelican crossing. Green is the resting state, on pin 10. Pressing the button on pin 2 triggers an interrupt that sets a flag, even while the sketch is waiting. Green lasts em least 3 seconds, and at most 9 seconds if no one presses.
Then amber shows for 1.5 seconds, red and the walk lamp on pin 11 show for 4 seconds, and flashing amber with a flashing walk lamp runs for 6 seconds. The blue WAIT lamp is not controlled by the Uno em all: a 74HC04 inverter lights it straight from the button line.
Lista de componentes
14 componentes, mais os jumpers. Eles custam cerca de $33 nas lojas; no Mokxi são grátis.
- 1 × Arduino Uno R3In Starter Kit, Claw Machine Kit, Vending Machine Kit.
- 1 × Protoboard grande
- 1 × 74HC04 hex inverter
- 1 × BotãoIn Starter Kit, Christmas Lights Kit, Logic Lab Kit.
- 5 × Resistor, 220 ΩIn Starter Kit, Claw Machine Kit, Halloween Prop Kit.
- 1 × LED vermelhoIn Starter Kit, Halloween Prop Kit, Logic Lab Kit.
- 1 × LED amareloIn Starter Kit, Halloween Prop Kit, Logic Lab Kit.
- 1 × LED verdeIn Starter Kit, Halloween Prop Kit, Logic Lab Kit.
- 1 × LED brancoIn Starter Kit, Halloween Prop Kit, Logic Lab Kit.
- 1 × LED azulIn Starter Kit, Halloween Prop Kit, Logic Lab Kit.
Wiring table
Every connection, pin by pin, read from the circuit itself. Each row joins the pin on the left to the pin on the right, by a jumper wire or a breadboard strip.
| Componente e pino | Connects to |
|---|---|
| 74HC04 hex inverter pin GND | Arduino Uno R3 pin GND |
| Pushbutton pin 2a | Arduino Uno R3 pin GND |
| LED, red pin C | Arduino Uno R3 pin GND |
| LED, yellow pin C | Arduino Uno R3 pin GND |
| LED, green pin C | Arduino Uno R3 pin GND |
| LED, white pin C | Arduino Uno R3 pin GND |
| LED, blue pin C | Arduino Uno R3 pin GND |
| Resistor, 220 Ω (4) pin 1 | Arduino Uno R3 pin 11 |
| Resistor, 220 Ω (3) pin 1 | Arduino Uno R3 pin 10 |
| Resistor, 220 Ω (2) pin 1 | Arduino Uno R3 pin 9 |
| Resistor, 220 Ω (1) pin 1 | Arduino Uno R3 pin 8 |
| 74HC04 hex inverter pin 1A | Arduino Uno R3 pin 2 |
| Pushbutton pin 1a | Arduino Uno R3 pin 2 |
| 74HC04 hex inverter pin VCC | Arduino Uno R3 pin 5V |
| Resistor, 220 Ω (5) pin 1 | 74HC04 hex inverter pin 1Y |
| LED, red pin A | Resistor, 220 Ω (1) pin 2 |
| LED, yellow pin A | Resistor, 220 Ω (2) pin 2 |
| LED, green pin A | Resistor, 220 Ω (3) pin 2 |
| LED, white pin A | Resistor, 220 Ω (4) pin 2 |
| LED, blue pin A | Resistor, 220 Ω (5) pin 2 |
O código
O firmware exatamente como o editor abre. Mude uma linha lá e aperte Rodar: ele compila no navegador.
// Traffic light: a pelican crossing with a button that actually does
// something.
//
// pin 8 red pin 11 walk
// pin 9 amber pin 2 request button, to GND, internal pull-up
// pin 10 green
//
// The button is on INT0, so a press is caught by the interrupt even while
// loop() is asleep inside delay(). Without that the sketch would only notice a
// press if you happened to be holding the button when it got round to looking,
// which is exactly the bug every first crossing sketch has.
//
// Green is the resting state and it waits there for a request, but never for
// less than MIN_GREEN: a crossing that stopped the traffic the instant anyone
// asked would never let a car through.
//
// The WAIT lamp on the breadboard is not driven from here at all. It hangs off
// a 74HC04 inverter wired straight to the button line, so it lights the moment
// the contact closes, a reminder that not everything has to be the
// microcontroller's job.
const int RED = 8;
const int AMBER = 9;
const int GREEN = 10;
const int WALK = 11;
const int BUTTON = 2;
const unsigned long MIN_GREEN = 3000;
const unsigned long MAX_GREEN = 9000;
const unsigned long AMBER_MS = 1500;
const unsigned long WALK_MS = 4000;
volatile bool requested = false;
static void onPress() { requested = true; }
static void lights(int red, int amber, int green) {
digitalWrite(RED, red ? HIGH : LOW);
digitalWrite(AMBER, amber ? HIGH : LOW);
digitalWrite(GREEN, green ? HIGH : LOW);
}
// Hold green until someone asks, or until the maximum runs out.
static void waitForRequest() {
unsigned long started = millis();
for (;;) {
unsigned long waited = millis() - started;
if (waited >= MAX_GREEN) return;
noInterrupts();
bool asked = requested;
interrupts();
if (asked && waited >= MIN_GREEN) return;
delay(20);
}
}
void setup() {
pinMode(RED, OUTPUT);
pinMode(AMBER, OUTPUT);
pinMode(GREEN, OUTPUT);
pinMode(WALK, OUTPUT);
pinMode(BUTTON, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(BUTTON), onPress, FALLING);
Serial.begin(115200);
Serial.println("Mokxi Arduino Uno: crossing ready, press the button");
}
void loop() {
lights(0, 0, 1);
Serial.println("green");
waitForRequest();
lights(0, 1, 0);
Serial.println("amber");
delay(AMBER_MS);
lights(1, 0, 0);
digitalWrite(WALK, HIGH);
Serial.println("walk");
delay(WALK_MS);
// the flashing period at the end of the walk phase
// The pelican's own ending: the walk lamp flashes to say "finish crossing"
// while the drivers get a flashing amber, which means "go if the crossing
// is clear". Then straight back to green. (A red-and-amber pair before
// green is the junction signal's sequence, not a crossing's.)
Serial.println("flashing amber");
for (int i = 0; i < 12; i++) {
int on = (i & 1) ? LOW : HIGH;
digitalWrite(WALK, on);
lights(0, on == HIGH, 0);
delay(500);
}
digitalWrite(WALK, LOW);
noInterrupts();
requested = false;
interrupts();
}
Code walkthrough
The key functions of the sketch, and what each one does.
onPress sketch.ino
The interrupt handler. It only sets the volatile flag requested to true. Keeping it tiny is the rule for interrupt code.
static void onPress() { requested = true; }waitForRequest sketch.ino
Holds green. It returns when MAX_GREEN has passed, or when a request exists and MIN_GREEN has passed. It copies the flag with interrupts off so the read is safe.
// Hold green until someone asks, or until the maximum runs out.
static void waitForRequest() {
unsigned long started = millis();
for (;;) {
unsigned long waited = millis() - started;
if (waited >= MAX_GREEN) return;
noInterrupts();
bool asked = requested;
interrupts();
if (asked && waited >= MIN_GREEN) return;
delay(20);
}
}lights sketch.ino
Sets the red, amber and green pins in one call. A non-zero argument turns that lamp on.
static void lights(int red, int amber, int green) {
digitalWrite(RED, red ? HIGH : LOW);
digitalWrite(AMBER, amber ? HIGH : LOW);
digitalWrite(GREEN, green ? HIGH : LOW);
}loop sketch.ino
Runs the whole sequence once per pass: green, amber, red with walk, then twelve half second flashes. At the end it clears the request flag.
void loop() {
lights(0, 0, 1);
Serial.println("green");
waitForRequest();
lights(0, 1, 0);
Serial.println("amber");
delay(AMBER_MS);
lights(1, 0, 0);
digitalWrite(WALK, HIGH);
Serial.println("walk");
delay(WALK_MS);
// the flashing period at the end of the walk phase
// The pelican's own ending: the walk lamp flashes to say "finish crossing"
// while the drivers get a flashing amber, which means "go if the crossing
// is clear". Then straight back to green. (A red-and-amber pair before
// green is the junction signal's sequence, not a crossing's.)
Serial.println("flashing amber");
for (int i = 0; i < 12; i++) {
int on = (i & 1) ? LOW : HIGH;
digitalWrite(WALK, on);
lights(0, on == HIGH, 0);
delay(500);
}
digitalWrite(WALK, LOW);
noInterrupts();
// ... 3 more lines in the editorTroubleshooting
The usual mistakes with this circuit, and the fix for each.
- A press is ignored. This project
The button must be on pin 2, the interrupt pin. It joins pin 2 to GND. - The WAIT lamp does not light. This project
It comes from the 74HC04, not the sketch. Check 5 V and GND on the chip, and the button line into 1A. - The crossing never leaves green. This project
That only happens beforeMIN_GREENhas passed. Wait three seconds after a press. - The outputs are random or noisy. 74HC04 hex inverter
Tie every unused input to GND or VCC. A floating CMOS input can oscillate, draw extra current and give random outputs. - The chip behaves badly or an LED is too dim. 74HC04 hex inverter
Add a 0.1 uF capacitor between VCC (pin 14) and GND (pin 7). Run it on 2 V to 6 V. An output gives only a few milliamps, so use a resistor with any LED. - The input reads random HIGH and LOW when the button is not pressed. Botão
A floating pin picks up noise. Add a 10 k pull-down or pull-up resistor, or use INPUT_PULLUP and wire the button between the pin and GND. Then pressed reads LOW. - The button seems always pressed, or never changes. Botão
A 4-leg tactile switch has legs joined in pairs. Place it across the breadboard center gap so the pairs sit on different rows. Wired along one side, the legs are already connected. - The LED is dim, burns out, or the pin reads wrong because the resistor value is off. Resistor
Read the color bands again. A 220 ohm to 330 ohm resistor suits a typical LED on 5 V. 10k is a common pull-up or pull-down value. Check with a multimeter if unsure.
Mude e guarde
Abra no editor, mude o circuito ou o código e guarde a sua versão numa conta grátis.