STM32F4 serielles RXNE-Flag

Ich versuche, Serien auf einem stm32f411 zu empfangen.

Ich beschloss, das RXNE-Flag zu überwachen, um den seriellen Puffer zu überprüfen. Ich kann das Flag zum Laufen bringen, aber das Problem ist, dass ich nicht glaube, dass es vollständig funktioniert.

Ich habe einen Test eingerichtet, um einen Zähler basierend darauf zu erhöhen, wie oft ich das DR-Register lesen muss. Das Problem ist, dass ich den Zähler nicht mehr als einmal erhöhen kann. Um dies zu überprüfen, habe ich einfach eine Schleife erstellt, um eine LED einzuschalten, je nachdem, wie oft ich auf das DR-Register zugegriffen habe. Das Maximum, mit dem ich die LED zum Blinken bringen kann, ist 2 Mal. Ist meine Logik in meinem Code falsch?

/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "stm32f4xx_hal.h"

/* USER CODE BEGIN Includes */

#include <stdbool.h>

/* USER CODE END Includes */

/* Private variables ---------------------------------------------------------*/
UART_HandleTypeDef huart1;

/* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/
uint8_t pdiddy_increment = 0;

int pdiddy[15];
/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
void Error_Handler(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

/* USER CODE END PFP */

/* USER CODE BEGIN 0 */

// detect if anything is in serial buffer
uint8_t Serial_Available(UART_HandleTypeDef *huart)
{
    uint32_t RX_State;

    RX_State = huart->Instance->SR & UART_FLAG_RXNE;

    //something is in the buffer 
    if (RX_State > 0)
    {
        return 1;
    }
    //nothing is there 
    return 0;
}
/* USER CODE END 0 */

int main(void)
{
  /* MCU Configuration----------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* Configure the system clock */
  SystemClock_Config();

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();

  while (1)
  {
      while (Serial_Available(&huart1))
      {
        /*read DR and put value in array*/
        /*Reading DR, increment shift*/
        pdiddy[pdiddy_increment] = (uint8_t)(huart->Instance->DR & (uint8_t)0x00FF);
        pdiddy_increment++;
     }

     while (pdiddy_increment > 0)
     {
       HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
       HAL_Delay(400);
       HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
       HAL_Delay(400);
       pdiddy_increment--;
     }
  }
  /* USER CODE END 3 */
}
Setzen Sie die Compileroptionen auf keine Optimierung und sehen Sie, ob das für Sie funktioniert. Ich sehe nichts Schlimmes an der Logik, aber ich sehe viele Stellen, an denen der Compiler Ihren Code so optimieren könnte, dass er nicht das tut, was Sie Ihrer Meinung nach tun sollten.
Sie haben huartund nicht huart1in Ihrer Hauptschleife, kompiliert sie überhaupt?
Mein Fehler ... Ich habe meinen Code tatsächlich ein wenig kombiniert, damit ich ihn zum leichteren Lesen prägnanter machen kann. Ja, es kompiliert. Im ursprünglichen Code befand sich das Lesen von DR und Inkrement in einer separaten Funktion, die den usart-Handler akzeptierte.

Antworten (1)

Ihr Code wurde mit der impliziten Annahme eines seriellen FIFO geschrieben, aber dieser FIFO ist nur 1-tief in der Hardware und wurde nicht auf eine größere Größe in der Software erweitert.

Das erste Element Ihrer while()Schleife prüft, ob ein Zeichen empfangen wurde, und erhöht in diesem Fall Ihren Zähler, kann ihn jedoch nur einmal erhöhen.

Als nächstes tritt Ihr Code in eine blockierende Drain-Schleife ein, die nicht verlassen wird, bis der Zähler auf Null geleert wurde.

Während der Blocking-Drain-Schleife könnten beliebig viele serielle Zeichen empfangen werden, aber da die Hardware nur ein einziges Halteregister hat, kann die Hardware nur wenige unterschiedliche Dinge anzeigen:

  1. Es wurde kein Zeichen empfangen
  2. Ein Zeichen wurde empfangen
  3. Ein Zeichen wurde empfangen und dann ist das Register übergelaufen, weil ein anderes empfangen wurde, bevor es geleert wurde.
  4. Ein serieller Formatierungsfehler ist aufgetreten, mit oder ohne einige dieser anderen Dinge.

Wenn Ihr Code, der die Seriennummer überprüft, erneut ausgeführt wird, kann er nur die ersten beiden dieser Zustände korrekt interpretieren - das einzige, was er möglicherweise tun kann, ist, den Zähler um eins zu erhöhen oder nicht - keine andere Erhöhung ist möglich .

Wenn Sie Zeichen zählen möchten, die während einer blockierenden LED-Blinksequenz eingehen, müssen Sie einen seriellen Empfangsinterrupt verwenden. Oder Sie könnten die LED in einer nicht blockierenden Zustandsmaschine blinken lassen, in einer Schleife, die auch die Seriennummer abfragt.

Würde das Flag nicht gesetzt, bis die serielle Zeichenfolge fertig ist und X-mal in das DR-Register eingelesen wird (wobei X die Länge der Zeichenfolge ist und somit X-mal inkrementiert wird)? Das ist die Annahme, die ich gemacht habe. Ist das eine schlechte Annahme? Muss ich vorher herausfinden, wie viele Bytes empfangen werden?
Der UART hat kein Konzept von "Strings". Verbringen Sie einige Zeit mit dem Datenblatt oder dem Programmierhandbuch, um die deutliche, begrenzte Bedeutung seiner Flags zu verstehen. Es kann im Grunde genommen einen vollständigen Charakter enthalten, den Sie noch nicht beansprucht haben, aber wenn es vor Ihnen einen anderen erhält, verlieren Sie Daten. Es gibt Chips mit tieferen Hardware-FIFOs, aber ich glaube nicht, dass dies einer von ihnen ist, oder zumindest betreiben Sie ihn nicht in einem Modus, der eine solche Fähigkeit nutzen würde.