⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 c514.txt

📁 dsp&c51的编程,从小百合上down的
💻 TXT
📖 第 1 页 / 共 2 页
字号:
    bit flag_1 ; 

(Note: bit variables are always placed in the bit-addressable memory area of 

 the 8051 - see section 2.1.1) 

With a processor such as the 8086, int is probably the commonest data type. 

As this is a 16 bit processor, the handling of 16 bit numbers is generally t 

he most efficient. The distinction between int and unsigned int has no parti 

cular impact on the amount of code generated by the compiler, since it will 

simply use signed opcodes rather than the unsigned variety. 

For the 8051, naturally enough, the char should be the most used type. Again 

, the programmer has to be aware of the thoroughly 8 bit nature of the chip. 

 Extensive use of 16 bit variables will produce slower code, as the compiler 

 has to use library routines to achieve apparently innocuous 16 by 8 divides 

, for example. 

The use of signed numbers has to be regulated, as the 8051 does not have any 

 signed arithmetic instructions. Again, library routines have to do the donk 

ey work. 

An interesting development has been the Siemens 80C537, which does have an e 

xtended arithmetic instruction set. This has, for instance, 32 by 16 divide 

and integer instructions. Indeed, this device might be a good upgrade path f 

or those 8051 users who need more number crunching power and who might be co 

nsidering the 80C196. A suite of runtime libraries is available from Keil to 

 allow the compiler to take advantage of the 80C537 enhancements. 

3.4.2 Special Function Bits 

A major frustration for assembler programmers coming to C is the inability o 

f ANSI C to handle bits in the bit-addressable BDATA area directly. Commonly 

 bit masks are needed when testing for specific bits with chars and ints. In 

 C51 version 3 however, it is possible to force data into the bit-addressabl 

e area (starting at 0x20) where the 8051's bit instructions can be used dire 

ctly from C. 

An example is testing the sign of a char by checking for bit = 1. 

Here, the char is declared as "bdata" thus: 

    bdata char test ; 

    sign_bit is defined as: 

    sbit sign ^ 7   ; 

To use this: 

void main(void) { 

     test = -1 ; 

     if(test & 0x80) { // Conventional bit mask and & 

        test = 1 ;     // test was -ve 

        } 

     if(sign == 1) {   // Use sbit 

        test = 1 ;     // test was -ve 

        } 

      } 

Results in the assembler: 

    RSEG  ?BA?T2 

test:            DS  1 

sign    EQU    test.7 

; 

; bdata char test ; 

; sbit sign = test ^ 7 ; 

; 

; void main(void) { 

main: 

;   test = -1 ; 

    MOV      test,#0FFH 

; 

;   if(test & 0x80) { // Conventional bit mask and & 

    MOV      A,test 

    JNB      ACC.7,?C0001 

; 

;      test = 1 ;        // test was -ve 

    MOV      test,#01H 

;    } 

?C0001: 

; 

;   if(sign == 1) {      // Use sbit 

    JNB      sign,?C0003 

; 

;        test = 1 ;      // test was -ve 

    MOV      test,#01H 

;    } 

; 

;    } 

?C0003: 

    RET 

Here, using the sbit, the check of the sign bit is a single JNB instruction, 

 which is an awful lot faster than using bit masks and &'s in the first case 

! The situation with ints is somewhat more complicated. The problem is that 

the 8051 does not store things as you first expect. The same sign test for a 

n int would still require bit 7 to be tested. This is because the 8051 store 

s int's high byte at the lower address. Thus bit 7 is the highest bit of the 

 higher byte and 15 is the highest bit of the lower. 

Byte Number: test_int(high) 20H Bit Number: 0,1,2,3,4,5,6,7 

Byte Number: test_int+1(low) 21H Bit Number: 8,9,10,11,12,13,14,15 

Bit locations in an integer 

3.4.3 Converting Between Types 

One of the easiest mistakes to make in C is to neglect the implications of t 

ype within calculations or comparisons 

Taking a simple example: 

    unsigned char x ; 

    unsigned char y ; 

    unsigned char z ; 

    x = 10 ; 

    y = 5  ; 

    z = x * y ; 

Results in z = 50 

However: 

    x = 10 ; 

    y = 50 ; 

    z = x * y ; 

results in z = 244. The true answer of 500 (0x1F4) has been lost as z is una 

ble to accommodate it. The solution is, of course, to make z an unsigned int 

. However, it is always a good idea to explicitly cast the two unsigned char 

 operands up to int thus: 

    unsigned char x ; 

    unsigned char y ; 

    unsigned int z ; 

    z = (unsigned int) x * (unsigned int) y ; 

While C51 will automatically promote chars to int, it is best not to rely on 

 it! It could be argued that on any small microcontroller you should always 

be aware of exactly what size data is. 

3.4.4 A Non-ANSI Approach To Checking Data Type 

A very common situation is where two bytes are to be added together and the 

result limited to 255, i.e. the maximum byte value. With the 8051 being byte 

-orientated, incurring integers must be avoided if maximum speed is to be ac 

hieved. Likewise, if the sum of two numbers exceeds the type maximum the use 

 of integers is needed. 

In this example the first comparison uses a proper ANSI approach. Here, the 

two numbers are added byte-wise and any resulting carry used to form the lea 

st significant bit of the upper byte of the notional integer result. A norma 

l integer compare then follows. Whilst C51 makes a good job of this, a much 

faster route is possible, as shown in the second case. 

; #include <reg51.h> 

; 

; 

; unsigned char x, y, z ; 

; 

; /*** Add two bytes together and check if ***/ 

; /***the result has exceeded 255 ***/ 

; 

; void main(void) { 

    RSEG  ?PR?main?T 

    USING    0 

main: 

            ; SOURCE LINE # 8 

; 

;    if(((unsigned int)x + (unsigned int)y) > 0xff) { 

            ; SOURCE LINE # 10 

    MOV      A,x 

    ADD      A,y 

    MOV      R7,A 

    CLR      A 

    RLC      A 

    MOV      R6,A 

    SETB     C 

    MOV      A,R7 

    SUBB     A,#0FFH 

    MOV      A,R6 

    SUBB     A,#00H 

    JC       ?C0001 

; 

;       z = 0xff ;   // ANSI C version 

            ; SOURCE LINE # 12 

    MOV      z,#0FFH 

;       } 

            ; SOURCE LINE # 13 

In this case the carry flag, "CY", is checked directly, removing the need to 

 perform any integer operations, as any addition resulting in a value over 2 

55 sets the carry. Of course, this is no longer ANSI C as a reference to the 

 8051 carry flag has been made. 

?C0001: 

; 

;    z = x + y ; 

            ; SOURCE LINE # 15 

    MOV      A,x 

    ADD      A,y 

    MOV      z,A 

; 

;    if(CY) { 

            ; SOURCE LINE # 17 

    JNB      CY,?C0003 

; 

;       z = 0xff ;   // C51 Version using the carry flag 

            ; SOURCE LINE # 19 

    MOV      z,#0FFH 

;       } 

            ; SOURCE LINE # 20 

; 

; 

; 

; 

;    } 

            ; SOURCE LINE # 25 

?C0003: 

    RET 

The situation of an integer compare for greater than 65535 (0xffff) is even 

worse as long maths must be used. This is almost a disaster for code speed a 

s the 8051 has very poor 32 bit performance. The trick of checking the carry 

 flag is still valid as the final addition naturally involves the two upper 

bytes of the two integers. 

In any high performance 8051 system this loss of portability is acceptable, 

as it allows run time targets to be met. Unfortunately, complete portability 



 always compromises performance! 

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

---- 

  

-- 

Ours is essentially a tragic age, so we refuse to take it tragically. 

  

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -