Proyek bawaan · Arduino Uno R3

Lampu lalu lintas di Arduino Uno

Uno menjalankan penyeberangan pelikan, dengan 74HC04 yang menyalakan lampu WAIT langsung dari tombol. Seluruh rakitannya, Arduino Uno dan 12 komponen lainnya, berjalan di browsermu dengan firmware di bawah; buka di editor untuk mengubah rangkaian atau kodenya, lalu jalankan lagi.

Mengajar? Berikan sebagai tugas ke kelasmu dengan sekali klik.

Menengah About 30 minutes to build and run. Berjalan di browsermu. Gratis, dan tidak perlu akun.

Komponennya dijual sekitar $33. Di Mokxi, semuanya gratis.

Langkah demi langkah, dengan rangkaian dan kesalahan umumnya: Kode Lampu Lalu Lintas Arduino dengan Tombol Penyeberang

Lampu lalu lintas · Arduino Uno R3live0.000 s 0.00x
Tahan tombolnya
Rangkaiannya sendiri, berjalan di simulator di sini. Tekan yang bisa ditekan; klik yang lainnya untuk membukanya di editor.

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: Menengah
  • Time: About 30 minutes
  • Board: Arduino Uno R3
  • Parts: 14

Cara kerjanya

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 di 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 di all: a 74HC04 inverter lights it straight from the button line.

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.

Komponen dan pinConnects to
74HC04 hex inverter pin GNDArduino Uno R3 pin GND
Pushbutton pin 2aArduino Uno R3 pin GND
LED, red pin CArduino Uno R3 pin GND
LED, yellow pin CArduino Uno R3 pin GND
LED, green pin CArduino Uno R3 pin GND
LED, white pin CArduino Uno R3 pin GND
LED, blue pin CArduino Uno R3 pin GND
Resistor, 220 Ω (4) pin 1Arduino Uno R3 pin 11
Resistor, 220 Ω (3) pin 1Arduino Uno R3 pin 10
Resistor, 220 Ω (2) pin 1Arduino Uno R3 pin 9
Resistor, 220 Ω (1) pin 1Arduino Uno R3 pin 8
74HC04 hex inverter pin 1AArduino Uno R3 pin 2
Pushbutton pin 1aArduino Uno R3 pin 2
74HC04 hex inverter pin VCCArduino Uno R3 pin 5V
Resistor, 220 Ω (5) pin 174HC04 hex inverter pin 1Y
LED, red pin AResistor, 220 Ω (1) pin 2
LED, yellow pin AResistor, 220 Ω (2) pin 2
LED, green pin AResistor, 220 Ω (3) pin 2
LED, white pin AResistor, 220 Ω (4) pin 2
LED, blue pin AResistor, 220 Ω (5) pin 2

Kodenya

Firmware persis seperti yang dibuka di editor. Ubah satu baris di sana lalu tekan Jalankan: kodenya dikompilasi di browser.

sketch.ino · Arduino Uno R3
// 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 editor

Troubleshooting

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 before MIN_GREEN has 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. Tombol tekan
    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. Tombol tekan
    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.

Ubah dan simpan

Buka di editor, ubah rangkaian atau kodenya, lalu simpan versimu di akun gratis.