Nebenuhrwerk "Digitalisieren" die zweite

OP #3755740
Lesenswert?

Hallöchen,

ich möchte zzt. ein Nebenurwerk (Bürk NU67) digitalisieren mit einem 
Atmega328P.

Ich hab an den besagten uC ein Quarzoszillator mit 16Mhz gehängt, sodass 
ich eine zuverlässige Frequenz habe. Allerdings bekomm ichs nicht hin 
mit meinen Ausgerechneten Werten eine Sekunde zu definieren.

Ich wollte über den Timer1 per CTC ein Signal von 1sek rausfiltern. 
Dieses Signal soll dann eben einen Sekundenzähler raufzählen und nach 60 
Sekunden einen Impuls von 800ms rausgeben.
Dieses Signal muss immer Wechseln, da ich das Uhrwerk per H-Brücke 
ansteuer, sodass die Polarität immer wieder geändert wird.

Ich musste schon den _delay_ms() "austricksen" indem ich sage das F_CPU 
4000000UL (4MhZ) ist, obwohl meine CPU_CLK bei 2Mhz liegen müsste (16MhZ 
mit Fuse DIV8)

Im Moment ist es so das ich am Ausgang 3 (PINB2) in einer Sekunde 4 
Impulse bekomme, obwohl dieser Sekündlich ausgelöst werden sollte (siehe 
funktion sekunde()).

Ich Danke schonmal für die Mühen.

Anbei mein Code:
1
/*
2
 * Nebenuhrwerk_Digitalisieren.cpp
3
 *
4
 * Created: 13.06.2014 11:24:10
5
 *  Author: h0d3nt3uf3l
6
 */ 
7

8

9
#include <avr/io.h>
10
#define F_CPU 4000000UL //16MhZ externer Oszillator
11
#include <util/delay.h>
12
#include <avr/interrupt.h>
13
#define Ausgang1 PINB0
14
#define Ausgang2 PINB1
15
#define Ausgang3 PINB2
16
#define Ausgang4 PINB3
17

18
int sekunden = 0;
19
bool wechsel_merker;
20

21
void minute();
22
void sekunde();
23

24
int main(void)
25
{
26
  
27
  //Ausgänge definieren
28
  DDRB |= (1<<Ausgang1) | (1<<Ausgang2) | (1<<Ausgang3) | (1<<Ausgang4);
29
  
30
  //Timer1 einstellen
31
  TCCR1B = (1<<CS10) | (1<<CS11) | (1<<WGM12); //Prescaler von 64 eingestellt, OCR1A wird auf null gesetzt
32
  OCR1A = 15624; //Errechnet für 1Hz = 15625 bei Prescaler von 64
33
  TIMSK1 = (1<<OCIE1A); //Compare-Interrupt aktivieren
34
  
35
  //Alle Interrupts aktivieren
36
  sei();
37
  
38
    while(1)
39
    {
40
        //TODO:: Please write your application code 
41
    }
42
  
43
}
44

45
void sekunde()
46
{
47
  sekunden++;
48
  
49
  if (sekunden >= 60)
50
  {
51
    sekunden = 0;
52
    minute();
53
  }
54
  
55
  PORTB |= (1<<Ausgang3);
56
  _delay_ms(10);
57
  PORTB &= ~(1<<Ausgang3);
58
  return;
59
  
60
}
61

62
void minute()
63
{
64
  if (wechsel_merker == false)
65
  {
66
    PORTB |= (1<<Ausgang1);
67
    _delay_ms(800);
68
    PORTB &= ~(1<<Ausgang1);
69
    wechsel_merker = true;
70
    return;
71
  } else if (wechsel_merker == true)
72
  {
73
    PORTB |= (1<<Ausgang2);
74
    _delay_ms(800);
75
    PORTB &= ~(1<<Ausgang2);
76
    wechsel_merker = false;
77
    return;
78
  }
79
}
80

81
ISR (TIMER1_COMPA_vect)
82
{
83
  sekunde();
84
}
OP #3755764
Lesenswert?

Danke für die schnelle Antwort.

Den Prescaler zu verändern hat keinen Sinn, trotzdem hab ichs gemacht 
und jetzt kommt der sekundenimpuls alle 4 sekunden.

Ich habs try-and-error mäßig auf 4mhz gestellt, weil so die exakten 
impulse rauskommen, ich hab keine ahnung warum.

Ich messe alles mit einem DS1052 von Rigol, sollte also schon hinhauen.
OP #3755803
Lesenswert?

Also, Fuse CKDIV8 ist gesetzt, hab jetzt sogar mal per Hand den 
Prescaler auf 4 gestellt:
1
  //Prescaler auf 4 stellen.
2
  CLKPR = (1<<CLKPCE) | (1<<CLKPS1);
So sollte ich wirklich 4MhZ haben.
F_CPU blieb auf 4 Mhz und der delay arbeitet nach wie vor hervorragend.
Den Prescaler vom Timer hab ich nun auf 256 gestellt und nun habe ich 
auch einen Sekündlichen ausschlag.
Aber diesen Prescaler bräuchte ich bei 8Mhz?

(CKSEL ist auf EXTCLK_6CK_14CK_65MS gestellt (Atmel Studio))
Gast #3755816
Lesenswert?

Sören Kleer schrieb:
> Also, Fuse CKDIV8 ist gesetzt, hab jetzt sogar mal per Hand den
> Prescaler auf 4 gestellt:  //Prescaler auf 4 stellen.
>   CLKPR = (1<<CLKPCE) | (1<<CLKPS1);
> So sollte ich wirklich 4MhZ haben.
> F_CPU blieb auf 4 Mhz und der delay arbeitet nach wie vor hervorragend.
> Den Prescaler vom Timer hab ich nun auf 256 gestellt und nun habe ich
> auch einen Sekündlichen ausschlag.
> Aber diesen Prescaler bräuchte ich bei 8Mhz?
>
> (CKSEL ist auf EXTCLK_6CK_14CK_65MS gestellt (Atmel Studio))

Ich meinte vorhin den Prescaler des Timers.
Bei 16MHz Systemtakt und Prescaler (Timer1) von 1024 kommst du mit OCR1A 
= 15624 auf 1s. Aber du hast ja den System-Prescaler noch gesetzt und 
außerdem CLKDIV8. Das wußte ich ja nicht. Hat das einen Grund?
OP #3755823
Lesenswert?

Deiner rechnung Stimme ich zu ;) allerdings dachte ich ich muss diese 
hier nehmen: f (OCnA) =  f clk/io / ( 2 x N x (1 + OCR1A))
Wobei N = der Prescaler ist.

So steht es zumindest im Datenblatt auf Seite 124.

Aber Okay, ist mir nun auch zu blöd :D es funktioniert.
Dankeschön
Gast #3755828
Lesenswert?

Die Formel ist für das Toggeln des OCR-Pins gültig. Deswegen die "2". 
Wenn du eine ISR-Routine aufrufen willst, muß die 2 weg. Zum Toggeln des 
Pins gehören ja immer zwei Aufrufe (1x low-high und 1x high-low). 
Deswegen muß das Toggeln mit der doppelten Frequenz erfolgen wie der 
Aufruf der ISR.

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