Ich versuche, zu den ST HAL-Bibliotheken zu wechseln, und kann die PWM anscheinend nicht zum Laufen bringen. Lässt sich gut kompilieren, startet nur nicht.
In meinem main() rufe ich die Timer-Initialisierungsfunktion auf:
/* TIM3 init function */
void MX_TIM3_Init(void)
{
TIM_MasterConfigTypeDef sMasterConfig;
TIM_OC_InitTypeDef sConfigOC;
htim3.Instance = TIM3;
htim3.Init.Prescaler = 0;
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 1300;
htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
HAL_TIM_PWM_Init(&htim3);
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig);
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_SET;
sConfigOC.Pulse = 650;
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_ENABLE;
HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1);
HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2);
HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_3);
HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_4);
HAL_TIM_PWM_MspInit(&htim3);
}
Der GPIO wird in der HAL_TIM_PWM_MspInit()
Funktion initialisiert:
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef* htim_pwm)
{
GPIO_InitTypeDef GPIO_InitStruct;
if(htim_pwm->Instance==TIM3)
{
/* Peripheral clock enable */
__TIM3_CLK_ENABLE();
/**TIM3 GPIO Configuration
PC9 ------> TIM3_CH4
PC8 ------> TIM3_CH3
PC7 ------> TIM3_CH2
PC6 ------> TIM3_CH1
*/
GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_8|GPIO_PIN_7|GPIO_PIN_6;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_HIGH;
GPIO_InitStruct.Alternate = GPIO_AF2_TIM3;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
}
}
Schließlich sieht mein main() so aus: (Ich rufe SystemInit() von main auf, weil ich STCube-generierte Dateien mit coocox coide verwende)
int main(void)
{
SystemInit() ;
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_TIM3_Init();
MX_GPIO_Init();
MX_LWIP_Init();
while (1)
{
}
}
Ich komme zu spät zur Party, aber ich befand mich in einer ähnlichen Situation und habe die richtige Antwort, oder zumindest die Antwort, die ich persönlich verifiziert habe, um mit meinem eigenen STM32-Board und den STM32CubeMx-Treibern zu funktionieren.
memset(&sConfigOC, 0, sizeof(sConfigOC));
Lokale Variablen werden nicht automatisch initialisiert und Sie werden eine unerwartete/unbeabsichtigte Konfiguration haben, weil die HAL basierend auf diesen Handle-Variablen sehr grundlegende Annahmen über den Peripheriezustand macht. Besonders ärgerlich ist es, wenn sich das Verhalten von Kompilierung zu Kompilierung oder von Funktionsaufruf zu Funktionsaufruf ändert, wenn sich der Stapelspeicher ändert.HAL_TIM_PWM_MspInit()
manuell an. Es wird automatisch aufgerufen, wenn Sie aufrufen HAL_TIM_PWM_Init()
, aber Sie müssen sicherstellen, dass Ihre Handle-Variablen richtig initialisiert sind (siehe Nr. 1 oben).HAL_TIMEx_MasterConfigSynchronization()
wenn Sie nicht von der Standardkonfiguration (nicht verkettet/synchronisiert) wechseln. Es schadet nichts, ist aber auch nicht nötig.MspInit()
Funktion ist gut, außer Sie sollten auch die Uhr des GPIOC-Peripheriegeräts aktivieren.Und die Magie, die verhindert, dass es funktioniert:
HAL_TIM_PWM_Start()
nach jedem Aufruf von aufrufen -- HAL_TIM_PWM_ConfigChannel()
das erste, was Sie tun HAL_TIM_PWM_ConfigChannel()
müssen, ist, die Timer-Ausgänge (die CCxE
Bits in TIMx_CCER
) zu deaktivieren. HAL_TIM_PWM_ConfigChannel()
schaltet die Timer-Ausgänge nicht wieder ein!Da die einzige HAL-Methode zum manuellen Aktualisieren des PWM-Tastverhältnisses durch ist HAL_TIM_PWM_ConfigChannel()
, müssen Sie immer anrufen HAL_TIM_PWM_Start()
oder Sie haben keinen PWM-Ausgang. Ich denke, dies geschieht, weil die normale Arbeitsweise mit PWM darin besteht, die _IT()
oder _DMA()
-Varianten von zu verwenden HAL_TIM_PWM_Start()
, und Sie aktualisieren den Arbeitszyklus sozusagen "im Hintergrund".
Einige der anderen Antworten (einschließlich der ursprünglich als akzeptiert markierten) sind falsch:
HAL_TIM_Base_Start()
noch HAL_TIM_Base_Init()
, noch einen der anderen Nicht-PWM-Aufrufe an; Erstens ruft die HAL Ihre PWM_MspInit()
Funktion nicht auf, da sich das Peripheriehandle nicht mehr im Reset-Zustand befindet, aber was noch wichtiger ist, die PWM (und OC und andere Varianten) rufen alle internen Funktionen auf niedriger Ebene ordnungsgemäß auf, ohne dass Sie dies manuell tun. Der springende Punkt bei der HAL ist, dass Sie sich nicht so viele Gedanken über die Details machen müssen, aber Sie müssen einen guten Überblick darüber haben, was die HAL tut und was sie erwartet. Die vollständige Quelle ist verfügbar und ziemlich gut dokumentiert. Sie müssen es nur lesen.HAL_TIMEx_PWMN_Start()
keine der anderen TIMEx
Funktionen aufrufen, es sei denn, Sie verwenden die kostenlosen Ausgänge. Auch dies ist in der HAL-Quelle ziemlich gut dokumentiert.HAL_TIM_PWM_Stop(&htim2, TIM_CHANNEL_1); HAL_TIM_PWM_ConfigChannel(&htim2, &sConfigOC, TIM_CHANNEL_1); HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
Ich verwende STCubeMX und die generierten HAL-Initialisierungsdateien. Prozess auf meinem F302 Nucleo Board verifiziert. Ich habe den erweiterten Timer 1 (TIM1) mit einem normalen und komplementären Ausgang ohne Totzeit eingerichtet.
So habe ich PWM in CubeMX konfiguriert:
Nachdem der Code generiert wurde, müssen wir noch die PWM starten. Dies geschieht durch Aufrufen der folgenden Funktionen im Benutzercodebereich vor while(1) innerhalb von main():
HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1); //starts PWM on CH1 pin HAL_TIMEx_PWMN_Start(&htim1, TIM_CHANNEL_1); //starts PWM on CH1N pin
Um die Konfigurationseinstellungen zu ändern, verwenden Sie die folgenden Makros, die in stm32f3xx_hal_tim.h bereitgestellt werden. HAL_TIM_PWM_ConfigChannel()
ist nicht die einzige Möglichkeit, die PWM-Einstellung manuell zu aktualisieren, wie von @akohlsmith gesagt.
__HAL_TIM_GET_AUTORELOAD(&htim1); //gets the Period set for PWm __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, dutyCycle); //sets the PWM duty cycle (Capture Compare Value)
Kein erneuter Anruf nötig HAL_TIM_PWM_Start()
. Diese Makros ändern die Einstellung während der Laufzeit.
Bei Verwendung von Cube Mx initialisiert der generierte Code das Timer-Peripheriegerät, startet es jedoch nicht. Die Lösung ist wie von anderen vorgeschlagen: Fügen Sie die Startfunktionen hinzu.
HAL_TIM_Base_Start(&htim3);
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_ALL);
Platzieren Sie diesen Code im Abschnitt „BENUTZERCODE“ nach dem generierten Code, der aufruft MX_TIM3_Init()
.
TIM_CHANNEL_ALL
dem zweiten Aufruf, sondern mit TIM_CHANNEL1
stattdessen (es startete die tatsächliche PWM-Ausgabe am Ausgangspin). Ähnlich für die anderen 3 Kanäle, indem Sie TIM_CHANNEL2
, TIM_CHANNEL3
bzw. TIM_CHANNEL14
im Anruf an verwenden HAL_TIM_PWM_Start()
(also insgesamt 4 Anrufe an HAL_TIM_PWM_Start()
).HAL_TIM_Base_Start(&htim3);
wird nicht benötigt (empirisch ermittelt und auch in der Antwort von akohlsmith ).Sie müssen zuerst den Timer starten. Fügen Sie die nächste Zeile zum main()
Start von timer3 hinzu CH1
:
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_1);
void PWM_Output(void)
{
TimerPeriod = 1000;
/* TIM1 clock enable */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1 , ENABLE);
/* Time Base configuration */
TIM_TimeBaseStructure.TIM_Prescaler = 48;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period = TimerPeriod;
TIM_TimeBaseStructure.TIM_ClockDivision = 1;
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
/* Channel 1, 2, 3 and 4 Configuration in PWM mode */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OCInitStructure.TIM_Pulse = 899;
TIM_OC1Init(TIM1, &TIM_OCInitStructure);
TIM_OCInitStructure.TIM_Pulse = 899;
TIM_OC2Init(TIM1, &TIM_OCInitStructure);
TIM_OCInitStructure.TIM_Pulse = 899;
TIM_OC3Init(TIM1, &TIM_OCInitStructure);
TIM_OCInitStructure.TIM_Pulse = 899;
TIM_OC4Init(TIM1, &TIM_OCInitStructure);
/* TIM1 counter enable */
TIM_Cmd(TIM1, ENABLE);
/* TIM1 Main Output Enable */
TIM_CtrlPWMOutputs(TIM1, DISABLE);
}
void GPIO_init(){
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);
GPIO_PWMEnPins.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;
GPIO_PWMEnPins.GPIO_Mode = GPIO_Mode_AF;
GPIO_PWMEnPins.GPIO_Speed = GPIO_Speed_Level_1;
GPIO_PWMEnPins.GPIO_OType = GPIO_OType_PP;
GPIO_PWMEnPins.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_PWMEnPins);
/*SMT32F0 has different config for Alternate Function assignment; below is the example. STM32F4 might have less code footprint to configure alternate func.*/
GPIO_PinAFConfig(GPIOA, GPIO_PinSource8, GPIO_AF_2);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_2);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_2);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_2);
}
Dieser Code funktioniert in CooCox mit Standard-STM32f0xx_yyy-Bibliotheken. Sie müssen auch die Uhr von GPIOC in GPIO init aktivieren.
Ich denke, Sie müssen die GPIO-Uhr durch Aufrufen initialisieren__GPIOC_CLK_ENABLE();
Ich habe ähnlichen Code, der funktioniert - aber ich habe das Master-Config-Zeug ausgelassen.
Es gibt ein Beispiel im Ordner stm32g-eval, das an das Discovery Board angepasst werden kann (falls das das Board ist, das Sie verwenden).
Sie müssen dazu:
HAL_TIM_Base_Start_IT(&htim3);
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_ALL);
HAL_TIMEx_PWMN_Start(&htim3,TIM_CHANNEL_ALL);
Oboist B