Mit STM32-HAL-Timer und Einstellen des Duty-Cycle eines PWM-Signals
Benutzte ich die STM32Cube-Initialisierung-code-generator zum erzeugen eines initialisierten Timer-Funktion. Zum generieren einer festen Tastverhältnis PWM-signal, fügte ich HAL_TIM_Base_Start(&htim1); //Starts the TIM Base generation
und HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1)//Starts the PWM signal generation
an der Timer-Initialisierung-Funktion, wie unten gezeigt.
/* Private variables ---------------------------------------------------------*/
int pulse_width=0;
/* TIM1 init function */
static void MX_TIM1_Init(void)
{
TIM_ClockConfigTypeDef sClockSourceConfig;
TIM_MasterConfigTypeDef sMasterConfig;
TIM_OC_InitTypeDef sConfigOC;
TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig;
htim1.Instance = TIM1;
htim1.Init.Prescaler = 0;//we want a max frequency for timer, so we set prescaller to 0
//And our timer will have tick frequency
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 1066;//max value for timer is 16bit = 65535, TIM_Period = timer_tick_frequency /PWM_frequency - 1
//In our case, for 15Khz PWM_frequency, set Period to TIM_Period = 16MHz /15KHz - 1 = 1066
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
if (HAL_TIM_Base_Init(&htim1) != HAL_OK)/* to use the Timer to generate a simple time base for TIM1 */
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;//the default clock is the internal clock from the APBx, using this function
if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)//Initializes the TIM PWM Time Base according to the specified
//parameters in the TIM_HandleTypeDef and create the associated handle.
{
Error_Handler();
}
if (HAL_TIM_PWM_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
//sConfig: TIM PWM configuration structure
//set duty cycle: pulse_length = ((1066 + 1) * duty_cycle) /(100 - 1)
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = pulse_width;/* 50% duty cycle is 538, set to 0 initially*///
sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
sConfigOC.OCNPolarity = TIM_OCNPOLARITY_HIGH;
sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
sConfigOC.OCIdleState = TIM_OCIDLESTATE_RESET;
sConfigOC.OCNIdleState = TIM_OCNIDLESTATE_RESET;
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
if (HAL_TIM_PWM_ConfigChannel(&htim1, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)
{
Error_Handler();
}
sBreakDeadTimeConfig.OffStateRunMode = TIM_OSSR_ENABLE;
sBreakDeadTimeConfig.OffStateIDLEMode = TIM_OSSI_ENABLE;
sBreakDeadTimeConfig.LockLevel = TIM_LOCKLEVEL_1;
sBreakDeadTimeConfig.DeadTime = 0;
sBreakDeadTimeConfig.BreakState = TIM_BREAK_ENABLE;
sBreakDeadTimeConfig.BreakPolarity = TIM_BREAKPOLARITY_HIGH;
sBreakDeadTimeConfig.AutomaticOutput = TIM_AUTOMATICOUTPUT_ENABLE;
if (HAL_TIMEx_ConfigBreakDeadTime(&htim1, &sBreakDeadTimeConfig) != HAL_OK)
{
Error_Handler();
}
HAL_TIM_MspPostInit(&htim1);//output pin assignment
HAL_TIM_Base_Start(&htim1); //Starts the TIM Base generation
if (HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1) != HAL_OK)//Starts the PWM signal generation
{
/* PWM Generation Error */
Error_Handler();
}
/* Start channel 2 */
if (HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_2) != HAL_OK)
{
/* PWM Generation Error */
Error_Handler();
}
}
Dies ist genug, um die PWM auf einen festen duty cycle angegeben in den Kommentaren oben, wenn ich schwer code auf den richtigen Wert zu ersetzen pulse_width
Wert insConfigOC.Pulse = pulse_width
.
In einer anderen Funktion, ich habe ein Algorithmus, der aktualisiert werden würde, die pulse_width
Globale variable. Die Funktion wird aufgerufen: adjust_PWM();
. Der Algorithmus berechnen gemessenen Werte aus dem ADC und gespeichert werden als Globale Variablen. Diese Funktion aufgerufen wird: Data_Update();
. In main()
nach werden alle Funktionen initialisiert. Ich nenne diese drei Funktionen endlos
Data_Update();
adjust_PWM();
MX_TIM1_Init();
Ich habe versucht, und erhalten komisch Wellenformen auf dem Oszilloskop, aber das könnte sein, weil Der ADC-pins, wo Sie schweben, verursacht floating-Messungen zu stören, die mit dem Arbeitszyklus durch den Algorithmus. Auch eingedenk der Initialisierung der timer ständig unterbrechen würden das PWM-signal. Gibt es eine bessere Möglichkeit zum ändern der Einschaltdauer beim ausführen der code ohne die Verwendung von globalen Variablen, oder ohne Initialisierung der timer jedes mal, wenn ich aktualisieren möchten, die Pflicht-Zyklus. Jeder link wäre sehr hilfreich.
direkt die Register programmiert? können Sie näher erläutern für jemanden, der mehr hardware orientiert?
Lesen Sie das Referenz-Handbuch (müssen Sie sowieso), nur die CMSIS und registrieren definition-Header von ST und direkt schreiben/Lesen der Register der Peripherie-Module. Als hardware-orientierte person, diese sollte auch passen Sie viel besser. Auf diese Weise müssen Sie nicht haben, um Geige mit dieser bloatware und die hardware, sondern nur die hardware.
Ich konnte nicht mehr Zustimmen, @Olaf 's Aussage über das fallen der code der Bibliothek. Es ist bestenfalls ein Chaos, und im schlimmsten Fall eine Haftung. Arbeiten aus dem Datenblatt und setzen der Peripheriegeräte bis Ihr selbst, Sie wissen genau, was Los ist. Wenn es eine Plattform, die Sie gehen, um zu arbeiten mit viele werden Sie schließlich am Ende mit Ihrem eigenen HAL-Bibliothek sowieso.
Anstelle von aufrufen MX_TIM1_Init() wiederholt, haben Sie versucht, Sie anzurufen, HAL_TIM_PWM_ConfigChannel() mit der neuen
pulse_width
Wert?
InformationsquelleAutor Nadim | 2017-04-18
Du musst angemeldet sein, um einen Kommentar abzugeben.
Nicht reinit den timer, wenn Sie eine Einstellung ändern möchte, hat HAL einen dedizierten makro für diesen Zweck genannt:
Timer 1 - Kanal 1 und Timer 1 - Kanal 2 sollte es so Aussehen:
InformationsquelleAutor Bence Kaulics
Schreiben Sie Ihre eigene Funktion zum aktualisieren der register regelt, dass der duty-cycle. Sie müssen manuell aktualisieren Sie die entsprechende CCRx register (x ist die PWM-Kanal du verwendest, das ist CCR1 in Ihrem Fall).
ARR-register ist das register, werden Sie die Referenz bei der Berechnung der neue Wert für das CCR-register basierend auf dem gewünschten duty cycle.
Es gibt Fälle, wo schwimmende Punkte sind gefährlich und sollte vermieden werden. Obwohl Sie sind viel einfacher zu verstehen und erfüllen Ihren Zweck auch in diesem Stück der illustration code. Wenn soft-float ist ein Thema, dann ist [0;100] DC zugeordnet werden können, [0;0xFFFFU] oder fester Punkt usw. Diese aber langsamer als die hardware-floating-point-letzteres ist auch die Erhaltung mehr Präzision.
Geschwindigkeit von float-Verarbeitung ist nicht das einzige Problem, und ich Sprach nicht über hazard (zwei Fragen). Dies ist nicht der Ort für die Nachhilfe, aber ein erfahrener embedded-Programmierer will vermeiden, schwimmt, wo angemessen, das ist sehr ofteen das problem.
Ein anderes problem ist die RAM/stack-Speicher. Für CM4F, FPU-Register, z.B. müssen 64 zusätzliche bytes im Stapelspeicher. Dieser Speicher kann ein problem für sehr parallelised MT code auf kleinen Geräten (die bevorzugt aus Kostengründen). Aber auch ein Zeit-problem für die extra-Uhren. Wie ich schon schrieb: die meisten Verwendungen der gloats in eingebettet werden, indem unerfahrene oder faule Programmierer. Bei allem Respekt, aber wie viel Erfahrung haben Sie auf solchen Plattformen? Die STM32F7 ist definitiv nicht einer von Ihnen (obwohl hier die FPU-Register nehmen 128 bytes (
double
). F4 ist grenzwertig.Btw: die Genauigkeit der Festkomma-Konstanten, die ein float ist relativ, so schwierig zu vergleichen. 32-bit-fixed-point hat eine höhere Präzision als IEEE754
single
um+/-1E0
. Typische ADCs und DACs verwenden Sie integer oder fixed-point sowieso.InformationsquelleAutor Flip