目录
描述
-
1
putchar
在没有读到数据时会一直死等,实现一个putchar_nowait
函数, 有串口数据就读出来,没有串口数据就立刻返回错误
-
2
printf函数是把输出信息直接从串口输出了,有时候我们要得到这些信息,比如后面的LCD程序中,想在LCD上显示这些信息时,就要先得到这些信息再一次性的输出到LCD。实现这个函数:int snprintf(char *str, size_t size, const char *format, …);它会把输出信息先保存在str里。(提示: printf函数中最终使用__out_putchar进行打印,你也许可以修改它,把字符保存在str中。)
解答
-
1
putchar在没有读到数据时会一直死等,实现一个putchar_nowait()函数, 有串口数据就读出来,没有串口数据就立刻返回错误,(添加一个时间变量,在
while
中一直递减就大致模拟无阻塞等待)
//修改前
void putchar(int c)
{
while (!(UTRSTAT0 & (1<<2)));
UTXH0 = (unsigned char)c;
}
//修改后(阻塞一段时间)
int putchar_nowait(void)
{
unsigned int time = 2000000;
unsigned char val;
while(!(UTRSTAT0&(1<<2)) && --time);
if(time)
{
val = URXH0;
while(!(UTRSTAT0&(1<<2)));
UTXH0 = (unsigned char)val;
return 1;
}
else
return 0;
}
-
2
思想是把原本输出到串口的内容都输出到
str
,在格式化输出的时候需要统计转换到的字符数,改变str
指针位置,同时要检查是否超出长度指定的长度
//my_print.h
/*
*模仿sprint函数,按照format格式,把数据输入到str中
*/
int snprintf(char *str, int size, const char *format, ...);
//my_printf.c
#include "my_printf.h"
void __out_putchar(char *str,unsigned char c)
{
*str = c;
return ;
}
unsigned char hex_tab[]= {'0','1','2','3','4','5','6','7',\
'8','9','a','b','c','d','e','f'
};
static int outc(char *str,int c)
{
__out_putchar(str,c);
return 0;
}
static int outs(char *str, const char *s)
{
int ret = 0;
while (*s != '\0')
{
__out_putchar(str++,*s++);
ret++;
}
return ret;
}
static int out_num(char *str,long n, int base,char lead,int maxwidth)
{
unsigned long m=0;
char buf[MAX_NUMBER_BYTES];
char *s = buf + sizeof(buf);
int count=0,i=0;
*--s = '\0';
if (n < 0)
{
m = -n;
}
else
{
m = n;
}
do
{
*--s = hex_tab[m%base];
count++;
}
while ((m /= base) != 0);
if( maxwidth && count < maxwidth)
{
for (i=maxwidth - count; i; i--)
*--s = lead;
}
if (n < 0)
*--s = '-';
return outs(str,s);
}
static int my_vprintf(char *str,int size,const char *fmt, va_list ap)
{
char lead=' ';
int maxwidth=0;
int s = 0;
for(; *fmt != '\0'; fmt++)
{
if (*fmt != '%')
{
if(++s <= size)
{
outc(str++,*fmt);
continue;
}
else
break;
}
//format : %08d, %8d,%d,%u,%x,%f,%c,%s
fmt++;
if(*fmt == '0')
{
lead = '0';
fmt++;
}
lead=' ';
maxwidth=0;
while(*fmt >= '0' && *fmt <= '9')
{
maxwidth *=10;
maxwidth += (*fmt - '0');
fmt++;
}
int len;
switch (*fmt)
{
case 'd':
len = out_num(str,va_arg(ap, int), 10,lead,maxwidth);
break;
case 'o':
len = out_num(str,va_arg(ap, unsigned int), 8,lead,maxwidth);
break;
case 'u':
len = out_num(str,va_arg(ap, unsigned int), 10,lead,maxwidth);
break;
case 'x':
len = out_num(str,va_arg(ap, unsigned int), 16,lead,maxwidth);
break;
case 'c':
if(++s <= size)
outc(str++,va_arg(ap, int ));
break;
case 's':
len = outs(str,va_arg(ap, char *));
break;
default:
if(++s <= size)
outc(str++,*fmt);
break;
}
//检查输入的字符串是否超出长度
if(len<= (size-s))
{
str+=len;
s+=len;
}
else
{
*(str+size) = '\0';
s = size+1;
}
}
return 0;
}
int snprintf(char *str, int size, const char *format, ...)
{
va_list ap;
//得到数据缓冲区首地址
va_start(ap, format);
//根据格式+数据进行输出到str
my_vprintf(str, size, format, ap);
//指针赋值,避免野指针
va_end(ap);
return 0;
}