通过USART1向计算机的串口调试助手打印数据,或者接收计算机串口调试助手的数据,接下来我们现STM32工程上的printf()函数,方便用于程序开发中调试信息的打印。

方法一:使用MicroLIB库

1.1 KEIL-MDK中的Use MicroLIB选项

在MDK开发环境中

MicroLib是缺省c库的备选库,它可装入少量内存中,与嵌入式应用程序配合使用,且这些应用程序不在操作系统中运行。 
MicroLib进行了高度优化以使代码变得很小,功能比缺省c库少,不具备某些ISO c特性,部分库函数的运行速度也比较慢,如内存拷贝函数memcpy()。 
MicroLib与缺省c库之间的主要差异在网上有许多文章都有写到,这里摘抄记录: 
(1)MicroLib 不符合 ISO C 库标准。 不支持某些 ISO 特性,并且其他特性具有的功能也较少。 
(2)MicroLib 不符合 IEEE 754 二进制浮点算法标准。 
(3)MicroLib 进行了高度优化以使代码变得很小。 
(4)无法对区域设置进行配置。 缺省 C 区域设置是唯一可用的区域设置。 
(5)不能将 main() 声明为使用参数,并且不能返回内容。 
(6)不支持 stdio,但未缓冲的 stdin、stdout 和 stderr 除外。 
(7)MicroLib对 C99 函数提供有限的支持。 
(8)MicroLib不支持操作系统函数。 
(9)MicroLib不支持与位置无关的代码。 
(10)MicroLib不提供互斥锁来防止非线程安全的代码。 
(11)MicroLib不支持宽字符或多字节字符串。 
(12)与stdlib不同,MicroLib不支持可选择的单或双区内存模型。MicroLib只提供双区内存模型,即单独的堆栈和堆区。

MicroLib提供了一个有限的stdio子系统,它仅支持未缓冲的stdin、stdout和stderr,那么也就是说勾选了Use MicroLib选项后,在代码工程中就可以使用printf()函数咯? 
然而事实并非如此,这样直接使用printf()函数,其打印的字符串最终不知道打印到何处。我们要做的是将调试信息打印到USART1中,所以需要对printf()函数所依赖的打印输出函数fputc()重定向(MicroLib中的printf()函数打印操作依赖fputc())。

1.2 重定向fputc函数

在MicroLib的stdio.h中,fputc()函数的原型为:

 int fputc(int ch, FILE* stream)                                                  

此函数原本是将字符ch打印到文件指针stream所指向的文件流去的,现在我们不需要打印到文件流,而是打印到串口1。基于前面的代码:

 #include <stdio.h>

 int fputc(int ch, FILE* stream)
{
//USART_SendData(USART1, (unsigned char) ch);
//while (!(USART1->SR & USART_FLAG_TXE));
USART_SendChar(USART1, (uint8_t)ch);
return ch;
}

注意,需要包含头文件stdio.h,否则FILE类型未定义。 
勾选了Use MicroLib选项,重定向fputc()函数后,我们就可以在工程代码中使用printf()函数了:

 int main(void)
{ USART_Configuration();
//USART_SendString(USART1, "HelloWorld\n");
//USART_SendChar(USART1, 'h');
printf("\r\nstm32f103rct6\r\n");
printf("\r\nCortex-M3\r\n");
while (); return ;
}

printf()函数的使用方法跟之前一样,运行结果:

方法2:不使用MicroLIB库

2.1 半主机模式

半主机模式是ARM的一种机制,实现将来ARM应用程序代码的输入/输出请求传送至运行着调试器的主机。例如设置使用半主机模式下的ARM应用程序,可以使用printf()和scanf()来使用主机的显示器和键盘,而不需要在ARM系统上搭配显示器和键盘。 
半主机通过一组定义好的软件指令(如SVC)来实现的,这些指令在程序控制下产生异常,ARM应用程序调用半主机对应的异常处理函数,然后调试代理处理该异常。

第二段话感觉理解起来有点模糊,但是第一段还是懂它在讲什么的。一般的ARM应用程序中并不需要半主机操作,在这里为确保ARM应用程序中没有链接MicroLib的半主机相关函数,我们要取消ARM的半主机工作模式。

2.2 代码实现

在工程中加上如下代码:

 //取消ARM的半主机工作模式
#pragma import(__use_no_semihosting)
struct __FILE {
int handle;
}; FILE __stdout;
_sys_exit(int x)
{
x = x;
} int fputc(int ch, FILE *f){
while((USART1->SR&0X40)==);
USART1->DR = (u8) ch;
return ch;
}

  上面的代码摘自正点原子的范例程序。

转载地址:https://blog.csdn.net/qq_29344757/article/details/75363639

STM32中如何对printf函数重定向的更多相关文章

  1. 【stm32】实现STM32的串口数据发送和printf函数重定向

    在调试电机驱动程序的时候,是不能随便利用中断来进行一些寄存器或数据的查看的,不然你在运行的时候突然来一下,如果占空比大的话那可能直接就把MOS管给烧了,所以我们很多情况下只能使用USART(串口)来进 ...

  2. printf函数重定向

    printf函数底层会调用fputc函数 /*重定向c库函数printf到USART1*/ int fputc(int ch, FILE *f) { /*发送一个字节数据USART1 */ USART ...

  3. php中sprintf与printf函数用法区别

    下面是一个示例:四舍五入保留小数点后两位  代码如下 复制代码 <?php$num1 = 21;echo sprintf("%0.2f",$num1)."<b ...

  4. STM32 KEIL 下的 printf 函数

    1 //加入以下代码,支持printf函数,而不需要选择use MicroLIB 2 #if 1 3 #pragma import(__use_no_semihosting) 4 //标准库需要的支持 ...

  5. stm32中如何进行printf重定向用于串口调试输出

    1 在main中包含stdio.h 文件 2 Target选项框里选Use MicroLib 选项 3 在main中添加UART1_Configuration()初始化的代码 Uart1初始化,voi ...

  6. STM32 printf函数

    /******************** (C) COPYRIGHT 2012 WildFire Team *************************** * 文件名 :usart1.c * ...

  7. 如果简化stm32中printf函数的使用——首先重定向

    STM32单片机极简方法 使用宏定义 代替复杂的重定向printf()函数,实现串口打印.(HAL库例程)https://blog.csdn.net/wu10188/article/details/9 ...

  8. 关于STM32中printf函数的重定向问题

    printf函数一般是打印到终端的,stm32芯片调试中经常需要用到串口来打印调试信息,那能不能用串口实现类似windows的Console中的printf呢? 答案是肯定的,那就是printf函数的 ...

  9. STM32 printf()函数和scanf()函数重定向到串口

    STM32 printf()函数和scanf()函数重定向到串口 printf()函数和scanf()函数重定向 在学习STM32的时候,常常需要用串口来测试代码的正确与否,这时候就要要用到print ...

随机推荐

  1. POJ-1020-Anniversary Cake

    链接:https://vjudge.net/problem/POJ-1020 题意: 给一个宽为s的正方形,再给n个变长为an的小正方形, 判断是否能将这n个小正方形完全填充到这个大正方形里面. 思路 ...

  2. 栈 && 教授的测试

    卡特兰数:https://blog.csdn.net/wu_tongtong/article/details/78161211 https://www.luogu.org/problemnew/sho ...

  3. 关于java中的不可变类(转)

    如何在Java中写出Immutable的类? 要写出这样的类,需要遵循以下几个原则: 1)immutable对象的状态在创建之后就不能发生改变,任何对它的改变都应该产生一个新的对象. 2)Immuta ...

  4. python_19(Django外键)

    第1章 Django ORM相关操作 1.1 在一个py文件中使用django项目 1.2 返回QuerySet对象的方法有 1.2.1 特殊的QuerySet 1.3 返回具体对象的 1.4 返回布 ...

  5. JDK原子类操作

    JDK原子类操作及原理 在JDK5之后,JDK提供了对变量的原子类操作, java.util.concurrent.atomic里都是原子类 原子类的分类 原子更新基本类型 原子更新数组 原子更新抽象 ...

  6. P1218 [USACO1.5]特殊的质数肋骨 Superprime Rib

    题目描述 农民约翰的母牛总是产生最好的肋骨.你能通过农民约翰和美国农业部标记在每根肋骨上的数字认出它们.农民约翰确定他卖给买方的是真正的质数肋骨,是因为从右边开始切下肋骨,每次还剩下的肋骨上的数字都组 ...

  7. 使用nginx+tomcat实现静态和动态页面的分离

    博主最近在优化一个javaweb项目,该项目之前一直都是使用tomcat处理用户请求的,无论静态还是动态的东西,一律交给tomcat处理.tomcat主要是负责处理servlet的,静态的文件还是交给 ...

  8. bin&sbin 命令作用

    最近需要了解sbin与bin的功能,需要整理一下.一下全部为Ubuntu14里面默认安装的.在这里收集一下,转载请注明出处! bin bash shell bunzip2 .bz2文件的解压缩程序. ...

  9. Python进程间通信和网络基础

    Python进程间通信和网络基础 Python支持多种进程间通讯的方式, 有单机通信的signal和mmap等, 也有可以通过网络的socket方式, 这里先介绍select等的有关知识, socke ...

  10. Kruskal与Prim

    一.最小生成树 在无向图中,连通且不含圈的图称为树(Tree).给定无向图G=(V,E),连接G中所有点,且边集是E的子集的树称为G的生成树(Spanning Tree),而权值最小的生成树称为最小生 ...