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

How to use extern sbit declare?

I declare a variable unsigned char bdata Kde in a.c.

[in file a.c]

unsigned char bdata Kde;

Than I want to use the variable inb.c.
[in file b.c]
#include <stdio.h>
.....
extern unsigned char bdata Kde;
sbit testbit=Kde^1;
void main(void)
{......}

:error C141:.......a.c:syntax error near 'sbit'

why?

Parents
  • Sfr and sbit's are special. They refer to hardware registers which are by definition global. Thus, Keil (at least if my memory serves me correctly) allows one to define the same named object in a header file and pretend that it is auto-externed/defined as needed. This is the only way files like reg552.h etc. could work. E.g.

    /* Foo.h */
    sfr r_port0 = 0x80;
    Now you can include foo.h in any C file you wish and use the name r_port0 to access the Register for Port 0. No extern is needed or allowed. As Graham Cole pointed out bdata vars. can be externed but they don't refer to hardware register bits. He is wrong about the sbit extern I think.

    However, your error is not related to extern anyhow. You have a simple syntax error. When you define an sbit you must provide the 8051's hardware address for the sbit var. You attempt to define testbit at the same time you initialize it, you cannot. Sbit's refer to hardware is that really what testbit is supposed to be?

Reply
  • Sfr and sbit's are special. They refer to hardware registers which are by definition global. Thus, Keil (at least if my memory serves me correctly) allows one to define the same named object in a header file and pretend that it is auto-externed/defined as needed. This is the only way files like reg552.h etc. could work. E.g.

    /* Foo.h */
    sfr r_port0 = 0x80;
    Now you can include foo.h in any C file you wish and use the name r_port0 to access the Register for Port 0. No extern is needed or allowed. As Graham Cole pointed out bdata vars. can be externed but they don't refer to hardware register bits. He is wrong about the sbit extern I think.

    However, your error is not related to extern anyhow. You have a simple syntax error. When you define an sbit you must provide the 8051's hardware address for the sbit var. You attempt to define testbit at the same time you initialize it, you cannot. Sbit's refer to hardware is that really what testbit is supposed to be?

Children
  • I have now tried it and it does work, but I did have to make a small change:

    [in file a.c]
    
    bdata unsigned char Kde;
    sbit testbit=Kde^1;
    
    [in file b.c]
    #include <stdio.h>
    .....
    extern bdata unsigned char Kde;
    extern bit testbit; 
    
    void main(void)
    {......}
    
    There is a section of this subject in appendix F of the C51 manual (page 328 in my copy).

  • Note that you are changing the type of 'testbit' from an sbit to a bit. How does the linker deal with this? This is very odd looking from a C standpoint and I wouldn't do it this way. Also, I cannot believe

    sbit testbit=Kde^1;
    can compile. I thought that sbits required a upper data space (e.g. DATA address 128 - 255) address to be assigned to them. Where does the linker actually place testbit? I think in this case you will simple end up with testbit as a lower data space bit var. which is not what sbit is for (that's why we have bdata). Talk about confusion.

    Regardless, this is all bad practice.

  • C51 is a bit strange with regard to bit memory, sbit etc. Of course, sbit is totally non-C. This thread contains some grumbles from me and some explanations from Keil: http://www.keil.com/forum/docs/thread1291.asp

    Yes, I agree, it is all bad practice and best avoided. Bit fields within structures is a much more natural and C compliant way to reference individual bits that belong in a 'set', but C51 does not emit efficient code for this. A variable residing in bdata and accessed by individual sbit addresses provides a way of efficiently accessing 1-bit fields withing a "structure". When fast and compact code is required, it is necessary to make use of bdata variables accessed via sbit definitions.

    The code I gave earlier in this thread is pretty much exactly what is in Appendix F of the C51 manual, it does compile and it seems to work. Actually, the type of testbit is not getting changed because bit is not a type but a memory area (like data). Perversely, C51 does not allow variables located in bit memory to have a type.

  • "I thought that sbits required a upper data space (e.g. DATA address 128 - 255) address to be assigned to them."

    It is with trepidation that I dare to suggest that you're wrong there, Mark.

    This was one of the first stumbling blocks which I fell over when I started using Keil - if you search back a couple of years, I probably moaned about it here!
    (probably along the lines, "you can tell it catches lots of people out by the way there's a special section in the manual!")

    Anyway, as I understand it, sbit is the means that Keil uses to give a name to a specific bit (hey - maybe I just hit on the meaning of the 's' there!) - whether it's in a hardware register, or a bdata variable.
    Effectively, sbit forms the definition of a bit "variable"

    bit, on the other hand, does not define the location of the "variable" - it simply says, "this is a single bit"

    Therefore, an extern must always use bit rather than sbit; repeating the sbit definition causes (if I remember correctly) a "multiple definition" Linker error.

  • Unbelievable! I never would have thought that sbit was meant for anything other than an sfr bit, that is DATA addresses > 0x80. I am sorry and disheartened about being wrong on this. I just assumed consistency where there isn't.

  • "I just assumed consistency where there isn't."

    Yes; as both Graham and I have noted, Keil's doesn't appear a particularly Elegant Solution...

  • Keil's doesn't appear a particularly Elegant Solution...

    From what I recall, the bit/sbit/bdata junk was what Intel introduced in the PL/M-51 Compiler. At the time the Keil C compiler was introduced, PL/M-51 was the de-facto standard compiler for the 8051. So, we adopted the Intel standard.

    These legacy language elements are sometimes difficult to kill-off or replace without breaking a lot of existing customer source code.

    Jon

  • The Buck Stops ... way over there! ;-)

  • I totally agree and sympathize. However, adding a feature such as

    /* foo.c */
    bit someBitVar = otherByteVar ^ 1;
    
    /* foo.h */
    extern bit someBitVar;
    probably would not break anyone's code. Right? Don't get me wrong, I think Keil's toolchain is top-notch. Especially after being stranded on PIC Island for my last project.

    - Mark

  • ...repeating the sbit definition causes (if I remember correctly) a "multiple definition" Linker error.

    If and only if they are defined in a bdata variable. There won't be any linker error if we do:

    /*Port.h*/
    .
    .
    sbit bTest   =P3^2;
    .
    .
    

  • Yes - I think that's the inconsistency Mark was referring to