Arduino Forum

International => Deutsch => Topic started by: -Micky on Jun 17, 2013, 01:23 pm

Title: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jun 17, 2013, 01:23 pm
Gibt es einen fertigen Code um den Fahrrad Computer durch einen Uno zu ersetzen? Kann diesbezüglich nichts finden.


Micky
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: jurs on Jun 17, 2013, 01:34 pm

Gibt es einen fertigen Code um den Fahrrad Computer durch einen Uno zu ersetzen? Kann diesbezüglich nichts finden.


Einen 4-Euro-Fahrradcomputer durch einen Arduino zu ersetzen klingt ein bischen danach, ein Stück Kaminholz durch ein Bündel 20-Euro-Scheine zu ersetzen.
;)

Klingt für mich irgendwie, als wenn es dafür nicht wirklich einen Bedarf gibt. Aber mal kurz gegoogelt, es scheint tatsächlich einige unentwegte zu geben:
http://www.instructables.com/id/Arduino-Bike-Speedometer/
Sieht ein bisschen klobiger als ein normaler Fahrradcomputer aus.
Und braucht häufiger mal einen Batteriewechsel als ein normaler Fahrradcomputer.
Sieht auch nicht so richtig wasserfest aus wie ein normaler Fahrradcomputer.

Aber sicher ein schönes Bastelobjekt, wenn man noch einen teuren, klobigen, batteriefressenden Schönwetter-Fahrradcomputer braucht.
;)
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jun 17, 2013, 01:51 pm
Geau das was ich suche.

Mir geht es um den Code. Ein Fahrradcomputer muß ja nicht zwangsweise am Fahrrad sein. Ich hab einen, statt Tacho, am Motorrad. Und wetterfest einbauen ist kein Problem.

Na ja, und Strom auch nicht.


Micky
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: jurs on Jun 17, 2013, 02:06 pm

Mir geht es um den Code. Ein Fahrradcomputer muß ja nicht zwangsweise am Fahrrad sein. Ich hab einen, statt Tacho, am Motorrad. Und wetterfest einbauen ist kein Problem.

Na ja, und Strom auch nicht.


Der Code ist bei der Instructables-Anleitung unter Step-11 abgedruckt.

Na dann viel Spaß beim TÜV mit Deinem aufgerüsteten Oldtimer!
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jun 17, 2013, 02:10 pm


Mir geht es um den Code. Ein Fahrradcomputer muß ja nicht zwangsweise am Fahrrad sein. Ich hab einen, statt Tacho, am Motorrad. Und wetterfest einbauen ist kein Problem.

Na ja, und Strom auch nicht.


Der Code ist bei der Instructables-Anleitung unter Step-11 abgedruckt.

Na dann viel Spaß beim TÜV mit Deinem aufgerüsteten Oldtimer!

Solange der Fahrrad Computer eine Beleuchtung hat die über das Bordnetz gespeist wird, ist das legitim. Ohne Beleuchtung aber nicht.

Danke für den Hinweis auf Step 11.

Was muß man denn ändern das der statt Inch und MPH Zentimeter und Km/h nimmt?


Micky
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: dlca on Jun 17, 2013, 02:28 pm
ohne den Quellcode jetzt angesehen zu haben, könntest du die Werte vorm Ausgeben einfach umrechnen.
Nach dem Motto:
lcd.Print(mph*1,60934);
Das wäre die einfachste Lösung. Ansonsten musst du halt die Bezugsgrößen im Quellcode ändern und die Berechnung
entsprechend anpassen.
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: jurs on Jun 17, 2013, 02:48 pm

Solange der Fahrrad Computer eine Beleuchtung hat die über das Bordnetz gespeist wird, ist das legitim. Ohne Beleuchtung aber nicht.


Ich kenne die genauen TÜV-Vorschriften nicht, aber wenn es Vorschrift ist, dass am Tacho die Beleuchtung automatisch angeht wenn die Beleuchtung am Fahrzeug eingeschaltet wird, mußt Du den Sketch etwas ändern. Denn die Anleitung sieht einen manuell betätigten Schalter zum Einschalten der Tachobeleuchtung vor. Oder Du läßt den Schalter weg und fährst dauernd mit beleuchtetem Tacho. Da die Hintergrundbedleuchtung fast aller LCD-Zeilen aus LEDs besteht, gibt es ja keine Gefahr durchgebrannter Glühlämpchen.


Was muß man denn ändern das der statt Inch und MPH Zentimeter und Km/h nimmt?


Man braucht eine andere Formel für km/h.

Ich habe ürbrigens gerade mal reingeschaut in den Code. Den Code kannst Du so leider nicht gebrauchen, da der nur bei fahrradtypischen Geschwindigkeiten funktioniert. So wie er da steht, funktioniert der Code bis 10 Radumdrehungen pro Sekunde. Bei einem Fahrrad mit Radumfang 2,20m wären das 22 m/s = 22*3,6= 79,2 km/h
Bei Motorrädern mit kleineren Rädern weniger.
Das reicht zwar für Fahrräder aus, aber nicht für Motorräder.

Man kann zwar das Limit hochsetzen durch Runtersetzen von
int maxReedCounter = 100;//min time (in ms) of one rotation (for debouncing)
auf z.B.
int maxReedCounter = 25;//min time (in ms) of one rotation (for debouncing)

Dann wäre man auf max. 40 Radumdrehungen pro Sekunde, bei 20" Radgröße = 160 cm Radumfang wären das
40*1,6 m//s = 64 m/s = 64*3,6 = 230 km/h
Reicht das als anzeigbare Höchstgeschwindigkeit?

Im Zweifelsfall kann man natürlich auch einen anderen Code programmieren.
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jun 17, 2013, 02:54 pm
Ja, ist dann mehr als ausreichend.

Danke schön für die Mühe.


Micky
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jun 23, 2013, 10:48 am
Habe folgenden Code:

Code: [Select]
// include the library code:
#define LCD_WIDTH 16                    //Anzahl Spalten des Display (16)
#define LCD_HEIGHT 2                    //Anzahl Zeilen des Display (2)

#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

int reedPin = 1;    //analog input, but could also be digital
int circleNum = 0;
float wheelDiameter = 18;
float wheelC = 3.14 * wheelDiameter;
float kilometers = 0;
float speedometer = 0;
float KPH = 0;
int reedTime;
int reedTimeDelta;
boolean reedOn = false;

void setup(){
  Serial.begin(9600);
  reedTime = millis();
}

void loop(){
 
  checkReed();
  getSpeed();
  }

void checkReed(){
  int r = analogRead(reedPin);
  if(r > 10 && reedOn == false){
    reedOn = true;
    reedTimeDelta = millis() - reedTime;
    reedTime = millis();
    circleNum++;
   
   //prints all metrics when magnet passes switch
    printAll();
  }
  else if (r < 10 && reedOn){
    reedOn = false;
  }
}

void getSpeed(){
  speedometer = wheelC/reedTimeDelta;
  //MPH = speedometer * 22.369;
  KPH = speedometer * 36;
}

void printAll(){
  lcd.begin(LCD_WIDTH, LCD_HEIGHT,2);
  lcd.setCursor(0, 0);
  lcd.print("Kilometer");
  lcd.setCursor(0, 1);
  lcd.print(KPH, 2);
}

Funktioniert auch, nur gehen die Kilometer nach Radstillstand nicht auf Null. Es wird die letzte Geschwindigkeit angezeigt. Was bitte kann man denn da machen?


Micky
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: ubetz on Jun 23, 2013, 11:18 am
Hallo Micky,

hab deinen Code kurz "quer gelesen" und was mir auffällt: Die Geschwindigkeit wird durch deine checkReed-Funktion nur berechnet und angezeigt, wenn ein Kontakt kommt: if (r>10)...
Bau doch noch sowas in der Art ein: if (millis()-reedTime > 3000)
Also "ist die letzten 3 Sekunden kein Signal gekommen?" Falls ja, kannst die Geschwindigkeit auf 0 setzen.

Nur so ein Vorschlag...

ulli.
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: jurs on Jun 23, 2013, 01:54 pm

Habe folgenden Code:
int r = analogRead(reedPin);


Einen schnell vorbeihuschenden Reedkontakt mit analogRead auszuwerten finde ich ja etwas abenteuerlich.

Ich habe Dir mal einen neuen Sketch gemacht, der stattdessen die Impulse vom Reedkontakt digital auswertet, mit Zählung in einer Interruptroutine. Die Aktualisierung erfolgt exakt einmal pro Sekunde, unabhängig von der Fahrgeschwindigkeit. Und auf 0 runter geht mein Sketch auch.

Der Sketch ist für ein Keypad-Shield, wie Du es offenbar auch verwendest.
Reedkontakt einfach direkt zwischen GND und digital Pin-2 anschließen.
(Nur die digitalen Pins 2 und 3 sind am Uno Interruptfähig und können mit meinem Sketch verwendet werden)

Die messbare Maximalgeschwindigkeit entspricht 40 Radumdrehungen pro Sekunde.

Teste mal, ich habe hier zwar ein LCD-Keypad Shield, aber keinen Reedkontakt zum Testen verfügbar.

Code: [Select]


//Anzahl Spalten des Display (16)
#define LCD_WIDTH 16

//Anzahl Zeilen des Display (2)
#define LCD_HEIGHT 2

// Pin für Reed-Kontakt, Digital-2 für Interrupt 0
#define REEDPIN 2

// Hardware-Interrupt für den Reed-Pin
#define REEDINTERRUPT 0

// Radumfang in mm
#define RADUMFANG 1540


#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);


void setup(){
  lcd.begin(LCD_WIDTH, LCD_HEIGHT);
  pinMode(REEDPIN, INPUT_PULLUP); // Reedkontakt direkt und ohne Widerstand angeschlossen 
  attachInterrupt(REEDINTERRUPT, reedISR, FALLING);
}

volatile byte reedCountSum;
volatile long reedMillisSum;

unsigned long lastReedMillis;

void reedISR()
{
  if (millis()-lastReedMillis>=25)  // 25ms entspricht max. 40 Radumdrehungen pro Sekunde
  {
    reedCountSum++;                 // eine Radumdrehung zählen
    reedMillisSum+=millis()-lastReedMillis;   // Zeit addieren
    lastReedMillis=millis();       // Zeit merken
  }
}

unsigned long gesamtUmdrehungen;

void tachoAnzeige()
{
  byte umdrehungen;
  unsigned long zeit;
  float kph, kilometer;
  char buffer[10];
  noInterrupts();            // Interrupts sperren
    umdrehungen=reedCountSum;// Zählvariable umkopieren
    reedCountSum=0;          // Zählvariable auf 0 zurücksetzen
    zeit=reedMillisSum;      // Zeitzähler umkopieren
    reedMillisSum=0;         // Zeitzähler auf 0 zurücksetzen
  interrupts();              // Interrupts wieder zulassen
  gesamtUmdrehungen+= umdrehungen; // Aufsummieren aller Radumdrehungen
  kilometer=(float)gesamtUmdrehungen*(float)RADUMFANG/1000000.0; // Fahrtkilometerzähler
  if (umdrehungen>0)
    kph=float(RADUMFANG)*(float)umdrehungen/(float)zeit*3.6;
  else
    kph=0.0; 
  lcd.setCursor(0, 0);
  dtostrf(kilometer,9,3,buffer);
  lcd.print(buffer);
  lcd.print(" km");
  lcd.setCursor(0, 1);
  lcd.print("KM/H ");
  dtostrf(kph,5,1,buffer);
  lcd.print(buffer);
}


unsigned long letzteSekunde=0;
void loop()
{
  unsigned long dieseSekunde=millis()/1000;
  // Tachoanzeige wird genau einmal pro Sekunde aktualisiert
  if (letzteSekunde != dieseSekunde)
  {
    tachoAnzeige();
    letzteSekunde=dieseSekunde;
  }
}


Zur besseren Kontrolle, ob auch alles stimmt, habe ich auch eine metergenaue Fahrtstreckenzählung seit dem letzten Reset eingebaut. Falls die Geschwindigkeitsanzeige fehlerhaft arbeitet, z.B. mögliches Kontaktprellen nicht ausreichend unterdrückt, würde man es daran erkennen, dass die gemessene Fahrtstrecke fehlerhaft ist. Ob eine gemessene Fahrtstrecke fehlerhaft gemessen wird, kann man leicht feststellen, indem man eine Strecke bekannter Länge abfährt und vergleicht.

Wenn der Tacho dann soweit OK läuft, könnte man noch die Anzeige verbessern. Und zwar kann man bei der Ausgabe von "nur Ziffern" die einfachen 1602 LCDs auch programmieren, "large digits", also große Zahlen über zwei Zeilen auszugeben. So wie hier im Youtube-Video zu sehen:
http://www.youtube.com/watch?v=0x3mUlYxfJA

Da könnte mann dann also eine Tachoanzeige machen, die nur die Geschwindigkeit in grossen Zahlen anzeigt und sonst nichts. Gross wegen der leichteren Ablesbarkeit bei möglicherweise vorhandenen Vibrationen.
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jun 23, 2013, 05:06 pm
Ganz lieben Dank für den Code und die Mühe die Du dir gemacht hast.

Der Code funktioniert. Erstmal nur am Schreibtisch getestet. Ich muß erst mal sehen wie ich das am Moped anbauen kann.

Die Idee mit den Großen Zahlen ist nicht schlecht. Ich hab das hier mit mal ausprobiert: http://forum.arduino.cc/index.php/topic,8790.0.html und die entsprechenden Codeteile in das Programm kopiert. Nur wenn ich dann die Anzeige in groß haben will, dann gibt es eine Fehlermeldung beim compilieren: Invalid conversion from "char*" to "byte"

Code: [Select]


//Anzahl Spalten des Display (16)
#define LCD_WIDTH 16

//Anzahl Zeilen des Display (2)
#define LCD_HEIGHT 2

// Pin für Reed-Kontakt, Digital-2 für Interrupt 0
#define REEDPIN 2

// Hardware-Interrupt für den Reed-Pin
#define REEDINTERRUPT 0

// Radumfang in mm
#define RADUMFANG 1540


#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// build 2-line digit font data array
// Digits are 3 characters wide.
byte bignums[10][2][3] = {
// Define which characters to use for each number. 255 is a solid block; 254 is a space  
// The format is { {TopLeft, TopMiddle, TopRight}, {BottomLeft, BottomMiddle, BottomRight} }
{ {255, 0, 255}, {255, 1, 255} },        // data to display "0"
{ {0, 255, 254}, {1, 255, 1} },          // data to display "1"
{ {2, 2, 255}, {255, 1, 1} },            // data to display "2"
{ {0, 2, 255}, {1, 1, 255} },            // data to display "3"
{ {255, 1, 255}, {254, 254, 255} },      // data to display "4"
{ {255, 2, 2}, {1, 1, 255} },            // data to display "5"
{ {255, 2, 2}, {255, 1, 255} },          // data to display "6"
{ {0, 0, 255}, {254, 255, 254} },        // data to display "7"
{ {255, 2, 255}, {255, 1, 255} },        // data to display "8"
{ {255, 2, 255}, {254, 254, 255} }       // data to display "9"
};

void setup(){
 
 // turn on DigitalPin 13 LED to signal that the custom characters have been loaded into the LCD  
 pinMode(13, OUTPUT);
 loadchars();
 digitalWrite(13, HIGH);
 
 lcd.begin(LCD_WIDTH, LCD_HEIGHT);
 pinMode(REEDPIN, INPUT_PULLUP); // Reedkontakt direkt und ohne Widerstand angeschlossen  
 attachInterrupt(REEDINTERRUPT, reedISR, FALLING);
}

volatile byte reedCountSum;
volatile long reedMillisSum;

unsigned long lastReedMillis;

void reedISR()
{
 if (millis()-lastReedMillis>=25)  // 25ms entspricht max. 40 Radumdrehungen pro Sekunde
 {
   reedCountSum++;                 // eine Radumdrehung zählen
   reedMillisSum+=millis()-lastReedMillis;   // Zeit addieren
   lastReedMillis=millis();       // Zeit merken
 }
}

unsigned long gesamtUmdrehungen;

void tachoAnzeige()
{
 byte umdrehungen;
 unsigned long zeit;
 float kph, kilometer;
 char buffer[10];
 noInterrupts();            // Interrupts sperren
   umdrehungen=reedCountSum;// Zählvariable umkopieren
   reedCountSum=0;          // Zählvariable auf 0 zurücksetzen
   zeit=reedMillisSum;      // Zeitzähler umkopieren
   reedMillisSum=0;         // Zeitzähler auf 0 zurücksetzen
 interrupts();              // Interrupts wieder zulassen
 gesamtUmdrehungen+= umdrehungen; // Aufsummieren aller Radumdrehungen
 kilometer=(float)gesamtUmdrehungen*(float)RADUMFANG/1000000.0; // Fahrtkilometerzähler
 if (umdrehungen>0)
   kph=float(RADUMFANG)*(float)umdrehungen/(float)zeit*3.6;
 else
   kph=0.0;  
 lcd.setCursor(0, 0);
 dtostrf(kilometer,9,3,buffer);
 lcd.print(buffer);
 lcd.print(" km");
 lcd.setCursor(0, 1);
 lcd.print("KM/H ");
 dtostrf(kph,5,1,buffer);
 printbigchar(buffer); //Zeile mit der Fehlermeldung
}


unsigned long letzteSekunde=0;
void loop()
{
 unsigned long dieseSekunde=millis()/1000;
 // Tachoanzeige wird genau einmal pro Sekunde aktualisiert
 if (letzteSekunde != dieseSekunde)
 {
   tachoAnzeige();
   letzteSekunde=dieseSekunde;
 }
}
void loadchars() {                        // This subroutine programs the custom character data into the LCD
 lcd.command(64);
// Custom character 0
 lcd.write(byte(B11111));
 lcd.write(byte(B11111));
 lcd.write(byte(B11111));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 
// Custom character 1
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B11111));
 lcd.write(byte(B11111));
 lcd.write(byte(B11111));
 
// Custom character 2
 lcd.write(byte(B11111));
 lcd.write(byte(B11111));
 lcd.write(byte(B11111));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B11111));
 lcd.write(byte(B11111));
 lcd.write(byte(B11111));
 
// Custom character 3
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B01110));
 lcd.write(byte(B01110));
 lcd.write(byte(B01110));
 
// Custom character 4
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B01110));
 lcd.write(byte(B01110));
 lcd.write(byte(B01110));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 
// Custom character 5
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 
// Custom character 6
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 
// Custom character 7
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));

 lcd.home();
}
void printbigchar(byte digit, byte col) { // This subroutine prints the big font characters on the LCD screen
if (digit > 9) return;                   // anything above 9 gets rejected
for (int i = 0; i < 2; i++) {            // count i from 0 to 1
  lcd.setCursor(col*4 , i);              // set LCD cursor at correct point
  for (int j = 0; j < 3; j++) {          // count j from 0 to 2
    lcd.write(bignums[digit][i][j]);     // write proper block to LCD from array
  }
  lcd.write(254);                        // write an empty space
}

lcd.setCursor(col + 4, 0);               // move the cursor to the top line, col + 4
}


Ich habe drangeschrieben welche Zeile gemeint ist.


Micky
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: michael_x on Jun 23, 2013, 06:16 pm
printbigchar(buffer);    gibts ja auch nicht.

Was du hast ist  void printbigchar(byte digit, byte col)

Da fehlt noch  die Funktion

Code: [Select]
void printbigchar(buffer) {
for (byte c = 0; c<4; c++)
  printbigchar(buffer[c], c);
}   


oder so ähnlich...
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: jurs on Jun 23, 2013, 07:39 pm

Nur wenn ich dann die Anzeige in groß haben will, dann gibt es eine Fehlermeldung beim compilieren: Invalid conversion from "char*" to "byte"


Korrigierter Code für einen "Big Digit Tacho" anbei.

Code: [Select]

//Anzahl Spalten des Display (16)
#define LCD_WIDTH 16

//Anzahl Zeilen des Display (2)
#define LCD_HEIGHT 2

// Pin für Reed-Kontakt, Digital-2 für Interrupt 0
#define REEDPIN 2

// Hardware-Interrupt für den Reed-Pin
#define REEDINTERRUPT 0

// Radumfang in mm
#define RADUMFANG 1540


#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// build 2-line digit font data array
// Digits are 3 characters wide.
byte bignums[10][2][3] = {
// Define which characters to use for each number. 255 is a solid block; 254 is a space 
// The format is { {TopLeft, TopMiddle, TopRight}, {BottomLeft, BottomMiddle, BottomRight} }
{ {255, 0, 255}, {255, 1, 255} },        // data to display "0"
{ {0, 255, 254}, {1, 255, 1} },          // data to display "1"
{ {2, 2, 255}, {255, 1, 1} },            // data to display "2"
{ {0, 2, 255}, {1, 1, 255} },            // data to display "3"
{ {255, 1, 255}, {254, 254, 255} },      // data to display "4"
{ {255, 2, 2}, {1, 1, 255} },            // data to display "5"
{ {255, 2, 2}, {255, 1, 255} },          // data to display "6"
{ {0, 0, 255}, {254, 255, 254} },        // data to display "7"
{ {255, 2, 255}, {255, 1, 255} },        // data to display "8"
{ {255, 2, 255}, {254, 254, 255} }       // data to display "9"
};

void loadchars() {                        // This subroutine programs the custom character data into the LCD
  lcd.command(64);
// Custom character 0
  lcd.write(byte(B11111));
  lcd.write(byte(B11111));
  lcd.write(byte(B11111));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
 
// Custom character 1
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B11111));
  lcd.write(byte(B11111));
  lcd.write(byte(B11111));
 
// Custom character 2
  lcd.write(byte(B11111));
  lcd.write(byte(B11111));
  lcd.write(byte(B11111));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B11111));
  lcd.write(byte(B11111));
  lcd.write(byte(B11111));
 
// Custom character 3
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B01110));
  lcd.write(byte(B01110));
  lcd.write(byte(B01110));
 
// Custom character 4
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B01110));
  lcd.write(byte(B01110));
  lcd.write(byte(B01110));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
 
// Custom character 5
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
 
// Custom character 6
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
 
// Custom character 7
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));

  lcd.home();
}

void printbigchar(byte digit, byte col) { // This subroutine prints the big font characters on the LCD screen
if (digit > 9) return;                   // reject anything above 9
for (int i = 0; i < 2; i++) {            // count i from 0 to 1
   lcd.setCursor(col*4 , i);              // set LCD cursor at correct point
   for (int j = 0; j < 3; j++) {          // count j from 0 to 2
     lcd.write(bignums[digit][i][j]);     // write proper block to LCD from array
   }
   lcd.write(254);                        // write an empty space
}
lcd.setCursor(col + 4, 0);               // move the cursor to the top line, col + 4
}


void setup(){
  pinMode(REEDPIN, INPUT_PULLUP); // Reedkontakt direkt und ohne Widerstand angeschlossen 
  lcd.begin(LCD_WIDTH, LCD_HEIGHT);
  loadchars();
  attachInterrupt(REEDINTERRUPT, reedISR, FALLING);
}

volatile byte reedCountSum;
volatile long reedMillisSum;

unsigned long lastReedMillis;

void reedISR()
{
  if (millis()-lastReedMillis>=25)  // 25ms entspricht max. 40 Radumdrehungen pro Sekunde
  {
    reedCountSum++;                 // eine Radumdrehung zählen
    reedMillisSum+=millis()-lastReedMillis;   // Zeit addieren
    lastReedMillis=millis();       // Zeit merken
  }
}

unsigned long gesamtUmdrehungen;

void tachoAnzeige()
{
  byte umdrehungen;
  unsigned long zeit;
  float kph, kilometer;
  int kphRounded;
  char buffer[10];
  noInterrupts();            // Interrupts sperren
    umdrehungen=reedCountSum;// Zählvariable umkopieren
    reedCountSum=0;          // Zählvariable auf 0 zurücksetzen
    zeit=reedMillisSum;      // Zeitzähler umkopieren
    reedMillisSum=0;         // Zeitzähler auf 0 zurücksetzen
  interrupts();              // Interrupts wieder zulassen
  gesamtUmdrehungen+= umdrehungen; // Aufsummieren aller Radumdrehungen
  kilometer=(float)gesamtUmdrehungen*(float)RADUMFANG/1000000.0; // Fahrtkilometerzähler
  if (umdrehungen>0)
    kph=float(RADUMFANG)*(float)umdrehungen/(float)zeit*3.6;
  else
    kph=0.0; 
  /* 
  lcd.setCursor(0, 0);
  dtostrf(kilometer,9,3,buffer);
  lcd.print(buffer);
  lcd.print(" km");
  lcd.setCursor(0, 1);
  lcd.print("KM/H ");
  dtostrf(kph,5,1,buffer);
  */
  kphRounded=int(kph+0.5); // auf ganze kph gerundet
  // Ausgabe kph in grossen Ziffern
  kphRounded = kphRounded % 1000;       // drop any digits above 999
  printbigchar(kphRounded / 100,0);     // print the speed hundreds
  kphRounded = kphRounded % 100;        // drop any digits above 99
  printbigchar(kphRounded/10,1);        // print the speed tens
  kphRounded = kphRounded % 10;         // drop any digits above 9
  printbigchar(kphRounded,2);           // print the speed ones
  lcd.setCursor(12, 1);
  lcd.print("km/h");
}


unsigned long letzteSekunde=0;
void loop()
{
  unsigned long dieseSekunde=millis()/1000;
  // Tachoanzeige wird genau einmal pro Sekunde aktualisiert
  if (letzteSekunde != dieseSekunde)
  {
    tachoAnzeige();
    letzteSekunde=dieseSekunde;
  }
}


Für die Ausgabe der Fahrkilometer ist in dem Fall ein bischen wenig Platz, denn Du hast ein 16x2 Display und wo Du den Code herhast wurde ein 20x2 Display verwendet. Aber wenn Du auf Nachkommastellen bei den Kilometern verzichtest, könnte man auch die gefahrenen Kilometer (seit Einschalten) noch mit ausgeben.
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jun 23, 2013, 07:50 pm
Wie machst Du das? Ich brech mir hier echt einen ab und die große Schrift funktioniert nicht. Danke!!!!!!!!!!!!!!!!!!!!!!!!!!!!

Das mit dem LCD Shield mache ich nur, weil ich momentan keinen I2C Adapter für ein Einzel Display mehr habe. Nehme ich gerne zum Testen.

Mal sehen was ich für ein Display nehme. Problem bei denen ist ja das ablesen bei Sonne.


Micky
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jun 23, 2013, 10:28 pm
Gut, habe die Gesamt Kilometeranzeige wieder sichtbar gemacht.

Code: [Select]
lcd.setCursor(12, 0);
  dtostrf(kilometer,3, 1, buffer);
  lcd.print(buffer);


Stimmt das so mit den 3,1,?


Micky
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: jurs on Jun 23, 2013, 11:09 pm

Code: [Select]
lcd.setCursor(12, 0);
  dtostrf(kilometer,3, 1, buffer);
  lcd.print(buffer);


Stimmt das so mit den 3,1,?


3 ist dann die von Dir gewählte Mindestbreite beim Formatieren, das würde nur für einstellige Kilometerzahlen mit einer Nachkommastelle reichen. Wenn die Zahlen größer werden, formatiert dtostrf automatisch längere Strings, Du mußt nur dafür sorgen, dass "buffer" dann auch breit genug ist.

Beim Kilometerzähler kannst Du es so machen, weil der Kilometerzähler nur vorwärts zählt und die Stellenanzahl daher nur zunehmen kann.

Aber bei der Geschwindigkeitsanzeige müßtest Du auf die tatsächliche maximale Breite formatieren, sonst gibt es beim langsamer werden merkwürdige Effekte.

Beispiel:
Code: [Select]

#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

void setup()
{
  lcd.begin(16,2);
}

void loop()
{
  char buffer[10];
  for (int i=80;i<120;i=i+3)
  {
    float kph=i/10.0;
    dtostrf(kph,3, 1, buffer);
    lcd.setCursor(0,0);
    lcd.print(buffer);
    delay(500);
  }
  for (int i=120;i>80;i=i-3)
  {
    float kph=i/10.0;
    dtostrf(kph,3, 1, buffer);
    lcd.setCursor(0,0);
    lcd.print(buffer);
    delay(500);
  }
}

Der Code zählt immer von 8.0 km/h bis 12.0 km/h hoch und wieder runter.

Beim Runterzählen wird beim Unterschreiten von 10.0 nur noch 3 Stellen breit formatiert, die letzte Stelle bleibt stehen und plötzlich werden zwei Nachkommastellen auf dem Display angezeigt, die letzte Stelle ist "eingefroren" (auf dem Wert, der zuletzt angezeigt wurde als die Anzeige eine Stelle länger war).

Wenn die Stellenzahl immer gleich bleiben und an gleicher Stelle auf einem Display erscheinen soll, müßtest Du immer auf gleiche Stellenzahl formatieren. D.h. zum Beispiel für eine maximal dreistellige Geschwindigkeit, Punkt und eine Nachkommastelle: 5 Stellen.
dtostrf(kph,5, 1, buffer);
Dann kannst Du hohe und niedrige Geschwindigkeiten auf dem Display an gleicher Stelle ausgeben und die Darstellung ist immer korrekt.

Wenn Du auf verschiedene Länge formatierst, müßtest Du stattdessen die tatsächliche Länge prüfen und ggf. übriggebliebene Zeichen auf dem Display gesondert löschen, z.B. durch Überschreiben mit Leerzeichen.

Zum Programmieren kannst Du übrigens nicht nur die auf der Arduino-Webseite beschriebenen Befehle benutzen, sondern die gesamte AVR-libc Library mit allen Funktionen. Die Referenz der Library findest Du hier:
http://www.nongnu.org/avr-libc/user-manual/modules.html

Mit Kurzbeschreibung der Funktion dtostrf unter: http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html#ga060c998e77fb5fc0d3168b3ce8771d42

Die Beschreibungen der Funktion sind in dieser Referenz immer sehr kurz gehalten, aber da es sich weitgehend um Standardfunktionen handelt, kannst Du Dir zu fast jeder Funktion andere Stellen im Internet ergoogeln, wo es ausführlichere Beschreibungen und Beispiele gibt.
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jun 24, 2013, 10:42 am
Dann muß das mit der Buffer Breite normalerweise stimmen, sonst spinnt die Sache.

Wie geht denn das mit den großen Zahlen? Ich wollte da gerne was ändern, nur weiß ich nicht so recht wie. Wieso sind einige Custom Charactere leer? Ich kann lediglich an den waagerechten Zahlen Elementen was ändern. Bei den senkrechten nicht.


Micky
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: jurs on Jun 24, 2013, 01:20 pm

Dann muß das mit der Buffer Breite normalerweise stimmen, sonst spinnt die Sache.


Ja, wenn sich die Stellenzahl ändern kann und ein Wert immer an gleicher Stelle ausgegeben werden soll, dann muß die Formatierung auf eine bestimmte Stellenzahl stimmen.

Gleitkommazahlen müssen unter Arduino einzeln mit "dtostrf" formatiert werden, wenn eine bestimmte Gesamtbreite gefordert ist.
Andere Werte (int, long, C-Strings etc.) lassen sich auch mit "sprintf" oder "snprintf" formatieren.


Wie geht denn das mit den großen Zahlen? Ich wollte da gerne was ändern, nur weiß ich nicht so recht wie. Wieso sind einige Custom Charactere leer? Ich kann lediglich an den waagerechten Zahlen Elementen was ändern. Bei den senkrechten nicht.


???
Leer sind die Custom Characters, die gar nicht verwendet werden.

Schau Dir mal die Definition der Big-Digits an:
Code: [Select]

byte bignums[10][2][3] = {
// Define which characters to use for each number. 255 is a solid block; 254 is a space 
// The format is { {TopLeft, TopMiddle, TopRight}, {BottomLeft, BottomMiddle, BottomRight} }
{ {255, 0, 255}, {255, 1, 255} },        // data to display "0"
{ {0, 255, 254}, {1, 255, 1} },          // data to display "1"
{ {2, 2, 255}, {255, 1, 1} },            // data to display "2"
{ {0, 2, 255}, {1, 1, 255} },            // data to display "3"
{ {255, 1, 255}, {254, 254, 255} },      // data to display "4"
{ {255, 2, 2}, {1, 1, 255} },            // data to display "5"
{ {255, 2, 2}, {255, 1, 255} },          // data to display "6"
{ {0, 0, 255}, {254, 255, 254} },        // data to display "7"
{ {255, 2, 255}, {255, 1, 255} },        // data to display "8"
{ {255, 2, 255}, {254, 254, 255} }       // data to display "9"
};


Es gibt 8 benutzerdefinierbare Zeichen, diese haben die Codes "0" bis "7" in der Zeichentabelle.
Im diesem Fall werden aber überhaupt in der bignums-Definition nur die benutzerdefinierbaren Zeichen "0", "1" und "2" in der Definition der grossen Zeichen verwendet. Der Rest wird aus den in der "normalen" Zeichentabelle bereits vorhandenen Zeichen mit den Codes 254 und 255 zusammengebastelt.

Wenn Du Deine Big-Digits aus anderen Mustern zusammensetzen möchtest, dann mußt Du
a) die Custom Characters entsprechend definieren
b) das "bignums" Array so umschreiben, dass die entsprechenden Zeichen an der gewünschten Stelle verwendet werden

Wenn Du beispielsweise irgendwo anstelle eines "254" oder eines "255" Zeichens ein anderes, selbstdefiniertes Zeichen haben möchtest, dann machst Du das selbstdefinierte Zeichen dort, wo jetzt ein nicht verwendetes Zeichen mit lauter Nullen drin steht, sagen wir mal "Custom character 5". Und wo dieses Zeichen verwendet werden soll, trägst Du im bignums-Array die 5 ein.
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jun 24, 2013, 09:00 pm
Hab es verstanden und die Zahlen etwas besser lesbar gemacht. Aber optimal ist das nicht. Besser wäre gleich ein Display mit größeren Ziffern.

Oder gleich ein Graikdisplay. Damit geht es dann viel einfacher größere Zahlen zu nehmen. Mal sehen.


Micky
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: jurs on Jun 24, 2013, 09:20 pm

Besser wäre gleich ein Display mit größeren Ziffern.


Vierzeilige Textdisplays existieren, damit kannst Du Dir Big Digits auch über 4 Zeilen Höhe zusammenbasteln:
http://www.phanderson.com/lcd106/lcd115_blue.jpg

Mit einer GPS-Tacho-App auf dem Smartphone, montiert am Lenker, ist der TÜV wohl nicht zufrieden, oder?
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jun 24, 2013, 09:32 pm

Vierzeilige Textdisplays existieren, damit kannst Du Dir Big Digits auch über 4 Zeilen Höhe zusammenbasteln:
http://www.phanderson.com/lcd106/lcd115_blue.jpg

Mit einer GPS-Tacho-App auf dem Smartphone, montiert am Lenker, ist der TÜV wohl nicht zufrieden, oder?
Ja klar kann man das auch über 4 Zeilen machen. Nur finde ich das man viel zu eckige Zahlen erhält. Man kann ja nur 8 Zeichen neu definieren.

Müßte eigentlich durchgehen mit dem Smartphone. Find ich aber nicht so doll, ich möchte nichts außer Km/H und Kilometer angezeigt bekommen.

Vielleicht doch eine 7-Segmentanzeige nehmen. Obwohl, da ist ja auch wieder alles eckig. Ich probiere das mal mit meinem grafischem Display wie das aussieht.


Micky
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jun 24, 2013, 09:47 pm
Hier die geänderte Version:

Code: [Select]
//Anzahl Spalten des Display (16)
#define LCD_WIDTH 16

//Anzahl Zeilen des Display (2)
#define LCD_HEIGHT 2

// Pin für Reed-Kontakt, Digital-2 für Interrupt 0
#define REEDPIN 2

// Hardware-Interrupt für den Reed-Pin
#define REEDINTERRUPT 0

// Radumfang in mm
#define RADUMFANG 2260


#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// build 2-line digit font data array
// Digits are 3 characters wide.
byte bignums[10][2][3] = {
// Define which characters to use for each number. 255 is a solid block; 254 is a space 
// The format is { {TopLeft, TopMiddle, TopRight}, {BottomLeft, BottomMiddle, BottomRight} }
{ {255, 0, 255}, {255, 1, 255} },        // data to display "0"
{ {0, 255, 254}, {1, 255, 1} },          // data to display "1"
{ {0, 5, 255}, {255, 1, 1} },            // data to display "2"
{ {0, 5, 255}, {1, 1, 255} },            // data to display "3"
{ {255, 1, 255}, {254, 254, 255} },      // data to display "4"
{ {255, 5, 5}, {1, 1, 255} },            // data to display "5"
{ {255, 5, 5}, {255, 1, 255} },          // data to display "6"
{ {0, 0, 255}, {254, 255, 254} },        // data to display "7"
{ {255, 5, 255}, {255, 1, 255} },        // data to display "8"
{ {255, 5, 255}, {254, 254, 255} }       // data to display "9"
};

void loadchars() {                        // This subroutine programs the custom character data into the LCD
  lcd.command(64);
// Custom character 0
  lcd.write(byte(B11111));
  lcd.write(byte(B11111));
  lcd.write(byte(B11111));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
 
// Custom character 1
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B11111));
  lcd.write(byte(B11111));
  lcd.write(byte(B11111));
 
// Custom character 2
  lcd.write(byte(B11111));
  lcd.write(byte(B11111));
  lcd.write(byte(B11111));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B11111));
  lcd.write(byte(B11111));
  lcd.write(byte(B11111));
 
// Custom character 3
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B01110));
  lcd.write(byte(B01110));
  lcd.write(byte(B01110));
 
// Custom character 4
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B01110));
  lcd.write(byte(B01110));
  lcd.write(byte(B01110));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
 
// Custom character 5
  lcd.write(byte(B11111));
  lcd.write(byte(B11111));
  lcd.write(byte(B11111));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B11111));
  lcd.write(byte(B11111));
 
// Custom character 6
  lcd.write(byte(B11111));
  lcd.write(byte(B11111));
  lcd.write(byte(B11111));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B11110));
  lcd.write(byte(B11111));
 
// Custom character 7
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));
  lcd.write(byte(B00000));

  lcd.home();
}

void printbigchar(byte digit, byte col) { // This subroutine prints the big font characters on the LCD screen
if (digit > 9) return;                   // reject anything above 9
for (int i = 0; i < 2; i++) {            // count i from 0 to 1
   lcd.setCursor(col*4 , i);              // set LCD cursor at correct point
   for (int j = 0; j < 3; j++) {          // count j from 0 to 2
     lcd.write(bignums[digit][i][j]);     // write proper block to LCD from array
   }
   lcd.write(254);                        // write an empty space
}
lcd.setCursor(col + 4, 0);               // move the cursor to the top line, col + 4
}


void setup(){
  pinMode(REEDPIN, INPUT_PULLUP); // Reedkontakt direkt und ohne Widerstand angeschlossen 
  lcd.begin(LCD_WIDTH, LCD_HEIGHT);
  loadchars();
  attachInterrupt(REEDINTERRUPT, reedISR, FALLING);
}

volatile byte reedCountSum;
volatile long reedMillisSum;

unsigned long lastReedMillis;

void reedISR()
{
  if (millis()-lastReedMillis>=25)  // 25ms entspricht max. 40 Radumdrehungen pro Sekunde
  {
    reedCountSum++;                 // eine Radumdrehung zählen
    reedMillisSum+=millis()-lastReedMillis;   // Zeit addieren
    lastReedMillis=millis();       // Zeit merken
  }
}

unsigned long gesamtUmdrehungen;

void tachoAnzeige()
{
  byte umdrehungen;
  unsigned long zeit;
  float kph, kilometer;
  int kphRounded;
  char buffer[10];
  noInterrupts();            // Interrupts sperren
    umdrehungen=reedCountSum;// Zählvariable umkopieren
    reedCountSum=0;          // Zählvariable auf 0 zurücksetzen
    zeit=reedMillisSum;      // Zeitzähler umkopieren
    reedMillisSum=0;         // Zeitzähler auf 0 zurücksetzen
  interrupts();              // Interrupts wieder zulassen
  gesamtUmdrehungen+= umdrehungen; // Aufsummieren aller Radumdrehungen
  kilometer=(float)gesamtUmdrehungen*(float)RADUMFANG/1000000.0; // Fahrtkilometerzähler
  if (umdrehungen>0)
    kph=float(RADUMFANG)*(float)umdrehungen/(float)zeit*3.6;
  else
    kph=0.0; 
 
  lcd.setCursor(12, 0);
  dtostrf(kilometer,3, 1, buffer);
  lcd.print(buffer);
  /* 
  lcd.setCursor(0, 0);
  dtostrf(kilometer,9,3,buffer);
  lcd.print(buffer);
  lcd.print(" km");
  lcd.setCursor(0, 1);
  lcd.print("KM/H ");
  dtostrf(kph,5,1,buffer);
  */
  kphRounded=int(kph+0.5); // auf ganze kph gerundet
  // Ausgabe kph in grossen Ziffern
  kphRounded = kphRounded % 1000;       // drop any digits above 999
  printbigchar(kphRounded / 100,0);     // print the speed hundreds
  kphRounded = kphRounded % 100;        // drop any digits above 99
  printbigchar(kphRounded/10,1);        // print the speed tens
  kphRounded = kphRounded % 10;         // drop any digits above 9
  printbigchar(kphRounded,2);           // print the speed ones
  lcd.setCursor(12, 1);
  lcd.print("km/h");
}


unsigned long letzteSekunde=0;
void loop()
{
  unsigned long dieseSekunde=millis()/1000;
  // Tachoanzeige wird genau einmal pro Sekunde aktualisiert
  if (letzteSekunde != dieseSekunde)
  {
    tachoAnzeige();
    letzteSekunde=dieseSekunde;
  }
}



Micky
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: jurs on Jun 24, 2013, 11:27 pm

Nur finde ich das man viel zu eckige Zahlen erhält. Man kann ja nur 8 Zeichen neu definieren.


Ja klar, irgendwo ist Schluss mit den Textdisplay-Tricksereien.

Anbei nochmal eine Version mit großen "abgerundeten" Ziffern.

Code: [Select]

//Anzahl Spalten des Display (16)
#define LCD_WIDTH 16

//Anzahl Zeilen des Display (2)
#define LCD_HEIGHT 2

// Pin für Reed-Kontakt, Digital-2 für Interrupt 0
#define REEDPIN 2

// Hardware-Interrupt für den Reed-Pin
#define REEDINTERRUPT 0

// Radumfang in mm
#define RADUMFANG 2260


#include <LiquidCrystal.h>
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);


void loadchars() {                        // This subroutine programs the custom character data into the LCD
// the 8 arrays that form each segment of the custom numbers
byte LT[8] =
{
  B00111,
  B01111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111
};
byte UB[8] =
{
  B11111,
  B11111,
  B11111,
  B00000,
  B00000,
  B00000,
  B00000,
  B00000
};
byte RT[8] =
{
  B11100,
  B11110,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111
};
byte LL[8] =
{
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B01111,
  B00111
};
byte LB[8] =
{
  B00000,
  B00000,
  B00000,
  B00000,
  B00000,
  B11111,
  B11111,
  B11111
};
byte LR[8] =
{
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11110,
  B11100
};
byte MB[8] =
{
  B11111,
  B11111,
  B11111,
  B00000,
  B00000,
  B00000,
  B11111,
  B11111
};
byte block[8] =
{
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111,
  B11111
};
// assignes each segment a write number
  lcd.createChar(0,LT);
  lcd.createChar(1,UB);
  lcd.createChar(2,RT);
  lcd.createChar(3,LL);
  lcd.createChar(4,LB);
  lcd.createChar(5,LR);
  lcd.createChar(6,MB);
  lcd.createChar(7,block);
}

byte bignums[10][2][3] = {
// Define which characters to use for each number. 255 is a solid block; 254 is a space 
// The format is { {TopLeft, TopMiddle, TopRight}, {BottomLeft, BottomMiddle, BottomRight} }
{ {0, 1, 2},   {3, 4, 5} },        // data to display "0"
{ {1, 2, 254}, {4, 7, 4} },          // data to display "1"
{ {6, 6, 2},   {3, 4, 4} },            // data to display "2"
{ {6, 6, 2},   {4, 4, 5} },            // data to display "3"
{ {3, 4, 7},   {254, 254, 7} },      // data to display "4"
{ {3, 6, 6},   {4, 4, 5} },            // data to display "5"
{ {0, 6, 6},   {3, 4, 5} },          // data to display "6"
{ {1, 1, 2},   {254, 254, 7} },        // data to display "7"
{ {0, 6, 2},   {3, 4, 5} },        // data to display "8"
{ {0, 6, 2},   {254, 254, 7} }       // data to display "9"
};

void printbigchar(byte digit, byte col) { // This subroutine prints the big font characters on the LCD screen
if (digit > 9) return;                   // reject anything above 9
for (int i = 0; i < 2; i++) {            // count i from 0 to 1
   lcd.setCursor(col*4 , i);              // set LCD cursor at correct point
   for (int j = 0; j < 3; j++) {          // count j from 0 to 2
     lcd.write(bignums[digit][i][j]);     // write proper block to LCD from array
   }
   lcd.write(254);                        // write an empty space
}
lcd.setCursor(col + 4, 0);               // move the cursor to the top line, col + 4
}


void setup(){
  pinMode(REEDPIN, INPUT_PULLUP); // Reedkontakt direkt und ohne Widerstand angeschlossen 
  lcd.begin(LCD_WIDTH, LCD_HEIGHT);
  loadchars();
  attachInterrupt(REEDINTERRUPT, reedISR, FALLING);
}

volatile byte reedCountSum;
volatile long reedMillisSum;

unsigned long lastReedMillis;

void reedISR()
{
  if (millis()-lastReedMillis>=25)  // 25ms entspricht max. 40 Radumdrehungen pro Sekunde
  {
    reedCountSum++;                 // eine Radumdrehung zählen
    reedMillisSum+=millis()-lastReedMillis;   // Zeit addieren
    lastReedMillis=millis();       // Zeit merken
  }
}

unsigned long gesamtUmdrehungen;

void tachoAnzeige()
{
  byte umdrehungen;
  unsigned long zeit;
  float kph, kilometer;
  int kphRounded;
  char buffer[10];
  noInterrupts();            // Interrupts sperren
    umdrehungen=reedCountSum;// Zählvariable umkopieren
    reedCountSum=0;          // Zählvariable auf 0 zurücksetzen
    zeit=reedMillisSum;      // Zeitzähler umkopieren
    reedMillisSum=0;         // Zeitzähler auf 0 zurücksetzen
  interrupts();              // Interrupts wieder zulassen
  gesamtUmdrehungen+= umdrehungen; // Aufsummieren aller Radumdrehungen
  kilometer=(float)gesamtUmdrehungen*(float)RADUMFANG/1000000.0; // Fahrtkilometerzähler
  if (umdrehungen>0)
    kph=float(RADUMFANG)*(float)umdrehungen/(float)zeit*3.6;
  else
    kph=0.0; 
 
  lcd.setCursor(12, 0);
  dtostrf(kilometer,3, 1, buffer);
  lcd.print(buffer);
  /* 
  lcd.setCursor(0, 0);
  dtostrf(kilometer,9,3,buffer);
  lcd.print(buffer);
  lcd.print(" km");
  lcd.setCursor(0, 1);
  lcd.print("KM/H ");
  dtostrf(kph,5,1,buffer);
  */
  kphRounded=int(kph+0.5); // auf ganze kph gerundet
  // Ausgabe kph in grossen Ziffern
//  kphRounded=random(999);  // nur zum Testen
   
  kphRounded = kphRounded % 1000;       // drop any digits above 999
  printbigchar(kphRounded / 100,0);     // print the speed hundreds
  kphRounded = kphRounded % 100;        // drop any digits above 99
  printbigchar(kphRounded/10,1);        // print the speed tens
  kphRounded = kphRounded % 10;         // drop any digits above 9
  printbigchar(kphRounded,2);           // print the speed ones
  lcd.setCursor(12, 1);
  lcd.print("km/h");
}


unsigned long letzteSekunde=0;
void loop()
{
  unsigned long dieseSekunde=millis()/1000;
  // Tachoanzeige wird genau einmal pro Sekunde aktualisiert
  if (letzteSekunde != dieseSekunde)
  {
    tachoAnzeige();
    letzteSekunde=dieseSekunde;
  }
}

Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jun 26, 2013, 02:03 pm
Sieht auch nicht schlecht aus, finde aber die Lesbarkeit nicht so gut.


Micky
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jun 28, 2013, 10:42 pm
Habe jetzt mal ein GLCD angeschlossen und den Code entsprechend umgestrickt. Sind die, im Gegensatz zu Textdisplays so langsam, das Reste von den vorherigen Zahlen stehen bleiben?


Mickxy
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: jurs on Jun 28, 2013, 10:58 pm

Sind die, im Gegensatz zu Textdisplays so langsam, das Reste von den vorherigen Zahlen stehen bleiben?


Um beispielsweise 32*32 Pixel in 3 RGB Werten auszugeben sind natürlich sehr viel mehr Daten zu übertragen als wenn nur ein einziges Byte geändert werden muß.

Das hat aber nichts mit übrigbleibenden Resten der vorherigen Zahlen zu tun.
Der Effekt hängt eher damit zusammen, dass Du möglicherweise erstmal den Bereich, auf dem ein neuer Text erscheinen soll, löschen bzw. mit der Hintergrundfarbe übermalen mußt, bevor Du neue Pixel darauf ausgeben kannst. Es kann auch sein, dass es für die Textausgabefunktion einen Parameter gibt oder eine Funktion mit etwas anderem Namen, die gleichzeitig mit der Textausgabe auch den Hintergrund neu ausmalt.

Die Library-Dokumentation oder der Quellcode sollte darüber Auskunft geben.
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jun 28, 2013, 11:50 pm
Danke für die Hinweise. GLCD.println(buffer); statt GLCD.print(buffer); funktioniert.


Micky
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jun 29, 2013, 01:01 pm
Das Display stellt schnelle Werte zu langsam da. Ist nicht dafür geeignet.


Micky
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jun 29, 2013, 01:57 pm
Wie kann man eigentlich die Anzeige der Kilometer so machen, das die Werte immer an der gleichen Stelle dargestellt werden?


Micky?
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: jurs on Jun 29, 2013, 02:19 pm

Wie kann man eigentlich die Anzeige der Kilometer so machen, das die Werte immer an der gleichen Stelle dargestellt werden?


Im Normalfall macht man das, indem man auf eine feste Stellenzahl formatiert.

Beispiel: Der Kilometerzähler soll bis 99999 km auf ganze km ohne Nachkommastellen angezeigt werden, dann formatierst Du den Kilometerstand auf einen String mit 5 Zeichen Breite, keine Nachkommastellen, und wenn Du den String immer an derselben Position ausgibst, erscheinen die Einerstellen immer ganz rechts, die Zehnerstellen als zweite Stelle von rechts usw. und das ganz unabhängig davon, ob der Kilometerstand ein-, zwei-, drei-, vier-, oder fünfstellig ist.
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jun 29, 2013, 11:24 pm
Nun hab ich es auch verstanden. 12345,67 muß dann heißen: 8,2,buffer.

Oder 123,456: 7,3 buffer.

Die Zahl vor dem Komma dient als Platzhalter für zu erwartende Zahlen und die hinter dem Komma für die Nachkommastellen. In Nullstellung wird aber nur die Null vor dem Komma aber alle Nullen nach dem Komma angezeigt.

Ich hoffe das stimmt jetzt so.


Micky
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: jurs on Jun 29, 2013, 11:35 pm

Nun hab ich es auch verstanden. 12345,67 muß dann heißen: 8,2,buffer.


Ja, das sind 8 Zeichen gesamt, 2 Stellen nach dem Dezimalpunkt.


Oder 123,456: 7,3 buffer.


Ja, das sind 7 Zeichen gesamt, 3 Stellen nach dem Dezimalpunkt.

Übrigens: Das Array zur Aufnahme der Zeichen muss immer (Minimum!) um eins länger sein, also 9 bzw 8 für eine Formatierung auf 8 und 7 Stellen: C-Strings werden intern nämlich immer mit einem abschließenden Nullzeichen gespeichert. Wenn der Puffer aus Versehen zu klein ist und Du formatierst über das Pufferende hinaus, können im Programm sehr schwierig zu entdeckende Fehler in anderen Programmstellen auftreten.
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jul 20, 2013, 02:41 pm
Hier mal was zum aktuellen Stand. Ist aber noch nicht ganz fertig. Ein Bild zeigt die Steuereinheit und das andere das Display.


Micky
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jul 30, 2013, 01:20 pm
Wie bekomme ich die große Schrift auf einem 8x2 Display unter? Paßt natürlich so nicht. Und ich weiß nicht wo ich den Code so abändern kann das nur drei Zahlen dargestellt werden.


Micky
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: jurs on Jul 30, 2013, 02:38 pm

Wie bekomme ich die große Schrift auf einem 8x2 Display unter? Paßt natürlich so nicht. Und ich weiß nicht wo ich den Code so abändern kann das nur drei Zahlen dargestellt werden.


Das ist jetzt aber die Wärme, oder?

Du brauchst nur die Display-Initialisierung auf das 8x2 Display anpassen und dann mußt Du eben die Ausgabe so kurz halten, dass nicht hinter das achte Zeichen geschrieben wird. Z.B. eine Anzeige nur mit dreistelliger Geschwindigkeit, ohne Nachkommastellen, linksbündig:
Code: [Select]

void tachoAnzeige()
{
  byte umdrehungen;
  unsigned long zeit;
  float kph, kilometer;
  int kphRounded;
  char buffer[10];
  noInterrupts();            // Interrupts sperren
    umdrehungen=reedCountSum;// Zählvariable umkopieren
    reedCountSum=0;          // Zählvariable auf 0 zurücksetzen
    zeit=reedMillisSum;      // Zeitzähler umkopieren
    reedMillisSum=0;         // Zeitzähler auf 0 zurücksetzen
  interrupts();              // Interrupts wieder zulassen
  if (umdrehungen>0)
    kph=float(RADUMFANG)*(float)umdrehungen/(float)zeit*3.6;
  else
    kph=0.0; 
  kphRounded=int(kph+0.5); // auf ganze kph gerundet
   
  kphRounded = kphRounded % 1000;       // drop any digits above 999
  printbigchar(kphRounded / 100,0);     // print the speed hundreds
  kphRounded = kphRounded % 100;        // drop any digits above 99
  printbigchar(kphRounded/10,1);        // print the speed tens
  kphRounded = kphRounded % 10;         // drop any digits above 9
  printbigchar(kphRounded,2);           // print the speed ones
}
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jul 30, 2013, 10:52 pm
Nee, daran liegt es nicht. Ich hab schon alles mögliche versucht. Ich kriege zwar eine zweistellige Anzeige hin, nur brauche ich aber eine dreistellige. Was geholfen hat ist statt long short zu nehmen.

Ich weiß nicht wo man die Nachkommastellen angibt. Bei diesem hier wäre das klar:

Code: [Select]
lcd.setCursor(0, 0);
 dtostrf(kilometer,9,3,buffer);
 lcd.print(buffer);
 lcd.print(" km");
 lcd.setCursor(0, 1);
 lcd.print("KM/H ");
 dtostrf(kph,5,1,buffer);


nicht aber bei dem von Dir genommenen Code. Hier ist der Code wie ich ihn eben nehme:

Code: [Select]
//Anzahl Spalten des Display (8)
//#define LCD_WIDTH 8

//Anzahl Zeilen des Display (2)
//#define LCD_HEIGHT 2

// Pin für Reed-Kontakt, Digital-2 für Interrupt 0
#define REEDPIN 2

// Hardware-Interrupt für den Reed-Pin
#define REEDINTERRUPT 0

// Radumfang in mm
#define RADUMFANG 1540


//#include <LiquidCrystal.h>
//LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

#include <LiquidCrystal_I2C.h> // Für I2C LCD Display
#include <Wire.h>
LiquidCrystal_I2C lcd(0x27,8,2);  // I2C LCD Adresse auf 0x20 gesetzt, 16 Zeichen / 2 Zeilen LCD


// build 2-line digit font data array
// Digits are 3 characters wide.
byte bignums[10][2][3] = {
// Define which characters to use for each number. 255 is a solid block; 254 is a space  
// The format is { {TopLeft, TopMiddle, TopRight}, {BottomLeft, BottomMiddle, BottomRight} }
{ {255, 0, 255}, {255, 1, 255} },        // data to display "0"
{ {0, 255, 254}, {1, 255, 1} },          // data to display "1"
{ {2, 2, 255}, {255, 1, 1} },            // data to display "2"
{ {0, 2, 255}, {1, 1, 255} },            // data to display "3"
{ {255, 1, 255}, {254, 254, 255} },      // data to display "4"
{ {255, 2, 2}, {1, 1, 255} },            // data to display "5"
{ {255, 2, 2}, {255, 1, 255} },          // data to display "6"
{ {0, 0, 255}, {254, 255, 254} },        // data to display "7"
{ {255, 2, 255}, {255, 1, 255} },        // data to display "8"
{ {255, 2, 255}, {254, 254, 255} }       // data to display "9"
};

void loadchars() {                        // This subroutine programs the custom character data into the LCD
 lcd.command(64);
// Custom character 0
 lcd.write(byte(B11111));
 lcd.write(byte(B11111));
 lcd.write(byte(B11111));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 
// Custom character 1
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B11111));
 lcd.write(byte(B11111));
 lcd.write(byte(B11111));
 
// Custom character 2
 lcd.write(byte(B11111));
 lcd.write(byte(B11111));
 lcd.write(byte(B11111));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B11111));
 lcd.write(byte(B11111));
 lcd.write(byte(B11111));
 
// Custom character 3
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B01110));
 lcd.write(byte(B01110));
 lcd.write(byte(B01110));
 
// Custom character 4
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B01110));
 lcd.write(byte(B01110));
 lcd.write(byte(B01110));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 
// Custom character 5
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 
// Custom character 6
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 
// Custom character 7
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));
 lcd.write(byte(B00000));

 lcd.home();
}

void printbigchar(byte digit, byte col) { // This subroutine prints the big font characters on the LCD screen
if (digit > 9) return;                   // reject anything above 9
for (int i = 0; i < 2; i++) {            // count i from 0 to 1
  lcd.setCursor(col*4 , i);              // set LCD cursor at correct point
  for (int j = 0; j < 3; j++) {          // count j from 0 to 2
    lcd.write(bignums[digit][i][j]);     // write proper block to LCD from array
  }
  lcd.write(254);                        // write an empty space
}
lcd.setCursor(col + 4, 0);               // move the cursor to the top line, col + 4
}


void setup(){
 
 // LCD I2C Initilaisieren und Hintergrundbeleuchtung aktivieren
  lcd.init();
  lcd.backlight();    
 
  lcd.init();                                        // LCD-Anzeige initialisieren
  lcd.clear();
 
 pinMode(REEDPIN, INPUT_PULLUP); // Reedkontakt direkt und ohne Widerstand angeschlossen  
 //lcd.begin(LCD_WIDTH, LCD_HEIGHT);
 loadchars();
 attachInterrupt(REEDINTERRUPT, reedISR, FALLING);
}

volatile byte reedCountSum;
volatile short reedMillisSum;

unsigned short lastReedMillis;

void reedISR()
{
 if (millis()-lastReedMillis>=25)  // 25ms entspricht max. 40 Radumdrehungen pro Sekunde
 {
   reedCountSum++;                 // eine Radumdrehung zählen
   reedMillisSum+=millis()-lastReedMillis;   // Zeit addieren
   lastReedMillis=millis();       // Zeit merken
 }
}

unsigned short gesamtUmdrehungen;

void tachoAnzeige()
{
 byte umdrehungen;
 unsigned short zeit;
 float kph, kilometer;
 int kphRounded;
 char buffer[10];
 noInterrupts();            // Interrupts sperren
   umdrehungen=reedCountSum;// Zählvariable umkopieren
   reedCountSum=0;          // Zählvariable auf 0 zurücksetzen
   zeit=reedMillisSum;      // Zeitzähler umkopieren
   reedMillisSum=0;         // Zeitzähler auf 0 zurücksetzen
 interrupts();              // Interrupts wieder zulassen
 gesamtUmdrehungen+= umdrehungen; // Aufsummieren aller Radumdrehungen
 kilometer=(float)gesamtUmdrehungen*(float)RADUMFANG/1000000.0; // Fahrtkilometerzähler
 if (umdrehungen>0)
   kph=float(RADUMFANG)*(float)umdrehungen/(float)zeit*3.6;
 else
   kph=0.0;  
 /*  
 lcd.setCursor(0, 0);
 dtostrf(kilometer,9,3,buffer);
 lcd.print(buffer);
 lcd.print(" km");
 lcd.setCursor(0, 1);
 lcd.print("KM/H ");
 dtostrf(kph,5,1,buffer);
 */
 kphRounded=int(kph+0.5); // auf ganze kph gerundet
 // Ausgabe kph in grossen Ziffern
 
 kphRounded = kphRounded % 1000;       // drop any digits above 999
 printbigchar(kphRounded / 100,0);     // print the speed hundreds
 kphRounded = kphRounded % 100;        // drop any digits above 99
 printbigchar(kphRounded/10,1);        // print the speed tens
 kphRounded = kphRounded % 10;         // drop any digits above 9
 printbigchar(kphRounded,2);           // print the speed ones
 //lcd.setCursor(12, 1);
 //lcd.print("km/h");
}


unsigned short letzteSekunde=0;
void loop()
{
 unsigned short dieseSekunde=millis()/1000;
 // Tachoanzeige wird genau einmal pro Sekunde aktualisiert
 if (letzteSekunde != dieseSekunde)
 {
   tachoAnzeige();
   letzteSekunde=dieseSekunde;
 }
}


Das entscheidene ist ja wohl der Teil den Du hier vorhin reingesetzt hast. Nur wo bitte muß ich da was ändern?

Hinzu kommt noch das die Anzeige nun viel zu träge reagiert.


Micky

Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: jurs on Jul 31, 2013, 10:53 am

Nee, daran liegt es nicht. Ich hab schon alles mögliche versucht. Ich kriege zwar eine zweistellige Anzeige hin, nur brauche ich aber eine dreistellige.


Dann nimm wieder das 16x2 Display, ein 8x2 Display ist dafür zu klein!

Für eine Anzeige großer Ziffern mit "printbigchar" brauchst Du immer 3 Zeichen Breite, das macht bei dreistelliger Anzeige:
printbigchar 3 Zeichen + 1 Zeichen Abstand + printbigchar 3 Zeichen + 1 Zeichen Abstand + printbigchar 3 Zeichen
= 11 Zeichen insgesamt
Da ist ein Display mit 8 Zeichen insgesamt zu wenig.

Selbst wenn Du sagst, Geschwindigkeiten unter 200 km/h reichen aus und Du würdest als 1 einen einfachen Strich von 1 Zeichen Breite nehmen, passt es immer noch nicht. Dann brauchst die dargestellte Ziffer "1" per printbigchar zwar 2 Zeichen weniger, macht also 9 statt 11 Zeichen insgesamt, aber 9 ist immer noch eins zuviel für ein Display mit 8 Zeichen in einer Zeile.
Title: Re: Ersatz Fahrrad Computer durch Uno
Post by: -Micky on Jul 31, 2013, 11:21 am
Dann liegt es doch nicht daran das ich es nicht hinbekomme. Das Display ist halt ein bißchen zu klein. Das macht aber nichts. Dann nehme ich halt die normale Schriftgröße.

Oder halt eine Vergrößerungsfolie darüber befestigen.


Micky