printf和scanf的串口重定向,格式化输入输出

这篇具有很好参考价值的文章主要介绍了printf和scanf的串口重定向,格式化输入输出。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、实验设计效果

通过重定向C标准库的printf和scanf函数,实现串口的格式化输出;

调用MDK微库(MicroLib)的方法和调用标准库的方法。

二、硬件工作原理和原理图

我们使用的正点原子STM32F103RB NANO开发板上将USART1(引脚为PA9,PA10)接出

scanf重定向,单片机,stm32,嵌入式硬件

USART1并没有在PCB上连接在一起,需要通过跳线帽来连接一下。这里我们把 P5 的 RXD 和 TXD 用跳线帽与 PA9 和 PA10 连接起来。

scanf重定向,单片机,stm32,嵌入式硬件

信号传输:串口 —— 调试器 —— USB ——电脑

scanf重定向,单片机,stm32,嵌入式硬件

三、实验记录

完成 CubeMX初始化配置 → 生成初始化HAL库工程 →在keli中编写串口程序

1. 完成 CubeMX初始化配置

1.1 利用CubeMX完成HAL库工程模板和初始化:

通过选择芯片型号创建CubeMX工程

在弹出的对话框中输入开发板上的芯片型号,STM32F103RB

在右侧筛选栏中选择Tx型,即开发板上芯片所用的LQFP64型封装,双击建立工程

scanf重定向,单片机,stm32,嵌入式硬件

1.2 RCC模块引脚的配置

在弹出的工程配置对话框中的第一个引脚配置选项卡下,先完成RCC时钟模块引脚配置:

选择启用外部的高速和低速时钟源,HSE和LSE,配置为晶振连接;

配置完成后,对应时钟引脚变绿,同时旁边出现其将要配置模式的文字说明;

scanf重定向,单片机,stm32,嵌入式硬件

1.3 串口的配置

  1. 在侧边栏的通信外设中选择USART1
  2. 在串口下拉框出选择异步(Asynchronous),成功后可以看到对应的串口引脚RX(接收引脚),TX(发送引脚)变绿。
  3. 选择下方的Parameter Settings选项卡确认串口参数。设置波特率为115200,传输数据长度为8 Bit,无奇偶校验位,1个停止位,数据方向(Data Direction)为接收和发送(Receive and Transmit)

scanf重定向,单片机,stm32,嵌入式硬件

  1. 在NVIC Settings选项卡下,开启串口中断,如需调整中断优先级可在右侧修改

scanf重定向,单片机,stm32,嵌入式硬件

1.4 完成时钟配置:

我们前面启用了RCC时钟模块的外部时钟引脚,这里我们需要将外部时钟源配置为实际使用的频率;

查看手册可知:LSE为32.768KHz,HSE为8MHz;

scanf重定向,单片机,stm32,嵌入式硬件

点击上方的时钟配置选项卡,进入时钟配置界面;

前面启用了外部晶振源,这里检查修改HSE\LSE的频率,和实际一致;

在主频选择框中输入72MHz,然后按回车OK;

系统将自动将时钟源、时钟流向、PLL等配置好,以产生相应的主频;

scanf重定向,单片机,stm32,嵌入式硬件

1.5 创建生成工程

scanf重定向,单片机,stm32,嵌入式硬件

scanf重定向,单片机,stm32,嵌入式硬件

 

 

2、printf 和 fputc

对于 printf 函数相信大家都不陌生,第一个C语言程序就是使用 printf 函数在屏幕上的控制台打印出Hello World,之后使用 printf 函数输出各种类型的数据,使用格式控制输出各种长度的字符,甚至输出各种各样的图案。

除此之外,在程序出错的时候,懒得调试,直接简单粗暴的加个 printf 找bug,有时候也不失为一种有效的方法。

对于已经习惯的 printf 函数,你了解多少呢?

printf 定义在 <stdio.h> 头文件中,如下:

int printf(const char *format, ...);

printf 函数根据 format 字符串给出的格式打印输出到 stdout(标准输出)中,当然,printf 函数是不会一个字符一个字符去输出,它会调用更底层的 I/O 函数:fputc去逐个字符打印。

fputc 也定义于头文件 <stdio.h>中,如下:

int fputc(int ch, FILE *stream);

fputc 函数写入字符 ch 到给定输出流 stream,printf函数在调用该函数时,会向stream参数传入stdout从而打印数据到标准输出。

那么,要实现printf打印到串口就变得非常简单了,只需要重新定义fputc函数,在fputc的函数中将数据通过串口发送,称之为:fputc重定向或者printf重定向。

同理,只需要重新定义fputc函数,在scanf的函数中将数据通过串口接收,称之为:scanf重定向。

3. printf,scanf的重定向方法介绍

3.1 方法一 使用HAL库函数实现串口重定向(勾选Use MicroLib)

MicroLib是对标准C库进行了高度优化之后的库,供MDK默认使用,相比之下,MicroLIB的代码更少,资源占用更少,在MDK编译环境下可以使用其MicroLib,快速实现printf重定向;

1)勾选Use MicroLib,使用半主机模式

scanf重定向,单片机,stm32,嵌入式硬件

2)重定义fputc到串口

在MicroLib的stdio.h中,fputc()函数的原型为:int fputc(int ch, FILE* stream)

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

在 usart.c 中,重写 fputc 函数,利用HAL_UART_Transmit打印到串口1,相应的,fgets也可以HAL_UART_Receive重定向;

int fputc(int ch, FILE *f)
{
    uint8_t temp = ch;
    HAL_UART_Transmit(&huart1, &temp, 1, 0xffff);//huart1需要根据你的配置修改
    return ch;
}

int fgetc(FILE *f)
{
    uint8_t ch = 0;
    HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
    return ch;
}

 别忘了在usart.h 中添加 stdio.h,这样在需要使用串口的文件中添加 usart.h 就可以使用串口HAL库和printf重定向了。

#include <stdio.h>

3.2 在MDK中使用标准库重定向printf

MicroLib很好,但在其他编译环境下不可用,有的MCU也不支持,这里再介绍使用标准库重定向printf,可以在各种编译环境下使用;

1)注意,不要勾选Use MicroLib使用半主机模式

2)重定向fputc()函数完整的代码

一样写在 usart.c文件中即可,这里使用了寄存器操作,运行效率更高;

#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 
}; 

FILE __stdout;  
FILE __stdin;   
//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{ 
	x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{ 	
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
	USART1->DR = (uint8_t) ch;      
	return ch;
}

///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数
int fgetc(FILE *f)
{
    uint8_t ch = 0;
	while((USART1->SR&0X20)==0);//循环发送,直到发送完毕   
	ch = (uint8_t) USART1->DR;   
    return ch;
}

别忘了在usart.h 中添加 stdio.h,这样在需要使用串口的文件中添加 usart.h 就可以使用串口HAL库和printf重定向了。

#include <stdio.h>

在所给的例程中,我使用了条件编译 #ifdef USE_PRINT...#endif、#ifndef USE_MICROLIB... #else...#endif来裁剪和选择这部分功能,对于大段代码的启用/弃用也可使用 #if 0/1 ...#endif 来裁剪。

4. 编写main.c测试printf、scanf重定向

1)按前述方法,完成printf、scanf重定向

2)添加printf、scanf的测试程序

在main.c 中写一个简单的测试程序,测试printf和scanf的整数、浮点数、字符和字符串的格式化输入输出。

  /* USER CODE BEGIN 2 */
	uint8_t name[10];
	int32_t age;
	float score;
	int8_t level;
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
		printf("Enter your  name: \r\n");
		scanf ("%10s",name);  
		printf("Enter your age: \r\n");
		scanf ("%d",&age);
		printf("Enter your score: \r\n");
		scanf ("%f",&score);
		printf("Enter your level: \r\n");
		scanf ("%c",&level);
		printf("\r\nHi, %s, %d years old. \r\n", name, age);
		printf("Your score is %2.2f. Your level is %c.\r\n\r\n", score, level);		
    /* USER CODE END WHILE */
  }

3)串口测试

a) 使用 XCOM 串口助手测试

打开串口助手,按下图提示进行测试,可以看到例程可以正常工作;

注意烧录时最好要关闭串口,烧录完成后再重新打开;

每次烧录后,都要重新关闭/打开一次串口助手,串口助手XCOM 才能正常工作;

b) 使用远程串行终端软件 PuTTY 测试

PuTTY 是一个 Telnet/SSH/rlogin/ 纯 TCP 以及串行阜连线软件。常用于远程连接控制台调试,使用非常方便。这里我们串口的简单输入输出测试,也可以使用它。

①先进行终端设置,勾选输入的回显和换行,方便观察输入信息;

scanf重定向,单片机,stm32,嵌入式硬件

②点击串口,配置串口参数后即可打开;

scanf重定向,单片机,stm32,嵌入式硬件

③像控制台一样进行访问,可以回删修改输入,按回车键确认输入,使用非常方便;文章来源地址https://www.toymoban.com/news/detail-757250.html

到了这里,关于printf和scanf的串口重定向,格式化输入输出的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++I/O流——(4)格式化输入/输出(第一节)

    归纳编程学习的感悟, 记录奋斗路上的点滴, 希望能帮到一样刻苦的你! 如有不足欢迎指正! 共同学习交流! 🌎欢迎各位→点赞 👍+ 收藏⭐ + 留言​📝 含泪播种的人一定能含笑收获! 一起加油! 目录 前言:  用ios类成员函数实现格式化输入/输出: 1.控制输入/输出的

    2024年01月21日
    浏览(38)
  • C++I/O流——(4)格式化输入/输出(第二节)

    归纳编程学习的感悟, 记录奋斗路上的点滴, 希望能帮到一样刻苦的你! 如有不足欢迎指正! 共同学习交流! 🌎欢迎各位→点赞 👍+ 收藏⭐ + 留言​📝 含泪播种的人一定能含笑收获! 一起加油!         格式化输出还可以使用控制符,这些控制符可以直接插入到输

    2024年01月18日
    浏览(46)
  • Go 中的格式化字符串`fmt.Sprintf()` 和 `fmt.Printf()`

    在 Go 中,可以使用 fmt.Sprintf() 和 fmt.Printf() 函数来格式化字符串,这两个函数类似于 C 语言中的 scanf 和 printf 函数。 fmt.Sprintf() 函数返回一个格式化后的字符串,而不是将其打印到标准输出流中。下面是一个例子: 输出: 在这个例子中,使用了 %s 和 %d 格式化动词来格式化字

    2024年02月09日
    浏览(45)
  • 【C语言趣味教程】(8) 标准 IO 流:输入和输出 | 标准输入 stdin | 标准输出 stdout | 详解 printf 和 scanf | 探讨 scanf 缓冲区问题和安全性问题

        🔗 《C语言趣味教程》👈 猛戳订阅!!! 0x00 引入:I/O 的概念 计算机中的输入和输出,简称 ,其中:  代表 Input,即输入。

    2024年02月09日
    浏览(51)
  • python格式化输出

    偶然看到一种格式化输出这么写的 可以看到 %(key)s 包围的值可以通过字典对应的值指定 另外的格式化输出还有 \\\"\\\".format() , \\\"\\\" % , f\\\"{}\\\"

    2024年02月05日
    浏览(39)
  • Python基础—格式化输出

    一、旧式字符串格式化方法 %s、%d、%f等被称为占位符,%s对应字符串、%d对应整型、%f对应浮点型 %f -- 默认保留6位小数 %.Nf -- N为整数 %f -- 四舍五入 二、format方法 在字符串中写{},字符串外调用format方法,在format方法中传入值,按照一一对应的关系被写入对应的{} 作用为说明

    2024年02月08日
    浏览(47)
  • C语言(输入输出函数getchar,putchar、gets、puts,scanf,printf的功能以及用法)

    int getchar( void ); 返回值为int,所以需要用一个int变量来接收,不管输入几个字符,每次都只接收第一个字符,常与while和putchar配合使用。 从下面这张图可以看出,输入一个空格也会打印 当然,获取一个字符用得不多,每次都需要获取一串,所以我们可以配合while来使用。 用

    2024年02月02日
    浏览(50)
  • C++常用格式化输出转换

     在C语言中可以用printf以一定的格式打印字符,C++当然也可以。 输入输出及命名空间还不太了解的小伙伴可以看一看C++入门讲解第一篇。  在C++中,可以用流操作符(stream manipulators)控制数据的输出格式,这些流操作符定义在2个头文件( iomanip 和 ios )中,可以用输出运算

    2024年02月04日
    浏览(44)
  • C语言printf格式化打印(%d、%md、%f、%c、%s、%o、%x、%p、%e、%E、%n等)

    我们要记住 signed ➕ 类型 完全等效与 单独的类型 所以我们下面会用 (signed) 来表示可以省略不写。 如果格式化输出的并不是类型匹配的格式,会发生隐式类型转换, (signed) int   (有符号整型)——— %d    unsigned int     (无符号的int类型)——— %u     size_t    (无符号的

    2024年02月04日
    浏览(50)
  • 【Python入门篇】——Python基础语法(字符串格式化,表达式格式化和数据输入)

    作者简介: 辭七七,目前大一,正在学习C/C++,Java,Python等 作者主页: 七七的个人主页 文章收录专栏: Python入门,本专栏主要内容为Python的基础语法,Python中的选择循环语句,Python函数,Python的数据容器等。 欢迎大家点赞 👍 收藏 ⭐ 加关注哦!💖💖 目前通过%符号占位

    2024年02月05日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包