Forum: Mikrocontroller und Digitale Elektronik Problem mit c Programm ATmega32


von jan (Gast)


Angehängte Dateien:

Lesenswert?

Folgender code funktioniert:
1
while(1)
2
  {
3
    
4
    if(calculateRpm)
5
    {
6
      if(rpmTemp > 0)
7
      {
8
        //6 steps per revolution
9
        //time per tick 32 us
10
        
11
        rpmTemp *= 6 * 32; //get periodtime for one revolution
12
        //period time in us
13
        
14
        rpmTemp = 10000000 / rpmTemp;
15
        //temp is now 1/10 rpm;
16
        rpmTemp *= 60;
17
        lastRpms[lastRpmsPos] = rpmTemp & 0xFFFF;
18
      }
19
      else
20
      {
21
        lastRpms[lastRpmsPos] = 0x00;
22
      }
23
      
24
      
25
      
26
      lastRpmsPos++;
27
      if (lastRpmsPos >= lastRpmsSize)
28
      {
29
        lastRpmsPos = 0;
30
      }
31
      
32
      tempU32 = 0;
33
      for(counter = 0;counter < lastRpmsSize; counter++)
34
      {      
35
        tempU32 += lastRpms[counter];
36
      }
37
      rpmAverage = tempU32 / lastRpmsSize;
38
            
39
         if(sendRpm == 1)
40
         {
41
           
42
           rpm_to_string(rpmString,rpmAverage,motor.direction);
43
           UART_send_blocking_string(rpmString);
44
           
45
           sendRpm = 0;
46
         }
47
        
48
      calculateRpm = 0;
49
      lockRpm = 0;
50
    }  
51
      
52
  }

In diesem Fall bekomme ich am RS232 Terminal am pc "-0300.0".

jedoch bei dieser Version:
1
int main(void)
2
{
3
  uint32_t tempU32;
4
  uint8_t counter;
5
  
6
  init();
7
  
8
  
9
  
10
  while(1)
11
  {
12
    
13
    if(calculateRpm)
14
    {
15
      if(rpmTemp > 0)
16
      {
17
        //6 steps per revolution
18
        //time per tick 32 us
19
        
20
        rpmTemp *= 6 * 32; //get periodtime for one revolution
21
        //period time in us
22
        
23
        rpmTemp = 10000000 / rpmTemp;
24
        //temp is now 1/10 rpm;
25
        rpmTemp *= 60;
26
        lastRpms[lastRpmsPos] = rpmTemp & 0xFFFF;
27
      }
28
      else
29
      {
30
        lastRpms[lastRpmsPos] = 0x00;
31
      }
32
      
33
      
34
      
35
      lastRpmsPos++;
36
      if (lastRpmsPos >= lastRpmsSize)
37
      {
38
        lastRpmsPos = 0;
39
      }
40
      
41
      tempU32 = 0;
42
      for(counter = 0;counter < lastRpmsSize; counter++)
43
      {
44
        tempU32 += lastRpms[counter];
45
      }
46
      rpmAverage = tempU32 / lastRpmsSize;
47
      
48
      if(sendRpm == 1)
49
      {
50
        
51
        rpm_to_string(rpmString,rpmAverage,motor.direction);
52
        UART_send_blocking_string(rpmString);
53
        
54
        sendRpm = 0;
55
      }
56
      
57
      
58
      calculateRpm = 0;
59
      lockRpm = 0;
60
    }    
61
  }
62
}

Kommt am Terminal nur -0.000 an. Meine rpm_to_string Funktion und meine 
UART_send_blocking_string Funktion funktioniert ja.

Variablen Definitionen (global):
1
volatile uint8_t motorDirection = 0, motorRPM = 0;
2
volatile uint8_t readyToSend = 0;
3
volatile uint8_t timer0_overflows = 0, timer0_overflow_error = 0;
4
5
uint32_t rpmTemp = 0;
6
7
#define lastRpmsSize 12
8
uint16_t lastRpms [lastRpmsSize] = {0,0,0,0,0,0,0,0,0,0,0,0};
9
uint8_t lastRpmsPos = 0;
10
volatile uint16_t rpmAverage;
11
12
volatile uint8_t calculateRpm = 0, lockRpm = 0, sendRpm = 0;
13
volatile uint8_t rpmString[8] = {0,0,0,0,0,0,0};

Versuch jetzt schon seit einer Stunde das Problem zu beheben, doch 
leider finde ich keinen Fehler. Ich hoffe ihr könnt mir helfen.

MfG
Jan

von Peter II (Gast)


Lesenswert?

jan schrieb:
> jedoch bei dieser Version:

beide Versionen sind doch gleich? (ich kann zumindest kein unterschied 
finden)

von jan (Gast)


Lesenswert?

Sry hatte beim zweiten das falsche kopiert.

Das richtige 2. Beispiel:
1
int main(void)
2
{
3
  uint32_t tempU32;
4
  uint8_t counter;
5
  
6
  init();
7
  
8
  
9
  
10
  while(1)
11
  {
12
    
13
    if(calculateRpm)
14
    {
15
      if(rpmTemp > 0)
16
      {
17
        //6 steps per revolution
18
        //time per tick 32 us
19
        
20
        rpmTemp *= 6 * 32; //get periodtime for one revolution
21
        //period time in us
22
        
23
        rpmTemp = 10000000 / rpmTemp;
24
        //temp is now 1/10 rpm;
25
        rpmTemp *= 60;
26
        lastRpms[lastRpmsPos] = rpmTemp & 0xFFFF;
27
      }
28
      else
29
      {
30
        lastRpms[lastRpmsPos] = 0x00;
31
      }
32
      
33
      
34
      
35
      lastRpmsPos++;
36
      if (lastRpmsPos >= lastRpmsSize)
37
      {
38
        lastRpmsPos = 0;
39
      }
40
      
41
      tempU32 = 0;
42
      for(counter = 0;counter < lastRpmsSize; counter++)
43
      {
44
        tempU32 += lastRpms[counter];
45
      }
46
      rpmAverage = tempU32 / lastRpmsSize;
47
      
48
      calculateRpm = 0;
49
      lockRpm = 0;
50
    }
51
    //sendRpm = 1;
52
    if(sendRpm == 1)
53
    {
54
      
55
      rpm_to_string(rpmString,rpmAverage,motor.direction);
56
      UART_send_blocking_string(rpmString);
57
      
58
      sendRpm = 0;
59
    }
60
        
61
  }
62
}

Übrigens: wenn ich das //sendRpm = 1; einkommentiere, bekomm ich auch 
die richtigen Werte.

von Peter II (Gast)


Lesenswert?

1
volatile uint8_t calculateRpm = 0, lockRpm = 0, sendRpm = 0;
2
[c]
3
ich bin mir nicht sicher ob das volatile wirklich für alle Variabel gilt.
4
5
schreibe es doch gleich lesbar.
6
7
[c]
8
volatile uint8_t calculateRpm = 0;
9
volatile uint8_t lockRpm = 0;
10
volatile uint8_t sendRpm = 0;

hätte sogar den Vorteil da man noch Kommentare für die Variablen 
verwenden kann.

von jan (Gast)


Lesenswert?

Hab das bei allen Variablen gemacht, brachte keinen Unterschied.

Wie gesagt bei dieser Form funktioniert es ja:
1
int main(void)
2
{
3
  uint32_t tempU32;
4
  uint8_t counter;
5
  
6
  init();
7
  
8
  
9
  
10
  while(1)
11
  {
12
    
13
    if(calculateRpm)
14
    {
15
      .....
16
    }
17
    
18
    sendRpm = 1;
19
    if(sendRpm == 1)
20
    {
21
      
22
      rpm_to_string(rpmString,rpmAverage,motor.direction);
23
      UART_send_blocking_string(rpmString);
24
      
25
      sendRpm = 0;
26
    }
27
        
28
  }
29
}

Deswegen denke ich das der Fehler nicht am volatile liegt.

Zur Sicherheit noch meine Funktionen:
1
#define digit_to_char(digit) '0' + digit
2
3
void rpm_to_string(volatile uint8_t * string, volatile uint16_t rpms, uint8_t direction)
4
{
5
  uint8_t thousands, hundreds, tens, ones, tenths;
6
  
7
  thousands = rpms / 10000;
8
  rpms = rpms % 10000;
9
  hundreds = rpms / 1000;
10
  rpms = rpms % 1000;
11
  tens = rpms / 100;
12
  rpms = rpms % 100;
13
  ones = rpms / 10;
14
  rpms = rpms % 10;
15
  tenths = rpms;
16
  
17
  if(direction == 1)
18
  *string = '-';
19
  else
20
  *string = '+';
21
  
22
  string++;
23
  *string = digit_to_char(thousands);
24
  string++;
25
  *string = digit_to_char(hundreds);
26
  string++;
27
  *string = digit_to_char(tens);
28
  string++;
29
  *string = digit_to_char(ones);
30
  string++;
31
  *string = '.';
32
  string++;
33
  *string = digit_to_char(tenths);
34
  string++;
35
  *string = 0;
36
  
37
}
38
39
uint8_t UART_send_blocking_string(volatile uint8_t * data)
40
{
41
  if (UCSRA & (1<<UDRE)) //ready to send
42
  {
43
    while(1)
44
    {
45
      if(*data == 0x00)
46
        break;
47
        
48
      UART_send_blocking(*data);
49
      data++;
50
    }  
51
    
52
    return UART_success;
53
  }
54
55
  return UART_failed;
56
}
57
58
uint8_t UART_send(uint8_t data)
59
{
60
  if (UCSRA & (1<<UDRE)) //ready to send
61
  {
62
    UDR = data;
63
    return UART_success;
64
  }
65
  
66
  return UART_failed;
67
}

von Joe F. (easylife)


Lesenswert?

Der Unterschied deiner 2 Varianten ist doch folgender:
1. Variante (die wohl geht):
rpm_to_string und UART_send_blocking_string wird nur ausgeführt, wenn 
calculateRpm != 0 ist, und damit auch rpmAverage berechnet wurde.

Im 2. Fall hast du rpm_to_string und UART_send_blocking_string 
ausserhalb von if(calculateRpm) plaziert, so dass es beim ersten 
Durchlauf wohl so ist, dass rpmAverage 0 ist, und dies wird dann auch 
auf den UART geschickt.

Wenn doch die 1. Variante geht, warum benutzt du dann nicht einfach 
diese?

von jan (Gast)


Lesenswert?

Joe F. schrieb:
> Der Unterschied deiner 2 Varianten ist doch folgender:
> 1. Variante (die wohl geht):
> rpm_to_string und UART_send_blocking_string wird nur ausgeführt, wenn
> calculateRpm != 0 ist, und damit auch rpmAverage berechnet wurde.
>
> Im 2. Fall hast du rpm_to_string und UART_send_blocking_string
> ausserhalb von if(calculateRpm) plaziert, so dass es beim ersten
> Durchlauf wohl so ist, dass rpmAverage 0 ist, und dies wird dann auch
> auf den UART geschickt.
>
> Wenn doch die 1. Variante geht, warum benutzt du dann nicht einfach
> diese?

Komischerweise funktioniert der zweite Fall ja wenn ich "if(sendRpm = 
1).." oder "sendRpm = 1; if(sendRpm)..." ja, das heist rpmAverage ist 
nicht 0....

und ich kann die ersten Variante nicht verwenden weil calculateRpm nur 
eins wird wenn ein neuer Wert reinkommt d.h. eine Flanke am encoder... 
um Rechenleistung zu sparen. Und ich will ja die die Rpm's ja auch 
senden können wenn der Motor steht ;).

Und weiter wird auf rpmAverage nur im main code zugegriffen, daher 
wüsste ich nicht warum der Wert auf einmal 0 sein sollte.

Trotzdem Danke schonmal an eure Hilfe!

von jan (Gast)


Lesenswert?

So jetzt funktionierts:
1
int main(void)
2
{
3
  uint32_t tempU32;
4
  uint8_t counter;
5
  uint16_t plsSendMeForGodsSake = 0;
6
  init();
7
  
8
  
9
  
10
  while(1)
11
  {
12
    
13
    if(calculateRpm)
14
    {
15
      if(rpmTemp > 0)
16
      {
17
        //6 steps per revolution
18
        //time per tick 32 us
19
        
20
        rpmTemp *= 6 * 32; //get periodtime for one revolution
21
        //period time in us
22
        
23
        rpmTemp = 10000000 / rpmTemp;
24
        //temp is now 1/10 rpm;
25
        rpmTemp *= 60;
26
        lastRpms[lastRpmsPos] = rpmTemp & 0xFFFF;
27
      }
28
      else
29
      {
30
        lastRpms[lastRpmsPos] = 0x00;
31
      }
32
      
33
      
34
      
35
      lastRpmsPos++;
36
      if (lastRpmsPos >= lastRpmsSize)
37
      {
38
        lastRpmsPos = 0;
39
      }
40
      
41
      tempU32 = 0;
42
      for(counter = 0;counter < lastRpmsSize; counter++)
43
      {
44
        tempU32 += lastRpms[counter];
45
      }
46
      rpmAverage = tempU32 / lastRpmsSize;
47
      plsSendMeForGodsSake = (uint16_t)rpmAverage;
48
      calculateRpm = 0;
49
      lockRpm = 0;
50
    }
51
    
52
    //sendRpm = 1;
53
    if(sendRpm)
54
    {   
55
      rpm_to_string((uint8_t *)rpmString,plsSendMeForGodsSake,motor.direction);
56
      UART_send_blocking_string(rpmString);
57
      sendRpm = 0;
58
    }       
59
  }
60
}

aber ich versteh noch immer nicht warum es mit Bsp. 2 nicht funktioniert 
hatte.
Vielleicht findet irgendjemand das Problem, würde mich interessieren was 
ich falsch hatte.

von asdfasd (Gast)


Lesenswert?

Mal davon abgesehen, dass die gesamte Programmlogik ziemlich konfus 
aussieht, in dieser Funktion:
1
> uint8_t UART_send_blocking_string(volatile uint8_t * data)
2
> {
3
>   if (UCSRA & (1<<UDRE)) //ready to send
4
>   {
5
>     while(1)
6
>     {
7
>       if(*data == 0x00)
8
>         break;
9
> 
10
>       UART_send_blocking(*data);
11
>       data++;
12
>     }
13
> 
14
>     return UART_success;
15
>   }
16
> 
17
>   return UART_failed;
18
> }

sieht das "if" falsch und überflüssig aus.  Entweder "blocking" oder 
nicht.  Du scheisst den ganzen String weg, wenn noch ein Byte im 
Transmitter ist.

Das volatile ergibt auch keinen Sinn.  Übrig bleibt:
1
void UART_send_blocking_string(uint8_t *data)
2
{
3
    while (*data)
4
        UART_send_blocking(*data++);
5
}


PS: Die Richtung solltest du in deinem Moving-Average evtl 
mitberücksichtigen...

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.