STM32的USARTx中u3_printf函数解析

发布者:虚拟现实迷最新更新时间:2022-04-21 来源: eefocus关键字:STM32 手机看文章 扫描二维码
随时随地手机看文章

我们在STM32中常常使用printf来将信息打印至PC端控制台上。但是有这样一种函数,它可以把数据以我们指定的格式装进字符串中——sprinft和vsprintf。


⑴ sprintf函数使用的方式如下:


① 将多个参数以指定格式写入字符串


int a=1,b=2;  

char s[10];  

sprintf(s,"a=%d,b=%d",1,2);  

puts(s); 

 


输出结果:a=1,b=2


② 错误使用:在函数封装中使用


void Myprintf(const char* fmt,...)  // 传递个数不定的参数

{  

  char s[10];  

  sprintf(s,fmt);  // 出现错误

  puts(s);  

}  

 


封装函数的使用:


int a=1,b=2;  

Myprintf("a=%d,b=%d",a,b);  

 


输出结果:


a=?,b=? // 不确定值

 


这是因为可变参数在入栈时如下列方式排列:

image.png

但是sprintf只接收了Param1作为自己的参数,这样的话,我们调用的封装函数等价如下:


int a=1,b=2;  

char s[10];  

sprintf(s,"a=%d,b=%d");  // 这里的a,b根本没有值

puts(s);

 


⑵ vsprintf粉墨登场了,它解决了sprintf无法读取可变参数的缺陷


我们要知道可变参数在栈中的排列是连续的,而且占用了一段栈的内存空间,我们首先要知道栈区中可变形参的排列顺序:


int func(int num,...)

{

     ......

}

 


其对应可变参数在栈区中的排列顺序是:

image.png

这里要注意:入栈的顺序是“先入后出-FILO”,因此这里的元素在栈中是倒序排列的,即栈区的末端地址就等于可变参数列表中首个参数的地址。


这里我们要将不定个数的参数传递给函数vsprintf函数,我们就必须要借助这N个参数(参数N~参数1)的地址来进行传参。我们一定要清楚:可变参数指的是参数1~N不包括第一个参数num,这个参数是已知的不算可变参数。


函数vsprintf原型如下:


// 函数功能:将函数地址->ParamEndAddr地址之间的所有参数以Format指定的格式转化为字符串进而赋给以StringFirstAddr为首地址的字符数组

// ParamEndAddr:参数列表中首个参数的地址(栈区中可变参数列表的末端地址)

// Format:指定转化为字符串的格式(详见:printf函数打印字符串的格式)

// StringFirstAddr:用于接受转换后字符串的字符型数组首地址

vpsrintf(char* StringFirstAddr, Format, ParamEndAddr);

 


这里我们要注意:函数在内存中的分布分为RAM和FLASH两大块,其中参数存在RAM中函数的执行内容存在FLASH中,这里的函数名就是参数列表所在栈区在RAM中的首地址,当我们提供一个RAM中参数列表所在栈区的末端地址,我们就可以将整个可变参数列表提取出来。


这里我们介绍几个函数:

image.png

程序如下:


void func(char *fmt, ...)

{

     va_list ap; // 指向参数列表(栈区)中某个元素的指针类型

 

     va_start(ap, fmt);

     va_arg(ap, int);

     va_end(va);

}

 


① 确定“栈区末端地址”的函数——va_start()


函数原型:va_start(va_list ap, 参数列表中的第一个元素)


函数功能:va_start(va_list ap, char* fmt)

image.png

函数的调用使得ap指针指向可变参数列表中的首个元素也是栈区中的最后一个元素地址。


② 根据栈区末端地址和参数类型提取可变参数列表中的指定元素——va_arg()


函数原型:va_arg(va_list ap, 元素的数据类型)


函数功能:va_arg(va_list ap, int)

image.png

va_arg()所做的就是根据ap指向的地址,和第二个参数所确定的类型,将这个参数的中的数据提取出来,作为返回值,同时让ap指向下一个参数。


③ 将指针置空(NULL)的函数——va_end()


函数原型:va_end(va_list ap)


函数功能:va_end()所做的就是让ap这个指针指向0。


函数vsprintf使用方式如下:


void Myprintf(const char* fmt,...)  

{  

  char s[10];  

  va_list ap;  // 定义指向栈区某个元素的指针

  va_start(ap,fmt);  // ap指向可变参数列表的首地址(栈区的末端元素地址)

  vsprintf(s,fmt,ap);  // 将函数首地址~ap之间的可变形参列表赋值给vsprintf函数形参列表

  va_end(ap); // ap指针置空(NULL)

  puts(s);  // 打印字符串至屏幕上

}  

 


但是,这里将一段封装函数Myprintf的参数列表赋值给vsprintf函数当作参数,如果我们操作单个可变参数列表中的元素,我们该如何做呢?


相较于前面一段一段的使用参数列表的元素的最大不同在于“我们需要指定输入参数的个数”,因为我们输入的参数的数据类型未知,个数未知,因此我们要知道我们每个输入参数的数据类型和输入参数的总个数才可以。


// 这里我们指定了可变形参个数为num个

float Average(int num,...) 

{

       int i=0;

       float sum;

       va_list valist;

       va_start(valist,num); // 通过参数列表中收个元素(int num)找到可变参数列表中的收个元素地址并赋值给valist

       for (i = 0; i < num; i++)

       {

             // 根据输入元素的数据类型在栈区中读取数据

             sum+=(float)va_arg(valist,int); // 假设所有输入元素全文int类型的参数,当不断循环时不断改变valist指针指向元素,进而不断轮询访问参数列表中的所有元素

       }

       va_end(valist); // 置空(NULL)valist指针

       return sum/(float)num;

}


 


注意:我们要使用这些函数必须要加载“#include ”头文件。

关键字:STM32 引用地址:STM32的USARTx中u3_printf函数解析

上一篇:基于战舰V3的MPU6050六轴陀螺仪实验
下一篇:独立看门狗IWDG详细解析

推荐阅读最新更新时间:2024-11-11 10:49

STM32学习笔记一一SysTick
1.简介 SysTick 定时器被捆绑在 NVIC 中,用于产生 SysTick 异常(异常号:15)。在以前,操作系统和有所有使用了时基的系统,都必须要一个硬件定时器来产生需要的“滴答”中断,作为整个系统的时基。滴答中断对操作系统尤其重要。例如,操作系统可以为多个任务许以不同数目的时间片,确保没有一个任务能霸占系统;或者把每个定时器周期的某个时间范围赐予特定的任务等,还有操作系统提供的各种定时功能,都与这个滴答定时器有关。因此,需要一个定时器来产生周期性的中断,而且最好还让用户程序不能随意访问它的寄存器,以维持操作系统“心跳”的节律。 Cortex-M3 在内核部分 包含了一个简单的定时器——SysTick timer。
[单片机]
<font color='red'>STM32</font>学习笔记一一SysTick
stm32 usb转串口的程序设计解析
  串口调试在项目中被使用越来越多,串口资源的紧缺也变的尤为突出。很多本本人群,更是深有体会,不准备一个USB转串口工具就没办法进行开发。   了解USB虚拟串口,为了在项目中用一下这个USB,调试方便一些,供电可直供。公司以后的产品开发就基于STM32这个平台,从contex_M3到contex-M4。不管速度、功耗、价格、采购的方便性都有竞争力,不想再修改了(除非它无法满足要求)。   STM32基本上都带有USB串口。如果不把它用上而另外加一个USB转串口单元,未免显得太落后了而且也是一种资源的浪费。顺便说一下,根据公司的状况,合适的才是好的。以前一直用TI的,从430到ARM到28XX。这个ST的包含了以前的所有,
[单片机]
<font color='red'>stm32</font> usb转串口的程序设计解析
STM32外部中断及定时器编程示例
简介:STM32外部中断及定时器编程示例 /*======================================================================================== *名 称: main.c *功 能: *入口 参数: *说 明: *范 例: *编者 时 间: *========================================================================================*/ #include stm32f10x.h #include 12864.h Er
[单片机]
STM32函数之断言
我们在学STM32的时候函数assert_param出现的几率非常大,上网搜索一下,网上一般解释断言机制,做为程序开发调试阶段时使用。下面我就谈一下我对这些应用的看法,学习东西抱着知其然也要知其所以然。 4 断言机制函数assert_param 我们在分析库函数的时候,几乎每一个函数的原型有这个函数assert_param();下面以assert_param(IS_GPIO_ALL_PERIPH(GPIOx));为例说一下我的理解,函数的参数IS_GPIO_ALL_PERIPH(GPIOx),我们可以寻找到原型 #define IS_GPIO_ALL_PERIPH(PERIPH) (((*(uint32
[单片机]
<font color='red'>STM32</font>库<font color='red'>函数</font>之断言
浅谈费控电表在充电站微电网的应用
摘要:现阶段由于充电站内的电费计量模块不能接入电网公司电表系统,电网公司需额外加装电表获取充电数据。设计了一种基于储能电表的充电站,整合电表与充电站的重复功能模块。利用STM32F103C8T6微控制器结合控制器局域网络总线完成充电站与储能电表之间的电气连接和交互控制,并进行了样机开发验证。结果表明相较于传统充电站,基于储能电表的充电站可以简化充电站结构,降低充电站制造、安装成本,更好地实现电动汽 0引言 近年来我国电动汽车(ElectricVehicle,EV)销量持续猛增,根据预测2021年中国新能源汽车销量或将超过180万辆,相较2020年销量同比增长明显。一方面持续增长的EV充电负荷会产生新的充电高峰,对电网运行造成
[单片机]
浅谈费控电表在充电站微电网的应用
stm32.cube(六)——HAL.FLASH
一、片内Flash特性 1.1 FLash结构简图 我的开发板是stm32f103xx,所以片内flash主存储器大小128K,单页为1K。不同的芯片flash大小不同,页大小也不同。 主存储器 用来存储Rom程序,烧写的区域。当然也可以存一些其他东西,比如做nvram使用。 信息块 这个区域分两个部分。 存储区,用户不可写区域,用来存储ISP下载时用到的程序。当用ISP模式进行烧写时,自动调用里面的程序下载数据并烧写到flash里。 用户选项字,存储硬件配置信息。某些复用的外设可能在上电复位后就要立即知道它被用作其中哪个用途。 用户选项字默认不可写,它上电自动加锁。只有通过向FLASH_OPTKEYR依次写入约定解锁码KE
[单片机]
STM32 USB NAND Flash模拟U盘无法格式化问题的解决
前几天,一直在寻找NAND Flash模拟U盘程序无法格式化的问题。在中秋月圆之夜,还苦逼地在实验室调代码,也许是杭州大圆月的原因,今晚感觉整人特别亢奋,效率也特别高,灵感也多。终于,在不懈的努力下,找到代码中的害群之马,把无法格式的问题解决掉了。下面就来说说。 这几天一直在想问题出在哪里,不知道自己的代码跟官方的例程对照了多少次,把不一样的地方全都改了一遍,最终未果。今晚思路特别清晰,于是在想到格式化实际上就是向存储器写数据而已,而设计到写数据部分的代码就只在mass_mal.c、memory.c以及存储器的驱动文件。于是反复检查这几个文件,终于发现一点端倪了,问题出在memroy.c这个文件里。 memory.c这个文
[单片机]
IAR环境下ucosii在STM32上的移植
Ucosii移植到STM32上 1.使用的开发环境是IAR 5.4 STM32芯片为STM32F103ZET6 使用ST官方提供的标准固件库,建立工程, 我下载的苦艰苦的版本为STM32F10x_StdPeriph_Lib_V3.5.0,里面的文件分布为: 其中,Libraries文件夹里面放的是标准库文件,Project文件夹里面放的是STM32的各个外设的使用范例和一个工程模板,Utilities文件夹里面放的是ST公司的评估板例子,剩下的文件就是教我们怎样使用标准库,而我们主要使用的就是Libraries和Project里面的文件。 1.1首先新建stm32这个文件夹,在里面再新建3个文件夹include,proj
[单片机]

推荐帖子

怎样测试TMS320DM6446是不是坏了
TMS320DM6446主板怎么回事采用TMS320DM6446主板测试找不到ip地址,灯亮的正常,不知是不是TMS320DM6446换了怎样测试TMS320DM6446是不是坏了
姚德军 DSP 与 ARM 处理器
【2024 DigiKey 创意大赛】智能垃圾桶开箱贴
元器件开箱贴:智能垃圾桶项目开箱情况 外观与尺寸:SeedSoM-STM32MP157C是一个小型的单板计算机,尺寸适中,外观精致,非常适合嵌入式项目。 功能特点: 处理能力:基于高性能的STM32MP157C芯片,具有强大的处理能力,适合处理复杂的数据和控制逻辑。 I/O接口:提供丰富的I/O接口,包括GPIO、SPI、I2C等,方便连接各种传感器和执行器。 操作系统支持:支持多种实时操作系统,如FreeRTOS,适合开发复杂的嵌入式应用。
zfw152666 DigiKey得捷技术专区
请问在ce6平台下怎么测试短信和电话程序呢?
在WM6下,仿真器可以与CellularEmulator配合使用测试电话和短信,但wince6在仿真器环境下该怎么弄呢?请问在ce6平台下怎么测试短信和电话程序呢?我也要弄电话功能,你用的GSM是什么?我的是SIM300C!我还没硬件呢,只是在仿真器上研究,不知道有没有跟仿真器配合使用的工具引用2楼srz007的回复:我还没硬件呢,只是在仿真器上研究,不知道有没有跟仿真器配合使用的工具 没有配件,还是不要想啦!模拟器是一点可能也没有的。。。。有设备的话就LOG呗。呵呵
goout 嵌入式系统
左手材料的理论起源与研究进展(转贴)
2001年美国加州大学制成一种新型异性材料并观察到其反常折射现象,引起学术界关注;2003年美国麻省理工大学实验证明了这种异性材料的可制造性,引起学术界、工业界和军方的高度重视;2003年美国《科学》杂志将这种奇异材料的研制纳入年度十大科学进展。这是科学界谓之的一种颠倒了物理学常规定律的“左手材料”,它在固体物理、材料科学、光学和应用电磁学领域内开始获得愈来愈广泛的青睐,其研究正呈现迅速发展之势,其反常特性则预示着材料世界前所未有的革命性时刻的到来。一、左手理论的起源“左手材料”研究所
yh19782000 RF/无线
中国MCU市场厂商排名2012
2012年供应商排名  1、RenesasElectronics  2、FreescaleSemiconductor  3、MicrochipTechnology  4、STMicroelectronics  5、Atmel  6、InfineonTechnologies  7、NXP  8、TexasInstruments  9、Toshiba  10、Samsung中国MCU市场厂商排名2012other也占
wangfuchong 单片机
【MicroPython】+家用气象仪
我的家用气像仪已经开工了,以后分享的内容都在会本贴分享。全程都开源!欢迎大家来指教,纯的菜鸟,所以希望大家帮忙指正。估对这python语言是完全零了解,所以是一边看着语法书一边写的,github.com上面的分享的驱动也挺多的,不过有些怪怪的,比如MicroPython5110的驱动不是太完善,没有提供简易字库供,需要自己建字库,另外也没有提供单字符与字符串输出API,所以就需要自己来写了,昨天简单的驱动一下LCD5110,今天去github.com别的树莓派上拷了个简易字库,建了一个
strong161 MicroPython开源版块
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved