?? c514.txt
字號:
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 + -