Lernziele: Arduino-Entwicklungsumgeung (IDE) kennenlernen; Programmiersprache C++ kennenlernen; erstes Arduino-Programm schreiben; Display ansteuern.
Zuerst baust du eine Adruino-Box. Das ist eine verschliessbaer Plastik-Box, die neben dem Arduino UNO folgende Komponenten enthält:
Die Idee der Box: Du kannst auf dem Breadboard elektronische Bauteile aufbringen und mit dem Arduino verbinden. Diesen Aufbau kannst du jederzeit mitnehmen: USB-Kabel rein, Box verschliessen und in den Rucksack!
Baue die Box zusammen. Überlege zuerst gut, wie du die Teile auf dem Deckel der Box platzierst, sodass es praktisch zum Arbeiten ist (Verbindung zum Laptop, Display-Verbindung etc.). Klebe dann die Teile mit doppelseitigem Klebenband oder Heissleim fest.
Informiere dich über die Arduino-Programmierung in der Programmiersprache C++ hier:
Arduino programmieren
Verbinde das Display und teste es: Dein Display soll „Hello World“ zeigen.
Lernziele: LEDs, Tasten und Potentiometer mit digitalen und analogen Ein- und Ausgängen verbinden und ansteuern.
Tipp: Du benötigst die Funktionen pinMode(), digitalWrite() und delay().
Lösung mit delay()
- Blink.ino
# define ledPin 2
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
digitalWrite(ledPin, HIGH);
delay(1000);
digitalWrite(ledPin, LOW);
delay(1000);
}
Lösung mit millis()
- BlinkMillis.ino
# define ledPin 2
bool toggleLED = false;
long time1;
int pauseTime = 1000
void setup() {
pinMode(ledPin, OUTPUT);
time1 = millis();
}
void loop() {
if(millis()-time1 > pauseTime){
if(toggleLED == true){
digitalWrite(ledPin, HIGH);
toggleLED = false;
}
else{
digitalWrite(ledPin, LOW);
toggleLED = true;
}
time1 = millis();
}
}
Tipp: Du benötigst u. a. die Funktion analogRead(). Informiere dich erst über diese Funktion: Arduino-Referenz
Lösung
- BlinkTune.ino
#define ledPin 2 // LED+ über Widerstand auf an Pin 2, LED- auf GND
#define potiPin A0 // Abriff des Potentiometers --> 0...5 V, auf Pin A0.
int analogValue = 0;
void setup() {
pinMode(ledPin, OUTPUT);
}
void loop() {
analogValue = analogRead(potiPin);
digitalWrite(ledPin, HIGH);
delay(analogValue);
digitalWrite(ledPin, LOW);
delay(analogValue);
}
Tipps:
Lösung
- BlinkSteps.ino
#define ledPin 2 // LED+ über Widerstand auf an Pin 13, LED- auf GND
#define downPin 4 // Taste "down" verbindet Pin 4 mit GND
#define upPin 5 // Taste "up" verbindet Pin 4 mit GND
#define debounce 200 // Wartezeit (in ms) zur "Entprellung" der Tasten
bool ledOn = false; // Umschalt-Flag: schalte ein, wenn false – schalte aus, wenn true
int waitTime = 1020; // setze Wartezeit auf Initialwert
int waitTime_max = 2020;
int waitTime_min = 20;
int waitTime_step = 200;
long time1;
void setup() {
Serial.begin(9600);
pinMode(ledPin, OUTPUT);
pinMode(downPin, INPUT_PULLUP);
pinMode(upPin, INPUT_PULLUP);
time1 = millis();
}
void loop() {
if (!digitalRead(downPin)){
delay(debounce);
if(waitTime > waitTime_min){
waitTime -= waitTime_step;
}
Serial.println(waitTime);
}
if (!digitalRead(upPin)){
delay(debounce);
if(waitTime < waitTime_max){
waitTime += waitTime_step;
}
Serial.println(waitTime);
}
if(millis()-time1 >= waitTime){
if(ledOn){
digitalWrite(ledPin, LOW);
ledOn = false;
}
else{
digitalWrite(ledPin, HIGH);
ledOn = true;
}
time1 = millis();
}
}
Tipp: Um unterschiedliche Helligkeitsstufen zu setzen benötigst du PWM-Ausgänge, die du mit analogWrite() ansteuerst:
Lösung
- RGB-LED.ino
/* RGB-LED mit gemeinsamer Annode --> Anode auf +5V.
Kathoden für red, green, blue über Widerstand auf
folgende PWM-Pins (für green ginge auch anderer Pin,
da grün bloss ein/ausgeschaltet wird): */
#define ledRedPin 9
#define ledGreenPin 10
#define ledBluePin 11
#define potiPin A0 // Abriff des Potentiometers --> 0...5 V, auf Pin A0.
#define downPin 4 // Taste "down" verbindet Pin 4 mit GND
#define upPin 5 // Taste "up" verbindet Pin 5 mit GND
#define onOffPin 6 // Taste "onOff" verbindet Pin 6 mit GND
#define debounce 200 // Wartezeit (in ms) zur "Entprellung" der Tasten
uint8_t red = 255; // Werte auf HIGH, sodass LED dunkel
bool green = 1;
uint8_t blue = 255;
uint8_t blueStep = 5;
void setup() {
pinMode(ledRedPin, OUTPUT);
pinMode(ledGreenPin, OUTPUT);
pinMode(ledBluePin, OUTPUT);
pinMode(potiPin, INPUT);
pinMode(downPin, INPUT_PULLUP);
pinMode(upPin, INPUT_PULLUP);
pinMode(onOffPin, INPUT_PULLUP);
}
void loop() {
red = analogRead(potiPin);
if(!digitalRead(onOffPin)){
delay(debounce);
green = !green;
}
if(!digitalRead(downPin)){
delay(debounce);
if(blue > 0){
blue -= blueStep;
}
}
if(!digitalRead(upPin)){
delay(debounce);
if(blue < 255){
blue += blueStep;
}
}
analogWrite(ledRedPin, red);
digitalWrite(ledGreenPin, green);
analogWrite(ledBluePin, blue);
}
Zusatzaufgaben
Zeige auf dem Display die aktuellen Farbwerte an.
Progammiere ein Leuchtmuster: LED-Farbe wechselt regelmässig.
Programmiere mehrere Leuchtmuster, die dann via Display und Tasten wählbar sind. Verwende evtl
Neo-Pixel-Bautele anstelle von RGB-LEDs.
Lernziele: Zeitmessung mit millis(), Strings und Formatierungen verwenden, Arrays verwenden, EEPROM beschreiben und auslesen, Bit-Operatoren verwenden.
Programmiere den Arduino so, dass du die Zeit stoppen kannst:
Lösung
- CrhonoMeter01.cpp
/* Chronometer gemäss Aufgabe 1:
* Start und Stop-Taste für Zeitmessung. Die gestoppte Zeit
* wird laufend und bei Betätigung der Stop-Taste angezeigt. */
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// create object of class LiquidCrytal_I22 and define parametes:
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
// Konstanten festlegen (für bessere Lesbarkeit des Codes):
#define startPin 5
#define stopPin 4
#define debounce 100 // Wartezeit zur "Entprellung" der Tasten (Millisekunden)
// Folgende Variable speichert den Status der Zeitmessung
bool timeRunning;
// Folgende Variablen speichern Zeiten in Millisekunden:
unsigned long startTime;
unsigned long currentTime;
unsigned long stoppedTime;
// Folgende Vraiabeln dienen der Anzeige im Format MM:SS:HH:
unsigned int minutes;
unsigned int seconds;
unsigned int hundreds;
char timeString[] = "00:00:00";
void setup() {
// Eingänge definieren:
pinMode(startPin, INPUT_PULLUP);
pinMode(stopPin, INPUT_PULLUP);
// Variablen definieren bzw. auf Initial-Werte setzen:
timeRunning = 0;
startTime = 0;
currentTime = 0;
stoppedTime = 0;
// Anzeige vorbereiten:
lcd.begin(16,2); // initialize the lcd
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Zeit:");
}
void loop() {
if(timeRunning == 1){
currentTime = millis() - startTime;
lcd.setCursor(8, 0);
showTime(currentTime);
}
if (digitalRead(startPin) == LOW) {
delay(debounce);
startTime = millis();
stoppedTime = 0;
currentTime = 0;
timeRunning = 1;
}
if (digitalRead(stopPin) == LOW) {
delay(debounce);
stoppedTime = millis() - startTime;
lcd.setCursor(8, 0);
showTime(stoppedTime);
timeRunning = 0;
}
}
void showTime(unsigned long timeMS){
// Minuten, Sekunden und Hundertstel berechnen:
minutes = timeMS/60000;
seconds = (timeMS-minutes*60000)/1000;
hundreds = (timeMS-minutes*60000-seconds*1000)/10;
// Werte im gewünschten Format in Array timeString schreiben:
sprintf(timeString,"%02d:%02d:%02d", minutes, seconds, hundreds);
// ...und ans LCD ausgeben:
lcd.print(timeString);
}
Speichere dein Programm Chronometer 1 unter neuem Namen und erweitere es wie folgt:
Lösung
- ChronoMeter02.cpp
/* Chronometer gemäss Aufgabe 2:
* Start und Stop-Taste für Zeitmessung. Die gestoppte Zeit
* wird jeweils bei Betätigung der Stop-Taste angezeigt.
* Zusätzlich wird die beste seit Reset gemessene Zeit angezeigt.
* Reset-Taste setzt alle Zeiten zurück.
*/
#include <SoftwareSerial.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// create object of class LiquidCrytal_I22 and define parametes:
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
// Konstanten festlegen (für bessere Lesbarkeit des Codes):
#define startPin 5
#define stopPin 4
#define resetPin 3
#define nextPin 2
#define debounce 100
// Folgende Variable speichert den Status der Zeitmessung
bool timeRunning;
// Folgende Variablen speichern die Zeiten in Millisekunden:
unsigned long startTime;
unsigned long currentTime;
unsigned long stoppedTime;
unsigned long bestTime;
// Folgende Vraiablen dienen der Anzeige im Format MM:SS:HH:
unsigned int minutes;
unsigned int seconds;
unsigned int hundreds;
char timeString[] = "00:00:00";
void setup() {
// Eingänge definieren:
pinMode(startPin, INPUT_PULLUP);
pinMode(stopPin, INPUT_PULLUP);
pinMode(resetPin, INPUT_PULLUP);
// Für Debugging:
// pinMode(13, OUTPUT);
// Serial.begin(9600);
// Variablen definieren bzw. auf Initial-Werte setzen:
timeRunning = 0;
startTime = 0;
currentTime = 0;
stoppedTime = 0;
bestTime = 3599990; // = 59:59:99 (MM:SS:HH)
// Anzeige vorbereiten:
lcd.begin(16,2); // initialize the lcd
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Jetzt:");
lcd.setCursor(0, 1);
lcd.print("Beste:");
updateTimes();
}
void loop() {
if(timeRunning == 1){
currentTime = millis() - startTime;
lcd.setCursor(8, 0);
showTime(currentTime);
}
if (digitalRead(startPin) == LOW) {
delay(debounce);
startTime = millis();
stoppedTime = 0;
currentTime = 0;
timeRunning = 1;
}
if (digitalRead(stopPin) == LOW) {
delay(debounce);
stoppedTime = millis() - startTime;
// Falls gestoppte Zeit kleiner als beste Zeit ODER falls beste Zeit = 0 (eben zurückgesetzt):
if(stoppedTime < bestTime || bestTime == 0){
bestTime = stoppedTime;
}
updateTimes();
timeRunning = 0;
}
if(digitalRead(resetPin) == LOW) {
stoppedTime = 0;
bestTime = 0;
updateTimes();
timeRunning = 0;
}
}
void updateTimes(){
lcd.setCursor(8, 0);
showTime(stoppedTime);
lcd.setCursor(8, 1);
showTime(bestTime);
}
void showTime(unsigned long timeMS){
// Minuten, Sekunden und Hundertstel berechnen:
minutes = timeMS/60000;
seconds = (timeMS-minutes*60000)/1000;
hundreds = (timeMS-minutes*60000-seconds*1000)/10;
// Werte im gewünschten Format in Array timeString schreiben:
sprintf(timeString,"%02d:%02d:%02d", minutes, seconds, hundreds);
// ...und ans LCD ausgeben:
lcd.print(timeString);
}
Speichere dein Programm Chronometer 2 unter neuem Name und erweitere es wie folgt:
Lösung
- ChronoMeter03.cpp
/* Chronometer gemäss Aufgabe 3:
* Start und Stop-Taste für Zeitmessung. Die gestoppte Zeit
* wird laufend und bei Betätigung der Stop-Taste angezeigt.
* Zusätzlich werden die besten fünf gemessenen Zeiten inkl. deren Rang angezeigt.
* Per Next-Taste kann durch die Zeiten "geblättert" werden.
* Die Zeiten bleiben bei ausgeschaltetem Arduino erhalten (im EEPROM gespeichert).
* Nur wenn die Reset-Taste betätigt wird, werden alle Zeiten zurückgesetzt.
*/
#include <EEPROM.h>
#include <SoftwareSerial.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
// create object of class LiquidCrytal_I22 and define parametes:
LiquidCrystal_I2C lcd(0x3F, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);
// Konstanten festlegen (für bessere Lesbarkeit des Codes):
#define startPin 5
#define stopPin 4
#define resetPin 3
#define nextPin 2
#define debounce 150 // Wartezeit zur "Entprellung" der Tasten (Millisekunden)
// Folgende Variable speichert den Status der Zeitmessung
bool timeRunning;
// Folgende Variablen speichern die Zeiten in Millisekunden:
unsigned long startTime;
unsigned long currentTime;
unsigned long stoppedTime;
unsigned long bestTimes[5]; // Array mit den besten fünf Zeiten
unsigned long tempTime; // Zwischenspeicher für den Wertetausch bei der Sortierung
// Folgende Variablen dienen der Anzeige im Format MM:SS:HH:
unsigned int minutes;
unsigned int seconds;
unsigned int hundreds;
char timeString[] = "00:00:00";
// Variable für den anzuzeigenden Rang:
uint8_t rank;
// Array für EEPROM-Adressen:
int addresses[5] = {0,3,6,9,12};
void setup() {
/*Für Debugging:
pinMode(13, OUTPUT);
Serial.begin(9600);*/
// Eingänge definieren:
pinMode(startPin, INPUT_PULLUP);
pinMode(stopPin, INPUT_PULLUP);
pinMode(resetPin, INPUT_PULLUP);
pinMode(nextPin, INPUT_PULLUP);
// Variablen definieren bzw. auf Initial-Werte setzen:
timeRunning = 0;
startTime = 0;
currentTime = 0;
stoppedTime = 0;
rank = 0;
// Beste fünf Zeiten aus EEPROM lesen:
readTimesEEP();
// Anzeige vorbereiten:
lcd.begin(16,2); // initialize the lcd
lcd.clear();
lcd.setCursor(0, 0);
lcd.print("Jetzt:");
lcd.setCursor(0, 1);
lcd.print("Rang :");
updateTimes();
}
void loop() {
if(timeRunning == 1){
currentTime = millis() - startTime;
lcd.setCursor(8, 0);
showTime(currentTime);
}
if (digitalRead(startPin) == LOW) {
delay(debounce);
startTime = millis();
stoppedTime = 0;
currentTime = 0;
timeRunning = 1;
}
if (digitalRead(stopPin) == LOW) {
delay(debounce);
stoppedTime = millis() - startTime;
// Falls gestoppte Zeit kleiner als fünft-beste Zeit ODER falls diese = 0:
if(stoppedTime < bestTimes[4] || bestTimes[4] == 0){
bestTimes[4] = stoppedTime;
sortTimes();
storeTimesEEP();
}
updateTimes();
timeRunning = 0;
}
if(digitalRead(resetPin) == LOW) {
delay(debounce);
stoppedTime = 0;
for(uint8_t i=0;i<5;i++){
bestTimes[i] = 0;
}
updateTimes();
storeTimesEEP();
timeRunning = 0;
}
if(digitalRead(nextPin) == LOW){
delay(debounce);
if(rank == 4){
rank = 0;
}
else{
rank +=1;
}
updateTimes();
}
}
void sortTimes(){
// Nullen im Array temporär durch hohe Zahlen ersetzen:
for(uint8_t i = 0; i<5;i++){
if(bestTimes[i] == 0){
bestTimes[i] = 4000000; // max. Wert zu stoppen = 3'599'999
}
}
// Bubblesort:
for(uint8_t n = 4; n>0; n--){
for(uint8_t i = 0; i<n;i++){
// Falls linker Wert höher als rechter ODER linker Wert = 0
if(bestTimes[i]>bestTimes[i+1]){
// ...beide Werte tauschen:
tempTime = bestTimes[i];
bestTimes[i] = bestTimes[i+1];
bestTimes[i+1] = tempTime;
}
}
}
// Hohe Zahlen im Array wieder durch Nullen ersetzen:
for(uint8_t i = 0; i<5;i++){
if(bestTimes[i] == 4000000){
bestTimes[i] = 0; // max. Wert zu stoppen = 3'599'999
}
}
}
void updateTimes(){
lcd.setCursor(8, 0);
showTime(stoppedTime);
lcd.setCursor(5,1);
lcd.print(rank+1);
lcd.setCursor(8, 1);
showTime(bestTimes[rank]);
}
void showTime(unsigned long timeMS){
// Minuten, Sekunden und Hundertstel berechnen:
minutes = timeMS/60000;
seconds = (timeMS-minutes*60000)/1000;
hundreds = (timeMS-minutes*60000-seconds*1000)/10;
// Werte im gewünschten Format in Array timeString schreiben:
sprintf(timeString,"%02d:%02d:%02d", minutes, seconds, hundreds);
// ...und ans LCD ausgeben:
lcd.print(timeString);
}
void storeTimesEEP(){
byte byte0; // byte0 = 0...255
byte byte1; // byte1 = 256...65'535
byte byte2; // byte2 = 65'536...16'777'215
for(uint8_t i=0;i<5;i++){
byte0 = (bestTimes[i] & 0x0000FF);
byte1 = (bestTimes[i] & 0x00FF00) >> 8;
byte2 = (bestTimes[i] & 0xFF0000) >> 16;
EEPROM.write(addresses[i],byte0);
EEPROM.write(addresses[i]+1,byte1);
EEPROM.write(addresses[i]+2,byte2);
}
}
void readTimesEEP(){
byte byte0; // byte0 = 0...255
byte byte1; // byte1 = 256...65'535
byte byte2; // byte2 = 65'536...16'777'215
for(uint8_t i=0;i<5;i++){
byte0 = EEPROM.read(addresses[i]);
byte1 = EEPROM.read(addresses[i]+1);
byte2 = EEPROM.read(addresses[i]+2);
bestTimes[i] = byte0 + (byte1 << 8) + (byte2 << 16);
}
}