Search code examples
cembeddedstm32stm32cubeide

Error in reading using HAL_UART_Receive_IT in STM32


I have the following program, which is to read the string "on" and "off" sent by terminal to the board STM32F429IDISC1, this will read the string sent and if it is an "on" lights the led, if it is an "off" should turn off the led:

int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

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

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

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

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */
  //uint8_t data;
  uint8_t LED_status = GPIO_PIN_RESET;
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  char buffer[5];
  while (1)
  {
        HAL_UART_Receive_IT(&huart1, (uint8_t *) buffer, 5);
        printf("Received buffer: %s\r\n", buffer);
        if (strncmp(buffer, "on", 2U) == 0 && LED_status == GPIO_PIN_RESET)
        {
            HAL_GPIO_WritePin(USER_LED_GPIO_Port, USER_LED_Pin, GPIO_PIN_SET);
            LED_status = GPIO_PIN_SET;
            printf("LED turned on\r\n");
        } else if (strncmp(buffer, "off", 3U) == 0 && LED_status == GPIO_PIN_SET)
        {
            HAL_GPIO_WritePin(USER_LED_GPIO_Port, USER_LED_Pin, GPIO_PIN_RESET);
            LED_status = GPIO_PIN_RESET;
            printf("LED turned off\r\n");
        }
        memset(buffer, 0, sizeof(buffer));
        HAL_Delay(1000);
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
  }
  /* USER CODE END 3 */
}

when I send the message through the terminal the program reads it and prints it on the screen, if I send an "ON" the program has no problem to recognize it and turn on the LED, but when I send an "OFF" sometimes it does not read it completely and it prints only the last character, in the same way it will not turn off the LED when it does not recognize the OFF, to turn it off I have to send it several times "off" until it reads it correctly.

Terminal console

I thought that using the functionHAL_UART_Receive_IT could avoid reading interruptions by giving priority to the process but this did not work.


Solution

  • HAL_UART_Receive_IT() returns immediately - it does not wait for any characters to be received. It configures the hardware to receive bytes into your buffer in the background. So checking the contents of the buffer after it returns is pointless, as you have no idea if any characters have been received yet.

    You could check the status of the UART to see if it is still busy or not. But since you have asked for 5 characters, it will be busy until it has received all 5. This doesn't match with your expected input of "on" or "off", which have less characters than that.

    As it is, you are not checking the return value from HAL_UART_Receive_IT() at all. If you were, you would see that it is mostly returning HAL_BUSY, since you are spinning in a tight loop calling that function while it is already trying to receive.

    Lastly, you are clearing your buffer with memset(buffer, 0, sizeof(buffer)); every time around the loop. So you might have received the 'o' from a string, but then you overwrite it with zero. The only way your code can ever do anything is if it receives all the characters of a string within the time it takes your loop to spin around.

    Using the interrupt driven receive routine here is pointless (and probably harmful, if you don't know what you are doing). Just use the regular polling routine. Here's some (completely untested) code that might be closer to what you want:

    #define BUFF_LEN 8
    
    char buff[BUFF_LEN];
    
    int ix = 0;
    
    for (;;)
    {
        HAL_StatusTypeDef status;
        uint8_t ch;
    
        status = HAL_UART_Receive(&huart1, &ch, 1, 1000); // 1000 ms timeout
        
        if (status == HAL_OK)
        {
            // Got a character
            if (ch == '\n')
            {
                // Parse the string in 'buff'
                if (strncmp(buff, "on", ix) == 0)
                {
                    // Do the on thing
                }
                else if (strncmp(buff, "off", ix) == 0)
                {
                    // Do the off thing
                }
                else
                {
                    // It was something else
                }
    
                ix = 0;
            }
            else if (ix < BUFF_LEN)
            {
                buff[ix] = ch;
                ++ix;
            }
            else
            {
                // Buffer is full
            }
        }
        else if (status == HAL_ERROR)
        {
            // Handle error
        }
    }