zoukankan      html  css  js  c++  java
  • STM32中如何对printf函数重定向

      通过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()函数的原型为:

    1 int fputc(int ch, FILE* stream)                                                  

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

    1 #include <stdio.h>
    2 
    3 int fputc(int ch, FILE* stream)
    4 {
    5     //USART_SendData(USART1, (unsigned char) ch);
    6     //while (!(USART1->SR & USART_FLAG_TXE));
    7     USART_SendChar(USART1, (uint8_t)ch);
    8     return ch;
    9 }

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

     1 int main(void)
     2 {
     3 
     4     USART_Configuration();
     5     //USART_SendString(USART1, "HelloWorld
    ");
     6     //USART_SendChar(USART1, 'h');
     7     printf("
    stm32f103rct6
    ");
     8     printf("
    Cortex-M3
    ");
     9     while (1);  
    10 
    11     return 0;
    12 }

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

    方法2:不使用MicroLIB库

    2.1 半主机模式

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

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

    2.2 代码实现

    在工程中加上如下代码:

     1 //取消ARM的半主机工作模式
     2 #pragma import(__use_no_semihosting)                             
     3 struct __FILE { 
     4     int handle; 
     5 }; 
     6 
     7 FILE __stdout;          
     8 _sys_exit(int x) 
     9 { 
    10     x = x; 
    11 }
    12 
    13 int fputc(int ch, FILE *f){      
    14     while((USART1->SR&0X40)==0);
    15     USART1->DR = (u8) ch;      
    16     return ch;
    17 }

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

    转载地址:https://blog.csdn.net/qq_29344757/article/details/75363639
  • 相关阅读:
    分析支付宝首页
    夺命雷公狗—angularjs—17—angularjs的静态库
    夺命雷公狗—angularjs—16—angularjs里面的缓存
    夺命雷公狗—angularjs—15—内置封装好的计时器$interval和$timeout
    夺命雷公狗—angularjs—14—$location的作用
    2016-08-20--回忆了下当年的夺命雷公狗(一)
    angularjs---$http.post发的数据,后台取不到
    夺命雷公狗—angularjs—13—post参数的接收发送
    夺命雷公狗—angularjs—12—get参数的接收
    夺命雷公狗—angularjs—11—service的基本概念
  • 原文地址:https://www.cnblogs.com/Lxk0825/p/9675742.html
Copyright © 2011-2022 走看看