cancel
Showing results for 
Search instead for 
Did you mean: 

stm32 use scanf with usart

VYoun
Associate III

Hello,

There is an example to use printf with usart. However, I need to find a way to use scanf with usart. I am using STM32H7, STM32Cubemx, and Atollic Truestudio.

Your help is much appreciated.

10 REPLIES 10
Olivier GALLIEN
ST Employee

Hi @VYoun​ ,

I know there is this exemple on MP1 Firmware package :

STM32Cube_FW_MP1_V1.2.0\Projects\STM32MP157C-DK2\Examples\UART\UART_Receive_Transmit_Console

Don't know if it has been ported to over MCU but might be fast forward to adapt to H7.

Hope it help,

Olivier

Olivier GALLIEN
In order to give better visibility on the answered topics, please click on 'Accept as Solution' on the reply which solved your issue or answered your question.

Hello @Community member​ 

thank you very much for your answer, I will check right now.

Best regards,

Vouria

See

STM32Cube_FW_H7_V1.7.0\Projects\STM32H743I-EVAL\Examples\BSP\SW4STM32\syscalls.c

Implementation of plumbing using __io_putchar() __io_getchar() which would support putchar(), getchar(), scanf(), etc

You'd need to a) initialize the UART you plan on using and b) implement the __io_put/getchar functions

In a general GNU/GCC sense the functionality comes out of the _write() / _read() implementation you provide

Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

Thank you very much for your answer Clive,

I will check right now.

Best regards,

Vouria

KnarfB
Principal III

Keep in mind, that there is no stream buffering in the hardware or HAL driver, execpt you implement it.

When scanf is implemented straightforward using _read, you must always call scanf *before* there is any input on the RX line or you will get overrun errors.

... and don't forget to remove the stdio internal buffering. A plain call

int i;
  scanf("%d",i);

ends up a in call to _read with a 1024 (BUFSIZ) char buffer! I.e. _read won't return before the UART supplied 1024 chars of input. This is not what you typically want for an interactive comm. You may remove that buffering by using

setvbuf( stdin, NULL, _IONBF, 0 );
  scanf("%d",i);

which results in calls to _read single char by single char.

Anyway, I would prefer collecting a string manually using USART functions and then using sscanf on it.

Hello @KnarfB​ ,

Thank you very much for your reply. I tried the code that you provided but unfortunately I got no results.

I am coming to believe that it is not possible to use scanf with usart. I think I should use usart interrupt and then parse the received string. I am really lost in using scanf with usart.

Thank you again Clive, I checked the syscalls.c with my own syscals.c and the __io_putchar() __io_getchar() have the same implementation.

Below is my __io_getchar() implementation

int __io_getchar(void)
{
	uint8_t ch = 0;
	// Clear the Overrun flag just before receiving the first character
	__HAL_UART_CLEAR_OREFLAG(&huart3);
 
	HAL_UART_Receive(&huart3, (uint8_t *)&ch, 1, 0xFFFF);
	//HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xFFFF);
	return ch;
}

Do you suggest a different implementation of __io_getchar()?

Thank you in advance

Thank you again Olivier,

I tried the example and used the code below from the example

#ifdef __GNUC__
	#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
	#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif  //__GNUC__
 
#ifdef __GNUC__
#define GETCHAR_PROTOTYPE int __io_getchar (void)
#else
#define GETCHAR_PROTOTYPE int fgetc(FILE * f)
#endif /* __GNUC__ */
 
GETCHAR_PROTOTYPE
{
  uint8_t ch = 0;
  // Clear the Overrun flag just before receiving the first character
  __HAL_UART_CLEAR_OREFLAG(&huart3);
 
  HAL_UART_Receive(&huart3, (uint8_t *)&ch, 1, 0xFFFF);
  HAL_UART_Transmit(&huart3, (uint8_t *)&ch, 1, 0xFFFF);
  return ch;
}

However, the example uses a special type of scanf which is implemented in the code. This scanf function is implemented in the code and has the following implementation:

int Serial_Scanf(char *ptr, int len)
{
 
  int DataIdx = 0;
  uint8_t thechar;
  thechar= ' ';
  while(thechar!= '\n' && thechar != '\r' && DataIdx<len)
  {
#ifdef __GNUC__
    thechar = __io_getchar();
 
#else
    thechar = fgetc(NULL);
#endif
  if ( thechar  >= 0xFF)
  {
    printf("\n\r  !!! Please enter a valid ASCII character \n");
    return 0xFF;
  }
  *ptr++ =thechar;
  DataIdx+=1;
  }
  return DataIdx;
} 

The problem with this scanf function is that the input length must be known. In my application this is not always known. However, I will try to utilize the above scanf function. I am happy to hear any suggestions. Thank you again for your help.

Best regards,

Vouria