printf函数重定向为往串口打印信息

在UART.h、UART1.h和UART.c文件的内容编写好后,在main函数中实现通过串口发送一串字符串和一个不断加1的变量

方法一:

使用sprintf函数,组装字符串,然后通过串口发送数组的函数进行串口发送

/* Includes ------------------------------------------------------------------*/
#include <main.h>/* Private define-------------------------------------------------------------*//* Private variables----------------------------------------------------------*/
uint16_t Cnt = 0;      //初始化自动加1的变量
/* Public variables-----------------------------------------------------------*//* Private function prototypes------------------------------------------------*//*
* @name   main
* @brief  主函数
* @param  void
* @retval int
*/
int main(void)
{//系统初始化Hradware.Sys_Init();//串口1发送初始化信息UART1.UART_SendString("Initialization completed,system startup!\r\n");//系统主循环while(1){//按键检测//KEY1.KEY_Detect();//KEY2.KEY_Detect();//PWM.PWM_LED_Adjust_Brightness();//通过串口发送字符串和自动加1的变量//方法一/*sprintf函数将Cnt按照格式组装成一个字符串,然后放入到UART1.pucSend_Buffer指向的发送数组中*/sprintf(UART1.pucSend_Buffer,"hello:%u\r\n",Cnt++);Public.Delay_ms(300);UART1.UART_SendArray(UART1.pucSend_Buffer,20);Run_LED.Run_LED_Flip();}
}
/********************************************************End Of File
********************************************************/

注意Cnt变量的类型以及组装字符串时的格式化%方式不对的话,都会造成不同的效果

注意一:

/* Private variables----------------------------------------------------------*/
uint8_t Cnt = 0;   //初始化自动加1的变量

如果Cnt的类型是uint8_t的话,下面的格式化不变,还是%u,则串口输出的不是加1,而是加256了

如果Cnt类型非得写成 uint8_t 的话,那么格式化前要强制类型转换才会正常加1,并从0加到255,然后又从0开始

sprintf(UART1.pucSend_Buffer,"hello:%u\r\n",(uint16_t)Cnt++);

注意二:

sprintf(UART1.pucSend_Buffer,"hello:%c\r\n",Cnt++);

如果格式化时,写成了%c,Cnt的类型还是uint16_t,则串口打印不了Cnt变量

如果把Cnt类型改为uint8_t,则Cnt被打印成了一个圈,而且还不连续,明显是错误的

方法二:

使用printf重定向来做,本次实验对putchar函数进行修改,需要在main.h头文件中引入< stdio.h >头文件

UART1.c:

/*
* @name   putchar
* @brief  字符发送函数重定向
* @param  c:发送的字符
* @retval char
*/
extern char putchar(char ch)
{UART1.UART_SendData((uint8_t)ch);      //在putchar函数内直接调用串口发送字符函数return ch;
}

main.c:

/* Includes ------------------------------------------------------------------*/
#include <main.h>/* Private define-------------------------------------------------------------*//* Private variables----------------------------------------------------------*/
uint16_t Cnt = 0;  //初始化自动加1的变量
/* Public variables-----------------------------------------------------------*//* Private function prototypes------------------------------------------------*//*
* @name   main
* @brief  主函数
* @param  void
* @retval int
*/
int main(void)
{//系统初始化Hradware.Sys_Init();//串口1发送初始化信息UART1.UART_SendString("Initialization completed,system startup!\r\n");//系统主循环while(1){//按键检测//KEY1.KEY_Detect();//KEY2.KEY_Detect();//PWM.PWM_LED_Adjust_Brightness();//通过串口发送字符串和自动加1的变量//方法一/*sprintf函数将Cnt按照格式组装成一个字符串,然后放入到UART1.pucSend_Buffer指向的发送数组中*/// sprintf(UART1.pucSend_Buffer,"hello:%u\r\n",Cnt++);// Public.Delay_ms(100);// UART1.UART_SendArray(UART1.pucSend_Buffer,20);// Run_LED.Run_LED_Flip();//方法二//printf函数重定向printf("hello:%u\r\n",Cnt++);Public.Delay_ms(100);Run_LED.Run_LED_Flip();}
}

重定向后,也可以使用printf函数打印浮点数

float f = 3.14;
。。。
printf("hello:%u%f\r\n",Cnt++,f);

注意:

网上文章许多都是说改写fputc函数,但我在这个程序中试了是不行的,会编译出错,定位到函数的FILE类型上,因为C51是没有FILE类型的,所以这里是使用不了fputc函数的

int fputc(int ch,FILE*stream)    //编译时在FILE处报错
{UART1.UART_SendData((uint8_t)ch);return ch;
}

那为什么网上还有那么多说改fputc函数呢?因为那是在编写STM32单片机程序的时候,可以在keil软件的设置里,勾选Use MicroLIB选项,就可以使用fputc函数来实现重定向了

打开STM32工程文件时keil设置界面:

为什么使用microlib库

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 只提供双区内存模型,即单独的堆栈和堆区。

(13)、可以合理地将 microlib 与 --fpmode=std 或 --fpmode=fast 配合使用。

勾选微库之后,重写fputc函数和fgetc函数就可以支持printf函数和scanf函数。

但打开编写51单片机的程序时,keil软件设置里是没有这个选项的,所以51的程序没法使用fputc函数

打开51工程文件时keil设置界面:

而从keil的帮助文档里可以知道, printf 也是基于putchar实现的,所以本次重新实现putchar,就可以实现printf的重定向了

至于重定向的方法网上有很多,但为什么可以重定向,就比较少文章介绍,这里看到有一篇文章写的不错:https://zhuanlan.zhihu.com/p/133460085

文章中介绍的weak的属性,相信以后在STM32中会经常遇到

fputc

语法:

#include <stdio.h>  int fputc( int ch, FILE *stream );

函数fputc()把给出的字符ch写到给出的输出流. 返回值是字符, 发生错误时返回值是EOF.

putchar

语法:

#include <stdio.h>  int putchar( int ch );

putchar()函数把 ch 写到STDOUT(标准输出). 代码

putchar( ch );

putc( ch, STDOUT );

一样.

putchar()的返回值是被写的字符, 发生错误时返回EOF

STC15单片机-串口打印printf重定向相关推荐

  1. 51单片机串口打印函数

    51单片机串口通信调试printf函数重定向输出打印 1.首先需要实现串口的发送和接收. 2.输出printf需要哪些步骤: 1)需要引入头文件 <stdio.h> 2)添加如下代码: c ...

  2. STM32 KEIL 串口打印printf使用详解

    常规打印方法 在STM32的应用中,我们常常对printf进行重定向的方式来把打印信息printf到我们的串口助手. 在MDK环境中,我们常常使用MicroLIB+fputc的方式实现串口打印功能,即 ...

  3. c语言输入输出重定向到串口,关于printf重定向到串口的问题分析 - 全文

    关于printf重定向到串口的问题 简单地说:想在mdk 中用printf,需要同时重定义fputc函数和避免使用semihosTIng(半主机模式), 标准库函数的默认输出设备是显示器,要实现在串口 ...

  4. DIY单片机串口打印函数print

    原始的单片机串口只能发送单字节数据,再加个封装也就能发送个字符串,但是无法发送数字变量,要发送数字变量那基本要引入C语言的库函数printf,但是这个pintf函数 好用确实是好用但是有个很大的缺点相 ...

  5. STM32软件学习笔记(一)基于HAL库的STM32F429单片机串口打印程序

    |版权声明:本文为博主原创文章,转载请注明出处.https://blog.csdn.net/NeverImagine_/article/details/95517664   目前ST官方有提供两种库文 ...

  6. 嵌入式串口打印信息重定向到当前终端界面

    转至 https://blog.csdn.net/wuquan_1230/article/details/105782687 概述 在嵌入式Linux系统中,有时通过远程(telnet或者ssh)登录 ...

  7. STM103单片机串口输出函数printf重映射

    在调试程序的时候经常需要使用printf'函数来打印相关调试信息,在STM103单片机中printf函数默认只能在串口1使用,有时候串口1被占用了,想要输出调试信息时会比较麻烦.现在就总结一下如何在其 ...

  8. 51单片机串口打印不管是中文还是英文都是乱码的问题

    讲道理都tm大三暑假了还搞51单片机而且关键是还遇到了一个问题解决了一天才解决出来真的是很丢人了. 不过我会珍惜这个机会的,毕竟这有可能是我辈子最后一次跟着老师搞这个破玩意了. 好了不废话了 收! 昨 ...

  9. 1.国民技术N32G45X例程之-串口打印

    国民技术N32G45X例程之-串口打印 提示:use MicroLIB,printf串口打印 文章目录 前言 一.国民技术N32G45X串口配置 二.printf函数 1.国民技术N32G45X官方库 ...

最新文章

  1. SAP RETAIL MM41 不能将Class分配给商品主数据
  2. iphone6 微信浏览器高度适配的问题
  3. windows+php+mysql+apache(wamp)安装配置问题
  4. 3分钟把区块链的技术与应用彻底讲清楚
  5. 初二下册计算机考试试题,2017下半年计算机等级考试二级Java模拟试题及答案(18)...
  6. 《Python Cookbook 3rd》笔记(4.5):反向迭代
  7. 手把手教你使用CocoaPods管理你的iOS第三方开源类库
  8. 甜蜜暴击情人节海报PSD分层模板|让人眼前一亮
  9. 2010——满地遍是网页防篡改和WAF
  10. node 单个表加条件查询
  11. CM安装部署介绍说明-尚硅谷大数据培训
  12. Windows远程桌面开发之九-虚拟显示器(Windows 10 Indirect Display 虚拟显示器驱动开发)
  13. 南京邮电大学网络信息安全——软件漏洞分析与防范(实验一——栈溢出和gs保护机制)
  14. 软件工程第三章(第一部分)
  15. 计算机word文档工作区名称,word文档界面名称 word文档的界面组成
  16. oracle表空间temp表空间满了,Oracle temp表空间爆满的处理方法
  17. 优麒麟系统安装MySQL_安装优麒麟(ubuntukylin)操作系统详解
  18. linux 环境下安装dubbo管理控制台 dubbo admin
  19. nz-select不能写在label标签里面
  20. 还不快到碗里来?软件测试接口测试面试题(大全)

热门文章

  1. 【筛质数】——朴素筛,埃式筛,欧拉筛
  2. Web前端理论知识记录
  3. ClickHouse CTO空降中国开发者和用户沙龙,B站、小红书、携程、阿里云携手分享ClickHouse实践
  4. Modbus RTU ASCII
  5. SPI message 基础 Part 2
  6. 微博和qq说说定时发送畅想
  7. Unittest自动化测试框架教程(二)——Python中Fixture测试夹具的使用和setUp方法相关参数传递
  8. 计算机用户锁定无法登陆,win7引用的账户当前已锁定 且可能无法登陆怎么办怎么办-win7账户被锁定,win7解除锁定账户...
  9. 重装系统中遇到的问题:(1)请检查你的介质驱动器,错误代码0x80300024(2)选中的磁盘采用gpt分区形式
  10. java毕业设计电子病历系统(附源码、数据库)