关于Stm32串口输出模仿printf编写的函数方法(野火stm32F103指南者板适用)

我在Stm32串口编程中遇到的一些很有用的函数

下面的这几个函数和测试是我在Stm32串口编程中遇到的一些对新人极不友好 的函数,但是学会之后非常的好用!!写好一次,以后可以直接复制粘贴了!!
再说一遍,这几个函数主要是围绕串口输出的哦。
最后一部分是我自己编写的输出函数,模仿printf就直接输出了,虽然也可以函数重定向,但是重定向不如这种方式灵活。
串口初始化就直接跳过,例程网上非常丰富。

1、va_list va_start(ap, variable) va_arg(ap, type) va_end(ap)

//当出现可变数量的入参时的va_list、va_start
va_list ap; 定义一个va_list变量ap
va_start(ap,v);执行ap = (va_list)&v + _INTSIZEOF(v),ap指向参数v之后的那个参数的地址,即ap指向第一个可变参数在堆栈的地址。
va_arg(ap,t)( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )取出当前ap指针所指的值,并使ap指向下一个参数。
ap+= sizeof(t类型),让ap指向下一个参数的地址。然后返回ap-sizeof(t类型)的t类型指针,这正是第一个可变参数在堆栈里的地址。然后
用取得这个地址的内容。
va_end(ap); 清空va_list ap。
//示例,这个函数就是我们的串口输出函数,把串口的输出写成模拟printf的形式
void u3_printf(char* fmt, ...)  
{  
	u16 i,j;
	va_list ap;
	va_start(ap,fmt);//初始化ap,ap指向第二个开始的参数(第一个参数后)
	vsprintf((char*)USART3_TX_BUF,fmt,ap);//将ap根据format格式化后填入数组
	va_end(ap);//结束可变参数获取
	i=strlen((const char*)USART3_TX_BUF);		//此次发送数据的长度
	for(j=0;j<i;j++)							//循环发送数据
	{
	  while(USART_GetFlagStatus(USART3,USART_FLAG_TC)==RESET); //循环发送,直到发送完毕
		USART_SendData(USART3,USART3_TX_BUF[j]);
	}
}

2、vsprintf() 将ap指针格式化写到char型指针

//vsprintf()函数
定义函数:int vsprintf(char * str, const char * format, va_list ap);
函数说明:vsprintf()会根据参数format 字符串来转换并格式化数据, 然后将结果复制到参数str 所指的字符串数组, 直到出现字符串结束('\0')为止. 关于参数format 字符串的格式请参考printf(). va_list 用法请参考附录C 或vprintf()范例.
//关于vsprintf()可见参数一为char* const类型 所以代表指针是常量,不可以更改指针
_Success_(return >= 0)
    _Check_return_opt_ _CRT_INSECURE_DEPRECATE(vsprintf_s)
    _CRT_STDIO_INLINE int __CRTDECL vsprintf(
        _Pre_notnull_ _Always_(_Post_z_) char*       const _Buffer,
        _In_z_ _Printf_format_string_    char const* const _Format,
                                         va_list           _ArgList
        )
//经过测试,只能在参数一的位置上放一个char型数组的头地址,即数组名
//附加在visualStudio2019中的测试代码,参数一不可以为char * p;或者char * const p;
#define _CRT_SECURE_NO_WARNINGS
#include 
#include 
#include 

void u3_printf(char* fmt, ...);

int main() {
	u3_printf("hi---%s","hhhhhha");
	return 0;
}


void u3_printf(char* fmt, ...)
{
	unsigned char USART3_TX_BUF[600];
	unsigned int i, j;
	va_list ap;
	va_start(ap, fmt);//初始化ap,ap指向第二个开始的参数(第一个参数后)
	vsprintf((char*)USART3_TX_BUF, fmt, ap);//将ap根据format格式化后填入数组,sizeof(USART3_TX_BUF)
	va_end(ap);//结束可变参数获取
	i = strlen((const char*)USART3_TX_BUF);		//此次发送数据的长度
	for (j = 0; j < i; j++)							//循环发送数据
	{
		//while (USART_GetFlagStatus(USART3, USART_FLAG_TC) == RESET); //循环发送,直到发送完毕   
		//USART_SendData(USART3, USART3_TX_BUF[j]);
		printf("%c", USART3_TX_BUF[j]);
	}
}

3、sprintf() 将数量可变的参数写到char型指针

//sprintf():
函数功能:把格式化的数据写入某个字符串
函数原型:int sprintf( char *buffer, const char *format [, argument] … );
返回值:字符串长度(strlen)
//例子:
char* who = “I”;
char* whom = “CSDN”;
sprintf(s, “%s love %s.”, who, whom); //产生:"I love CSDN. " 这字符串写到s中
sprintf(s, “%10.3f”, 3.1415626); //产生:" 3.142"

4、strstr() 判断子串

//strstr()函数
strstr ()函数:
strstr (str1,str2)函数用于判断字符串str2是否是str1的子串。如果是,则返回str2在str1中首次出现的地址:否则,返回NULL。 

5、我的串口输出函数(重点)

/*
 *我写的串口格式化输出函数	u_printf()这个更简单一些
 */
void u_printf(USART_TypeDef * USARTx, const char * format, ...){
	int length;
	int j;
	va_list ap;
	va_start(ap, format);//初始化
	vsprintf((char *)USART3_TX_BUF, format, ap);
	va_end(ap);//清除
	length = strlen((const char *)USART3_TX_BUF);
	for(j = 0; j < length; j++){
		while(USART_GetFlagStatus(USARTx, USART_FLAG_TC)==RESET);//等待
		USART_SendData(USARTx, USART3_TX_BUF[j]);
	}
}
//或者这个,麻烦一些
void USART_printf ( USART_TypeDef * USARTx, char * Data, ... )
{
	const char *s;
	int d;   
	char buf[16];

	
	va_list ap;
	va_start(ap, Data);

	while ( * Data != 0 )     // 判断是否到达字符串结束符
	{				                          
		if ( * Data == 0x5c )  //'\'
		{									  
			switch ( *++Data )
			{
				case 'r':							          //回车符
				USART_SendData(USARTx, 0x0d);
				Data ++;
				break;

				case 'n':							          //换行符
				USART_SendData(USARTx, 0x0a);	
				Data ++;
				break;

				default:
				Data ++;
				break;
			}			 
		}
		
		else if ( * Data == '%')
		{									  //
			switch ( *++Data )
			{				
				case 's':										  //字符串
				s = va_arg(ap, const char *);
				
				for ( ; *s; s++) 
				{
					USART_SendData(USARTx,*s);
					while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );
				}
				
				Data++;
				
				break;

				case 'd':			
					//十进制
				d = va_arg(ap, int);
				
				itoa(d, buf, 10);
				
				for (s = buf; *s; s++) 
				{
					USART_SendData(USARTx,*s);
					while( USART_GetFlagStatus(USARTx, USART_FLAG_TXE) == RESET );
				}
				
				Data++;
				
				break;
				
				default:
				Data++;
				
				break;
				
			}		 
		}
		
		else USART_SendData(USARTx, *Data++);
		
		while ( USART_GetFlagStatus ( USARTx, USART_FLAG_TXE ) == RESET );
		
	}
}

就这些~
好用的话点个赞吧~

你可能感兴趣的:(我的单片机学习笔记,stm32,c语言,c++,单片机,visual,studio)