mikrocontroller.net

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


Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :/

Autor: Magnetus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
( tätscheltätscheltätschel )

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 ;)

Autor: spess53 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

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

Code?

MfG Spess

Autor: g457 (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
nenene, der Fehler liegt eindeutig in Zeile 42!

SCNR

Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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...
bitmask_l[0] = '\0';
 :D

Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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ß.:
...
       bitmask_l[0] = '\0';
       
       TOIE2_bit  = 0;
       strcat(bitmask_l,bitmask1);
       strcat(bitmask_l,bitmask2);
       strcat(bitmask_l,bitmask3);
       strcat(bitmask_l,bitmask4);
       strcat(bitmask_l,bitmask5);
       strcat(bitmask_l,bitmask6);
   
       
       UART1_Write_text(bitmask_l);
       
       for(i=0;i<24;i++)
       {
                 PortB.B1 = 0;                 
                 PortB.B3 = bitmask_l[i];      
                 PortB.B1 = 1;                 
       
       
       }
       TOIE2_bit  = 1;
..


Hier der Interrupt.:
void Timer2Overflow_ISR() org IVT_ADDR_TIMER2_OVF {
     if (PINB.F7 == 1)
        {
         ++dcf_time;
         if (dcf_time2  >= 100)
           {
             if (dcf_time2 >= 5000)
             {
                           dcf_count = -1;
                           dcf_calc_v = 1;
                           for(i = 0;i<58;i++)
                           {
                             dcf_bitmask[i] = dcf_bitmask_temp[i];
                           }
             }
             dcf_time2 = 0;
           }
        }

     if (PINB.F7 == 0)
        {
         ++dcf_time2;
         if (dcf_time  >= 100)
           {
             ++dcf_count;
             itoa(dcf_c,dcf_count);
             if (dcf_time >= 800)
             {
                          dcf_bitmask_temp[dcf_count] = 1;
             }  else
             {
                          dcf_bitmask_temp[dcf_count] = 0;
             }
             dcf_time = 0;

           }
        }
}

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

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :/
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...

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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:

uint8_t my_array[3];

void setbit( uint8_t bitno, uint8_t bit )
{
  my_array[bitno >> 3] &= ~(1<<(bit_no & 7));
  if( bit )
    my_array[bitno >> 3] |= 1<<(bit_no & 7);
}


Peter

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Sooo nun bin ich soweit.:

long test;

for(i=0;i<24;i++)
{
 test |= (1 << i);
}

for(i=0;i<24;i++)
{
   if ((test & (1 << i)) != 1) UART1_Write_text("1"); else UART1_Write_text("0");
}

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 :/

Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
So hab nun die Abfrage geändert.:
       for(i=0;i<32;i++)
       {

        if ((test >> i) & 1 == 1) UART1_Write_text("1"); else UART1_Write_text("0");

       }


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...

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?

Autor: Falk Willberg (dl3daz) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Draco schrieb:
...

>    if ((test & (1 << i)) != 1)
> 

> 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

Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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:

for(i=0;i<24;i++)
{
test |= (1L << i);
}


Peter

Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
   

       unsigned long test;


       for(i=0;i<24;i++)
       {

        if(bitmask_l[i] == '1') test |= (1L << i); else test &= ~(1L << i);

       }

       for(i=0;i<24;i++)
       {
        //if ((test & (1 << i)) != 1) UART1_Write_text("1"); else UART1_Write_text("0");
        //if ((test >> i) & 1 == 1) UART1_Write_text("1"); else UART1_Write_text("0");
        //if ((test & (1 << i)) >= 1) UART1_Write_text("1"); else UART1_Write_text("0");
        if ((test & (1 << i))) UART1_Write_text("1"); else UART1_Write_text("0");
       }

Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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?! :/

Autor: Falk Willberg (dl3daz) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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
printf("%d\n",sizeof(unsigned long));
?

Falk

Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe es! :D So funktioniert es:

       for(i=0;i<24;i++)
       {
          if(bitmask_l[i] == '1') test |= ((unsigned long)1 << i); else test &= ~((unsigned long)1 << i);
       }

       for(i=0;i<24;i++)
       {
        if ((test >> i) & 1 == 1) UART1_Write_text("1"); else UART1_Write_text("0");
       }

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

Autor: Falk Willberg (dl3daz) Benutzerseite
Datum:

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

Statt des
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

Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: holger (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Draco (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Guten Morgen Holger,

meintest du das Beispiel:
uint32_t test = 0xAAAAAAAA;
 uint32_t mask = 0x80000000;

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

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?!

Autor: Helmut Lenzen (helmi1)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht 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

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.