Hallo, ich wollte euch mal fragen ob mein Vorhaben mit dem Timer machbar
ist: Jede Sekunde soll TIMER1_COMPA_vect aufrufen in der eine Uhr läuft
und ca. jede ms TIMER1_COMPB_vect.
Stimmt die Konfiguration so? Geht das mit einem Timer oder muss ich 2
nehmen?
>> Hallo, ich wollte euch mal fragen ob mein Vorhaben mit dem Timer machbar> ist: Jede Sekunde soll TIMER1_COMPA_vect aufrufen in der eine Uhr läuft> und ca. jede ms TIMER1_COMPB_vect.>> Stimmt die Konfiguration so?
Die Bits hast du ja sicherlich mit dem Datenblatt daneben
zusammengestellt, also wird das wohl stimmen.
> Geht das mit einem Timer oder muss ich 2> nehmen?
Prinzipiell kannst du dich an beide Compare klemmen.
Aber ob deine Zahlen stimmen?
> Jede Sekunde soll TIMER1_COMPA_vect aufrufen> und ca. jede ms TIMER1_COMPB_vect.
1 Sekunde hat 1000 Millisekunden. Daher müsste B tausend mal öfter
aufgerufen werden als A. D.h. der Comparewert für A muss 1000 mal größer
als der von B sein.
> OCR1A = 34286;> OCR1B |= 1000;
Das ist aber nicht der Fall :-)
(Und was macht das Oder beim Setzen vvon OCR1B?)
Wozu brauchst du eigentlich den 1 Sekunden Interrupt?
Wenn du im Millisekunden-Interrupt die Aufrufe zählst, dann ist nach dem
1000-sten Aufruf auch 1 Sekunde vergangen.
Christian Q. schrieb:> Oh, atmega16 - 8Mhz
Und wie bist du da jetzt auf deine Zahlen gekommen?
Lotto - Wasserstand - Luftfeuchte - Aussentemperatur in Haiti -
sonstiges?
Hab ein bisschen probiert bis es ca. hinkam.
Also ich brauch den timer mit 1ms fürs multiplexen von led's. Habe 2
timer genommen, da ich so besser das timing, getrennt von einander
regeln kann.
Wie berechne ich die Timer genau?
Ich betreibe 8 LED, 4 untereinander in 2 Spalten. Wie beziehe ich das in
die Rechnung für Timer B ein? Man brauch pro LED ja ca. 25Hz. Weiß da
jemand wie ich das einbaue?
Wofür steht das OCRnA in der Formel vom Datenblatt?
spess53 schrieb:> Für die Frequenz setzt du 1/2s bzw 1/2ms ein.
Wie bitte?
Christian Q. schrieb:> Ich betreibe 8 LED, 4 untereinander in 2 Spalten. Wie beziehe ich das in> die Rechnung für Timer B ein? Man brauch pro LED ja ca. 25Hz. Weiß da> jemand wie ich das einbaue?
Wie hast du das denn hardwaretechnisch gelöst?
Im Idealfall steuerst du ja nicht jede LED einzeln im Multiplex an,
sondern zb jeweils 4 LED auf einmal.
> Wofür steht das OCRnA in der Formel vom Datenblatt?
n ist die Nummer des Timers. Das Prinzip ist ja bei allen Timern
identisch. Schliesslich funktionieren ja Timer im Prinzip immer gleich:
sie zählen und bei bestimmten Zählerständen passiert was.
> spess53 schrieb:>> Für die Frequenz setzt du 1/2s bzw 1/2ms ein.> Wie bitte?
Vergiss es, das gilt nur, wenn du toggeln würdest.
Christian Q. schrieb:> Also ich brauch den timer mit 1ms fürs multiplexen von led's.
Nur dass du natürlich mit einem OCR Wert von 1000 keine 1 Millisekunde
hast. Ist aber egal, fürs Multiplexen brauchst du sowieso keine so kurze
Zeit
Hi
>Vergiss es, das gilt nur, wenn du toggeln würdest.
Nein. Die Formel ist zum Ausrechnen der Toggle-Frequenz. Und ein
Interruptabstand von 1s würde eine Toggle-Frequenz von 0,5Hz=1/2s
ergeben.
MfG Spess
spess53 schrieb:> Hi>>>Vergiss es, das gilt nur, wenn du toggeln würdest.>> Nein. Die Formel ist zum Ausrechnen der Toggle-Frequenz. Und ein> Interruptabstand von 1s würde eine Toggle-Frequenz von 0,5Hz=1/2s> ergeben.
Sag ich doch (Wir haben aneinander vorbeigeredet)
Wenn ein Timer etwas toggeln soll, kommt der Faktor 1/2 ins Spiel, wenn
es nur um die reine Aufruffrequenz einer ISR geht, kommt kein Faktor.
Besser?
Genau aus dem Grund mag ich die Formeln im Datenblatt nicht. Erstens
weiß ich sie nicht auswendig, zweitens werden sie oft hirnlos
angewendet, drittens braucht man sie nicht, wenn man das Timerprinzip
verstanden hat. Christian hats ja auch in ein paar Minuten mit Überlegen
richtig hingekriegt. Spätestens nach dem 3. Einrichten eines Timers hat
man das ganze durch das Funktionsprinzip schneller berechnet, als man im
Datenblatt die Formel nachschlagen könnte. Und verstanden hat man dann
auch, was man da eigentlich warum macht.
Die 8 LED teilen sich 4 Pins. Ich schalte dann nur die "Spalten" also 2
weitere Pins dafür.
Karl heinz Buchegger schrieb:> fürs Multiplexen brauchst du sowieso keine so kurze> Zeit
Wie viele ms brauch ich ca?
Christian Q. schrieb:> Die 8 LED teilen sich 4 Pins. Ich schalte dann nur die "Spalten" also 2> weitere Pins dafür.>>> Karl heinz Buchegger schrieb:>> fürs Multiplexen brauchst du sowieso keine so kurze>> Zeit>> Wie viele ms brauch ich ca?
Wenn du auf 100 bis 150Hz kommst, dann reicht das.
Der Rest ist wieder Mathe.
Eine 'Schwingung' dauert vom Aufleuchten einer LED-Spalte bis zum
erneuten Aufleuchten.
Wenn das 100 mal in der Sekunde passieren soll, dann dauert ein
einmaliger Zyklus logischerweise 1/100 = 0.01 Sekunden.
In diesen 0.01 Sekunden brauchst du aber 2 Ereignisse, denn die
"Schwingung" geht ja: Einschalten - warten - Ausschalten - warten -
Da sind also 2 Ereignisse, die bearbeitet werden müssen.
D.h. du musst dafür sorgen, dass du alle 0.005 Sekunden einen Interrupt
bekommst (bei angestrebten 100Hz). Das sind dann 50ms
Den OCR Wert darfst du wieder selber ausrechnen :-)
Es ist aber nicht zeitkritisch. Wenn die ISR zu selten aufgerufen wird,
dann flackerts wie Sau und das merkst du.
Übrigens:
>> Geht das mit einem Timer oder muss ich 2>> nehmen?>> Prinzipiell kannst du dich an beide Compare klemmen.
Das war Unsinn. Du brauchst 2 Timer wenn du die Uhr vom Multiplex
trennen willst. Wofür es allerdings keinen wirklichen Grund gibt.
Habe 155 ermittelt.
Leider funktioniert meine Software jetzt nichtmehr. Sehe immer nur die
Oberen LED an. Dieses Einschalten - warten - Ausschalten - warten -
das Warten ist bei mir die Zeit zwischen der ISR.
Also ich schalte im 1. Schritt
Alle LED, Spalten aus.
2. je nach Anzeige den Pin der aktuellen Spalte schalten und Spalte
einschalten
3. ... Zeit bis zum nächsten ISR Aufruf
4. Alle LED, Spalten aus.
5. .. alles genauso, halt nur mit der nächsten Spalte
... Zeit bis zum nächsten ISR Aufruf .. wieder zu 1.
Christian Q. schrieb:> Habe 155 ermittelt.>> Leider funktioniert meine Software jetzt nichtmehr. Sehe immer nur die> Oberen LED an. Dieses Einschalten - warten - Ausschalten - warten -> das Warten ist bei mir die Zeit zwischen der ISR.>> Also ich schalte im 1. Schritt> Alle LED, Spalten aus.> 2. je nach Anzeige den Pin der aktuellen Spalte schalten und Spalte> einschalten> 3. ... Zeit bis zum nächsten ISR Aufruf> 4. Alle LED, Spalten aus.> 5. .. alles genauso, halt nur mit der nächsten Spalte> ... Zeit bis zum nächsten ISR Aufruf .. wieder zu 1.
Jetzt kommt mein Lieblingsspiel:
Anstatt die Dinge zu beschreiben - zeige deinen Schaltplan, zeige dein
Programm. Keine Beschreibung die du geben könntest, zeigt so exakt was
du tatsächlich gemacht hast wie das tatsächliche Programm/Schaltplan.
Und einfacher ist es für dich auch :-)
Der Ablauf ist:
in der ISR
1
alle LED aus
2
je nachdem die Spalte mit den richtigen Werten beschicken
Ich bin mir sich, dass die Umrechnung klappt, liegt also nur am Inhalt
der ISR. Würd gern auf der Ebene mit den Arrays bleiben. Es hängt nur
beim Durchlaufen der Spalten.
Im Anhang ist die Schaltung, woebi ich hier erstmal nur wie gesagt 2x4
(4x2?) aufgebaut habe.
Das kommt mir aber alles sehr bekannt vor!
Ich hab dir doch vor ein paar Tagen die Multiplex Routine geschrieben.
Das war tatsächlich nicht mehr als dieser 5-Zeiler!
Deine LEDs fasst du am besten als ein 6*4 Multiplex auf, bei dem einige
LED einfach nicht besetzt sind.
Christian Q. schrieb:> der ISR. Würd gern auf der Ebene mit den Arrays bleiben.
Das ist Blödsinn.
Du machst dir nur eine Menge Mehrarbeit mit deinem 2D Array
Diesen 5-Zeiler verstehen wir nicht und wir wollen nicht wieder alles
mit der Umrechnung neu machen um in diese Datenstruktur zu kommen.
1
uint8_tledMatrix[4];
2
uint8_tactLine;
3
uint8_tlineCode[]={1<<PB0,1<<PB1,1<<PB2,1<<PB3};
4
5
ISR(TIMER2_COMP_vect)
6
{
7
PORTB=0;// aktuelle Zeile abschalten, welche es auch immer war
8
9
actLine++;// welches ist die nächste Zeile?
10
if(actLine==4)
11
actLine=0;
12
13
PORTD=ledMatrix[actLine];// die enstprechenden Bits für diese Zeile ausgeben
14
PORTB=lineCode[actLine];// und die Zeilentreiber entsprechend einschalten.
15
}
Karl heinz Buchegger schrieb:> Du brauchst jetzt noch eine Funktion, die dir in ledMatrix das jeweils> richtige Bit setzt.> zb wenn die LED in der 3. Spalte / 2. Zeile gesetzt werden soll, dann> muss
Christian Q. schrieb:> Diesen 5-Zeiler verstehen wir nicht und wir wollen nicht wieder alles> mit der Umrechnung neu machen
Du brauchst ganze 2 Funktionen um von der Spalten/Zeilen Denkweise auf
eine Datenstruktur zu kommen, die dir innerhalb der ISR keine
Sonderfälle aufmacht!
2 Funktionen!
Bei denen es darum geht im richtigen Byte das richtige Bit zu setzen
oder zu löschen! Und das ist zu schwer?
>PORTB=0;// aktuelle Zeile abschalten, welche es auch
8
>immerwar
9
>
10
>actLine++;// welches ist die nächste Zeile?
11
>if(actLine==4)
12
>actLine=0;
13
>
14
>PORTD=ledMatrix[actLine];// die enstprechenden Bits für diese
15
>Zeileausgeben
16
>PORTB=lineCode[actLine];// und die Zeilentreiber entsprechend
17
>einschalten.
18
>}
19
>
Alles was du noch brauchst ist eine Funktion die aus Zeile/Spalte in
ledMatrix das jeweils richtige Bit ein bzw. ausschaltet.
Hier ist die Zuordnung der LEDs zu den Bits im Array
Bit 7 6 5 4 3 2 1 0
+---+---+---+---+---+---+---+---+
| | | 21| 17| 13| 9| 5| 1| ledMatrix[0]
+---+---+---+---+---+---+---+---+
| | | 22| 18| 14| 10| 6| 2| ledMatrix[1]
+---+---+---+---+---+---+---+---+
| | | 23| 19| 15| 11| 7| | ledMatrix[2]
+---+---+---+---+---+---+---+---+
| | | 24| | 16| | 8| | ledMatrix[4]
+---+---+---+---+---+---+---+---+
Um also LED 10 (laut Schaltplan) einzuschalten, muss das Bit 2 in
ledMatrix[1] gesetzt werden. In Spalten/Zeilen Notation ist das Zeile 1
(wenn man bei 0 anfängt zu zählen) bzw. Spalte 2 (ebenfalls bei 0
angefangen)
Eine Setzroutine ist also
Da das ganze aber, so wie es aussieht eine Binäruhr werden soll, würde
es sich anbieten, den Multiplex genau anders rum zu machen. Also nicht
über die Zeilen, sondern über die Spalten.
Dann hat man ein 6-er Array. Jedes Array Element steht für genau 1
Spalte und die werden reihum ausgegeben.
Denn: dann braucht man nämlich überhaupt nicht umrechnen :-)
Jede Ziffer, die aus der Zerlegung der Zeit rauskommt, kann direkt so
wie sie ist ausgegeben werden. Ihre jeweilige Binärdarstellung
korrespondiert mit den LEDs.
Das hier müsste dein Programm sein
Studiere es und sieh dir an, wie ich Dinge gelöst habe. Ich mach das ja
nicht, weil es so lustig ist, sondern weil du was lernen sollst. Bringt
doch nichts, wenn du immer nur immer wieder denselben Stiefel
programmierst und dir selber das Leben schwer machst.
PORTD=0;// aktuelle Spalte abschalten, welche es auch immer war
45
46
actCol++;// welches ist die nächste Spalte?
47
if(actCol==6)
48
actCol=0;
49
50
PORTB=ledMatrix[actCol];// die enstprechenden Bits für diese Zeile ausgeben
51
PORTD=colCode[actCol];// und die Spaltentreiber entsprechend einschalten.
52
53
//
54
// die Uhr weiterstellen falls notwendig
55
// die ISR wird 600 mal in der Sekunde aufgerufen
56
// 8000000 Hz
57
// Prescaler: 1
58
// Top Wert der CTC: 13333
59
// 8000000 / 1 / 13333 -> 600
60
//
61
subSec++;
62
if(subSec==600){
63
subSec=0;
64
65
sekunde++;
66
if(sekunde==60){
67
sekunde=0;
68
69
minute++;
70
if(minute==60){
71
minute=0;
72
73
stunde++;
74
if(stunde==24)
75
stunde=0;
76
}
77
}
78
79
ledMatrix[0]=stunde/10;
80
ledMatrix[1]=stunde%10;
81
82
ledMatrix[2]=minute/10;
83
ledMatrix[3]=minute%10;
84
85
ledMatrix[4]=sekunde/10;
86
ledMatrix[5]=sekunde%10;
87
}
88
}
Disclaimer: Da ich deine Hardware nicht hier habe, kann ich das nur im
Simulator testen. Bei 8Mhz stimmt das Timing und auch die Portpins
schalten IMHO so wie es die Schaltung erfordert.
macht, wenn du es dir genau überlegst, genau dasselbe wie (aus deinem
Code)
1
switch(ausgabe_spalte){
2
case0:
3
PORTD=(1<<PD0);
4
break;
5
case1:
6
PORTD=(1<<PD1);
7
break;
8
case2:
9
PORTD=(1<<PD2);
10
break;
11
case3:
12
PORTD=(1<<PD3);
13
break;
14
case4:
15
PORTD=(1<<PD4);
16
break;
17
case5:
18
PORTD=(1<<PD5);
19
break;
20
default:
21
PORTD=0;
22
break;
23
}
(nur dass es bei dir ausgabe_spalte heißt und bei mir actCol).
Nur ist es kürzer und leichter zu überblicken. Aber funktional (da
actCol nicht größer als 5 werden kann) sind sie gleichwertig! Ich hab
einfach nur das jeweilige Bitmuster, dass bei einem bestimmten Wert
ausgegeben werden muss, in ein Array gelegt und benutze den Wert um
damit aus dem Array das jeweils richtige Bitmuster zu holen. Du benutzt
den Wert um in einem switch-case den Fall anzuspringen um dort dann das
jeweils richtige Bit auszugeben. Im Endeffekt läuft es aber auf exakt
die gleiche Funktion an den Portpins hinaus. Je nach Wert wird ein
anderer Portpin auf 1 gesetzt und alle anderen auf 0.
Christian Q. schrieb:> und wir wollen nicht wieder alles> mit der Umrechnung neu machen
Und manchmal muss man auch akzeptieren, dass man bereits geschriebene
Dinge wieder verwirft, wenn es einen guten Grund dafür gibt.
Nur Neulinge kleben an einmal geschriebenem Code fest wie das Pech im
T-Shirt. Ich hab im Lauf der Jahre wahrscheinlich mehr Code umgearbeitet
und wieder weggeschmissen, als dann tatsächlich übrig geblieben ist. Am
Anfang wars mehr, mit der Zeit wirds weniger. Man lernt ja auch mit der
Zeit was funktioniert und was nicht.
Dankeschön für deine Mühe.
Wir sind echt verwundert wie "einfach" das zu machen geht. Konnten es
aber auch erst mit deinem vollständig angepassten Code sehen, wie nun
letzlich das colCode[] aus dem Vorpost zum Einsatz kam.
Am meisten sind wir überrascht, dass garkeine Umrechnung nach Binär
gebraucht wird (anscheinend übernimmt uint8_t das von allein). Wir
denken, das war auch der Punkt warum das in zweidimensionale Arrays
ausgeartet ist.
1 Sekunde dauert mit dem Code 8. Auf subSec == 75 geändert haut es hin.
Oder sollte man am Timer ansetzen?
Christian Q. schrieb:> Dankeschön für deine Mühe.> Wir sind echt verwundert wie "einfach" das zu machen geht.
Ihr habt den Fehler gemacht, euch auf ein Schema einzulassen (2D Array)
und dann habt ihr das auf Biegen und Brechen durchgezogen ohne euch je
zu fragen wie sinnvoll das noch ist bzw. wie man es noch anders machen
könnte.
>> Am meisten sind wir überrascht, dass garkeine Umrechnung nach Binär> gebraucht wird (anscheinend übernimmt uint8_t das von allein).
IN einem Computer ist alles Binär!
Alles!
Jede Zahl, jedes Zeichen, jeder Befehl, alles!
Erst bei der Ausgabe trickst man es so hin, dass das Bitmuster 00000110
mir dem Zeichen '6' auf einer Anzeige angezeigt wird. Oder aber man gibt
das Bitmuster gleich auf ein paar LED einfach aus und hat dann 2
leuchtende LED.
Ganz im Gegenteil: eine binäre Ausgabe ist immer am einfachsten. Nur
wenn man eben nicht binär haben will, muss man Aufwand treiben.
Habt ihr denn nie ausprobiert einfach mal eine Variable hochzählen zu
lassen und ihr Bitmuster auf einen Port mit 8 LED auszugeben?
> 1 Sekunde dauert mit dem Code 8.
Dann läuft dein µC nicht mit 8Mhz sondern nur mit 1Mhz :-)
> Oder sollte man am Timer ansetzen?
Weder noch.
Du sollst den µC auf die richtige Taktfrequenz einstellen.
Nur dadurch dass du F_CPU auf 8000000 stellst, arbeitet der µC noch
lange nicht mit 8Mhz
Karl heinz Buchegger schrieb:>> 1 Sekunde dauert mit dem Code 8.>> Dann läuft dein µC nicht mit 8Mhz sondern nur mit 1Mhz :-)
Ähm okay.. in den Projekteinstellungen steht 8Mhz. confused
Karl heinz Buchegger schrieb:> Habt ihr denn nie ausprobiert einfach mal eine Variable hochzählen zu> lassen und ihr Bitmuster auf einen Port mit 8 LED auszugeben?
Natürlich :) Das Prinzip des Dualen-Systems war nicht das Problem bei
der Sache, sondern die Umsetzung. (Bitmanipulation, die Bitmuster mit
ein paar Zeichen ^&~ einfach zu ändern)
//Edit bei den Fuses aus Versehen 8 Mhz ext. Osc statt int. ausgewählt.
Ist er jetzt tot?
Christian Q. schrieb:> Karl heinz Buchegger schrieb:>>> 1 Sekunde dauert mit dem Code 8.>>>> Dann läuft dein µC nicht mit 8Mhz sondern nur mit 1Mhz :-)>> Ähm okay.. in den Projekteinstellungen steht 8Mhz. confused
Auch die Projekteinstellungen sind uninteressant.
Entscheidend ist, wie die Fuses im µC selber stehen!
Die entscheiden wie schnell der µC arbeitet.
Ob Projekteinstellungen oder F_CPU selber setzen: Das hat nur
informellen Charakter für das C-Programm.
Anders ausgedrückt:
Du kannst einem Trabi einen Tacho einbauen, auf dem 300km/h
Spitzengeschwindigkeit draufsteht. Kannst du machen. Du kannst auch 500
ans Ende der Skala schreiben.
Trotzdem wird der real nicht schneller als 90 fahren.
Wenn du dann allerdings ausrechnen musst wie lang du von München nach
Berlin unterwegs bist und du benutzt deine Tachowerte, laut denen du mit
knapp 450 Sachen unterwegs bist, dann werden die Ergebnisse nicht
stimmen :-)
Karl heinz Buchegger schrieb:> Anders ausgedrückt:> Du kannst einem Trabi einen Tacho einbauen, auf dem 300km/h> Spitzengeschwindigkeit draufsteht. Kannst du machen. Du kannst auch 500> ans Ende der Skala schreiben.> Trotzdem wird der real nicht schneller als 90 fahren.> Wenn du dann allerdings ausrechnen musst wie lang du von München nach> Berlin unterwegs bist und du benutzt deine Tachowerte, laut denen du mit> knapp 450 Sachen unterwegs bist, dann werden die Ergebnisse nicht> stimmen :-)
Schreibst du das immer? Kommt mir so bekannt vor. Bin aber davon
ausgegangen, dass AVR Studio die Fuses nach den Projekteinstellungen
belegt.
Edit bei den Fuses aus Versehen 8 Mhz ext. Osc statt int. ausgewählt.
Ist er jetzt tot? Hab ihn auf dem Pollin Eval Board. Ist doch eigentlich
ein ext. Osc dran...