STM32F4 последовательный флаг RXNE

Я пытаюсь получить серийный номер на stm32f411.

Я решил следить за флагом RXNE, чтобы проверить последовательный буфер. Я могу заставить флаг работать, однако проблема в том, что я не думаю, что он работает полностью.

Я настроил тест для увеличения счетчика в зависимости от того, сколько раз мне нужно прочитать регистр DR. Проблема в том, что я не могу заставить его увеличивать счетчик более одного раза. Чтобы проверить это, я просто сделал цикл для включения светодиода в зависимости от того, сколько раз я обращался к регистру DR. Максимум, который я могу заставить светодиод мигать, составляет 2 раза. Моя логика в моем коде неверна?

/* 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 */
}
Установите параметры компилятора на отсутствие оптимизации и посмотрите, сработает ли это для вас. Я не вижу ничего ужасно неправильного в логике, но я вижу много мест, где компилятор может оптимизировать ваш код таким образом, что он не будет делать то, что, по вашему мнению, он должен делать.
У вас есть huartи не huart1в вашем основном цикле, он вообще компилируется?
Плохо... На самом деле я немного объединил свой код, чтобы сделать его более кратким для облегчения чтения. Да, компилируется. В исходном коде чтение DR и приращение находилось в отдельной функции, которая принимала обработчик usart.

Ответы (1)

Ваш код написан с неявным предположением о последовательном FIFO, но этот FIFO имеет только 1-кратную глубину в аппаратном обеспечении и не был расширен до большего размера в программном обеспечении.

Первый элемент вашего while()цикла проверяет, был ли получен символ, и если да, то он увеличивает ваш счетчик, но он может увеличить его только один раз.

Затем ваш код входит в блокирующий цикл слива, который не выйдет, пока счетчик не будет сброшен до нуля.

Во время цикла блокировки слива может быть получено любое количество последовательных символов, но поскольку аппаратное обеспечение имеет только один регистр хранения, аппаратное обеспечение может указывать только несколько отдельных вещей:

  1. Персонаж не получен
  2. Был получен один персонаж
  3. Был получен символ, а затем регистр переполнился, потому что другой был получен до того, как он был очищен.
  4. Произошла ошибка серийного форматирования, с некоторыми из этих других вещей или без них.

Когда ваш код, проверяющий серийный номер, запускается снова, он может правильно интерпретировать только первые два из этих состояний, поэтому единственное, что он может сделать, это увеличить счетчик на единицу или нет - никакое другое увеличение невозможно .

Если вы хотите подсчитать символы, поступающие во время мигания блокирующего светодиода, вам нужно будет использовать последовательное прерывание приема. Или вы можете сделать мигание светодиода в неблокирующем конечном автомате, в цикле, который также опрашивает последовательный порт.

Разве флаг не будет установлен до тех пор, пока последовательная строка не будет сделана и не будет прочитана в регистр DR X раз (X - это длина строки, таким образом увеличивая X раз)? Это предположение я сделал. Это плохое предположение? Нужно ли мне заранее вычислять количество полученных байтов?
UART не имеет понятия «строки». Потратьте некоторое время на лист данных или руководство программиста, чтобы понять строгое, ограниченное значение его флагов. В основном он может содержать один полный символ, который вы еще не забрали, но если он закончит получать другой до того, как вы это сделаете, вы потеряете данные. Существуют чипы с более глубокими аппаратными FIFO, но я не верю, что это один из них, или, по крайней мере, вы не используете его в режиме, который использовал бы такие возможности.