Forum: Mikrocontroller und Digitale Elektronik Interrupt zerschießt andere Funktionen


von Draco (Gast)


Lesenswert?

Also nun muß ich echt mal nen Frustthread loslassen :(

Ich arbeite zur Zeit an einer Nixie Uhr und ärgere mich kontinuierlich 
mit einem Interrupt rum.

Jedesmal wenn der Interrupt aufgerufen wird (Timer2 Overflow) zerschießt 
es mir andere Funktionen oder die Inhalte der Variablen etc...

Ich arbeite mit einem Atmega32 und 10Mhz Quartz, den Interrupt benötige 
ich für die Abfrage des DCF Modules.

Da ich ein 24Bit Schieberegister nutze und die Werte daraus mit strcat 
zu einem kompletten 24Bit Wert zusammensetze und dies dann in das 
Register schiebe kommt nur noch Müll bei raus...

Statt sowas:

001000010010000000101000

halt sowas:

0001_ÿ0101001100100001

0001W0000010100100001

00000000000000000001X`³

Ein Grund dafür konnte ich mir noch nicht erklären, ich dachte 
eigentlich immer das der aktuelle Prozess unterbrochen wird, und genau 
an dieser Stelle weitergeführt wird, es sind ja keine Zeitkritischen 
Sachen :/

von Magnetus (Gast)


Lesenswert?

( tätscheltätscheltätschel )

von holger (Gast)


Lesenswert?

>Da ich ein 24Bit Schieberegister nutze und die Werte daraus mit strcat
>zu einem kompletten 24Bit Wert zusammensetze und dies dann in das
>Register schiebe kommt nur noch Müll bei raus...

Und was machst du vor strcat? Hoffentlich den alten String
erstmal löschen. Sonst wird der immmmmer länger ;)

von spess53 (Gast)


Lesenswert?

Hi

Einen richtig gemachten Interrupt bemerkt man nur wenn es gewollt ist.

Code?

MfG Spess

von g457 (Gast)


Lesenswert?

nenene, der Fehler liegt eindeutig in Zeile 42!

SCNR

von Draco (Gast)


Lesenswert?

Magnetus schrieb:
> ( tätscheltätscheltätschel )

Danke das brauche ich :D

holger schrieb:
> Und was machst du vor strcat? Hoffentlich den alten String
> erstmal löschen. Sonst wird der immmmmer länger ;)

Jep...
1
bitmask_l[0] = '\0';
 :D

von Draco (Gast)


Lesenswert?

spess53 schrieb:
> Hi
>
> Einen richtig gemachten Interrupt bemerkt man nur wenn es gewollt ist.
>
> Code?
>
> MfG Spess


Also den Bereich den ich aus dem Interrupt nehmen muß.:
1
...
2
       bitmask_l[0] = '\0';
3
       
4
       TOIE2_bit  = 0;
5
       strcat(bitmask_l,bitmask1);
6
       strcat(bitmask_l,bitmask2);
7
       strcat(bitmask_l,bitmask3);
8
       strcat(bitmask_l,bitmask4);
9
       strcat(bitmask_l,bitmask5);
10
       strcat(bitmask_l,bitmask6);
11
   
12
       
13
       UART1_Write_text(bitmask_l);
14
       
15
       for(i=0;i<24;i++)
16
       {
17
                 PortB.B1 = 0;                 
18
                 PortB.B3 = bitmask_l[i];      
19
                 PortB.B1 = 1;                 
20
       
21
       
22
       }
23
       TOIE2_bit  = 1;
24
..


Hier der Interrupt.:
1
void Timer2Overflow_ISR() org IVT_ADDR_TIMER2_OVF {
2
     if (PINB.F7 == 1)
3
        {
4
         ++dcf_time;
5
         if (dcf_time2  >= 100)
6
           {
7
             if (dcf_time2 >= 5000)
8
             {
9
                           dcf_count = -1;
10
                           dcf_calc_v = 1;
11
                           for(i = 0;i<58;i++)
12
                           {
13
                             dcf_bitmask[i] = dcf_bitmask_temp[i];
14
                           }
15
             }
16
             dcf_time2 = 0;
17
           }
18
        }
19
20
     if (PINB.F7 == 0)
21
        {
22
         ++dcf_time2;
23
         if (dcf_time  >= 100)
24
           {
25
             ++dcf_count;
26
             itoa(dcf_c,dcf_count);
27
             if (dcf_time >= 800)
28
             {
29
                          dcf_bitmask_temp[dcf_count] = 1;
30
             }  else
31
             {
32
                          dcf_bitmask_temp[dcf_count] = 0;
33
             }
34
             dcf_time = 0;
35
36
           }
37
        }
38
}

hier der Init des Int.:
1
   SREG_I_bit = 1;
2
   TOIE2_bit  = 1;
3
   TCCR2      = 2;

von Peter D. (peda)


Lesenswert?

Draco schrieb:
> Jep...bitmask_l[0] = '\0'; :D

Puh, ist ja voll von hinten durch die Brust ins Auge.
Gehts nicht noch komplizierter?

Es sind doch Bits, also speichere sie auch als Bits.
Am besten schreibe sie gleich an die richtige Stelle in die Variablen 
und schon hast Du alle Werte (Minuten, Stunden, ...) fix und fertig 
vorliegen ohne irgendwelchen kruden Umwandlungen.
Spart Code, SRAM und CPU-Zeit.

Keine Angst, Du kannst jedes Bit in harter Echtzeit bearbeiten. Bei 
wahnsinns Speed von 1 Baud, also 1 Bit pro Sekunde gähnt die CPU vor 
langer Weile.
Du mußt also nicht erst umständlich alle Bits in ein 
"Text"-Schieberegister packen.


Peter

von Draco (Gast)


Lesenswert?

Peter Dannegger schrieb:
> Draco schrieb:
>> Jep...bitmask_l[0] = '\0'; :D
>
> Puh, ist ja voll von hinten durch die Brust ins Auge.
> Gehts nicht noch komplizierter?
>
> Es sind doch Bits, also speichere sie auch als Bits.
> Am besten schreibe sie gleich an die richtige Stelle in die Variablen
> und schon hast Du alle Werte (Minuten, Stunden, ...) fix und fertig
> vorliegen ohne irgendwelchen kruden Umwandlungen.
> Spart Code, SRAM und CPU-Zeit.
>
> Keine Angst, Du kannst jedes Bit in harter Echtzeit bearbeiten. Bei
> wahnsinns Speed von 1 Baud, also 1 Bit pro Sekunde gähnt die CPU vor
> langer Weile.
> Du mußt also nicht erst umständlich alle Bits in ein
> "Text"-Schieberegister packen.
>
>
> Peter

Tja... hab ich ja versucht ... aber :/
1
11 312 Internal error 'bad declaration of [bitfield] arrays of bit type objects is not allowed' 24Bit Nixie.c

Ich könnte höchstens alles direkt in das Char Array schreiben an die 
gewünschte Position...

von Peter D. (peda)


Lesenswert?

Draco schrieb:
> Tja... hab ich ja versucht ... aber :/
> 11 312 Internal error 'bad declaration of [bitfield] arrays of bit type objects 
is not allowed' 24Bit Nixie.c

Ein Indexzugriff auf Bitfelder geht unter C nicht.

> Ich könnte höchstens alles direkt in das Char Array schreiben an die
> gewünschte Position...

Ja, so schlimm ist das nicht. Einfach ein Array aus 3 Bytes nehmen:
1
uint8_t my_array[3];
2
3
void setbit( uint8_t bitno, uint8_t bit )
4
{
5
  my_array[bitno >> 3] &= ~(1<<(bit_no & 7));
6
  if( bit )
7
    my_array[bitno >> 3] |= 1<<(bit_no & 7);
8
}


Peter

von Peter D. (peda)


Lesenswert?

P.S.:
Du wirst damit aber nicht glücklich werden, wenn Du direkt den 
empfangenen Code an die Nixies rausschiebst. Die werden dann öfter mal 
Mumpitz anzeigen.

Die übliche Methode ist daher, daß man erstmal ne Quarzuhr programmiert, 
die die Uhrzeit weiterzählt.

Und die DCF-77 Routine läuft im Hintergrund mit und empfängt die 
Impulse.
Und wenn dann der Minutenimpuls kommt, wird geprüft, ob es keine 
Empfangsfehler gab und dann erst wird die Quarzuhr mit der empfangenen 
Zeit gestellt.

Und bei nem Fehler läuft die Quarzuhr eben weiter und die Nixies zeigen 
keinen Mist an.


Peter

von Draco (Gast)


Lesenswert?

Sooo nun bin ich soweit.:
1
long test;
2
3
for(i=0;i<24;i++)
4
{
5
 test |= (1 << i);
6
}
7
8
for(i=0;i<24;i++)
9
{
10
   if ((test & (1 << i)) != 1) UART1_Write_text("1"); else UART1_Write_text("0");
11
}

Jetzt müsste er doch alle 24 Stellen mit einer 1 beschreiben oder? Aber 
irgendweie klappt das nicht so ganz, denke ich mir. Denn er schreibt 
immer nur den ersten Bit um... Steig da nicht so ganz durch :/

von Draco (Gast)


Lesenswert?

So hab nun die Abfrage geändert.:
1
       for(i=0;i<32;i++)
2
       {
3
4
        if ((test >> i) & 1 == 1) UART1_Write_text("1"); else UART1_Write_text("0");
5
6
       }

Das funktioniert auch soweit, jedoch kann ich nur 2Byte beschreiben 
(16Bit) alles danach schreibt er nicht, oder ließt es nicht... :/ Obwohl 
long ja eine 4Byte Datentyp ist...

von holger (Gast)


Lesenswert?

uint32_t test = 0xAAAAAAAA;
 uint32_t mask = 0x80000000;

 while(mask)
 {
  if(test & mask) UART1_Write_text("1");
  else UART1_Write_text("0");
  mask >>= 1;
 }

Geht das?

von Falk W. (dl3daz) Benutzerseite


Lesenswert?

Draco schrieb:
...
1
>    if ((test & (1 << i)) != 1)
2
>

> Jetzt müsste er doch alle 24 Stellen mit einer 1 beschreiben oder?

Ja, tut er auch.

> Aber
> irgendweie klappt das nicht so ganz, denke ich mir. Denn er schreibt
> immer nur den ersten Bit um... Steig da nicht so ganz durch :/

Mit test==1 wird aus test&(1<<0)->1&1->1
mit test==2 wird aus test&(1<<1)->2&2->2 und nicht 1!

Schreib': if ((test & (1 << i))), dann klappt's.

Falk

von Draco (Gast)


Lesenswert?

Jep, scheint so... das kommt raus.:

10101010101010101010101010101010

Das sind schonmal 32Bit also 4Byte.
Jedoch muß ich in MicroC mit long deklarieren, der kennt uint32_t nicht.

von Peter D. (peda)


Lesenswert?

Draco schrieb:
> Jetzt müsste er doch alle 24 Stellen mit einer 1 beschreiben oder?

Nein, C rechnet default erstmal int (16Bit).
Wenn Du es danach einem long zuweist, ist es zu spät.
Du mußt also gleich long rechnen:
1
for(i=0;i<24;i++)
2
{
3
test |= (1L << i);
4
}


Peter

von Draco (Gast)


Lesenswert?

Falk Willberg schrieb:

>
> Mit test==1 wird aus test&(1<<0)->1&1->1
> mit test==2 wird aus test&(1<<1)->2&2->2 und nicht 1!
>
> Schreib': if ((test & (1 << i))), dann klappt's.
>
> Falk

Jep.. das schreiben und auslesen klappt ja nun auch, auch mit deiner 
Funktion danke, jedoch komme ich nun immer noch nicht über diese 
komische 16Bit / 2Byte Hürde weg... alles nach Bit 16 wird 
weggeschluckt. :/

Peter Dannegger schrieb:
> Draco schrieb:
>> Jetzt müsste er doch alle 24 Stellen mit einer 1 beschreiben oder?
>
> Nein, C rechnet default erstmal int (16Bit).
> Wenn Du es danach einem long zuweist, ist es zu spät.
> Du mußt also gleich long rechnen:
> for(i=0;i<24;i++)
> {
> test |= (1L << i);
> }
>
>
> Peter

Oh ein sehr guter Ansatz, leider kommt er auch da nicht über den 16. Bit 
weg... bin am durchdrehen hier :D Gleich werfe ich microC in die Ecke 
und nehm AVR-GCC.

Momentan sieht es so aus. Mit mehreren funtionierenden Funktionen:
1
   
2
3
       unsigned long test;
4
5
6
       for(i=0;i<24;i++)
7
       {
8
9
        if(bitmask_l[i] == '1') test |= (1L << i); else test &= ~(1L << i);
10
11
       }
12
13
       for(i=0;i<24;i++)
14
       {
15
        //if ((test & (1 << i)) != 1) UART1_Write_text("1"); else UART1_Write_text("0");
16
        //if ((test >> i) & 1 == 1) UART1_Write_text("1"); else UART1_Write_text("0");
17
        //if ((test & (1 << i)) >= 1) UART1_Write_text("1"); else UART1_Write_text("0");
18
        if ((test & (1 << i))) UART1_Write_text("1"); else UART1_Write_text("0");
19
       }

von Draco (Gast)


Lesenswert?

Habe den Cast nun auch mal mit ((unsigned long)1 << n) gemacht, auch 
ohne Erfolg langsam komme ich wirklich zu der Schlußfolgerung das MicroC 
long nur als 2Byte nutzt?! :/

von Falk W. (dl3daz) Benutzerseite


Lesenswert?

Draco schrieb:
> Habe den Cast nun auch mal mit ((unsigned long)1 << n) gemacht, auch
> ohne Erfolg langsam komme ich wirklich zu der Schlußfolgerung das MicroC
> long nur als 2Byte nutzt?! :/

Was sagt
1
printf("%d\n",sizeof(unsigned long));
?

Falk

von Draco (Gast)


Lesenswert?

Ich habe es! :D So funktioniert es:

1
       for(i=0;i<24;i++)
2
       {
3
          if(bitmask_l[i] == '1') test |= ((unsigned long)1 << i); else test &= ~((unsigned long)1 << i);
4
       }
5
6
       for(i=0;i<24;i++)
7
       {
8
        if ((test >> i) & 1 == 1) UART1_Write_text("1"); else UART1_Write_text("0");
9
       }

Danköööö euch allen! Habt mir sehr geholfen!

von Falk W. (dl3daz) Benutzerseite


Lesenswert?

Draco schrieb:
> Ich habe es! :D So funktioniert es:
>
>
>
1
>        for(i=0;i<24;i++)
2
>        {
3
>           if(bitmask_l[i] == '1') test |= ((unsigned long)1 << i); else
4
> test &= ~((unsigned long)1 << i);
5
>
>
> Danköööö euch allen! Habt mir sehr geholfen!

Statt des
1
else test &= ~((unsigned long)1 << i);
 könntest Du bestimmt am Anfang auch test=0; schreiben. Wenn das nicht 
reicht, würde ich einen Compiler-Fehler annehmen.

Falk

von Draco (Gast)


Lesenswert?

Falk Willberg schrieb:
> Statt deselse test &= ~((unsigned long)1 << i); könntest Du bestimmt am >
> reicht, würde ich einen Compiler-Fehler annehmen.
>
> Falk

Ja klappt auch :D Manchmal wird man halt paranoid.

von holger (Gast)


Lesenswert?

>test |= ((unsigned long)1 << i);

Shifts mit Variablen kosten viel Speicher und Zeit.
Versuchs mal mit meiner oben geposteten Methode.
Nur die Bitmaske um eine Stelle schieben und dann mit Variable verunden.

von Draco (Gast)


Lesenswert?

Guten Morgen Holger,

meintest du das Beispiel:
1
uint32_t test = 0xAAAAAAAA;
2
 uint32_t mask = 0x80000000;
3
4
 while(mask)
5
 {
6
  if(test & mask) UART1_Write_text("1");
7
  else UART1_Write_text("0");
8
  mask >>= 1;
9
 }

Wie verhält sich das ganze, kann dem Code nicht so recht folgen.:

test = 10101010 10101010 10101010 10101010
mask = 10000000 00000000 00000000 00000000

if(test & mask) <-- Prüft ob der aktuelle Bit von Test UND Mask gleich 
ist?!

mask >>= 1; <-- das verstehe ich nicht ganz, wird damit der eine Bit in 
der maske um eins verrutscht?!

von Helmut L. (helmi1)


Lesenswert?

Draco schrieb:
> if(test & mask) <-- Prüft ob der aktuelle Bit von Test UND Mask gleich
> ist?!
>

Nein. Die beiden Werte werden verundet und danach geprueft ob das 
Ergebnis 0 oder ungleich 0 ist.


> mask >>= 1; <-- das verstehe ich nicht ganz, wird damit der eine Bit in
> der maske um eins verrutscht?!

Damit schiebst du deine Bitmaske um eins nach rechts. Nach dem naechsten 
aufruf von "if" wird dann das naechste Bit geprueft. So hast du bei 
jedem Schleifendurchgang nur einmal nach rechts geshiftet und nicht wie 
sonst erst 31 mal , dann 30 mal usw. Spart massig Zeit beim 
konvertieren.

Gruss Helmi

von Peter D. (peda)


Lesenswert?

Auch wenn diese Anwendung kaum Probleme mit Code- und CPU-Zeitverbrauch 
haben wird, ist die Variante mit dem 3 Byte-Array deutlich effektiver.
Insbesondere, wenn Du dann die 24 Bit an die Hardware rausschieben 
willst. Das SPI will nämlich mit Bytes gefüttert werden und dann müßtest 
Du das long ja wieder auseinanderpflücken.


Peter

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.