赞
踩
读了一些文章,添加syscalls.c到工程中,放在user文件夹下,syscall.c文件来自之前自己用STM32CubeMX创建的工程目录的Core文件夹下:
拷贝到User文件夹下,刷新CMake, 再次Debug:
提示:undefined reference to `_sbrk'
这份syscalls.c唯独缺了这个函数定义,所以只有这个提示,没有加入syscall.c文件的时候,还会有很多其他函数未定义的提示。
搜索syscalls.c,电脑里好多地方都有,当然都是跟STM32的库和工程有关:
这些syscalls.c 有些有_sbrk函数,有些没有,_sbrk函数定义如下:
- caddr_t _sbrk(int incr)
- {
- extern char end asm("end");
- static char *heap_end;
- char *prev_heap_end;
-
- if (heap_end == 0)
- heap_end = &end;
-
- prev_heap_end = heap_end;
- if (heap_end + incr > stack_ptr)
- {
- // write(1, "Heap and stack collision\n", 25);
- // abort();
- errno = ENOMEM;
- return (caddr_t) -1;
- }
-
- heap_end += incr;
-
- return (caddr_t) prev_heap_end;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
把这个函数添加进去工程里的syscalls.c里面,再次build:
提示:error: 'stack_ptr' undeclared (first use in this function); did you mean 'stack_t'?
回到拷贝的地方,原来的syscalls.c里有声明这个:
- /* Variables */
- //#undef errno
- extern int errno;
- extern int __io_putchar(int ch) __attribute__((weak));
- extern int __io_getchar(void) __attribute__((weak));
-
- register char * stack_ptr asm("sp");
-
- char *__env[1] = { 0 };
- char **environ = __env;
-
-
- /* Functions */
- void initialise_monitor_handles()
- {
- }
-
- int _getpid(void)
- {
- return 1;
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
所以再加上这个声明,编译通过:
不过这样,还是没法对串口输出printf的。
接下来,要解决重定向的问题:
用CLION 构建STM32的工程,用的是ARM_GCC, Keil用的是ARMCC
与在keil5中重定义fputs()
函数不一样,在GCC
编译器中(stm32标准库)需要重定义的是__io_putchar(int ch)
,而这个函数,在_write中被使用
,即syscalls.c
中重写了_write()
函数。
参考文章【教程】手把手教你用Clion进行STM32开发【如何优雅の进行嵌入式开发】 - 知乎 (zhihu.com)
的 3.10 、更优雅的方法实现串口输入输出流 部分操作(原理可看3.8 / 3.9)
新建retarget.h:
- #ifndef UART1_RXTX_RETARGET_H
- #define UART1_RXTX_RETARGET_H
-
-
- #include <stdio.h>
- #include "stm32f10x_usart.h"
-
- #ifdef __GNUC__
- /* With GCC, small printf (option LD Linker->Libraries->Small printf
- set to 'Yes') calls __io_putchar() */
- #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
- #else
- #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
- #endif /* __GNUC__ */
-
- #ifdef __GNUC__
- #define GETCHAR_PROTOTYPE int __io_getchar (void)
- #else
- #define GETCHAR_PROTOTYPE int fgetc(FILE * f)
- #endif /* __GNUC__ */
-
- /**
- * @brief 注册重定向串口
- * @param usartx 需要重定向输入输出的串口
- */
- void RetargetInit(USART_TypeDef *huart);
-
-
- #endif //UART1_RXTX_RETARGET_H
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
和retarget.c文件:
- #include "retarget.h"
-
- /* 定义USART端口,用于注册重定向的串口(也可以用UART,根据实际情况来改写) */
- static USART_TypeDef *sg_retargetUsart;
-
- /**
- * @brief 注册重定向串口
- * @param usartx 需要重定向输入输出的串口
- */
- void RetargetInit(USART_TypeDef *usartx) {
- /* 注册串口 */
- sg_retargetUsart = usartx;
-
- /* Disable I/O buffering for STDOUT stream, so that
- * chars are sent out as soon as they are printed. */
- setvbuf(stdout, NULL, _IONBF, 0);
- /* Disable I/O buffering for STDIN stream, so that
- * chars are received in as soon as they are scanned. */
- setvbuf(stdin, NULL, _IONBF, 0);
-
- }
-
- /**
- * @brief Retargets the C library printf function to the USART.
- * @param None
- * @retval None
- */
- PUTCHAR_PROTOTYPE {
- /* 发送一个字节数据到串口 */
- /* 很简单,直接调用库函数中的 串口发送数据函数 */
- USART_SendData(sg_retargetUsart, (uint8_t) ch);
-
- /*等待发送完毕*/
- while (USART_GetFlagStatus(sg_retargetUsart, USART_FLAG_TXE) == RESET);
- /* 返回发送的字符 */
- return ch;
-
- }
-
- /**
- * @brief Retargets the C library scanf, getchar function to the USART.
- * @param None
- * @retval None
- */
- GETCHAR_PROTOTYPE {
-
- /* 很简单,直接调用库函数中的接收 */
- /* 等待串口输入数据 */
- while (USART_GetFlagStatus(sg_retargetUsart, USART_FLAG_RXNE) == RESET);
- /* 直接返回接收到的字符 */
- return (int) USART_ReceiveData(sg_retargetUsart);
-
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
在main.c文件中包含retarget.h,并调用RetargetInit(DEBUG_USARTx);
- #include "stm32f10x.h"
- #include "bsp_usart.h"
- #include "retarget.h"
-
- /**
- * @brief 主函数
- * @param 无
- * @retval 无
- */
- int main(void) {
- /**
- * 注册 USART1 用于重定向
- * 当然其他端口也行
- */
- RetargetInit(DEBUG_USARTx);
- /*初始化USART 配置模式为 115200 8-N-1,中断接收*/
- USART_Config();
-
- /* 发送一个字符串 */
- Usart_SendString(DEBUG_USARTx, "这是一个串口中断接收回显实验\n");
- printf("欢迎使用野火STM32开发板\n\n\n\n");
-
- while (1) {
-
- }
- }
![](https://csdnimg.cn/release/blogv2/dist/pc/img/newCodeMoreWhite.png)
然而build的时候却出现问题,提示
AR19DD~1.EXE: error: User/Inc/retarget.h: No such file or directory
AR19DD~1.EXE: error: User/Src/retarget.c: No such file or directory
搜索了一遍,参考文章 【Clion】Clion运行C/C++文件报错问题(解决方法二)-CSDN博客
在CMakeLists.txt中找到 set(LINKER_SCRIPT 这行:
删除后面的 “User/Inc/retarget.h User/Src/retarget.c” , 变成这样:
再次build,就好了
然而Run程序,下载到开发板,串口USB接电脑,打开野火的串口调试器,却没有任何打印输出。
检查retarget.c,没有加禁用半主机模式,加上#pragma import(__use_no_semihosting)就好了:
- #include "retarget.h"
-
- /* 定义USART端口,用于注册重定向的串口(也可以用UART,根据实际情况来改写) */
- static USART_TypeDef *sg_retargetUsart;
-
- /* 告知连接器不从C库链接使用半主机的函数 */
- /*重要!!!,不然串口没有打印输出*/
- #pragma import(__use_no_semihosting)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。