终于解决了MDK 3.80a中不能使用printf()函数的问题

来源:互联网 发布:mac dock透明 编辑:程序博客网 时间:2024/05/16 15:57
刚开始学stm32,顺着gpio、uart。。。的顺序慢慢爬
初始化的方法学习了马老师的STM32_Init.h大法,自己英文还可以,加上avr的基础还不错,所以gpio和时钟配置都很顺利
碰到uart就头大了,看到各种例程里都是printf()函数,自己也想用,毕竟是avr想用却开销不了的东西。但是我自己写的程序里一旦出现printf,单片机的不干活了。查论坛首先发现要重定义fputc函数,照做了,还是不行。
后来怀疑是uart1初始化问题,用自己写的put_c函数却没问题。
后来又发现一种说法,需要避免使用semihosting(半主机模式),我也把代码加进去了(改fputc去掉了),还是不行。
再一想,重定义fputc是绝对必须的,加上了之后问题解决,成功使用printf("(敏感词0373) \n");输出了,哈哈
***************************************************************************************************

以上废话,可以不看。
简单地说:想在mdk 3.80a中用printf,需要同时重定义fputc函数和避免使用semihosting(半主机模式), 
论坛里应该有完整介绍这个的帖子,但是我没搜到,也许是沉了。重发出来希望能帮上像我这样的菜鸟们。

需要添加以下代码


#pragma import(__use_no_semihosting) 
/****************************************************************************** 
*标准库需要的支持函数 
******************************************************************************/ 
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 is typedef’ d in stdio.h. */ 
FILE __stdout; 

/// <summary> 
/// 定义_sys_exit()以避免使用半主机模式 
/// </summary> 
/// <param name="x"></param> 
/// <returns></returns> 
_sys_exit(int x) 

x = x; 




int fputc(int ch, FILE *f)
{
    //USART_SendData(USART1, (u8) ch);
    USART1->DR = (u8) ch;
    
    /* Loop until the end of transmission */
    while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET)
    {
    }

    return ch;
}

以上代码来自goway 和 yugen 的发言,在此表示感谢



********************************************************************************************
更新:

根据四楼的帖子,发现在Options里选上microlib之后,就不用关闭半主机模式了。



我顺便查了一下semihosting的作用,介绍如下
Semihosting is a mechanism for ARM targets to communicate input/output requests
from application code to a host computer running a debugger. This mechanism could be
used, for example, to allow functions in the C library, such as printf() and scanf(), to use the screen and keyboard of the host rather than having a screen and keyboard on the target system.
This is useful because development hardware often does not have all the input and
output facilities of the final system. Semihosting allows the host computer to provide these facilities.
Semihosting is implemented by a set of defined software interrupt (SWI) operations.
The application invokes the appropriate SWI and the debug agent then handles the SWI
exception. The debug agent provides the required communication with the host.
In many cases, the semihosting SWI will be invoked by code within library functions. The application can also invoke the semihosting SWI directly. Refer to the C library descriptions in the ADS Compilers and Libraries Guide for more information on support for semihosting in the ARM C library.

找我的理解,这个模式是用来调试的,通过仿真器,使用主机的输入输出代替单片机自己的,也就是说即便单片机没有输出口也能printf到电脑上。反过来,由于这个模式更改了printf()等的实现方式,输入输出就不走单片机的外设了,所以只重定义fputc不起作用。

用代码关闭此模式后,需要同时更新一下__stdout 和__stdin 的定义,所以有后面的语句。

以上仅为个人理解,如有错误请指正。


另外,勾选microlib之后,也许编译的时候就不把开启semihosting的文件包进去了,所以没事。