Forum: Mikrocontroller und Digitale Elektronik STM32F4 Servo PWM


von Moritz M. (avrprogger)


Lesenswert?

Hallo,

ich möchte gerne ein PWM Signal mit einem STM32F4 erzeugen. Das Signal 
soll einen Frequenz von 50Hz haben und eine Puls von 1500µs länge.

Hat jemand vielleicht einen Code-Ausschnitt für mich wo ein Timer 
Initalisiert und gestartet wird? Am besten wenn der Timer auch noch per 
DMA geladen wird.

Moritz

von RP6Conrad (Gast)


Lesenswert?

Bei mein discovery board (STM32F100) lauft das mit Timer 1 in PWM mode 
(hat 4 Channels, damit kan men dan 4 verschiedene Servo-signale 
erzeugen). Timer lauft an 1 MHz (forteiler), zaehlt bis 19999 (= 20ms), 
dan fangt er wieder an. Die 4 channels stellt men dan ein auf 1000 bis 
2000 (= 1 bis 2 ms). Auflosung ist dan 1µs. Code config Timer 1 : (GPIO 
und clock Timer 1 auch noch configurieren !)
1
void Timer_Config(void)
2
{
3
    /* -----------------------------------------------------------------------
4
    TIM1 Configuration: generate 2 PWM signals with 2 different duty cycles:
5
    TIM1CLK = 24 MHz, Prescaler = 23, TIM1 counter clock = 1 MHz
6
    TIM1 ARR Register = 19999=> TIM1 Frequency = TIM1 counter clock/(ARR + 1)
7
    TIM1 Frequency = 50 Hz.
8
    TIM1 Channel1 pulse lenght = TIM1->CCR1 value gives servo between 1000 and 2000 µs
9
    TIM1 Channel4 pulse lenght = TIM1->CCR4 value gives servo between 1000 and 2000 µs
10
  ----------------------------------------------------------------------- */
11
  TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
12
  TIM_OCInitTypeDef  TIM_OCInitStructure;
13
  /* Time base configuration TIM1*/
14
  TIM_TimeBaseStructure.TIM_Period = 19999;//PWM freq. = 1MHz/20000 = 50Hz
15
  TIM_TimeBaseStructure.TIM_Prescaler = 23;// Timer loopt aan 24 MHz/24 = 1MHz
16
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
17
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
18
  TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
19
  /* PWM1 Mode configuration: TIM 1, Channel1 */
20
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
21
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
22
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
23
  TIM_OC1Init(TIM1, &TIM_OCInitStructure);
24
  TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);
25
  /* PWM1 Mode configuration: TIM 1, Channel4 */
26
  TIM_OC4Init(TIM1, &TIM_OCInitStructure);
27
  TIM_OC4PreloadConfig(TIM1, TIM_OCPreload_Enable);
28
}

von Moritz M. (avrprogger)


Lesenswert?

Hallo,

viele Dank für das Beispiel. Hat jemand viellecht noch ein Beispiel für 
STM32F4?

Moritz

von Moritz M. (avrprogger)


Lesenswert?

Hallo,

hat jemand vielleicht einen Kompletten source code, wo ein TIMER 
Initalisiert wird? Weiß jemand wovon der TIMCLK1 abgeleitet wird?

Moritz

von Julian (Gast)


Lesenswert?

Beim F1er gabs in der Firmwarebibliothek Beispiele für alle 
Peripherieeinheiten, beim F4er nicht?

Andersrum wird hier ein Schuh draus: zeige, was du bisher geschafft hast 
und wir helfen dir Fehler zu finden. Für dich was schreiben wird hier 
niemand! Aber zwischen den Zeilen lese ich eine gewisse Unlust zur 
selbstständigen Arbeit heraus...

von Moritz M. (avrprogger)


Lesenswert?

Hallo,

ja ich möchte schon selber etwas programmieren doch leider weiß ich noch 
nichts über die Timer (Deshalb frage ich ja). Am einfachsten für mich 
ist es aus fertigem code zu lernen. Bei der Lib sind auch einige 
Beispiele dabei dabei, allerdings erklärt die nicht woher der Takt der 
Timer kommt, was die verschidenen Vorteile Bedeuten und wozu die gut 
sind usw... .

In den Reference Manual und dem Datasheet werde ich auch nicht schlauer.

Moritz

von Markus K. (markus_k64) Flattr this


Lesenswert?

Hi Moritz

mir ist das Benutzen eines Timers heute erfolgreich mit dem STM32F4 
Board gelungen.

Das folgende Beispiel nutzt TIM4 mit PWM. Das "Ergebnis" wird auf der 
grünen onboard LED ausgegeben. Die LED wird entsprechend heller und 
dunkler.
1
#include "stm32f4xx_conf.h"
2
3
#define MOTORPWMTIMER      TIM4
4
#define MOTORPWMTIMCLOCK    RCC_APB1Periph_TIM4
5
#define MOTORPWMPORTCLOCK    RCC_AHB1Periph_GPIOD
6
#define MOTORPWMAF         GPIO_AF_TIM4
7
#define MOTORPWMPORT      GPIOD
8
#define MOTORPWMBIT        GPIO_Pin_12
9
#define MOTORPWMTIMBIT      GPIO_PinSource12
10
11
12
// Private typedefs ----------------------------------------------------------
13
GPIO_InitTypeDef     GPIO_InitStructureLED;
14
GPIO_InitTypeDef     GPIO_InitStructureTimer;
15
TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
16
TIM_OCInitTypeDef    TIM_OCInitStructure;
17
18
19
// Private variables ---------------------------------------------------------
20
uint32_t TimerCounterClock = 0;
21
uint32_t TimerOutputClock = 0;
22
uint16_t PrescalerValue = 0;
23
uint32_t PulseDurationInMicroSeconds = 0;
24
25
int i;
26
27
28
// the prototypes ------------------------------------------------------------
29
int main(void);
30
31
// Timer init for PWM
32
void TimerInit(void);
33
34
void Delay(__IO uint32_t nCount);
35
36
37
int main(void)
38
{
39
  /*!< At this stage the microcontroller clock setting is already configured, 
40
     this is done through SystemInit() function which is called from startup
41
     file (startup_stm32f4xx.s) before to branch to application main.
42
     To reconfigure the default setting of SystemInit() function, refer to
43
      system_stm32f4xx.c file
44
  */
45
46
  // /dev/tty.usbserial-A900J1T0
47
48
  // call my new USART init
49
  usartInit();
50
51
  
52
  // call timer init for PWM
53
  TimerInit();
54
55
56
  // Timer base configuration
57
  //   Don't know why, but this code has to be here (not in a seperate method)
58
  TIM_TimeBaseStructure.TIM_Period = (uint16_t) (TimerCounterClock / TimerOutputClock);
59
  TIM_TimeBaseStructure.TIM_Prescaler = (uint16_t) ((SystemCoreClock /2) / TimerCounterClock) - 1;
60
  TIM_TimeBaseStructure.TIM_ClockDivision = 0;
61
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
62
63
  // basic timer init
64
  TIM_TimeBaseInit(MOTORPWMTIMER, &TIM_TimeBaseStructure);
65
66
  // configure PWM mode and duration
67
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
68
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
69
  TIM_OCInitStructure.TIM_Pulse = PulseDurationInMicroSeconds; // set the duty cycle / pulse here!
70
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
71
  TIM_OC1Init(MOTORPWMTIMER, &TIM_OCInitStructure);
72
  TIM_OC1PreloadConfig(MOTORPWMTIMER, TIM_OCPreload_Enable);
73
74
  // preload timer config
75
  TIM_ARRPreloadConfig(MOTORPWMTIMER, ENABLE);
76
77
  // enable timer / counter
78
  TIM_Cmd(MOTORPWMTIMER, ENABLE);
79
80
81
  //
82
  //  motor pwm test ! ! !
83
  //
84
  while(1)
85
  {
86
    for (i=1; i<70; i++)
87
    {
88
      Delay(0x03FFFF);
89
      TIM_Cmd(MOTORPWMTIMER, DISABLE);
90
91
      PulseDurationInMicroSeconds = i;
92
93
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
94
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
95
      TIM_OCInitStructure.TIM_Pulse = PulseDurationInMicroSeconds; // set the duty cycle / pulse here!
96
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
97
      TIM_OC1Init(MOTORPWMTIMER, &TIM_OCInitStructure);
98
      TIM_OC1PreloadConfig(MOTORPWMTIMER, TIM_OCPreload_Enable);
99
100
      TIM_ARRPreloadConfig(MOTORPWMTIMER, ENABLE);
101
102
      TIM_Cmd(MOTORPWMTIMER, ENABLE);
103
    }
104
105
    for (i=70; i>2; i--)
106
    {
107
      Delay(0x03FFFF);
108
      TIM_Cmd(MOTORPWMTIMER, DISABLE);
109
110
      PulseDurationInMicroSeconds = i;
111
112
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
113
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
114
      TIM_OCInitStructure.TIM_Pulse = PulseDurationInMicroSeconds; // set the duty cycle / pulse here!
115
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
116
      TIM_OC1Init(MOTORPWMTIMER, &TIM_OCInitStructure);
117
      TIM_OC1PreloadConfig(MOTORPWMTIMER, TIM_OCPreload_Enable);
118
119
      TIM_ARRPreloadConfig(MOTORPWMTIMER, ENABLE);
120
121
      TIM_Cmd(MOTORPWMTIMER, ENABLE);
122
    }
123
  }
124
}
125
126
127
/**
128
  * @brief  Configure the timer for PWM.
129
  * @param  None
130
  * @retval None
131
  */
132
void TimerInit(void)
133
{
134
  // set timer frequencies
135
  TimerCounterClock = 1000000; //  1 MHz
136
  TimerOutputClock = 10000;    // 10 kHz = 100 µs period
137
138
  // set pulse duration in mili seconds (HIGH time)
139
  // can be up to from 0 to 99 (due to a TimerOutputClock of 10 kHz)
140
  PulseDurationInMicroSeconds = 50;
141
142
  // Timer clock enable
143
  RCC_APB1PeriphClockCmd(MOTORPWMTIMCLOCK, ENABLE);
144
145
  // Port clock enable
146
  RCC_AHB1PeriphClockCmd(MOTORPWMPORTCLOCK, ENABLE);
147
148
  // Set PWM Port, Pin and method
149
  GPIO_InitStructureTimer.GPIO_Pin = MOTORPWMBIT;
150
  GPIO_InitStructureTimer.GPIO_Mode = GPIO_Mode_AF;
151
  GPIO_InitStructureTimer.GPIO_Speed = GPIO_Speed_100MHz;
152
  GPIO_InitStructureTimer.GPIO_OType = GPIO_OType_PP;
153
  GPIO_InitStructureTimer.GPIO_PuPd = GPIO_PuPd_UP ;
154
  GPIO_Init(MOTORPWMPORT, &GPIO_InitStructureTimer); 
155
156
  // Connect TIM pin to AF
157
  GPIO_PinAFConfig(MOTORPWMPORT, MOTORPWMTIMBIT, MOTORPWMAF);
158
}
159
160
161
/**
162
  * @brief  Delay Function.
163
  * @param  nCount:specifies the Delay time length.
164
  * @retval None
165
  */
166
void Delay(__IO uint32_t nCount)
167
{
168
  while(nCount--)
169
  {
170
  }
171
}

Ich hoffe, ich habe nichts vergessen hier rein zu kopieren...
Gib mir Bescheid, wenn es nicht läuft. Wie du am englischen Kommentar 
siehst, funktioniert der Code innerhalb der main Methode komischerweise 
nicht, wenn ich ihn in eine separate Funktion schiebe. Warum habe ich 
noch nicht herausgefunden...

Das Beispiel aber läuft soweit gut. Das Delay muss natürlich auch nicht 
sein. Nur der Vollständigkeit halber.

Gruß,

Markus

--
http://www.robotiklabor.de
http://www.direcs.de

von Markus K. (markus_k64) Flattr this


Lesenswert?

PS.:

Wenn nicht Channel 1 des Timers verwendet wird, müssen die Zeilen
1
      TIM_OC1Init(MOTORPWMTIMER, &TIM_OCInitStructure);
2
      TIM_OC1PreloadConfig(MOTORPWMTIMER, TIM_OCPreload_Enable);

natürlich angepasst werden. Für Channel 2 dann z.B.
1
      TIM_OC2Init(MOTORPWMTIMER, &TIM_OCInitStructure);
2
      TIM_OC2PreloadConfig(MOTORPWMTIMER, TIM_OCPreload_Enable);

Und so weiter...

von dmitry (Gast)


Lesenswert?

small remark regarding while loop markus_k64.

it can be as simple as :

1
 
2
while ( 1 )
3
  {
4
    for (i= 1 ; i< 70 ; i++)
5
    {
6
      Delay( 0x03FFFF );
7
8
      PulseDurationInMicroSeconds = i;
9
10
      TIM_SetCompare1(MOTORPWMTIMER, PulseDurationInMicroSeconds);
11
    }
12
13
    for (i= 70 ; i> 2 ; i--)
14
    {
15
      Delay( 0x03FFFF );
16
17
      PulseDurationInMicroSeconds = i;
18
19
      TIM_SetCompare1(MOTORPWMTIMER, PulseDurationInMicroSeconds);
20
    }
21
  }

von lee dyche (Gast)


Lesenswert?


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.