ich bin seit kurzem im besitz eines Arduino Mega 2560 Boards und habe schon ein paar Sketches ausprobiert und modifiziert.
Als Anzeige nutze ich ein 20x4 DotMatrix VFD-Display das sich bis auf Sonderbefehle bequem mit der LiquidCrystal-Lib ansteuern lässt.
Würde jetzt gerne zwei Zählerwerte im Uhrzeitformat auf dem Display ausgeben deren Takt von jeweils einem der externen Interrups kommt.
Leider steh ich da schon komplett auf dem Schlauch... eine einzelne Uhrzeit, angetrieben durch einen externen Interrupt, bekäme ich noch hin aber 2?
Der erste Interrupt bekommt seinen Sekundentakt von einem RTC-Modul und soll als "Real: hh:mm:ss" in der 3. Zeile angezeigt werden.
Der zweite Interrupt bekommt seinen Takt von der Bandlaufrolle* eines Tonbandgerätes, muß intern noch durch 2 geteilt werden und soll dann in der 4. Zeile als "Tape: hh:mm:ss" angezeigt werden.
Wer von euch wäre so nett mir auf die Sprünge zu helfen?
*Die Bandlaufrolle wird direkt vom Band angetrieben und liefert daher immer einen zur Bandgeschwindigkeit (Abspielen, Umspulen) proportionalen Takt.
Bei deinem Arduino hast du ja mehrere interrupt-pins zur verfügung!
Welche das jetzt genau sind kann ich dir nicht sagen aber abfragen kannst du sie in etwa so:
attachInterrupt(0, rtcINT, RISING);
attachInterrupt(1, tapeINT, RISING);
Dann machst du zwei kurz gehaltene routinen
Wo du nur hoch zählst mehr nicht. rtcVal++ und tapeVal++
im loop passiert der rest.
TapeVal/2
Und die umrechnung in minuten und stunden
Naja und das display immer aktualisieren wenn sich ein wert geändert hat .
Also entweder tapeVal oder rtcVal dann aktualisiert sich dein display auch nur wenn sich was ändert.
Max 2 mal in der Sekunde.
Machst du das nicht wird sich dein display immer aktulasieren wenn die loop durch ist und das ist zu schnell.
Was dann noch fehlt sind so Sachen wie reset für die rtcVal und die TapeVal.
Ist aber auch nicht das Problem
Hab jetzt mal einen Counter realisiert doch auf dem Display bekomm ich als Zählerwert nur 000 angezeigt, sehe nur nicht wo der Fehler liegt...
Hier mein Sketch:
/*
The circuit:
* LCD RS pin to digital pin 7
* LCD Enable pin to digital pin 6
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
int counter0 = 0; // Incremented by switch0
int counter1 = 0; // Incremented by switch1
void setup() {
pinMode(20, INPUT); // Pin20 is input
digitalWrite(20, HIGH); // Switch on pull up
pinMode(21, INPUT); // Pin21 is input
digitalWrite(21, HIGH); // Switch on pull up
//attachInterrupt(2, tapeINT, FALLING);
attachInterrupt(3, rtcINT, FALLING);
// set up the LCD's number of columns and rows:
lcd.begin(20, 4);
// Print a message to the LCD
lcd.print("Tape vs. Real Time");
}
// Zähler 0
void rtcINT(){
if (rtcINT == LOW) {
counter0++;
}
}
void loop(){
char Cnt[4];
lcd.setCursor(0, 2);
lcd.print("Real: ");
sprintf(Cnt, "%03d", counter0);
lcd.print(Cnt);
}
Wofür ist das rtcINT== LOW?
Soweit ich weiß bringt/geht das nicht.
Das ist ja eine routiene und keine variable.
In der rtcINT brauchst du nur deinen counter ++ machen
Habe jetzt nach längerem googlen auch den Zählerstand im Zeitformat drinnen, allerdings hab ich da noch einen Denkfehler weil die Sekunden immer weiter hochzählen, hab aber grad keinen Plan wie ich das ändern kann.
Hier mein Sketch:
/*
The circuit:
* LCD RS pin to digital pin 7
* LCD Enable pin to digital pin 6
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
int counter0 = 0; // Incremented by switch0
int counter1 = 0; // Incremented by switch1
//Initial time set
int sec0=00;
int min0=00;
int hour0=00;
int sec1=00;
int min1=00;
int hour1=00;
// Setup
void setup() {
pinMode(13, OUTPUT); // Pin13 as output
pinMode(20, INPUT); // Pin20 is input
//digitalWrite(20, HIGH); // Switch on pull up
pinMode(21, INPUT); // Pin21 is input
digitalWrite(21, HIGH); // Switch on pull up
attachInterrupt(2, tapeINT, FALLING);
attachInterrupt(3, rtcINT, FALLING);
// set up the LCD's number of columns and rows:
lcd.begin(20, 4);
// Print a message to the LCD
lcd.print("Tape vs. Real Time");
}
// Zähler 0
void rtcINT(){
counter0++;
}
// Zähler 1
void tapeINT(){
counter1++;
}
void rtcZeit(){
char Cnt[30];
sec0=counter0;
if(sec0==60){
min0++;
sec0=0;
}
if(min0==60){
hour0++;
min0=0;
}
if(hour0==24){
hour0=0;
}
lcd.setCursor(0, 2);
lcd.print("Real: ");
sprintf(Cnt,"%02d:%02d:%02d",hour0,min0,sec0);
lcd.print(Cnt);
}
void tapeZeit(){
char Cnt[30];
sec1=counter1;
if(sec1==60){
min1++;
sec1=0;
}
if(min1==60){
hour1++;
min1=0;
}
if(hour1==24){
hour1=0;
}
lcd.setCursor(0, 3);
lcd.print("Tape: ");
sprintf(Cnt,"%02d:%02d:%02d",hour1,min1,sec1);
lcd.print(Cnt);
}
void loop(){
rtcZeit();
tapeZeit();
digitalWrite(13, HIGH);
delay(950);
digitalWrite(13, LOW);
delay(50);
}
Mit dem digitalWrite im loop hab ich einen 1Hz-Taktgeber realisiert da das RTC-Modul im Auslieferungszustand keinen Referenztakt ausgibt, den muß man erst mit einer Codesequenz aktivieren und dafür hab ich grad keine Lust.
Ich weiß nicht ob das das problem ist aber es könnte sein:
Durch dein delay störst du den gesammten ablauf.
Und du setzt zwar sec0 auf 0 wenn es 60 war aber überschreibst dies im nächsten durchlauf wieder mit counter.
Ich würde vielleicht in deinen rechnung einfach den counter immer durch 60 bzw durch 3600 teilen um vom counter direkt die minuten bzw die stunden zu bekommen.
luemmel:
Habe jetzt nach längerem googlen auch den Zählerstand im Zeitformat drinnen, allerdings hab ich da noch einen Denkfehler weil die Sekunden immer weiter hochzählen, hab aber grad keinen Plan wie ich das ändern kann.
gibt denn dein Impulsgeber an der Capstanwelle z.b. bei Ruecklauf einen negativen Wert aus?
Sonst können sie ja nur größer werden. Wenn das Band zurueckläuft muß dein Zähler irgendwie decrementiert werden.
Welches Tonbandgerät gibt eigentlich genau 1 Impuls pro Sekunde aus?
Nachfolgend mal ein Codebeispiel (Auszug) aus meinem Fernbedienungsprogramm fuer meine Otari MX55, vielleicht kannst du damit was anfangen.
volatile long zaehler = 0;
volatile long runden = 0;
boolean richtung = 0;
long daten[10];
// Konstante fuer Bandlänge pro Impuls (in cm)
const double meter = 0.15875;
void setup()
{
// Interrupt mit Pin 2 verbinden
attachInterrupt(0, zaehlen, CHANGE);
}
void loop()
{
// if an incoming client connects, there will be bytes available to read:
EthernetClient client = server.available();
/* Speed abfragen
// speeda = 0 & speedb = 0 entspricht 3,75 ips
// speeda = 0 & speedb = 1 entspricht 7,5 ips
// speeda = 1 & speedb = 1 entspricht 15 ips*/
// speed A abfragen
daten[0] = digitalRead(16);
// speed B abfragen
daten[1] = digitalRead(17);
// Laufrichtung abfragen
richtung = digitalRead(18);
// Sekunden der Laufzeit uebermitteln
daten[8] = runden;
// Verbrauchte Bandlänge uebermitteln
long lang = 0;
lang = zaehler * meter;
daten[9] = lang;
}
void zaehlen()
{
// Impulszaehler inkrementieren fuer Wiedergabe, Aufnahme und schnellen Vorlauf
if (richtung == 0){
zaehler++;
}
// Impulszaehler dekrementieren fuer schnellen Ruecklauf
else {
zaehler--;
}
// zaehler auf- oder abrunden und in der Variablen "runden" speichern
// Fuer 3,75 ips, 30 Impulse pro Sekunde
if (daten[0] == 0 & daten[1] == 0){
runden = zaehler/60;
if((zaehler % 60) >= 30){
runden++;
}
}
// Fuer 7,5 ips, 60 Impulse pro Sekunde
if (daten[0] == 0 & daten[1] == 1){
runden = zaehler/120;
if((zaehler % 120) >= 60){
runden++;
}
}
// Fuer 15 ips, 120 Impulse pro Sekunde
if (daten[0] == 1 & daten[1] == 1){
runden = zaehler/240;
if((zaehler % 240) >= 120){
runden++;
}
}
}
Die Daten werden, zusammen mit vielen anderen, im Array Daten [] gespeichert und an ein Java-Programm zur Anzeige und Steuerung via Ethernet uebergeben.
Ich möchte erstmal klein anfangen, bin ja blutiger Einsteiger in die Welt der Microprozessoren und deren Programmierung.
Möchte erstmal nur schauen wie genau die Bandlaufzeit mit einer realen Zeit synchron bleibt.
Super das hier noch jemand mit dem Tonbandfieber unterwegs ist
Ich habe die Akai GX-77 die über eine Impulsrolle verfügt die direkt vom Tonband angetrieben wird. Pro Umdrehung gibt diese zwei Inkrementalpulse aus, da ich aber eine externe Steuerungseinheit plane mit der ich die Akai dann komplett steuere, gibt der Arduino ja dann die Laufrichtung selbst an.
Die schwierigkeit die ich habe ist den Zählerwert in die Zeiteinheiten Stunden, Minuten und Sekunden umzuwandeln.
ich würde mich der Meinung von MueThoS anschließen.
Die beiden durch die Interrupts gesteuerten Zähler musst Du auch mit bearbeiten. Also nach 60 Sek auf null setzen, oder über den Weg mit 3600 Sek bearbeiten und dann zurücksetzen.
“delay“ stört eigentlich nur bedingt, weil die Zählerberechnung immer nur im nach Ablauf der delay- Zeiten erfolgt.Unter Umständen musst Du „int counter0 = 0; // Incremented by switch0“ durch „volatile int counter0 = 0; // Incremented by switch0“ ersetzen um die bearbeitung des counters vom normaln Programm aus zu erledigen.
wie bereits weiter oben geschrieben sollten (laut Arduino-Referenz) alle Variablen, die in einer Interrupt-Funktion benutzt werden, als "volatile" deklariert werden. Ganz verstanden habe ich das zwar auch noch nicht, aber bei mir funktioniert das nur so. Vielleicht kann ja ein anderer näheres dazu sagen, wuerde mich interessieren.
Die Umrechnung in Std., Min. wird bei mir (noch) von dem Java-Programm erledigt. Der Arduino sendet nur den Wert in Sekunden.
Ich vermute aber ein Problem in deinem Code hier:
if(sec0==60)
if(min0==60)
if(hour0==24){
Die Interrupts und dein "loop" laufen unabhängig voneinander.
Durch den Vergleich (genau 60) wird aber z.b. der Minutenzähler nur erhöht, wenn die Sekunden genau bei 60 sind. Was passiert aber, wenn wir schon bei 61 sind? Dann wird die Bedingung niemals war.
Versuche es vielleicht mal so:
Ich hoffe das stimmt? An die Profis: Geht das auch besser?
Dann könntest du dir deine IFs sparen.
und wenn du jetzt noch dein delay für den Takt (den du ja im mom selber erstellst mit millies auslößt ist diese unschöne Sache auch noch raus.
Schau dir hierzu mal blinkwithoutdelay aus dem Playground an. Das ist genau das was du brauchst.
Habe mein Sketch entsprechend euren Hinweisen und Anmerkungen geändert und es läuft so wie gewünscht.
Zwischendurch hatte ich noch mit einem DS1307-Testsketch den Rechteckausgang mit 1Hz aktiviert wodurch der Blinkerteil in meinem Sketch wegfällt.
/*
The circuit:
* LCD RS pin to digital pin 7
* LCD Enable pin to digital pin 6
* LCD D4 pin to digital pin 5
* LCD D5 pin to digital pin 4
* LCD D6 pin to digital pin 3
* LCD D7 pin to digital pin 2
* LCD R/W pin to ground
* 10K resistor:
* ends to +5V and ground
* wiper to LCD VO pin (pin 3)
*/
// include the library code:
#include <LiquidCrystal.h>
// initialize the library with the numbers of the interface pins
LiquidCrystal lcd(7, 6, 5, 4, 3, 2);
volatile int counter0 = 0; // Incremented by switch0
volatile int counter1 = 0; // Incremented by switch1
const int RTCLED = 13;
const int RTC = 20;
const int TAPE = 21;
int RTCstate = 0;
int sec0 = 00;
int min0 = 00;
int hour0 = 00;
int sec1 = 00;
int min1 = 00;
int hour1 = 00;
// Setup
void setup() {
pinMode(RTCLED, OUTPUT); // Pin13 as output
pinMode(RTC, INPUT); // Pin20 is input
digitalWrite(RTC, HIGH); // Switch on pull up
pinMode(TAPE, INPUT); // Pin21 is input
digitalWrite(TAPE, HIGH); // Switch on pull up
attachInterrupt(2, tapeINT, FALLING);
attachInterrupt(3, rtcINT, FALLING);
// set up the LCD's number of columns and rows:
lcd.begin(20, 4);
// Print a message to the LCD
lcd.print("Tape vs. Real Time");
}
// Zähler 0
void rtcINT(){
counter0++;
}
// Zähler 1
void tapeINT(){
counter1++;
}
void rtcZeit(){
char Cnt[30];
hour0=counter0/3600;
min0=(counter0/60)-(hour0*60);
sec0=counter0-(hour0*3600)-(min0*60);
lcd.setCursor(0, 2);
lcd.print("Real: ");
sprintf(Cnt,"%02d:%02d:%02d",hour0,min0,sec0);
lcd.print(Cnt);
}
void tapeZeit(){
char Cnt[30];
hour1=counter1/3600;
min1=(counter1/60)-(hour1*60);
sec1=counter1-(hour1*3600)-(min1*60);
lcd.setCursor(0, 3);
lcd.print("Tape: ");
sprintf(Cnt,"%02d:%02d:%02d",hour1,min1,sec1);
lcd.print(Cnt);
}
void loop(){
rtcZeit();
tapeZeit();
RTCstate = digitalRead(RTC);
if (RTCstate == HIGH) {
// turn LED on:
digitalWrite(RTCLED, HIGH);
} else {
// turn LED off:
digitalWrite(RTCLED, LOW);
}
}