Forum: Mikrocontroller und Digitale Elektronik Arduino: Ausgabe Zeit als Funktionsaufruf für mehreren "Devices"


von Äxl (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,
ich hab mir mit meinem Arduino Micro eine vierkanal-Stoppuhr gebastelt.
Funktioniert ansich auch ganz prima (war ich ja angehnehm überrascht, 
wie schnell und "einfach" das umzusetzen ging.)

Ich hab also eine Ausgabe der Uhrzeit auf den frolgenden drei 
"Gerätschaften"
 - Serielle Schnittstelle -> (Serieller Monitor in der Arduino IDE)
 - OLED-Display
 - EPSON Thermodrucker

Es werden eben die Startzeiten und die Stopzeiten, die Rundendauer usw. 
angezeigt bzw. ausgedruckt..
Dies alles funktioniert sehr gut. Bei der Durchsicht meines Codes fiel 
mir dann irgendwann auf, dass ja ständig das gleiche gemacht werden 
muss, nur eben von jeweils 'nem anderen "Gerät".
Meine vier Zeiten kopier' ich zur Ausgabe lokal um (Startzeit1-4, 
Endzeit): ABER wie kann ich jetzt ein Ausgabedevice meiner "PRINT_TIME" 
- Funktion zuordnen?

Ich weiss es wirklich nicht. ich habe schon mit "&" und "*" und ohne 
probiert. Hab schon in der Funktion "Stream.print" angeben wollen. Aber 
das muss ich ja dann (am Ende der Funktion) mit dem tatsächlichen 
Ausgabemedium "verheiraten".
Es interessiert mich wirklich, wie man das macht!

Grüße
Äxl
(TestCode auch im Anhang)
1
#include <SPI.h>
2
#include <Wire.h>
3
#include "DS3231.h"
4
#include <Adafruit_GFX.h>
5
#include <Adafruit_SSD1306.h>
6
#include "thermalprinter.h"
7
8
#define SCREEN_WIDTH 128 // OLED display width, in pixels
9
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
10
#define OLED_RESET    -1 // Reset pin # (or -1 if sharing Arduino reset pin)
11
Adafruit_SSD1306  display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
12
Epson TM88(&Serial1); // init the Printer with HW-Serial (Serial1)
13
RTClib RTC;
14
DateTime time_now;
15
void setup() {
16
  // put your setup code here, to run once:
17
  Serial1.begin(9600); //open Printer connection
18
  Serial.begin(115200); // Initialize serial communications with the PC
19
  Wire.begin();
20
  display.display(); // Display Intro Adafruit
21
  delay(500); // wait to display it
22
  display.clearDisplay(); // clear
23
24
  time_now = RTC.now();
25
  // DISPLAY TIME VIA SERIAL(USB-DEBUG)
26
  Serial.print(time_now.hour(), DEC);
27
  Serial.print(':');
28
  Serial.print(time_now.minute() < 010 ? "0" : "");
29
  Serial.print(time_now.minute(), DEC);
30
  Serial.print(':');
31
  Serial.print(time_now.second() < 010 ? "0" : "");
32
  Serial.print(time_now.second(), DEC);
33
  Serial.println();
34
35
  // DISPLAY TIME VIA SERIAL1(THERMOPRINTER)
36
  TM88.print(time_now.hour() < 10 ? "0" : "");
37
  TM88.print(time_now.hour(), DEC);
38
  TM88.print(':');
39
  TM88.print(time_now.minute() < 10 ? "0" : "");
40
  TM88.print(time_now.minute(), DEC);
41
  TM88.print(':');
42
  TM88.print(time_now.second() < 10 ? "0" : "");
43
  TM88.print(time_now.second(), DEC);  
44
 
45
  // DISPLAY TIME VIA OLED(128x64 I2C Adafruit)
46
  display.print(time_now.hour(), DEC);
47
  display.print(':');
48
  display.print(time_now.minute() < 010 ? "0" : "");
49
  display.print(time_now.minute(), DEC);
50
  display.print(':');
51
  display.print(time_now.second() < 010 ? "0" : "");
52
  display.print(time_now.second(), DEC);
53
  display.display();
54
  // Function Call
55
//  Print_Time(Serial,time_now);
56
//  Print_Time(TM88,time_now);
57
//  Print_Time(display,time_now);
58
59
  Print_Time(&Serial,time_now);
60
  Print_Time(&TM88,time_now);
61
  Print_Time(&display,time_now);
62
63
}
64
65
void loop() {
66
  // put your main code here, to run repeatedly:
67
}
68
69
// PRINTFUNCTION
70
71
//int Print_Time(int *Printobj, DateTime time_to_print) {
72
int Print_Time(int Printobj, DateTime time_to_print) {
73
//int Print_Time(int &Printobj, DateTime time_to_print) {
74
// int Print_Time(int *Printobj, DateTime time_to_print) {
75
76
      Printobj.print(time_to_print.hour() < 10 ? "0" : "");
77
      Printobj.print(time_to_print.hour(), DEC);
78
      Printobj.print(':');
79
      Printobj.print(time_to_print.minute() < 10 ? "0" : "");
80
      Printobj.print(time_to_print.minute(), DEC);
81
      Printobj.print(':');
82
      Printobj.print(time_to_print.second() < 10 ? "0" : "");
83
      Printobj.print(time_to_print.second(), DEC);  
84
}

von Stefan F. (Gast)


Lesenswert?

Was du vor hast setzt voraus, dass alle Ausgabeobjekte einen gemeinsamen 
Vorfahren haben, der die print() Methode bereitstellt.

Die Serial Klasse ist von der Stream Klasse abgeleitet, welche wiederum 
von der Print Klasse abgeleitet ist, wo die print() Methode definiert 
ist.

Deine Adafruit_SSD1306 ist von Adafruit_GFX abgeleitet, welche von Print 
abgeleitet ist. Das passt also schonmal.

Die Epson Klasse ist auch von Print abgeleitet. Du hast Glück!

Du musst deine Funktion so schreiben, dass sie als Input ein Objekt 
erwartet, das vom Typ Print ist oder davon abgeleitet wurde. Dabei hast 
du die Wahl, das Objekt als Referenz oder als Zeiger zu übergeben. 
Referenz scheint mir in diesem Fall einfacher:

1
int Print_Time(Print& printobj, DateTime time_to_print) 
2
{
3
      printobj.print(time_to_print.hour() < 10 ? "0" : "");
4
      printobj.print(time_to_print.hour(), DEC);
5
      printobj.print(':');
6
      printobj.print(time_to_print.minute() < 10 ? "0" : "");
7
      printobj.print(time_to_print.minute(), DEC);
8
      printobj.print(':');
9
      printobj.print(time_to_print.second() < 10 ? "0" : "");
10
      printobj.print(time_to_print.second(), DEC);  
11
}
12
13
Print_Time(Serial,time_now);
14
Print_Time(TM88,time_now);
15
Print_Time(display,time_now);

Das Datum würde ich vielleicht auch als Referenz übergeben. Dadurch 
würdest du den Speicherbedarf eventuell etwas reduzieren. So wie du es 
jetzt gerade machst, wird eine Kopie vom Datum an die Funktion 
übergeben.

von Äxl (Gast)


Lesenswert?

Ich sag mal ganz lieb "DANKE!!!" es funktioniert freu.
(Im Ernst; ich freue mich tatsächlich)
Dann mach ich mal ans "optimieren" ;)
der ATMega32u4 ist schon randvoll. Jetzt kann ich eventuell noch'n 
kleines Menü zum Uhrzeitstellen etc. mit einbauen. Platz sollte jetzt, 
wenn auch knapp, ausreichen.
(Die OLED-Lib nimmt sich ganz schön viel Flash...)
Nochmals: vielen Dank für diese wertvolle Hilfestellung zum Eingangs 
genannten Problem!
Mit dem Thema "Referenzen" hab ich mich (jetzt erst in diesem 
Zusammenhang) letzte Nacht belesen. Unterschied konnte ich schonmal 
herausarbeiten, mal seh'n, wie man das umsetzt...

LG
Äxl

von Stefan F. (Gast)


Lesenswert?

Hier hat jemand eine andere Library veröffentlicht, die mit weniger RAM 
auskommt - dafür aber auf Textausgabe beschränkt ist.

Für solch kleine Mikrocontroller eignen sich Displays mit eingebautem 
Zeichen-Generaot und ggf. Grafik-Engine besser.

von Äxl (Gast)


Lesenswert?

>Für solch kleine Mikrocontroller eignen sich Displays mit eingebautem
>Zeichen-Generaot und ggf. Grafik-Engine besser.

Das denke ich auch.

Viel interessanter ist die Tatsache, dass, wenn ich den Seriellen 
Monitor ausschalte, sich nach einigen (noch genau herauzufindener) 
Anzahl Zeichen (denke mal 64) die "Serial.print" in einen ein-sekündigen 
Timeout geht und meinen ganzen Ablauf aufhält. Gut - sind im Moment nur 
Debugausgeben, die nachher rausfliegen können. Aber blöd ist das 
trotzdem.- Wird mit dem USB zusammenhängen.
Ein anderer, "netter" Effekt hingegen ist, dass, wenn man mit 
"Serial.begin(9600)" gestartet hat und man im Seriellen Monitor im 
laufendem Betrieb 115200 einstellt, sich die Serial automatisch auf jene 
Baudrate umstellt -on the fly- quasi. witzig...
(Nur mit dem Timeout ist natürlich doof)
Googlet man mal nach diesem Phänomen, kommen nur "Beschwerden" darüber, 
dass sich der Arduino resettet, wenn man den seriellen Port neu aufmacht 
(über die DTR(?) Leitung). Das macht mein Micro Pro
https://www.reichelt.de/arduino-micro-atmega32u4-microusb-arduino-micro-p130166.html?
nicht.
Soll ich jetzt in den Tiefen des CDC rumwühlen, um jene Abfrage 
auszuschalten? Hab ich doch garkeine Ahnung von :))
Vielleicht mach hich hier mal nen eigenen Thread zu eben jenem Thema 
auf. Ich werde ja wohl nicht der erste sein, dem das auffällt.

Gruß
Äxl

von Äxl (Gast)


Lesenswert?

Nimmt man higegen ein anderes, (Hier "Terminal")
https://sites.google.com/site/terminalbpp/
ergibt eine öffnen und schliessen des COM-Ports auf Rückfrage mit

"If(!Serial)" ein korrektes Ergebins.

Port offen und da -> Print Sekunden
Port geschlossen (disconnect) -> Print ("Serial off")

Bei geöffnetem Port lässt sich das mit setzen/löschen der DTR-Leitung 
ebenso
provozieren. Nur der serielle Monitor der Arduino - IDE macht da nicht 
"ordentlich" den Port zu, denk' ich mal.
1
   if(!Serial) {
2
     display.setTextSize(1);             // Normal 1:1 pixel scale
3
     display.setTextColor(WHITE);        // Draw white text
4
     display.setCursor(16, 40);            // Start at top-left corner
5
    display.println("Serial off");
6
   }
7
  else Print_Time(display,time_now);
8
  display.display();

Ich verwende noch die Arduino-IDE Version 1.6.11, sehe ich gerade. Ich 
werde mal n update auf die 1.8.x machen, wenn ich hier mit diesem 
Projekt durch bin.

Danke fürs mitlesen bis hierher.

LG
Äxl

von Stefan F. (Gast)


Lesenswert?

Äxl schrieb:
> Viel interessanter ist die Tatsache, dass, wenn ich den Seriellen
> Monitor ausschalte, sich nach einigen (noch genau herauzufindener)
> Anzahl Zeichen (denke mal 64) die "Serial.print" in einen ein-sekündigen
> Timeout geht und meinen ganzen Ablauf aufhält.

Das liegt an der USB spezifischen Implementierung der Serial Klasse. Sie 
ist so geschrieben, dass bei vollem Puffer möglichst nichts verloren 
gibt. Es gibt andere Implementierungen die sich in dieser Situation ganz 
aufhängen würden. Mit if(Serial) gekommst du das in den Griff: 
https://www.arduino.cc/en/Serial/IfSerial

> Ein anderer, "netter" Effekt hingegen ist, dass, wenn man mit
> "Serial.begin(9600)" gestartet hat und man im Seriellen Monitor im
> laufendem Betrieb 115200 einstellt, sich die Serial automatisch auf jene
> Baudrate umstellt -on the fly- quasi. witzig...

Das liegt daran, dass es sich nur um eine virtuelle serielle Verbindung 
handelt. In Wirklich hat sie gar keine Baudrate. Die 
Übertragungsgeschwindigkeit wird vom USB Bus diktiert.

von Äxl (Gast)


Lesenswert?

> Mit if(Serial) gekommst du das in den Griff:
1
   if(!Serial) {
2
     display.setTextSize(1);             // Normal 1:1 pixel scale
3
     display.setTextColor(WHITE);        // Draw white text
4
     display.setCursor(16, 40);            // Start at top-left corner
5
    display.println("Serial off");
6
   }
7
  else Print_Time(display,time_now);
8
  display.display();

Ja, hab ich probiert (wollte ja eigentlich am Menü schreiben, aber 
nunja)

mit jedem anderen Terminalprogramm und/oder mit händischem Setzen der 
DTR-Leitung funktioniert das auch. [TerraTerm, Putty, Terminal(@bray)].
Nur im seriellen Monitor der IDE (hier unter 1.6.11) eben NICHT :|
Ich installiere mal die 1.8.8 und werde brav berichten. ;)

von Äxl (Gast)


Lesenswert?

So - gleiche "in grün". Serieller Monitor schliessen: Arduino bekommt 
nichts davon mit uns sendet ins leere, bis irgendwo ein Buffer 
überläuft, was dann in einem Time-Out endet.
Der serielle Monitor der Arduino IDE setzt die DTR Leitung bei öffnen 
des virtuellen COM-Ports, löscht die Leitung aber aber nicht. Das sagt 
mein Serieller Monitor.

Mitm Terminalprogramm gegengetestet: DTR wird gesetzt, wenn der Port 
geöffnet wird und gelöscht, wenn der Port geschlossen wird. In dem 
Moment geht "IF (!Serial)" auch auf. Natürlich kann man im 
TerminalProgramm die DTR Leitung auch händisch setzen/löschen. Kein 
Timeout am Arduino "Ein "IF(!Serial)" in Zeile42 springt sofort an. 
Anderenfalls sendet der Arduino noch fleissig weiter, bis er dann so ca. 
3 Sekunden Time-Out zwischen jeder Aussendung hinlegt.

https://www.heise.de/download/product/free-serial-port-monitor-26030
https://sites.google.com/site/terminalbpp/Terminal20141030.zip?attredirects=0&d=1
http://playground.arduino.cc/interfacing/java

Wird's wohl hier zu suchen sein...
http://rxtx.qbang.org/wiki/index.php/Main_Page

von Äxl (Gast)


Lesenswert?

1
Port geöffnet durch Vorgang "Terminal.exe" (PID: 7332)
2
3
DOWN (0x00000000): IOCTL_SERIAL_SET_DTR: Set DTR
4
5
DOWN (0x00000000): IOCTL_SERIAL_CLR_DTR: Clear DTR
6
7
Port geschlossen
8
9
Port geöffnet durch Vorgang "javaw.exe" (PID: 6964)
10
11
DOWN (0x00000000): IOCTL_SERIAL_SET_DTR: Set DTR
12
13
Port geschlossen

anbei nochmal der Mitschnitt zur Steuerleitung DTR.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.