STC15单片机-串口打印printf重定向

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

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值