Rechenproblem mit Counter

Gast #3892974
Lesenswert?

Hallo,

ich bin gerade dabei mir einen Wecker selbst zu bauen. Als Basis dient 
der ATmega 16.

Momentan arbeite ich an der Sequenz, die die Netzfrequenz als Zeitgeber 
nutzen soll. Dazu will ich einen Counter nehmen.

Mein Problem ist eigentlich ein simples Rechenproblem. Wie hoch muss ich 
den Counter vorab füllen, damit bei 100 Ticks pro Sekunde nach genau 
einer Minute ein Interrupt ausgelöst wird?

Rein logisch wäre ich jetzt so vorgegangen:
100 Ticks sind eine Sekunde
6000 Ticks sind eine Minute
Maximalwert des Timer1 als Counter: 65535
65535 - 6000 = 59535

Ist das korrekt? Ich bin etwas verunsichert weil der Counter ja bei 0 
anfängt zu zählen.

Wäre sehr nett wenn da jemand drüberschaut!
Gast #3892984
Lesenswert?

Netzfrequenz, also 50 Hz. Da ich sie aber zuerst mit einem Trafo auf 
gefahrlose 6V reduziere und dann gleichrichte (Brückengleichrichter) 
verdoppelt sich die Frequenz.

Also 100 Hz.

@chaoskind: Wie geht das? Bisher habe ich immer mit vorab gefüllten 
Countern gearbeitet. Zum CTC-Modus habe ich hier nur ein Beispiel für C 
gefunden, ich arbeite jedoch mit Bascom :/
#3892989
Lesenswert?

Hm mit Bascom kann ich dir da auch nicht weiterhelfen. Davon hab ich 
keine Ahnung. Aber prinzipiell kannst du den CTC-Modus so einstellen, 
das er entweder bis zum Wert im ICR-Register zählt, oder bis zum Wert im 
OCR-Register. Dann musst du noch den Interrupt und die globalen 
Interrupts freigeben. Frag mich aber nicht, wie das in Bascom geht...

In Assembler ist das auch recht fix gelöst zur Not. (Fand ich recht 
leicht zu lernen, zumindest in den Grundzügen, und man lernt den 
Controller vor allem sehr gut kennen)
Gast #3892998
Lesenswert?

Udo schrieb:
> Wieso verdoppelt sich die Frequenz nach dem
> gleichrichten ?

Ich klappe doch beim Brückengleichrichter die negativen Halbwellen nach 
oben. Das Signal wird durch einen Komparator digitalisiert und 
anschließend auf den Timerpin gelegt.
#3893000
Lesenswert?

Rechenproblem schrieb:
> Ist das korrekt? Ich bin etwas verunsichert weil der Counter ja bei 0
> anfängt zu zählen.

Der Counter fängt nicht bei 0 an, sondern hört bei 0 auf. Die 0 
entspricht 65536. Also ist dein Preload-Wert 65536 - 6000.
Diesen Prload schreibst du in der OVF-ISR in den TCNT, der jetzt noch 0 
ist.
Aber beim nächsten Takt steht Preload im Counter und wird um 1 erhöht.

Aber das ist Steinzeittechnik. Nimm den CTC. das wird auch in Bascom 
gehen.

mfg.
(Firma: Vescomp) #3893003
Lesenswert?

Rechenproblem schrieb:
> Maximalwert des Timer1 als Counter: 65535
> 65535 - 6000 = 59535
>
> Ist das korrekt? Ich bin etwas verunsichert weil der Counter ja bei 0
> anfängt zu zählen.
>
> Wäre sehr nett wenn da jemand drüberschaut!

 In CTC-Mode wird auch die Null mitgerechnet und gezählt.
 Maximalwert interessiert dich nicht, du brauchst 6000, also rechnest
 du 6000 - 1 = 5999, das ist der Wert, den du in Timer1 Vergleichs-
 register schreiben must.
 Wahrscheinlich so etwas wie: OCR1A = 5999
#3893012
Lesenswert?

Rechenproblem schrieb:
> Netzfrequenz, also 50 Hz. Da ich sie aber zuerst mit einem Trafo auf
> gefahrlose 6V reduziere und dann gleichrichte (Brückengleichrichter)
> verdoppelt sich die Frequenz.

Wenn ich als Arduino-Bastler die Netzfrequenz von einem Netzkabel für 
einen Atmega-Controller abgreifen möchte, dann ziehe ich einen Draht von 
einem Input-Pin zum nächsten Netzkabel und klebe es dort mit etwas 
Klebeband an die Isolierung oder knote es mit genau einer Windung und 
einem Hausfrauenknoten an das Netzkabel. Macht 100 Hz am Input-Pin ganz 
ohne Trafo und ohne Gleichrichter.
#3893017
Lesenswert?

Jürgen S. schrieb:
> Wenn ich als Arduino-Bastler die Netzfrequenz von einem Netzkabel für
> einen Atmega-Controller abgreifen möchte, dann ziehe ich einen Draht von
> einem Input-Pin zum nächsten Netzkabel und klebe es dort mit etwas
> Klebeband an die Isolierung oder knote es mit genau einer Windung und
> einem Hausfrauenknoten an das Netzkabel. Macht 100 Hz am Input-Pin ganz
> ohne Trafo und ohne Gleichrichter.

Ja nee, is klar.
Deswegen ist ein Arduino auch genau das richtige für dich.
Die Idioten, die nicht so gewieft sind wie du, machen das halt ein 
bisschen komplizierter.

mfg.
Gast #3893018
Lesenswert?

Kurzes Feedback: Ohne CTC funktioniert es. Da ich aber eigentlich 
Steinzeittechnik vermeiden will versuche ich mich am CTC, leider haut es 
nicht hin.
1
$regfile = "M16def.dat"
2
$crystal = 8000000
3
$hwstack = 100
4
$swstack = 100
5
$framesize = 100
6

7

8
Config Portb.0 = Output
9
Config Pinb.1 = Input
10

11
Frequenz Alias Pinb.1
12
Kontrolle Alias Portb.0
13

14
Dim Minuten As Byte
15

16
Config Timer1 = Counter , Edge = Rising , Clear Timer = 1
17
Ocr1a = 6
18
On Ocr1a Plusminute
19
Enable Timer1
20
Enable Interrupts
21

22
Minuten = 0
23

24

25
Do
26
Loop
27

28
End
29
Plusminute:
30
Toggle Kontrolle
31
Timer1 = 0
32
Minuten = Minuten + 1
33
Return

Der Compiler meckert, dass OCR1A ein unbekannter Interrupt wäre. Was 
habe ich falsch gemacht/vergessen?
Gast #3893028
Lesenswert?

Thomas Eckmann schrieb:
> Rechenproblem schrieb:
>> Der Compiler meckert, dass OCR1A ein unbekannter Interrupt wäre. Was
>> habe ich falsch gemacht/vergessen?
>
> Der Interrupt-Vektor heisst TIMER1_COMPA. Entweder heisst der in Basic
> genauso oder es gibt eine Entsprechung dafür.
>
> mfg.
Danke, dann mache ich mich mal auf die Suche wie der heißt. TIMER1_COMPA 
heißt er offensichtlich nicht, gibt ebenfalls eine Fehlermeldung.
holger schrieb:
> Bascom verwendet

Woran erkennt man den Profi? Er lässt ihn jederzeit und überall 
raushängen.
(Firma: Vescomp) #3893037
Lesenswert?

Rechenproblem schrieb:
>
> Der Compiler meckert, dass OCR1A ein unbekannter Interrupt wäre. Was
> habe ich falsch gemacht/vergessen?

 Wahrscheinlich heisst der nur OC1A

 Das ist doppelt falsch:
Ocr1a = 6
On Ocr1a Plusminute

 Sollte heissen:
 Ocr1a = 5999
 On Oc1a Plusminute

 Und das ist zuviel:
> Plusminute:
> Toggle Kontrolle
> Timer1 = 0
> Minuten = Minuten + 1
> Return
 Timer1 ist schon auf Null, nicht nochmal nullen.
Gast #3893040
Lesenswert?

OK, du erzeugst aus der Netzfrequenz nach Trafo und 2-Weg-
Geichrichter einen 100-Hz-Trigger für deine Uhrenschaltung.

Hat schon vor 50 Jahren jeder Radiowecker so gemacht - sollte
also vom Prinzip her funktionieren.

Ich kann dir aber nicht glauben, dass du schon vorher
mit voreingestellten Zählern was sinnvolles gemacht hast,
weil es bei Zählern viel zu aufwändig ist, aus ihrem Maximalwert
was abzuleiten! Der ÜBERLAUF beim nächsten Zählschritt, wo sie
wieder auf NULL gehen, ist leicht zu detektieren und wird
daher üblicherweise verwendet.

Somit musst du mit 59536 starten.
Überlauf ist bei 65536 (= 0 bei 16 Bit Auflösung).
Vor dem nächsten Zähltakt musst du den Zählerstand wieder
auf 59536 setzen. UMSTÄNDLICH!

Benutze den CTC-Mode (max = 5999) und der 16-Bit-Zähler
teilt genau durch 6000.
Mit Overflow-, oder Compare-Match-Interrupt kannst du nun die
Minuten zählen.
Gast #3893042
Lesenswert?

1) hättest Du die Hilfe zu On Interrupt gelesen, würdest Du den 
richtigen Namen kennen.
2) der Compare-Interrupt muss enabled werden, wird dagegen TimerX 
enabled, so betrifft das den betreffenden Overflow-Interrupt.
Gast #3893089
Lesenswert?

Oldie schrieb:
> Ich kann dir aber nicht glauben, dass du schon vorher
> mit voreingestellten Zählern was sinnvolles gemacht hast,
> weil es bei Zählern viel zu aufwändig ist, aus ihrem Maximalwert
> was abzuleiten! Der ÜBERLAUF beim nächsten Zählschritt, wo sie
> wieder auf NULL gehen, ist leicht zu detektieren und wird
> daher üblicherweise verwendet.
>
> Somit musst du mit 59536 starten.
> Überlauf ist bei 65536 (= 0 bei 16 Bit Auflösung).
> Vor dem nächsten Zähltakt musst du den Zählerstand wieder
> auf 59536 setzen. UMSTÄNDLICH!
1
$regfile = "M16def.dat"
2
$crystal = 8000000
3
$hwstack = 100
4
$swstack = 100
5
$framesize = 100
6

7
Const Preset = 59536
8
'Const Preset = 65533
9
Dim Minuten As Byte
10
Dim X As Byte
11

12
Config Portd.6 = Output
13
Config Pinb.1 = Input
14

15
Frequenz Alias Pinb.1
16

17
Config Timer1 = Counter , Edge = Rising
18
On Timer1 Plusminute
19
Timer1 = Preset
20
Enable Timer1
21
Enable Interrupts
22

23

24
Do
25
Loop
26

27
End
28
Plusminute:
29
Timer1 = Preset
30
Toggle Portd.6
31
Minuten = Minuten + 1
32
Return
#3893527
Lesenswert?

Rechenproblem schrieb:

>
1
> ...
2
>


Feigling.
Es wird sich doch wohl irgendwo im Web ein BASCOM Tutorial auftreiben 
lassen, bei dem gezeigt wird, wie man den CTC Modus benutzt und wie der 
Interrupt heisst, an den man sich klemmen muss. Ich wette Google findet 
sowas in weniger als 0.1 Sekunden.

Im übrigen wird deine Lösung nicht richtig funktionieren. Bei einer Uhr 
ist es nun mal wichtig, dass ausnahmslos alle Ticks richtig gezählt 
werden. Fällt ein Fehler da in der Testphase von 10 Minuten nicht weiter 
auf, spätestens nach 2 Monaten fällt der auf, wenn sich der 
Einzeltickfehler in den Minutenbereich aufsummiert hat. Diese 
vermaledeite Timer-Preset Lösung ist dann nur auf den ersten Blick 
einfacher. Spätestens wenn dann das Programm umfangreicher wird, 
vielleicht noch 1 oder 2 andere Interrupts dazu kommen (um zb eine 
7-Segment Anzeige zu multiplexen), ist es dann ganz schnell Essig mit 
der Langzeit-Genauigkeit.
Gast #3894054
Lesenswert?

Ich habe mich nochmal am CTC versucht, leider erfolglos. Dazu habe ich 
den halbe Nachmittag verbracht um mich über die Register schlauzumachen, 
die ich brauche. :/
1
$regfile = "M16def.dat"
2
$crystal = 8000000
3
$hwstack = 100
4
$swstack = 100
5
$framesize = 100
6

7
Config Portd.7 = Output
8
Config Portd.5 = Output
9

10
'### TIMER INITIALISIERUNG ###
11
Tccr1a = 01000000
12
Tccr1b = 01001111
13
Ocr1a = 3
14
Timsk = 01000000
15
'### ENDE TIMER INITIALISIERUNG ###
16

17

18
Enable Interrupts
19
Enable Oc1a
20
Enable Timer1
21
Enable Compare1a
22
On Oc1a Plusminute
23

24

25
Do
26
Toggle Portd.7
27
Waitms 2500
28
Loop
29
End
30

31
Plusminute:
32
Waitms 10000
33
Return
Die LED toggelt, aber egal wie oft ich an T1 (Timer1/Counter clock 
source) ein positives High-Signal anlege, es kommt nicht zur Pause von 
10 s.
Gast #3894065
Lesenswert?

Rechenproblem schrieb:
> Tccr1a = 01000000
> Tccr1b = 01001111
> Ocr1a = 3
> Timsk = 01000000
>
> Die LED toggelt, aber egal wie oft ich an T1 (Timer1/Counter clock
> source) ein positives High-Signal anlege, es kommt nicht zur Pause von
> 10 s.

Das liegt daran, dass diese Art Konfiguration völliger Quatsch ist, denn 
wenn schon Binär, dann muss ein "&b" vorangestellt werden, ansonsten ist 
01001111 einfach eine Million eintausend einhundertelf und das geht 
schlecht in ein 8-Bit Register rein.
Gast #3894138
Lesenswert?

Daniel schrieb:
> Hallo an alle,
>
> darf ich mal fragen, warum die Netzfrequenz als Zeitzähler genommen
> werden soll und nicht ein 32,768 kHz Uhrenquarz??

Darfst Du. Antwort wirst Du aber nicht von ALLEN kriegen, sondern
bestenfalls vom TO.

Es ist gleichgültig, warum er die Netzfrequenz benutzen will, er will
es.

-----------------------------------------------------------------------
@TO
Lege mal die 100 Hz in echt an und lade das Regsietr OCR1A mit 100.
Schließe an PortD.5 eine weitere LED an. Die muß dann mit 1HZ blinken.

Das Programm erscheint mir so in Ordnung.
Gast #3894281
Lesenswert?

Könnte es eventuell so funktionieren und ausreichende Genauigkeit 
bringen? Ich verpasse ja keine Ticks, weil der Interrupt quasi nur 
pausiert wird während der Ausführung der if-Schleife und danach 
nachgeholt wird.
1
$regfile = "attiny45.dat"
2
$crystal = 8e6
3
$hwstack = 50
4
$swstack = 50
5
$framesize = 50
6

7
Dim Zeit As Long
8

9
Config Portb.3 = Output
10
Config Portb.4 = Output
11

12
 Config Int0 = Rising                                       'configuriere Int0 Auf Rising
13
 Enable Interrupts                                          'einschalten der Interrupts
14
 Enable Int0                                                'einschalten von Interrupt Int0
15
 On Int0 Isr_von_int0                                       'springe zu Isr_von _Int0
16

17
Portb.4 = 1
18
Portb.3 = 1
19
Do
20
If Zeit = 3000 Then
21
Disable Interrupts
22
Zeit = 0
23
Enable Interrupts
24
Toggle Portb.3
25
End If
26

27
 Loop
28
 End
29

30
Isr_von_int0:                                               'ISR von Int0
31
Zeit = Zeit + 1
32
Return
Dann hätte ich als Ausgang eine Flanke pro Minute, die ich dann in einem 
anderen µC auswerten kann. Ein Interrupt pro Minute sollte nicht 
wirklich ein Problem darstellen, weil der andere µC keine zeitkritischen 
Aufgaben durchführen muss.
Gast #3894305
Lesenswert?

Rechenproblem schrieb:
> Wurde korrigiert, leider erfolglos.

Rechenproblem schrieb:
> Ich habe mich nochmal am CTC versucht, leider erfolglos. Dazu habe
> ich den halbe Nachmittag verbracht um mich über die Register
> schlauzumachen,
> Timsk = 01000000

War leider nix, sonst wäre TIMSK richtig. Auch mit &b wird das also nix.

Es wäre problemlos mit den Config-Befehlen gegangen, aber wenn Du schon 
die Register direkt einstellen willst: es gibt auch Klarnamen für die 
Konfigurationbits.

Darum schrieb ich in Bezug auf diese Binärkonfiguriererei auch von 
Quatsch, es ist einfach fehleranfällig, besonders dann, wenn man mit der 
grundsätzlichen Anwendung der Sprache schon Probleme hat.
Gast #3894314
Lesenswert?

Hm...
ich habe hier nachgelesen:
http://www.avrbeginners.net/architecture/timers/timers.html
Da stehen folgende Erklärungen bei:
######
TOIE1: Timer Overflow Interrupt Enable (Timer 1); If this bit is set and 
if global interrupts are enabled, the micro will jump to the Timer 
Overflow 1 interrupt vector upon Timer 1 Overflow.

OCIE1A: Output Compare Interrupt Enable 1 A; If set and if global 
Interrupts are enabled, the micro will jump to the Output Compare A 
Interrupt vetor upon compare match.

TICIE1: Timer 1 Input Capture Interrupt Enable; If set and if global 
Interrupts are enabled, the micro will jump to the Input Capture 
Interrupt vector upon an Input Capture event.

TOIE0: Timer Overflow Interrupt Enable (Timer 0); Same as TOIE1, but for 
the 8-bit Timer 0.
######
Das Bit habe ich deshalb bei OCIE1A gesetzt, weil ich doch will, dass 
ein Interrupt ausgelöst wird wenn mein OCR1A-Registerwert mit TCNT 
übereinstimmt.

Wie konfiguriere ich das denn nichtbinär?
Gast #3894337
Lesenswert?

Das:

Timsk = &b01000000

setzt das Bit: TOIE2 = Timer Overflow Interrupt Enable 2
Die 2 bezeichnet die Nummer des Timers, deswegen wird das nix.

So könnt's was werden:

Config Timer1 = Counter, Clear Timer = 1
COMPARE1A = 3
On COMPARE1A DeineISR
Enable COMPARE1A
Enable Interrupts
Gast #3894362
Lesenswert?

Stimmt, ich habs gerade im Datenblatt auf S. 85 gefunden. Dann steht bei 
deren Tutorial was falsches da oder es gilt für eine andere CPU. Deins 
sieht sehr logisch aus, danke dafür.

Aber nur zum Verständnis: Laut Datenblatt wäre das Bit für OCIE1A im 
TIMSK-Register das 4. Also würde der korrekte TIMSK-Code lauten:

&b00010000

oder?
Gast #3894379
Lesenswert?

heiner schrieb:
> deren Tutorial was falsches da oder es gilt für eine andere CPU.

Zitat: This description is based on the AT90S2313.

> Aber nur zum Verständnis: Laut Datenblatt wäre das Bit für OCIE1A im
> TIMSK-Register das 4. Also würde der korrekte TIMSK-Code lauten:
>
> &b00010000
>
> oder?

Richtig, es ist Bitnummer 4 und das fünfte Bit.

Oder: TIMSK.OCIE1A = 1
Oder: TIMSK = Bits(OCIE1A)
Gast #3894391
Lesenswert?

Danke für die Aufklärung. Dann setze ich morgen mal den Quellcode ein, 
den du mir gezeigt hast.

Eine Frage noch: Muss ich nicht noch festlegen, dass er nur die 
Rising-Flanke zählen darf?

Also die Zeile
Config Timer1 = Counter, Clear Timer = 1
noch ergänzen
Config Timer1 = Counter, Clear Timer = 1, Edge = Rising
?
Denn wenn ich einfach nur bei einem Eingang zählen lasse kriege ich ja 
nicht das gewünschte Ergebnis weil ein Takt von meinem Taktgeber ja 
deutlich länger als ein Takt meines Prozessors dauert.
Gast #3894402
Lesenswert?

Er zählt entweder bei steigender oder fallender Flanke, wobei es eben 
nur um die Flanke geht, die ordentlich kommen muss. Wie lange danach der 
Level gehalten wird, ist egal. Bei der Änwendung hier, sollte es egal 
sein, ob fallende oder steigende Flanke.

Da das Beispiel in der Hilfe gezielt auf "falling" konfiguriert, dürfte 
"rising" die Standardeinstellung sein. Schadet aber nix, es 
hinzuschreiben.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren