Forum: Mikrocontroller und Digitale Elektronik STM32 HAL Interrupt löst nicht aus?


von Tim K. (timkl94)


Angehängte Dateien:

Lesenswert?

Hallo Leute,

ich habe eine Schaltung, die mir jeden Nulldurchgang der Netzspannung 
detektiert.
Ich möchte bei jeder fallenden Flanke einen Interrupt bei meinem 
STM32L031C6Ten und einen Transistor schalten.
Ich habe aber das Problem, dass der Interrupt nicht auslöst. Hat jemand 
eine Idee, woran das liegen könnte?

gpio.c

/*Configure GPIO pin: PB10 */
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Pin = GPIO_MODE_FALLING;
GPIO_InitStruct.Pin = GPIO_NOPULL;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

/*EXTI Interrupt init*/
HAL_NVIC_SetPriority(EXTI4_15_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI4_15_IRQn);

stm32l0xx_it.c

void EXTI4_15_IRQHandler(void)
{

HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_10);

}

main.c

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{

if(GPIO_Pin == GPIO_PIN_10)
{
HAL_GPIO_WritePin(GPIOA_PAC_Pin, GPIO_PIN_SET);
}

}

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Nächstes mal bitte den Mikrocontroller benennen. Irgendein L0 ist zu 
unspezifisch.

> GPIO_MODE_FALLING

Muss es nicht GPIO_MODE_IT_FALLING heissen? So steht das jedenfalls in 
der Doku UM1749.

Falls es das nicht ist: Greife mal zur Probe innerhalb von 
EXTI4_15_IRQHandler() direkt auf einen I/O Pin zu. An der HAL vorbei, 
also über ein BSRR Register.

von Häh? (Gast)


Lesenswert?

Tim K. schrieb:
> GPIO_InitStruct.Pin = GPIO_PIN_10;
> GPIO_InitStruct.Pin = GPIO_MODE_FALLING;
> GPIO_InitStruct.Pin = GPIO_NOPULL;

Welchen Sinn soll das ergeben?

von Tim K. (timkl94)


Lesenswert?

Stefan ⛄ F. schrieb:
> Nächstes mal bitte den Mikrocontroller benennen. Irgendein L0 ist
> zu
> unspezifisch.
>
>> GPIO_MODE_FALLING
>
> Muss es nicht GPIO_MODE_IT_FALLING heissen? So steht das jedenfalls in
> der Doku UM1749.
>
> Falls es das nicht ist: Greife mal zur Probe innerhalb von
> EXTI4_15_IRQHandler() direkt auf einen I/O Pin zu. An der HAL vorbei,
> also über ein BSRR Register.

GPIO_MODE_IT_FALLING ist richtig. Das habe ich auch so.

Wie sieht der Zugriff auf das BSRR Register aus?

void EXTI4_15_IRQHandler(void)
{

HAL_GPIO_EXTI_IRQHandler(GPIO_PIN_10);

GPIOB->BSRR = (1<<10); //Pin PB10

}

von Peter D. (peda)


Lesenswert?

Häh? schrieb:
> Tim K. schrieb:
>> GPIO_InitStruct.Pin = GPIO_PIN_10;
>> GPIO_InitStruct.Pin = GPIO_MODE_FALLING;
>> GPIO_InitStruct.Pin = GPIO_NOPULL;
>
> Welchen Sinn soll das ergeben?

Nach C-Standard gewinnt die letzte Zuweisung. Da IO-Register volatile 
definiert sind, werden trotzdem alle 3 Zuweisungen ausgeführt.

von Tim K. (timkl94)


Lesenswert?

Peter D. schrieb:
> Häh? schrieb:
>> Tim K. schrieb:
>>> GPIO_InitStruct.Pin = GPIO_PIN_10;
>>> GPIO_InitStruct.Pin = GPIO_MODE_FALLING;
>>> GPIO_InitStruct.Pin = GPIO_NOPULL;
>>
>> Welchen Sinn soll das ergeben?
>
> Nach C-Standard gewinnt die letzte Zuweisung. Da IO-Register volatile
> definiert sind, werden trotzdem alle 3 Zuweisungen ausgeführt.

So siehts eigentlich aus.

GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIOO_MODE_FALLING;
GPIO_InitStruct.Pull = GPIO_NOPULL;

von Jim (Gast)


Lesenswert?

Peter D. schrieb:
> Da IO-Register volatile
> definiert sind, werden trotzdem alle 3 Zuweisungen ausgeführt.

Weil die struct direkt auf den IO-Registern liegt. Klingt logisch.

von Peter D. (peda)


Lesenswert?

Tim K. schrieb:
> So siehts eigentlich aus.
>
> GPIO_InitStruct.Pin = GPIO_PIN_10;
> GPIO_InitStruct.Mode = GPIOO_MODE_FALLING;
> GPIO_InitStruct.Pull = GPIO_NOPULL;

Deshalb haben hier schon viele Leute Fusseln vor dem Mund, weil sie 
ständig sagen müssen:
"Nicht aus dem Gedächtnis nachschreiben, sondern per copy&paste den 
exakten getesteten Code posten!"

Was ist sonst noch falsch abgetippt?

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Peter D. schrieb:
> Nach C-Standard gewinnt die letzte Zuweisung.

Ist hier aber trotzdem falsch. Für Pin, Mode und Pull gibts je ein 
eigenes I/O-register.

von Marcel B. (cable545)


Lesenswert?

Hast Du den Takt für den GPIO Port eingeschaltet? In Deinem Code kann 
ich nichts dergleichen finden.

Wird über den RCC (reset and clock controller) gemacht.

: Bearbeitet durch User
von Tim K. (timkl94)


Lesenswert?

Also der Interrupt an sich funktioniert.

Marcel B. schrieb:
> Hast Du den Takt für den GPIO Port eingeschaltet? In Deinem Code
> kann
> ich nichts dergleichen finden.
>
> Wird über den RCC (reset and clock controller) gemacht.

Ja, hab ich.

von Darth Moan (Gast)


Lesenswert?

Frank M. schrieb:
> Peter D. schrieb:
>> Nach C-Standard gewinnt die letzte Zuweisung.
>
> Ist hier aber trotzdem falsch. Für Pin, Mode und Pull gibts je ein
> eigenes I/O-register.

GPIO_InitStruct ist eine Datenstruktur im RAM deren Adresse and
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
übergeben wird, welche dann die HW Register beschreibt oder auch nicht.

von Marcel B. (cable545)


Lesenswert?

Tim K. schrieb:
> Also der Interrupt an sich funktioniert.
>
> Marcel B. schrieb:
>> Hast Du den Takt für den GPIO Port eingeschaltet? In Deinem Code
>> kann
>> ich nichts dergleichen finden.
>>
>> Wird über den RCC (reset and clock controller) gemacht.
>
> Ja, hab ich.

Versteh ich nicht. Wenn Du das gemacht hast, dann frage ich mich wo das 
in Deinem Code steht? Wenn Du nicht den kompletten Code postest, ist das 
sehr zäh Dir zu helfen. Also mit alles meine ich, alles was zur 
Initialisierung Deiner GPIO Interrupt Prozedur gehört.

Und was heißt "Also der Interrupt an sich funktioniert." Hast du das in 
dem entsprechenden Register gesehen und der Handler reagiert nicht? Denn 
in Deinem ersten Post schreibst Du "Ich habe aber das Problem, dass der 
Interrupt nicht auslöst".

von Stefan F. (Gast)


Lesenswert?

Tim K. schrieb:
> GPIOB->BSRR = (1<<10); //Pin PB10

Nicht ganz. In dem Register sind immer zwei Bits pro Pin nebeneinander. 
Eins setzt ihn auf HIGH, das andere aus LOW. Du musst nur das richtige 
Bit beschrieben. Würde ich so machen:
1
GPIOB->BSRR = GPIO_BSRR_BS_10;  // HIGH, oder
2
GPIOB->BSRR = GPIO_BSRR_BR_10;  // LOW

Peter D. schrieb:
> Nach C-Standard gewinnt die letzte Zuweisung.

Frank M. schrieb:
> Für Pin, Mode und Pull gibts je ein eigenes I/O-register.

Ach wie doof, das habe ich gar nicht gesehen!

von pegel (Gast)


Lesenswert?

Ja, so ist das, wenn man um jeden Preis CubeMX vermeiden will.

Mit ein paar Klicks wäre das Problem erst gar nicht entstanden. ;)

von Viktor B. (coldlogic)


Lesenswert?

pegel schrieb:
> Mit ein paar Klicks wäre das Problem erst gar nicht entstanden. ;)

Dann hat man aber das Problem, dass die CubeMX einem einen 
undurchschaubaren Haufen von miteinander verknoteten Funktionen und 
Definitionen in einem genauso undurchschaubaren Haufen von miteinander 
verknoteten Header- und Sourcedateien erzeugt. Manchmal ist es besser, 
die Sachen langsamer anzugehen.

von Stefan F. (Gast)


Lesenswert?

Die HAL ist halt nichts für Anfänger - sieht aber so aus.

von Tim K. (timkl94)


Lesenswert?

Inzwischen funktioniert es mit HAL.
Mein eigentliches Ziel ist es eine Phasenanschnittsteuerung zu 
programmieren. Ich habe eine gleichgerichtete Netzspannung.
Mein Problem ist, dass die if-Bedingung nie erfüllt wird und der 
Transistor somit nicht ausschaltet. Die diff soll noch mit einem Poti 
eingestellt werden können (20 -> 100 % von der Phase).

main.c

while(1)
{

if((counter - prevCounter) >= diff)
{
HAL_GPIO_Write(GPIOA, PAC_Pin, GPIO_PIN_RESET)
}

}

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{

if(GPIO_Pin == GPIO_PIN_10)
{
HAL_GPIO_WritePin(GPIOA, PAC_Pin, GPIO_PIN_SET);
prevCounter = counter;
diff = counter - countNull;
countNull = counter;
}

}

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{

if(htim->Instance==TIM2)
{
counter++; // alle 10 us hochzählen
}

}

void poti()
{
}

: Bearbeitet durch User
von pegel (Gast)


Lesenswert?

Beobachte mal deine Variablen im Debugger.

Wenn sich da nichts tut, fehlt vermutlich ein "volatile".

von Tim K. (timkl94)


Lesenswert?

Der Code funktioniert jetzt an sich.
Meine Frage ist gerade, wie errechne ich den Zeitpunkt für den 
Phasenabschnitt unabhängig von der Eingangsspannung (110/230 V und 
50/60Hz) für 20 bis 100 % der Eingangsspannung.
Ich benötige einen Faktor mit dem ich mein diff dann multipliziere.

von Peter D. (peda)


Lesenswert?

Tim K. schrieb:
> Zeitpunkt für den
> Phasenabschnitt unabhängig von der Eingangsspannung

Der Zeitpunkt des Nulldurchgangs ist immer spannungsunabhängig oder 
Deine Schaltung taugt nichts. Warum zeigst Du sie uns nicht?

von pegel (Gast)


Lesenswert?

Dann musst Du erst mal feststellen, ob 50 oder 60 Hz anliegen.

Die jeweilige Periodendauer ist dann 0,2 .. 1,0 * Periode.
10µs Schritte hast Du schon vorgegeben.

ADC muss natürlich für das Poti auch noch berücksichtigt werden.


Ich würde aber vielleicht alles mit Comparator, Timer, Encoder/Timer und 
internem Trigger probieren.

von Tim K. (timkl94)


Lesenswert?

Die Periode steckt in der Variablen diff. Für eine Periode von 10ms ist 
diff = 1000.
Wenn ich einen Faktor z.B. 0.5 mit diff multipliziere, wird das 
Steuersignal falsch berechnet.

if((counter - prevCounter) >= (uint16_t) (float) diff * fac))
{
HAL_GPIO_Write(GPIOA, PAC_Pin, GPIO_PIN_RESET)
}

von Stefan F. (Gast)


Lesenswert?

Tim K. schrieb:
> Mein Problem ist, dass die if-Bedingung nie erfüllt wird

Welche genau?

Und formatiere bitte den Quelltext ordentlich, da bekommt man ja 
Augenkrebs.

von Tim K. (timkl94)


Lesenswert?

Diese Schleife

if((counter - prevCounter) >= (uint16_t) (float) diff * fac))
{
   HAL_GPIO_Write(GPIOA, PAC_Pin, GPIO_PIN_RESET);
}

von Stefan F. (Gast)


Lesenswert?

Sind counter und prevCounter denn auch beide vom Typ uint16_t?
Haben diff und fac die erwarteten Werte?

Ich würde hier den Umweg über fließkomma Arithmetik vermeiden wollen. 
Oft ist es erheblich effizienter, notfall mit größeren Integer Werten zu 
rechnen.

Als Beispiel würde ich 50% nicht als 0.5 darstellen, sondern als 50 und 
dann durch 100 teilen. Das würde bequem in 32bit Integer passen.

Außerdem ist der Prozessor bei 32bit Integern oft schneller, als bei 
16bit, aber gewiss niemals langsamer. Speicherplatz sparen macht nur bei 
größeren Ansammlungen von Daten Sinn. Funktionsargumente und Ergebnisse 
werden sowieso immer als 32bit übergeben, was mehrfache Konvertierung 
hin und zurück mit sich bringen kann.

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.