| 
 
	大家是不是觉得C标准库里面的printf函数特别的好用呢?FatFs文件系统也有一个f_printf函数,大部分时候这个函数是很好用的。 
 
自己就折腾了一段时间,终于将基本用到的功能实现了。 
 
函数如下 
 
 
[mw_shl_code=c,true]/**
  *****************************************************************************
  * @Name   : printf格式化输出到液晶
  *
  * @Brief  : none
  *
  * @Input  : lcd_ch: printf结构体指针
  *           format: 格式化字符串
  *           ...:    长参数
  *
  * @Output : none
  *
  * @Return : none
  *****************************************************************************
**/
int LCD_printf(_Typedef_lcdprintf* lcd_pr/* 结构参数 */, const u8 *format/* 格式化参数 */, .../* 长参数 */)
{
	const char *str;
	char c=0;
	float valflt=0;
	int dec=0;
	u8 index=0;
	
	va_list ap;
	va_start(ap, format);
	
	lcd_pr->min_width = 7;
	lcd_pr->precision = 3;
	lcd_pr->charcnt   = 0;
	
	while(*format != '\0')  //直到遇到结束符
	{
		if(*format == 0x5c)  //符号'\'
		{
			format++;
			switch(*format)
			{
				case 'r':  //LF
						_printfch(lcd_pr, '\r');
						format++;
						break;
				
				case 'n':  //CR
						_printfch(lcd_pr, '\n');
						format++;
						break;
				
				case 't':  //Tab
						_printfch(lcd_pr, '\t');
						format++;
						break;
				
				default:
						format++;
						break;
			}
		}
		else if(*format == '%')  //带格式输出
		{
			format++;
			index = 0;
			lcd_pr->min_width = 0;
			while((*format <= '9') && (*format >= '0'))  //域宽
			{
				lcd_pr->min_width = (lcd_pr->min_width * index * 10) + (*format - '0');
				index++;
				format++;
			}
			if(*format == '.')  //检测到点
			{
				format++;
				index = 0;
				lcd_pr->precision = 0;
				while((*format <= '9') && (*format >= '0'))  //精度
				{
					lcd_pr->precision = (lcd_pr->precision * index * 10) + (*format - '0');
					index++;
					format++;
				}
			}
			switch(*format)  //检测格式码
			{
				case '%':  //输出%符号
						_printfch(lcd_pr, '%');
						lcd_pr->cursorx += lcd_dev.ascii_w;
						format++;
						break;
				
				case 'c':  //输出字符
						c = va_arg(ap, int);
						_printfch(lcd_pr, c);
						format++;
						break;
				
				case 'S':
				case 's':  //输出字符串
						str = va_arg(ap, const char *);
						_printfstr(lcd_pr, (char*)str);
						format++;
						break;
						
				case 'd':  //输出十进制数
						dec = va_arg(ap, int);
						_printfint(lcd_pr, dec);
						format++;
						break;
				
				case 'f':  //输出浮点数
						valflt = va_arg(ap, double);
						_printfflt(lcd_pr, valflt);
						format++;
						break;
				
				case 'X':
				case 'x':  //输出十六进制数
						dec = va_arg(ap, int);
						_printfhex(lcd_pr, dec, 16);
						format++;
						break;
				
				case 'o':  //输出八进制数
						dec = va_arg(ap, int);
						_printfhex(lcd_pr, dec, 8);
						format++;
						break;
				
				case 'm':
						dec = va_arg(ap, int);
						if(dec > 21)  dec = 21;  //限制最大的域宽是21,包括小数点
						lcd_pr->min_width = (u16)dec;
						format++;
						if(*format == '.')
						{
							format++;
							if(*format == 'n')
							{
								dec = va_arg(ap, int);
								if(dec > 8)  dec = 8;  //限制最小的小数精度是,0.00000001
								lcd_pr->precision = (u16)dec;
								format++;
								if(*format == 'f')
								{
									valflt = va_arg(ap, double);
									_printfflt(lcd_pr, valflt);
									format++;
								}
							}
						}
						break;				
				
				default:
						_printfch(lcd_pr, *format);
						format++;
						break;
			}  //end check format
		}
		else if(*format < 0x80)  //字符输出
		{
			_printfch(lcd_pr, *format);
			lcd_pr->cursorx += lcd_dev.ascii_w;  //下一个字符位置
			format++;
		}
#if _LCD_Support_GBK==1  //支持中文
		else
		{
			LCD_Draw_GBK(lcd_pr->cursorx, lcd_pr->cursory, (u8*)format++, (u8)lcd_pr->mode);
			lcd_pr->cursorx += lcd_dev.gbk_w;
			format++;
			lcd_pr->charcnt++;
		}
#endif
	}  //end while
	va_end(ap);
	
	return (int)lcd_pr->charcnt;
}[/mw_shl_code]
 
	功能使用说明:
 
	1、函数直接返回输出字符的个数,不包含’\r’、’\n’、’\t’符号的计数,或者直接读取结构体lcd_printf.charcnt也是可以得到输出字符总数的,最大为256个 
 
	2、具体实现功能如下:
 
	    A、直接打印字符串,支持中文
 
	    B、%c输出字符 
 
	    C、%%输出%符号 
 
	    D、%d输出十进制数,有正负之分 
 
	    E、%f输出浮点数,默认域宽是7,小数精度是0.001,小数点包含在域宽内,有正负之分(下同) 
 
	    F、%12.5f输出一定长度和精度的浮点数,12就是域宽,5就是小数精度 
 
	    G、%m.nf自定义输出指定域宽和长度可变的浮点数,限制最大的域宽21,精度0.00000001 
 
	    H、%s输出字符串,支持中文输出 
 
	    I、%x(或者%X)输出十六进制数,前序统一显示为“0x” 
 
	    J、%o输出八进制数,前序显示为0 
 
	    K、支持回车功能’\n’
 
	    L、支持换行功能’\r’
 
	    M、支持Tab功能’\t’,默认4个ASCII空位 
 
3、测试代码 
 
 
[mw_shl_code=c,true]lcd_printf.cursorx = 30;
	lcd_printf.cursory = 287+48;
	LCD_printf(&lcd_printf, "Hello\tWord!\n");
	LCD_printf(&lcd_printf, "Hello WarShip & 原子哥!\n");
	
	LCD_printf(&lcd_printf, "LCD Printf Test->%s\n", (u8*)menu_buf[2][1]);
	LCD_printf(&lcd_printf, "Congratulations!!!\n");
	
	LCD_printf(&lcd_printf, "the float&m.n is:%m.nf\n", (int)5, (int)2, (float)655.353);
	
	LCD_printf(&lcd_printf, "The Pre is:%c", 0x38);
	lcd_printf.cursorx += lcd_dev.ascii_w;
	LCD_printf(&lcd_printf, "%%\n");
	
	LCD_printf(&lcd_printf, "LCD ID is:%x\n", (u16)lcd_dev._lcdobj.lcdid);
	LCD_printf(&lcd_printf, "LCD ID is:%d\n", (u16)9328);
	LCD_printf(&lcd_printf, "LCD ID is:%8.3f\n", (float)293.283);
	LCD_printf(&lcd_printf, "LCD ID is:%f\n", (float)-293.283);
	LCD_printf(&lcd_printf, "LCD ID is:%d\n", (int)-9328);
	
	LCD_printf(&lcd_printf, "Hello Printf!\n");
	LCD_printf(&lcd_printf, "String is:%s\n", (u8*)menu_buf[0][1]);
	
	LCD_printf(&lcd_printf, "您好\n");
	LCD_printf(&lcd_printf, "中文字符串是:%s\n", (u8*)menu_buf[0][0]);
	
	LCD_printf(&lcd_printf, "Long Parameter is: d%d, f%f, 0x9325->%x\n", (u16)1338, (float)13.88, (u16)9325);
	
	LCD_printf(&lcd_printf, "8 hex is:9325->%o\n", (u16)9325);
	
	i = (u8)LCD_printf(&lcd_printf, "Hello Printf!\n");  //13
	
	LCD_printf(&lcd_printf, "String Len is: %d\n", (u8)i);  //13
	
	LCD_printf(&lcd_printf, "最后整体测试结果是->%s!!!\n", (u8*)menu_buf[2][1]);[/mw_shl_code]
 
 
	 
 
 
附上4.3寸屏幕测试“裸照” 和战舰测试工程: 
  
 
 
	 
 
附: 
想要改变某个行的背景颜色(画笔颜色类似),这个版本可以这样操作,后续版本增加直接修改背景颜色和画笔颜色的函数,步骤如下: 
1、先保存之前的背景颜色:old_color = lcd_dev._lcdobj.backcol 
2、设置新的颜色值          :LCD_Set_BackCol(news_color) 
3、显示完这行之后(多行也可以)再变回原来的颜色即可:LCD_Set_BackCol(old_color) 
  |