Forum: Mikrocontroller und Digitale Elektronik Interruptproblem (Variable wird geändert)


von Niklas N. (niklas_n)


Lesenswert?

Ich mach eine Wordclock mit DCF77 und hab ein Problem und zwar beim 
initialisieren ändert es die werte hs auf 256 und n auf 258 ohne das ich 
das will. Woran könnte das liegen? ich hab schon vieles ausprobiert, 
leider ist das Problem noch immer da...
1
/* Uhr_DCF.c
2
 *    Created: 19.02.2012 23:45:47
3
 *     Author: Niklas Neumeister
4
 */ 
5
6
#include <stdint.h>
7
#include <stdbool.h>
8
#include <stdio.h>
9
#include <avr/io.h>
10
#include <avr/interrupt.h>
11
#include <avr/portpins.h>
12
13
volatile int hh = 0, mm = 0, ss = 0, hs = 0, mode = 0, counter = 0, n = 0, mmc = 0, hhc = 0, z = 1, DCF[60], i = 0x00, light = 0x00;
14
bool time = false, zu = false;
15
16
void portinit(void)      //Ein- und Ausgaenge
17
{
18
  DDRA = 0xFE;      //PA7 Eingang sonst alle Ausgang
19
  DDRB = 0xFF;
20
  DDRC = 0xFF;
21
  DDRD = 0xFB;
22
  PORTA = 0x00;      //Standart auf low
23
  PORTB = 0x00;
24
  PORTC = 0x00;
25
  PORTD = 0x00;
26
}
27
void timerinit(void)        //Timer Interrupts
28
{ 
29
    //Timer0
30
  TCCR0A |= (1<<WGM01);        //CTC-Mode
31
  TCCR0B |= ((1<<CS01)|(1<<CS00));  //Teiler Osz/64 auf 125kHz
32
  OCR0A = 0x7C;            //Interrupt alle ms; 1/125kHz=8us; 8us*0x7C=8us*125=1ms
33
  TIMSK0 |= (1<<OCIE0A);        //Compare Match A Interrupt Enable
34
    //Timer1
35
  TCCR1B |= (1<<CS11);        //Teiler Osz/8 auf 1Mhz
36
  TIMSK1 |= (1<<TOIE1);        //Overflow Interrupt Enable
37
  
38
}
39
void adcinit(void)      //ADC Einstellungen
40
{
41
  ADMUX |= ((1<<REFS0)|(1<<ADLAR));    //Reference Selection AVCC mit Kondensator
42
  ADCSRA |= (1<<ADEN);          //ADC Enable
43
  DIDR0 = 0xFE;              //andere Pins disable (Sensor an PA0)  
44
}
45
void intinit(void)      //Externe Interrupts
46
{
47
  EICRA |= (1<<ISC00);  //INT0: immer wenn eine Zustandsaenderung ist
48
  EIMSK |= (1<<INT0);    //INT0: ENABLE
49
}
50
int main (void)        //Haubtprogramm
51
{
52
  portinit();
53
  timerinit();
54
  adcinit();
55
  
56
  PORTD = 0x08;      //high fuer DCF77
57
  
58
  intinit();
59
  
60
  sei();          //Alle Interrupts aktivieren
61
  
62
  PORTD = 0x00;      //low fuer DCF77 / Start der Uhr
63
  
64
  while(1);        //Warteschleife
65
}
66
ISR(INT0_vect)        //DCF Signal
67
{
68
  if (INT0 == 1) counter = 0;  //Beginn des High
69
  else            //Ende des High
70
  {
71
    if (counter <= 150) DCF[n] = 0;
72
    else if (counter <= 250) DCF[n] = 1;
73
    n++;          //für nächsten durchlauf n+1
74
    if (counter >= 500) n = 0;
75
  }
76
  if(n == 36 && time == false)              //Zeit das erstemal empfangen
77
  {    
78
    if ( ((DCF[21] + DCF[22] + DCF[23] + DCF[24] + DCF[25] + DCF[26] + DCF[27])%2 == DCF[28]) && ((DCF[29] + DCF[30] + DCF[31] + DCF[32] + DCF[33] + DCF[34])%2 == DCF[35]) )  //Prüfen des empfangenen Signales
79
    {
80
      ss = 36;
81
      if (DCF[21] == 1) mm = mm + 1;          //Minuten Einer
82
      if (DCF[22] == 1) mm = mm + 2;
83
      if (DCF[23] == 1) mm = mm + 4;
84
      if (DCF[24] == 1) mm = mm + 8;
85
      if (DCF[25] == 1) mm = mm + 10;          //Minuten Zehner
86
      if (DCF[26] == 1) mm = mm + 20;
87
      if (DCF[27] == 1) mm = mm + 40;
88
      if (DCF[29] == 1) hh = hh + 1;          //Stunden Einer
89
      if (DCF[30] == 1) hh = hh + 2;
90
      if (DCF[31] == 1) hh = hh + 4;
91
      if (DCF[32] == 1) hh = hh + 8;
92
      if (DCF[33] == 1) hh = hh + 10;          //Stunden Zehner
93
      if (DCF[34] == 1) hh = hh + 20;
94
      
95
      time = true;                  //Zeit ist korrekt
96
    }  
97
    if (DCF[19] == 1);                  //Sommer- oder Winterzeit
98
    {
99
      if ((DCF[17] == 1) && (DCF [18] == 0)) hh++;  //MESZ
100
      if ((DCF[17] == 0) && (DCF [18] == 1)) hh--;  //MEZ
101
    }  
102
    if ((mm == 0) && (n==36))              //Zeitkontrolle
103
    {
104
      mmc = 0, hhc = 0, ss = 36;
105
      if (DCF[21] == 1) mmc = mmc + 1;        //Minuten Einer
106
      if (DCF[22] == 1) mmc = mmc + 2;
107
      if (DCF[23] == 1) mmc = mmc + 4;
108
      if (DCF[24] == 1) mmc = mmc + 8;
109
      if (DCF[25] == 1) mmc = mmc + 10;        //Minuten Zehner
110
      if (DCF[26] == 1) mmc = mmc + 20;
111
      if (DCF[27] == 1) mmc = mmc + 40;
112
      if (DCF[29] == 1) hhc = hhc + 1;        //Stunden Einer
113
      if (DCF[30] == 1) hhc = hhc + 2;
114
      if (DCF[31] == 1) hhc = hhc + 4;
115
      if (DCF[32] == 1) hhc = hhc + 8;
116
      if (DCF[33] == 1) hhc = hhc + 10;        //Stunden Zehner
117
      if (DCF[34] == 1) hhc = hhc + 20;
118
      
119
      if ((hh != hhc) && (mm != mmc))          //Wenn falsch dann aktualisieren
120
      {
121
        hh = hhc;
122
        mm = mmc;
123
      }
124
    }
125
  }
126
}
127
ISR(TIMER0_COMPA_vect)    //Timer für Zeit
128
{
129
  counter++;
130
  if(time == true)
131
  {
132
    hs++;
133
    if (hs == 1000) hs = 0, ss++, ADCSRA |= (1<<ADSC),  light = ADCH;    //Um einmal zu lesen dannach ist es wieder automatisch 0;
134
    if (ss == 60) ss = 0, mm++;
135
    if (mm == 60) mm = 0, hh++;
136
    if (hh == 24) hh = 0;
137
    mode = mm / 5;
138
  }  
139
}
140
ISR(TIMER1_OVF_vect)    //Timer für Anzeige
141
{  
142
  if (time == false)            //Zu aendern je nach Beschaltung der LED-Strips
143
  {
144
    //1. FUNK 2. UHR
145
  }
146
  else
147
  {
148
    i++;
149
    if(i >= 0xFF) i = 0x00;          //aendert die Helligkeit wenn man i höher oder niedriger zählen lässt
150
    if(i <= light)
151
    {
152
      switch (mode)            //Zu aendern je nach Beschaltung der LED-Strips
153
      {
154
        case 0:
155
          //1. n 2. UHR (EINS ohne "S")
156
          break;
157
        case 1:
158
          //1. FÜNF 2. NACH 3. n
159
          break;
160
        case 2:
161
          //1. ZEHN 2. NACH 3. n
162
          break;
163
        case 3:
164
          //1. VIERTEL 2. n+1
165
          break;
166
        case 4:
167
          //1. ZWANZIG 2. NACH 3. n
168
          break;
169
        case 5:
170
          //1. FÜNF 2. VOR 3. HALB 4. n+1
171
          break;
172
        case 6:
173
          //1. HALB 2. n+1
174
          break;
175
        case 7:
176
          //1. FÜNF 2. NACH 3. HALB 4. n+1
177
          break;
178
        case 8:
179
          //1. ZEHN 2. NACH 3. HALB 4. n+1
180
          break;
181
        case 9:
182
          //1. DREI- 2. VIERTEL 3. n+1
183
          break;
184
        case 10:
185
          //1. ZEHN 2. VOR 3. n+1
186
          break;
187
        case 11:
188
          //1. FÜNF 2. VOR 3. n+1
189
          break;
190
      }    
191
    }  
192
    else PORTA = 0x00, PORTB = 0x00, PORTC = 0x00, PORTD = 0x00;        
193
  }  
194
}

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Wo nach dem Initialisieren?
An welcher Stelle stellst du das fest?
Welchen uC hast du denn überhaupt?
Müssen diese globalen Variablen alle 16 Bit breit sein?

BTW: Was macht deine Uhr, wenn der DCF-Sender für Wartungsarbeiten mal 
für ne Stunde abgeschaltet wird? Oder wenn dein Empfangssignal gestört 
ist?

von Peter II (Gast)


Lesenswert?

der code ist sehr schwer zu lesen!

> volatile int hh = 0, mm = 0, ss = 0, hs = 0, mode = 0, counter = 0, n =
> 0, mmc = 0, hhc = 0, z = 1, DCF[60], i = 0x00, light = 0x00;
> bool time = false, zu = false;

volatile ist untötig weil du alle Variabeln nur in der ISR verwendest. 
Auserdem kann man das auch lesbaren auf mehre Zeilen schreiben.

> if (ss == 60) ss = 0, mm++;
klar kann man soetwas machen, aber freunde man man sich damit nicht.


Kann es sein das dein N für  DCF[n] mal größer als 60 wird? ich sehen 
keine stelle wo du es begrenzt.

von Niklas N. (niklas_n)


Lesenswert?

Lothar Miller schrieb:
> Wo nach dem Initialisieren?
> An welcher Stelle stellst du das fest?

void timerinit(void)        //Timer Interrupts
{
    //Timer0
  TCCR0A |= (1<<WGM01);
  TCCR0B |= ((1<<CS01)|(1<<CS00));
  OCR0A = 0x7C;
  TIMSK0 |= (1<<OCIE0A);  //hier wird n auf 2 erhöt also n+2
    //Timer1
  TCCR1B |= (1<<CS11);
  TIMSK1 |= (1<<TOIE1);   // und hier wird n auf 258 erhöt also n+256
}

und dann noch da:

void intinit(void)      //Externe Interrupts
{
  EICRA |= (1<<ISC00);
  EIMSK |= (1<<INT0);  //und hier wird hs auf 256 erhöt also n+256
}

hs sind die Hundertstelsekunden.

> Welchen uC hast du denn überhaupt?

einen ATMEGA 164A

> Müssen diese globalen Variablen alle 16 Bit breit sein?

Nein...

> BTW: Was macht deine Uhr, wenn der DCF-Sender für Wartungsarbeiten mal
> für ne Stunde abgeschaltet wird? Oder wenn dein Empfangssignal gestört
> ist?

Er verwendet automatisch immer den Timer und stellt ihn das erste Mal 
genau auf die Sekunde mit dem DCF-Signal synchron...

von Niklas N. (niklas_n)


Lesenswert?

Peter II schrieb:
> der code ist sehr schwer zu lesen!
>
>> volatile int hh = 0, mm = 0, ss = 0, hs = 0, mode = 0, counter = 0, n =
>> 0, mmc = 0, hhc = 0, z = 1, DCF[60], i = 0x00, light = 0x00;
>> bool time = false, zu = false;
>
> volatile ist untötig weil du alle Variabeln nur in der ISR verwendest.
> Auserdem kann man das auch lesbaren auf mehre Zeilen schreiben.

also brauch ich volatile gar nicht. Ich hab es jz nur auf die schnelle 
am Abendgeschrieben, deswegen hab ich nicht so viel formatiert.

>> if (ss == 60) ss = 0, mm++;
> klar kann man soetwas machen, aber freunde man man sich damit nicht.

was würdest du an deiner stelle da schreiben? würd mich freuen wenn es 
einen besseren weg gibt ;)

> Kann es sein das dein N für  DCF[n] mal größer als 60 wird? ich sehen
> keine stelle wo du es begrenzt.

Ja danke das sollte ich noch begrenzen ;)

von Niklas N. (niklas_n)


Lesenswert?

@Florian:
stimmt danke is eine bessere struktur

von Niklas N. (niklas_n)


Lesenswert?

Ich hab das Problem...
Hab mal geschaut welches Register mein AVR verwendet und zwar waren das 
die Register wo genau das TIMSK0-Regsiter und das TIMS1-Register und das 
EIMSK-Register liegt. Gibt es eine Möglichkeit das zu verhindern? 
Vielleicht ein fixes Register zuweißen? oder ist das dann beim ATMEGA 
selbst anders?

Mfg Niklas

von Dirk (Gast)


Lesenswert?

Hi,

ich habe mir deinen Code jetzt nicht intensiv angeschaut.

Deine Interrupt-Routinen sind allerdings zimelich lang, was nicht so gut 
ist.

Ein funktionierendes Bsp für DCF77 auf ATMega kannst du bei Ulrich Radig 
finden:

http://www.ulrichradig.de/home/index.php/avr/dcf77_uhr

Vllt. kannst du dir da was abgucken.

Denk auch dran, dass die meisten DCF77 Module recht empfindlich sind. 
Also möglichst weit weg von Elektronishen Geräten ausprobieren. Auf sehr 
saubere Betriebsspannung achten. Vor dem Modul gut filtern!

Du wirst über eine Pufferung der Zeit nicht drumrum kommen. Der DCF 
Empfang ist nicht so gut wie du dir das wahrscheinlich vorstellst 
(musste ich auch erst lernen).

Ich habe irgendwo mal gelesen, dass diese ganzen Standard-Uhren ihre DCF 
Zeit irgendwann nachts holen, weil da die größte Chance besteht, dass 
möglichst wenig elektrische Geräte in der Nähe eingeschaltet sind.

Viel Erfolg noch
Dirk

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.