前言

这看似是一篇烂大街的文章,但其实并非如此。

本文使用的环境非常特殊:STM32CubeMX + Clion

项目配置

本项目使用STM32F411CEU6,项目配置如下

项目代码生成配置使用STM32CubeIDE

测试代码

1
2
3
4
5
6
7
8
9
10
11
12
/* USER CODE BEGIN WHILE */
char hal_msg[] = "This is send by HAL\n";
while (1)
{

printf("HelloWorld\n");
HAL_UART_Transmit(&huart1,hal_msg,strlen(hal_msg),0xffff);
HAL_Delay(1000);
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
}

网络上的方案

先来尝试第一个方案

1
2
3
4
5
int fputc(int ch,FILE *f)
{
HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xFFFF);
return ch;
}

效果

1
2
3
4
5
6
7
This is send by HAL
This is send by HAL
This is send by HAL
This is send by HAL
This is send by HAL
This is send by HAL
This is send by HAL

这个方案只显示了通过串口发送的数据,没有显示通过printf发送的数据

方案二

1
2
3
4
5
int __io_putchar(int ch)
{
HAL_UART_Transmit(&huart1,(uint8_t *)&ch,1,0xFFFF);
return ch;
}
1
2
3
4
5
6
7
8
9
10
11
HelloWorld
This is send by HAL
HelloWorld
This is send by HAL
HelloWorld
This is send by HAL
HelloWorld
This is send by HAL
HelloWorld
This is send by HAL
HelloWorld

这个方案是可以使用的,但是还存在一些问题

使用了FreeRTOS的配置

在FreeRTOS中添加了NEW-LIB的支持(USE_NEWLIB_REENTRANT)之后就会出现一些问题

1
Error: selected FPU does not support instruction -- `vstmdbeq r0!,{s16-s31}'

解决方案

1
2
3
4
取消下面的注释,如果想要再每一次生成项目模板的时候都不需要修改可以在CMakeLists_template.txt一并修改
add_compile_definitions(ARM_MATH_CM4;ARM_MATH_MATRIX_CHECK;ARM_MATH_ROUNDING)
add_compile_options(-mfloat-abi=hard -mfpu=fpv4-sp-d16)
add_link_options(-mfloat-abi=hard -mfpu=fpv4-sp-d16)

解决完这个问题后。上面的重定向输出代码也需要完成一些修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
void StartDefaultTask(void *argument)
{
/* USER CODE BEGIN StartDefaultTask */
/* Infinite loop */
char hal_msg[] = "This is send by HAL\n";
while (1)
{
printf("HelloWorld\n");
HAL_UART_Transmit(&huart1,hal_msg,strlen(hal_msg),0xffff);
HAL_Delay(1000);
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
}
/* USER CODE END StartDefaultTask */
}

非常奇怪,上面这段代码有时候能正常工作,有时候会出现下面的问题

1
2
3
4
writer.c:(.text._write_r+0x14): undefined reference to `_write'
closer.c:(.text._close_r+0xc): undefined reference to `_close'
fstatr.c:(.text._fstat_r+0x12): undefined reference to `_fstat'
isattyr.c:(.text._isatty_r+0xc): undefined reference to `_isatty'

究其原因是有时候cubemx不会生成一个叫做syscalls.c的文件,文件内容如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158

/**
******************************************************************************
* @file syscalls.c
* @author Auto-generated by STM32CubeIDE
* @brief STM32CubeIDE Minimal System calls file
*
* For more information about which c-functions
* need which of these lowlevel functions
* please consult the Newlib libc-manual
******************************************************************************
* @attention
*
* <h2><center>&copy; Copyright (c) 2020 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/

/* Includes */
#include <sys/stat.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <signal.h>
#include <time.h>
#include <sys/time.h>
#include <sys/times.h>


/* Variables */
extern int __io_putchar(int ch) __attribute__((weak));
extern int __io_getchar(void) __attribute__((weak));


char *__env[1] = { 0 };
char **environ = __env;


/* Functions */
void initialise_monitor_handles()
{
}

int _getpid(void)
{
return 1;
}

int _kill(int pid, int sig)
{
errno = EINVAL;
return -1;
}

void _exit (int status)
{
_kill(status, -1);
while (1) {} /* Make sure we hang here */
}

__attribute__((weak)) int _read(int file, char *ptr, int len)
{
int DataIdx;

for (DataIdx = 0; DataIdx < len; DataIdx++)
{
*ptr++ = __io_getchar();
}

return len;
}

__attribute__((weak)) int _write(int file, char *ptr, int len)
{
int DataIdx;

for (DataIdx = 0; DataIdx < len; DataIdx++)
{
__io_putchar(*ptr++);
}
return len;
}

int _close(int file)
{
return -1;
}


int _fstat(int file, struct stat *st)
{
st->st_mode = S_IFCHR;
return 0;
}

int _isatty(int file)
{
return 1;
}

int _lseek(int file, int ptr, int dir)
{
return 0;
}

int _open(char *path, int flags, ...)
{
/* Pretend like we always fail */
return -1;
}

int _wait(int *status)
{
errno = ECHILD;
return -1;
}

int _unlink(char *name)
{
errno = ENOENT;
return -1;
}

int _times(struct tms *buf)
{
return -1;
}

int _stat(char *file, struct stat *st)
{
st->st_mode = S_IFCHR;
return 0;
}

int _link(char *old, char *new)
{
errno = EMLINK;
return -1;
}

int _fork(void)
{
errno = EAGAIN;
return -1;
}

int _execve(char *name, char **argv, char **env)
{
errno = ENOMEM;
return -1;
}

没有那个文件导致编译失败可以把这个文件贴进去尝试解决一下