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


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Tim K. (timkl94)


Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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. (stefanus)


Bewertung
0 lesenswert
nicht 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.

: Bearbeitet durch User
von Häh? (Gast)


Bewertung
1 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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


Bewertung
1 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
2 lesenswert
nicht 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. (stefanus)


Bewertung
0 lesenswert
nicht 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:
GPIOB->BSRR = GPIO_BSRR_BS_10;  // HIGH, oder
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!

: Bearbeitet durch User
von pegel (Gast)


Bewertung
1 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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. (stefanus)


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

von Tim K. (timkl94)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht lesenswert
Beobachte mal deine Variablen im Debugger.

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

von Tim K. (timkl94)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht 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. (stefanus)


Bewertung
0 lesenswert
nicht 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)


Bewertung
0 lesenswert
nicht lesenswert
Diese Schleife

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

von Stefan ⛄ F. (stefanus)


Bewertung
0 lesenswert
nicht 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.

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.