Hi, I want to create a bit field structure for a group of bits associated with 'sfr P1' /* Bit definitions within sfr P1 */ #define NRAMEN (1 << 5) #define A20 (1 << 4) #define A19 (1 << 3) #define A18 (1 << 2) #define A17 (1 << 1) #define A16 (1 << 0) #define NCSDUART NRAMEN+A18 struct myp1 { unsigned char bankSelect :6; /* select banked device */ unsigned char wdog :1; }; struct myp1 data port1 _at_ 0x90; /* problem line doesnt work */ My problem is the last line, how do i get my struct to use P1 so I can do the following ? port1.bankSelect = NCSDUART; /* set/res the appropriate bits on port1 */ Or will i have to start doing something like the following (which i was trying to avoid)? P1 = (P1 & 0xC0) + NCSDUART; /* mask off unwanted bits then select appropriate banked device */ Thanks Mark.
Have you looked at the bit-addressing facilities of C51? Look up "Bit Addressable Objects" in the manual.
You can't do the struct version. SFR's are in the DATA space from 0x80 to 0xFF. The compiler will not generate the appropriate mov's for what want to do. For setting one bit use sbit:
sfr r_port1 = 0x90; sbit r_nRamEn = r_port1 ^ 5; /* Enable RAM */ r_nRamEn = 0; /* use the RAM */ /* Disable RAM */ r_nRamEn = 1;
#define SELECT_BANK(port, dev) do { port &= ~(dev); port |= (dev); } while (0) /* <-- No semicolon! */ /* Usage */ #define NRAMEN (1 << 5) #define A20 (1 << 4) #define A19 (1 << 3) #define A18 (1 << 2) #define A17 (1 << 1) #define A16 (1 << 0) #define NCSDUART (NRAMEN + A18) SELECT_BANK(r_port1, NSCDUART);
I guess my botched post (above) proves one shouldn't use CodeWright to edit one's replies. Sorry for the mess.
There are other issues you should consider before using a structure. The following struct:
struct myp1 { unsigned char bankSelect :6; /* select banked device */ unsigned char wdog :1; };
#define SET_ADDRESS(x) (P1 = (P1 & 0xC0) | ((x) & 0x3F)
SET_ADDRESS(0x12);
"The order in which the bits are accesses LSB first or MSB first is implementation specific" Not only the order of bits within the byte, but also the order of bytes within larger words, and the possibility (though not in C51) of the compiler adding "padding" for alignment. Keil's implementation does seem to be somewhat abstruse - judging by the fact that there's several App Notes addressing it! (use the 'Search' for further details) "Using bit masking is very specific, is portable to other compilers, and is clear" Of course, there's no such thing as a free lunch, and the downside is that this can give you bigger & slower code - possibly quite significantly so. It is, as always, up to you to weigh up the pros & cons in the light of your own specific requirements and determine whether legibility/maintainability or speed/size is your overriding concern. You can (I say you should) isolate all your compiler- and target-dependencies with conditional compilation; as I mentioned here: http://www.keil.com/forum/docs/thread1760.asp
The ability to describe a port and other addresses as bit-fields would be a very nice feature indeed. In principle, a compiler should be able to do this and generate different object code for accessing bit-addressable and non-bit-addressable locations in an efficient way. Of course, compilers can vary in their placing of bit fields within words (that is a weakness of C). However, the advantage is that a statement such as:
select.bank = 3;