STM32-HAL-printf redirection of serial port

1. Formatted output of C language

printf in C language is a standard library function used to output formatted data to a standard output device (usually a terminal)

  • Basic syntax:
int printf(const char *format, ...);

The first parameter const char *formatindicates the output format, and the following parameters are variable parameters, which are used to fill the placeholders in the format string.

  • Character output principle:
  1. const char *formatFormat string processing: the printf function parses the format placeholders in the first parameter, and then takes the values ​​in the variable parameters in turn according to the type and order of the placeholders, converts these values ​​into strings, and It is combined into the final output string in the order and style in the format string.
  2. Output string storage: The printf function stores the formatted output string in a memory buffer.
  3. Output string display: The printf function displays the output string in the memory buffer to the standard output device, usually the terminal.

When learning C language, when calling the header file #include "stdio.h", you can use the printf function to format and print

#include <stdio.h>

int a = 10;
char str[] = "hello,world!";
int main(void)
{
    
    
    printf("%s\n",str);
    printf("a = %d",a);  
    return 0;
}

[result]

hello,world!
a = 10

However, in Keil, the printing function of C language cannot be used directly in the use of stm32, and support settings need to be added, that is, the redirection of calling MDK's micro library (MicroLib) called printf. In fact, not only can print characters be redirected, but also get characters can be redirected.

2. Development preparation

  • Bear pie development board based on STM32L431RCT6
    insert image description here

  • A computer with Windows system and installed Cubemx and Keil MDK

3. Initialize on-chip peripherals

This development mainly introduces the redirection of the serial port, so it is necessary to initialize the serial port peripherals.

Set the serial communication as asynchronous communication, the baud rate is 115200
insert image description here

Generate code and select keil-MDK to open the project

4. Set redirection

4.1 Click the magic wand, then check Use MicroLIB
insert image description here

Introduction to MicroLIB:

​ MicroLIB is a C standard library provided by Keil, which is specially developed for embedded system design. Compared with the standard C library, the MicroLIB library is more lightweight and has a smaller code size, and is suitable for resource-constrained environments such as embedded systems. The MicroLIB library supports most of the functions of the ISO/ANSI C standard, and adds some functions commonly used in embedded systems, such as serial communication, GPIO control, etc. In MDK projects, developers can choose to use the MicroLIB library for development to reduce the code size and memory space of the program.

It should be noted that the MicroLIB library is not a complete C standard library, it only implements a part of the C standard functions, and the implementation of some functions may differ from the standard C library. If you need to use the functions of the standard C library or the C standard library with more complete functions, developers need to use other C standard libraries, such as GNU C Library (glibc), etc.

4.2 Add serial port redirection code

main.cAdd the header file in the function :

#include "stdio.h"

Add the following code inside the main.cfunction :/* USER CODE BEGIN 4 */

int fputc(int c,FILE *f)
{
    
    
    uint8_t ch;  //定义一个无符号8位整型变量ch 并将字符C赋值给它
    ch = c;
    HAL_UART_Transmit(&huart1,&ch,1,1000);
    // 调用HAL库的串口发送函数,将ch发送到USART1串口,等待时间为1000ms
    return c;
}

4.3 Add code in the main loop for testing

/* USER CODE BEGIN 2 */
	uint8_t str[] = "Hello GearLong!";
	uint8_t num1 = 10;
	float f = 3.1415926;
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    
    
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		printf("%s\r\n",str);
		printf("num = %d\r\n",num1);
		printf("f1 = %f\r\n",f);
		printf("f2 = %.2f\r\n",f);
		printf("f3 = %8.3f\r\n",f);
		HAL_Delay(1000);		
  }

4.4 Compile, download, and then open the serial port debugging assistant to view the execution

Remember to turn the AT switch to AT_MCU

insert image description here

4.5 Print data without using the micro library

The following code comes from the serial port printing in the HAL library code of punctual atoms, copy the code to the usart.cplace where the code is added, uncheck the micro library, and remove the redirection code that has been set above.

usart.cAdd the header file in the function :

#include "stdio.h"

Add the following code inside the usart.cfunction :/* USER CODE BEGIN 1 */

/* 加入以下代码, 支持printf函数, 而不需要选择use MicroLIB */

#if 1
#if (__ARMCC_VERSION >= 6010050)                    /* 使用AC6编译器时 */
__asm(".global __use_no_semihosting\n\t");          /* 声明不使用半主机模式 */
__asm(".global __ARM_use_no_argv \n\t");            /* AC6下需要声明main函数为无参数格式,否则部分例程可能出现半主机模式 */

#else
/* 使用AC5编译器时, 要在这里定义__FILE 和 不使用半主机模式 */
#pragma import(__use_no_semihosting)

struct __FILE
{
    
    
    int handle;
    /* Whatever you require here. If the only file you are using is */
    /* standard output using printf() for debugging, no file handling */
    /* is required. */
};

#endif

/* 不使用半主机模式,至少需要重定义_ttywrch\_sys_exit\_sys_command_string函数,以同时兼容AC6和AC5模式 */
int _ttywrch(int ch)
{
    
    
    ch = ch;
    return ch;
}

/* 定义_sys_exit()以避免使用半主机模式 */
void _sys_exit(int x)
{
    
    
    x = x;
}

char *_sys_command_string(char *cmd, int len)
{
    
    
    return NULL;
}

/* FILE 在 stdio.h里面定义. */
FILE __stdout;

/* 重定义fputc函数, printf函数最终会通过调用fputc输出字符串到串口 */
int fputc(int ch, FILE *f)
{
    
    
    while ((USART1->SR & 0X40) == 0);               /* 等待上一个字符发送完成 */
    
    USART1->DR = (uint8_t)ch;                       /* 将要发送的字符 ch 写入到DR寄存器 */	
    return ch;
}
#endif

注意In the HAL library code generated by Cubmex, USART1的相关寄存器it may change with different types of MCUs. If the compilation fails, it can be modified in time.

4.6 The results of the printouts are consistent
insert image description here

Guess you like

Origin blog.csdn.net/sinat_41690014/article/details/130273292