Hey zusammen, ich hab mal eine kurze Verständnisfrage zum STM32F4 Discovery Board. Ich möchte gerne ein Ferngesteuerten Auto bauen bei welchem es einen Antriebsmotor und einen Servomotor zur Lenkung gibt. Daher benötige ich zwei PWM Signale an zwei unterschiedlichen Pins. Um den Antriebsmotor nicht surren zu lassen wäre es ideal ihn mit einer höheren Frequenz als den Servo zu betreiben. Darum meine Frage: Ist es generell bei dem Disco Board möglich zwei PWM Signale mit unterschiedlicher Frequenz zu erzeugen? Wenn ja muss man bei der Initialisierung irgendetwas besonderes beachten? Z.B. TIM3 mit 50 Hz und 20 ms Periode und TIM4 mit 10kHz und 100 µs Periode (Werte als Beispiel angenommen) Hab bisher leider nur Beispiele gefunden, welche mit einem Timer das selbe PWM Signal auf mehrere Pins ausgeben. Auch im RefMan hab ich bisher nichts passendes gefunden. Über eine Antwort wäre ich sehr dankbar. Gruß Michael
Das geht - du musst dir nur freie Pins suchen. PA1 z.b. kann auf Timer2 Channel 2 gemappt werden und PA2 auf Timer5 Channel 3. Wenn die die Pins gemappt hast, initialisierst du die beiden Timer per Period auf die gewünschte Wiederholfrequenz und dann den gewünschten Channel auf PWM.
Wie schon von Matthias geschrieben geht das. Unterschiedliche PWM Frequenzen sind aber nur mit unterschiedlichen Timern möglich. Wenn du mehrere Channel eines Timers nutzt, haben die auch die gleiche Frequenz.
Hey vielen Dank für eure Antworten. Dann habe ich wohl einen Fehler im Code den ich bereinigen muss. Hab jetzt mal beide PWM's auf die GPIOs gelegt, welche Matthias vorgeschlagen hat. Leider tut sich bei meinen Motoren immer noch nichts. Anbei hab ich mal den Code gepostet. Ziel ist es einen Servo und einen DC Motor zu betreiben um das Fahrzeug zu steuern. Vielleicht könnt ihr ja nochmal über den Code schauen und mir evtl Verbesserungsvorschläge mitteilen. Gruß Michi
1 | // Init der GPIO's
|
2 | |
3 | void InitGPIO (void) |
4 | {
|
5 | // GPIO für PWMServo (PA1)
|
6 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); |
7 | |
8 | GPIO_InitTypeDef GPIO_InitStructurePWMServo; // GPIOC Configuration: TIM2 CH2 (PA1) |
9 | GPIO_InitStructurePWMServo.GPIO_Pin=GPIO_Pin_1; // PWM Signalausgang an PA1 |
10 | GPIO_InitStructurePWMServo.GPIO_Mode=GPIO_Mode_AF; // _IN _AF:Alternate _AN:Analog |
11 | GPIO_InitStructurePWMServo.GPIO_Speed=GPIO_Speed_100MHz; // _2MHz _10MHz |
12 | GPIO_InitStructurePWMServo.GPIO_OType=GPIO_OType_PP; // _PP:Push/Pull _OD:OpenDrain |
13 | GPIO_InitStructurePWMServo.GPIO_PuPd=GPIO_PuPd_UP; // _No Pull _UP _DOWN |
14 | GPIO_Init(GPIOA,&GPIO_InitStructurePWMServo); |
15 | |
16 | GPIO_PinAFConfig(GPIOA,GPIO_PinSource1,GPIO_AF_TIM2); // TIM2, CH2, AF2 |
17 | |
18 | |
19 | |
20 | // GPIO für PWMEngine (PA2)
|
21 | RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); |
22 | |
23 | GPIO_InitTypeDef GPIO_InitStructurePWMEngine; // GPIOC Configuration: TIM5 CH3 (PA2) |
24 | GPIO_InitStructurePWMEngine.GPIO_Pin=GPIO_Pin_2; // PWM Signalausgang an PA2 |
25 | GPIO_InitStructurePWMEngine.GPIO_Mode=GPIO_Mode_AF; // _IN _AF:Alternate _AN:Analog |
26 | GPIO_InitStructurePWMEngine.GPIO_Speed=GPIO_Speed_100MHz; // _2MHz _10MHz |
27 | GPIO_InitStructurePWMEngine.GPIO_OType=GPIO_OType_PP; // _PP:Push/Pull _OD:OpenDrain |
28 | GPIO_InitStructurePWMEngine.GPIO_PuPd=GPIO_PuPd_UP; // _No Pull _UP _DOWN |
29 | GPIO_Init(GPIOA,&GPIO_InitStructurePWMEngine); |
30 | |
31 | GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_TIM5); // TIM5, CH3, AF2 |
32 | |
33 | }
|
34 | |
35 | |
36 | |
37 | |
38 | // Init der Timer
|
39 | |
40 | void InitPWMServo (void) |
41 | {
|
42 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); // 42 MHz * 2 = 84 MHz |
43 | |
44 | TIM_TimeBaseInitTypeDef TIM_TimeBaseStructurePWMServo; |
45 | TIM_TimeBaseStructurePWMServo.TIM_Period=400; |
46 | TIM_TimeBaseStructurePWMServo.TIM_Prescaler=839; |
47 | TIM_TimeBaseStructurePWMServo.TIM_CounterMode=TIM_CounterMode_Up; |
48 | TIM_TimeBaseStructurePWMServo.TIM_ClockDivision=0; |
49 | TIM_TimeBaseInit(TIM2,&TIM_TimeBaseStructurePWMServo); |
50 | |
51 | TIM_OCInitTypeDef TIM_OCInitStructurePWMServo; |
52 | TIM_OCInitStructurePWMServo.TIM_OCMode=TIM_OCMode_PWM1; |
53 | TIM_OCInitStructurePWMServo.TIM_OutputState=TIM_OutputState_Enable; |
54 | TIM_OCInitStructurePWMServo.TIM_Pulse=CCR2Servo_Val; // CCR2Servo_Val = 30 für Servo Mittelstellung zu Beginn |
55 | TIM_OCInitStructurePWMServo.TIM_OCPolarity=TIM_OCPolarity_High; |
56 | TIM_OC2Init(TIM2,&TIM_OCInitStructurePWMServo); |
57 | |
58 | TIM_OC2PreloadConfig(TIM2,TIM_OCPreload_Enable); |
59 | |
60 | TIM_Cmd(TIM2,ENABLE); |
61 | |
62 | }
|
63 | |
64 | |
65 | void InitPWMEngine (void) |
66 | {
|
67 | RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE); // 42 MHz * 2 = 84 MHz |
68 | |
69 | |
70 | TIM_TimeBaseInitTypeDef TIM_TimeBaseStructurePWMEngine; |
71 | TIM_TimeBaseStructurePWMEngine.TIM_Period=30; |
72 | TIM_TimeBaseStructurePWMEngine.TIM_Prescaler=249; |
73 | TIM_TimeBaseStructurePWMEngine.TIM_CounterMode=TIM_CounterMode_Up; |
74 | TIM_TimeBaseStructurePWMEngine.TIM_ClockDivision=0; |
75 | TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructurePWMEngine); |
76 | |
77 | TIM_OCInitTypeDef TIM_OCInitStructurePWMEngine; |
78 | TIM_OCInitStructurePWMEngine.TIM_OCMode=TIM_OCMode_PWM1; |
79 | TIM_OCInitStructurePWMEngine.TIM_OutputState=TIM_OutputState_Enable; |
80 | TIM_OCInitStructurePWMEngine.TIM_Pulse=CCR3Engine_Val; // CCR3Engine_Val= 0 für Motorstillstand zu Beginn |
81 | TIM_OCInitStructurePWMEngine.TIM_OCPolarity=TIM_OCPolarity_High; |
82 | TIM_OC3Init(TIM5,&TIM_OCInitStructurePWMEngine); |
83 | |
84 | TIM_OC3PreloadConfig(TIM5,TIM_OCPreload_Enable); |
85 | |
86 | TIM_Cmd(TIM5,ENABLE); |
87 | }
|
88 | |
89 | |
90 | |
91 | |
92 | |
93 | // Main - Abfahren von Min bis Max Werte zum testen des Servo Motors und des DC Motors
|
94 | |
95 | |
96 | for (WertServo = Servo_MIN_VALUE; WertServo <= Servo_MAX_VALUE; WertServo = WertServo+5) |
97 | {
|
98 | int a; |
99 | |
100 | for (a = 0; a < 0x000AFFFF; ++a) |
101 | {
|
102 | }
|
103 | |
104 | SERVO_PWM_VALUE = WertServo; // #define SERVO_PWM_VALUE TIM2->CCR2 |
105 | }
|
106 | |
107 | |
108 | |
109 | for (WertEngine = 0; WertEngine <= 25; WertEngine = WertEngine+1) |
110 | {
|
111 | int i; |
112 | |
113 | for (i = 0; i < 0x000AFFFF; ++i) |
114 | {
|
115 | }
|
116 | |
117 | ENGINE_PWM_VALUE = WertEngine; // #define ENGINE_PWM_VALUE TIM5->CCR3 |
118 | }
|
Michi Müller schrieb: > TIM_TimeBaseStructurePWMServo.TIM_ClockDivision=0; Diese beiden Zeilen machen mich etwas unruhig. Ich guck jetzt nicht ins Datenbuch, aber schreib doch sowas hier:
1 | TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; |
Rufst du in der main() irgendwann SystemInit() auf? Wenn nein, tue es. Mach dir am besten auch mal ein paar LED an die Ausgänge. Wenn du übrigens mehrere Pins am Port auf gleich konfigurieren willst, kannst du sowas machen:
1 | GPIO_InitStructurePWMEngine.GPIO_Pin=GPIO_Pin_2 | GPIO_Pin_1; |
Der Rest sieht eigentlich richtig aus, habe ich so auch bei funktionierender PWM. Wenn du LED an den Ausgängen hast, kannst du ja den Prescaler auch mal richtig gross machen, dann solltest du es blinken sehen. Zum Testen kannst du auch mal TIM4 auf Kanal 2 nehmen (Pin PD13), der sollte die orangene LED blinken lassen. Auf den 4 LED (PD12 - PD15) sind ja CH1 bis CH4 von TIM4.
:
Bearbeitet durch User
Danke für deine Antwort Matthias. Soo PWM läuft jetzt (nachdem ich SystemInit() AUSkommentiert habe) Allerdings kann ich mir das nicht erklären :-) Ich lasse mir zum Debuggen von anderen Funktionen noch einige Werte mit sprintf auf dem Display ausgeben. Variante1: SystemInit() auskommentiert PWM funktioniert sprintf funktioiert nicht (nur flimmern auf dem Display) Variante 2: SystemInit() einkommentiert PWM funktioniert nicht (Servo fährt auf Anschlag und rattert->falsche Frequenz/Periodendauer) sprintf funktioniert Kann es sein, dass sich die PWM und sprintf in die Quere kommen? SystemCoreClock ist mit und ohne SystemInit() bei 180 MHz. Ab nächster Woche habe ich auch wieder ein Oszi zur Verfügung, dann werde ich das nochmals an den µC hängen und schauen welche Werte ausgegeben werden solange SystemInit() einkommentiert ist. Gruß Michi
Michi Müller schrieb: > SystemCoreClock ist mit und ohne SystemInit() bei 180 MHz. Je nach Entwicklungsystem und CMSIS oder HAL wird der Clocktree unterschiedlich initialisiert. Die 180 MHz sind demnach nicht unbedingt richtig bzw. gegeben. Hier mit Coocox und dem STM32F4 Disco wird z.B. auf 168MHz initialisiert, wobei ich da mächtig drin rumfummeln musste, weil z.B. die I2S Clock nicht richtig gestartet wurde.
Wenn ich mich nicht täusche wird die SystemClock doch wie folgt berechnet:
1 | Core Clock = ((HSE_VALUE / PLL_M) * PLL_N) / PLL_P |
2 | #define HSE_VALUE ((uint32_t)8000000) /*!< Value of the External oscillator in Hz */ |
3 | #define PLL_M 8
|
4 | #define PLL_N 360
|
5 | #define PLL_P 2
|
6 | --> Core Clock = 180000000 Hz |
7 | |
8 | PLL_VCO = (HSE_VALUE or HSI_VALUE / PLL_M) * PLL_N |
9 | -->PLL_VCO = 360000000 Hz |
10 | |
11 | SYSCLK = PLL_VCO / PLL_P |
12 | --> SYSCLK = 180000000 Hz |
Somit sollte sie bei mir mit 180 MHz definiert sein. Ich verwende übrigens auch CoIDE. Was ich einfach bisher nicht nachvollziehen kann warum die PWM ohne die Verwendung von SystemInit() funktioniert und nach dem Einbinden von SystemInit() nicht mehr. Der Zusammenhang kann doch nur aus einem Umkonfigurieren einer Varibalen innerhalb dieser Funktion kommen. Wie gesagt ich werde mich kommende Woche mal vor das Oszi setzen. Ohne ist es ein bisschen wie stochern im Nebel. Ich melde mich sobald ich Neuigkeiten oder eine Lösung gefunden habe. Vielen Dank nochmal für deine/eure Hilfe. Gruß Michi
Soo hab jetzt endlich die Lösung gefunden. Nach einigen Stunden suchen ;-) Die Funktion SystemInit() initialisiert bei meinem Programm die SystemClock mit 180 MHz. In dem Beispiel aus welchem ich den Code für die PWM des Servo-Motor genommen habe, wurde die SystemInit nicht durchgeführt. Anscheinend war also eine andere Systemclock und/oder andere Prescaler für die AHB's eingestellt. Habe jetzt durch das Zurückrechnen der am Oszi ausgegebenen PWM Frequenz mit eingestellten Prescaler und der Periode herausgefunden, dass die Timer TIM3 und TIM4 mit 90 MHz laufen. --> Ändern der Werte für Prescaler und Periode und schon läuft alles und ist durch die bekannte Berechnung auch nachvollziehbar:
1 | TIM Update Frequency = TIM Clock / (P * Q) |
2 | Prescaler = P - 1, and Period = Q - 1 |
Kann mir vielleicht noch jemand verraten ob es Variablen gibt, welche ich beim Debuggen (oder mit printf) dafür verwenden kann um herauszufinden mit welchem Takt AHB1 und AHB2 initialisiert sind? Gibt es diese Variablen oder kann ich mir das nur über die eingestellten PLL_-Werte und der SysClock berechnen? Dann tue ich mich beim nächsten Mal evtl etwas leichter den Fehler zu ermitteln. Vielen Dank nochmals für eure Hilfe. Und ein schönes Wochenende !!! Gruß Michi
Michi Müller schrieb: > Kann mir vielleicht noch jemand verraten ob es Variablen gibt, welche > ich beim Debuggen (oder mit printf) dafür verwenden kann um > herauszufinden mit welchem Takt AHB1 und AHB2 initialisiert sind? Du kannst die RCC Register auslesen und auf die Konsole werfen. Interessant sind hier vor allem RCC->CR, RCC->PLLCFGR und RCC->CFGR.
:
Bearbeitet durch User
>Kann mir vielleicht noch jemand verraten ob es Variablen gibt, welche >ich beim Debuggen (oder mit printf) dafür verwenden kann um >herauszufinden mit welchem Takt AHB1 und AHB2 initialisiert sind? Es gibt eine Funktion dafür void RCC_GetClocksFreq(RCC_ClocksTypeDef* RCC_Clocks)
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.