Forum: Mikrocontroller und Digitale Elektronik STM32 > Encoder Interface


von Jan H. (janiiix3)


Lesenswert?

Hallo Community,

ich bin gerade am verzweifeln ich versuche mit dem Timer 3 und dem 
entsprechenden Encoder Interface meinen Drehencoder auszuwerten.
Die Init. rufe ich wie folgt auf..
1
TIMEREncoderInit( TIM3, TIMER_ENC_MODE_3, 100 );

Die internen PullUps an PB4 / PB5 sind auch aktiviert und auch gemessen.
Mein Enc. sollte also auf fallende Flanken reagieren.
Die beiden ALT Modes für die entsprechenden Pins wurden auch gewählt.
(TIM3_CH1, TIM3_CH2).

Wenn ich jetzt in der while(1) das Zählregister von meinem Timer auf 
gemessene Impulse abfrage kommt gefühlt nur Mist bei raus..
1
    if ( TIM3->CNT > 10 )
2
    {
3
      GPIOTogglePin( GPIOC, PIN_9 );
4
      TIM3->CNT = 0;
5
    }
Bei einem RASTPUNKT geht er direkt in die if Abfrage.

Habe ich etwas falsches initalisiert?!

Hier mal die Init.
1
TIMER_ERROR_CODE_t TIMEREncoderInit( TIM_TypeDef *pTim, TIMER_ENCODER_MODE_t eEncMode, TIMER_ENCODER_EDGES_t eEdge, uint32_t uiMaxCount )
2
{
3
  if ( TIMERHasTimer( pTim ) != TIMER_OK )
4
  {
5
    return TIMER_UNKNOWN;
6
  }
7
8
  pTim->CCMR1 |= ( TIM_CCMR1_CC1S_0 | TIM_CCMR1_CC2S_0 ); // TI1FP1 mapped to TI1, TI2FP2 mapped to TI2
9
  pTim->CCER &= ~( TIM_CCER_CC1NP | TIM_CCER_CC2NP | TIM_CCER_CC1P | TIM_CCER_CC2P );
10
11
12
  switch ( eEdge )
13
  {
14
    case TIMER_ENCODER_FALLING_EDGE:
15
    {
16
      pTim->CCER |= ( TIM_CCER_CC1P | TIM_CCER_CC2P );
17
    }break;
18
19
    case TIMER_ENCODER_RISING_EDGE:
20
    {
21
      // pTim->CCER &= ~( TIM_CCER_CC1NP | TIM_CCER_CC2NP );
22
    }break;
23
24
    case TIMER_ENCODER_BOTH_EDGE:
25
    {
26
      pTim->CCER |= ( TIM_CCER_CC1P | TIM_CCER_CC1NP );
27
      pTim->CCER |= ( TIM_CCER_CC2P | TIM_CCER_CC2NP );
28
    }break;
29
30
    case __TIMER_ENCODER_EDGE_MAX__:
31
    {
32
      return TIMER_ENCODER_EDGE_UNKNOWN;
33
    }break;
34
  }
35
36
37
  switch ( eEncMode )
38
  {
39
    case TIMER_ENC_MODE_1:
40
    {
41
      pTim->SMCR &= ~( TIM_SMCR_SMS_1 );
42
      pTim->SMCR |= ( TIM_SMCR_SMS_0 );
43
    }break;
44
45
    case TIMER_ENC_MODE_2:
46
    {
47
      pTim->SMCR &= ~( TIM_SMCR_SMS_0 );
48
      pTim->SMCR |= ( TIM_SMCR_SMS_1 );
49
    }break;
50
51
    case TIMER_ENC_MODE_3:
52
    {
53
      pTim->SMCR |= ( TIM_SMCR_SMS_0 | TIM_SMCR_SMS_1 );
54
    }break;
55
56
    case __TIMER_ENC_MODE_MAX__:
57
    {
58
      return TIMER_ENC_MODE_UNKNOWN;
59
    }break;
60
  }
61
62
  pTim->ARR = uiMaxCount;
63
64
  return TIMER_OK;
65
}

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


Lesenswert?

Jan H. schrieb:
> TIM3->CNT = 0;
Lass das doch mal weg (denn es ist generell eine schlechte Idee, an 
Zählerwerten herumzufrickeln).

Wenn das erledigt ist, dann startest du das Programm und schreibst dir 
den aktuellen Zählerwert auf. Danach drehst du den Encoder mal 1 
Umdrehungen in die eine Richtung und schreibst dir den Zählerwert auf.

Und dann drehst du den Encoder mal wieder diese 1 Umdrehung zurück und 
schaust, ob der Zähler wieder (in etwa) beim Ausgangswert ankommt.

Und dann drehst du den weiter um 1 Umdrehung zurück und kontrollierst, 
ob der Zähler (in etwa) um gleich viele Schritte in die andere Richtung 
gegangen bist, wie zuvor beim erstmaligen Drehen.

: Bearbeitet durch Moderator
von Jan H. (janiiix3)


Lesenswert?

Lothar M. schrieb:
> Und dann drehst du den weiter um 1 Umdrehung zurück und kontrollierst,
> ob der Zähler (in etwa) um gleich viele Schritte in die andere Richtung
> gegangen bist, wie zuvor beim erstmaligen Drehen.
Ich habe leider noch keine gute DEBUG Möglichkeit.

von Hermann S. (diphtong)


Lesenswert?

Servus,

ich starte den Encoder Timer folgndermaßen:
1
HAL_TIM_Encoder_Start(&htim3, TIM_CHANNEL_ALL);

und hier die init (von CubeIDE erzeeugt):
1
  htim3.Instance = TIM3;
2
  htim3.Init.Prescaler = 0;
3
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
4
  htim3.Init.Period = 65535;
5
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
6
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
7
  sConfig.EncoderMode = TIM_ENCODERMODE_TI12;
8
  sConfig.IC1Polarity = TIM_ICPOLARITY_FALLING;
9
  sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
10
  sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
11
  sConfig.IC1Filter = 0;
12
  sConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
13
  sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
14
  sConfig.IC2Prescaler = TIM_ICPSC_DIV1;
15
  sConfig.IC2Filter = 0;
16
  if (HAL_TIM_Encoder_Init(&htim3, &sConfig) != HAL_OK)
17
  {
18
    Error_Handler();
19
  }
20
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
21
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
22
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
23
  {
24
    Error_Handler();

und dann einfach auslesen mit:
1
encoder = TIM3->CNT;

Gruss

von Hermann S. (diphtong)


Lesenswert?

Jan H. schrieb:

> Ich habe leider noch keine gute DEBUG Möglichkeit.

nimm am Besten ein kleines Display. z. B. so ein SSD1309 OLED...da 
kannst dir alles anzeigen lassen

von Jan H. (janiiix3)


Lesenswert?

Hermann S. schrieb:
> Jan H. schrieb:
>
>> Ich habe leider noch keine gute DEBUG Möglichkeit.
>
> nimm am Besten ein kleines Display. z. B. so ein SSD1309 OLED...da
> kannst dir alles anzeigen lassen

Soweit bin ich noch nicht.
Ich möchte auch keine fertigen Libs bzw. Routinen nehmen sondern alles 
mehr oder weniger selbst erarbeiten und daran lernen.
Nebenbei schreibe ich eine Lib für USART dann ist das ein bisschen 
einfacher.

von Hermann S. (diphtong)


Lesenswert?

Ok, an was bastelst Du wenn ich fragen darf? -Oder ist das einfach nur 
ein Lernprojekt?

Perfekt, dann kannst ja gleich ne neue lib für das OLED schreiben, vll. 
mit einer beseren Schrift und mit Sonderzeichen wie "%" ;-P

von Stefan F. (Gast)


Lesenswert?

Ich kann dir nur empfehlen, als allererstes eine Debug Möglichkeit zu 
schaffen. Sonst tappst du im Dunkeln und verschwendest Unmengen von 
Zeit.

Das Minimum wären Textausgaben auf den TraceSWO Ausgang.
http://stefanfrings.de/stm32/stm32f3.html#traceswo

Hier ein beispiel, wie du printf() für serielle Ausgaben verwenden 
kannst. Das lässt sich ganz einfach mit UART oder TraceSWO kombinieren.
http://stefanfrings.de/stm32/stm32f3.html#newlib

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


Lesenswert?

Jan H. schrieb:
> Ich habe leider noch keine gute DEBUG Möglichkeit.
Du hast "Halt", "Watch" und "Run". Das ist mehr als, die ganzen 
Arduino-Bastler haben.

Zum Debuggen musst du hier erst mal gar nichts tun, sondern eben einfach 
nur den Zähler initialisieren, dann die fast leere Mainloop laufen 
lassen:
1
    while (1) {
2
       counter = TIM3->CNT;
3
    }

Wen du jetzt einen Watch auf den counter setzt, dann siehst du darin bei 
jedem "Halt" den Zählerwert. Und mehr brauchst du zum Analysieren des 
Zählers eigentlich nicht.

Jan H. schrieb:
> ich versuche mit dem Timer 3 und dem
> entsprechenden Encoder Interface meinen Drehencoder auszuwerten.
Du hast aber schon vorneweg mit dem Oszi kontrolliert, ob die Signale an 
den µC-Pins halbwegs brauchbar aussehen?

von MR9000 (Gast)


Lesenswert?

Richtigen Encodermodus? (Quadraturencoder?)
Richtig verbunden? (A/B-Signale, Rastpunkt klingt nach verbundenem 
Indexchannel)

von Jan H. (janiiix3)


Lesenswert?

Hermann S. schrieb:
> Ok, an was bastelst Du wenn ich fragen darf? -Oder ist das einfach
> nur
> ein Lernprojekt?
>
> Perfekt, dann kannst ja gleich ne neue lib für das OLED schreiben, vll.
> mit einer beseren Schrift und mit Sonderzeichen wie "%" ;-P

Ich möchte halt einfach viel lernen über Mikrocontroller und versuche 
jederzeit alles mitzunehmen was geht. Ein LoRa Modul liegt neben mir. 
Bis ich daran gehe muss erstmal die Basis stimmen.

von Jan H. (janiiix3)


Lesenswert?

Stefan ⛄ F. schrieb:
> Ich kann dir nur empfehlen, als allererstes eine Debug Möglichkeit
> zu
> schaffen. Sonst tappst du im Dunkeln und verschwendest Unmengen von
> Zeit.
>
> Das Minimum wären Textausgaben auf den TraceSWO Ausgang.
> http://stefanfrings.de/stm32/stm32f3.html#traceswo
>
> Hier ein beispiel, wie du printf() für serielle Ausgaben verwenden
> kannst. Das lässt sich ganz einfach mit UART oder TraceSWO kombinieren.
> http://stefanfrings.de/stm32/stm32f3.html#newlib

Genau deswegen stelle ich meine Fragen hier. Man lernt immer wieder 
neues und viel dazu. Danke!

von Jan H. (janiiix3)


Lesenswert?

Jan H. schrieb:
>> Das Minimum wären Textausgaben auf den TraceSWO Ausgang.
>> http://stefanfrings.de/stm32/stm32f3.html#traceswo

Kann es sein dieses Feature nicht auf einem "STM32F030xx" verfügbar 
ist?!.

von Jan H. (janiiix3)


Lesenswert?

Lothar M. schrieb:
> Du hast aber schon vorneweg mit dem Oszi kontrolliert, ob die Signale an
> den µC-Pins halbwegs brauchbar aussehen?

Ja die kommen an. Nur habe ich jetzt nicht festgestellt was Phase:A und 
Phase:B ist.

von Stefan F. (Gast)


Lesenswert?

Jan H. schrieb:
> Kann es sein dieses Feature nicht auf einem "STM32F030xx" verfügbar
> ist?!.

Ja, die Cortex M0 haben keinen TraceSWO Ausgang. Da musst du einen UART 
Ausgang nehmen (oder Soft-UART).

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


Lesenswert?

Jan H. schrieb:
> Nur habe ich jetzt nicht festgestellt was Phase:A und Phase:B ist.
Das ist im ersten Augenblick auch mal uninteressant.
Schlimmstenfalls läuft der Zähler halt nicht in die Richtung, die du 
erwartest (vermutlich "rechts drehen = hochzählen"), sondern umgekehrt 
(also "links drehen = hochzählen").

von W.S. (Gast)


Lesenswert?

Jan H. schrieb:
> Nur habe ich jetzt nicht festgestellt was Phase:A und
> Phase:B ist.

Wie das Kind genannt wird, ist eigentlich egal. Wichtig ist nur, daß mit 
dem Signal gezählt wird, was sich im oder beim Rastpunkt NICHT ändert.

W.S.

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.