6.5 C51的库函数

C51语言中提供了大量功能强大的库函数,这些库函数都是编译系统自带的已定义好的函数,用户可以在程序中直接调用,而无须再定义。合理使用库函数可以简化程序设计、加快程序执行速度。每个库函数都在相应的头文件中给出了函数原型声明,在C51中使用库函数时,必须在源程序的开始处使用预处理命令#include将相应的头文件包含进来。下面就对KeilµVision3编译环境提供的C51库函数分类进行介绍。

6.5.1 I/O函数库

I/O函数主要用于数据通过串口的输入和输出等操作,C51的I/O库函数的原型声明包含在头文件stdio.h中。由于这些I/O函数使用了8051单片机的串行接口,因此在使用之前需要先进行串口的初始化。然后,才可以实现正确的数据通信。典型的串口初始化需要设置串口模式和波特率,示例如下。


01:SCON=0x50;//串口模式1,允许接收

02:TMOD|=0x20;//初始化T1为定时功能,模式2

03:PCON|=0x80;//设置SMOD=1

04:TL1=0xF4;//波特率4800bit/s,初值

05:TH1=0xF4;

06:IE|=0x90;//中断

07:TR1=1;//启动定时器


提示第6行使用的是复合运算符“|=”。

当然,在KeilµVision3集成开发环境中如果没有进行串口初始化同样可以进行编译仿真。在下面的I/O函数介绍中,将省略串口初始化代码,而不影响程序的仿真执行。但如果程序运行在实际的硬件设备上,则必须对串口进行初始化。

I/O函数库中提供的库函数,如表6.1所示。下面将分别进行介绍。

6.5 C51的库函数 - 图1

1.字符读入函数_getkey

字符读入函数_getkey的函数原型如下。


char_getkey(void);


字符读入函数用于从单片机串口读入一个字符。该函数执行的操作是首先等待从8051的串口读入一个字符,当有字符输入时返回读入的原字符。程序示例如下。


include<stdio.h>//头文件

include<reg51.h>

void main(void)//主函数

{

char ch;

SCON=0x50;//串口模式1,允许接收

TMOD|=0x20;//初始化T1为定时功能,模式2

PCON|=0x80;//设置SMOD=1

TL1=0xF4;//波特率4800bit/s,初值

TH1=0xF4;

IE|=0x90;//中断

TR1=1;//启动定时器

while((ch=_getkey())!=0x0d)//获取字符

{

printf(“Input key=%c%bx\n”,ch,ch);//输出结果

}

}


该程序可以在KeilµVision3编译环境中执行,当通过串口输入字符d时,运行的结果如下。


Input key=d 64


在本例中,首先对串口进行了初始化,设置4800bit/s的波特率。接着调用库函数_getkey等待获取串口输入的字符。当有字符输入时,通过串口0输出该字符以及其对应的十六进制数。当输入回车字符0x0d的时候将结束程序。

2.字符读入输出函数getchar

字符读入输出函数getchar的函数原型如下。


char getchar(void);


字符读入输出函数getchar用于从串口读入一个字符并输出该字符。该函数与_getkey函数类似,但也有不同之处。字符读入输出函数getchar执行的操作是使用_getkey从单片机串口读入的一个字符,然后再使用putchar函数将读入的字符从串口输出。程序示例如下。


include<stdio.h>//头文件

include<reg51.h>

void main(void)//主函数

{

char ch;

//初始化串口

while((ch=getchar())!=0x0d)//获取字符

{

printf(“Input key=%c%bx\n”,ch,ch);//输出结果

}

}


该程序可以在KeilµVision3编译环境中执行,当字符输入e时,运行的结果如下。


d Input key=d 64


在本例中,首要定义了字符型变量ch,接着调用getchar函数获取字符并赋值给ch。当有字符输入的时候,通过串口0输出该字符以及对应的十六进制数。当输入回车字符0x0d的时候将结束程序。

注意这里省略了单片机串口的初始化语句,如果需要在单片机硬件上运行,则需要添加相应的初始化语句。后面的程序均作了相同的省略。

3.字符串读入函数gets

字符串读入函数gets的函数原型如下。


chargets(chars,int n);


其中,s为读入的字符串,n为字符串的长度。字符串读入函数gets用于从串口读入一个字符串。该函数执行的操作是使用getchar函数从单片机串口读入一个长度为n的字符串,并保存到字符数组s中。在字符串读入的过程中,如果遇到换行符将结束字符的输入。字符串输入成功时将返回传入的参数指针,失败时返回空指针NULL。程序示例如下。


include<stdio.h>//头文件

include<reg51.h>

void main(void)//主函数

{

xdata char str[50];

//初始化串口

gets(str,sizeof(str));//字符串读入

printf(“Input string=%s\n”,str);//输出结果

}


该程序可以在KeilµVision3编译环境中执行,当通过串口输入字符串“Good morning!”时,程序运行的结果如下。


Input string=Good morning!


在本例中,首要定义一个字符型数组str,接着调用gets函数通过串口获取字符。当输入字符串“Good morning!”并加上换行符时,gets函数将结束,最后使用printf函数通过串口0输出该字符串。

4.字符回送函数ungetchar

字符回送函数ungetchar的函数原型如下。


char ungetchar(char c);


其中,c为输入字符。字符回送函数ungetchar用于将输入的字符回送到输入缓冲区。该函数执行的操作是将输入的字符回送到输入缓冲区,如果该函数调用成功则返回char型值c,调用失败时将返回EOF。程序示例如下。


include<stdio.h>//头文件

include<ctype.h>

include<reg51.h>

void main(void)//主函数

{

char k;

//初始化串口

while(isdigit(k=getchar()))//判断输入的是否为数字

{}

ungetchar(k);//调用函数

}


该程序可以在KeilµVision3编译环境中执行。在本例中,调用getchar函数获取字符,使用isdigit函数判断获取的字符是否为数字,如果是则一直循环接收,否则将使用ungetchar输出该字符。

5.字符输出函数putchar

字符输出函数putchar的函数原型如下。


char putchar(char c);


其中,c为通过8051串行口输出的字符。字符输出函数putchar用于通过8051串行口输出字符。程序示例如下。


include<stdio.h>//头文件

include<ctype.h>

include<reg51.h>

void main(void)//主函数

{

char k;

//初始化串口

for(k=0x30;k<=0x39;k++)//循环输出字符

putchar(k);

}


该程序可以在KeilµVision3编译环境中执行,运行的结果如下。


0123456789


在本例中,使用for循环调用putchar函数通过串口0输出10个字符0~9。

6.格式化输出函数printf

格式化输出函数printf的函数原型如下。


int printf(const char*fmstr[,argument]……);


其中,参数fmstr为格式控制字符串,参数argument可以是字符串指针、字符或数值,printf函数的返回值为实际输出的字符个数。格式化输出函数printf的功能是以一定的格式通过8051单片机的串行口输出数值和字符串。

注意由于8051存储空间的限制,允许作为printf参数的总字节数是受限的。在KeilµVision3编译环境下,如果采用SMALL和COMPACT编译模式,最多可传递的参数为15个字节(即5个指针,或1个指针和3个长字),而在LARGE编译模式下,则最多可传递的参数为40个字节。

在printf函数中,格式控制字符串的格式如下。


%[flag][width][.percision][{b[B][l]L}]type


其中,方括号内是可选项,下面分别介绍各项的含义。

❑标志字符flag,用于控制输出位置、符号、小数点以及八进制的和十六进制的前缀等。在C51语言中可使用的flag标志字符,如表6.2所示。

6.5 C51的库函数 - 图2

❑显示宽度width,用来定义显示的字符数。width是一个正的十进制数。如果实际输出显示的字符数小于width值,则在其左边以空格补齐。

❑输出精度precision,用来表示输出精度。precision由小圆点“.”加上一个非负的十进制整数构成。使用precision指定精度时,将使输出的浮点数进行四舍五入。在C51语言中,可以设置输出精度来控制输出字符的数目、整数值的位数或浮点数的有效位数等。

❑可选字符b或B、l或L和格式转换字符一起使用,其意义如表6.3所示。

6.5 C51的库函数 - 图3

❑输出格式转换字符type,其意义如表6.4所示。

6.5 C51的库函数 - 图4

这里举例讲解printf函数的使用,程序示例如下。


include<string.h>//头文件

include<stdio.h>

include<reg51.h>

void main(void)//主函数

{

char a=2;//变量声明并赋初值

int b=23456;

long c=0x7FFFFFFF;

unsigned char x1=‘A’;

unsigned int x2=54321;

unsigned long x3=0x5A6F7E00;

char buf[]=“Good morning!”;//字符串

char*p=buf;

float f=17.0;//浮点型

float g=25.63;

//初始化串口

printf(“char%bd int%d long%ld\n”,a,b,c);//格式化输出

printf(“Uchar%bu Uint%u Ulong%lu\n”,x1,x2,x3);//格式化输出

printf(“xchar%bx xint%x xlong%lx\n”,x1,x2,x3);//格式化输出

printf(“String%s is at address%p\n”,buf,p);//格式化输出

printf(“%f!=%g\n”,f,g);//格式化输出

printf(“%f!=%g\n”,(int)8,f,(int)8,g);//格式化输出

}


该程序可以在KeilµVision3编译环境中执行,运行的结果如下。


char 2 int 23456 long 2147483647

Uchar 65 Uint 54321 Ulong 1517256192

xchar 41 xint d431 xlong 5a6f7e00

String Good morning!is at address I:0038

17.000000!=25.63

17.000000!=25.63


在本例中,首要声明并初始化了各个变量,接着分别使用printf函数进行格式化输出,结果通过串口0输出。读者可以根据格式化字符串的介绍进行分析其输出格式。

7.格式化内存缓冲区输出函数sprintf

格式化内存缓冲区输出函数sprintf的函数原型如下。


int sprintf(chars,const charfmstr[,argument]……);


格式化内存缓冲区输出函数sprintf,用于按照一定的格式将数据或字符串输出到内存缓冲区中。该函数执行的操作是通过指针s,将字符串送入8051单片机的内存数据缓冲区,并以ASCII码的形式储存。程序示例如下。


include<string.h>//头文件

include<stdio.h>

include<reg51.h>

void main(void)//主函数

{

char buf[60];//声明变量

int n;

int a,b;

float pi;

//初始化串口

a=111;//变量赋值

b=222;

pi=3.1415926;

n=sprintf(buf,“%f\n”,1.5);//调用sprintf函数

n=n+sprintf(buf+n,“%d\n”,a);//再次调用,buf递增

n=n+sprintf(buf+n,“%d%s%g”,b,“——”,pi);

puts(buf);//输出

}


该程序可以在KeilµVision3编译环境中执行,运行的结果如下。


1.500000

111

222——3.1415926


在本例中,首要声明并初始化变量,接着调用sprintf函数格式化字符串并保存在buf中。最后使用puts函数将总的格式化结果通过串口0输出。

8.字符串输出函数puts

字符串输出函数puts的函数原型如下。


int puts(const char*s);


其中,参数s为输出的字符串或换行符。如果该函数执行成功则返回0,执行错误则返回EOF。字符串输出函数puts用于将字符串和换行符写入串行口。程序示例如下。


include<stdio.h>//头文件

include<reg51.h>

void main(void)//主函数

{

//初始化串口

char buf[]=“Good morning!”;//字符串

puts(buf);//输出字符串

puts(“This is a test line”);//输出字符串常量

puts(“This is another test line”);//输出字符串常量

}


该程序可以在KeilµVision3编译环境中执行,运行的结果如下。


Good morning!

This is a test line

This is another test line


在本例中,首要定义并初始化字符数组buf,接着调用puts函数通过串口0输出该字符数组。同时,还演示了使用puts函数输出字符串常量的例子。

9.格式化输入函数scanf

格式化输入函数scanf的函数原型如下。


int scanf(const char*fmstr[,argument]……);


格式化输入函数scanf用于将字符串和数据按照一定的格式从串口读入。其中,scanf函数每个参数都必须是指针,该函数的返回值是所发现并转换的输入项数,如遇到错误则返回EOF。

在C51语言中,scanf函数格式控制字符串的格式如下。


%[*][width][{B[h][l]}]type


其中,方括号内是可选项,下面分别介绍各项的含义。

❑输入长度width,用来控制输入数据的最大长度或字符数目,其是十进制正整数。该函数从输入数据流中读出不超过规定宽度的字符,并转换到相应的变量中。注意,如果先输入一个空格符或者是无法识别的字符,这样读入的字符数将会小于需要的宽度值。

❑可选字符B、h、l与输入格式转换字符一起使用,其含义如表6.5所示。

6.5 C51的库函数 - 图5

❑输入格式转换字符type,其含义如表6.6所示。

6.5 C51的库函数 - 图6

使用格式化输入函数scanf的程序示例如下。


include<string.h>//头文件

include<stdio.h>

include<reg51.h>

void main(void)//主函数

{

char a;

int b;

long c;

unsigned char x;

unsigned int y;

unsigned long z;

float f,g;

char d,buf[10];

int argsread;

//初始化串口

printf(“Enter a signed byte,int,and long\n”);

argsread=scanf(“%bd%d%ld”,&a,&b,&c);//输入整型数据

printf(“%d arguments read.a=%c,b=%d,c=%ld\n”,argsread,a,b,c);

printf(“Enter an unsigned byte,int,and long\n”);

argsread=scanf(“%bu%u%lu”,&x,&y,&z);//输入无符号型数据

printf(“%d arguments read.x=%c,y=%u,z=%lu\n”,argsread,x,y,z);

printf(“Enter a character and a string\n”);

argsread=scanf(“%c”,&d);//输入字符型数据

printf(“%d arguments read.d=%c\n”,argsread,d);

printf(“Enter two floating-point numbers\n”);

argsread=scanf(“%f%f”,&f,&g);//输入浮点型数据

printf(“%d arguments read.f=%f,g=%f\n”,argsread,f,g);

printf(“Enter a string\n”);

argsread=scanf(“%9s”,buf);//输入字符串

printf(“%d arguments read.buf=%s\n”,argsread,buf);

}


该程序可以在KeilµVision3编译环境中执行。在本例中,分别调用scanf函数从串口0获得输入的数据,然后使用printf函数通过串口输出。

10.格式化内存缓冲区输入函数sscanf

格式化内存缓冲区输入函数sscanf的函数原型如下。


int sscanf(chars,const charfmstr[,argument]……);


格式化内存缓冲区输入函数sscanf,用于将格式化的字符串和数据送入数据缓冲区。该函数的功能是将输入的字符串通过指针s指向的数据缓冲区。输入数据根据格式控制字符串fmstr被存放到由argument指定的地址。sscanf函数与scanf函数在格式化字符串方面类似,程序示例如下。


include<string.h>//头文件

include<stdio.h>

include<reg51.h>

void main(void)//主函数

{

char a;

int b;

long c;

unsigned char x;

unsigned int y;

unsigned long z;

float f,g;

char d,buf[10];

int argsread;

//初始化串口

printf(“Please input a signed byte,int,and long\n”);

argsread=sscanf(“7-335 345678”,“%bd%d%ld”,&a,&b,&c);

printf(“%d arguments read.a=%bd,b=%d,c=%ld\n”,argsread,a,b,c);

printf(“Please input an unsigned byte,int,and long\n”);

argsread=sscanf(“1 56 87654321”,“%bu%u%lu”,&x,&y,&z);

printf(“%d arguments read.x=%bu,y=%u,z=%lu\n”,argsread,x,y,z);

printf(“Please input two floating-point numbers\n”);

argsread=sscanf(“11.5 34.7”,“%f%f”,&f,&g);

printf(“%d arguments read.f=%f,g=%f\n”,argsread,f,g);

printf(“Please input a character and a string\n”);

argsread=sscanf(“A ABCDEFG”,“%c%9s”,&d,buf);

printf(“%d arguments read.d=%c,buf=%s\n”,argsread,d,buf);

}


该程序可以在KeilµVision3编译环境中执行,运行的结果如下。


Please input a signed byte,int,and long

3 arguments read.a=7,b=-335,c=345678

Please input a unsigned byte,int,and long

3 arguments read.x=1,y=56,z=87654321

Please input two floating-point numbers

2 arguments read.f=11.500000,g=34.700000

Please input a character and a string

2 arguments read.d=A,buf=ABCDEFG


在本例中,调用sscanf函数获取字符串及数据,最后使用printf函数通过串口0输出结果。

11.字符串内存输出函数vprintf

字符串内存输出函数vprintf的函数原型如下。


int vprintf(const charfmstr,charargptr);


其中,参数fmstr为格式化字符串,argptr指向变量表的指针而不是变量表,函数返回值为实际写入到输出字符串中的字符数。其他方面,vprintf函数与printf函数类似,只不过字符串内存输出函数vprintf用于将格式化字符串输出到内存数据缓冲区。程序示例如下。


include<stdarg.h>//头文件

include<stdio.h>

include<reg51.h>

void ErrorFunc(char*fmt,……);//函数声明

void main(void)//主函数

{

int i;

i=100;

//初始化串口

ErrorFunc(“Error:number‘%d’is too large\n”,i);//调用ErrorFunc函数

ErrorFunc(“This is a syntax Error\n”);

}

void ErrorFunc(char*fmt,……)//定义ErrorFunc函数

{

va_list arg_ptr;

va_start(arg_ptr,fmt);//格式化字符串

vprintf(fmt,arg_ptr);//调用函数

va_end(arg_ptr);

}


该程序可以在KeilµVision3编译环境中执行,运行的结果如下。


Error:number‘100’is too large

This is a syntax Error


在本例中,首先定义了错误处理函数ErrorFunc,该函数中调用了vprintf函数。在主程序中,调用自定义函数ErrorFunc通过串口0输出错误信息。

12.指向缓冲区的输出函数vsprintf

指向缓冲区的输出函数vsprintf的函数原型如下。


int vsprintf(chars,const charfmstr,char*argptr);


指向缓冲区的输出函数vsprintf,用于将格式化字符串和数字输出到由指针所指向的内存数据缓冲区。该函数执行的操作是将格式化字符串和数字输出到由指针所指向的内存数据缓冲区。其中,该函数接受的是一个指向变量表的指针而不是变量表,其返回值为实际写入到输出字符串中的字符数。其他方面,vsprintf函数与sprintf函数类似。程序示例如下。


include<stdarg.h>//头文件

include<stdio.h>

include<reg51.h>

void ErrorFunc(char*fmt,……);//声明函数

xdata char etxt[50];//字符串缓冲区

void main(void)//主函数

{

int i;

i=100;

//初始化串口

ErrorFunc(“Error:number‘%d’is too large\n”,i);//调用ErrorFunc函数

ErrorFunc(“This is a syntax Error\n”);

}

void ErrorFunc(char*fmt,……)//自定义函数

{

va_list arg_ptr;

va_start(arg_ptr,fmt);//格式化字符串

vsprintf(etxt,fmt,arg_ptr);//调用vsprintf函数

va_end(arg_ptr);

}


该程序可以在KeilµVision3编译环境中执行,运行的结果如下。


Error:number‘100’is too large

This is a syntax Error


在本例中,首先定义了错误处理函数ErrorFunc,该函数中调用了vsprintf函数。在主程序中,调用自定义函数ErrorFunc通过串口0输出错误信息。