printf in KEIL C51

轉自:http://blog.csdn.net/it1988888/article/details/8821713html

在keil中printf默認是向串口中發送數據的,因此,若是應用該函數,必須先初始化串口,不然可能引發死機的狀況,而且在printf以前應該先將TI置位,摘抄緣由以下:git

1.printf函數是調用putchar函數輸入的,而putchar應該是先判斷ti是否爲1,不爲1則等待爲1。若是爲1則清0,而後送出一 個字符。所以你若是直接使用printf函數,你的程序就會在putchar函數中等待ti爲1。這時你的程序就至關於直接死掉了。你能夠經過改寫 putchar函數實現本身的目的的。promise

2.Keil的串口處理比較巧妙的,個人分析以下:
   putchar.c裏面,是先檢測TI再發送。這樣作的目的是把儘量多的時間留給2次串口操做之間的程序,而不是把等待字節發送的時間白白空等待浪費掉。因此,在系統初始化的時候,必定要令TI=1; 就能夠順暢的使用printf函數了。摟主sbuf=" "的辦法,其實就是令TI=1.   另外要特別注意,printf函數執行完畢後,最後一個字節並未發送完畢,例如在485通信中,此時若是切換爲收模式,會丟失最後一字節.app

3.通常串口發送都是等TI(字節發送完標誌)爲1就立刻發送下一字節,因爲無論是中斷仍是查詢TI標誌的方法,都會檢測TI,所以首次發送必須置 位TI標誌,使串口開始發送你的「在程序的初始化部分往串口數據寄存器SBUF裏放一個字符來起用終端顯示;」方法最終做用也就是把TI置1,改爲 TI=1;來啓動發送也是同樣的(固然,不會發出那個' '字符了)。less

4.<stdio.h>中定義,調用底層的putchar()來實現.底層發送數據到串口時,先查TI=1是否成立,死等直到TI=1時將新數據寫入SBUF,函數返回,因此要先將TI置1,啓動第一次傳輸操做.可查看反彙編相關代碼理解其工做機理!ide

文章轉載自:
http://hi.baidu.com/zsb7739/blog/item/35385417898a8f4021a4e91c.html/cmtid/7adc563582303c43241f146f


下面舉一個簡單的例子:
//===========================
#include <reg51.h>
#include <stdio.h>
//-------------------------------
int main()
{
    Uart_init();   //初始化串口,這裏就不寫具體代碼了。
    TI = 1;                        //keil 調用stdio.h中printf函數前要置位。


    while(1)
    {
         printf("Hello world!\n");
         delay_ms(800);   //延時程序,這裏也不寫具體代碼了。
    }
    return 0;
}

 
 
------------------------------
 

printf

Summary
#include <stdio.h>

int printf (
  const char *fmtstr       /* format string */
  <[>, arguments ... <]>);   /* additional arguments */
Description

The printf function formats a series of strings and numeric values and builds a string to write to the output stream using theputcharfunction. The fmtstr argument is a format string that may be composed of characters, escape sequences, and format specifications.this

Ordinary characters and escape sequences are copied to the stream in the order in which they are interpreted. Format specifications always begin with a percent sign ('%') and require that additionalarguments are included in the printf function call.spa

The format string is read from left to right. The first format specification encountered references the firstargument after fmtstr and converts and outputs it using the format specification. The second format specification accesses the secondargument after fmtstr, and so on. If there are more arguments than format specifications, extra arguments are ignored. Results are unpredictable if there are not enougharguments for the format specifications or if the argument types do not match those specified byfmtstr.

Format specifications have the following general format:

% <[>flags<]> <[>width<]> <[>.precision<]> <[>{b|B|l|L}<]> type

Each field in the format specification may be a single character or a number which specifies a particular format option.

The type field is a single character that specifies whether the argument is interpreted as a character, string, number, or pointer, as shown in the following table.

Type Argument Type Input Format
d int Signed decimal number.
u unsigned int Unsigned decimal number.
o unsigned int Unsigned octal number.
x unsigned int Unsigned hexadecimal number using "0123456789abcedf".
X unsigned int Unsigned hexadecimal number using "0123456789ABCDEF".
f float Floating-point number formatted as
<[>-<]>dddd.dddd.
e float Floating-point number formatted as
<[>-<]>d.dddde<[>-<]>dd.
E float Floating-point number formatted as
<[>-<]>d.ddddE<[>-<]>dd.
g float Floating-point number using either the e or f format, whichever is more compact for the specified value and precision.
G float Floating-point number using either the E or f format, whichever is more compact for the specified value and precision.
c char A single character.
s * A string of characters terminated by a null character ('\0').
p * A generic pointer formatted as t:aaaa where t is the memory type andaaaa is the hexadecimal address.

 Note

  • The optional characters l or L may immediately precede the type character to respectively specify long types for d, i, u, o, x, and X.
  • The optional characters b or B may immediately precede the type character to respectively specify char types for d, i, u, o, x, and X.

Characters following a percent sign that are not recognized as a format specification are treated as ordinary characters. For example, "%%" writes a single percent sign to the output stream.

The flags field is a single character used to justify the output and to print +/- signs and blanks, decimal points, and octal and hexadecimal prefixes, as shown in the following table.

Flag Description
- Left justify the output in the specified field width.
+ Prefix the output value with a + or - sign if the output is a signed type.
blank (' ') Prefix the output value with a blank if it is a signed positive value. Otherwise, no blank is prefixed.
# Prefixes a non-zero output value with 0, 0x, or 0X when used with o, x, and X field types, respectively.

When used with the e, E, f, g, and G field types, the # flag forces the output value to include a decimal point.

The # flag is ignored in all other cases.

The width field is a non-negative number that specifies the minimum number of characters printed. If the number of characters in the output value is less than width, blanks are added on the left (by default) or right (when the - flag is specified) to pad to the minimum width. If width is prefixed with a '0', zeros are padded instead of blanks. The width field never truncates the output. If the length of the output value exceeds the specified width, all characters are output.

The width field may be an asterisk ('*'), in which case an int argument from the argument list provides the width value. Specifying a 'b' in front of the asterisk specifies that the argument is an unsigned char.

The precision field is a non-negative number that specifies the number of characters to print, the number of significant digits, or the number of decimal places. Theprecision field can cause truncation or rounding of the output value in the case of a floating-point number as specified in the following table.

Type Precision Field Meaning
d,u,o,x,X The precision field specifies the minimum number of digits that are included in the output value. Digits are not truncated if the number of digits in the argument exceeds that defined in the precision field. If the number of digits in the argument is less than the precision field, the output value is padded on the left with zeros.
f The precision field specifies the number of digits to the right of the decimal point. The last digit is rounded.
e,E The precision field specifies the number of digits to the right of the decimal point. The last digit is rounded.
g,G The precision field specifies the maximum number of significant digits in the output value.
s The precision field specifies the maximum number of characters in the output value. Excess characters are not output.
c,p The precision field has no effect on these field types.

The precision field may be an asterisk ('*'), in which case an int argument from the argument list provides the value. Specifying a 'b' in front of the asterisk specifies that the argument is an unsigned char.

 Note

  • You must ensure that the argument type matches that of the format specification. You may use type casts to ensure that the proper type is passed to printf.
  • This function is implementation-specific and is based on the operation of the_getkey and putchar functions. These functions, as provided in the standard library, read and write characters using the microcontroller's serial port. Custom functions may use other I/O devices.
  • The total number of bytes that may be passed to this function is limited due to the memory restrictions imposed by the 8051. A maximum of 15 bytes may be passed in SMALL or COMPACT model. A maximum of 40 bytes may be passed in LARGE model.
Return Value

The printf function returns the number of characters actually written to the output stream.

See Also

gets,printf517,puts,scanf,scanf517,sprintf,sprintf517,sscanf,sscanf517,vprintf,vsprintf

Example
#include <stdio.h>

void tst_printf (void) {
  char a = 1;
  int b  = 12365;
  long c = 0x7FFFFFFF;

  unsigned char x = 'A';
  unsigned int y  = 54321;
  unsigned long z = 0x4A6F6E00;

  float f = 10.0;
  float g = 22.95;

  char buf [] = "Test String";
  char *p = buf;

  printf ("char %bd int %d long %ld\n",a,b,c);
  printf ("Uchar %bu Uint %u Ulong %lu\n",x,y,z);
  printf ("xchar %bx xint %x xlong %lx\n",x,y,z);
  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);
}

 

C51: PRINTF GIVES WRONG VALUES


 

Information in this article applies to:

  • C51 All Versions

QUESTION

In C51, I am using printf and sprintf with many arguments and it is printing out wrong values. What is the reason for this behavior?

ANSWER

There are any number of reasons why printf can output incorrect values.

Probably the most common reason is that the format specifier and the argument type do not match. To solve this kind of problem, explicitly type cast each argument to the desired type. Be sure that you accurately specify the correct format specifier for that type.

Another reason may be that the number of bytes you may pass to functions with variable-length argument lists is fixed (since arguments are not passed on the stack). In small and compact memory model, printf and sprintf only reserve 15 bytes for the argument list. In the large memory model 40 bytes are reserved. For example, 15 bytes allow you to pass up to five generic (3-byte) pointers, or one generic pointer and three long arguments. This parameter limitation is a compromise to the limited memory available in 8051 devices.

Eight arguments will not fit in the space reserved for small or compact memory models. So, instead of one sprintf call with many arguments you must perform two or three calls and distribute the arguments among the sprintf calls. For example:

The following code exceeds the parameter space limits since seven generic pointers (21 bytes) are passed to sprintf.

char str[] = "Any Text";
sprintf (buff_out, "%s %s %s %s %s", str, str, str, str, str);

The above example may be rewritten as follows:

char str[] = "Any Text";
int len;

len = sprintf (buff_out, "%s %s %s ", str, str, str);
sprintf (buff_out + len, "%s %s", str, str);

MORE INFORMATION

  • Refer to printf in the Cx51 User's Guide.
相關文章
相關標籤/搜索