Forum: Mikrocontroller und Digitale Elektronik STM32 Servoansteuerung PWM


von Kerstin M. (kerstin)


Lesenswert?

Hallo,

bin neu hier und möchte eine PWM
mit Hilfe des TIM1 Kanal2 entwickeln.

Ich besitze das IAR STM32-SK Board mit dem J-Link Debugger.
Laut mitgeliefertem Schaltplan sitzt der TIM_CH2 auf Pin A9.
Meine erste Frage. Wie gebe ich den Pin korrekt an?
1
void main(void)
2
{
3
  GPIO_InitTypeDef          GPIO_InitStructure;
4
  TIM_TimeBaseInitTypeDef   TIM1_TimeBaseInitStruct;
5
  TIM_OCInitTypeDef         TIM_OCInitStructure;
6
  
7
  SystemInit();
8
9
  /* Set the Vector Table base location at 0x20000000 */
10
  NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
11
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);
12
13
  // Enable GPIO clock and release reset
14
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA |
15
                         RCC_APB2Periph_AFIO,
16
                         ENABLE);
17
  
18
  // Timer1 Init
19
  // Enable Timer1 clock and release reset
20
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
21
  RCC_APB2PeriphResetCmd(RCC_APB2Periph_TIM1,DISABLE);
22
  
23
  // Setup 
24
  GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_9;
25
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
26
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; 
27
  GPIO_Init(GPIOA, &GPIO_InitStructure);

Das war meine Initialisierun der Main Methode.
Danach stelle ich die Timer ein.
Ich möchte damit einen Modellbau Servo ansteuern.
Das heisst: 0.5 bis 2.5ms variable Pulsweite
und eine Periodendauer von 20ms.
1
  // Set timer period 1.5 ms
2
  TIM1_TimeBaseInitStruct.TIM_Prescaler = 720;  // 720 = 10us resolution
3
  TIM1_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up;
4
  TIM1_TimeBaseInitStruct.TIM_Period = 150;  // 10000 = 100 ms  200 = 2ms  50 = 0.5ms
5
  TIM1_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1;
6
  TIM1_TimeBaseInitStruct.TIM_RepetitionCounter = 0;
7
  TIM_TimeBaseInit(TIM1,&TIM1_TimeBaseInitStruct);
8
  
9
  //TIM_OCStructInit( &TIM_OCInitStruct );
10
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
11
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
12
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
13
  TIM_OCInitStructure.TIM_Pulse = 500;
14
  TIM_OC1Init(TIM1, &TIM_OCInitStructure);
15
 
16
  // TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
17
  TIM_Cmd( TIM1, ENABLE );
18
  
19
  //PWM1 Mode configuration: TIM 1, Channel2
20
  TIM_OC2Init(TIM1, &TIM_OCInitStructure);
21
  TIM_OC2PreloadConfig(TIM1, TIM_OCPreload_Enable);
22
  
23
  while(1)
24
  {
25
    
26
  }
27
}

Nun funktioniert aber die PWM aber nicht.
Ich bekomme kein Signal.
Was mache ich falsch.
Wie kann ich während der Laufzeit die Pulsweite ändern?

Wäre echt lieb wenn mir von euch jemand helfen könnte.

lg Kerstin.

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Hi, ich habe gerade keine Muße deinen Code zu analysieren, aber ich kann 
dir eben meinen funktionierenden Code hinklatschen zum Selbststudium:
1
// TimeBase
2
TIM_TimeBaseInitTypeDef timBase;
3
4
TIM_TimeBaseStructInit (&timBase);
5
timBase.TIM_Prescaler = ((SystemCoreClock / 2 ) / 1000000)-1;
6
timBase.TIM_ClockDivision = TIM_CKD_DIV1;
7
timBase.TIM_CounterMode = TIM_CounterMode_Up;
8
timBase.TIM_Period = 20000;
9
TIM_TimeBaseInit (TIM4, &timBase);
10
TIM_ARRPreloadConfig (TIM4, ENABLE);
11
12
// Update registers
13
TIM4->EGR |= (1 << TIM_EGR_UG);
14
15
// Output compare match
16
TIM_OCInitTypeDef oc;
17
TIM_OCStructInit (&oc);
18
19
oc.TIM_OCIdleState = TIM_OCIdleState_Reset;
20
oc.TIM_OCNIdleState = TIM_OCNIdleState_Set;
21
oc.TIM_OCMode = TIM_OCMode_PWM1;
22
oc.TIM_OCPolarity = TIM_OCPolarity_High;
23
oc.TIM_OutputState = TIM_OutputState_Enable;
24
oc.TIM_Pulse = 1500; // Initiale Pulsweite in Millisekunden
25
26
TIM_OC1Init (TIM4, &oc);
27
TIM_OC1PreloadConfig (TIM4, TIM_OCPreload_Enable);
28
29
TIM_BDTRInitTypeDef bdtr;
30
TIM_BDTRStructInit (&bdtr);
31
bdtr.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable;
32
TIM_BDTRConfig (TIM4, &bdtr);
33
34
// Start the timer
35
TIM_Cmd (TIM4, ENABLE);
36
37
// Configure GPIO Pin
38
RCC_AHB1PeriphClockCmd(RCC_AHB1ENR_GPIODEN, ENABLE);
39
GPIO_InitTypeDef GPIO_InitStructure;
40
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
41
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
42
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
43
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
44
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
45
GPIO_Init(GPIOD, &GPIO_InitStructure);
46
GPIO_PinAFConfig (GPIOD, GPIO_PinSource12, GPIO_AF_TIM4);
47
48
// Ändern der Pulsweite:
49
TIM_SetCompare1 (TIM4, 1500); // Pulsweite in Millisekunden
Bei der GPIO-Konfiguration muss man natürlich den richtigen Pin 
erwischen, bei meinem STM32F4407VG ist das PD12. Herausfinden kann man 
den richtigen Pin aus der "Alternate function mapping" aus dem 
Datenblatt.

von Kerstin M. (kerstin)


Lesenswert?

Danke für den Code. Beantwortet nur nicht meine Frage.
Wie ich die einzelnen Kanäle der Timer ansprechen kann...

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Indem du diesen Abschnitt
1
// Output compare match
2
TIM_OCInitTypeDef oc;
3
TIM_OCStructInit (&oc);
4
5
oc.TIM_OCIdleState = TIM_OCIdleState_Reset;
6
oc.TIM_OCNIdleState = TIM_OCNIdleState_Set;
7
oc.TIM_OCMode = TIM_OCMode_PWM1;
8
oc.TIM_OCPolarity = TIM_OCPolarity_High;
9
oc.TIM_OutputState = TIM_OutputState_Enable;
10
oc.TIM_Pulse = 1500; // Initiale Pulsweite in Millisekunden
11
12
TIM_OC1Init (TIM4, &oc);
13
TIM_OC1PreloadConfig (TIM4, TIM_OCPreload_Enable);
Für jeden der gewünschten, max. 4 Channels, 1x ausführst. Du musst dann 
das OC1* durch OC2, etc. ersetzen.
Gleiches gilt für:
1
TIM_SetCompare1 (TIM4, 1500); // Pulsweite in Millisekunden

von Kerstin M. (kerstin)


Lesenswert?

Ah prima, danke Dir!
Nun noch zwei weitere Fragen dann werd ich es aufs neue probieren.

Was machen diese 2 Zeilen Code?
1
// Update registers
2
TIM4->EGR |= (1 << TIM_EGR_UG);
1
// Configure GPIO Pin
2
RCC_AHB1PeriphClockCmd(RCC_AHB1ENR_GPIODEN, ENABLE);

lg

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Kerstin M. schrieb:
1
TIM4->EGR |= (1 << TIM_EGR_UG);
Das updatet die Counter-Register und Flags. Das steht im übrigen auch im 
Datenblatt...
1
RCC_AHB1PeriphClockCmd(RCC_AHB1ENR_GPIODEN, ENABLE);
Das schaltet die Clock für den GPIOD Port ein, damit der überhaupt 
irgendwas macht.

von Kerstin M. (kerstin)


Lesenswert?

Verstehe ich das richtig. Ich muss den Timer1 Kanal2 immer auf einen 
Port mappen?

von holger (Gast)


Lesenswert?

>Verstehe ich das richtig. Ich muss den Timer1 Kanal2 immer auf einen
>Port mappen?

Nö.

von Kerstin M. (kerstin)


Lesenswert?

OK vielen Dank an alle habs hingebracht!

von holger (Gast)


Lesenswert?

Versuch doch mal das:

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, 
ENABLE);

von Kerstin M. (kerstin)


Lesenswert?

Nun noch ne Frage zur Änderung der Pulsweite während der Laufzeit.

In der While Schleife habe ich nun den Befehl:

TIM_SetCompare1 (TIM1, 155);

ausgeführt, der meine Pulsweite von 140ms auf den Wert 155 ändern 
sollte.
dies funktioniert leider nicht.

Jemand eine Idee?

lg

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Oh, sorry, ich habe mich vertippt, es handelt sich um Mikrosekunden, 
nicht Millisekunden... d.h. der sinnvolle Bereich liegt zwischen 1000 
und 2000.

von Kerstin M. (kerstin)


Lesenswert?

Kein Problem habs schon kapiert.
Hab nun alles so eingebaut.

Wenn ich das Signal des RC-Empfängers mit angeschlossenem Servo in 
MITTELSTELLUNG messe ist die Periodendauer 22ms lang und hat eine
Pulsweite von 1,48ms

Wenn ich dies mit dem Microcontroller nachahme
habe ich zwar auf dem DSO das gleiche Bild, jedoch fährt der
Servo immer an den Anschlag....

Wieso?

von holger (Gast)


Lesenswert?

>Wenn ich dies mit dem Microcontroller nachahme
>habe ich zwar auf dem DSO das gleiche Bild, jedoch fährt der
>Servo immer an den Anschlag....

Vieleicht mag der Servo ja keine 3.3V sondern möchte
5V haben.

von Kerstin M. (kerstin)


Lesenswert?

War ein Masse Problem ;-)
Nun funktioniert blos noch das ändern der Pulsweite zur Laufzeit nicht?

lg

von Niklas G. (erlkoenig) Benutzerseite


Lesenswert?

Versuch mal
// Update registers
TIM4->EGR |= (1 << TIM_EGR_UG);
nach dem Ändern des Werts durchzuführen

von Jan H. (jan_h74) Flattr this


Lesenswert?

Ich schreibe diect in das register : TIM4->CCR1=1500; Jetzt soll die 
Pulswweite von TIM4 Channel 1 1500 µs sein.

von Kerstin M. (kerstin)


Lesenswert?

Vielen Dank für alles!!!! funktioniert nun super

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.