常见开发环境下printf重定向方法

本文介绍常见开发环境下printf重定向方法。

串口作为调试接口在MCU开发过程中经常用到,为了方便格式化输出(使用printf函数),我们需要printf进行重定向输出到串口,通过串口调试软件打印调试信息,方便我们查找问题。本文针对常见开发环境(gcc,Keil,IAR,CrossWorks for ARM),介绍printf重定向的方法。

1.gcc开发环境

新建“syscalls.c”,添加如下内容。

#if !defined(__CROSSWORKS_ARM) && defined(__GNUC__)

#include <sys/stat.h>
#include <stddef.h>


int _close(int file);
void _exit(int status);
int _fstat(int file, struct stat *st);
int _getpid(void);
int _isatty(int file);
int _kill(int pid, int sig);
int _lseek(int file, int ptr, int dir);
int _read(int file, char *ptr, int len);
int _write(int file, const char *ptr, int len);

/**************************************************************************//**
 * Close a file.
 *
 * @param[in] file  File you want to close.
 *
 * @return  Returns 0 when the file is closed.
 *****************************************************************************/
int _close(int file)
{
  (void) file;
  return 0;
}

/**************************************************************************//**
 * Exit the program.
 *
 * @param[in] status The value to return to the parent process as the
 *            exit status (not used).
 *****************************************************************************/
void _exit(int status)
{
  (void) status;
  while (1) {
  }                 // Hang here forever...
}

/**************************************************************************//**
 * Status of an open file.
 *
 * @param[in] file  Check status for this file.
 *
 * @param[in] st    Status information.
 *
 * @return  Returns 0 when st_mode is set to character special.
 *****************************************************************************/
int _fstat(int file, struct stat *st)
{
  (void) file;
  st->st_mode = S_IFCHR;
  return 0;
}

/**************************************************************************//**
 * Get process ID.
 *
 * @return  Return 1 when not implemented.
 *****************************************************************************/
int _getpid(void)
{
  return 1;
}

/**************************************************************************//**
 * Query whether output stream is a terminal.
 *
 * @param[in] file  Descriptor for the file.
 *
 * @return  Returns 1 when query is done.
 *****************************************************************************/
int _isatty(int file)
{
  (void) file;
  return 1;
}

/**************************************************************************//**
 * Send signal to process.
 *
 * @param[in] pid Process id (not used).
 *
 * @param[in] sig Signal to send (not used).
 *****************************************************************************/
int _kill(int pid, int sig)
{
  (void)pid;
  (void)sig;
  return -1;
}

/**************************************************************************//**
 * Set position in a file.
 *
 * @param[in] file  Descriptor for the file.
 *
 * @param[in] ptr   Poiter to the argument offset.
 *
 * @param[in] dir   Directory whence.
 *
 * @return  Returns 0 when position is set.
 *****************************************************************************/
int _lseek(int file, int ptr, int dir)
{
  (void) file;
  (void) ptr;
  (void) dir;
  return 0;
}

/**************************************************************************//**
 * Read from a file.
 *
 * @param[in] file  Descriptor for the file you want to read from.
 *
 * @param[in] ptr   Pointer to the chacaters that are beeing read.
 *
 * @param[in] len   Number of characters to be read.
 *
 * @return  Number of characters that have been read.
 *****************************************************************************/
int _read(int file, char *ptr, int len)
{
  (void)file;

  return readBuffer(ptr, len);
}

/**************************************************************************//**
 * Write to a file.
 *
 * @param[in] file  Descriptor for the file you want to write to.
 *
 * @param[in] ptr   Pointer to the text you want to write
 *
 * @param[in] len   Number of characters to be written.
 *
 * @return  Number of characters that have been written.
 *****************************************************************************/
int _write(int file, const char *ptr, int len)
{
  (void)file;

  return writeBuffer(ptr, len);
}

#endif /* !defined( __CROSSWORKS_ARM ) && defined( __GNUC__ ) */

在自己的程序中,只需实现:

int writeBuffer(char *ch, int length);
int readBuffer(char *ch, int length);

2.Keil开发环境

1)方法1

在Keil中勾选“use MicroLib”。

#if defined(__CC_ARM)

#include <stdio.h>


/**************************************************************************//**
 * Writes character to file
 *
 * @param[in] f   File
 *
 * @param[in] ch  Character
 *
 * @return  Written character
 *****************************************************************************/
int fputc(int ch, FILE *f)
{
  return putChar(ch);
}

/**************************************************************************//**
 * Reads character from file
 *
 * @param[in] f File
 *
 * @return  Character
 *****************************************************************************/
int fgetc(FILE *f)
{
  return getChar();
}


#endif /* defined( __CC_ARM ) */

 在自己的程序中,只需实现:

int putChar(char ch);
int getChar(void);

2)方法2

非半主机模式,新建“syscalls.c”,添加如下内容。

#if defined(__CC_ARM)
/******************************************************************************/
/* RETARGET.C: 'Retarget' layer for target-dependent low-level functions      */
/******************************************************************************/
/* This file is part of the uVision/ARM development tools.                    */
/* Copyright (c) 2005-2006 Keil Software. All rights reserved.                */
/* This software may only be used under the terms of a valid, current,        */
/* end user licence from KEIL for a compatible version of KEIL software       */
/* development tools. Nothing else gives you the right to use this software.  */
/******************************************************************************/

#include <stdio.h>

#pragma import(__use_no_semihosting_swi)

struct __FILE{
  int handle;
};

//Standard output stream
FILE __stdout;

/**************************************************************************//**
 * Writes character to file
 *
 * @param[in] f   File
 *
 * @param[in] ch  Character
 *
 * @return  Written character
 *****************************************************************************/
int fputc(int ch, FILE *f)
{
  return putChar(ch);
}

/**************************************************************************//**
 * Reads character from file
 *
 * @param[in] f File
 *
 * @return  Character
 *****************************************************************************/
int fgetc(FILE *f)
{
  return getChar();
}

/**************************************************************************//**
 * Tests the error indicator for the stream pointed to by file
 *
 * @param[in] f File
 *
 * @return  Returns non-zero if it is set
 *****************************************************************************/
int ferror(FILE *f)
{
  // Your implementation of ferror
  return EOF;
}

/**************************************************************************//**
 * Writes a character to the console
 *
 * @param[in] ch  Input character
 *****************************************************************************/
void _ttywrch(int ch)
{
  putChar(ch);
}

/**************************************************************************//**
 * Library exit function. This function is called if stack overflow occurs.
 *
 * @param[in] return_code Return code
 *****************************************************************************/
void _sys_exit(int return_code)
{
  label:  goto label; // endless loop
}

#endif /* defined( __CC_ARM ) */

 在自己的程序中,只需实现:

int putChar(char ch);
int getChar(void);

3.IAR开发环境

新建“syscalls.c”,添加如下内容。

#if defined(__ICCARM__)
/*******************
 *
 * Copyright 1998-2003 IAR Systems.  All rights reserved.
 *
 * $Revision: 38614 $
 *
 * This is a template implementation of the "__write" function used by
 * the standard library.  Replace it with a system-specific
 * implementation.
 *
 * The "__write" function should output "size" number of bytes from
 * "buffer" in some application-specific way.  It should return the
 * number of characters written, or _LLIO_ERROR on failure.
 *
 * If "buffer" is zero then __write should perform flushing of
 * internal buffers, if any.  In this case "handle" can be -1 to
 * indicate that all handles should be flushed.
 *
 * The template implementation below assumes that the application
 * provides the function "MyLowLevelPutchar".  It should return the
 * character written, or -1 on failure.
 *
 ********************/

#include <yfuns.h>
#include <stdint.h>

_STD_BEGIN

/**************************************************************************//**
 * Write to.
 *
 * @param[in] handle  Handle
 *
 * @param[in] buffer  Pointer to the buffer you want to write
 *
 * @param[in] size    Number of characters to be written.
 *
 * @return  Number of characters that have been written.
 *
 * @note  If the __write implementation uses internal buffering, uncomment
 *        the following line to ensure that we are called with "buffer" as 0
 *        (i.e. flush) when the application terminates.
 *****************************************************************************/
size_t __write(int handle, const unsigned char * buffer, size_t size)
{
  // Remove the #if #endif pair to enable the implementation

  if (buffer == 0) {
    // This means that we should flush internal buffers.  Since we
    // don't we just return.  (Remember, "handle" == -1 means that all
    // handles should be flushed.)
    return 0;
  }

  // This template only writes to "standard out" and "standard err",
  // for all other file handles it returns failure.
  if (handle != _LLIO_STDOUT && handle != _LLIO_STDERR) {
    return _LLIO_ERROR;
  }

  return writeBuffer(buffer, size);
}

/**************************************************************************//**
 * Read from.
 *
 * @param[in] handle  Handle
 *
 * @param[in] buffer   Pointer to the characters that have been read.
 *
 * @return  Number of characters that have been read.
 *****************************************************************************/
size_t __read(int handle, unsigned char * buffer, size_t size)
{
  // This template only reads from "standard in", for all other file
  // handles it returns failure.
  if (handle != _LLIO_STDIN) {
    return _LLIO_ERROR;
  }

  return readBuffer(buffer, size);
}

_STD_END

#endif /* defined( __ICCARM__ ) */

在自己的程序中,只需实现:

int writeBuffer(char *ch, int length);
int readBuffer(char *ch, int length);

4.CrossWorks for ARM开发环境

#if defined(__CROSSWORKS_ARM)

/**************************************************************************//**
 * Write a character.
 *
 * @param[in] ch  character
 *
 * @return  1
 *****************************************************************************/
int __putchar(int ch)
{
  return putChar(ch);
}

/**************************************************************************//**
 * Read a character.
 *
 * @return  Character read
 *****************************************************************************/
int __getchar(void)
{
  return getChar();
}

#endif /* defined( __CROSSWORKS_ARM ) */

在自己的程序中,只需实现:

int putChar(char ch);
int getChar(void);

总结,本文介绍了常见开发环境下printf重定向方法。

  • 5
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
printf重定向是指将printf函数的输出从默认的显示器改为其他设备或文件。在C语言中,可以通过重定义fputc函数来实现printf重定向。具体来说,可以通过重定义fputc函数将printf的输出重定向到串口、文件或其他设备上。 示例代码中使用了freopen函数来实现printf重定向。首先,通过调用freopen函数将标准输出(stdout)重定向到指定的文件或设备。例如,可以将printf的输出重定向到USART1串口,这样就可以将单片机的数据打印到PC上的超级终端或串口调试助手。然后,通过再次调用freopen函数将标准输出恢复为默认的显示器。 需要注意的是,重定义fputc函数是实现printf重定向的关键。在重定义的fputc函数中,可以将printf的输出数据重定向到指定的设备或文件,例如将数据重定向到ITM端口。 总结起来,printf重定向是通过重定义fputc函数来实现的,可以将printf的输出从默认的显示器改为其他设备或文件。 #### 引用[.reference_title] - *1* [printf函数的重定向](https://blog.csdn.net/weixin_51121577/article/details/127337297)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [printf重定向的相关总结](https://blog.csdn.net/gogo0707/article/details/124652111)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^control_2,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值