This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

Accesing bit addressable variables

I was wondering what the "best" way to set a bit in a variable declared in the bit addressable area.

Originally I declared each bit as an sbit and therefore can set and clear them as follows

uint8_t bdata status ;
sbit enable = staus ^ 0 ;

enable = 1 ;
enable = 0 ;
I think it looks clearer to do as follows
#define ENABLE 0x01

uint8_t bdata status ;

status |= ENABLE ;
status &= ~ENABLE ;

but I am worried that this could less maintainable because there will be many #defines with the same values but related to different variables and confusion could ensue.

I was wondering what other people do and if there is a standard method for doing this?

  • The two methods that you have given are not at all the same. Personally, I would always go for the first method as it is so much clearer.

    The only down-side is that the first method it is absolutly non-portable. The second method will be much more familiar to an ANSI C programmer.

    The compiler will generate quite different code in each case. I'd predict that the first method will cause SETB and CLR instructions to be used (quick and compact) whereas the second method will require a read, ORL or ANL, and a write.

  • The compiler generates the same code. It is smart.

  • "Personally, I would always go for the first method as it is so much clearer." (my emphasis)

    I agree, although the OP thinks the opposite!

    "The only down-side is that the first method it is absolutly non-portable."

    But it can (I say should) be encapsulated in a macro, so that porting is simply a matter of suitably redefining the macro.
    Similarly for all other compiler-specifics.

    "The compiler will generate quite different code in each case."

    Absolutely.
    Why would Keil bother to dream up this special syntax if it made no difference?!

  • "I was wondering what other people do and if there is a standard method for doing this?"

    The #define and masking is the conventional way when using a compiler without specific bit-addressing extensions (and for non bit-addressable data with Keil).

    Although you seem to have found a (the?) case where the Keil compiler is smart enough to replace a simple mask with a bit-set operation, the only way to guarantee it would be to use the bit-addressing extensions.

    And the current score is 2:1 that the bit-addressing is clearer! ;-)

  • The compiler does not generate the same code!

    ----- FUNCTION main (BEGIN) -----
     FILE: 'main.c'
        9: void main( void )
       10: {
       11:     enable = 1;
       12:     enable = 0;
    00000F D200              SETB    enable
       13:
    000011 C200              CLR     enable
       14:     status |= ENABLE;
    000013 432001            ORL     status,#01H
       15:     status &= ~ENABLE;
    000016 5320FE            ANL     status,#0FEH
       16: }
    000019 22                RET
    ----- FUNCTION main (END) -------
    
    I am pretty sure that the compiler always treads variables stored in bdata identically with those in data. The only difference is that it is possible to locate a bit in a byte of bdata by using the sbit keyword.

  • It looks like mine does. Maybe it has something to do with the way i have defined the variable.

    $NOMACRO
    $SEGMENTED CASE MOD167
    ;
    ; 'main.SRC' GENERATED FROM INPUT FILE 'main.c'
    ; COMPILER INVOKED BY:
    ;	C:\Keil\C166\BIN\C166.EXE main.c BROWSE MOD167 DEBUG
    ;
    $MODINF (43)
    		 NAME MAIN
    
              NCODE  CGROUP  ?PR?MAIN
              SDATA  DGROUP  ?BD0?MAIN,SYSTEM
    
                     ASSUME  DPP3 : SDATA
    
          ?BD0?MAIN  SECTION  DATA BITADDRESSABLE 'BDATA0'
             status  DSB  1
             PUBLIC  status
          ?BD0?MAIN  ENDS
    
              EXTRN  ?C_STARTUP : NEAR
             enable  BIT   status.0
             PUBLIC  enable
    
    
                     REGDEF   R0 - R15
    
    
           ?PR?MAIN  SECTION  CODE WORD 'NCODE'
    ; line 1: #include "types.h"
    ; line 2:
    ; line 3: #define ENABLE 0x01
    ; line 4:
    ; line 5: uint8_t bdata status ;
    ; line 6:
    ; line 7: sbit enable = status ^ 0 ;
    ; line 8:
    ; line 9: #pragma SRC
    ; line 10:
    ; line 11: void main ( void )
    
    	main  PROC  NEAR
    	GLOBAL  main
    ; FUNCTION main (BEGIN  RMASK = @0x8000)
    ; line 12: {
    ; line 13:
    ; line 14:
    ; line 15:
    ; line 16: 	enable = 1 ;
    	BSET	enable
    ; line 17: 	enable = 0 ;
    	BCLR	enable
    ; line 18:
    ; line 19: 	status |= ENABLE ;
    	BSET	(status).0
    ; line 20: 	status &= ~ENABLE ;
    	BCLR	(status).0
    ; line 21:
    ; line 22: 	while(1)
    ; line 23: 	{
    ; line 24:
    ; line 25: 	}
    ?C0001:
    	JMP	cc_UC,?C0001
    ; FUNCTION main (END    RMASK = @0x8000)
    	main  ENDP
           ?PR?MAIN  ENDS
    
    
    ; line 26:
    ; line 27: }
    
    	END
    

  • "Maybe it has something to do with the way i have defined the variable."

    Or because you are using a C166 compiler as opposed to the (apparent) use of C51 by other posters. In fairness to everyone, your posts did not specify a product and I would hazard a guess that when none is specified, C51 is assumed.

  • "Or because you are using a C166 compiler as opposed to the (apparent) use of C51 by other posters."

    Which does, of course, beg the question: If C166 can do it, why can't (or doesn't) C51?

  • A: Because the C167 has a different output structure.