Embedded nubie help

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 having 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 need, 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 statement at the beginning , so far so good. Further down this post I have copied the global.h file. I am having trouble 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. Cheers Rob


//---------------------------------------------------------------------------- // 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 ///

#else #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], reply, incomming_data, mm, clr, debounce_in, debounce_out, status_change, mode, edge_flag, update, sec_flag, wait;

EXTERN unsigned int idata temp_num, simple_tmr, delay, pwr_delay, tenths, dsp_address, dsp_timer, screen_ptr;

EXTERN unsigned long int idata temp_long, dsp_job_number;

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

Reply to
Loading thread data ...

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

Reply to
Paul Burke


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'

Reply to
John McCabe



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; else extern int xdata;

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

Reply to
John R. Strohm

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


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[] = {0,1,2};

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

#indef MASTER_SOURCE # define EXTERN_INITIALIZED(name, initializer) extern name #else # define EXTERN_INITIALIZED(name, initializer) name = initializer #endif

This particular line in your case:

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 (broeker@physik.rwth-aachen.de)
Even if all the snow were burnt, ashes would remain.
Reply to
Hans-Bernhard Broeker

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, Yaakov


Reply to





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.



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; doSetPwm(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) { initAdc(); initPwm(); while (1) { pollAdc(); setPwm(input); }; }

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).

Reply to
David Brown

OP = Original Poster

Regards, Doug

Reply to
Cone Killer

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


Reply to

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.