STM32 C++ 和重定向 std::cout 到 UART
STM32 C++ and Retargeting std::cout to UART
我在尝试 std::cout 使用 STM32CubeIDE(通常是标准安装的 STM32CubeIDE 的标准安装包)在 STM32 上工作时遇到问题。
为了 stdio.h 和 printf 的目的,我查阅了许多有关重定向 UART 的资源,但我正在尝试使用 std::cout 使这一切在 C++ 环境中工作。我找到的主要来源在这里:https://www.keil.com/support/man/docs/armlib/armlib_chr1358938931411.htm
根据包含 headers 的方式和时间,我会遇到不同的错误,这是我尝试过的方法:
retarget.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++.3.1\ext\string_conversions.h:43,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\bits\basic_string.h:6557,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\string:55,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\bits\locale_classes.h:40,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\bits\ios_base.h:41,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\ios:42,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\ostream:38,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\iostream:39,
from ../Core/Src/main.cc:26:
c:{stm32 tools path snipped}arm-none-eabi\include\c++.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 文件中的 include 以便首先拉入 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++.3.1\cstdio:42,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\ext\string_conversions.h:43,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\bits\basic_string.h:6557,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\string:55,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\bits\locale_classes.h:40,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\bits\ios_base.h:41,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\ios:42,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\ostream:38,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.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
有什么建议吗?提前致谢。
终于偶然发现了解决方案,归结为 _write()
函数是如何编译的。这个函数必须用C编译器编译才能正常工作(据我所知)。
所以,解决方案,就对我有用的而言:
我将 retarget.cc
重命名回 retarget.c
(它保持 retarget.c
,除了 retarget.h
的包含路径外没有修改)。
对于 retarget.h
我使用了 retarget.h
的关联文件将函数原型包装在 extern "C":"
#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;
我在尝试 std::cout 使用 STM32CubeIDE(通常是标准安装的 STM32CubeIDE 的标准安装包)在 STM32 上工作时遇到问题。
为了 stdio.h 和 printf 的目的,我查阅了许多有关重定向 UART 的资源,但我正在尝试使用 std::cout 使这一切在 C++ 环境中工作。我找到的主要来源在这里:https://www.keil.com/support/man/docs/armlib/armlib_chr1358938931411.htm
根据包含 headers 的方式和时间,我会遇到不同的错误,这是我尝试过的方法:
retarget.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++.3.1\ext\string_conversions.h:43,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\bits\basic_string.h:6557,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\string:55,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\bits\locale_classes.h:40,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\bits\ios_base.h:41,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\ios:42,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\ostream:38,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\iostream:39,
from ../Core/Src/main.cc:26:
c:{stm32 tools path snipped}arm-none-eabi\include\c++.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 文件中的 include 以便首先拉入 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++.3.1\cstdio:42,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\ext\string_conversions.h:43,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\bits\basic_string.h:6557,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\string:55,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\bits\locale_classes.h:40,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\bits\ios_base.h:41,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\ios:42,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.3.1\ostream:38,
from c:{stm32 tools path snipped}arm-none-eabi\include\c++.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
有什么建议吗?提前致谢。
终于偶然发现了解决方案,归结为 _write()
函数是如何编译的。这个函数必须用C编译器编译才能正常工作(据我所知)。
所以,解决方案,就对我有用的而言:
我将 retarget.cc
重命名回 retarget.c
(它保持 retarget.c
,除了 retarget.h
的包含路径外没有修改)。
对于 retarget.h
我使用了 retarget.h
的关联文件将函数原型包装在 extern "C":"
#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;