Bei einer Lösung mit zwei Lichtschranken weiß der Mikrocontroller, welche Lichtschranke gerade angefahren wurde. Das ist möglich, da das System mit
zwei Eingängen jeweils für eine Lichtschranke arbeitet. So ist die Berechnung der Geschwindigkeit deutlich einfacher. Bei Verwendung von nur einer Lichtschranke hat
der Mikrocontroller ein Problem, da er nicht weiß, ob das Fahrzeug gerade in den Messbereich reinfährt oder ihn gerade verlässt. Für die beiden sehr wichtigen
Erkennungsmomente (Messpunkte) steht lediglich ein Eingang zur Verfügung. Das Prinzip:
Der Infrarotstrahl wird von der Lichtschranke zum ersten Reflektor (im Beispiel ein Spiegel) gesendet. Hier wird sein Lauf gebrochen und er erreicht den zweiten Reflektor.
Von dem zweiten Reflektor wird er komplett reflektiert. Über den ersten Reflektor erreicht er dann auf dem Rückweg den Empfänger der Lichtschranke. Bei solchem
Aufbau entstehen zwei Messpunkte, die sich in einem bestimmten Abstand zueinander befinden. Die Lichtschranke sendet dann ein Signal zu dem Mikrocontroller, wenn
der Lichtstrahl am ersten oder zweiten Messpunkt unterbrochen wird.
Der Abstand zwischen beiden Messpunkten muss vor der Inbetriebnahme der Schaltung ermittelt werden und als Konstante im Programm eingegeben werden. Die Aufgabe
der Schaltung ist es dann, die Zeit, die ein Fahrzeug benötigt, um die Strecke zwischen den beiden Messpunkten zu passieren, zu ermitteln. Die anschließend berechnete
Geschwindigkeit des Fahrzeugs wird auf der Geschwindigkeitstafel angezeigt.
Schaltplan
Testschaltung
Damit unsere Geschwindigkeitstafel richtig funktioniert und die Geschwindigkeitsanzeige der tatsächlichen Geschwindigkeit eines Fahrzeugs entspricht,
führen wir in das Programm eine weitere Variable „Messintervall_in_micros“ ein. In dem Beispiel hat die Variable den Wert 1000000. Damit wird die minimale Geschwindigkeit
eines Fahrzeugs festgelegt. Sie beträgt in dem Fall ca. 17 km/h. Das bedeutet, dass Geschwindigkeiten, die darunter liegen, nicht berücksichtigt werden.
Damit schließen wir Fehler, die entstehen könnten, wenn bei neuer Messung zuerst der zweite Messpunkt angefahren wäre, aus. Ohne diese Einschränkung könnte
folgendes passieren: Zuerst wird der zweite Messpunkt angefahren. Das Programm registriert diese Tatsache, als ob der erste Messpunkt angefahren wäre. Erst nach
einiger Zeit wird von einem anderen Fahrzeug der erste Messpunkt angefahren. Das Programm würde daraufhin die Geschwindigkeit berechnen, die möglicherweise sehr klein
ausfallen würde. Obwohl das zweite Fahrzeug möglicherweise in Wirklichkeit mit z.B. 50 km/h durch die Tempo-30-Zone rast.
Programm (Sketch)
// ****************************************************************************************************
// Geschwindigkeitstafel mit einer Lichtschranke und zwei Reflektoren
// Eine Schaltung mit Arduino Mega
// Arduino IDE 2.2.1
// ****************************************************************************************************
#include "RGBmatrixPanel.h"
#define CLK 11 // Matrix Anschlüsse
#define OE 9
#define LAT 10
#define A A0
#define B A1
#define C A2
#define D A3
#define E A4
RGBmatrixPanel matrix(A, B, C, D, E, CLK, LAT, OE, false, 64);
int Interrupt_Start = 2; // Eingang Interrupt (Zeitmessung Anfang+Ende)
bool Erste_Messung_erlaubt; // Neue Messung erst, wenn Anzeige zu Ende
bool Zweite_Messung_erlaubt; // Reihenfolge der Zeitmessung beachten
unsigned long Zeit_Messung_Anfang; // Zeit Anfang festhalten
unsigned long Zeit_Messung_Ende; // Zeit Ende festhalten
unsigned long Anzeige_neutral_verzoegerung; // Keine Messungen = Smiley neutral
float Geschwindigkeit_km_h; // Ergebnis Geschwindigkeit in km/h
bool Anzeige_Smiley_neutral; // true - Anzeige Smiley neutral aktiv
int Verzoegerung; // Anzeige Verzögerung
float Lichtschranken_Abstand_in_mm = 95.0; // tatsächlicher Lichtschranken-Abstand
unsigned long Messintervall_in_micros = 1000000; // Zeitspanne, in der Messung akzeptiert wird
// ****************************************************************************************************
void setup() {
matrix.begin();
delay(500);
pinMode(Interrupt_Start, INPUT);
attachInterrupt(digitalPinToInterrupt(Interrupt_Start), Lichtschranke_angefahren, RISING);
Erste_Messung_erlaubt = true;
Smiley_neutral ();
}
// ****************************************************************************************************
void loop() {
if (abs(Geschwindigkeit_km_h) <= 30 && Geschwindigkeit_km_h > 0) { // Tempo OK
Geschwindigkeitsanzeige ();
Smiley_happy ();
Anzeige_Smiley_neutral = false;
Geschwindigkeit_km_h = 0;
Erste_Messung_erlaubt = true;
Anzeige_neutral_verzoegerung = millis();
}
if (Geschwindigkeit_km_h > 30) { // Tempo zu hoch
Geschwindigkeitsanzeige ();
Smiley_traurig ();
Anzeige_Smiley_neutral = false;
Geschwindigkeit_km_h = 0;
Erste_Messung_erlaubt = true;
Anzeige_neutral_verzoegerung = millis();
}
Verzoegerung = millis () - Anzeige_neutral_verzoegerung;
if (Verzoegerung > 8000) {
if (Geschwindigkeit_km_h == 0) { // keine Bewegung
Erste_Messung_erlaubt = true;
if (not Anzeige_Smiley_neutral) {
Smiley_neutral ();
Anzeige_Smiley_neutral = true;
}
}
}
}
// ****************************************************************************************************
// Interrupt - Programm ------------------------------------------------------------------------------
void Lichtschranke_angefahren () {
if (Zweite_Messung_erlaubt) { // 2. Messpunkt
Zeit_Messung_Ende = micros();
float Zeit = Zeit_Messung_Ende - Zeit_Messung_Anfang; // Ermittelte Zeit
Erste_Messung_erlaubt = true;
if (Zeit < Messintervall_in_micros) { // Geschwindigkeitsberechnung
Geschwindigkeit_km_h = (Lichtschranken_Abstand_in_mm * 1000) / Zeit;
Geschwindigkeit_km_h = Geschwindigkeit_km_h * 3.6;
Geschwindigkeit_km_h = Geschwindigkeit_km_h * 50; // *50 Wert in Bereich um 30 km/h
Geschwindigkeit_km_h = abs(Geschwindigkeit_km_h); // Anzeige ohne Komma
Erste_Messung_erlaubt = false; // Neue Messungen blockieren
Zweite_Messung_erlaubt = false; // bis Anzeige angeschlossen
}
}
if (Erste_Messung_erlaubt) { // 1. Messpunkt
Zeit_Messung_Anfang = micros(); // Zeit festhalten in Microsekunden
Zweite_Messung_erlaubt = true; // Zweite Zeitmessung kann folgen
}
}
// Anzeige grün smiley happy --------------------------------------------------------------------------
void Smiley_happy () {
screen_clear(); // Matrix löschen
Kreis (32,32,25,0,7,0); // Kopf
Kreis (21,24,6,0,7,0); // Auge links
Kreis (43,24,6,0,7,0); // Auge rechts
Halbkreis_unten (32,38,10,0,7,0); // Mund
delay (1000);
}
// Anzeige rot smiley traurig -------------------------------------------------------------------------
void Smiley_traurig () {
screen_clear();
Kreis (32,32,25,7,0,0);
Kreis (21,24,6,7,0,0);
Kreis (43,24,6,7,0,0);
Halbkreis_oben (32,48,10,7,0,0);
delay (1000);
}
// Anzeige gelb smiley neutral ------------------------------------------------------------------------
void Smiley_neutral () {
screen_clear();
Kreis (32,32,25,7,7,0);
Kreis (21,24,6,7,7,0);
Kreis (43,24,6,7,7,0);
matrix.drawLine(25, 44, 38, 44, matrix.Color333(7, 7, 0));
}
// Aktuelle Geschwindigkeit anzeigen ------------------------------------------------------------------
void Geschwindigkeitsanzeige () {
screen_clear(); // Matrix löschen
matrix.setTextSize(1); // Textgröße
matrix.setCursor(3, 5); // Cursor Position
matrix.setTextColor(matrix.Color333(7,7,0)); // Textfarbe
matrix.println("Sie fahren"); // Textausgabe
matrix.setTextSize(2);
matrix.setCursor(19, 25);
matrix.setTextColor(matrix.Color333(0,7,0));
if (abs(Geschwindigkeit_km_h) > 30) {
matrix.setTextColor(matrix.Color333(7,0,0));
}
String Anzeige = String (Geschwindigkeit_km_h,0);
matrix.println(Anzeige);
matrix.setTextSize(1);
matrix.setCursor(33, 50);
matrix.setTextColor(matrix.Color333(7,7,0));
matrix.println("km/h");
delay(1000);
}
// Matrix Löschen -------------------------------------------------------------------------------------
void screen_clear() {
matrix.fillRect(0, 0, matrix.width(), matrix.height(), matrix.Color333(0, 0, 0));
}
// Kreis zeichnen -------------------------------------------------------------------------------------
void Kreis (int X, int Y, int r, int R, int G, int B) {
for (int i=X-r; i <= X+r; i++) {
for (int j=Y-r; j <= Y+r; j++) {
int a = abs (X-i);
int b = abs (Y-j);
float R_Ist = sqrt (sq(a) + sq(b));
float R_Soll = r;
if (R_Ist < (R_Soll + 0.5) and R_Ist > (R_Soll - 0.5)) {
matrix.drawPixel(i, j, matrix.Color333(R, G, B));
}
}
}
}
// Halb-Kreis unten zeichnen --------------------------------------------------------------------------
void Halbkreis_unten (int X, int Y, int r, int R, int G, int B) {
for (int i=X-r; i <= X+r; i++) {
for (int j=Y+2; j <= Y+r; j++) {
int a = abs (X-i);
int b = abs (Y-j);
float R_Ist = sqrt (sq(a) + sq(b));
float R_Soll = r;
if (R_Ist < (R_Soll + 0.5) and R_Ist > (R_Soll - 0.5)) {
matrix.drawPixel(i, j, matrix.Color333(R, G, B));
}
}
}
}
// Halb-Kreis oben zeichnen ---------------------------------------------------------------------------
void Halbkreis_oben (int X, int Y, int r, int R, int G, int B) {
for (int i=X-r; i <= X+r; i++) {
for (int j=Y-r; j <= Y-2; j++) {
int a = abs (X-i);
int b = abs (Y-j);
float R_Ist = sqrt (sq(a) + sq(b));
float R_Soll = r;
if (R_Ist < (R_Soll + 0.5) and R_Ist > (R_Soll - 0.5)) {
matrix.drawPixel(i, j, matrix.Color333(R, G, B));
}
}
}
}
// ****************************************************************************************************