首页 - 信息 - stm32重新定义printf(stm32重新定义printf寄存器)

stm32重新定义printf(stm32重新定义printf寄存器)

2023-09-30 20:11

stm32重新定义printf(stm32重新定义printf寄存器)

如何解决STM32中printf函数无法使用的问题

简单来说:如果想在mdk中使用printf,需要重新定义fputc函数,同时避免使用semihosting(半主机模式)。
标准库函数默认的输出设备是显示器,如果需要实现串口或者液晶输出,则需要重新定义标准库函数中调用的输出设备相关的函数。
例如:printf 输出到串口,需要将 fputc 中的输出指向串口(重定向),方法如下:
#ifdef __GNUC__
/* 与 GCC/RAISONANCE , 小 printf (选项 LD Linker->Libraries->Small printf
设置为 'Yes') 调用 __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
# Define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
PUTCHAR_PROTOTYPE
{
/* 将 fputc 的实现放在这里 * /
/* 例如向USART写入一个字符 */
USART_SendData(USART1, (uint8_t) ch);
/*循环直到传输结束*/
while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
return ch;
}
对于printf()等函数,采用半托管模式。使用标准库会导致程序无法运行。下面是解决方法:
方法一、使用微库,因为使用微库不会使用半托管模式。
方法2.仍然使用标准库,在main程序中添加如下代码:
#pragma import(__use_no_semihosting)
_sys_exit(int x)
{
x = x ;
}
struct __FILE
{
int 句柄;
/* 无论您需要什么。如果您使用的唯一文件是 */
/* 使用 printf() 进行调试的标准输出,则不需要文件处理 */
/ *。 */
};
/* FILE 在 stdio.h 中是 typedef 的。 */
FILE __stdout;
如果您使用MDK,请在项目属性中设置“目标”“-”在“代码生成”中勾选“使用MicroLIB”;今天查阅论坛发现使用微库可以很好的解决这个问题。
2。另一种方法:(其实类似)
需要添加以下代码
(论坛里应该有完整的帖子,但是我没找到,可能是被埋了。)
# pragma import(__use_no_semihosting)
/********* ************************************ ****************** ******************
*支持标准库所需的函数
**************************************************** ********************* **********/
struct __FILE
{
int 句柄;
/* 无论您需要什么。如果您使用的唯一文件是 */
/ * 使用 printf() 进行调试的标准输出,则不需要文件处理 */
/*。 */
};
/* FILE 在 stdio.h 中是 typedef 的。 */
文件 __stdout;
///


/// 定义 _sys_exit() 为避免使用半主机模式
///

///
///
_sys_exit(int x)
{
x = x ;
}
int fputc(int ch, FILE *f)
{
//USART_SendData(USART1, (u8) ch);
USART1->DR = (u8) ch;
/* 循环直到传输结束 */
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
{
}
return ch;
}
半主机的作用,介绍如下
半主机是 ARM 目标将输入/输出请求
从应用程序代码传送到运行调试器的主机的机制。例如,可以使用此机制来允许 C 库中的函数(例如 printf() 和 scanf())使用主机的屏幕和键盘,而不是在目标系统上使用屏幕和键盘。
这很有用,因为开发硬件通常不具备最终系统的所有输入和
输出设施。半主机允许主机提供这些设施。
半主机是由一组已定义的软件中断 (SWI) 操作。
应用程序调用适当的 SWI,然后调试代理处理 SWI
异常。调试代理提供与主机所需的通信。
在许多情况下,半主机 SWI 将由库函数中的代码调用。应用程序还可以直接调用半主机 SWI。有关 ARM C 库中半主机支持的更多信息,请参阅《ADS 编译器和库指南》中的 C 库说明。
据我了解,这种模式是用来调试的。通过仿真器,使用上位机的输入和输出,而不是单片机自己的。也就是说,即使单片机没有输出口,也可以printf到计算机上。相反,由于该模式改变了printf()等的实现,输入输出不经过单片机的外设,所以仅仅重新定义fputc是行不通的。
用代码关闭该模式后,需要同时更新__stdout和__stdin的定义,所以还有后续的语句。
以上仅是个人理解,如有错误请指正。
另外,检查了microlib后,编译时可能不会包含启用semihosting的文件,所以没关系。
C 库函数重定向:
用户可以定义自己的C 语言库函数,连接器在连接时自动使用这些新函数。这个过程称为重定向C语言库函数,如下图所示。
例如,用户有一个I/O设备(例如UART)。原本,库函数fputc()将字符输出到调试器控制窗口,但用户将输出设备更改为UART端口。这样,所有的printf()都基于fputc()函数) 系列功能输出重定向至 UART 端口。
以下是实现 fputc() 重定向的示例:
externvoidsendchar(char*ch);
intfputc(intch,FILE*f)
{/*e.g.writeacharactertoanUART*/
chartemp ch =ch;
sendchar(&tempch);
returnch;

这个示例只是将输入字符重定向到另一个函数sendchar(),假设该函数是另外定义的串口输出函数。在这里,fputc() 就像目标硬件和标准 C 库函数之间的抽象层。

STM32串口printf()重定向问题

你首先尝试看看你的串口配置是否正确,这样你就可以使用USART_SendData(USART1, (uint8_t) ch);该函数发送一个字符 a 等。如果没有问题,再检查是否重定向。问题

stm32中重新定义printf的功能,只要把USART1改成USART2等其他的就可以使用吗?

如果之前用uart1没问题,那就改成uart2就可以了。
注意,如果不使用微库,则必须添加以下代码
#pragma import(__use_no_semihosting)
_sys_exit(int x)
{
x = x;
}
struct __FILE
{
int 句柄;
};
文件__stdout;

stm32编程中如何使用printf函数

有两种配置方法:
1。配置项目属性。详细步骤如下
1。首先,在主文件中包含“stdio.h”(标准输入和输出头文件)。
2。重新定义主文件中的函数如下:
//发送数据
int fputc(int ch, FILE *f)
{
USART_SendData(USART1, (unsigned char) ch );// USART1可以替换为USART2等
while (!(USART1->SR & USART_FLAG_TXE));
return (ch);
}
//接收数据
int GetKey (void ) {
while (!(USART1->SR & USART_FLAG_RXNE));
return ((int)(USART1->DR & 0x1FF));
}
使用 printf 时这样自定义将调用fputc函数来发送字符。
3。在项目属性的“目标”->“代码生成”选项中选中“使用 MicroLIB”。
MicroLIB是默认C的备份库,你可以在网上找到关于它的详细信息。
至此配置完成。项目中可以使用printf向串口发送数据。
2.第二种方法是将“Regtarge.c”文件添加到项目
1中。在主文件.h”文件中包含“stdio”
2。在项目中创建一个文件,保存为Regtarge.c,然后添加到项目中
在文件中输入以下内容(直接复制即可)
#include
#include
#pragma import(__use_no_semihosting_swi)
extern int SendChar(int ch); // 声明外部函数,在主文件中定义
extern int GetKey(void);
struct __FILE {
int handle; // 在此处添加您需要的内容
};
FILE __stdout;
FILE __stdin;
int fputc(int ch, FILE *f) {
return (SendChar(ch));
}
int fgetc(FILE *f) {
return (SendChar(GetKey()));
}
void _ttywrch(int ch) {
SendChar (ch);
}
int Ferr(FILE *f) { // 你的ferror实现
return EOF;
}
void _sys_exit(int return_code) {
标签:转到标签; //无限循环
}
3.在主文件中添加并定义以下两个函数
int SendChar ( int ch) {
while (!(USART1->SR & USART_FLAG_TXE)); // 程序中可以将USART1替换为串口进行通信
USART1->DR = (ch & 0x1FF);
return (ch);
}
int GetKey (void) {
while (!(USART1->SR & USART_FLAG_RXNE));
return ((int)(USART1->DR & 0x1FF)) ;
}
现已配置完成,可以使用在主文件中自由使用 printf 。

STM32 printf的重新定义

STM32重新定义printf的参考代码如下:
#define STDIO_COM USARTx
int fputc(int ch, FILE *f) //将字符ch写入到文件指向的文件的当前写入处指针 fp 指针的位置
{
/* 将 fputc 的实现放在这里 *//* 例如向 USART 写入一个字符 */
USART_SendData(STDIO_COM, (uint8_t) ch);
/* 循环直到传输结束 */
while (USART_GetFlagStatus(STDIO_COM, USART_FLAG_TC) == RESET)
{}
返回ch; //返回结果
}

以上就是小编对stm32重定义printf(stm32重定义printf寄存器)及相关问题的解答。 stm32重定义printf的问题(stm32重定义printf寄存器)希望对你有用!