Forum: Mikrocontroller und Digitale Elektronik Peter Dannegger´s ( PeDa ) Entprellroutine in ein Arduino Sketch einbinden


von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

wie geht das?

Hier sind 3-Dateien, mit denen es gehen sollte :

Beitrag "Re: Tasterverarbeitung mit ARDUINO-C"

Habe mal alles in eine Datei im Anhang zu sehen gepackt.


Ich bekomme jedoch diese Fehlermeldung :

In file included from 
C:\Users\Ich\AppData\Local\Arduino15\packages\arduino\hardware\avr\1.8.6 
\cores\arduino/Arduino.h:30:0,
                 from G:\AVR-Projekte\Arduino\MEGA2560 Board\GLCD_ST 
7920\Entprellen\GLCD_entprellen\GLCD_entprellen.ino:1:
G:\AVR-Projekte\Arduino\MEGA2560 Board\GLCD_ST 
7920\Entprellen\GLCD_entprellen\GLCD_entprellen.ino: In function 'void 
loop()':
GLCD_entprellen:76:1: error: expected unqualified-id before string 
constant
 ISR( TIMER1_COMPA_vect ) {                        // every 10ms
 ^
GLCD_entprellen:76:26: error: a function-definition is not allowed here 
before '{' token
 ISR( TIMER1_COMPA_vect ) {                        // every 10ms
                          ^
GLCD_entprellen:96:26: error: a function-definition is not allowed here 
before '{' token
 void init_entprell(void) {
                          ^
GLCD_entprellen:112:43: error: a function-definition is not allowed here 
before '{' token
 uint8_t get_key_press( uint8_t key_mask ) {
                                           ^
GLCD_entprellen:128:41: error: a function-definition is not allowed here 
before '{' token



Bernd_Stein

Beitrag #7491776 wurde vom Autor gelöscht.
von Steve van de Grens (roehrmond)


Lesenswert?

Erstmal ordentlich einrücken, dann sieht man den Fehler auch:
1
#include <Arduino.h>
2
#include <stdint.h>
3
#include <avr/interrupt.h>
4
5
uint8_t get_key_press(uint8_t key_mask);
6
uint8_t get_key_rpt(uint8_t key_mask);
7
uint8_t get_key_state(uint8_t key_mask);
8
uint8_t get_key_short(uint8_t key_mask);
9
uint8_t get_key_long(uint8_t key_mask);
10
void init_entprell(void);
11
12
#define KEY_DDR DDRB
13
#define KEY_PORT PORTB
14
#define KEY_PIN PINB
15
#define KEY0 0
16
#define KEY1 1
17
#define KEY2 2
18
#define ALL_KEYS(1 << KEY0 | 1 << KEY1 | 1 << KEY2)
19
20
#define REPEAT_MASK(1 << KEY1 | 1 << KEY2) // repeat: key1, key2
21
#define REPEAT_START 50 // after 500ms
22
#define REPEAT_NEXT 20 // every 200ms
23
#define F_TIMER1 100 // Timer 1 frequency /Hz
24
25
extern volatile uint8_t key_state; // debounced and inverted key state:
26
// bit = 1: key pressed
27
extern volatile uint8_t key_press; // key press detect
28
29
extern volatile uint8_t key_rpt; // key long press and repeat
30
31
#define LED_DDR DDRC
32
#define LED_PORT PORTC
33
#define LED0 0
34
#define LED1 1
35
#define LED2 2
36
37
void setup(void) {
38
  LED_PORT = 0; // LED outputs
39
  LED_DDR = 0xFF;
40
41
  init_entprell();
42
} //Ende setup
43
44
void loop(void) {
45
  if (get_key_short(1 << KEY0)) LED_PORT ^= 1 << LED0; // reaction on key release
46
  if (get_key_long(1 << KEY1)) LED_PORT ^= 1 << LED1; // reaction after REPEAT_START ms
47
48
  // single press and repeat, running light
49
  if (get_key_press(1 << KEY2)) { // reaction on key press
50
    uint8_t i = LED_PORT;
51
    i = (i & 0x03) | ((i & ~0x03) << 1);
52
    if ((i & ~0x03) == 0) i |= (1 << LED2);
53
    LED_PORT = i;
54
  }
55
56
  volatile uint8_t key_state; // debounced and inverted key state:
57
  // bit = 1: key pressed
58
  volatile uint8_t key_press; // key press detect
59
60
  volatile uint8_t key_rpt; // key long press and repeat
61
62
  ISR(TIMER1_COMPA_vect) { // every 10ms
63
    static uint8_t ct0 = 0xFF, ct1 = 0xFF, rpt;
64
    uint8_t i;
65
66
    i = key_state ^ ~KEY_PIN; // key changed ?
67
    ct0 = ~(ct0 & i); // reset or count ct0
68
    ct1 = ct0 ^ (ct1 & i); // reset or count ct1
69
    i &= ct0 & ct1; // count until roll over ?
70
    key_state ^= i; // then toggle debounced state
71
    key_press |= key_state & i; // 0->1: key press detect
72
73
    if ((key_state & REPEAT_MASK) == 0) { // check repeat function
74
      rpt = REPEAT_START; // start delay
75
    }
76
    if (--rpt == 0) {
77
      rpt = REPEAT_NEXT; // repeat delay
78
      key_rpt |= key_state & REPEAT_MASK;
79
    }
80
  }
81
82
  void init_entprell(void) {
83
    KEY_DDR &= ~ALL_KEYS; // configure key port for input
84
    KEY_PORT |= ALL_KEYS; // and turn on pull up resistors
85
86
    // Timer 1, CTC mode 4, prescaler 256  
87
    TCCR1A = 0;
88
    TCCR1B = (1 << WGM12) | (1 << CS12);
89
    OCR1A = (F_CPU / (256 L * F_TIMER1)) - 1;
90
    TIMSK1 |= (1 << OCIE1A); // enable timer interrupt
91
  }
92
93
  /*
94
   * check if a key has been pressed. Each pressed key is reported
95
   * only once
96
   */
97
98
  uint8_t get_key_press(uint8_t key_mask) {
99
    cli(); // read and clear atomic !
100
    key_mask &= key_press; // read key(s)
101
    key_press ^= key_mask; // clear key(s)
102
    sei();
103
    return key_mask;
104
  }
105
106
  /*
107
   * check if a key has been pressed long enough such that the
108
   * key repeat functionality kicks in. After a small setup delay
109
   * the key is reported being pressed in subsequent calls
110
   * to this function. This simulates the user repeatedly
111
   * pressing and releasing the key.
112
   */
113
114
  uint8_t get_key_rpt(uint8_t key_mask) {
115
    cli(); // read and clear atomic !
116
    key_mask &= key_rpt; // read key(s)
117
    key_rpt ^= key_mask; // clear key(s)
118
    sei();
119
    return key_mask;
120
  }
121
122
  /*
123
   * check if a key is pressed right now
124
   */
125
126
  uint8_t get_key_state(uint8_t key_mask) {
127
    key_mask &= key_state;
128
    return key_mask;
129
  }
130
131
  /*
132
   * Get short key press
133
   */
134
135
  uint8_t get_key_short(uint8_t key_mask) {
136
    cli(); // read key state and key press atomic !
137
    return get_key_press(~key_state & key_mask);
138
    sei();
139
  }
140
141
  /*
142
   * Get long key press
143
   */
144
145
  uint8_t get_key_long(uint8_t key_mask) {
146
    return get_key_press(get_key_rpt(key_mask));
147
  }
148
149
} //Ende Loop ***

Unter LED_PORT = i; gehört eine zweite geschlossene Klammer "}". Danach 
bekommst du die nächsten Fehler angezeigt.

von Turbine K. (Gast)


Lesenswert?

Steve van de Grens schrieb:
>
> Unter LED_PORT = i; gehört eine zweite geschlossene Klammer "}". Danach
> bekommst du die nächsten Fehler angezeigt.

1400 Beitraege und nie diesen Satz gelesen und verstanden:
1
Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Na ja.

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Und immer schön hierdrann denken, so wie in diesem Fall, an *Punkt 4.*

"Die fünf universellen Forenregeln ;-)"

1. Threadüberschrift lesen
2. Evtl. Datum beachten
3. Posting verstehen
4. Falls nicht drittens, dann nachfragen oder Klappe halten.
5. Auf die Fragen eingehen und / oder Alternativen bzw. Verbesserungen
nennen.

Die Punkte kann man an einer Hand abzählen, man sollte also in der Lage
sein, bis fünf zählen zu können.
Deshalb sind sie evtl. gut zu merken, falls nicht dann nur Punkt 3 und
Punkt 4 merken.


Bernd_Stein

von Falk B. (falk)


Lesenswert?

Bernd S. schrieb:
> Hier sind 3-Dateien, mit denen es gehen sollte :
>
> Beitrag "Re: Tasterverarbeitung mit ARDUINO-C"
>
> Habe mal alles in eine Datei im Anhang zu sehen gepackt.

Du bist echt selbst mit Kopieren überfordert. Geh zum Teich die Enten 
füttern.

von Hugo H. (hugo_hu)


Lesenswert?


von Turbine K. (Gast)


Lesenswert?

Jetzt muss ich meinen Bildschirm saubermachen...

YMMD

Turbine

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Angehängte Dateien:

Lesenswert?

Es geht um einen Hand-Encoder in Verbindung mit PeDa's 
Komfort-Entprell-Routine.

Warum wird der Text " Spur_A & Spur_B " angezeigt, wenn doch nur Spur_A 
eine 1 vorweist?

Wie muss ich es richtig schreiben, damit nur bei Spur_A & Spur_B = 1 der 
Text angezeigt wird?


Bernd_Stein

Beitrag #7496114 wurde von einem Moderator gelöscht.
von Michael P. (mipo)


Lesenswert?

Versuch mal "&" (binär) anstatt von "&&" (logic)

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Angehängte Dateien:

Lesenswert?

Michael P. schrieb:
> Versuch mal "&" (binär) anstatt von "&&" (logic)
>
Ich hab es so wie hier gelöst, aber danke für deine Hilfestellung die 
ich nicht verstehe, aber egal ich hab ja eine Lösung.

Beitrag "Re: Abfrage ob bits gesetzt in "C""


Bernd_Stein

von Falk B. (falk)


Lesenswert?

Bernd S. schrieb:
> Ich hab es so wie hier gelöst, aber danke für deine Hilfestellung die
> ich nicht verstehe, aber egal ich hab ja eine Lösung.

Du hast keine Lösung, du hast auch keine Ahnung. Und daran wird sich 
auch zu deinen Lebzeiten nichts mehr ändern. Du stolperst nur vollkommen 
planlos durch die Gegend in der irrigen Annahme, auch nur ansatzweise 
was Sinnvolles zu programmieren.

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Angehängte Dateien:

Lesenswert?

Oder man läßt es so und macht die Bit-Schieberei in der IF-Anweisung.


Bernd_Stein

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


Lesenswert?

Hallo,

gehe bitte nochmal auf Start, sonst blickst du nie durch was du machst.
https://www.mikrocontroller.net/articles/Bitmanipulation
https://www.mikrocontroller.net/articles/Kategorie:AVR-Tutorial

von Falk B. (falk)


Lesenswert?

Veit D. schrieb:
> gehe bitte nochmal auf Start,

Nö.

> sonst blickst du nie durch was du machst.

Das wird nie passieren, wenn man den "Werdegang" von Bernd in den 
letzten 10 Jahren mal so betrachtet.

> https://www.mikrocontroller.net/articles/Bitmanipulation
> https://www.mikrocontroller.net/articles/Kategorie:AVR-Tutorial

Perlen vor die Säue!

von Georg (alphageorg)


Lesenswert?

Falk B. schrieb im Beitrag #7496114:
> Und täglich grüßt das Murmeltier. Unser Exemplar hier hat ordentlich was
> an der Murmel!

Warum so unfreundlich zu einem unerfahrenen Newbie?

von Harald K. (kirnbichler)


Lesenswert?

Georg schrieb:
> Warum so unfreundlich zu einem unerfahrenen Newbie?

Bernd ist hier seit 2009 angemeldet.

von Georg (alphageorg)


Lesenswert?

gibt ja trotzdem Leute die nur alle Jubeljahre was programmieren ...

: Bearbeitet durch User
von Michael P. (mipo)


Lesenswert?

Bernd S. schrieb:
> Michael P. schrieb:
>> Versuch mal "&" (binär) anstatt von "&&" (logic)
>>
> Ich hab es so wie hier gelöst, aber danke für deine Hilfestellung die
> ich nicht verstehe, aber egal ich hab ja eine Lösung.
>
> Beitrag "Re: Abfrage ob bits gesetzt in "C""
>
>
> Bernd_Stein

Nei, in deiner originalen Abfrage testet du ob eine Variable gleich 
einem Wert ist und gleichzeitig (logisches &&) ob das Ergebnis einer 
Schiebeoperation ungleich Null ist. Letzteres ist bei dir immer der 
Fall.

Im zitierten Beitrag wird getestet ob zwei Bits einer Variable (binär 
'ver-und-tete'(&) mit Bitmaske) gleichzeitig (logisches &&) gesetzt 
sind.

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Georg schrieb:
> gibt ja trotzdem Leute die nur alle Jubeljahre was programmieren
> ...
>
Das verstehen die nicht, die sind krank und lassen sich nicht helfen, 
also ignorieren.


Bernd_Stein

von Falk B. (falk)


Lesenswert?

Georg schrieb:
> Falk B. schrieb:
>> Und täglich grüßt das Murmeltier. Unser Exemplar hier hat ordentlich was
>> an der Murmel!
>
> Warum so unfreundlich zu einem unerfahrenen Newbie?

Der einzige unerfahrene Anfänger (aka Newbie) bist du.

von Georg (alphageorg)


Lesenswert?

Falk B. schrieb:
> Georg schrieb:
>> Falk B. schrieb:
>>> Und täglich grüßt das Murmeltier. Unser Exemplar hier hat ordentlich was
>>> an der Murmel!
>>
>> Warum so unfreundlich zu einem unerfahrenen Newbie?
>
> Der einzige unerfahrene Anfänger (aka Newbie) bist du.

Ok Boomer! ;-)

von Falk B. (falk)


Lesenswert?

Georg schrieb:
>> Der einzige unerfahrene Anfänger (aka Newbie) bist du.
>
> Ok Boomer! ;-)

Falsche Schublade. Eher Gen X

von Gerhard O. (gerhard_)


Lesenswert?

Moin,

bei mir lese ich die Key Pins in der Arduino TIMER0 ISR mit einem 
Huckepack Compare A Interrupt.

Dazu habe ich diese ISR hinzugefügt die im Hintergrund (Schmarotzerisch) 
mit der Arduino TIMER0 ISR mitläuft:

ISR(TIMER0_COMPA_vect)
{
  _keyreg = ....
}


// Der TIMER0 ist schon fuer millis() gebraucht. Man triggert den 
Interrupt // einfach in der Mitte des T0 Timers und ruft die COMPARE A 
Funktion auf/
OCR0A = 0xAF;
TIMSK0 |= _BV(OCIE0A);

Der Rest ist der normale Einsatz des Standard Beispiels von Peter.

_keyregs ist natuerlich Global deklariert und übermittelt den 
Portzustand der KEYS in Peters Code .

Das ganze hat den Vorteil den AVR kaum zu belasten und die Keys werden 
bequem von der schon existierenden ARDUINO TIMER0 ISR mitgezogen. die 
rund 1ms T0 Rate lässt sich mit einem Zähler wie gewünscht anpassen. Bei 
mir werden die Pins dann alle 10ms abgetastet.

Im konkreten Fall eigentlich über einen PCF8575 IO Expander. Aber das 
tut nichts zur Sache.

Jedenfalls funktioniert es bei mir so ausgezeichnet. Läuft wie ein 
Uhrwerk.

Gerhard

: Bearbeitet durch User
von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Angehängte Dateien:

Lesenswert?

Ich möchte die Variable tmp bei jedem " key_press " jeweils um eine 
Stelle nach links schieben.

Wie geht so etwas?
1
void loop(void)
2
{
3
  if( key_press )  { 
4
    static byte tmp;
5
    tmp = ( H_ENCODER_MSK ) & ( key_press );
6
    
7
8
  Serial.println( );
9
  Serial.println( );
10
  Serial.println( );
11
  Serial.print  ( "key_press       = "   );
12
  Serial.println(  key_press,    BIN   );
13
14
15
    byte temp = tmp;       // Dient dazu tmp..
16
    tmp = (temp<<1) | (temp>>7);    //..einmal links zu schieben
17
 
18
  //Serial.println( );
19
  Serial.print  ( "tmp             = "   );
20
  Serial.println(  tmp,    BIN           );
21
22
      if( tmp & (1<<6) ) {
23
        
24
  Serial.println( );
25
  Serial.print  ( "Rechts          = "    );
26
  Serial.println( tmp, BIN );
27
  Serial.println( );
28
      
29
      tmp = 0;
30
      }
31
      if( tmp & (1<<4) )  {
32
        
33
  Serial.println( );
34
  Serial.print  ( "Links           = "    );
35
  Serial.println( tmp, BIN );
36
  Serial.println( );
37
38
      tmp = 0;
39
      }
40
      get_key_press ( key_press );  // key_press loeschen
41
  }  
42
43
} //Ende Loop ***


Bernd_Stein

von Falk B. (falk)


Lesenswert?

Gerhard O. schrieb:
> Moin,
>
> bei mir lese ich die Key Pins in der Arduino TIMER0 ISR mit einem
> Huckepack Compare A Interrupt.

Gerhard, du verschwendest dein Zeit und Energie und fütterst einen 
lernresistenten Narzistzen! Meine Aussage war kein Witz!

Beitrag "Re: Peter Dannegger´s ( PeDa ) Entprellroutine in ein Arduino Sketch einbinden"

Der OP hat schon 10 Jahre (!) versucht, AVR Assembler zu kapieren, mit 
SEHR begrenztem Ergebnis. Nun murkst er planlos mit 1/8 Wissen mit C 
rum!

Don't feed the troll/fool!

: Bearbeitet durch User
von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Habe zum Schieben eine elegantere Schreibweise gefunden " tmp<<=1 ".
1
    //int temp = tmp;               // Dient dazu tmp..
2
    //tmp = (temp<<1) | (temp>>7);  //..einmal links zu schieben
3
4
    tmp<<=1;  // Variable eine Stelle nach links schieben


Bernd_Stein

von Wastl (hartundweichware)


Lesenswert?

Bernd S. schrieb:
> Habe zum Schieben eine elegantere Schreibweise gefunden

Hast du vielleicht doch mal ausnahmsweise einen Blick in
ein C-Lehrbuch geworfen? Oder hat dir ein Arduino-Flüsterer
was untergeschoben?

Falk B. schrieb:
> Don't feed the troll/fool!

Ja, war ein Fehler hier was zu schreiben, geb's ja zu ....

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Angehängte Dateien:

Lesenswert?

Ich habe einen Hand-Encoder der 20 Rastungen hat.
Pro Rastung werden 4 Signaländerungen erzeugt, also der typische
2-Bit-Graycode => 00; 01; 11; 10

Könnte jemand mal den Code im Anhang mit so wenig Codezeilen wie möglich 
ändern, damit pro Klick bzw. Rastung nur eine Zahl ausgegeben wird und 
nicht 4 ?

Aber bitte nicht gleich die Universallösung für 1, 2, 4 Rastungen.

Ist wieder mal ein Code von PeDa :

Beitrag "Re: Drehgeber auslesen"

Ich gebe es ja zu, so ganz bin ich da noch nicht durchgestiegen.


Bernd_Stein

von Steve van de Grens (roehrmond)


Lesenswert?

Schon wieder?

von Veit D. (devil-elec)


Lesenswert?

Bernd S. schrieb:
> Könnte jemand mal den Code im Anhang mit so wenig Codezeilen wie möglich
> ändern, damit pro Klick bzw. Rastung nur eine Zahl ausgegeben wird und
> nicht 4 ?

Die Anpassung ans Raster pro Änderung kann man über das Shiften des 
Zählerwertes machen.

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Angehängte Dateien:

Lesenswert?

Veit D. schrieb:
> Die Anpassung ans Raster pro Änderung kann man über das Shiften des
> Zählerwertes machen.
>
Ich vermute durch 2 maliges Rechtsschieben, was ja einer Teilung durch 4 
entspricht.

Verstehe leider nur nicht, warum dies nicht klappt.
Packe ich *enc_delta >>= 2;* an die eine Stelle, passiert das Eine und 
ein weiterdrehen bewirkt nichts mehr.

Genauso, wenn ich es an die andere Stelle kopiere ( siehe Screenshots ).


Bernd_Stein

von Veit D. (devil-elec)


Lesenswert?

Hallo,

du brauchst jetzt noch einen Absolutenzähler. Datentyp für deine 
Anwendung passend. Auf diesen wird immer der Wert von enc_delta 
aufaddiert. enc_delta gibt jetzt pro Rastung nur noch +1 oder -1 oder 0 
raus.

von Wilhelm M. (wimalopaan)


Lesenswert?

Wie heißt diese Disziplin: erratisches Programmieren?

von Veit D. (devil-elec)


Lesenswert?

Hallo,

bei uns in der Ausbildung hieß das MUP. Methode des unbekümmerten 
Probierens. Kann man durchaus einmal machen.  :-)  Ich kann Bernd nicht 
einschätzen. Es fällt ihm scheinbar sehr schwer und er quält sich durch.

von Harald K. (kirnbichler)


Lesenswert?

Wilhelm M. schrieb:
> Wie heißt diese Disziplin: erratisches Programmieren?

Nee:

https://de.wikipedia.org/wiki/Infinite-Monkey-Theorem

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Angehängte Dateien:

Lesenswert?

Ich habe PeDa`s solide Lösung für einen ATmega 2560-Board angepasst, 
wobei der CTC-Modus des Timer1 genutzt wird.

Könnte mir jemand einen Code zeigen oder schreiben, wo pro Klick, also 
pro Rastung nur einmal ein Wert über die RS232 geschickt wird?

An den LED`s kann ich sehen, dass es generell funktioniert.

Veit D. schrieb:
> Es fällt ihm scheinbar sehr schwer und er quält sich durch.
>
Dies stimmt leider. Ich bin kein Autodidakt und C ist noch sehr 
kryptisch für mich.
1
void loop() 
2
{
3
 val += encode_read(4);          // read a single step encoder
4
    
5
Serial.print  ( "val                             = "  );
6
Serial.println(  val, DEC );
7
//Serial.println( );
8
    
9
    LEDS = val;
10
    
11
  
12
} // Ende void loop()


Bernd_Stein

von Veit D. (devil-elec)


Angehängte Dateien:

Lesenswert?

Hallo,

val entfernt, dafür struct Counter erstellt, kannste auch umbenennen.
Immer wenn alt ungleich neu ist wird das verarbeitet.
Einfaches Prinzip um ständige Wiederholungen ohne Änderung zu 
unterdrücken.

von Wilhelm M. (wimalopaan)


Lesenswert?

Vielleicht sollte man auch mal ein C++ Variante des zugehörigen Artikels

https://www.mikrocontroller.net/articles/Drehgeber

erstellen.

von Harald K. (kirnbichler)


Lesenswert?

Niemand hält Dich davon ab, es zu tun. Bring' Dich ein!

von Wilhelm M. (wimalopaan)


Lesenswert?

Harald K. schrieb:
> Niemand hält Dich davon ab, es zu tun. Bring' Dich ein!

Es geht ja nur im den Variablennamen `new`, in C++ ist das ein 
Schlüsselwort.

von Harald K. (kirnbichler)


Lesenswert?

Wilhelm M. schrieb:
> Es geht ja nur im den Variablennamen `new`, in C++ ist das ein
> Schlüsselwort.

Du kannst den Text auch ändern, das ist ein Wiki.

Ich zitier' mich mal selbst:
> Niemand hält Dich davon ab, es zu tun. Bring' Dich ein!

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Wilhelm M. schrieb:
>> Niemand hält Dich davon ab, es zu tun. Bring' Dich ein!
>
> Es geht ja nur im den Variablennamen `new`, in C++ ist das ein
> Schlüsselwort.

Naja, aber durch Änderung des Namens wird keine "echtes" C++ draus.

von Wilhelm M. (wimalopaan)


Lesenswert?

Falk B. schrieb:
> Wilhelm M. schrieb:
>>> Niemand hält Dich davon ab, es zu tun. Bring' Dich ein!
>>
>> Es geht ja nur im den Variablennamen `new`, in C++ ist das ein
>> Schlüsselwort.
>
> Naja, aber durch Änderung des Namens wird keine "echtes" C++ draus.

Das stimmt, jedoch wird es als C++-Code compilierbar. Und das würde 
sicher vielen Arduino-Leuten (wie hier) helfen.

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)



Lesenswert?

Veit D. schrieb:
> Hallo,
>
> val entfernt, dafür struct Counter erstellt, kannste auch umbenennen.
>
Vielen dank für deinen Code, der auch funktioniert, den ich aber leider 
nicht nachvollziehen konnte.

Vielleicht kann mir ja jemand erklären warum meine Lösung auch 
funktioniert.

Selbst meine Lösung verstehe ich nicht. Habe sie durch Zufall gefunden, 
als ich wenigstens nur einen Wert, nämlich die 1 ausgeben wollte. Beim 
weiterdrehen kam dann 2 usw. Die Gegenrichtung funktionierte nicht, da 
hab ich einfach mal ...
1
void loop() 
2
{
3
  if( enc_delta == 4 | enc_delta == -4 )  {
4
    val += encode_read(4);          // 4 Signaländerungen pro Rastung
5
    
6
Serial.print  ( "val = "  );
7
Serial.println(  val, DEC );
8
9
  }  
10
  LEDS = val;
11
} // Ende void loop()

Ach, anbei noch eine gute Erklärung zu PeDa's Hand-Encoder-Lösung.
Ab Kapitel 5, Seite 11 bzw. 20.


Bernd_Stein

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Wilhelm M. schrieb:
> Das stimmt, jedoch wird es als C++-Code compilierbar. Und das würde
> sicher vielen Arduino-Leuten (wie hier) helfen.

To whom it may concern.

Beitrag "Drehgeber und Tastenentprellung für Arduino"

von Christoph M. (mchris)


Lesenswert?

Kleiner Tipp: *.txt ist kein guter Name für einen Dateianhang mit Code.
Wenn ihr statt dessen *.cpp verwendet, kriegt ihr auch das 
"Syntax-Highlighting). Ob das MC-net auch *.ino kann, weiß ich nicht.

von Harald K. (kirnbichler)


Lesenswert?

Christoph M. schrieb:
> Ob das MC-net auch *.ino kann, weiß ich nicht.

Tut es.

von J. T. (chaoskind)


Lesenswert?

Falk B. schrieb:
> Der einzige unerfahrene Anfänger

Gibt es auch erfahrene Anfänger?

von Wilhelm M. (wimalopaan)


Lesenswert?

Harald K. schrieb:
> Wilhelm M. schrieb:
>> Es geht ja nur im den Variablennamen `new`, in C++ ist das ein
>> Schlüsselwort.
>
> Du kannst den Text auch ändern, das ist ein Wiki.

Echt? War mir noch gar nicht aufgefallen ;-)

> Ich zitier' mich mal selbst:
>> Niemand hält Dich davon ab, es zu tun. Bring' Dich ein!

Die Frage ist, ob es überhaupt Sinn macht. Zwar bin ich davon überzeugt, 
dass meine Lösung tatsächlich die flexibelste und effektivste ist, 
jedoch scheitert es ja regelmäßig daran, dass die Leute hier sich 
beschweren, dass bspw. für avr-g++ keine libstdc++ verfügbar ist, und 
dass deswegen kein std::array<> oder std::make_index_sequence<>, ... 
verfügbar sei. Aber auf die Idee, das selbst zu erstellen, kommt 
irgendwie keiner. Und wenn man die Sachen hinzufügt, dann kommt die 
Beschwerde, es sei zu umfangreich. Obwohl das natürlich Bestandteil 
einer Bibliothek ist, damit gar keine Rolle spielt und der eigentliche 
Code zur Lösung der Aufgabe recht kurz. Weil er so kurz ist, kommt die 
Beschwerde, dass zu viel hinter Bibliotheken versteckt sei und man 
deswegen nichts verstehe bzw. Meta-Programmierung, funktionale Ansätze 
und Closures nicht geeignet seien. Für die meisten größeren Controller 
(etwa STM) macht es dann auch wieder wenig Sinn, weil die ja oft einen 
Quadratur-Encoder als interne Peripherie dabei haben. Daher verspüre ich 
wenig Drang dazu, das in das Wiki zu schreiben.

von Harald K. (kirnbichler)


Lesenswert?

Wilhelm M. schrieb:
> Zwar bin ich davon überzeugt, dass meine Lösung tatsächlich
> die flexibelste und effektivste ist,

Wenn Du Leute überzeugen willst, musst Du Leute überzeugen. Aufstampfen 
und "meins ist aber besser" sagen bringt nicht viel.

von Wilhelm M. (wimalopaan)


Lesenswert?

Harald K. schrieb:
> Wilhelm M. schrieb:
>> Zwar bin ich davon überzeugt, dass meine Lösung tatsächlich
>> die flexibelste und effektivste ist,
>
> Wenn Du Leute überzeugen willst, musst Du Leute überzeugen.

Ich will hier(!) keinen überzeugen ;-)
An anderer Stelle schon

> Aufstampfen

Kann mich nicht daran erinnern, das gemacht zu haben ;-)

von Falk B. (falk)


Lesenswert?

Wilhelm M. schrieb:
> Die Frage ist, ob es überhaupt Sinn macht. Zwar bin ich davon überzeugt,
> dass meine Lösung tatsächlich die flexibelste und effektivste ist,

Kann sein, ist beim Thema Arduino und seiner großen Zielgruppe aber 
nicht das wesentliche Kriterium. Es muss einfach anwendbar und robust 
sein. Das reicht. Selbst Einschränkungen in der Funktionalität sind in 
vielen Fällen akzeptabel und werden teileise sogar aktiv betrieben, um 
die Einfachheit zu erreichen. Der Wurm muss dem Fisch schmecken und 
nicht dem Angler!

von Wilhelm M. (wimalopaan)


Lesenswert?

Falk B. schrieb:
> Der Wurm muss dem Fisch schmecken und
> nicht dem Angler!

Ich mache mir weder Gedanken um den Wurm, noch um die kulinarischen 
Vorlieben des Anglers oder das Nahrungsangebot für den Fisch ...

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Wieso meine Lösung auch funktioniert weiß wohl keiner hier oder ?
1
if( enc_delta == 4 | enc_delta == -4 )

Beitrag "Peter Dannegger´s ( PeDa ) Solide-Encoder-Lösung in ein Arduino Sketch einbinden"


Bernd_Stein

von Stefan S. (chiefeinherjar)


Lesenswert?

Bernd S. schrieb:
> if( enc_delta == 4 | enc_delta == -4 )

Müsste es nicht

> if( enc_delta == 4 || enc_delta == -4 )

heißen?

Denn ansonsten verodert man den Wert 4 mit enc_delta und fragt keine 
zwei Bedingungen ab.

von J. S. (jojos)


Lesenswert?


von Sebastian W. (wangnick)


Lesenswert?

Bernd S. schrieb:
> Wieso meine Lösung auch funktioniert weiß wohl keiner hier oder ?
>
> if( enc_delta == 4 | enc_delta == -4 )

Doch, natürlich.

https://en.cppreference.com/w/cpp/language/operator_precedence

Wie du siehst, bindet == stärker sowohl als | (bitwise OR) als auch als 
|| (logical OR). Du führst also eine bitweise Veroderung zweier 
Vergleichsresultate aus. Vergleichsresultate sind immer entweder 0 oder 
1. Und deren bitweise Veroderung ergibt dasselbe Resultat wie deren 
logische Veroderung.

Dennoch solltest du dir natürlich angewöhnen, in logischen Ausdrücken 
die logischen Operatoren zu verwenden, und nicht die Bitoperatoren.

LG, Sebastian

: Bearbeitet durch User
von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Angehängte Dateien:

Lesenswert?

Sebastian W. schrieb:
> Dennoch solltest du dir natürlich angewöhnen, in logischen Ausdrücken
> die logischen Operatoren zu verwenden, und nicht die Bitoperatoren.
>
Ich versuch es ja.
Ich versteh es trotzdem nicht.
Wenn ich beispielsweise 5 habe ist dies weder == 4 noch == -4.

Jetzt was anderes. Habe schon sämtliche Datentypen durch und weiß nicht 
wie ich es schaffen soll, dass wenn der Wert von val < 0 wird, val = 0 
gesetzt wird. Oder wenn val >= 65535 wird val auf 65535 begrenzt wird 
(siehe Screenshot ).


Bernd_Stein

von Stefan S. (chiefeinherjar)


Lesenswert?

Bernd S. schrieb:
> val >= 65535

Kann val denn überhaupt größer als 65535 werden? Wenn es ein uint16 ist, 
dann wird dieser Wert nie erreicht. Der Zähler wenn er immer um 4 
inkrementiert wird) erreicht erst den Wert 65.532 und läuft dann über 
und steht auf dem Wert 1 anstatt 65.536 zu erreichen.

Konkret sieht es so aus:
val wird um 4 inkrementiert und hat den Wert 65.532. Dies erfüllt deine 
Bedinungung noch nicht. Nächster Durchlauf, val wird wieder um 4 
inkrementiert und anstatt 65536 zu erreichen, hat val den Wert 1. Und 
vergleicht man, ob 1 >= 65535 ist, kommt man zu dem Schluss, dass dies 
nicht der Fall ist.

Was aber außerhalb deines Schnipsels mit val passiert liegt wieder im 
Dunkeln...

von Veit D. (devil-elec)


Lesenswert?

Wilhelm M. schrieb:

> Die Frage ist, ob es überhaupt Sinn macht. Zwar bin ich davon überzeugt,
> dass meine Lösung tatsächlich die flexibelste und effektivste ist,
> jedoch scheitert es ja regelmäßig daran, dass die Leute hier sich
> beschweren, dass bspw. für avr-g++ keine libstdc++ verfügbar ist, und
> dass deswegen kein std::array<> oder std::make_index_sequence<>, ...
> verfügbar sei. Aber auf die Idee, das selbst zu erstellen, kommt
> irgendwie keiner. Und wenn man die Sachen hinzufügt, dann kommt die
> Beschwerde, es sei zu umfangreich. Obwohl das natürlich Bestandteil
> einer Bibliothek ist, damit gar keine Rolle spielt und der eigentliche
> Code zur Lösung der Aufgabe recht kurz. Weil er so kurz ist, kommt die
> Beschwerde, dass zu viel hinter Bibliotheken versteckt sei und man
> deswegen nichts verstehe bzw. Meta-Programmierung, funktionale Ansätze
> und Closures nicht geeignet seien. Für die meisten größeren Controller
> (etwa STM) macht es dann auch wieder wenig Sinn, weil die ja oft einen
> Quadratur-Encoder als interne Peripherie dabei haben. Daher verspüre ich
> wenig Drang dazu, das in das Wiki zu schreiben.

Das liest sich alles nach Ausrede. Man muss ja nicht immer mit der 
größten Keule jedes Problem erschlagen. Wenn man die libstdc++ nicht 
hat, löst man das Problem eben ohne. Da finden sich immer Wege. Und wenn 
du jemanden eine praktische Lösung vorschlagen möchtest ist es irgendwie 
vermessen und gar komisch, von den gleichen Leuten denen man mit einer 
Lösung ihres Problems helfen möchte gleichzeitig zu verlangen das die 
gefälligst vorher sich ihre libstdc++ selbst schreiben. Das passt ja nun 
nicht zusammen. Wer in der Lage ist seine libstdc++ zu schreiben, der 
benötigt sicherlich keine fremde Hilfe mehr für irgendwas anderes. Für 
diese Encoderauswertung hier benötigt man zudem keine libstdc++. Ich 
wüßte nicht wofür. Der nächste Gedanke ist, wenn jeder seine libstdc++ 
schreibt ist das bestimmt nie zu 100% zur echten libstdc++ kompatibel. 
Da gibt es zu viele Fallstricke der Umsetzung, nehme ich an. Du wirst 
deine sicherlich auch immer mal wieder anpassen müssen, weil irgendwo 
ein Problem auftauchte.
Wenn du wirklich helfen möchtest, dann kannst du den Leuten hier helfen 
ihre libstdc++ aktuell zu halten. 
https://github.com/modm-io/avr-libstdcpp
Das ist die Beste die ich kenne, läuft aber manchmal noch nicht "ganz 
rund".
Ich formuliere es einmal anders. Du musst nicht jeden Tag den Leuten 
unter die Nase reiben das du deine libstdc++ hast und sie alle 
gefälligst nachprogrammieren sollen. Die meisten werden davon noch nie 
etwas gehört haben und kamen auch ohne gut klar. Viele Dinge der 
libstdc++ kann man auf dem AVR sowieso nicht nutzen wegen 
Speicherallokationen. Da muss man sowieso wissen was man tut. Von daher 
ist die komplette libstdc++ in meinen Augen witzlos.

Laut meines Wissens wird die libstdc++ für C++23 in größerem Umfang 
"umgebaut". Um das Problem zu bekämpfen das man eigentlich gar nicht 
weiß welche Bibliothek man einbinden muss um irgendwas passendes 
anwenden zu können. Die ist also wie der gcc selbst nie fertig. Der 
Pflegeaufwand muss sehr hoch sein. Das ist in meinen Augen noch ein 
Grund warum ich mir bis jetzt nur paar Type Traits davon nachgebaut habe 
aber nie wirklich angefangen habe mich mit der libstdc++ als solches zu 
befassen. Ich will ja meine Aufgaben lösen und mir nicht künstlich neue 
Probleme schaffen. Das Ding heißt ja nicht umsonst Standard STL und 
nicht Wilhelm-STL oder Veit-STL. Die ist ja nur einfachen Nutzung da und 
nichts anderes und ausgiebig getestet.

Wenn du für den Encoder eine praktische Lösung hast ohne libstdc++ 
kannste die zeigen. Vielleicht haste ja eine bessere Lösung als meine 
für meinen Nano Every. Aber deine ständige Wiederholung nach dem Motto 
"warum habt ihr Idioten keine eigene libstdc++" geht mir langsam aber 
sicher auf den Zeiger. Weil das hilft niemanden weiter. Denn wenn ich 
was habe was ich sowieso niemanden anderem zeige, dann erzähle ich davon 
erst gar nicht.

: Bearbeitet durch User
von Wilhelm M. (wimalopaan)


Lesenswert?

Veit D. schrieb:
> Für
> diese Encoderauswertung hier benötigt man zudem keine libstdc++. Ich
> wüßte nicht wofür.

Wenn man etwas mit TMP macht, so benötigt man eigentlich immer 
std::index_sequence<>, std::integral_constant<>, 
std::make_index_sequence<>. Und für integrierte Test oder LUTs dann auch 
std::array<>.

Veit D. schrieb:
> https://github.com/modm-io/avr-libstdcpp
> Das ist die Beste die ich kenne, läuft aber manchmal noch nicht "ganz
> rund".

Na, das ist ja großartig. Es ist schon wirklich Jahre her, dass ich mir 
das Projekt mal angesehen hatte. Aber der Hinweis ist natürlich sehr 
wichtig, als es nun gar keinen Grund mehr gibt, Dinge abzulehnen, die 
für AVR auch die stdlibc++ benutzen.

Veit D. schrieb:
> Viele Dinge der
> libstdc++ kann man auf dem AVR sowieso nicht nutzen wegen
> Speicherallokationen. Da muss man sowieso wissen was man tut. Von daher
> ist die komplette libstdc++ in meinen Augen witzlos.

Wenn die o.g. Realisierung nun tatsächlich einen std::vector<> oder 
std::string<> mit Heap-Alloc anbietet, dann ist das natürlich Murks. 
Vielleicht doch nicht so gut, was Du da erwähnst. Entweder man hat so 
etwas wie FixedVector<> oder man benutzt einen static-pool-allocator.

Veit D. schrieb:
> Um das Problem zu bekämpfen das man eigentlich gar nicht
> weiß welche Bibliothek man einbinden muss um irgendwas passendes
> anwenden zu können.

Du meinst "modules". Man wird aber weiterhin header benutzen können. Der 
Vorteil der "modules" liegt woanders.

Veit D. schrieb:
> Aber deine ständige Wiederholung nach dem Motto
> "warum habt ihr Idioten keine eigene libstdc++" geht mir langsam aber
> sicher auf den Zeiger.

Es hat aber nun endlich Deinen Hinweis zu Tage gebracht, dass es 
tatsächlich eine stdlibc++ für AVR gibt. Das finde ich schon mal sehr 
wichtig.

von Veit D. (devil-elec)


Lesenswert?

Wilhelm M. schrieb:
> Veit D. schrieb:
>> Für
>> diese Encoderauswertung hier benötigt man zudem keine libstdc++. Ich
>> wüßte nicht wofür.
>
> Wenn man etwas mit TMP macht, so benötigt man eigentlich immer
> std::index_sequence<>, std::integral_constant<>,
> std::make_index_sequence<>. Und für integrierte Test oder LUTs dann auch
> std::array<>.

Ein Bsp. von mir ohne stdlibc++.
Beitrag "Drehgeber und Tastenentprellung für Arduino"

> Veit D. schrieb:
>> Viele Dinge der
>> libstdc++ kann man auf dem AVR sowieso nicht nutzen wegen
>> Speicherallokationen. Da muss man sowieso wissen was man tut. Von daher
>> ist die komplette libstdc++ in meinen Augen witzlos.
>
> Wenn die o.g. Realisierung nun tatsächlich einen std::vector<> oder
> std::string<> mit Heap-Alloc anbietet, dann ist das natürlich Murks.
> Vielleicht doch nicht so gut, was Du da erwähnst. Entweder man hat so
> etwas wie FixedVector<> oder man benutzt einen static-pool-allocator.

Ist es nicht der Sinn eines Standards das Standardverhalten für alle zu 
haben? Ich kann doch niemanden einen Vorwurf machen wenn er das 
Standardverhalten für AVR nachbaut. Der es dann nutzt muss wissen was er 
auf einem AVR sinnvoll einsetzen kann und was nicht. Soweit muss man da 
gar nicht schauen. Das fängt schon mit der String Lib an, ohne zu wissen 
was man tut kann die nach hinten losgehen. Das Problem mit dem Speicher 
ist auch nicht zwingend auf AVR begrenzt. Alle die µC programmieren und 
die libstdc++ verwenden müssen wissen was sie ihrem stark begrenzten 
Speicher im Vergleich zur Desktop CPU/RAM zumuten können und was nicht.

> Veit D. schrieb:
>> Um das Problem zu bekämpfen das man eigentlich gar nicht
>> weiß welche Bibliothek man einbinden muss um irgendwas passendes
>> anwenden zu können.
>
> Du meinst "modules". Man wird aber weiterhin header benutzen können. Der
> Vorteil der "modules" liegt woanders.

Ja richtig, hing mit dem kommenden Modules zusammen.

Sorry Bernd für die Abschweifung in deinem Thread.

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)



Lesenswert?

Veit D. schrieb:
> Sorry Bernd für die Abschweifung in deinem Thread
>
Danke, das zeigt dass du Anstand hast.
Ich finde hier seid ihr mit eurer Diskusion besser aufgehoben :

Beitrag "Drehgeber und Tastenentprellung für Arduino"

Stefan S. schrieb:
> Kann val denn überhaupt größer als 65535 werden? Wenn es ein uint16 ist,
> dann wird dieser Wert nie erreicht.
> ...
>
Auch int32_t brachte kein Erfolg, aber jetzt mal ganz von Anfang.
val wurde in Einer Schritten gezählt. Zuerst vorwärts bis 2, dann 
rückwärts um die Bedingung *val < 0* zu prüfen. Hierbei erwartete ich 
-1, aber stattdessen wird die Bedingung *val >= 65535* erfüllt ( siehe 
Screenshot im Link ).

Beitrag "16-Bit Wertbegrenzungen 0 und 65535 setzen"

Das Programm ist im Anhang ( ..._Original ) und die Folge für val ist " 
*2 + 102 ", was eigentlich 164346 ergeben müsste. Jetzt dürfen wir 
raten, warum 38810 herauskommt ( siehe Screenshot ).
1
if( val >= 65535 ) val = 65535; 
2
if( val  <  0    ) val = 0;


Bernd_Stein

: Bearbeitet durch User
von Klaus (feelfree)


Lesenswert?

Bernd S. schrieb:
> was eigentlich 164346 ergeben müsste. Jetzt dürfen wir
> raten, warum 38810 herauskommt

tippfehler (104346 wäre richtig), minus 65536 macht 38810.

von Veit D. (devil-elec)


Lesenswert?

Hallo,

warum soll für val 164.346 rauskommen wenn du den Wert nach oben auf 
65.535 begrenzt?
1
if( val > 65535 ) val = 65535; 
2
    if( val <     0 ) val = 0;
Das ist in der Reihenfolge quatsch.
1
void loop() 
2
{
3
  if( enc_delta == 4 || enc_delta == -4 )  {
4
    val += encode_read(4);          // 4 Signaländerungen pro Rastung
5
    val += val +100;  // Zum Testen
6
    cli( );
7
    OCR3A = val;                    // An Rechteckgenerator Wert übergeben
8
    sei( );
9
    if( val > 65535 ) val = 65535; 
10
    if( val <     0 ) val = 0; 
11
  
12
Serial.print  ( "val   = "  );
13
Serial.println(  val, DEC   );
14
Serial.print  ( "OCR3A = "  );
15
Serial.println(  OCR3A, DEC );

Bei der Zuweisung kommt es zum Überlauf. OCR3A hat nur den uint16_t 
Wertebereich.
1
OCR3A = val;

Das muss nach der Limitüberprüfung zugewiesen werden. Nicht davor.

Hier ist eine doppelte Addition drin.
1
val += val +100;

Das macht zum testen eher Sinn. 'DEC' kannste übrigens weglassen.
1
void loop() 
2
{
3
  if( enc_delta == 4 || enc_delta == -4 )  {
4
    val += encode_read(4);          // 4 Signaländerungen pro Rastung
5
    Serial.print  ( "val = " );
6
    Serial.println( val );
7
    val = val + 100;  // Zum Testen
8
    Serial.print  ( "+100 = " );
9
    Serial.println( val );
10
    if( val > 65535 ) val = 65535; 
11
    if( val <     0 ) val = 0; 
12
    Serial.println( "Limits" );  
13
    Serial.print  ( "val = " );
14
    Serial.println( val );
15
    cli( );
16
    OCR3A = val;                    // An Rechteckgenerator Wert übergeben
17
    sei( );
18
    Serial.print  ( "OCR3A = " );
19
    Serial.println( OCR3A );

von Falk B. (falk)


Angehängte Dateien:

Lesenswert?

Jaja, programmieren mit Unlogik . . .
Ich weiß zwar nicht warum ich das hier mache, ich mach's trotzdem. Siehe 
Anhang.
1
volatile int8_t enc_delta;
2
static uint8_t last;

Diese beiden Variabelen sind TABU!!! Die faßt man an Anwender NIE an! 
Die einzige Funktion, die man benutzt, ist

int8_t encode_read( uint8_t klicks );

Die liefert die Anzahl der Schritte seit dem letzten Aufruf mit 
Vorzeichen! Nur DAMIT arbeitet man.

Dann ist es auch leicht, zu erkennen, wann am Rad gedreht wurde. Nämlich 
dann, wenn der Rückgabewert ungleich 0 ist! WOW! Der Rest ist trivial^2. 
Oder doch nicht? Naja, man sollte schon VOR der Benutzung einer 
Variablen deren Grenzen prüfen und nicht DANACH! Du hast es genau anders 
herum gemacht! (Sind wir überrascht? Nicht wirklich)

Und interen Pull-Ups schaltet man auch anders ein.

von Christoph M. (mchris)


Lesenswert?

>Ich weiß zwar nicht warum ich das hier mache, ich mach's trotzdem. Siehe
Anhang.

Und wenn man es richtig machen wollte, würde man sich dann noch an die 
Spezifikation halten:

https://arduino.github.io/arduino-cli/0.34/library-specification/

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

1
    cli( );
2
    OCR3A = val;                    // An Rechteckgenerator Wert übergeben
3
    sei( );
Bin mir gar nicht mehr sicher ob das mit cli und sei überhaupt nötig 
ist.
Und wenn nein - warum ?

Falk B. schrieb:
> Ich weiß zwar nicht warum ich das hier mache, ich mach's trotzdem.
>
Wahrscheinlich, weil du es kannst ;-)
1
case  4: enc_delta = val & 3; val >>= 2; break;
Diese Logik verstehe ich nicht. val ist zu Begin = enc_delta.
Man maskiert Bit 0 & 1 aus, dann schiebt diese so, dass enc_delta immer 
Null ergibt.
1
////////////////////////////////////////////////////////////////////////////////
2
void loop() 
3
{
4
  int8_t delta;
5
6
  delta = encode_read(4);          // 4 Signaländerungen pro Rastung
7
  if( delta != 0 )  {
8
    pwm_wert += delta;
9
    if( pwm_wert > 65535 ) pwm_wert = 65535; 
10
    if( pwm_wert <     0 ) pwm_wert = 0; 
11
    OCR3A = pwm_wert;                    // An Rechteckgenerator Wert übergeben
Warum erzeugt man zwei weitere Variablen ( delta, pwm_wert ) und 
arbeitet nicht einfach mit val weiter ?

Bernd_Stein

: Bearbeitet durch User
von Falk B. (falk)


Lesenswert?

Bernd S. schrieb:
> cli( );
>     OCR3A = val;                    // An Rechteckgenerator Wert
> übergeben
>     sei( );
> Bin mir gar nicht mehr sicher ob das mit cli und sei überhaupt nötig
> ist.
> Und wenn nein - warum ?

Weil das Register durch den Compiler schon richtig beschrieben wird und 
in deinem Programm kein Zugriff darauf in einem Interrupt passiert.

> Wahrscheinlich, weil du es kannst ;-)

case  4: enc_delta = val & 3; val >>>= 2; break;

> Diese Logik verstehe ich nicht. val ist zu Begin = enc_delta.
> Man maskiert Bit 0 & 1 aus, dann schiebt diese so, dass enc_delta immer
> Null ergibt.

Das muss du gar nicht verstehen, denn du willst den Drehgeber nur 
benutzen. Fertig.

> //////////////////////////////////////////////////////////////////////// 
////////
> void loop()
> {
>   int8_t delta;
>   delta = encode_read(4);          // 4 Signaländerungen pro Rastung
>   if( delta != 0 )  {
>     pwm_wert += delta;
>     if( pwm_wert > 65535 ) pwm_wert = 65535;
>     if( pwm_wert <     0 ) pwm_wert = 0;
>     OCR3A = pwm_wert;                    // An Rechteckgenerator Wert
> übergeben
> Warum erzeugt man zwei weitere Variablen ( delta, pwm_wert ) und
> arbeitet nicht einfach mit val weiter ?

Weil es so besser ist. Klar kann man sich auch den alten Wert merken und 
prüfen, ob eine Änderung vorliegt. Ist aber doppelt gemoppelt. Außerdem 
ist delta eine kleine 8 Bit Zahl, pwm_wert ja nach Anwendung 16 oder 32 
Bit. Mehr Speicher, mehr CPU-Last, mehr Aufwand für einen Vergleich.

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Falk B. schrieb:
> Das muss du gar nicht verstehen, denn du willst den Drehgeber nur
> benutzen. Fertig.
>
1
case  4: h_encoder_delta = val & 3; val >>= 2; break;
Wär aber schön, denn ich verstehe auch nicht, wieso h_encoder_delta in 
der ISR nur bis 4 bzw. -4 zählt. Der Ausdruck rechts vom 
Gleichheitszeichen ergibt ja entweder 1 oder -1. Also wird doch 
eigentlich h_encoder_delta  bis zum Überlauf hoch,- bzw. runtergezählt

Was sorgt dafür, dass h_encoder_delta nur bis 4 hochzählt, wenn doch 
immer 1 addiert wird ?
1
volatile  int8_t h_encoder_delta;
2
3
h_encoder_delta += (diff & 2) - 1;   // bit 1 = direction (+/-)


Bernd_Stein

von Falk B. (falk)


Lesenswert?

Bernd S. schrieb:
> Falk B. schrieb:
>> Das muss du gar nicht verstehen, denn du willst den Drehgeber nur
>> benutzen. Fertig.
>>case  4: h_encoder_delta = val & 3; val >>= 2; break;

> Wär aber schön, denn ich verstehe auch nicht, wieso h_encoder_delta in
> der ISR nur bis 4 bzw. -4 zählt.

Bei jedem Aufruf der Funktion passiert folgendes

h_encoder_delta = val & 3;
nur die unteren 2 Bit von h_encoder_delta bleiben übrig, die oberen Bits 
werden gelöscht. 3 = 0b00000011, siehe Bitmanipulation.

val >>= 2; break;
Die Variable val, welche den Wert von h_encoder_delta enthält, wird um 2 
Bits nach rechts geschoben. Damit werden die unteren 2 Bits 
rausgeschoben und die Variable praktisch durch 4 dividiert. Denn genau 
das will man bei einem Encoder, der 4 elektrische Pulse / mechanischer 
Raststufe besitzt.

> Der Ausdruck rechts vom
> Gleichheitszeichen ergibt ja entweder 1 oder -1. Also wird doch
> eigentlich h_encoder_delta  bis zum Überlauf hoch,- bzw. runtergezählt

Nö.

> Was sorgt dafür, dass h_encoder_delta nur bis 4 hochzählt, wenn doch
> immer 1 addiert wird ?

Die Tatsache, daß dein Programm die Funktion encode_read(4) sehr oft 
aufruft, mit mehreren Dutzend kHz. In der Zeit kann sich die Variable 
gar nicht schneller ändern, denn die ISR, welche die Variable verändert, 
läuft nur mit 1kHz. In einem richtigen Programm wird die Funktion 
deutlich langsamer aufgerufen, vielleicht mit 1-10 Hz. In der Zeit kann 
der Drehgeber aber mehrere Schritte machen. Die werden alle korrekt 
gezählt.

Mach einfach mal einen Test. Füge ein

delay(1000);

ans Ende deiner Funktion loop() ein und staune.

von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Angehängte Dateien:

Lesenswert?

Falk B. schrieb:
> Bei jedem Aufruf der Funktion passiert folgendes
> ...
>
Danke, dass du es mir doch noch erklärt hast.

Die einfachsten Dinge bereiten mir Probleme, es ist schon fast 
verflucht.
In der rechteckgenerator_init, weise ich OCR3A den Wert 10.000 zu.
Es hat aber seltsamerweise den Wert 16. Mache ich dies an einer anderen 
Stelle, so stimmt alles.

Was läuft hier falsch?


Bernd_Stein

von J. S. (jojos)


Lesenswert?

10.000 scheint nicht in ein 8 Bit Register zu passen. 10.000 modulo 256 
ergibt 16.
Du musst mit den Grundlagen vom ersten Kapitel an anfangen.

Edit:
Ok, es ist ein 16 Bit Register. Das ist es nicht.
Der Wert steht vermutlich richtig im Register, aber im PrintLn wird der 
Zugriff nicht richtig gemacht. Auslesen über 16 Bit Hilfsvariable könnte 
gehen.

: Bearbeitet durch User
von Arduino F. (Firma: Gast) (arduinof)


Lesenswert?

Bernd S. schrieb:
> Was läuft hier falsch?

Ich stelle fest: Arduino Mega
Also werden alle Timer für 8 Bit PWM vorbereitet und Timer0 ist 
zusätzlich für millis() und Freunde vorbereitet.

Das kann die lustigsten Fallen stellen!

Darum grundsätzlich die Timer Control Register erst zurücksetzen, bevor 
man irgend etwas anderes damit anstellt.
(Ausnahme Timer0)

Es gab mal einen Thread hier, über das sonst entstehende undokumentierte 
Durcheinander.
Denn, entweder hat der Timer einen Bug, oder das Datenblatt ist 
unvollständig.


Beispiel:
1
void rechteckgenerator_init ( void )  {
2
  TCCR3A  = 0;               
3
  TCCR3B  = 0; 
4
5
   
6
  TCCR3A  = 1<< COM3A0;                 // OC3A Toggeln
7
  TCCR3B  = 1<< WGM12 | 1<< CS10;   // Mode 4 & Vorteiler = 1
8
9
  OCR3A  = 10000;                         // OCR3A bestimmt die Frequenz
10
         
11
Serial.print  ( "OCR3A init = "  );
12
Serial.println(  OCR3A              );
13
14
    DDRE |= 1<<3;                          // OC3A-Pin als Ausgang konfigurieren
15
}

Ich empfehle diese Reihenfolge einzuhalten.

: Bearbeitet durch User
von Bernd S. (Firma: Anscheinend Corner-Cases ;-)) (bernd_stein)


Lesenswert?

Arduino F. schrieb:
> Ich empfehle dies Reihenfolge einzuhalten
>
Jo, danke. OCR3A ganz zum Schluss der initialisierung und es klappt !


Bernd_Stein

von Veit D. (devil-elec)


Lesenswert?

Hallo,

man kann nicht einfach wahllos irgendein Register ändern und danach den 
gesamten Timer neu konfigurieren. Bei Arduino sind die Timer mit PWM 
Einstellungen für analogWrite vorkonfiguriert. Wenn man noch nicht ganz 
genau weiß was macht macht, immer erstmal alle relevanten Timer Register 
reseten. Zuerst TCCRnB, damit steht der Timer und kann keinen Unsinn 
mehr machen. Dann den Rest reseten, dann neu einstellen und zum Schluss 
den Prescaler setzen. Dann läuft der Timer sauber an. Wenn der vorher 
schon läuft und die Konfig noch nicht fertig, kann und wird er Mist 
machen, auch wenn es ggf. nur kurzeitig ist.
1
void rechteckgenerator_init ( void )  {
2
  // Reset
3
  TCCR3B = 0;             
4
  TCCR3A = 0;
5
  TCNT3  = 0;       
6
  TIMSK3 = 0;
7
  // Neukonfiguration 
8
  TCCR3A = _BV(COM3A0);              // OC3A Toggeln
9
  DDRE   = _BV(3);                   // OC3A-Pin als Ausgang konfigurieren
10
  OCR3A  = 10000;                    // OCR3A bestimmt die Frequenz
11
  TCCR3B = _BV(WGM12) | _BV(CS10);   // Mode 4, Prescaler 1
12
  
13
  Serial.print  ( "OCR3A init = " );
14
  Serial.println(  OCR3A          );
15
}
1
// Timer 1, CTC mode 4, prescaler  64
2
  // Reset
3
  TCCR1B = 0;              
4
  TCCR1A = 0;
5
  TCNT1  = 0;       
6
  TIMSK1 = 0;
7
  // Neukonfiguration 
8
  OCR1A  = (F_CPU * F_TIMER1 / 256UL)-1;
9
  TIMSK1 = _BV(OCIE1A);
10
  TCCR1B = _BV(WGM12) | _BV(CS11) | _BV(CS10);

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.