Forum: Mikrocontroller und Digitale Elektronik Encoder Winkel ?


von Michael H. (h_m)


Lesenswert?

Hallo,

ich möchte mit einem Encoder 250 Teilungen der nach dem Auswerten 1000 
Zählimpulse hat mir den Winkel Seriell auf meinem Hterm anzeigen lassen.

dazu muß ich 1000/360= 2.777 Grad Pro Schritt Rechnen richtig ?

jetzt habe ich aber bei der Ausgabe ein Problem, das der Wert überhaupt 
nicht stimmt.

das mit Sicherheit an meiner Schreibweise für die Ausgabe liegt. Da hab 
ich natürlich schon verschiedene Varianten ausprobiert, aber aktuell 
habe ich es so, da wird mir nur ein ? \r\n angezeigt
1
  printf("\r\n %f", enc_delta/1000*2.77   );
1
volatile float  enc_delta;


Wie kann ich das richtig ausgeben das ich mir den winkel von 0-360 Grad 
ausgeben kann ?

kann mir das Bitte jemand zeigen, ich habe auch ein Buch wo das mit den 
Ausgabeformaten steht, mit % i, d, f, c usw. aber Irgenwie steig ich da 
gerade nicht durch.


Grüsse Huber

von Barrex (Gast)


Lesenswert?

Du hast den Dreisatz einfach nur falsch angewendet.

Überlege Dir, ob dein zu berechnender Winkel zu 360 oder 1000 gehört!
Überlege Dir, ob Dein enc_delta zu 360 oder 1000 gehört!

Wenn Dir das klar ist, erstelle die passende Verhältnisgleichung.

von Barrex (Gast)


Lesenswert?

Im übrigen hilft es bei der Erstellung von Gleichungen die 
physikalischen Einheiten mitzuführen. Kommt die richtige einheit raus, 
ist die Wahrscheinlichleit hoch das die Gleichung stimmt. Passt die 
Einheit des Ergebnisses nicht, stimmt die Gleichung nicht.

von Michael H. (h_m)


Lesenswert?

also dasmit der berechnug bekomme ich dann schon hin, mein Problem ist 
die richtige Ausgabe.

ich dachte, wenn ich mit komma Zahelen rechne, dann muss ich die 
Variable in float benennen und bei der Ausgabe auch auf float achten 
"%f" da kommt nur ein ? raus und %d kommt nur irgendwas mit +30000 und - 
30000 am terminal



1
 #define F_CPU 16000000UL
2
 #define BAUD  9600UL
3
 
4
 #include <util/delay.h>
5
 #include <string.h>
6
 #include <stdlib.h>
7
 #include <stdio.h>
8
 #include <ctype.h>
9
 #include <avr/io.h>
10
 #include <avr/interrupt.h>
11
 #include "serial2.h"
12
 
13
 FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, uart_getchar, _FDEV_SETUP_RW); // Wandelt putchar und getchar in printf um
14
15
// target: ATmega328
16
//------------------------------------------------------------------------
17
18
 #define XTAL        16e6             // 16MHz
19
20
#define PHASE_A     (PINB & 1<<PB0)
21
#define PHASE_B     (PINB & 1<<PB1)
22
23
#define LEDS_DDR    DDRC
24
#define LEDS        PORTC           // LEDs against VCC
25
26
27
volatile float  enc_delta;         // Variable Zählimpuls
28
static int8_t last;
29
30
31
void encode_init( void )
32
{
33
  int8_t new;
34
35
  new = 0;
36
  if( PHASE_A ) new = 3;
37
  if( PHASE_B ) new ^= 1;       // convert gray to binary
38
  last = new;                   // power on state
39
  enc_delta = 0;
40
  TCCR1B = (1<<WGM12) | (1<<CS10) ;   // CTC, prescaler 1
41
  OCR1A = (uint8_t)(XTAL/ 1.0 * 1e-4 - 0.5);   // 1ms
42
  TIMSK1 |= 1<<OCIE1A;
43
}
44
45
46
ISR( TIMER1_COMPA_vect )            // 1ms for manual movement
47
{
48
  int8_t new, diff;
49
50
  new = 0;
51
  if( PHASE_A ) new = 3;
52
  if( PHASE_B ) new ^= 1;          // convert gray to binary
53
  diff = last - new;               // difference last - new
54
  if( diff & 1 ) {                 // bit 0 = value (1)
55
    last = new;                    // store new as next last
56
    enc_delta += (diff & 2) - 1;   // bit 1 = direction (+/-)
57
  }
58
}
59
60
61
int8_t encode_read1( void )         // read single step encoders
62
{
63
  int8_t val;
64
65
  cli();
66
  val = enc_delta;
67
  enc_delta = 0;
68
  sei();
69
  return val;                   // counts since last call
70
}
71
72
73
74
75
int main( void )
76
{
77
   uart_init(F_CPU, BAUD);
78
   stdout = stdin = &mystdout;
79
   
80
   
81
  int32_t val = 0;
82
83
  LEDS_DDR = 0xFF;
84
  encode_init();
85
  sei();
86
  
87
       while (1)
88
       {
89
        
90
         printf("\r\n %d", enc_delta*0.36   );
91
         //_delay_ms(10);
92
        
93
       }
94
      
95
96
  for(;;)
97
  {
98
    val += encode_read1();          // read a single step encoder
99
    LEDS = val;
100
  }
101
    
102
  
103
}

von Hauke Haien (Gast)


Lesenswert?

Michael H. schrieb:
> also dasmit der berechnug bekomme ich dann schon hin, mein Problem ist
> die richtige Ausgabe.

Das sieht hier aber ganz anders aus.
Der Encoder gibt dir 1000 Inkremente / 360°.
Ein Inkrement entspricht demnach einem Tausendstel von 
dreihundertsechzig grad.
Klingelts!?

von Michael H. (h_m)


Lesenswert?

Hauke Haien schrieb:
> Michael H. schrieb:
>> also dasmit der berechnug bekomme ich dann schon hin, mein Problem ist
>> die richtige Ausgabe.
>
> Das sieht hier aber ganz anders aus.
> Der Encoder gibt dir 1000 Inkremente / 360°.
> Ein Inkrement entspricht demnach einem Tausendstel von
> dreihundertsechzig grad.
> Klingelts!?
1
printf("\r\n %d", enc_delta*0.36   );
1
printf("\r\n %i", enc_delta*0.36   );
1
printf("\r\n %f", enc_delta*0.36   );
1
printf("\r\n %c", enc_delta*0.36   );
1
printf("\r\n %o", enc_delta*0.36   );
1
printf("\r\n %s", enc_delta*0.36   );

1000*0.36= 360

aber ich bekomme ja das richtige Ausgabeformat nicht hin, das es mir den 
Wert richtig im Terminal anzeigt, egal was ich von oben genannten 
probiere bekomme ich irgend etwas auf dem Terminal angezeigt aber keine 
komma Zahl.

von Barrex (Gast)


Lesenswert?

Ausgabe float variable:

float value = 0.0;
printf("value = %f\n",value);

Das stimmmt schon so. Allerdings ist die Frage ob die Verwendung von %f 
im printf in den AVR Bibliotheken überhaupt realisiert ist. Denn die 
Verwendung von float kostet ziemlich viel Ressourcen. Das muss dir aber 
ein AVR Experte beantworten.

In der Regel ist es besser rein mit Integer-Variablen zu arbeiten, 
sprich also mit Festkomma Zahlen. und dafür dann eine eigene 
Ausgabefunktion zu schreiben.

von Barrex (Gast)


Lesenswert?

Es kann sogar sein, dass Du solche ausgabe Funktionen wie printf() 
sowieso allein implementieren musst. Eventuell sind sie zwar bekannt, 
und könnten verwendet werden aber die eigentliche Implementation fehlt 
ganz.

Denn bezogen auf den eigentlichen Mikrocontroller IC ist ja ohne 
konkrete Anwendung und Schaltung ja erstmal nicht klar, wo solche 
Ausgaben überhaupt erfolgen sollen.

Aber wie oben geschrieben, das ist ein Thema für einen AVR Experten der 
den Compiler genau kennt.

von Michael H. (h_m)


Lesenswert?

hier ist mal meine Serial.h dateies muss doch möglich sein den wert 
ausgeben zu können.

weil oben gennnant integer (Ganzzahl) mit festkomma Zahlen. Ich will 
nicht float unbedingt hernehmen, aber ich dachte float ist di einzige 
Bezeichnung mit der ich kommastellen darstellen kann

1
/ * serial2.h*/
2
3
4
#ifdef UCSR0A
5
6
//Initialisiert UART gegebener Oszillatorfrequenz und Baudrate
7
void uart_init(long Oszi, long Baud)
8
{ 
9
  if ((Oszi / 16L / Baud - 1) > 30)
10
  {    
11
    UBRR0L = (unsigned char)(Oszi /16L / Baud - 1);
12
    UBRR0H = (unsigned char)((Oszi / 16L / Baud - 1) >> 8);
13
    UCSR0A = 0; 
14
  }
15
  else
16
  {
17
    //Falls Teilerwert zu klein => Rundungsfehler
18
    //Daher doppelte Rate waehlen  
19
    UBRR0L = (unsigned char)(Oszi / 8L / Baud - 1);
20
    UBRR0H = (unsigned char)((Oszi / 8L / Baud - 1) >> 8);
21
    UCSR0A = (1 << U2X0);
22
  }
23
   
24
  UCSR0B = UCSR0B | (1 << TXEN0) | (1 << RXEN0);
25
  UCSR0C = UCSR0C | (1 << UMSEL01) | (1 << UCSZ01) | 
26
          (1 << UCSZ00);  
27
}
28
    
29
//Sendet 1 Byte an UART 
30
int uart_putchar(char data, FILE* stream) 
31
{ 
32
  while (!(UCSR0A & (1 << UDRE0)));
33
  UDR0 = (char)data;
34
  return 0;
35
} 
36
37
//Empfaengt 1 Byte vom UART
38
static int uart_getchar(FILE *STREAM) 
39
{ 
40
  while (!(UCSR0A & (1 << RXC0))); 
41
  return (UDR0); 
42
} 
43
 
44
#else
45
46
//Initialisiert UART gegebner Oszillatorfrequenz und Baudrate
47
void uart_init(long Oszi, long Baud) 
48
{ 
49
  if ((Oszi / 16L / Baud - 1) > 30)
50
  {
51
    UBRRL = (unsigned char)(Oszi / 16L / Baud - 1);
52
    UBRRH = (unsigned char)((Oszi / 16L / Baud - 1) >> 8);
53
    UCSRA = 0x00;  
54
  }
55
  else
56
  {
57
    //Falls Teilerwert zu klein => Rundungsfehler
58
    //Daher doppelte Rate waehlen
59
    UBRRL = (unsigned char)(Oszi / 8L / Baud - 1);
60
    UBRRH = (unsigned char)((Oszi /8L / Baud - 1) >> 8);
61
    UCSRA = (1 << U2X);
62
  }
63
  
64
  UCSRB = UCSRB | (1 << TXEN) | (1 << RXEN); //RX TX Enable
65
  //Bit Mode
66
  CSRC =  UCSRC | (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);
67
}
68
    
69
//Sendet 1 Byte an UART
70
int uart_putchar(char data, FILE* stream)
71
{
72
  while (!(UCSRA & (1 << UDRE)));
73
  UDR = (char)data;
74
  return 0;
75
}   
76
77
//Empfaengt 1 Byte vom UART
78
int uart_getchar(FILE* stream) 
79
{ 
80
  while (!(UCSRA & (1 << RXC))); 
81
  return (UDR); 
82
}
83
 
84
#endif

von Yalu X. (yalu) (Moderator)


Lesenswert?

Michael H. schrieb:
> "%f" da kommt nur ein ? raus

Dann musst du das hier lesen und befolgen:

  http://nongnu.org/avr-libc/user-manual/group__avr__stdio.html#gaa3b98c0d17b35642c0f3e4649092b9f1

1
Since the full implementation of all the mentioned features becomes
2
fairly large, three different flavours of vfprintf() can be selected
3
using linker options.
4
...

von Frickelfritze (Gast)


Lesenswert?

Bevor das hier zur float-Orgie ausartet:

#include<stdio.h>
1
int main() 
2
{
3
   unsigned int hundertselgrad = 18234;
4
   while (1)
5
   {
6
    printf("Winkel ist  %u.%02u Grad\r\n", hundertselgrad/100, hundertselgrad%100);
7
    //delay_ms(1000);
8
    hundertselgrad += 456;
9
   }
10
   
11
}

von Michael H. (h_m)


Lesenswert?

Frickelfritze schrieb:
> int main()
> {
>    unsigned int hundertselgrad = 18234;
>    while (1)
>    {
>     printf("Winkel ist  %u.%02u Grad\r\n", hundertselgrad/100,
> hundertselgrad%100);
>     //delay_ms(1000);
>     hundertselgrad += 456;
>    }

Danke, das ist ein Traum. unter welchen Schlagwort kann ich denn das 
noch im Netz finden. alles aber das steht nicht in meinem Buch

von Barrex (Gast)


Lesenswert?

Festkommazahlen ist das Stichwort. :-)

von M. K. (sylaina)


Lesenswert?

Michael H. schrieb:
> aber ich bekomme ja das richtige Ausgabeformat nicht hin, das es mir den
> Wert richtig im Terminal anzeigt, egal was ich von oben genannten
> probiere bekomme ich irgend etwas auf dem Terminal angezeigt aber keine
> komma Zahl.

Das liegt wahrscheinlich an die printf-Geschichte, da muss man was am 
Linker oder so einstellen damit printf auch %f kann. Ich umgehe das nur 
immer mit folgendem Code weshalb ich da nicht genau sagen kann was da im 
Busch ist.
1
...
2
float myFloat = 3.1415;
3
char myValueToSend[7];
4
...
5
dtostrf(myFloat,  // Variable die zum String gewandelt werden soll
6
        6,        // Gesamtzahl der Stellen incl. Komma
7
        4,        // Zahl der Nachkommastellen
8
        myValueToSend); // String-Variable, in die die Wandlung soll
9
printf("Winkel ist ");
10
printf(myValueToSend);
11
printf(" Grad\r\n);
12
...

: Bearbeitet durch User
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.