1. 方法一
/// 重定向c库函数printf到USART1
int fputc(int ch, FILE *f)
{
/* 发送一个字节数据到USART1 */
USART_SendData(USART1, (uint8_t) ch);
/* 等待发送完毕 */
while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
return (ch);
}
/// 重定向c库函数scanf到USART1
int fgetc(FILE *f)
{
/* 等待串口1输入数据 */
while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET);
return (int)USART_ReceiveData(USART1);
}
2. 方法二(只有printf)
//需加入这个头文件
#include "stdarg.h"
static char * itoa ( int value, char * string, int radix );
/*
* 函数名:USART2_printf
* 描述 :格式化输出,类似于C库中的printf,但这里没有用到C库
* 输入 :-USARTx 串口通道,这里只用到了串口2,即USART2
* -Data 要发送到串口的内容的指针
* -... 其他参数
* 输出 :无
* 返回 :无
* 调用 :外部调用
* 典型应用USART2_printf( USART2, "\r\n this is a demo \r\n" );
* USART2_printf( USART2, "\r\n %d \r\n", i );
* USART2_printf( USART2, "\r\n %s \r\n", j );
// */
void USART2_printf ( USART_TypeDef * USARTx, char * Data, ... )
{
const char *s;
int d;
char buf[16];
va_list ap;
va_start(ap, Data);
while ( * Data != 0 ) // 判断是否到达字符串结束符
{
if ( * Data == 0x5c ) //'\'
{
switch ( *++Data )
{
case 'r': //回车符
USART_SendData(USARTx, 0x0d);
Data ++;
break;
case 'n': //换行符
USART_SendData(USARTx, 0x0a);
Data ++;
break;
default:
Data ++;
break;
}
}
else if ( * Data == '%')
{ //
switch ( *++Data )
{
case 's': //字符串
s = va_arg(ap, const char *);
for ( ; *s; s++)
{
USART_SendData(USARTx,*s);
while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );
}
Data++;
break;
case 'd':
//十进制
d = va_arg(ap, int);
itoa(d, buf, 10);
for (s = buf; *s; s++)
{
USART_SendData(USARTx,*s);
while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );
}
Data++;
break;
default:
Data++;
break;
}
}
else USART_SendData(USARTx, *Data++);
while ( USART_GetFlagStatus ( USARTx, USART_FLAG_TXE ) == RESET );
}
}
/*
* 函数名:itoa
* 描述 :将整形数据转换成字符串
* 输入 :-radix =10 表示10进制,其他结果为0
* -value 要转换的整形数
* -buf 转换后的字符串
* -radix = 10
* 输出 :无
* 返回 :无
* 调用 :被USART2_printf()调用
*/
static char * itoa( int value, char *string, int radix )
{
int i, d;
int flag = 0;
char *ptr = string;
/* This implementation only works for decimal numbers. */
if (radix != 10)
{
*ptr = 0;
return string;
}
if (!value)
{
*ptr++ = 0x30;
*ptr = 0;
return string;
}
/* if this is a negative value insert the minus sign. */
if (value < 0)
{
*ptr++ = '-';
/* Make the value positive. */
value *= -1;
}
for (i = 10000; i > 0; i /= 10)
{
d = value / i;
if (d || flag)
{
*ptr++ = (char)(d + 0x30);
value -= (d * i);
flag = 1;
}
}
/* Null terminate the string. */
*ptr = 0;
return string;
} /* NCL_Itoa */
3.方法三
#if 1
#pragma import(__use_no_semihosting_swi)
/*标准库需要的支持函数,use_no_semihosting_swi以避免使用半主机模式*/
struct __FILE
{
int handle;
};
FILE __stdout;
FILE __stdin;
/*重定向Printf函数*/
int fputc(int ch,FILE *f)
{
return(SendChar(ch));
}
/*重定向Scanf函数*/
int fgetc(FILE*f)
{
return(SendChar(GetKey()));
/*调用scanf()在串口中输入数据时,必须以空格结束,否则无法完成发送*/
}
void _ttywrch(int ch)
{
SendChar(ch);
}
int _ferror(FILE*f)
{
/*Yourimplementationofferror*/
return EOF;
}
#endif
int SendChar(int ch)
{
while(!(USART1->SR&USART_FLAG_TXE));
USART1->DR=(ch&0x1FF);
return ch;
}
int GetKey(void)
{
while(!(USART1->SR&USART_FLAG_RXNE));
return((int)(USART1->DR&0X1FF));
}
!!注意,使用scanf()函数输入的时候,USATR请不要开中断,不然接收不到。printf()函数则没有限制。
下图中红框里面的不要出现,本人就是因为开了中断,虽然并没有写出中断函数,但是使用scanf()函数一直接收不到,不写中断就好使了,也不知道是为什么,也不知道是否是个例。