大家是不是觉得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)
|