STM32串口printf函数重映射教程

目录

前言:

1.在Scr文件夹下建立retarget.c文件

2.在Inc文件夹下建立retarget.h文件

3.屏蔽syscalls.c文件

目录

前言:

方法1:

1.在Scr文件夹下建立retarget.c文件

2.在Inc文件夹下建立retarget.h文件

3.屏蔽syscalls.c文件

4.包含头文件

5.重新编译

方法2:

1.原理

2.打印中文乱码设置

3.不能打印浮点数设置

总结:


4.包含头文件

5.重新编译



前言:

 基于CubeIDE环境+HAL库实现,作为学习记录使用。

printf函数是C语言函数库中自带的函数,最初用于电脑上使用C语言时,将需要显示的内容通过C语言库中的fputc函数打印到电脑屏幕,不同的C库中的fputc指向的输出目标也不是一样的,所以需要重定向。

方法1:

1.在Scr文件夹下建立retarget.c文件

        在Scr文件夹下建立retarget.c文件,并插入以下代码

// All credit to Carmine Noviello for this code
// https://github.com/cnoviello/mastering-stm32/blob/master/nucleo-f030R8/system/src/retarget/retarget.c
 
#include <_ansi.h>
#include <_syslist.h>
#include <errno.h>
#include <sys/time.h>
#include <sys/times.h>
#include <limits.h>
#include <signal.h>
#include <../Inc/retarget.h>
#include <stdint.h>
#include <stdio.h>
 
#if !defined(OS_USE_SEMIHOSTING)
 
#define STDIN_FILENO  0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
 
UART_HandleTypeDef *gHuart;
 
void RetargetInit(UART_HandleTypeDef *huart) {
  gHuart = huart;
 
  /* Disable I/O buffering for STDOUT stream, so that
   * chars are sent out as soon as they are printed. */
  setvbuf(stdout, NULL, _IONBF, 0);
}
 
int _isatty(int fd) {
  if (fd >= STDIN_FILENO && fd <= STDERR_FILENO)
    return 1;
 
  errno = EBADF;
  return 0;
}
 
int _write(int fd, char* ptr, int len) {
  HAL_StatusTypeDef hstatus;
 
  if (fd == STDOUT_FILENO || fd == STDERR_FILENO) {
    hstatus = HAL_UART_Transmit(gHuart, (uint8_t *) ptr, len, HAL_MAX_DELAY);
    if (hstatus == HAL_OK)
      return len;
    else
      return EIO;
  }
  errno = EBADF;
  return -1;
}
 
int _close(int fd) {
  if (fd >= STDIN_FILENO && fd <= STDERR_FILENO)
    return 0;
 
  errno = EBADF;
  return -1;
}
 
int _lseek(int fd, int ptr, int dir) {
  (void) fd;
  (void) ptr;
  (void) dir;
 
  errno = EBADF;
  return -1;
}
 
int _read(int fd, char* ptr, int len) {
  HAL_StatusTypeDef hstatus;
 
  if (fd == STDIN_FILENO) {
    hstatus = HAL_UART_Receive(gHuart, (uint8_t *) ptr, 1, HAL_MAX_DELAY);
    if (hstatus == HAL_OK)
      return 1;
    else
      return EIO;
  }
  errno = EBADF;
  return -1;
}
 
int _fstat(int fd, struct stat* st) {
  if (fd >= STDIN_FILENO && fd <= STDERR_FILENO) {
    st->st_mode = S_IFCHR;
    return 0;
  }
 
  errno = EBADF;
  return 0;
}
 
#endif //#if !defined(OS_USE_SEMIHOSTING)

2.在Inc文件夹下建立retarget.h文件

        在Inc文件夹下建立retarget.h文件,并插入以下代码

// All credit to Carmine Noviello for this code
// https://github.com/cnoviello/mastering-stm32/blob/master/nucleo-f030R8/system/include/retarget/retarget.h
 
#ifndef _RETARGET_H__
#define _RETARGET_H__

 
#include "stm32f1xx_hal.h" //这里根据自己的单片机型号做修改
#include <sys/stat.h>
 
void RetargetInit(UART_HandleTypeDef *huart);
int _isatty(int fd);
int _write(int fd, char* ptr, int len);
int _close(int fd);
int _lseek(int fd, int ptr, int dir);
int _read(int fd, char* ptr, int len);
int _fstat(int fd, struct stat* st);

 
#endif //#ifndef _RETARGET_H__//如果使用cubeide生成会包含#ifnde   #define   #endif  需要去重复

3.屏蔽syscalls.c文件

        在Src文件夹下右键syscalls.c点击属性

        取消源码构建

4.包含头文件

        在主函数main.c文件下包含头文件,并将printf()函数映射到指定的串口

      包含头文件:  

#include "../inc/retarget.h"   //用于printf函数串口重映射

        printf()映射到指定的串口

RetargetInit(&huart1); //映射大UART1上

5.重新编译

       保存并 重新编译后即可使用printf()函数

方法2:

1.原理

先看源码:实际上printf()函数是调用extern int __io_putchar(int ch) __attribute__((weak));函数将字符一个一个的打印出来,但实际上这个函数并没有实现,需要我们自己实现

在main函数中添加


/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

int __io_putchar(int ch)
{
	HAL_UART_Transmit(huart1, (const uint8_t *)&ch, 1, 1000);
	return ch;
}

2.打印中文乱码设置

右键工程->属性按下图将编码改为GBK

3.不能打印浮点数设置

总结:

两种方法的实质是一样的,都是先指定串口再重写函数,方法1比较全面,方法只写了发送,比较简略,任君选择参考。

作者:th576951469

物联沃分享整理
物联沃-IOTWORD物联网 » STM32串口printf函数重映射教程

发表回复