STM32 C++ 和重定向 std::cout 到 UART

STM32 C++ and Retargeting std::cout to UART

提问人:Andrew Ressa 提问时间:3/12/2022 最后编辑:Andrew Ressa 更新时间:3/15/2022 访问量:1824

问:

我尝试使用 STM32CubeIDE(通常是软件包中 STM32CubeIDE 的标准安装)在 STM32 上工作时遇到问题。

我已经查看了许多关于为 stdio.h 和 printf 目的重定向 UART 的来源,但我试图使用 std::cout 在 C++ 环境中让这一切正常工作。我找到的主要来源是这里:https://www.keil.com/support/man/docs/armlib/armlib_chr1358938931411.htm

根据我包含标题的方式和时间,我收到不同的错误,这是我尝试过的:

重定向.h:

#ifndef _RETARGET_H__
#define _RETARGET_H__

#include "stm32f1xx_hal.h"
#include <sys/stat.h>
#include <stdio.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);


namespace std {

int fputc(int, FILE *);

}

#endif //#ifndef _RETARGET_H__

retarget.cc(略微删减)[更正了这是一个 c++ 文件]

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 _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;
}

namespace std {

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. */
};
FILE __stdout;
FILE __stdin;
FILE __stderr;


int fputc(int c, FILE *stream)
{
      char tOut = c;

      return _write(STDOUT_FILENO, &tOut, 1);

  /* Your implementation of fputc(). */
}

}

和 main.cpp(也被剪掉了一点):

#include "retarget.h"
#include <iostream>

int main(void)
{
  /* HAL Init stuff Clipped */
  RetargetInit(&huart1);
  std::cout << "\n\nSTM32 main.c Startup\n" << std::endl;

  while(1){
      std::cout << "*";

      HAL_Delay(1000);
  }
}

如果我去 printf(更改为 std::cout 到 printf),一切正常,所以 _write 函数可以正常工作以发送到 UART,所以我知道很多事情都在工作。

现在,谈谈错误。

如上所述,编译器抛出:

In file included from c:{stm32 tools path snipped}arm-none-eabi\include\c++\10.3.1\ext\string_conversions.h:43,
                 from c:{stm32 tools path snipped}arm-none-eabi\include\c++\10.3.1\bits\basic_string.h:6557,
                 from c:{stm32 tools path snipped}arm-none-eabi\include\c++\10.3.1\string:55,
                 from c:{stm32 tools path snipped}arm-none-eabi\include\c++\10.3.1\bits\locale_classes.h:40,
                 from c:{stm32 tools path snipped}arm-none-eabi\include\c++\10.3.1\bits\ios_base.h:41,
                 from c:{stm32 tools path snipped}arm-none-eabi\include\c++\10.3.1\ios:42,
                 from c:{stm32 tools path snipped}arm-none-eabi\include\c++\10.3.1\ostream:38,
                 from c:{stm32 tools path snipped}arm-none-eabi\include\c++\10.3.1\iostream:39,
                 from ../Core/Src/main.cc:26:
c:{stm32 tools path snipped}arm-none-eabi\include\c++\10.3.1\cstdio:111:11: error: 'int fputc(int, FILE*)' conflicts with a previous declaration
  111 |   using ::fputc;
      |           ^~~~~
In file included from ../Core/Src/main.cc:25:
../Core/Inc/retarget.h:23:5: note: previous declaration 'int std::fputc(int, FILE*)'
   23 | int fputc(int, FILE *);
      |     ^~~~~
make: *** [Core/Src/subdir.mk:41: Core/Src/main.o] Error 1 

如果我翻转 main.cc 文件中的包含,以便首先拉入 iostream,我会得到:

In file included from ../Core/Src/main.cc:26:
../Core/Inc/retarget.h:23:22: error: 'int std::fputc(int, FILE*)' conflicts with a previous declaration
   23 | int fputc(int, FILE *);
      |                      ^
In file included from c:{stm32 tools path snipped}arm-none-eabi\include\c++\10.3.1\cstdio:42,
                 from c:{stm32 tools path snipped}arm-none-eabi\include\c++\10.3.1\ext\string_conversions.h:43,
                 from c:{stm32 tools path snipped}arm-none-eabi\include\c++\10.3.1\bits\basic_string.h:6557,
                 from c:{stm32 tools path snipped}arm-none-eabi\include\c++\10.3.1\string:55,
                 from c:{stm32 tools path snipped}arm-none-eabi\include\c++\10.3.1\bits\locale_classes.h:40,
                 from c:{stm32 tools path snipped}arm-none-eabi\include\c++\10.3.1\bits\ios_base.h:41,
                 from c:{stm32 tools path snipped}arm-none-eabi\include\c++\10.3.1\ios:42,
                 from c:{stm32 tools path snipped}arm-none-eabi\include\c++\10.3.1\ostream:38,
                 from c:{stm32 tools path snipped}arm-none-eabi\include\c++\10.3.1\iostream:39,
                 from ../Core/Src/main.cc:25:
c:{stm32 tools path snipped}arm-none-eabi\include\stdio.h:214:5: note: previous declaration 'int fputc(int, FILE*)'
  214 | int fputc (int, FILE *);
      |     ^~~~~
make: *** [Core/Src/subdir.mk:41: Core/Src/main.o] Error 1

有什么建议吗?提前致谢。

C++ ARM STM32 IOstream COUT

评论

1赞 KamilCuk 3/12/2022
namespace std {为什么要在 C 源文件中对命名空间 std 做任何事情? 这是您的IDE,无关紧要。你用的是什么编译器? 是的,对于 Keil ARM C/C++ 编译器。你在使用它吗?我怀疑您正在使用 GCC 和 newlib,在这种情况下 embecosm.com/appnotes/ean9/ean9-howto-newlib-1.0.html#id2719973an STM32 using the STM32CubeIDEThe prime source
0赞 Andrew Ressa 3/14/2022
对不起,文件名中有错别字。这些是C++源文件(retarget.cc 和 main.cc),它们是使用 g++ 编译的。我必须研究 newlib,我从我所看到的任何东西中都没有意识到这一点。
0赞 KamilCuk 3/14/2022
这回答了你的问题吗?您如何从 Newlib 在 GCC 中实现 printf?
0赞 Andrew Ressa 3/14/2022
查看链接的 newlib 移植指南,我已经实现了_write(这使得 printf 工作)。我试着复制它来写(没有下划线),但没有任何区别。我注意到的一件事是,printf 在使用 g++(在 c++ 文件中)编译时也不起作用,但在使用 gcc(使用 c 文件)编译时可以正常工作。
0赞 Andrew Ressa 3/14/2022
您发布的第二个链接也无济于事。我专门想让 std::cout 工作。我有 printf() 工作正常(使用 C 文件和 gcc 时),但是当我使用 g++ 编译时(使用 c++ 文件时),没有任何工作(printf 或 std::cout)。

答:

0赞 Andrew Ressa 3/15/2022 #1

最后偶然发现了解决方案,归结为函数的编译方式。这个函数必须用 C 编译器编译才能正常工作(据我所知)。_write()

所以,就对我而言,解决方案是:

我重命名为(它仍然是 retarget.c,除了 include 路径外未修改)。retarget.ccretarget.cretarget.h

因为我使用了 retarget.h 的关联文件,将函数原型包装在 extern “C”:”retarget.h

#ifndef _RETARGET_H__
#define _RETARGET_H__

#include "stm32f1xx_hal.h"
#include <sys/stat.h>
#include <stdio.h>

#ifdef __cplusplus
extern "C"
{
#endif

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);

#ifdef __cplusplus
} //extern "C"
#endif

#endif //#ifndef _RETARGET_H__

现在一切都按预期工作——std::cout << "Working now!" << std::endl;