Zápisník experimentátora
The popular project for Arduino is the simulation of the traffic lights. In today's article, we will program this traffic lights. We will not do this classically, but we will use a sequencer to make this task a very simple task. We programmed the sequencer in the past in the article on generating a signal SOS.
The Arduino Pro Mini is on the photos. It does not limit you, you can use any Arduino.
Our example simulates two semaphores. There are three lights on both. The three lights take care the cars do not crashed on the crossing. So one semaphore has the green light and the other has the red. At regular intervals, lights on traffic lights exchange.
A typical traffic light in Slovakia operates as follows. The traffic lights illuminate for 10-20 seconds green. It switches to orange and then to red. Then the red color shines for 10-20 seconds. Simultaneously with red color turns orange. Then both colors go out and the green color turns on. This is repeated over and over again. At the second traffic lights, the colors are shifted. Always the red color is on one traffic light and the green color is on the other.
Sequencers are very simple tools. At regular intervals, they send the requested value to the output. In our case, we will create a sequencer to simulate the previous example. At 1 s intervals, the LEDs are turned on or off. The sequencer has the advantage that if the program requirements change, the program itself does not need to change and only the sequence changes.
I wrote three sketches. Two serve to test the circuit, and the third is to simulate a semaphore.
The first program is used to test the circuit. Gradually turns on each LED. If all lights up, you are connected properly.
int leds[] = {2, 3, 4, 5, 6, 7};
int step = 0;
void setup() {
for (int i = 0; i < 6; i++)
pinMode(leds[i], OUTPUT);
}
void loop() {
for (int i = 0; i < 6; i++)
digitalWrite(leds[i], i == step ? HIGH : LOW);
step++;
step %= 6;
delay(1000);
}
The second program serves to test the circuit and the sequencer. The sequencer is created in the Sequencer
class. It has only two functions. In the constructor
, we mark the sequence data and in the function next
, we advance each time in sequence and set the LED to HIGH or LOW. Note the LEDs on which Arduine pins are connected. These are pins 2, 3, 4, 5, 6 and 7. Why did I choose these pins? Because all these pins are on port D and I can control them by assigning a value directly to the port.
int leds[] = {2, 3, 4, 5, 6, 7};
// 222111xx
// GYRGYR
const char PROGMEM sequence[] = {
0b00000100,
0b00001000,
0b00010000,
0b00100000,
0b01000000,
0b10000000,
};
const int sequence_length = sizeof(sequence) / sizeof(char);
class Sequencer {
char *data;
int len;
int pos;
public:
Sequencer(char *_data, int _len)
: data(_data), len(_len), pos(0)
{}
void next() {
char b = pgm_read_byte(&data[pos]);
PORTD = b;
pos++;
if (pos == len)
pos = 0;
}
};
Sequencer seq(sequence, sequence_length);
void setup() {
for (int i = 0; i < 6; i++)
pinMode(leds[i], OUTPUT);
}
void loop() {
seq.next();
delay(1000);
}
The third program is the simulation of the lights at the crossroad. The previous example has been timed with function delay
due to clarity. Now we can make our program as efficient as possible and use timer1 for timing. Using the calculator we set the timer to 1 Hz (every 1000 ms), and the function next
in the Sequencer
class will be called from the TIMER1_COMPA_vect
interrupt.
int leds[] = {2, 3, 4, 5, 6, 7};
// 222111xx
// GYRGYR
const char PROGMEM sequence[] = {
0b10000100, // red, green
0b10000100,
0b10000100,
0b10000100,
0b10000100,
0b10000100,
0b10000100,
0b10000100,
0b10000100,
0b10000100,
0b01000100, // red, orange
0b01000100,
0b00100100, // red, red
0b00101100, // red+orange, red
0b00110000, // green, red
0b00110000,
0b00110000,
0b00110000,
0b00110000,
0b00110000,
0b00110000,
0b00110000,
0b00110000,
0b00110000,
0b00101000, // orange, red
0b00101000,
0b00100100, // red, red
0b01100100, // red, red+orange
};
const int sequence_length = sizeof(sequence) / sizeof(char);
class Sequencer {
char *data;
int len;
int pos;
public:
Sequencer(char *_data, int _len)
: data(_data), len(_len), pos(0)
{}
void next() {
char b = pgm_read_byte(&data[pos]);
PORTD = b;
pos++;
if (pos == len)
pos = 0;
}
};
Sequencer seq(sequence, sequence_length);
void setupTimer1() {
noInterrupts();
// Clear registers
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
// 1 Hz (16000000/((15624+1)*1024))
OCR1A = 15624;
// CTC
TCCR1B |= (1 << WGM12);
// Prescaler 1024
TCCR1B |= (1 << CS12) | (1 << CS10);
// Output Compare Match A Interrupt Enable
TIMSK1 |= (1 << OCIE1A);
interrupts();
}
void setup() {
for (int i = 0; i < 6; i++)
pinMode(leds[i], OUTPUT);
setupTimer1();
}
void loop() {
}
ISR(TIMER1_COMPA_vect) {
seq.next();
}
The source code is located on the GitHub server.
12.09.2017