Nabend,
ich bin seit langem mal wieder am programmieren und will eine Uhr mit
vier 7-Segmentanzeigen programmieren.
Das multiplexen funktioniert, muss aber die Zeit noch etwas anpassen da
es leicht flackert.
Jetzt zum Problem.
Ich habe das Datenblatt vom Atmega 8535 versucht zu verstehen und bin
eigentlich der Meinung das ich den Interrupt richtig programmiert habe?.
Da es aber nicht funktioniert und den Fehler einfach nicht finde und
verstehe, bitte ich um eine kurze Kontrolle und hoffentlich um
Hilfestellung was ich falsch mache.
Die Anzeigen bleiben dauerhaft auf 0 0 0 0 stehen.
1
#include<avr/io.h>
2
#ifndef F_CPU //Vordefinieren für delay.h
3
#define F_CPU 8000000UL //Definition von F_CPU in Herz
Robin F. schrieb:> Die Anzeigen bleiben dauerhaft auf 0 0 0 0 stehen.
1
if(ZehnerM==6)
2
{
3
ZehnerM=0;
4
EinerS++;
5
...<<UndhierkommtzuerstdieAbfrageaufZehnerS
6
if(ZehnerS<2)
7
{
8
...// EinerS geht bis 9
9
}
10
else
11
{
12
...// EinerS geht bis 3
13
}
14
}
15
16
17
if(ZehnerS&&EinerS!=24)<<???Wassolldassein?
18
{
19
...
20
}
21
else<<<Wirdimmerangesprungen=dauerndNull
22
{
23
EinerM=0;
24
ZehnerM=0;
25
EinerS=0;
26
ZehnerS=0;
27
}
P.S.
Nur weil ein paar selbsternannte Experten hier im Forum die
Klammern so schreiben, heisst es noch lange nicht, dass es so
richtig ist.
Aber wenn man die Klammern so schreibt, dass es übersichtlich und
leichter zu debugen ist, wird man als blutiger Anfänger angesehen,
oder ?
Bei while(1) hast du es doch auch anders geschrieben, bleib dabei,
nur bisschen einrücken.
Morgen,
danke für die schnellen Antworten. Ich habe vorhin "schnell" mal die
erste Antwort ausprobiert, leider bislang noch ohne Erfolg. Ich glaube
das der Interrupt nicht auslöst, da sonst ja wenigstens die Minuten
hochgezählt und angezeigt werden müssten.
Ich werde das nach der Arbeit noch einmal versuchen zu realisieren.
Des weiteren werde ich mein Progrmam dann weiter anpassen und die
Antwort zwei berücksichtigen. Hier weiß ich leider aber noch nicht wie
ich dann den Sekundentakt ohne delay realisieren soll.
Dazu werde ich mich aber noch einmal belesen und ggf. hier nochmal
nachfragen müssen.
Marc V. schrieb:> P.S.> Nur weil ein paar selbsternannte Experten hier im Forum die> Klammern so schreiben, heisst es noch lange nicht, dass es so> richtig ist.> Aber wenn man die Klammern so schreibt, dass es übersichtlich und> leichter zu debugen ist, wird man als blutiger Anfänger angesehen,> oder ?
Danke für deine konstruktive Kritik.
Ich habe das damals so gelernt und von dort an immer so geschrieben, das
es im main anders geschrieben war, war eigentlich eher ein versehen.
Ich werde aber in Zukunft versuchen deinen Ratschlag zu beherzigen und
dies so schreiben.
In der zwischen Zeit (bis heute Nachmittag) werde ich mich noch einmal
vermehrt über Interrupts schlau machen.
Sobald ich nachher das ganze erneut probiert habe, werde ich mich noch
mal melden und meine Erkenntnisse mit euch teilen.
Beste Grüße
Hallo,
ich habe jetzt das Datenblatt und weitere Internetseiten durchwühlt und
mir ist ein Fehler bei dem Interrupt aufgefallen.
Ich habe bei TCCR1 das falsche Register verwendet.
Das TCCR1A ist nicht für den CTC Mode ausgelegt, ich muss dort das
Register B nehmen.
Hoffentlich ist das der Fehler gewesen!
Robin F. schrieb:> Ich habe bei TCCR1 das falsche Register verwendet.
Ja, deswegen schreibt man normalerweise alle bits ab und setzt bei
den unbenutzten bits Null ein.
Thomas E. schrieb:>> Die Zaehlerei macht man nicht im Interrupt.>> Unsinn. Wo denn sonst?
'Türlich in der ISR. Das geht so schnell, das die ISR in Nullkomamnix
durchläuft.
Hier mal ein Getriebe für eine 50Hz Uhr, ist bei mir etwas einfacher,
weil ich die Stellen nicht getrennt brechnen muss:
1
// a simple clock gearbox
2
volatileuint8_tfifties=0;
3
volatileuint8_tseconds=0;
4
volatileuint8_tminutes=0;
5
volatileuint8_thours=0;
6
volatileuint16_tdays=0;
7
// clock gearbox is called every 1/50 of a second
8
// Note that it is really the CTC interrupt but the 8515 uses the COMP vector
Robin F. schrieb:> Ich glaube> das der Interrupt nicht auslöst, da sonst ja wenigstens die Minuten> hochgezählt und angezeigt werden müssten.
Dann lass doch zuerst die Zählerei weg und toogle im Interrupt nur eine
LED. So kannst Du Dich ganz auf die Funktion des Interrupts
konzentrieren.
Solange die LED nicht blinkt brauchst Du gar nicht weitermachen.
Dietrich L. schrieb:> Solange die LED nicht blinkt brauchst Du gar nicht weitermachen.
Da hast du vollkommen Recht. Wenn das mit dem TCCR Register immer noch
nicht die Lösung bringt, werde ich das heute nochmal so versuchen.
Kann ich ich eigentlich in einem Programm auch mehrere Timer verwenden?
Also um z.b. das Zählen in Timer 0 ablaufen zu lassen und um ggf. einen
Taster oder die Anzeigen in einem weiteren Timer 1 unterbringen?
Wenn ja, muss man da irgendwas beachten oder eifnach beide
initialisieren?
Robin F. schrieb:> Kann ich ich eigentlich in einem Programm auch mehrere Timer verwenden?
Natürlich, nur die jeweiligen Routinen so kurz wie möglich halten.
Und nur eine davon darf (soll) die gemeinsamen Variablen ändern.
Hallo,
ich habe meine Lösung nicht ausprobiert, sondern nur mal ins Datenblatt
geschaut.
In TCCR1 gibt es kein WGM12. Ich würde Mode 0 vorschlagen, siehe
Table48.
In TIMSK TOIE1 setzen, Timer1 Überlauf Interrupt. Hierzu den passenden
overflow-irq heraus suchen. Table19 Timer1 OVF Vector9.
CS12 Takt/256 läßt den Timer laufen.
sei ()
Mit freundlichem Gruß
Alles klar vielen Dank.
Ich habe das Datenblatt auch nochmal angeguckt und auf Seite 113 steht
bei 16-Bit Timer bei Register B des TTCR1 das es ein WGM12 gibt.
Siehe Bild.
Ich werde deine Variante dennoch testen.
Robin F. schrieb:> Kann ich ich eigentlich in einem Programm auch mehrere Timer verwenden?>> Also um z.b. das Zählen in Timer 0 ablaufen zu lassen und um ggf. einen> Taster oder die Anzeigen in einem weiteren Timer 1 unterbringen?
Selbstverständlich geht das. Meine Uhr z.B. von oben läuft als Nebenjob
in einem Frequenzgenerator, der eigentliche Frequenzgenerator läuft mit
Timer 1 und kommt sich mit der Uhr nicht in die Quere. Ehrlich gesagt,
benutze ich die Uhr zum Langzeitabgleich des Quarzes, um den
Frequenzgenerator genauer zu machen.
Wenn die ISR einigermassen zügig fertig werden, gibts da keine Probleme.
Aber das Multiplexen lassen ich jetz wie gehabt im main oder sollte ich
das dann auch lieber auslagern?
Aber erstmal abwarten. Ich will erstmal die Anzeige vernünftig zum
laufen bekommen.
Wenn das funktioniert will ich Taster mit implementieren um manuell
Einstellungen vornehmen zu können und dann kommt die nächste Große
Aufgabe und das wird dann ein DCF-77 Modul sein.
Robin F. schrieb:> Aber das Multiplexen lassen ich jetz wie gehabt im main oder> sollte ich> das dann auch lieber auslagern?
Das kann da bleiben, wo es ist. Aber nicht mit Delays, sondern von einem
Timer getriggert. Wobei es allerdings auch nichts ausmacht, die
Mux-Ausgaben in einer ISR zu erledigen. Denn die gebetsmühlenartig
vorgetragene So-kurz-wie-möglich-Regel ist zwar nicht kompletter Unsinn,
sollte aber einem, bezogen auf das gesamte Programm, "So kurz wie nötig"
weichen.
Robin F. schrieb:> Aber das Multiplexen lassen ich jetz wie gehabt im main oder sollte ich> das dann auch lieber auslagern?
Wenn Du im main() sonst nichts zu tun hast, kannst Du es da lassen.
Falls aber zu erwarten ist, dass da noch Funktionen hinzu kommen (was Du
ja planst), ist das Auslagern nicht schlecht. Dann läuft der Multiplexer
wenigstens immer "rund" und ohne Flackern.
Robin F. schrieb:> Aber das Multiplexen lassen ich jetz wie gehabt im main oder sollte ich> das dann auch lieber auslagern?
Multiplex per Timer hat den Vorteil, das die Anzeige nicht flimmert,
wenn main() gerade was anderes macht, sondern beinhart durchgezogen
wird. Per Timerintervall kannst du dann bequem den Kompromiss zwischen
Flimmern der Anzeige und Überlast des MC programmieren. Ausserdem kann
der Multiplex Interrupt auch gleich die Tastenentprellroutine mit
übernehmen.
Bewahre dir das also als Erweiterung für später auf und fummel dich
erstmal durch den Uhren Interrupt durch.
Thomas E. schrieb:> Denn die gebetsmühlenartig> vorgetragene So-kurz-wie-möglich-Regel ist zwar nicht kompletter Unsinn,> sollte aber einem, bezogen auf das gesamte Programm, "So kurz wie nötig"> weichen.
Hmmm.
Für mich ist es dasselbe.
Wenn irgendetwas nötig ist, dann ist es unmöglich ohne diesen
auszukommen, also ist "So kurz wie nötig" gleichzusetzen mit
"So kurz wie möglich".
Robin F. schrieb:> Aber das Multiplexen lassen ich jetz wie gehabt im main oder sollte ich> das dann auch lieber auslagern?
Das gehört in einen Timerinterrupt. Ansonsten wirst Du immer ein
Flackern sehen, abhängig von allen anderen Tasks.
Benutzt Du noch andere Interrupts, ist es am besten, diese als
ISR(xxx_vect, ISR_NOBLOCK)
unterbrechbar zu machen. Damit erreichst Du das geringste Flackern.
Geht aber nicht immer, z.B. bei UART, SPI, I2C nicht.
Peter D. schrieb:> Das gehört in einen Timerinterrupt. Ansonsten wirst Du immer ein> Flackern sehen, abhängig von allen anderen Tasks.
Kommt auf die Refreshrate an.
Bei ausreichend schnellem Refresh ist eher ein Unterschied in der
Helligkeit zu sehen.
So ich habe das jetzt nochmal angepasst.
Jetzt funktioniert es. Eine Fragen habe ich jetzt noch.
Ich versteh noch nicht ganz wie ich den Vorteiler und den Vorladewert
richtig berechne.
Ich habe versucht die Werte zu bestimmen aber mit keiner Rechnung komme
ich auf das Ergebnis, welches in der Hardware funktioniert.
Ich habe jetzt den Vorladewert auf 15624 und den Vorteiler auf 64
gestellt.
Mit diesen Werten komme ich auf einen Sekunden Takt aber wie berechne
ich das richtig und nachvollziehbar?
Hier noch etwas Code zum lesen:
1
#include<avr/io.h>
2
#ifndef F_CPU //Vordefinieren für delay.h
3
#define F_CPU 16000000UL //Definition von F_CPU in Herz
Robin F. schrieb:> Ich habe jetzt den Vorladewert auf 15624 und den Vorteiler auf 64> gestellt.
Nach meiner Rechnung (F_CPU/64/15625) kämest du damit auf genau 16 Hz
Ticker, was mich zu der Annahme verleitet, das dein Mega mit dem
internen Oszillator läuft und damit nicht mit dem externen 16MHz Quarz,
sondern mit den 1MHz des Auslieferzustandes.
Um das zu ändern, setzt du die Fuses auf den externen High Frequency
Crystal Modus (CKOPT = 0), den du aber tunlichst erst dann aktivierst,
wenn da wirklich ein externer 16MHz Quarz mit den beiden kleinen
Kondensatoren dran hängt.
Robin F. schrieb:> Okey also muss ich gucken das ich mit dem 1Mhz rechne und gucke ob dann> eine annehmliche Zeit bei raus kommt?
Das hast du ja schon. Bei 1000000 Hertz geteilt durch 64 geteilt durch
15625 kommt ja genau 1 Hz raus. Du solltest nur dein
1
#define F_CPU 16000000UL
auf 1000000UL umstellen, damit auch etwaige Aufrufe von _delay_ms() das
richtige Ergebnis bringen.
Für eine gut gehende Uhr ist übrigens der interne RC Oszillator viel zu
ungenau. Wenn es dir darauf aber nicht ankommt, geht der RC aber.
Hab ich jetzt angepasst danke.
Dann funktioniert das jetzt alles soweit.
Jetzt baue ich die nächsten Funktionen ein:
- Sekundentakt blinken
- mit dem Taster manuell einstellen können
- DCF-77 (Zukunftsmusik)
Ich danke euch!!!
Wenn ich das Programm fertig habe, kann es gern noch einmal hier rein
laden für weitere Verwendungen.
Beste Grüße
Hallo zusammen,
ich möchte mal ein kleines Update zu meinem Projekt geben.
Ein paar Probleme gab es zu lösen da es nicht richtig funktioniert hatte
die Zeit manuell runter zu zählen.
Aus diesem Grund habe ich Taster 1 für Stunden hochzählen und Taster 2
für Minuten hochzählen verwendet.
Des weiteren habe ich das Zählen der Zeit noch einmal anderst gelöst.
Hier der Code:
1
#include<avr/io.h>
2
#ifndef F_CPU
3
#define F_CPU 1000000UL //1MHz Takt
4
#endif
5
#include<avr/interrupt.h>
6
#include<util/delay.h>
7
8
/*
9
Port B = Ziffern der Anzeigen
10
Port C = Anzeigen
11
Port D = Taster, Sekunden LED, DCF-77, Temperaturfühler
So hier noch einmal ein Update des Programms.
Jetzt sind die Taster nicht mehr mit den Interrupts realisiert.
Die nächsten Schritte sind dann DCF-77 und Temperaturfühler DS1820 zu
implementieren.