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