Forum: Mikrocontroller und Digitale Elektronik Servo-Pulssignalläge messen mit Atmega328p


von l. w. (Gast)


Lesenswert?

Hallo liebes Forum,

ich möchte gerne die HIGH Pulslänge eines Modellbau Servo Signals messen 
und daraufhin LEDs ansteuern. Ich versuche aktuell von der Arduino IDE 
aufs Atmel Studio umzusteigen. In der Arduino IDE gibt es ja die 
PulseIn() Funktion. Jetzt hab ich mal im Internet nach einem Code fürs 
Atmel Studio gesucht und einen gefunden...
1
#define F_CPU 8000000UL    //internal 8MHz
2
#include <avr/io.h>
3
#include <util/delay.h>
4
5
6
unsigned long rc_value;
7
8
int main(void)
9
{
10
  DDRD = (0<<PD2); // port pd2 input rc signal
11
  DDRD = (1<<PD6); // port , output led
12
  
13
  //PORTD = (1<<PD6);    //test function led
14
  //char rc_pin_state = (PIND & (1<<PD2)); // read state of pin pd2 , put state variable
15
  
16
  while(1)
17
  {
18
    char rc_pin_state = (PIND & (1<<PD2));
19
    
20
    //timeout zone
21
    unsigned long numloops = 0;
22
    unsigned long maxloops = 500000;
23
    unsigned long width = 0;
24
    // wait previous pulse end
25
    while ( rc_pin_state == 1)
26
    {
27
      rc_pin_state = (PIND & (1<<PD2)); //keep reading pin until changes state
28
      if (numloops++ == maxloops) break;
29
    }
30
    // wait pulse start
31
    while (rc_pin_state == 0)
32
    {
33
      rc_pin_state = (PIND & (1<<PD2)); //keep reading pin until changes state
34
      if (numloops++ == maxloops) break;
35
    }
36
    
37
    // wait pulse stop @ here measuring pulse width = incrementing width value 1 each cycle. atmega328 1 micro second equal 16 cycles.
38
    while (rc_pin_state == 1)
39
    {
40
      rc_pin_state = (PIND & (1<<PD2));
41
      if (numloops++ == maxloops) break;
42
      width++;
43
    }
44
45
    rc_value = width/4;
46
    
47
    
48
    if(rc_value >= 0 && rc_value < 1600)
49
    {
50
      PORTD = (1<<PD6); // turn led on
51
    }
52
    
53
    /*else if(rc_value > 1600 && rc_value < 2200) 
54
    {
55
      PORTD = (0<<PD6); // turn led off
56
    }*/
57
  }
58
}

Hab den Code ausprobiert, aber er funktioniert nicht. Vielleicht kann 
mir da jemand weiterhelfen oder hatte schon mal ein ähnliches Projekt...
Schon mal Danke im Voraus!

von Peter D. (peda)


Lesenswert?

Zählschleifen sind immer Mist, Du hast keinerlei Kontrolle über deren 
reale Laufzeit.
Nimm die Input Capture Funktion.
Und schließe ne UART oder ein LCD zum Anzeigen der Meßwerte an.

von MaWin (Gast)


Lesenswert?

l. w. schrieb:
> Hab den Code ausprobiert, aber er funktioniert nicht

Natürlich nicht.

width sollte man vor dem Zählen mal auf 0 setzen, und ob dein maxloops 
vorher nicht zum break führt weiss man auch nicht.
Wieso width gerade bis 6400 zählen soll weiss auch keiner, einen 
stabilen Bezug zu einem Zeitgeber hat dein Programm ja nicht, hängt ganz 
von den Vompilereinstellungen zu Optimierungen ab.

So geht es also schon mal nicht.

Ob man unbedingt gleich Input Capture mit Interrupts macht, oder einfach 
nur den Timer Zählerregister ausliest um zu erfahren, wie lange etwas 
gedauert hat, ist egal.

von Toxic (Gast)


Angehängte Dateien:

Lesenswert?

l. w. schrieb:
> ich möchte gerne die HIGH Pulslänge eines Modellbau Servo Signals messen

siehe Anhang wie man es machen kann.Ist zwar fuer einen Pic aber dies 
umzusetzen auf Atmal uc's sollte kein Problem sein

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

MaWin schrieb:
> Ob man unbedingt gleich Input Capture mit Interrupts macht, oder einfach
> nur den Timer Zählerregister ausliest um zu erfahren, wie lange etwas
> gedauert hat, ist egal.
Ich würde im ersten Anlauf einfach den Eingang pollen, dann den 
Zeitstempel aus dem Timer lesen und eine Differenz berechnen. Etwa so:
1
main ()
2
  char rcpinold, rcpin;
3
  unsigned long risetime, pulsdauer;
4
  :
5
  while(1) {
6
    :
7
    rcpin = (PIND & (1<<PD2));
8
    if (rcpin!=rcpinold) { // Flanke?
9
      if (rcpin) { // steigende Flanke
10
        risetime = lesetimeraus();
11
      }
12
      else {       // fallende Flanke  --> Pulsdauer berechnen
13
        pulsdauer = lesetimeraus() - risteime;
14
      }
15
    }
16
    rcpinold = rcpin;
17
    :
18
  }
19
}
Merke: man setzt einen Zähler nie zurück. Es sei denn, man weiß genau, 
was man da tut und kann die Folgen abschätzen.

Toxic schrieb:
> l. w. schrieb:
>> ich möchte gerne die HIGH Pulslänge eines Modellbau Servo Signals messen
> siehe Anhang wie man es machen kann.I
High-Zeit != Periodendauer   ;-)

: Bearbeitet durch Moderator
von Toxic (Gast)


Angehängte Dateien:

Lesenswert?

Toxic schrieb:
> siehe Anhang wie man es machen kann.

falsches Bild gepostet...

von MaWin (Gast)


Lesenswert?

MaWin schrieb:
> width

Äh, numloops meinte ich.

von l. w. (Gast)


Lesenswert?

@Lothar M.

Kannst du mir bei der lesetimeraus() Funktion noch weiterhelfen. Hab mir 
das Datenblatt des ATmega328 jetzt ne Zeit lang angeschaut und auch 
schon ein bisschen herumprobiert aber hab da zu wenig Grundwissen zu 
Timer und Registern, dass ich das hinbekomme. Wahrscheinlich sind es nur 
ein paar Zeilen Code. Vlt kann mir da noch jemand weiterhelfen.

Schon mal danke !

von Joachim J (Gast)


Lesenswert?

Hallo zusammen,

ich hoffe ich werde nicht aus dem Forum verjagt, wenn ich dieses alte 
Thema wieder ausgrabe. ;-)
Ich möchte das gleiche machen wie der Eröffner des Beitrags.
Idee: 16 bit Variable über Timer mit 1 MHz zählen lassen. Bei steigender 
Flanke (Erkennung über INT0) Variable löschen und bei fallender Flanke 
der Hauptschleife sagen, dass der Wert jetzt weiter verarbeitet werden 
kann.
Mein Code sieht folgendermaßen aus:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
#include <util/delay.h>
4
#include <stdio.h>
5
#include <stdlib.h>
6
#include <util/atomic.h>
7
8
/*-------- Define --------*/
9
#define FOSC 16000000 //Clock Speed
10
#define BAUD 19200 //Debug
11
#define MYUBRR FOSC/16/BAUD-1
12
13
#define LED_PORT PC0
14
#define LED_ON PORTC |= (1 << LED_PORT)
15
#define LED_OFF PORTC &= ~(1 << LED_PORT)
16
17
#define RC_RECEIVER_PORT PD2
18
#define RISING_EDGE PIND & (1 << RC_RECEIVER_PORT)
19
20
/*Variablen*/
21
volatile uint16_t Throttle;
22
volatile uint16_t micros;
23
24
volatile uint8_t pwm_ready = 0;
25
volatile uint16_t pwm_duty_cycle;
26
volatile uint8_t count;
27
volatile uint8_t overflows = 0;
28
29
void USART_Init( unsigned int ubrr)
30
{
31
  /*Set baud rate */
32
  UBRR0H = (unsigned char)(ubrr>>8);
33
  UBRR0L = (unsigned char)ubrr;
34
  /*Enable receiver and transmitter */
35
  UCSR0B = (1<<RXEN0)|(1<<TXEN0);
36
  /* Set frame format: 8data, 1stop bit */
37
  UCSR0C = (1<<UCSZ01)|(1<<UCSZ00);
38
}
39
40
void debug_transmit(unsigned char data)
41
//Nur für Debug
42
{
43
  // Wait for empty transmit buffer
44
  while ( !( UCSR0A & (1<<UDRE0)) );
45
  // Put data into buffer, sends the data
46
  UDR0 = data;
47
  //return 0;
48
}
49
50
void debug_puts (char *s)
51
{
52
  while (*s)
53
  {   // so lange *s != '\0' also ungleich dem "String-Endezeichen(Terminator)"
54
    debug_transmit(*s);
55
    s++;
56
  }
57
}
58
59
void pin_change_init(void)
60
{
61
  EICRA = (1<<ISC00);
62
  EIMSK = (1<<INT0);
63
}
64
65
void PWM_Timer0_init (void)
66
{
67
  TCCR0A = (1<<COM0A1)|(1<<COM0A0)|(1<<COM0B1)|(1<<COM0B0)|(1<<WGM01)|(1<<WGM00); //Clear OC0A/OC0B on Compare Match, set OC0A/OC0B at BOTTOM (inverting mode) Fast PWM, Top=0xFF
68
  TCCR0B = (1<<CS01); //Prescaler = 8 --> 10 kHz für Motoren
69
  OCR0A=0; //Motor1 aus
70
  OCR0B=0; //Motor2 aus
71
}
72
73
void PWM_Timer2_init (void)
74
{
75
  TCCR2A = (1<<COM2A1)|(1<<COM2A0)|(1<<COM2B1)|(1<<COM2B0)|(1<<WGM21)|(1<<WGM20); //Clear OC0A/OC0B on Compare Match, set OC0A/OC0B at BOTTOM (inverting mode) Fast PWM, Top=0xFF
76
  TCCR2A = (1<<CS21); //Prescaler = 8 --> ca. 10 kHz für Motoren
77
  OCR2A=0; //Motor1 aus
78
  OCR2B=0; //Motor2 aus
79
}
80
81
void PPM_Counter_Timer1_init(void)
82
//Interrupt über CTC, ISR zählt mit 1 MHz
83
{
84
  
85
  TCNT1 = 0;               //Rücksetzen des Timers
86
  OCR1A = 16;        // 1MHz
87
  TCCR1B = (1<<WGM12);  //CTC Modus
88
  TCCR1B |= (1<<CS10);    //Timer an / Kein Prescaler
89
  TIMSK1 = (1<<OCIE1A);   //Timer/Counter1, Output Compare A Match Interrupt Enable
90
}
91
92
ISR (INT0_vect)
93
//ISR für Pin Change
94
{
95
  // interrupt service routine for pin change interrupt
96
  if ( RISING_EDGE ){       // check if rising edge pin change interrupt (beginning of servo pulse)
97
    
98
    micros = 0;                           // reset counter
99
    LED_ON;
100
    return;
101
  }
102
103
  // only reached when falling edge detected (end of servo pulse)
104
105
  Throttle = micros;                           // take timer value to global variable
106
  pwm_ready = 1;
107
  LED_OFF;
108
}
109
110
ISR (TIMER1_COMPA_vect)
111
//Interrupt 1 MHz, läuft
112
{
113
  micros++;
114
}
115
116
int main()
117
118
{
119
  char Buffer[12];
120
  uint16_t Throttle_l;
121
  
122
  DDRD = (1<<DDD6)|(1<<DDD5)|(1<<DDD3); //Ausgänge
123
  //DDRD |= (1<<DDD1); //Onboard LED, für TX auskommentieren
124
  DDRC = (1<<DDC1)|(1<<DDC0); //Ausgänge
125
  
126
  USART_Init(MYUBRR);
127
  _delay_ms(10);
128
  
129
  debug_puts("Start\r\n"); //Debug
130
  debug_puts("Init Timers\r\n"); //Debug
131
  
132
  pin_change_init();
133
  PPM_Counter_Timer1_init();
134
  PWM_Timer0_init();
135
  PWM_Timer2_init();
136
137
  sei();
138
  
139
  //Main
140
  while(1)
141
  {
142
    if (pwm_ready)
143
    {
144
      ATOMIC_BLOCK(ATOMIC_RESTORESTATE)
145
      {
146
        Throttle_l = Throttle;
147
      }
148
      utoa(Throttle_l,Buffer,10);
149
      debug_puts(Buffer); //Debug
150
      debug_puts("\r\n");
151
      pwm_ready=0;
152
    }
153
    
154
  }
155
}

Basis ist von hier: 
https://github.com/chiefenne/ATTINY85-RC-Receiver-Decoder . Ich verwende 
allerdings einen ATmega 328 p in der finalen Version mit 20 MHz (Pololu 
Baby Orangutan) und hier einen 16 bit Timer statt dem 8 bit Timer. Der 
Code ist für 16 MHz.

Mein Problem: Es sollten bei 1MHz Timer 1 CTC Werte zwischen 1000 und 
2000 über den USART kommen. Es kommen aber nur Werte zwischen ca. 500 
und 900. Wenn ich den Takt auf 100 kHz ändere, kommen Werte zwischen ca. 
100 und 200 raus, was auch plausibel ist. (OCR1A = 16 -> 1 MHz / OCR1A = 
160 -> 100 kHz). Aber warum? Ist das schon so zeitkritisch, dass der MC 
nicht mehr nachkommt?

Gruß
Joachim

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Hier noch ein anderer Ansatz:
https://www.mikrocontroller.net/attachment/highlight/284442

Das Dings liefert ein Vorwärts/Rückwärts Signal, PWM für einen Motor und 
hat eine Failfunktion bei Ausfall des RC Signals - ist aber für einen 
Tiny25-85.

: Bearbeitet durch User
von Veit D. (devil-elec)


Lesenswert?

Hallo,

F_CPU 16MHz?

Das hier ist deine Timerkonfiguration.
1
void PPM_Counter_Timer1_init(void)
2
// Interrupt über CTC, ISR zählt mit 1 MHz
3
{
4
  TCNT1 = 0;            // Rücksetzen des Timers
5
  OCR1A = 16;          // 1MHz
6
  TCCR1B = (1<<WGM12);  // CTC Modus
7
  TCCR1B |= (1<<CS10);  // Timer an / Kein Prescaler
8
  TIMSK1 = (1<<OCIE1A);  // Timer/Counter1, Output Compare A Match Interrupt Enable
9
}
1
ISR (TIMER1_COMPA_vect)
2
// Interrupt 1 MHz, läuft
3
{
4
  micros++;
5
}

Wie kommst du darauf das Timer 1 mit 1MHz läuft?
Laut meiner Rechnung läuft er mit 470,6kHz.
Nimm nochmal das Manual und die Formel vom CTC Mode zur Hand.

Eine andere Möglichkeit wäre der Input Capture Modus. Wäre auch genauer.

Beitrag #6818605 wurde von einem Moderator gelöscht.
von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Joachim J schrieb:
> Idee: 16 bit Variable über Timer mit 1 MHz zählen lassen.
Ich würde nicht gefühlte 70% der Rechenleistung mit dem schnellen 
Hochzählen einer Variablen vergeuden. Denn immerhin hast du bei 16MHz 
nur 16 Zyklen zwischen den Interrupts und davon gehen schon einige für 
das Interrupt-Framework drauf. Dazu noch das eigentliche Hochzählen und 
schon ist die Rechenzeit verbraucht.

Veit D. schrieb:
> Eine andere Möglichkeit wäre der Input Capture Modus. Wäre auch genauer.
Oder einfach den 16-Bit-Zähler mit einem halbwegs geeigneten Vorteiler 
geradeaus durchlaufen lassen und dann per Pin-Flankeninterrupt den 
Anfangs- und Ende-Zeitstempel erfassen und die Differenz davon nehmen.

> Laut meiner Rechnung läuft er mit 470,6kHz.
Es ist immer gut, wenn man sich zur Kontrolle in so einen Timerinterrupt 
mal einen Portpin togglet und den mit dem Oszi misst. Dann kann man 
kontrollieren, ob der 1. überhaupt angesprungen wird und 2. das mit der 
Häufigkeit tut wie man sich das gedacht hat.


EDIT: weil der vorgehende Post eine Beleidigung enthielt, wurde er 
gelöscht. Die Information darin war allerdings erhaltenswert und lautete 
zusammengefasst:
Erklehr Behr schrieb im Beitrag #6818605:
> die Anweisungen zum Posten von Sourcecode ... befolgen.
>>> Wichtige Regeln - erst lesen, dann posten!
>>> Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

: Bearbeitet durch Moderator
von Peter D. (peda)


Lesenswert?

Joachim J schrieb:
> Idee: 16 bit Variable über Timer mit 1 MHz zählen lassen. Bei steigender
> Flanke (Erkennung über INT0) Variable löschen und bei fallender Flanke
> der Hauptschleife sagen, dass der Wert jetzt weiter verarbeitet werden
> kann.

Viel zu kompliziert und laufzeitabhängig (Jitter).
Man läßt den Timer durchlaufen und nimmt den Input-Capture-Eingang.
Bei der einen Flanke den Capturewert merken und die Flanke umschalten. 
Bei der anderen Flanke Differenz zum ersten Wert bilden und ausgeben.

von Ronny (Gast)


Lesenswert?

Und bedenke: Eine Funkstrecke kann immer gestört sein! D.h. du kannst 
auch mal einen Puls haben, der weit ab vom 1...2 ms-Fenster ist auch mal 
0 oder 20 ms lang ist.
Darum nie auf ein einzelnes Sample verlassen, sondern immer eine 
Plausibilitätskontrolle machen und/oder mitteln.

von Erich (Gast)


Lesenswert?

l. w. schrieb:
>> ich möchte gerne die HIGH Pulslänge eines Modellbau Servo Signals messen

Peter D. schrieb:
> Viel zu kompliziert und laufzeitabhängig
> Man läßt den Timer durchlaufen und nimmt den Input-Capture-Eingang.

Dieser Aussage von Peter stimme ich zu.
Allerdings folgendes:
Bei Modellbauservo ist wohl die PWM Periodendauer auf 20 ms definiert.
Ist die garantiert genau, so reicht die Messung des Hi Anteils.

Jedoch mag es Ansteuerungen geben, bei denen die 20 ms nicht exakt sind, 
sei es durch Tolenanzen, ungenauen Oszillator o.ä.
Dann wäre die echte Berechnung des Duty Cycle sinnvoll.
Also nicht nur Hi Anteil messen (mit "input capture") sondern zusätzlich 
auch gesamte Periode, dann Verältnisbildung (Division).

Der prinzipielle Vorgang ist dann derselbem welcher für den "sensiblen" 
Temperatursensor SMT160 (SMT160-30) oder SMT172 verwendet wird.

https://forum.arduino.cc/t/smartec-smt172-temperature-sensor-library/359391/2
Dort bei "Jan. '16" #3 von EdwinCroissant :

= Capture the first falling edge and store the value of the timer in 
startTime
= Capture the rising edge and store the value of the timer in tempTime
= Capture the second falling edge and add the difference between the 
value of the timer and the tempTime to highTime
= Repeat until we have a multiple of 8 cycles from the sensor.
= On the last falling edge add the difference between the value of the 
timer and the tempTime to the highTime and store the value of the timer 
as endTime.
= Duty cycle is now the highTime divided by the difference between the 
endTime and the startTime.

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Erich schrieb:
> Bei Modellbauservo ist wohl die PWM Periodendauer auf 20 ms definiert.
> Ist die garantiert genau, so reicht die Messung des Hi Anteils.

Darauf kann man sich nicht verlassen. Meine alte Graupner FM4014 macht 
z.B. 22ms und die Robbe Terra liegt bei 19ms.
Gemeinsam ist allen die immer exakte Pulslänge nach dem Dekoder (im 
Receiver) von 1000µs bis 2000µs. Nur die zählt und muss plausibel sein. 
Auch auf die Mittelstellung bei 1500µs kann man sich grob verlassen.

Meine Software von oben misst 50 Pulse auf Plausibilität und gibt dann 
erst die Steuerung frei. D.h., es muss eine Sekunde lang ein plausibles 
Signal kommen, ehe es losgeht. Fällt das Signal für einen Puls aus, 
schaltet sie in den Notbetrieb.

von Peter D. (peda)


Lesenswert?

Erich schrieb:
> Bei Modellbauservo ist wohl die PWM Periodendauer auf 20 ms definiert.

Nö, die 20ms sind nur ein Richtwert. Werden mehrere Kanäle 
hintereinander übertragen, darf sie auch länger dauern. Eine lange Pause 
zwischen 2 Kanälen dient zur Erkennung, wann wieder Kanal 1 gesendet 
wird. Die Information über den Servowert trägt nur die Impulsdauer.

von Stefan F. (Gast)


Lesenswert?

Viele Servos unterstützen Periodendauern von weit weniger als 20ms, um 
die Reaktionszeit (in Kombination mit einer passenden Ansteuerung) zu 
reduzieren.

von Joachim (Gast)


Lesenswert?

Hallo zusammen,

danke für die vielen Infos und Antworten! Das nächste mal kommt der Code 
als Anhang. :-)

Ich stimme euch da zu, dass es besser ist, dass Signal über Input 
Capture zu verwenden. Da ich allerdings 20 MHz habe und ich über die 
Prescaler nicht auf glatte 1 MHz komme und im Nachgang umrechnen muss, 
habe ich diesen Ansatz gewählt.

Ich kann die 470,6 kHz nachvollziehen, aber soweit ich das im Datenblatt 
sehe, sollten die nur für den CTC im Waveform Modus gelten. Ich habe 
mich hieran orientiert:
"An interrupt can be generated at each time the counter value reaches 
the TOP value by either using the OCF1A or ICF1 flag according to the 
register used to define the TOP value." (S. 101 ganz oben, aktuelles DB 
vom 328p)
Und das wollte / will ich auch mit dem Code erreichen.
Mit meinem einfachen Oszi sehe ich auch, dass der Timer passt. Das 
überprüfe ich später aber nochmal.
Rechnerisch passt die Formel für 20 MHz und 200 für OCR1A nicht (49,75 
kHz Interrupt). Da müssten dann Werte für die Servoposition zwischen 49 
und 99 herauskommen. Es kommen aber plausible Werte zwischen 100 und 200 
heraus.
Zeiten zwischen Signalen mittels einem 1 MHz Zähler zu messen, scheinen 
in der Arduino Bibliothek gängige Praxis zu sein und scheint dort auch 
zu funktionieren (Funktion micros()). Deswegen wundert mich auch, dass 
das hier nicht funktioniert.

Gruß
Joachim

von Peter D. (peda)


Lesenswert?

Joachim schrieb:
> Da ich allerdings 20 MHz habe und ich über die
> Prescaler nicht auf glatte 1 MHz komme und im Nachgang umrechnen muss

Das ist gängige Praxis. Intern zählt man in Ticks und rechnet erst zum 
Schluß für den Menschen um. So kann man auch mit einem 32.768kHz 
Uhrenquarz auf 1/100s anzeigen.

Joachim schrieb:
> Zeiten zwischen Signalen mittels einem 1 MHz Zähler zu messen, scheinen
> in der Arduino Bibliothek gängige Praxis zu sein und scheint dort auch
> zu funktionieren (Funktion micros()).

Dann lies Dir mal die Beschreibung dazu durch.
Einen Wert in µs auszugeben, heißt noch lange nicht, daß die Auflösung 
1µs ist.

von m.n. (Gast)


Lesenswert?

Noch ein Beispiel für Verwendung von INT0/INT1. Zwar nicht mit ICP aber 
für Zeiten im ms-Bereich problemlos verwendbar:
Beitrag "Stoppuhr – Geschwindigkeit – Pulsweite mit Atmega88"

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Joachim schrieb:
> Da ich allerdings 20 MHz habe und ich über die
> Prescaler nicht auf glatte 1 MHz komme und im Nachgang umrechnen muss,
> habe ich diesen Ansatz gewählt.
Es juckt doch gar nichts, wenn du nicht auf eine "glatte" Zahl kommst. 
Denn das, was du für eine "glatte" Zahl hältst, ist für den µC (der kann 
super toll in Zweierpotenzen rechnen) eine höchst umständliche Zahl.

Und jetzt kommts: du musst diese für dich "glatte" Rechnung nur 1x 
während der Entwicklungszeit machen. Der µC muss die für ihn 
resultierende umständliche Rechnung andauernd den Rest des Lebens 
machen.

Ergo ist es am sinnvollsten, du strengst 1x den Kopf an und denkst dir 
eine Lösung aus, die der µC möglichst einfach ausführen kann. Dann ist 
auch noch Platz und Zeit für weitere Aufgaben...

Erich schrieb:
> Dann wäre die echte Berechnung des Duty Cycle sinnvoll.
Dieser Wert ist bei Modellbauservos im Grunde nutzlos und enthält keine 
zuverlässige Information.

> Jedoch mag es Ansteuerungen geben, bei denen die 20 ms nicht exakt sind,
> sei es durch Tolenanzen, ungenauen Oszillator o.ä.
> Dann wäre die echte Berechnung des Duty Cycle sinnvoll.
> Dort bei "Jan. '16" #3 von EdwinCroissant
Da geht es um einen schnarchlangsamen Temperatursensor. Da würde ich 
ganz ohne Pinchangeinterrupt einfach in irgendeinem Timerinterrupt 
jedesmal den Pin einlesen. Und mit 2 Zählern mitzählen, ob er gerade 
high oder low ist. Aus diesen beiden Zählern kann ich dann das TV 
ausrechnen:

DutyCycle = cntHi/(cntHi+cntLo)

Das wurde vor Kurzem im 
Beitrag "Re: PWM Frequenzteiler in Hardware?" diskutiert und auch 
im Beitrag "Re: Pulslänge mit STM32 Timer vermessen"

: Bearbeitet durch Moderator
von Veit D. (devil-elec)


Lesenswert?

Hallo,

am Rande, wenn du den CTC Mode im Timer einstellst, dann gilt auch nur 
die Formel vom CTC Mode.

Und wie die anderen schon geschrieben haben. Dich interessiert beim 
Timer Zähler erstmal nur der reine Zählwert bzw. die Differenz zweier 
Werte. Du weißt, weil du das ausgerechnet hast, wieviel Zeit ein Tick 
entspricht. Das ist eine Konstante. Bei 20MHz immer Vielfache von 50ns. 
Vorteil dabei es ist eine Ganzzahl. Erst am Ende rechnest du für eine 
Ausgabe etc. deine Tick Differenz der Messung in eine Zeit um.

Wenn du Prescaler 8 verwendest reicht die Messauflösung noch locker aus. 
Selbst Prescaler 64 sollte noch ausreichend sein. Rechne das alles in 
Ruhe auf dem Papier durch.

von Erich (Gast)


Lesenswert?

Lothar M. schrieb:
> Da geht es um einen schnarchlangsamen Temperatursensor.

Ach, wenn du meinst...
Der Temperaturwert (berechnet aus dem Duty Cycle) mag langsam sein,
nicht jedoch das PWM Signal selbst.
Lt. Datenblatt des SMT172 variiert die PWM Frequenz zwischen 0.5 und 7 
kHz.
Nach meiner Berechnung ist das durchaus flotter als 20 ms.

Aber das ist eigentlich nur Nebenthema hier.
Ich wollte dem TO lediglich auf die verlinkte Library hinweisen, als 
Beispiel für "input capture".

Gruss

von Stefan F. (Gast)


Lesenswert?

Erich schrieb:
> Nach meiner Berechnung ist das durchaus flotter als 20 ms.

Er meinte nicht die Signalfrequenz sondern die Geschwindigkeit mit der 
sich die Temperatur verändert.

Man kann ein PWM Signal durchaus mit einer viel geringeren Frequenz 
abtasten.

Ein Extremes Beispiel: Sagen wir mal das PWN Signal hätte 10 MHz. Wenn 
du eine Stunde lang jede Sekunde das Signal digital abtastest und dabei 
zählst wie oft du HIGH und wie oft du LOW gesehen hast, kommen dabei 
vielleicht Zahlen wie diese heraus:

3200 mal LOW
400 mal HIGH

Dies ergibt ein Tastverhältnis von 400/3600 =  0,1111

So einfach kommst du auf einen mittleren Wert pro Stunde ohne dich 
überhaupt mit den 10 Mhz herum schlagen zu müssen.

Genau so funktionieren Stichproben und representative Studien.

von Veit D. (devil-elec)


Lesenswert?

Stefan ⛄ F. schrieb:

> Genau so funktionieren ... representative Studien.

Offtopic:
Ich weiß wie du das meinst. Muss dennoch meine Meinung dazu sagen.
Wenn man 1000 Leute fragt und auf 80 Millionen hochrechnet ist das genau 
NICHT representativ wie immer behauptet. Das ist der Haken an den 
Studien und  Quotenermittlungen usw.

: Bearbeitet durch User
von Erich (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
>
> Er meinte nicht die Signalfrequenz sondern die Geschwindigkeit mit der
> sich die Temperatur verändert.
>
Ach wirklich?
>>
>>Da würde ich ganz ohne Pinchangeinterrupt
>>einfach in irgendeinem Timerinterrupt jedesmal den Pin einlesen.
>>Und mit 2 Zählern mitzählen, ob er gerade high oder low ist.
>>


> Man kann ein PWM Signal durchaus mit einer viel geringeren Frequenz abtasten.
>
Aber nicht,
wenn zur Erkennung der Signalgültigkeit genau 8 aufeinanderfolgende PWM 
Zyklen betrachtet werden müssen.
(Steht im Datenblatt des "Schmach langsamen" Sensors).


> Genau so funktionieren Stichproben
> und representative Studien.
>
Die haben auch kein Datenblatt (Berechnungsvorschrift) und keine 
Gültigkeitserkennung.
Ergebnis: 106% aller Deutschen können nicht prozentrechnen.

Gruss

von Erich (Gast)


Lesenswert?

"Schmach langsamen"
Ja, lustig diese Automatiken heutzutage.
Gruss

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Erich schrieb:
> Ach, wenn du meinst...
> Der Temperaturwert (berechnet aus dem Duty Cycle) mag langsam sein,
> nicht jedoch das PWM Signal selbst.
Ja, aber wenn du das Verfahren verstanden hast, dann merkst du, dass die 
Abtastung beliebig langsam sein darf. Und dann ist es eben völlig egal, 
wie hochfrequent das PWM-Signal hat und ob diese Frequenz stabil ist.

Veit D. schrieb:
> Wenn man 1000 Leute fragt und auf 80 Millionen hochrechnet ist das genau
> NICHT representativ wie immer behauptet.
Das mit dem Kraut und den Rüben ist dir aber schon klar? Denn die 
anderen, nicht berücksichtigten Signale haben ja keine "andere Meinung", 
sondern jede einzelne Abtastung wird nur ein wenig mehr Genauigkeit 
bringen. Und das ist dann pure Statistik und hat nichts mit Meinungen zu 
tun.

Erich schrieb:
> Aber nicht, wenn zur Erkennung der Signalgültigkeit genau
> 8 aufeinanderfolgende PWM Zyklen betrachtet werden müssen.
> (Steht im Datenblatt des "Schmach langsamen" Sensors).
Tja, dann darf man die Messdauer nicht beliebig lang machen, sondern 
zählt einfach mit einem zusätzlichen Zähler ein Vielfaches dieser 8 
Pulse ab (z.B. 4096) und wertet dann erst das Verhältnis aus.

Erich schrieb:
> Ich wollte dem TO lediglich auf die verlinkte Library hinweisen, als
> Beispiel für "input capture".
Richtig, er braucht aber nur einen Capture auf die steigende Flanke und 
merkt sich t_rise und einen auf die fallende Flanke und merkt sich 
t_fall. Dann ist die Pulsdauer im einfach tfall-trise, und falls 
inzwischen ein Zählerüberlauf aufgetreten ist, wird der damit gratis 
"rausgerechnet".

von Veit D. (devil-elec)


Lesenswert?

Lothar M. schrieb:

> Veit D. schrieb:
>> Wenn man 1000 Leute fragt und auf 80 Millionen hochrechnet ist das genau
>> NICHT repräsentativ wie immer behauptet.
> Das mit dem Kraut und den Rüben ist dir aber schon klar? Denn die
> anderen, nicht berücksichtigten Signale haben ja keine "andere Meinung",
> sondern jede einzelne Abtastung wird nur ein wenig mehr Genauigkeit
> bringen. Und das ist dann pure Statistik und hat nichts mit Meinungen zu
> tun.

Nein. Demnach müssten nur 1000 Leute zur Wahl gehen und repräsentieren 
damit die Meinung aller Bundesbürger? Also wenn du das ernst meinst dann 
gute Nacht.

Beitrag #6819476 wurde von einem Moderator gelöscht.
von Wolfgang (Gast)


Lesenswert?

Stefan ⛄ F. schrieb:
> Man kann ein PWM Signal durchaus mit einer viel geringeren Frequenz
> abtasten.
>
> Ein Extremes Beispiel: Sagen wir mal das PWN Signal hätte 10 MHz. Wenn
> du eine Stunde lang jede Sekunde das Signal digital abtastest und dabei
> zählst wie oft du HIGH und wie oft du LOW gesehen hast, kommen dabei
> vielleicht Zahlen wie diese heraus:

Damit bekommst du das Tastverhältnis raus, aber nicht notwendigerweise 
die Pulsbreite eines Servosteuersignals. Die Information ist (bis auf 
einige Exoten) in der Dauer des High-Pulses codiert. Nur wenn die 
Periodendauer konstant und bekannt ist, lässt sich die Information mit 
deiner Methode statistisch bestimmen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Wolfgang schrieb:
> Damit bekommst du das Tastverhältnis raus, aber nicht notwendigerweise
> die Pulsbreite eines Servosteuersignals.
Genau das war es, was
ich schrieb:
> Erich schrieb:
>> Dann wäre die echte Berechnung des Duty Cycle sinnvoll.
> Dieser Wert ist bei Modellbauservos im Grunde nutzlos

Veit D. schrieb:
> Demnach müssten nur 1000 Leute zur Wahl gehen und repräsentieren
> damit die Meinung aller Bundesbürger?
Was hast du denn dauernd mit deiner Wahl?
Du kannst die Unterabtastung eines PWM-Signals deshalb nicht mit einer 
Wählerbefragung vergleichen, weil sich diese Meinung unter den 
angenommenen 80Mio Leuten eben nicht ständig periodisch immer gleich 
wiederholt(!), sondern völlig zufällig oder doch nicht zufällig verteilt 
ist.
Genau das ist der Unterschied zwischen einem absolut unzufälligen 
periodischen(!) PWM Signal und der Meinung zufällig verteilter Wähler.

: Bearbeitet durch Moderator
von Peter D. (peda)


Lesenswert?

Bei diskreten Sendern hat man oft eine Kette aus Monoflops verwendet.
Z.B. ein 74HC123 oder CD14538 mit 2 Potis konnte je 2 Kanäle kodieren. 
Ein letzter Monoflop mit >10ms hat dann die lange Pause signalisiert. 
Damit war die Periodendauer immer die Summe aller Kanäle + lange Pause, 
d.h. überhaupt nicht konstant.

von Stefan F. (Gast)


Lesenswert?

Wolfgang schrieb:
> Damit bekommst du das Tastverhältnis raus, aber nicht notwendigerweise
> die Pulsbreite eines Servosteuersignals.

Ja, bei einem Servo passt es nicht gut. Da müsste der Sender die Impulse 
immer schön regelmäßig mit konstanter Periodendauer senden. Aber wer 
will schon einen Empfänger bauen, der nur mit vielen (nicht mit allen) 
Sendern funktioniert?

Ich bezog mich auf den Lösungsvorschlag für den "schnarch langsamen" 
Temperatursensor. bei dessen Ausgangssignal interessiert man sich für 
das Tastverhältnis.

von Erich (Gast)


Lesenswert?

>
> Beitrag #6819476 wurde von einem Moderator gelöscht.
>

Ein erbärmliches, gleichwohl erwartetes Verhalten.

Gruss

von Stefan F. (Gast)


Lesenswert?

Erich schrieb:
> Ein erbärmliches, gleichwohl erwartetes Verhalten.

Was ist denn daran erbärmlich? Der Inhaber dieser Domain bestimmt, was 
hier veröffentlicht wird und was er löschen will. Er hat hier nicht nur 
das Hausrecht sondern sogar die Pflicht gewisse Beiträge aufzuräumen.

Was man mal positiv erwähnen sollte ist, dass hier unerwünschte Beiträge 
nur noch äußerst selten sofort gelöscht werden. Die Diskussion wird 
zugelassen wie sie sich ergibt. Gelöscht wird meistens erst ein paar 
Tage später.

Ganz anders wäre es mit automatischen content filtern, die unsere 
Regierung auf einigen Seiten nun doch erzwungen hat.

von Veit D. (devil-elec)


Lesenswert?

Lothar M. schrieb:

Naja Lothar, ursprünglich hast du auf meinen Kommentar reagiert. Dabei 
ging es nur Offtopic um eine angebliche repräsentative Ermittlung. Das 
hatte nichts mit wiederholter Unterabtastung zu tun. Irgenwelche 
Umfragen kann man nur einmal machen. Das hast du schon richtig 
geschrieben.

Der Rest ist mir schon zu sehr zerpflückt als das ich darauf sinnvoll 
eingehen kann. Das wird nichts mehr.  :-)  Ich halte mich raus.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Erich schrieb:
> Ein erbärmliches, gleichwohl erwartetes Verhalten.
Lass das Wort "Depp" weg und der Post bleibt stehen.
Wobei, wenn du das Wort aus dem Post löscht, dann bleibt ausser Gejammer 
und einem unsinnigen Angriff auf mich nichts übrig. Und schon gar 
nichts, was in der Sache irgendwie weiterhelfen würde.

> gleichwohl erwartetes Verhalten.
Es ist übrigens schon bedenklich, dass/wenn es mit den Löschungen immer 
die selben trifft. Und die solche Löschungen schon "erwarten".

Veit D. schrieb:
> Der Rest ist mir schon zu sehr zerpflückt
Richtig, da laufen 2 Threads in einem:
1. Highimpuls-Dauer-Messung
2. Bestimmung des Tastverhältnisses

> Ich halte mich raus.
Dürfte soweit wohl sowieso alles Nötige gesagt sein.

von Joachim J (Gast)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich habe den Code auf Input Capture umgeschrieben und ich bekomme 
saubere PP Werte. Den Code findet ihr im Anhang. Verbesserungsvorschläge 
werden gerne angenommen. :-)

Auf einem ATMega 328p mit 16MHz und DRV8833 Motortreiber funktioniert 
er. Allerdings "verhäddert" sich der Code auf einem Pololu Baby Orang 
Utan (ATmega 328p mit 20 MHz und Toshiba TB6612FNG Motor Treiber). 
Zwischendurch wir für das Motor Signal eine 0 berechnet, der Motor wird 
kurzzeitig auf 0 gesetzt und stottert. Ich konnte noch nicht 
herausfinden warum.

Gruß
Joachim

von erklehr behr (Gast)


Lesenswert?

Joachim J schrieb:
> Allerdings "verhäddert" sich der Code

http://www.rechtschreibwerkstatt.de/GrafOrtho/AF-uM/html/verheddern.html

Joachim J schrieb:
> Ich konnte noch nicht herausfinden warum.

Wahrscheinlich weil dein Aufbau scheisse ist bzw. eine
Entstörung nicht vorhanden oder zu mickrig.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Joachim J schrieb:
> Ich konnte noch nicht herausfinden warum.
Hast du mal überlegt, was passiert, wenn ein Störimpuls mit 100ns kommt, 
einen Interrupt auslöst und dann, wenn du den Pegel am Interruptpin 
einlesen willst, schon lange wieder "weg" ist?
Also sowas:
1
  
2
1                          -----          .               ----- 
3
0 -------------------------     ----------'---------------     ------
4
                                       Störimpuls
Hast du die Behandlung eines solchen recht alltäglichen EMV-Störeffekts 
in deiner Software berücksichtigt?

von Matthias S. (Firma: matzetronics) (mschoeldgen)


Lesenswert?

Joachim J schrieb:
> Ich konnte noch nicht
> herausfinden warum.

Du solltest testweise mal den seriellen Output in der Hauptschleife 
rausnehmen. Das kostet immer wahnsinnig viel Zeit und oft weiss man bei 
den Routinen nicht, was sie für Seiteneffekte haben.
Ich synchronisiere übrigens die Hauptschleife mit einem der Timer, damit 
ich ein gleichmässiges Zeitraster habe.
Es lohnt sich auch, wie Lother schon sagte, die gemessene Zeit auf 
Plausibilität zu prüfen, beovr man sie auf die Motoren loslässt.
Uner anderem deswegen habe ich so ausführliche Routinen für 
Fehlererkennung in meinem Code (und weil ich das U-Boot nur ungerne 
verliere).

: Bearbeitet durch User
von m.n. (Gast)


Lesenswert?

erklehr behr schrieb:
>> Allerdings "verhäddert" sich der Code

Richtig geschrieben heißt es auch "Trottel".
1
ISR (TIMER1_CAPT_vect)
2
{
3
  if (cap_low_high==1) //steigende Flanke
4
  {
5
    TCNT1=0;

Gewöhne es Dir ab TCNT1 auf 0 zu setzen. Einfach die Differenz 
neuer_wert - alter_wert bilden.

von Veit D. (devil-elec)


Lesenswert?

Hallo,
1
Zwischendurch wir für das Motor Signal eine 0 berechnet, der Motor wird 
2
kurzzeitig auf 0 gesetzt ...

Mal abgesehen von dem Timer auf 0 setzen was man nicht machen soll.

Wenn man deine Rechnung anschaut und folgendes gültig wird
1
if (Throttle_l<PPM_min)
2
{
3
  Throttle_l=PPM_min;
4
}
wird danach noch folgendes gemacht
1
Throttle_l = Throttle_l-PPM_min

Welchen Wert hat Throttle_l?
Danach wird dann noch versucht
1
M1 = Throttle_l/3.1

zu rechnen. (M1 uint8_t).

Welchen Wert hat M1?

Das wird öfters 0 sein wie du denkst.

von Joachim J (Gast)


Lesenswert?

Hallo zusammen,

ich hätte erwartet, dass es entweder gar nicht oder immer funktioniert:
Gleicher Code (bis auf Anpassungen zur Frequenz), gleicher MC Typ 
(328p), unterschiedliche Taktfrequenz (16 MHz zu 20 MHz), 
unterschiedlicher Motortreiber, aber gleicher Motor: Einmal funktioniert 
es, einmal gar nicht. Und bei gar nicht auch erst dann, wenn der Motor 
angeschlossen.

Bei einem U-Boot hätte ich natürlich auch mehr Sicherheit / eine 
Plausibilitätsprüfung eingebaut. :-) Für meine Anwendung benötige ich 
das nicht, da nichts wegfahren / wegschwimmen oder defekt gehen kann.
In dem 16 MHz Aufbau funktioniert alles wie gewünscht bzw. für meine 
Anwendung ausreichend.

Gruß
Joachim

von Veit D. (devil-elec)


Lesenswert?

Hallo,

ich dachte du möchtest das Rechenproblem lösen.

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.