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
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.
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?
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 }
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.
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;
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.
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?
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.
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
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.
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.
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".
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!
Ja, so ist das, wenn man um jeden Preis CubeMX vermeiden will. Mit ein paar Klicks wäre das Problem erst gar nicht entstanden. ;)
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.
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
Beobachte mal deine Variablen im Debugger. Wenn sich da nichts tut, fehlt vermutlich ein "volatile".
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.
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?
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.
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) }
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.
Diese Schleife if((counter - prevCounter) >= (uint16_t) (float) diff * fac)) { HAL_GPIO_Write(GPIOA, PAC_Pin, GPIO_PIN_RESET); }
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.