Embedded nubie help

Do you have a question? Post it now! No Registration Necessary

Translate This Thread From English to

Threaded View
Hi to all.
I am quite new to programming and embedded system design and could use
some help.
Most of the hardware/software that I have done has been fairly small
and the software fitted into 1 C file without problem.
I am now modifying some software written by someone else , and am
some trouble understanding some of his variable definitions.I don't
need to know any of this part of the software to make the changes I
but would like to know what he has done :0)
 I am working in Raisonance by the way.
Most of the variable definitions are in a seperate file named global.h
In the main C file(named Main.c for some reason :0) )  there is a
#include <global.h>     statement at the beginning , so far so good.
 Further down this post I have copied the global.h file. I am having
understanding how these definitions work.
Some of the EXTERN statements are in capitals and some not. This seems
to make a difference.

What is happening in the first three lines if the file?
I am happy with the xdata and idata as meaning external ram and
internal ram.

Hope that I have made "some" sence to someone!!
Any help that anyone can give would be appreciated , or any good
pointers to online documentation would also be appreciated.


//   Global Variables - global.h
#undef EXTERN
#ifdef _GLOBAL_H_
#define EXTERN

unsigned int xdata at 0x500     dbase[30];            // Modbus Datbase    
unsigned int xdata at  0x500  offset_dummy;
unsigned int xdata at  0x502  job_number[5];   // 40002-40006
unsigned int xdata at  0x504  reason_ptr;        // 40007
unsigned int xdata at  0x506  user_ID;           // 40008-HI,40009-LOW
unsigned int xdata at  0x508  stop_secs;        // 40010-HI,40011-LOW
unsigned int xdata at  0x50a  counter;         // 40012_HI,40013-LOW
unsigned int xdata at  0x51c  counter_in;  // 40014_HI,40015-LOW
unsigned int xdata at  0x51e  counter_out;   // 40016_HI,40017-LOW
unsigned int xdata at  0x520  spoilage;      // 40018
unsigned int xdata at  0x522  dbase_address;   // 40019

#define EXTERN extern

extern unsigned int   dbase[30];        // Modbus Datbase

extern unsigned int       offset_dummy;
extern unsigned int       job_number[5];
extern unsigned int       reason_ptr;
extern unsigned  int      user_ID;
extern unsigned  int      stop_secs;    
extern unsigned  int      counter;
extern unsigned  int      counter_in;
extern unsigned int       counter_out;
extern unsigned int       spoilage;
extern unsigned int       dbase_address;


//--- Other global variables ---
 EXTERN unsigned char idata barcode_buffer[16],

 EXTERN unsigned int idata  temp_num,

 EXTERN unsigned long int idata  temp_long,

 EXTERN unsigned char xdata counted_in,counted_out;

//--- Constants ----
#define WDOG P1_6
#define COUNTER_IN  ~P3_2
#define COUNTER_OUT ~P3_3
#define INP_3  ~P3_4
#define BL      P1_0
#define DEBOUNCE 2
#define RUN 1
#define STOP 0

Re: Embedded nubie help

Quoted text here. Click to load it

No, it DOESN'T refer to external and internal RAM- I understand your
confusion- it refers to the SCOPE of the variable. An "extern" variable
is one that is "created" and perhaps initialised in another file. He has
defined a macro EXTERN that converts to a blank in the definition file,
and as the string "extern" in all the other files.

Take the variable

EXTERN int BreadBasket;

So in the file where _GLOBAL_H_ is defined, this converts to just:

int BreadBasket;

but in the other files it converts to:

extern int BreadBasket;

What he's trying to do is ensure that the variables get defined in the
same way for all files. Imagine writing in one module:

extern int ChoppingBoard;

and in another:

float ChoppingBoard;

The result is chaos. I know, I've done it!

Paul Burke

Re: Embedded nubie help

Quoted text here. Click to load it


You seem to have misread a little - Rob said he is happy that xdata
and idata refer to external and internal RAM, he wasn't referring to
EXTERN/extern at that point.

The rest is fine though :-)

Best Regards
John McCabe

To reply by email replace 'nospam' with 'assen'

Re: Embedded nubie help
Quoted text here. Click to load it

David, I'm invoking the rule that says you don't get away with asserting the
existence of better techniques unless you are prepared to show examples.

Given the declarations at hand, which are defining memory-mapped registers,
using a language extension, what do you suggest as an "easier and safer way
to ensure consistenccy"?  Please show example code, using

   int at 0x500 xdata;
   extern int xdata;

as part of your example.  In other words, show us how to accomodate that
specific language extension.

Re: Embedded nubie help
Quoted text here. Click to load it

Fair enough - I didn't want to complicate matters for the OP by showing
different methods - I just wanted to point out that there are other ways of
dealing with externs, so that he did not "learn" from the code he is fixing
now.  I thought maybe he'd ask when he was ready, or else find some book or
tutorial on C.

Quoted text here. Click to load it

That's a non-standard extension, which is not used on any compiler I have,
but I guess my system will work fine there too.  The system I use is, as far
as I know, widely used by C programmers on big and small systems.

As an example, consider a program that reads an analogue input and drives a
pwm output to the value read, and you want to split the program into neat
modules.  Then you have files such as:

/* common.h */
typedef unsigned char byte;

/* pwm.h */
extern void initPwm(void);
extern void setPwm(byte newPwm);
extern byte currentPwm;

/* pwm.c */
#include "common.h"
#include "pwm.h"

byte currentPwm;
void initPwm(void) { .... }

static void doSetPwm(byte newPwm) { ... }

void setPwm(byte newPwm) {
    if (newPwm != currentPwm) {
        currentPwm = newPwm;

/* adc.h */
extern void initAdc(void);
extern byte at 0x500 input;
extern void pollAdc(void);

/* adc.c */
#include "common.h"
#include "adc.h"

byte input;
static byte samples[4];        /* For average filter */
void initAdc(void)
void pollAdc(void)

/* main.c */
#include "common.h"
#include "adc.h"
#include "pwm.h"

void main(void) {
    while (1) {

The whole idea is that each module has its own global data and functions,
which are declared as extern in that modules header file.  The module itself
also #include's its own header - any conflicts between the extern
declerations and the definitions show up as compiler errors when the module
is compiled.  I also prefer to declare functions and data as static if they
are not global, but that is not really necessary (unless you are working on
big programs, especially in colaberation with others).  The advantages of
this system are that modules are much more self-contained, their external
interface is completly specified in the module header file, you can't get
conflicts between declerations and definitions (unless you fail to
re-compile modules as necessary - in which case, you need to learn "make"),
and your code does what it says it does (i.e., no claims of "EXTERN" when
you really mean a definition).

Re: Embedded nubie help
Quoted text here. Click to load it

Okay, I give up.  What is "OP"?


Re: Embedded nubie help
OP = Original Poster

Regards, Doug

Quoted text here. Click to load it

Re: Embedded nubie help
Quoted text here. Click to load it

Of course it does.  C is a case-sensitive programming language, after all.

Quoted text here. Click to load it
Quoted text here. Click to load it


This is one of several different tricks people like to pull off to
avoid one of the little quirks of C: the fact that the preprocessor is
the only thing you get to couple individual source modules together.

Without this hack, you would have to write down every global variable
twice: once as a "definition" proper, like in:

    int foo;
or    char bar[] = ;

to be found only exactly *once* in the whole source tree.  The second
mention of each variable is in one header file.  It's not allowed to
be initialized, and is flagged with "extern" keyword to make it a
"declaration" instead of a definition:

    extern int foo;
and    extern char bar[];

Some people dislike having to type everything twice, so they invented
this EXTERN hack.  You write "EXTERN" instead of "extern" in the
header file.  With some preprocessor magic, you

    #define EXTERN extern

for almost all sources being compiled, except for a single source file
(per header file).  That one has

    #define EXTERN /* nothing */

and thus the declarations turn into definitions, in this single source
file's compilation.

Note that, as given, this trick only works for un-initialized globals.
For initialized ones, you need more involved tricks, like a macro

# define EXTERN_INITIALIZED(name, initializer) extern name
# define EXTERN_INITIALIZED(name, initializer) name = initializer

This particular line in your case:

Quoted text here. Click to load it

hints that this is using one of the sillier approaches to deciding which
sourcefile will generate the definitions: it's the one that does

    #include "global.h"

*twice*, instead of once.  That plan is silly because properly written
headers should always be allowed to be #include'd more than once,
without changing their effect.  Otherwise, you'll have a hell of a
time extending their usage to larger projects.
Hans-Bernhard Broeker ( snipped-for-privacy@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.

Re: Embedded nubie help
snipped-for-privacy@yahoo.com (rob) wrote in message
Quoted text here. Click to load it

Lowercase extern is a reserved word. It informs the compiler that the
following variable exist somewhere. Allow this module to work with it
but don't allocate any space for it. That's ecough for the compiler
(The Linker will later verify that the variable really exists)

Uppercase EXTERN is being defined as nothing or as extern, depending
if _GLOBAL_H is defined. If _GLOBAL_H_ is defined, then EXTERN is
turned into white space. Any variables defined will also have memory
allocation. If it's not defined the EXTERN is turned into extern and
the preceding paragraph applies

Hope this helps,

Quoted text here. Click to load it
Quoted text here. Click to load it

Site Timeline