Error in reading using HAL_UART_Receive_IT in STM32

huangapple go评论62阅读模式
英文:

Error in reading using HAL_UART_Receive_IT in STM32

问题

I understand your request. Here is the translated text:

我有以下程序,用于读取终端发送到STM32F429IDISC1板上的字符串"on""off",程序会读取发送的字符串,如果是"on"则点亮LED灯,如果是"off"则关闭LED灯

```c
int main(void)
{
  /* 用户代码开始 1 */

  /* 用户代码结束 1 */

  /* MCU 配置--------------------------------------------------------*/

  /* 复位所有外设,初始化闪存接口和SysTick。*/
  HAL_Init();

  /* 用户代码开始 初始化 */

  /* 用户代码结束 初始化 */

  /* 配置系统时钟 */
  SystemClock_Config();

  /* 用户代码开始 系统初始化 */

  /* 用户代码结束 系统初始化 */

  /* 初始化所有配置的外设 */
  MX_GPIO_Init();
  MX_USART1_UART_Init();
  /* 用户代码开始 2 */
  //uint8_t data;
  uint8_t LED_status = GPIO_PIN_RESET;
  /* 用户代码结束 2 */

  /* 无限循环 */
  /* 用户代码开始 循环 */
  char buffer[5];
  while (1)
  {
    HAL_UART_Receive_IT(&huart1, (uint8_t *) buffer, 5);
    printf("接收到的数据:%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已打开\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已关闭\r\n");
    }
    memset(buffer, 0, sizeof(buffer));
    HAL_Delay(1000);
    /* 用户代码结束 循环 */
  }
  /* 用户代码开始 3 */
  /* 用户代码结束 3 */
}

当我通过终端发送消息时,程序会读取它并在屏幕上打印出来。如果我发送"ON",程序能够正确识别并点亮LED灯,但是当我发送"OFF"时,有时它无法完全读取并只打印出最后一个字符。同样,当它无法识别"OFF"时,它也无法关闭LED灯,我必须多次发送"off"直到它正确读取为止。

终端控制台

我以为使用HAL_UART_Receive_IT函数可以避免读取中断,给予处理过程优先级,但这并没有起作用。

英文:

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.

答案1

得分: 0

HAL_UART_Receive_IT() 立即返回,不等待任何字符接收。它配置硬件在后台接收字节到您的缓冲区中。因此,在它返回后检查缓冲区的内容是没有意义的,因为您不知道是否已接收任何字符。

您可以检查UART的状态,以查看它是否仍然忙碌或不忙碌。但是,由于您要求接收5个字符,它将在接收所有5个字符之前保持忙碌。这与您期望的输入"on""off"不符,因为它们的字符数少于这个。

就目前而言,您根本没有检查HAL_UART_Receive_IT()的返回值。如果您这样做了,您会看到它大部分时间都返回HAL_BUSY,因为您在一个紧密的循环中调用该函数,而它已经在尝试接收。

最后,您在每次循环中使用memset(buffer, 0, sizeof(buffer)); 清除您的缓冲区。因此,您可能已经接收到一个字符串的'o',但然后用零覆盖它。只有在您的代码能够在循环中旋转的时间内接收到字符串的所有字符时,您的代码才能做任何事情。

在这里使用中断驱动的接收程序是没有意义的(如果您不知道自己在做什么,可能会有害)。只需使用常规的轮询程序。以下是一些(完全未经测试的)代码,可能更接近您想要的:

#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')
        {
            // 解析 'buff' 中的字符串
            if (strncmp(buff, "on", ix) == 0)
            {
                // 执行 "on" 操作
            }
            else if (strncmp(buff, "off", ix) == 0)
            {
                // 执行 "off" 操作
            }
            else
            {
                // 它是其他内容
            }

            ix = 0;
        }
        else if (ix < BUFF_LEN)
        {
            buff[ix] = ch;
            ++ix;
        }
        else
        {
            // 缓冲区已满
        }
    }
    else if (status == HAL_ERROR)
    {
        // 处理错误
    }
}

希望这能帮助您。

英文:

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 &quot;on&quot; or &quot;off&quot;, 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 &#39;o&#39; 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(&amp;huart1, &amp;ch, 1, 1000); // 1000 ms timeout
    
    if (status == HAL_OK)
    {
        // Got a character
        if (ch == &#39;\n&#39;)
        {
            // Parse the string in &#39;buff&#39;
            if (strncmp(buff, &quot;on&quot;, ix) == 0)
            {
                // Do the on thing
            }
            else if (strncmp(buff, &quot;off&quot;, ix) == 0)
            {
                // Do the off thing
            }
            else
            {
                // It was something else
            }

            ix = 0;
        }
        else if (ix &lt; BUFF_LEN)
        {
            buff[ix] = ch;
            ++ix;
        }
        else
        {
            // Buffer is full
        }
    }
    else if (status == HAL_ERROR)
    {
        // Handle error
    }
}

huangapple
  • 本文由 发表于 2023年5月7日 11:00:44
  • 转载请务必保留本文链接:https://go.coder-hub.com/76192016.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定