IDLE-Flag-Problem mit uart?

void USART2_IRQHandler(void)
 
{
 
 /* USER CODE BEGIN USART2_IRQn 0 */
 
  /* UART IDLE Interrupt */
 
    if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_IDLE) == SET)  
 
    {
 
     __HAL_UART_CLEAR_IDLEFLAG(&huart2);
 print("time %d",timeCounter");
receivedDataFlag = 1;

 
}
 
}

Wenn ich diese Funktion verwende, überprüfe den Ruhezustand der Leitung und entscheide, welche Daten empfangen oder nicht empfangen werden. Aber dieser Interrupt löst beim Senden aus. Wie kann ich Datenempfangsleitungsruhe und Empfangsruhe trennen?

Ich möchte auslösen, dass nur die Datenleitung leer ist, wie kann ich das tun? Welches andere Register sollte ich mir ansehen?

Ich bekomme ein sehr interessantes Ergebnis,

Sender sendet alle 100 ms Daten an mein Gerät;

Wenn ich nur die DMA-Funktionen empfange; Zeitrückgabe 10, 110, 220,330 (Ruhezustände arbeiten)

Aber wenn ich als nach dem Senden von Daten mit uart dieses Mal Werte 10,13,15, ... zurückbekomme, ändert eine mittlere Sendefunktion den Leitungsruhezustand, wie ist das möglich? Bezieht sich UART_FLAG_IDLE nur auf RX?

BEARBEITEN: Übrigens verwende ich rs485. Wenn ich also mit dem Senden beginne, stelle ich den Transceiver-Sendermodus ein, also den senderseitigen Empfängermodus, damit meine MCU diesen Zustand in den Leerlauf versetzt? ist das möglich? Wie kann ich diese Situation schützen?

Wenn ich nach empfangenen Daten den Übertragungsmodus starte, dann abgeschlossener Rückruf, wenn ich die HAL_UART_Receive_DMA(&huart2,(uint8_t*)dma_rx_buf,DMA_BUF_SIZE); Funktion IDLE Interrupt wird alle 5 ms ausgelöst, aber Timeout für das Senden von Daten beträgt 100 ms

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
 

  HAL_UART_DMAStop(&huart2);
  dmaTransmitCompletedFlag = 1;
  RS485_Set_Receive_Mode();
  HAL_UART_Receive_DMA(&huart2,(uint8_t*)dma_rx_buf,DMA_BUF_SIZE);
  waitForTransmittingData = 0;

}
Führen Sie niemals Funktionsaufrufe von ISRs aus! Sie haben gerade alle in ISR verwendeten Register verschoben und jetzt tun Sie es erneut. Das printf erhöht die verwendeten Register und die Latenzzeit von der Funktion in ISR ist verschwenderisch. Setzen Sie Ihre Flagge. Markieren Sie in Ihrer Software das Flag, verarbeiten Sie es und drucken Sie die Nachricht.
@StainlessSteelRat Meinst du das ernst, was du gesagt hast? Das Aufrufen von Funktionen von ISR ist in Ordnung. Das macht der STM32 HAL bereits. Es ist ein STM32, also werden bei ISR ​​die Register sowieso von der Hardware für den ISR-Kontext auf den Stapel geschoben, es gibt keine Strafe mehr als für einen regulären Funktionsaufruf. Außerdem könnte der STM32 etwa 1 Megabyte RAM haben, also ist es kein Problem, nicht einmal auf einem 8-Kilobyte-STM32. Was nicht richtig ist, ist, eine schwere Funktion wie printf in ISR aufzurufen, und höchstwahrscheinlich ist sie nicht wiedereintrittsfähig, also sind dies die größten Probleme.
Kommt auf die Funktion an. Jeder printf ist ein Schwein und Teil des Problems von OP.
@StainlessSteelRat hat Recht, dass die Verwendung von Drucken in einem Interrupt ein Problem darstellt, da der Stdio-Stream-Treiber Thread-sicher sein sollte. Was es nicht standardmäßig für stm32 ist.

Antworten (3)

Dieser Interrupt wird sowohl zum Senden als auch zum Empfangen verwendet.

Das IDLE ist nur für den Empfang relevant, es bedeutet, dass mindestens ein vollständiger Rahmen des Leerlaufs erkannt wird.

Die Verwendung von print in einem Interrupt ist unklug, insbesondere wenn der Druck denselben UART verwendet, für den der Interrupt ist.

Drucken Sie mit usart1, aber dieser Interrupt mit usart2, ist IDLE nur für den Empfang relevant, wie dies möglich ist? Wie ist mein Timer sehr nah?
Übrigens verwende ich rs485. Wenn ich also mit dem Senden beginne, stelle ich den Transceiver-Sendermodus ein, also den senderseitigen Empfängermodus, damit meine MCU diesen Zustand in den Leerlauf versetzt. ist das möglich?
Zweitens die Warnung vor dem Drucken in einem Interrupt. Zusätzlich zu der blockierenden Natur dieser Funktion gibt es eine Menge Overhead und RAM-Nutzung, was die Ausführungszeit weiter verlängert. Best Practice ist es, Ihre Handler sehr schnell und einfach zu halten und zeitintensivere Funktionen zu übergeben, indem Sie Flags im Handler setzen und sie in der Hauptschleife löschen. Wenn Ihre Handler zu lange laufen, erhalten Sie „Unterbrechungsstürme“, die Ihren Code im Grunde weichzeichnen.
@mathco Ich verstehe nicht, warum Sie fragen, wie das möglich ist, weil es so konzipiert ist. IDLE ist nur für den Empfang relevant, es wird gesetzt, wenn nach einem Frame-Empfang der Empfang eines neuen Frames nicht innerhalb einer Timeout-Periode von einem Frame erkannt wird. Wenn Sie möchten, dass ich das Handbuch für Sie zitiere, müssen Sie angeben, welches genaue STM32-Mikrocontrollermodell Sie verwenden.
Ich habe meiner Frage einige Details hinzugefügt
Ich verstehe das Problem immer noch nicht. Wenn Sie RS485 in den Sendemodus versetzen, wissen wir nicht, ob der STM32 gesendete Daten empfangen kann oder nicht. Immer dann, wenn der Empfänger einen Leerlaufrahmen sieht, erzeugt er eine Leerlaufunterbrechung. Wenn Sie keine Leerlauf-Interrupts wollen, hören Sie auf, sie zu verwenden. Aber wie gesagt, es gibt kein Problem, wie IDLE-Interrupts funktionieren, das Problem ist, dass Sie vielleicht erwarten, dass sie anders funktionieren, als sie wirklich funktionieren und wie Sie den RS485-Transceiver verwenden, kann dies beeinflussen. Und Sie erwähnen nie, welchen genauen STM32-Mikrocontroller Sie verwenden, damit niemand das Handbuch für Sie zitieren kann. Bearbeiten Sie den STM32-Typ.

Dieser IRQ ist für USART2 bestimmt, wird aber für jeden aktivierten Interrupt aufgerufen , der USART2 zugeordnet ist. Das bedeutet, dass der Handler jedes aktivierte Interrupt-Signal prüfen und verarbeiten muss. Für STM32 USART umfasst dies Signale, die für unterbrechungsgesteuerte UART wie TXNE und RXNE von grundlegender Bedeutung sind, sowie Fehlersignale, IDLE usw.

Das IDLE-Signal dient zum Framing von Multibyte-Empfängen (ein häufiges Problem für USART, insbesondere in lauten Umgebungen). Es wird aktiviert, wenn die Empfangsleitung für eine gewisse Entprellzeit (bestimmt durch die Baudrate/Oversampling-Einstellungen) hoch (oder „idle“) aktiviert wurde, nachdem diese Leitung aktiv war (während des Empfangs einer Gruppe von einem oder mehreren Bytes). . Dies ist nützlich, da Sie damit Ihren Empfangspuffer auf den Index '0' zurücksetzen können, damit der nächste Frame richtig aufgereiht wird (auch wenn im aktuellen Frame zu wenige oder zu viele Bytes empfangen wurden). Normalerweise müssen Sie diese Art von Logik mit einem dedizierten Timer-Peripheriegerät implementieren, aber STM32 packt es bequem in seine USART-Peripheriegeräte (obwohl es vom nativen HAL-Treiber nicht unterstützt wird).

Wenn Sie wirklich möchten, dass nur das Leerlaufsignal einen Interrupt auslöst, müssen Sie jedes andere Interrupt-Signal manuell deaktivieren. Wenn Sie einen nützlichen Interrupt-gesteuerten UART-Empfänger wollen, schlage ich nicht vor, dass Sie das tun.

Aus einer Ihrer vorherigen Fragen habe ich Ihnen einige Links gegeben, wo dies implementiert ist.

Quellcode

USART3_IRQHandler(void) {
    /* Check for IDLE line interrupt */
    if (LL_USART_IsEnabledIT_IDLE(USART3) && LL_USART_IsActiveFlag_IDLE(USART3)) {
        LL_USART_ClearFlag_IDLE(USART3);        /* Clear IDLE line flag */
        usart_rx_check();                       /* Check for data to process */
    }

    /* Implement other events when needed */
}
Ich habe mir den gesamten Quellcode in diesem Link angesehen, bevor ich meinen Code geschrieben habe, aber der IDLE-Interrupt-Trigger, wenn der RS485-Tranceiver den Sendemodus startet, weiß ich nicht warum?
Nach dieser Funktion IDLE-Interrupt-Trigger; void HAL_UART_TxCpltCallback(UART_HandleTypeDef huart) {HAL_UART_DMAStop(&huart2); dmaTransmitCompletedFlag = 1; RS485_Set_Receive_Mode(); HAL_UART_Receive_DMA(&huart2,(uint8_t )dma_rx_buf,DMA_BUF_SIZE); waitForTransmittingData = 0; }