Forum: Mikrocontroller und Digitale Elektronik STM32F103RB, Input capture und Encoder kollidieren


von Werner D. (werner_d74)


Lesenswert?

Irgendetwas verstehe ich offensichtlich nicht an der STM32F103 
Beschaltung.

Ich habe am PA0 und PA1 den Encoder aktiviert, TIM2_CH1 & 2. 
Funktioniert, zählt schön hoch und runter.

Am Pin PA2 möchte ich ein PWM Signal zählen, TIM2_CH3. Das funktioniert 
auch, aber nur wenn ich den obigen Encoder abschalte. Nur warum geht 
nicht beides?

Im main.c rufe ich diese Init Prozeduren auf, zuerst die vom Tim2_Ch3 
counter und dann die vom Encoder.


Ich kann doch CH1&2 für eine Sache verwenden und CH3&4 für eine Andere, 
oder?

Danke im Voraus!


PWM Zähler
1
void P_ICPWM_InitIO(void)
2
{
3
  GPIO_InitTypeDef GPIO_InitStructure;
4
5
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
6
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
7
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
8
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
9
  GPIO_Init(GPIOA, &GPIO_InitStructure); 
10
}
11
12
void P_ICPWM_InitTIM(void)
13
{
14
  TIM_ICInitTypeDef  TIM_ICInitStructure;
15
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
16
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
17
  TIM_TimeBaseStructure.TIM_Period = 0xFFFF; /* overflow after ~65 ms */
18
  TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1; /* counter increments every 1 µs */
19
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
20
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); /* initialize timer */
21
  TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; /* trigger capture event on rising edge */
22
  TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; /* input pins directly connected */
23
  TIM_ICInitStructure.TIM_ICFilter = 0x3;  /* input must be stable for 8 ticks */
24
  TIM_ICInitStructure.TIM_Channel = TIM_Channel_3; /* configure channel3 (PA2) */
25
  TIM_ICInit(TIM2, &TIM_ICInitStructure);  /* configure input capture */
26
  TIM_Cmd(TIM2, ENABLE); /* start timer */
27
}
28
29
void P_ICPWM_InitNVIC(void)
30
{
31
  NVIC_InitTypeDef NVIC_InitStructure;
32
33
  // NVIC init
34
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); /* 1 bit for pre-emption priority, 3 bits for subpriority */
35
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
36
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
37
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
38
  NVIC_Init(&NVIC_InitStructure);
39
  NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
40
  NVIC_Init(&NVIC_InitStructure);
41
42
  TIM_ITConfig(TIM2, TIM_IT_CC3, ENABLE); /* enable CC-interrupts */
43
}
44
45
//--------------------------------------------------------------
46
// ISR of Timer2
47
//--------------------------------------------------------------
48
void TIM2_IRQHandler(void)
49
{
50
  static uint16_t CCR3_rise;
51
  static uint16_t CCR3_falling;
52
53
  if (TIM_GetITStatus(TIM2, TIM_IT_CC3) == SET) {
54
    if (timing[6][0] < 1 || timing[6][0] >= MAX_TIMING_SAMPLES) {
55
      timing[6][0] = 1;
56
    }
57
    timing[6][ timing[6][0]] = TIM2->CCR3;
58
    timing[6][0]++;
59
    if (TIM2->CCER & TIM_CCER_CC3P) {    /* captured falling edge? */
60
      CCR3_falling = TIM2->CCR3;
61
      ICPWM_Var[6].duty = CCR3_falling - CCR3_rise;  /* Get the Input Capture value, calculate high pulse length */
62
      ICPWM_Var[6].last_update = getCounter();
63
      TIM2->CCER &= ~TIM_CCER_CC3P;    /* select rising edge as capture event */
64
    } else {                  /* captured rising edge? */
65
      CCR3_rise = TIM2->CCR3;        /* Get the Input Capture value */
66
      TIM2->CCER |= TIM_CCER_CC3P;    /* select falling edge as capture event */
67
      ICPWM_Var[6].pause  = CCR3_rise - CCR3_falling;
68
    }
69
    TIM_ClearITPendingBit(TIM2, TIM_IT_CC3);
70
  }
71
}


Encoder Init
1
void P_ENCODER_InitIO(void)
2
{
3
  GPIO_InitTypeDef GPIO_InitStructure;
4
5
  // Clock Enable
6
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
7
8
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;
9
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
10
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
11
  GPIO_Init(GPIOA, &GPIO_InitStructure);
12
}
13
14
15
void P_ENCODER_InitTIM()
16
{
17
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
18
  TIM_ICInitTypeDef TIM_ICInitStructure;
19
20
  TIM_DeInit(TIM2);
21
  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
22
23
  // Clock enable
24
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
25
26
  TIM_TimeBaseStructure.TIM_Period = 0xFFFF;
27
  TIM_TimeBaseStructure.TIM_Prescaler = 0;
28
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
29
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
30
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
31
32
  TIM_ICStructInit(&TIM_ICInitStructure);
33
  TIM_ICInitStructure.TIM_ICFilter = 0x00;
34
  TIM_ICInit(TIM2, &TIM_ICInitStructure);
35
36
  TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
37
38
  TIM2->CNT = 0;
39
40
  // Timer enable
41
  TIM_Cmd(TIM2, ENABLE);
42
}

von chris (Gast)


Lesenswert?

Werner D. schrieb:
> Ich kann doch CH1&2 für eine Sache verwenden und CH3&4 für eine Andere,
> oder?

Nein, wie soll das auch gehen, wenn du beides mal Timer2 verwendest?
Im Encoder Modus wird das Timerregister von den Encodersignalen rauf- 
oder runtergezähzl.
Im "normalen" Modus wird es über den mittels Prescaler vom Systemtakt 
abgeleiteten Takt hochgezählt.
Da es nur ein Timer-Register gibt, kann natürlich nicht beides 
gleichzeitig gehen.
Du musst für dein Input Capture einen zweiten Timer benutzen.

von Werner D. (werner_d74)


Lesenswert?

Ich Esel. Natürlich, alle 4 Kanäle haben ja nur einen Timer-Wert. Also 
entweder den vom PWM oder den vom Encoder, wie Du sagst.

Mist, es müssen genau die Pins PA0, PA1 und PA2 sein. Da ist kein 
Remapping möglich. Mein Problem.

Danke!

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


Lesenswert?

TIM9_CH1 sollte sich auf PA2 remappen lassen. Ich bin allerdings im 
Moment überfragt, ob deine MC Version diesen Timer überhaupt hat.

von Roland (Gast)


Lesenswert?

Hallo Werner,

ich verwende den gleichen Controller und habe einen Encoder auf die 
Ports PA6 und PA7 angeschlossen. Als Timer verwende ich dann TIM3. Beim 
Auslesen bekomme ich aber nur 0 und 1 ! Habe ich was vergessen ?
Habe auch mal Deine EncoderInitIO und Encoder_InitTim kopiert (und die 
Ports sowie TIM auf TIM3 geändert), doch bei mir zählt er nur 0 und 1.

Grüße
Roland

von Werner D. (werner_d74)


Lesenswert?

Ich nehme an die verwendest TIM3 nicht für Anderes und Du hast auch 
keine Remapping Funktion auf PB4,5? Denn dort kann man TIM3 CH1/2 auch 
verwenden...

von Roland (Gast)


Lesenswert?

Ne, TIM3 ist nur für den Encoder gedacht und ein Remapping mache ich 
auch nicht.
Zählen tut er ja, aber nur 0 und 1.

von Werner D. (werner_d74)


Lesenswert?

Fällt mir nichts ein. Magst Du mal den kompletten Source Code posten?

von Roland (Gast)


Lesenswert?

Hier die main.c

/**************************************************************
**  MINI STM32
**  V: 0.1
**  2015.04.07
***************************************************************/
// Pinbelegung:
// KEY 1:      PA0
// KEY 2:      PA1
// LED 1:      PA2
// LED 2:      PA3
//
// ** USART **
// USART1 Tx      PA9
// USART1 Rx      PA10
//
// ** LCD **
// LCD_CS        PC 8
// LCD_RS      PC 9
// LCD_WR        PC 10
// LCD_RD      PC 11

/* Includes 
------------------------------------------------------------------*/
#include "stm32f10x.h"
#include "hardware_conf.h"
#include "USART.h"
#include "ili932x_conf.h"
#include <stdio.h>


/* Private define 
------------------------------------------------------------*/
/* LED */
#define LED1    PAout(2)
#define LED2    PAout(3)

/* KEY */
#define KEY1    PAin(0)
#define KEY2    PAin(1)

uint8_t AsciiBuff[5];
static __IO uint32_t TimingDelay;

void GPIO_Configuration(void);
void NVIC_Configuration(void);
void TIM2_Configuration(void);
void TIM3_Configuration(void);
uint8_t KEY_Scan(void);
void Delay(__IO uint32_t nTime);
void Delay_Ms(uint16_t time);
void DelayNS(u16 time);
void HexToASCII(uint16_t data);

volatile char Temp=0;
volatile char Frame_Write_Status=0;
volatile char Frame_Writed=0;

/*********************************************************************** 
******
** main
************************************************************************ 
*****/
int main(void)
{
  uint8_t key;
  uint32_t encoder=0;

  SystemInit();
  while(SysTick_Config(SystemFrequency / 1000));
  GPIO_Configuration();
  TIM3_Configuration();
  USART_Configuration();

  LCD_Init();
  LCD_Clear(BLACK);

  USART_Send_Str(" *** STM32 Test *** \n");
  LCD_Clear(BLACK);
  WriteString(40,0,"STM32 Demo !      (40,0)",WHITE);
  WriteString(0,160, "Encoder: ",WHITE);

  LED2=1;

  while(1)
  {

    key=KEY_Scan();
    encoder = TIM_GetCounter(TIM3);
    HexToASCII(encoder);
    WriteString(70,160, (uint8_t*)AsciiBuff,WHITE);

    if(key==1)  //KEY1 pressed
    {
      WriteString(150,220,"1 LED-1 ON ",GREEN);
      USART_Send_Str(" *** LED-1 ON  *** \n");
      LED1 = 1;
      // Timer enable
      TIM_Cmd(TIM3, ENABLE);
    }

    if(key==2)  //KEY2 pressed
    {
      WriteString(150,220,"2 LED-1 OFF",RED);
      USART_Send_Str(" *** LED-1 OFF *** \n");
      LED1 = 0;
      // Timer disable
      TIM_Cmd(TIM3, DISABLE);
    }
  }
}

/*********************************************************************** 
******
** GPIO_Configuration
************************************************************************ 
*****/
void GPIO_Configuration(void)
{
  GPIO_InitTypeDef GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA
                                               | RCC_APB2Periph_GPIOB
                                               | RCC_APB2Periph_GPIOC
                                               | RCC_APB2Periph_GPIOD
                                               | RCC_APB2Periph_AFIO, 
ENABLE);

  //RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);      // TIM3 
für Encoder

  /* Configure Encoder (PA6, PA7) 
**************************************/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
  //GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* Configure IO connected to LED1, LED2 *********************/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2 | GPIO_Pin_3;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  /* Configure IO connected to KEY1, KEY2 *********************/
  GPIO_InitStructure.GPIO_Pin = KEY1 | KEY2;
   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  /*Configure USART1 Tx (PA9) as alternate function push-pull*/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  /*Configure USART1 Rx (PA10) as input floating*/
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

}

/*********************************************************************** 
******
** Name: TIM3_Configuration
************************************************************************ 
*****/
void TIM3_Configuration(void)
{
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  TIM_ICInitTypeDef TIM_ICInitStructure;

  TIM_DeInit(TIM3);
  TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);

  // Clock enable
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);

  TIM_TimeBaseStructure.TIM_Period = 0x000f;
  TIM_TimeBaseStructure.TIM_Prescaler = 0;
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
  TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);

  TIM_ICStructInit(&TIM_ICInitStructure);
  TIM_ICInitStructure.TIM_ICFilter = 0x00;
  TIM_ICInit(TIM3, &TIM_ICInitStructure);

  TIM_EncoderInterfaceConfig(TIM3, TIM_EncoderMode_TI12, 
TIM_ICPolarity_Rising, TIM_ICPolarity_Falling);

  TIM3->CNT = 0;
}

/*********************************************************************** 
******
** Delay
************************************************************************ 
*****/
void Delay(__IO uint32_t nTime)
{
  TimingDelay = nTime;

  while(TimingDelay != 0);
}

/*********************************************************************** 
******
** TimingDelay
************************************************************************ 
*****/
void TimingDelay_Decrement(void)
{
  if (TimingDelay != 0x00)
  {
    TimingDelay--;
  }
}

/*********************************************************************** 
******
** Delay_Ms
************************************************************************ 
*****/
void Delay_Ms(uint16_t time)
{
  uint16_t i,j;
  for(i=0;i<time;i++)
    for(j=0;j<10260;j++);
}

/*********************************************************************** 
******
** KEY_Scan
************************************************************************ 
*****/
u8 KEY_Scan(void)
{
  static u8 KEY_UP=1;
  if(KEY_UP&&(KEY1==0||KEY2==0))
  {
    Delay(10);
    KEY_UP=0;
    if(KEY1==0)return 1;
    else if(KEY2==0)return 2;
  }
  else

  if(KEY1==1&&KEY2==1)KEY_UP=1;
  return 0;
}

/*********************************************************************** 
******
** HexToASCII
************************************************************************ 
*****/
void HexToASCII(uint16_t data)
{
  AsciiBuff[0] = data/1000%10 + 0x30;
  AsciiBuff[1] = data/100%10 + 0x30;
  AsciiBuff[2] = data/10%10 + 0x30;
  AsciiBuff[3] = data%10 + 0x30;
  AsciiBuff[4] = 0;
}

von Michael W. (Gast)


Lesenswert?

Looooiiiiiteee!!! Was ist eigentlich an diesem Satz so schwer zu 
verstehen?

> Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

von Roland (Gast)


Lesenswert?

Hallo zusammen,

habe nun in der TIM3-Config folgendes geändert:

  TIM_TimeBaseStructure.TIM_Period = 14;
  TIM_TimeBaseStructure.TIM_Prescaler = 3;
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;


Nun zählt der Counter auf 14 nach jedem 3. Schritt, aber nur immer 
aufwärts.
Wie muss ich den TIM3 konfigurieren, dass er auf und ab zählt ?

Grüße
Roland

von Werner D. (werner_d74)


Lesenswert?

Ich nehme an das bis 14 gezählt wird und alle 3 Schritte, ist klar 
warum? Schließlich hast Du das mit Period=14 und PreScalter=3 so 
eingestellt.

Zu Deiner Frage:
TIM_EncoderInterfaceConfig(TIM2, TIM_EncoderMode_TI12, 
TIM_ICPolarity_Rising, TIM_ICPolarity_Rising);
macht das. Der zweite Parameter mit dem Wert TIM_EncoderMode_TI12 sagt 
dass zwei Eingänge verwendet werden sollen, somit wird hoch/runter 
gezählt.

von Roland (Gast)


Lesenswert?

Hallo Werner,

danke für die Erläuterung.
Mein Problem ist, dass nur in eine Richtung gezählt wird.
Für meine Steuerung brauche ich aber von 0 - 14, es soll also rauf und 
runter gezählt werden.

Habe ich da was vergessen ?

von Werner D. (werner_d74)


Lesenswert?

Wie gesagt, dieser TIM_EncoderMode_TI12 Wert macht das. Wenn es nicht 
funktioniert, dann scheint kein Signal von einem der beiden Anschlüsse 
an den Counter zu kommen. Kann alles sein, von Lötstelle über den GPIOs 
nicht richtig konfiguriert bis zu dem Fall dass eine Spannungspitze den 
Pin im MCU verschmort hat.

Ich würde als nächstes beide Pins als normalen Input konfigurieren und 
deren Werte ausgeben. Bekommst Du von beiden ein High/Low? Wenn ja, dann 
ist die Hardware in Ordnung und es muss etwas in Code sein.

Übrigens, mir hat das hier geholfen:
http://www.diller-technologies.de/stm32.html#timer_encoder

von Roland (Gast)


Lesenswert?

Hallo Werner,

hab nun den TIM4 am Encoder angeschlossen (PB6 und PB7) und nun zählt er 
rauf und runter, so wie er soll.
Danke für die Hilfe und den Tipp mit Diller, ein sehr gutes Tutorial !!!

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.