www.mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik Mein µC kann nicht rechnen ?!


Autor: Lu Ke (luke)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Forum,

hab ein Problem: Lese mit einem ATMega48 die Signale von einem 
Servosignal ein, das klappt auch wunderbar, nur verrechnet sich der 
Controller ab und zu? Anbei ein Auszug aus den Werten die ich über Rs232 
übertragen habe.


+ Fl.   -FL.     Differenz
23368  24891  1523
48268  49793  1525
32579  34106  1527
57500  59026  42158   !!!
41799  43328  1529
1186  2712  1526
26127  27655  1528
10466  11994  1528
35417  36946  1528
19755  21282  1527
44672  46203  42124   !!!
29012  30541  1529
53948  55477  1529
13353  39797  1529
63211  64739  1528
22596  24125  1527
6943  8473  1530
31884  33414  42112   !!!
16247  17776  1529
41191  42717  1526
572  2099  1525
50413  51942  1529
9763  11285  1524
59591  61120  1529
18986  20512  1526
43878  4796  1528
28187  29714  1527
53102  54625  1526
37376  38901  1525
62282  63810  1527
46560  48087  1527
5944  7471  1527
30872  57331  1529
15187  16715  1528
40103  41630  1527
24385  25914  1529
49288  50814  42157   !!!
33577  35105  1528
58474  59996  1522
17827  44256  1526
2111  3638  1527

hier noch der Code aus´m AVRStudio:
#include <avr/io.h>
#include <avr/interrupt.h> 
#include <stdlib.h>      // ***********nur debug*******
#include <util/delay.h>
volatile  unsigned short int rise;
volatile  unsigned short int fall;
volatile  unsigned short int pulse;
//*********
int uart_putc(unsigned char c);
void uart_puts (char *s);
char s[7];
//***********
int main()
  {

  // debug rs232

  UBRR0 = 0x33;          // 9600 BAUD
  UCSR0A =0x00;
  UCSR0B =0x18;          //Enable Tx,Rx
  UCSR0C =0x06;          //async. 8bit,1 Stoppbit

  // Timer1 Init

  TCCR1B |= (1<<CS11);              // Prescaler clk/8
  TCCR1C |= (1<<FOC1B);              
  TIMSK1 |= ((1<<TOIE1)|(1<<OCIE1B));        // Overflow,Compare Interrupt enable
  // Interrupt settings

  EICRA  |= (1<<ISC00);              // Logical Change generates Interrupt
  EIMSK  |= (1<<INT0);              // enable INT0
  sei();                      // enable global Interrupts

  // Ports
  DDRD = 0x00;                  // Input
  PORTD |= (1<<PD2);                // pullup PD2 on
  DDRB  |= (1<<PB2);                // PB2 output

  while(1)
    {
              
    OCR1B= pulse;                // pulse duration
    uart_puts( utoa( rise, s, 10 ) );//************
    uart_puts("\t");    //***********  
    uart_puts( utoa( fall, s, 10 ) );//************
    uart_puts("\t");    //***********
    uart_puts( utoa( pulse, s, 10 ) );//************
     uart_puts("\r");    //***********
    _delay_ms(20);    //***********
    }
  }

ISR(SIG_INTERRUPT0)
  {
  if (PIND&(1<<PD2))              // rising edge
  rise = TCNT1;
  else if (!(PIND&(1<<PD2)))          // falling edge      
  fall = TCNT1;
  pulse = fall-rise;
  }

ISR(SIG_OVERFLOW1)
  {
  PORTB = 0xff;
  }

ISR(SIG_OUTPUT_COMPARE1B)
  {
  PORTB = 0x00;
  }


//***************************nur debug**********
int uart_putc(unsigned char c)
  {
    while (!(UCSR0A & (1<<UDRE0)));  /* warten bis Senden moeglich */
       
    UDR0 = c;                      /* sende Zeichen */
    return 0;
  }
    
void uart_puts (char *s)
{
    while (*s)
    {   /* so lange *s != '\0' also ungleich dem "String-Endezeichen" */
        uart_putc(*s);
        s++;
    }
}

Was mache ich da falsch?
Vielen Dank für eure Tipps

Autor: Obelix (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was sagt denn dein Debugger, wenn du dein Programm Schritt für Schritt 
ausführst?

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schon mal drüber nachgedacht, was passiert, wenn der Interrupt mitten 
zwischen die puts Statements reinrutscht?

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mehrbytevariablen, die in Interrutps gesetzt werden, muß man im Main 
atomar auslesen, d.h. mit cli(); und sei(); klammern.

Peter

Autor: Lu Ke (luke)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hoppla das ging ja schnell !

Also wenn ich das richtig verstanden habe müsste ich das dann so machen:
...
while(1)
    {
    cli();          
    rise1=rise;
    fall1=fall;
    pulse1=pulse;                // pulse duration
    sei();
    OCR1B= pulse1;
    uart_puts( utoa( rise1, s, 10 ) );//************
    uart_puts("\t");    //***********  
    uart_puts( utoa( fall1, s, 10 ) );//************
    uart_puts("\t");    //***********
    uart_puts( utoa( pulse1, s, 10 ) );//************
     uart_puts("\n\r");    //***********
    _delay_ms(20);    //***********
    
    }
...
oder ?
sorry aber hab erst vor kurzem mit dem Programmieren angefangen

Ich bekomme dann aber immernoch falsche Werte, ist das vielleicht wenn 
genau dann ein Flankenwechsel zwischen cli(); und sei(); auftritt?
Auch wenn ich OCR1B= pulse; direkt in der ISR setzte stimmt der Impuls 
auf dem Oszi nicht immer ??

Autor: Lu Ke (luke)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter wrote:

> Na super. Dann lerne doch erstmal Programmieren, bevor du versuchst, zu
> rechnen!
>
> Die Überschrift lautete wohl treffender:
> Bin ich noch blöder als ich aussehe?!

Da bin ich gerade dabei, ich kann aber nicht alles auf Anhieb und suche 
deshalb Hilfe im Forum. Auf solch blöde Kommentare von Leuten wie dir 
kann ich dabei gerne verzichten. Du konntest wahrscheinlich alles gleich 
auf Anhieb ...

Autor: Gastarbeiter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
na.. er ist halt der SUPER PETER ;-) (legte sein Rosarotes Cape um die 
Schultern und flog davon .. plopp).

Aber mach dir nix draus es gibt halt immer wieder so überaus schlaue 
Menschen, die von sich meinen alles überall und immer besser gemacht zu 
haben oder die gleich als Superhacker(es gibbet nur einen!) auf die Welt 
gekommen sind fg

in diesen Sinne  .. die Macht ist bei dir Luke!!


Gruß euer Superhacker

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Die Überschrift lautete wohl treffender:
> Bin ich noch blöder als ich aussehe?!

Na du Superprogrammierer. Wo liegt denn das Problem in
diesem Programm? Ich halte mich nicht für einen schlechten
Programmierer und ich bin weis Gott kein Anfänger. Aber
ich sehe das Problem auch nicht.

Also Super-Peter. Erhelle uns.

@Lukas

Mach dir nichts draus.
Dein Problem ist knifflig. Irgendetwas übersehen wir
(oder der Compiler). Ich hab schon versucht mal mit einem
Taschenrechner ein bischen mit den Zahlen zu spielen um
rauszukriegen, was hier tatsächlich gerechnet wird. Aber
irgendwie komme ich auf keinen grünen Zweig.

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also ich wuerd die Variablen kopieren mit sei() cli() eingeschlossen und 
dann ersst per UART versenden... ist natürlich nur jezt sone Idee.

Autor: Lu Ke (luke)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das hab ich auch schon versucht ;-), aber selbst wenn ich direkt in der 
ISR den OCR1B setzte und die RS232 deaktiviere funktioniert es nicht :-(
aber trotzdem Vielen Dank für Eure Vorschläge

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hmmm, Da muss Deep Thought seine Finger im Spiel haben... Ist Dir 
aufgefallen, dass alle falschen Zahlenwerte mit 42 anfangen? ;-)

Ich habe mir das ganze jetzt auch mal genauer angesehen, aber kein 
System bei den falschen Werten gefunden (eben bis auf die o.g. 
Tatsache). An der Auswertung an sich scheint nichts verkehrt zu sein.

@Läubi:
Genau das macht er ja jetzt. Da dürfte es keine Kollisionen mehr geben.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lukas Keller wrote:
> Also wenn ich das richtig verstanden habe müsste ich das dann so machen:
>
> ...
> while(1)
>     {
>     cli();
>     rise1=rise;
>     fall1=fall;
>     pulse1=pulse;                // pulse duration
>     sei();
>     OCR1B= pulse1;
>     uart_puts( utoa( rise1, s, 10 ) );//************
>     uart_puts("\t");    //***********
>     uart_puts( utoa( fall1, s, 10 ) );//************
>     uart_puts("\t");    //***********
>     uart_puts( utoa( pulse1, s, 10 ) );//************
>      uart_puts("\n\r");    //***********
>     _delay_ms(20);    //***********
> 
>     }
> ...
> 
> oder ?

Sieht gut aus.

> Ich bekomme dann aber immernoch falsche Werte,

Sind die falschen Werte immer noch im Bereich von ~43000
oder hat sich dieser Wertebereich in Richtung 64000 verschoben?

Autor: Läubi .. (laeubi) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja sorry. Ich hab zuwenig geschalfen.
Komm auch nicht drauf einzige idee wäre --> Überlauf
War da nicht mal was das manche COmpiler andere Datenwortlängen haben 
als die Orginal "PC-Typen"???
(Welchen Wertbereich hat unsigned short?)

Autor: Obelix (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie ich schon ober geschrieben habe, was sagt dein Debugger?

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vielleicht meinte der Super-Peter, daß ne Klammerung fehlt und man auch 
mit Einrückung arbeiten sollte.

Probier mal das hier:
ISR(SIG_INTERRUPT0)
{
  if (PIND&(1<<PD2)){              // rising edge
    rise = TCNT1;
    return;
  }
                                   // falling edge      
  fall = TCNT1;
  pulse = fall-rise;
}


Peter

Autor: willivonbienemaya (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> (Welchen Wertbereich hat unsigned short?)

sizeof sagt im AVR Studio "2".
Also ist es eine 16 bit Zahl. Das sollte passen.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab da eine Theorie.

Wenn ich deine ISR mal etwas einrücke, kommt folgendes
heraus.
ISR(SIG_INTERRUPT0)
{
  if (PIND&(1<<PD2))              // rising edge
    rise = TCNT1;
  else if (!(PIND&(1<<PD2)))          // falling edge      
    fall = TCNT1;

  pulse = fall-rise;
}

Das Problem ist jetzt, dass du pulse auch dann neu berechnest
wenn du einen neuen rise Wert hast. In dem Fall macht aber
eine pulse Berechnung keinen Sinn, denn du Berechnest hier
die Zeit von der letzten fallenden Flanke zur jetzigen
steigenden Flanke.
In den meisten Fällen ist diese unnötige Berechnung belanglos,
nur ab und zu erwischt du in main() die Berechnung in einem
Zustand, in dem genau dieser Zustand herrscht: Du hast nicht
die Zeit von der steigenden bis zur fallenden Flanke berechnet
sondern von der fallenden Flanke bis zur steigenden Flanke.

Vorschlag:
Probier mal:
ISR(SIG_INTERRUPT0)
{
  if (PIND&(1<<PD2))              // rising edge
    rise = TCNT1;
  else if (!(PIND&(1<<PD2))) {          // falling edge      
    fall = TCNT1;
    pulse = fall-rise;
  }
}

  

Autor: Rene Zimmermann (renezimmermann)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

was passiert wenn du
pulse = fall - rise;
 aus der ISR raus nimmst und direkt bei
uart_puts( utoa( fall - rise, s, 10 ) );
 einfügst?

Immer noch das gleiche oder richtig oder "anders falsch" ?

Gruß Rene

Autor: elko (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

hat wohl eher nichts mit rechnen zu tun kontrolliere doch mal zeile 14

13353  39797  1529

das ist wohl auch nicht ganz richtig. solch fehler kommen mindestens 4 
mal vor
Gruß elko

Autor: Lu Ke (luke)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Habe nur einen ISPMKII, und mit dem Softwaredebugging bin ich auch nicht 
weiter gekommen, aber wenn ich es so mache dann geht es :-) fragt mich 
nicht warum aber es geht !!
ISR(SIG_INTERRUPT0)
  {
  if (PIND&(1<<PD2))              // rising edge
  rise = TCNT1;
  else if (!(PIND&(1<<PD2)))          // falling edge      
  {
  fall = TCNT1;
  pulse = fall-rise;
  OCR1B= pulse;
  }
  }

Danke nochmal für eure Bemühungen

@Karl heinz Buchegger:
Danke genau das war das Problem

Autor: Currywurst (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kleines Gedankenexperiment.
Darf man bei unsigned int einfach so Subtrahieren ohne auf die Grösse 
der operanden zu achten?
Der Identifier "unsigned" bedeutet doch "ohne Vorzeichen"
Beispiel:
Unsigned int a,b,c;
a = 30000;
b = 32000;
c = a - b
Nach Adam Riese:
30000 - 32000 = -2000
Aber da "unsigned" VAriablen nicht negativ werden können, was steht dann 
wohl in Variable c?

In deinem Code steht:
/*
.
.
.
volatile  unsigned short int rise;
volatile  unsigned short int fall;
volatile  unsigned short int pulse;
.
.
.
pulse = fall-rise;
*/

Autor: johnny.m (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Aber da "unsigned" VAriablen nicht negativ werden können, was steht dann
> wohl in Variable c?
Da steht die Zweierkomplement-Darstellung von "-2000", also 0xF830 oder 
63536...

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lukas Keller wrote:
> aber wenn ich es so mache dann geht es :-) fragt mich
> nicht warum aber es geht !!

Also doch.
Du hast eine Race Condition.

Das eigentliche Problem ist, dass du unsynschronisiert
aus der main Schleife auf die Variablen zugreifst
(das erklärt auch die Anomalie, die elok entdeckt hat)

Deine main() Schleife kümmert sich nicht darum, ob eine
vollständige Messung (also Detektierung der rising edge,
Detektierung der falling edge und Berechnung der Pulsdauer)
erfolgt ist.

Angenommen du hast eine vollständige Messung
Die rising edge war 13059
die falling edge war 15089

dann wird eine neue rising edge festgestellt.
Neuer Wert 14234

Aber noch bevor die falling Edge kommt, greift sich das
Hauptprogramm die Werte ab und erhält:

rising edge 14234
falling edge 15089

Du hast also 2 Messwerte aus völlig unterschiedlichen Messungen.

Du musst dir ein Flag in der ISR setzten, dass der main() Schleife
signalisiert, dass die Messung vollständig ist.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Lukas Keller wrote:
> Habe nur einen ISPMKII, und mit dem Softwaredebugging bin ich auch nicht
> weiter gekommen, aber wenn ich es so mache dann geht es :-) fragt mich
> nicht warum aber es geht !!

Hat Karl Heinz doch erklärt.

Und das 2.Testen des Pins ist unnütz.
Wenn er nicht 1 war, muß er 0 sein. Binärsignale können nur 2 Zustände 
haben.
Schau Dir mal mein oberes Posting an.


Peter

Autor: Lu Ke (luke)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@ Peter:

ja das hab ich gelesen, allerdings erst nach meinem posting,
danke für den tipp mit der unnützen Abfrage, is ja eigenlich klar ;-)

Autor: Karl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>ja das hab ich gelesen, allerdings erst nach meinem posting,
>danke für den tipp mit der unnützen Abfrage, is ja eigenlich klar ;-)

Eigentlich war der Fehler von Anfang an klar. Uneigentlich auch. Wie 
schrieb der Typ weiter oben? Wer nichr Programmieren kann, sollte nicht 
auch noch versuchen, Probleme zu lösen. Bei deiner Überheblichkeit wirst 
du es nicht weit bringen. Wir habe dir diesmal weitergeholfen, aber 
gelernt hast du nichts.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Karl wrote:
>>ja das hab ich gelesen, allerdings erst nach meinem posting,
>>danke für den tipp mit der unnützen Abfrage, is ja eigenlich klar ;-)
>
> Eigentlich war der Fehler von Anfang an klar.

Warum hast du dann nicht gleich mit dem Finger darauf gezeigt?
Ich kann mich nicht erinnern, ein Posting von dir gesehen zu haben.

> schrieb der Typ weiter oben? Wer nichr Programmieren kann, sollte nicht
> auch noch versuchen, Probleme zu lösen.

Von dem Typen hab ich zwar einige blöde Sprüche in Erinnerung
aber seltsamerweise ist mir keine einzige C-Problemlösung von
ihm im Gedächtnis geblieben.

Es ist hinterher immer leicht, gescheit zu sein.
Du kennst die urban legend von Kolumbus und dem Ei?

> Bei deiner Überheblichkeit wirst
> du es nicht weit bringen.

Ich seh in seinen Antworten keineswegs Überheblichkeit.
Wenn man das erste mal auf race conditions trifft, dann können
die einem den Schlaf rauben. Und dafür, dass er noch nicht
lange µC programmiert, ist sein Programm wirklich nicht schlecht
geschrieben. Zumindest wurde hier schon jede Menge schlechteres
Material präsentiert.

> Wir habe dir diesmal weitergeholfen, aber
> gelernt hast du nichts.

Das kannst du natürlich beurteilen. Und bevor du fragst:
Nein, ich kann es auch nicht beurteilen. Aber zumindest hab
ich versucht ihm zu erklären, wo das Problem liegt und wenn
er die Erklärung nur halbwegs verstanden hat, dann hat er schon
eine Menge dabei gelernt.

Autor: Lu Ke (luke)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das sollte auch keineswegs überheblich gemeint sein. Ich bin froh hier 
im Forum so tolle und schnelle Hilfe gefunden zu haben.

@ Karl heinz Buchegger:
Ja Danke deine Erklärungen haben mir sehr weitergeholfen, war super 
verständlich geschrieben.

Autor: Gastarbeiter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Karl & || (Super)Peter//...

typedef enum {nicht_wirklich, ein_bissl, joah, glasklar} t_verstanden;

//Programmierer vs. Problemlösung
void lies( unsigned char auge, unsigned char iq_of_g_hirn, t_verstanden 
verstanden)
{
 if(auge && iq_of_g_hirn > 20) //Augen auf und Iq über 20?
 {
  if(verstanden != glas_klar) loop_hammer(); //nochmal
 }
}
void loop_hammer(void);
{
 unsigned char i;
 for(i=0; i < 100; i++)
 {
   printf("Persönlichkeiten werden nicht");
   printf("durch schöne Reden geformt");
   printf("sondern durch Arbeit und eigene Leistung")
   //Albert Einstein
 }
}

Autor: Christoph H. (derschrauber)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Gastarbeiter wrote:

> void loop_hammer(void);
Das Semikolon solltest Du da besser entfernen...

>    printf("Persönlichkeiten werden nicht");
>    printf("durch schöne Reden geformt");
>    printf("sondern durch Arbeit und eigene Leistung")
Und hier jeweils eins hinter die Zeilen - ich würde auch noch ein \n ans 
String-Ende setzen, sonst wird die Ausgabe recht unleserlich.

Autor: Sven S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich tip mal auf einen überlauf.

volatile  unsigned short int x;

würd ich nicht so schreiben. besser wäre uint16_t x;
versuchs mal mit nem 32bit breiten wort. bin jetzt zu müd um das genau 
durchzurechnen müsste aber glaub schon ein 32bit wort sein.

gruss sven

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.