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


von Lu K. (luke)


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:
1
#include <avr/io.h>
2
#include <avr/interrupt.h> 
3
#include <stdlib.h>      // ***********nur debug*******
4
#include <util/delay.h>
5
volatile  unsigned short int rise;
6
volatile  unsigned short int fall;
7
volatile  unsigned short int pulse;
8
//*********
9
int uart_putc(unsigned char c);
10
void uart_puts (char *s);
11
char s[7];
12
//***********
13
int main()
14
  {
15
16
  // debug rs232
17
18
  UBRR0 = 0x33;          // 9600 BAUD
19
  UCSR0A =0x00;
20
  UCSR0B =0x18;          //Enable Tx,Rx
21
  UCSR0C =0x06;          //async. 8bit,1 Stoppbit
22
23
  // Timer1 Init
24
25
  TCCR1B |= (1<<CS11);              // Prescaler clk/8
26
  TCCR1C |= (1<<FOC1B);              
27
  TIMSK1 |= ((1<<TOIE1)|(1<<OCIE1B));        // Overflow,Compare Interrupt enable
28
  // Interrupt settings
29
30
  EICRA  |= (1<<ISC00);              // Logical Change generates Interrupt
31
  EIMSK  |= (1<<INT0);              // enable INT0
32
  sei();                      // enable global Interrupts
33
34
  // Ports
35
  DDRD = 0x00;                  // Input
36
  PORTD |= (1<<PD2);                // pullup PD2 on
37
  DDRB  |= (1<<PB2);                // PB2 output
38
39
  while(1)
40
    {
41
              
42
    OCR1B= pulse;                // pulse duration
43
    uart_puts( utoa( rise, s, 10 ) );//************
44
    uart_puts("\t");    //***********  
45
    uart_puts( utoa( fall, s, 10 ) );//************
46
    uart_puts("\t");    //***********
47
    uart_puts( utoa( pulse, s, 10 ) );//************
48
     uart_puts("\r");    //***********
49
    _delay_ms(20);    //***********
50
    }
51
  }
52
53
ISR(SIG_INTERRUPT0)
54
  {
55
  if (PIND&(1<<PD2))              // rising edge
56
  rise = TCNT1;
57
  else if (!(PIND&(1<<PD2)))          // falling edge      
58
  fall = TCNT1;
59
  pulse = fall-rise;
60
  }
61
62
ISR(SIG_OVERFLOW1)
63
  {
64
  PORTB = 0xff;
65
  }
66
67
ISR(SIG_OUTPUT_COMPARE1B)
68
  {
69
  PORTB = 0x00;
70
  }
71
72
73
//***************************nur debug**********
74
int uart_putc(unsigned char c)
75
  {
76
    while (!(UCSR0A & (1<<UDRE0)));  /* warten bis Senden moeglich */
77
       
78
    UDR0 = c;                      /* sende Zeichen */
79
    return 0;
80
  }
81
    
82
void uart_puts (char *s)
83
{
84
    while (*s)
85
    {   /* so lange *s != '\0' also ungleich dem "String-Endezeichen" */
86
        uart_putc(*s);
87
        s++;
88
    }
89
}

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

von Obelix (Gast)


Lesenswert?

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

von A.K. (Gast)


Lesenswert?

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

von Peter D. (peda)


Lesenswert?

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

Peter

von Lu K. (luke)


Lesenswert?

Hoppla das ging ja schnell !

Also wenn ich das richtig verstanden habe müsste ich das dann so machen:
1
...
2
while(1)
3
    {
4
    cli();          
5
    rise1=rise;
6
    fall1=fall;
7
    pulse1=pulse;                // pulse duration
8
    sei();
9
    OCR1B= pulse1;
10
    uart_puts( utoa( rise1, s, 10 ) );//************
11
    uart_puts("\t");    //***********  
12
    uart_puts( utoa( fall1, s, 10 ) );//************
13
    uart_puts("\t");    //***********
14
    uart_puts( utoa( pulse1, s, 10 ) );//************
15
     uart_puts("\n\r");    //***********
16
    _delay_ms(20);    //***********
17
    
18
    }
19
...
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 ??

von Lu K. (luke)


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

von Gastarbeiter (Gast)


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

von Karl H. (kbuchegg)


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.

von Läubi .. (laeubi) Benutzerseite


Lesenswert?

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

von Lu K. (luke)


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

von johnny.m (Gast)


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.

von Karl H. (kbuchegg)


Lesenswert?

Lukas Keller wrote:
> Also wenn ich das richtig verstanden habe müsste ich das dann so machen:
>
1
> ...
2
> while(1)
3
>     {
4
>     cli();
5
>     rise1=rise;
6
>     fall1=fall;
7
>     pulse1=pulse;                // pulse duration
8
>     sei();
9
>     OCR1B= pulse1;
10
>     uart_puts( utoa( rise1, s, 10 ) );//************
11
>     uart_puts("\t");    //***********
12
>     uart_puts( utoa( fall1, s, 10 ) );//************
13
>     uart_puts("\t");    //***********
14
>     uart_puts( utoa( pulse1, s, 10 ) );//************
15
>      uart_puts("\n\r");    //***********
16
>     _delay_ms(20);    //***********
17
> 
18
>     }
19
> ...
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?

von Läubi .. (laeubi) Benutzerseite


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

von Obelix (Gast)


Lesenswert?

Wie ich schon ober geschrieben habe, was sagt dein Debugger?

von Peter D. (peda)


Lesenswert?

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

Probier mal das hier:
1
ISR(SIG_INTERRUPT0)
2
{
3
  if (PIND&(1<<PD2)){              // rising edge
4
    rise = TCNT1;
5
    return;
6
  }
7
                                   // falling edge      
8
  fall = TCNT1;
9
  pulse = fall-rise;
10
}


Peter

von willivonbienemaya (Gast)


Lesenswert?

> (Welchen Wertbereich hat unsigned short?)

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

von Karl H. (kbuchegg)


Lesenswert?

Ich hab da eine Theorie.

Wenn ich deine ISR mal etwas einrücke, kommt folgendes
heraus.
1
ISR(SIG_INTERRUPT0)
2
{
3
  if (PIND&(1<<PD2))              // rising edge
4
    rise = TCNT1;
5
  else if (!(PIND&(1<<PD2)))          // falling edge      
6
    fall = TCNT1;
7
8
  pulse = fall-rise;
9
}

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:
1
ISR(SIG_INTERRUPT0)
2
{
3
  if (PIND&(1<<PD2))              // rising edge
4
    rise = TCNT1;
5
  else if (!(PIND&(1<<PD2))) {          // falling edge      
6
    fall = TCNT1;
7
    pulse = fall-rise;
8
  }
9
}

  

von Rene Z. (renezimmermann)


Lesenswert?

Hi,

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

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

Gruß Rene

von elko (Gast)


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

von Lu K. (luke)


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 !!
1
ISR(SIG_INTERRUPT0)
2
  {
3
  if (PIND&(1<<PD2))              // rising edge
4
  rise = TCNT1;
5
  else if (!(PIND&(1<<PD2)))          // falling edge      
6
  {
7
  fall = TCNT1;
8
  pulse = fall-rise;
9
  OCR1B= pulse;
10
  }
11
  }

Danke nochmal für eure Bemühungen

@Karl heinz Buchegger:
Danke genau das war das Problem

von Currywurst (Gast)


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;
*/

von johnny.m (Gast)


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

von Karl H. (kbuchegg)


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.

von Peter D. (peda)


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

von Lu K. (luke)


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 ;-)

von Karl (Gast)


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.

von Karl H. (kbuchegg)


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.

von Lu K. (luke)


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.

von Gastarbeiter (Gast)


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

von Christoph H. (Gast)


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.

von Sven S. (Gast)


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

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.