Forum Menu




 


Log in Problems?
New User? Sign Up!
AVR Freaks Forum Index

Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Author Message
Mickjc75
PostPosted: Aug 01, 2011 - 12:41 AM
Rookie


Joined: Mar 16, 2006
Posts: 20


If you want the output of a module to be more universal, then the module could contain a FILE* which either gets loaded directly by main, or via a function.

Code:
// uart.c
#include <stdio.h>
#include <avr/io.h>
#include "uart.h"

int uart_putchar(char c, FILE *stream);

FILE uart_str = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);

int uart_putchar(char c, FILE *stream)
{
   // blah blah
   UDR = c;
   return 0;
}

Code:


/ uart.h
extern FILE uart_str;


Code:


// main.c
#include <stdio.h>
#include "uart.h"
#include "second.h"

int main(void) {
   second_init(&uart_str);
   fprintf(&uart_str, "Hello");
   second_foo();
   while(1);
}

Code:


// second.c
#include <stdio.h>
#include "uart.h"
#include "second.h"

   FILE *second_output_fptr;

void second_init( FILE* output)
{
   second_output_fptr=output;
}

void second_foo(void) {
     fprintf(second_output_fptr, "Hi from foo");
}


Code:

// second.h
void second_init( FILE* output);
void second_foo(void);


_________________
Telling yourself something is too hard, or too complicated, is not a determination. It is a decision.
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
jerryr
PostPosted: Jan 04, 2012 - 07:01 PM
Wannabe


Joined: Apr 23, 2004
Posts: 69
Location: Liederbach/Germany

The tutorial is very good - I used similar modules in a project containing about 40 source files.
A small hint to improve the source readability:
Use a template for your .c and .h files.
The example below is for a smaller project, a controller for a brushless DC motor. It includes comments for Doxygen. The template.h is similar

Code:
/*! \file NAME.c
  \brief description
*/

/* Include files */
#include "config.h"
#ifdef SYMBOL
#include <file>
#include "file"
/********************
   local RAM variables with initialisation as needed
*********************/

/********************
   local PROM variables with initialisation
*********************/

/********************
   local EEPROM variables with initialisation
*********************/

/********************
   external variable and function definitions in order
   RAM, PROM, EEPROM, functions
*********************/
/* **************** AVRDSS ****************/
/* ************** BLDControl **************/
/* ************** commutator **************/
/* *************** dispatch ***************/
/* ***************** PID ******************/
/* ***************** PLL ******************/

/********************
   Functions
*********************/

/********************
   Interrupt service routines
*********************/

/********************
   Event handlers
*********************/

#endif /* SYMBOL */
 
 View user's profile Send private message Send e-mail  
Reply with quote Back to top
lammelm
PostPosted: Aug 06, 2012 - 03:50 PM
Hangaround


Joined: Aug 27, 2007
Posts: 143
Location: Budapest, Hungary

Where do you put the module related header files?

Like for example my uart.c needs avr/io.h, avr/pgmspace.h etc. where should I put it? In the uart.h or in the uart.c?

I know that uart.h should be included in uart.c so even if I put the other header files in the uart.h it will be included in uart.c

So which version do you prefer? Putting the includes in the module header file, or in the source file?
 
 View user's profile Send private message  
Reply with quote Back to top
clawson
PostPosted: Aug 06, 2012 - 03:58 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62281
Location: (using avr-gcc in) Finchingfield, Essex, England

Try to keep header files as local as possible to what they document. Not everyone who includes your uart.h necessarily wants an inclusion of avr/io.h and especially avr/pgmspace.h forced upon them.

What you can do is use those files own header protection to give warnings about their requirement. Say your uart.h uses types such as uint8_t which are indirectly defined by the inclusion of avr/io.h you could rely on the fact that the io.h has this:
Code:
#ifndef _AVR_IO_H_
#define _AVR_IO_H_

So in your own header file you could include:
Code:
#ifndef _AVR_IO_H_
 #error "uart.h requires avr/io.h to be included before it"
#endif

If the user then uses:
Code:
#include "uart.h"
#include <avr/io.h>

they would get that compilation error. While:
Code:
#include <avr/io.h>
#include "uart.h"

would work just fine.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
ibapah
PostPosted: Aug 15, 2012 - 11:13 PM
Hangaround


Joined: May 08, 2011
Posts: 228
Location: Tooele/Lake Point/Erda, Utah

I generally don't use header files, I just declare everything (relating to that module) at the top of each code module. Seems quicker from an editing point of view and reduces the number of files involved.

But I frequently have to put #include <avr/io.h> et al at the top of each code module. Is there a danger in having the same header file appear multiple times like this at the top of multiple modules.

_________________
I use:
AS6 (under duress)
WinAvr 20100110
Windows 7 & XP
STK 600
AVR ONE!(broken and Atmel won't fix)
JTAGICE3 (only works with AS6)
AVRISP II
So far - '88 '2560
Sometimes my own RTOS
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
Kartman
PostPosted: Aug 16, 2012 - 04:44 AM
Raving lunatic


Joined: Dec 30, 2004
Posts: 8764
Location: Melbourne,Australia

Quote:
I generally don't use header files, I just declare everything (relating to that module) at the top of each code module. Seems quicker from an editing point of view and reduces the number of files involved.

But I frequently have to put #include <avr/io.h> et al at the top of each code module. Is there a danger in having the same header file appear multiple times like this at the top of multiple modules.

Those comments seem to suggest you really haven't got the concept of header files. The #include basically just pastes the included file into the file that has the #include - no magic. Consider the instance where you #include that file into another file that has already #included the <avr/io.h> file - you have two instances of that file - thus the compiler will complain. Understand the concept, follow the rules and life will be good.
 
 View user's profile Send private message  
Reply with quote Back to top
ibapah
PostPosted: Aug 16, 2012 - 05:02 AM
Hangaround


Joined: May 08, 2011
Posts: 228
Location: Tooele/Lake Point/Erda, Utah

I used to use them all the time for larger projects, but I find that with smaller MCU code, I would rather have the function declarations and variable definitions at the top of the .c module than having a separate file open. Just laziness more than anything else.

My question is if I have a program comprised of three .c modules and each of them have a io.h (or any other include) file included at the top, is there any danger? The compiler does not complain. Actually it will not compile if I don't do it. I could make a foo.h to go with my foo.c and put the io.h file inside the foo.h but that seems pointless.

_________________
I use:
AS6 (under duress)
WinAvr 20100110
Windows 7 & XP
STK 600
AVR ONE!(broken and Atmel won't fix)
JTAGICE3 (only works with AS6)
AVRISP II
So far - '88 '2560
Sometimes my own RTOS
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
Koshchi
PostPosted: Aug 16, 2012 - 06:46 AM
10k+ Postman


Joined: Nov 17, 2004
Posts: 13834
Location: Vancouver, BC

Quote:
Consider the instance where you #include that file into another file that has already #included the <avr/io.h> file - you have two instances of that file - thus the compiler will complain.
No it won't. <avr/io.h> is set up correctly so that the already knows that it has been included.
Quote:
I would rather have the function declarations and variable definitions at the top of the .c module
That works for that file, but what if you need those variables and functions visible is multiple other files? Then you need to declare those functions and variables multiple times. Put them into a .h file, then you need only declare them once.
Quote:
My question is if I have a program comprised of three .c modules and each of them have a io.h (or any other include) file included at the top, is there any danger?
No, not at all. Separate .c files are just that, separate. None know what files the others include.

_________________
Regards,
Steve A.

The Board helps those that help themselves.
 
 View user's profile Send private message  
Reply with quote Back to top
JohanEkdahl
PostPosted: Aug 16, 2012 - 08:25 AM
10k+ Postman


Joined: Mar 27, 2002
Posts: 18545
Location: Lund, Sweden

Quote:

Those comments seem to suggest you really haven't got the concept of header files.

And even more so the concepts of function prototypes, typedefs and extern declarations.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
clawson
PostPosted: Aug 16, 2012 - 09:14 AM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62281
Location: (using avr-gcc in) Finchingfield, Essex, England

Quote:

And even more so the concepts of function prototypes, typedefs and extern declarations.

Indeed. Suppose you have an adc.c that contains:
Code:
int ADC_init(void) { .. }
uint16_t ADC_read(void) { .. }
void ADC_change_channel(uint8_t chan) { .. }

Now in main.c you want to call those functions. How on earth can you achieve that? How can the compiler know when it encounters a call to:
Code:
foo = ADC_Read();
or
ADC_change_channel(5);

what the input or return parameter types are? This is the whole reason you would have adc.h:
Code:
// adc.h
int ADC_init(void);
uint16_t ADC_read(void);
void ADC_change_channel(uint8_t chan);

It would be #include'd in main.c so the compiler knows what the interface to each of the routines is. This is pretty fundamental to the use of the C programming language, ignore it at your peril.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
JohanEkdahl
PostPosted: Aug 16, 2012 - 11:28 AM
10k+ Postman


Joined: Mar 27, 2002
Posts: 18545
Location: Lund, Sweden

I believe that it is important for the understanding of this to keep the concepts of prototypes, typedefs and externals apart from the concept of the #include mechanism as such. Together they form a powerful mechanism for structuring projects on the source file level, but taking them apart will reveal what is actually going on and helps understanding what this is all about.

As short as I can manage:

Using Cliffs example, suppose you have functions for handling the ADC in a separate source file adc.c, but you want to call these functions from another source file, say main.c . Now purely technically you might get away without having any prototypes in adc.h but just the definitions (implementations) of the functions. In main.c you definitively must have prototypes for the functions, or else (as Cliff points out) the compiler will not know about parameter and return types etc.

But (and that is a big BUT): If you at some time change the actual definitions (implementations) of the functions in adc.c, but fail to update the prototypes in main.c the result will likely be disastrous. Since the compiler actually compiles each C source file separately it will not spot the mismatch. The linker will then happily resolve the calls from main.c to functions in adc.c – but since the code from main.c will push different parameters from what the code from adc.c expects everything will be a mess. You will not get any build errors, but you application will likelt crash at run time.

The solution is to make sure that the very same prototypes are seen in both adc.c and main.c. I am not speaking about two prototypes that look identical (because, again, with time one of them will change but not the other). I am talking about the two source files actually “seeing” the same prototype. The solution is to place such prototypes in a text file that is then inserted into both source files just before compilation proper takes place. This is what header files and the #include pre-processor directive is all about.

Now when you change an implementation in adc.c but fail to change the corresponding prototype in adc.h, the compiler will emit an error when compiling adc.c. You now change the prototype, but fail to change the actual call (e.g. adding a newly introduced parameter) in main.c – and the compiler will emit an error compiling main.c. When that also is corrected the application builds clean.

Think of an include file as a contract between the supplier (implementation) and consumer (caller) of some functionality. Both ends must “do the same thing” or you will get a build error. Without that contract you will get a runtime error. A build error is always preferable to a runtime error.

I cannot see how you can get around this if you have several source files. If you actually have your prototypes only in main.c and implementations in adc.c, then you need to rethink and take in what I describe above. Effectively, you are satisfying the compilers need for knowing how to call the functions, but lose out on the advantages you can get from a common include file. Ignoring this will lead to disaster sooner or later. Probably sooner..

Not so short after all, but I hope it helps to clear up what this is really about.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
ibapah
PostPosted: Aug 16, 2012 - 03:28 PM
Hangaround


Joined: May 08, 2011
Posts: 228
Location: Tooele/Lake Point/Erda, Utah

Guys, my original question was:
"Is there a danger in having the same header file appear multiple times like this at the top of multiple modules." Like io.h.

I do use a .h file if I find I want to put all the prototypes and variable declarations in one place. Sometimes. Most of the time they are at the top of my main source code module. If I want to re-use a bunch of stuff then I create a .h file for the module so I don't have to do much work the next time around.

I do use typedefs when I want to get a bit more portable.

I understand and use extern when needed.

I just asked what was going to happen if I put #include io.h at the top of each c module to make the compiler happy.

I do appreciate the extention of the tutorial but to extrapolate from my original question and statement that I prefer to put everything at the top rather than a separate .h file means I lack a bunch of understanding was a touch pedantic and condecending, don't you think?

_________________
I use:
AS6 (under duress)
WinAvr 20100110
Windows 7 & XP
STK 600
AVR ONE!(broken and Atmel won't fix)
JTAGICE3 (only works with AS6)
AVRISP II
So far - '88 '2560
Sometimes my own RTOS
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
ibapah
PostPosted: Aug 16, 2012 - 03:42 PM
Hangaround


Joined: May 08, 2011
Posts: 228
Location: Tooele/Lake Point/Erda, Utah

I may have a module called read_gps.c
I call it and it returns a variable.

My main module would have the prototype for read_gps(xxx) But the read_gps.c module may have 50 functions to do its work. And all 50 functions may have their prototypes at the top of that code module.

Why is that a sin?

I don't and won't ever need to call any of those internal functions from anywhere else. I can make a single read_gps.h file and include the prototype for the read_gps(xxx) but that is just as much work or more than putting the prototype along with the others at the top of the main module.

I can put all the prototypes for the internal read_gps.c file in read_gps.h but then I would have to include it in two places to get the compiler to work.

I can have two .h files, one containing the read_gps(xxx) prototype to include in the main module and another containing all the internal module protypes to include inside the read_gps.c module but that is just for housekeeping. In this case I see no added value of header files.

_________________
I use:
AS6 (under duress)
WinAvr 20100110
Windows 7 & XP
STK 600
AVR ONE!(broken and Atmel won't fix)
JTAGICE3 (only works with AS6)
AVRISP II
So far - '88 '2560
Sometimes my own RTOS
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
JohanEkdahl
PostPosted: Aug 16, 2012 - 05:01 PM
10k+ Postman


Joined: Mar 27, 2002
Posts: 18545
Location: Lund, Sweden

Extrapolationg, you said? For functions that are both defined in and called from one and the same source file you do not need to have prototypes in a separate header file. I never said that.

I wasn't my meaning to be condecending. Every time one answers, one has to make some assumption of the knowledge and skill level of the intended receivers/readers. If I missed the mark widely this time, I did that. Period.

OTOH, when you're saying
Quote:

I can make a single read_gps.h file and include the prototype for the read_gps(xxx) but that is just as much work or more than putting the prototype along with the others at the top of the main module.

it seems to me that you've missed the point. The prototype for read_gps() should be seen in two source files, not only in the main module. If you actually type it into both files then i) this will be un-necessary work, and ii) it will not in any way "guarantee the contract".

Quote:
I just asked what was going to happen if I put #include io.h at the top of each c module to make the compiler happy.

Nothing bad, since that header file is nicely written and following good conventions. The compiler will use the parts of it that it needs, and the rest of the stuf in it will not be used.

Quote:
I do use a .h file if I find I want to put all the prototypes and variable declarations in one place.

I am a bit uncertain what is meant by "variable declarations" above, but if it is something like
Code:
int foo;

then this will spell problems when the header file in inluded into more than one source file. The root of the problem isn't the inclusion into two source files, but having the variable definition in the header file. They should go into .c source files just like function implementations.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
clawson
PostPosted: Aug 16, 2012 - 07:03 PM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62281
Location: (using avr-gcc in) Finchingfield, Essex, England

Sorry, very importantly above my example for adc.h SHOULD have said:
Code:

// adc.h
#ifndef _ADC_H_
#define _ADC_H_

int ADC_init(void);
uint16_t ADC_read(void);
void ADC_change_channel(uint8_t chan);

#endif // _ADC_H_

If you look at any "standard" header file such as those within the AVR-LibC collection you will see they all have protection like this. If main.c then said (in error):
Code:
#include "adc.h"
#include <avr/io.h>
#include "adc.h"

or perhaps more likely
Code:
#include <avr/io.h>
#include "adc.h"
#include "uart_that_happens_to_include_adc.h"

then on the first inclusion of adc.h the _ADC_H_ define is not made so the bit between #ifndef and #endif is used. This introduces all the types/interfaces and, inportantly now #define's _ADC_H_.

Now when it gets to the second (perhaps indirect) #include "adc.h" the _ADC_H_ symbol is already defined so the entire section between #ifndef and #endif is ignored this and all subsequent times.

THAT is the way you ensure that it doesn't matter if there are multiple inclusions of a .h file.

EDIT: BTW just looked at the universally used <avr/io.h> and guess what...:
Code:
#ifndef _AVR_IO_H_
#define _AVR_IO_H_

PS the annoying thing is that I even realised I'd forgotten to mention the header protection thing when I was sat in the local health centre having an ECG for a suspected heart attack (luckily not it turns out) but I was only just allowed back near a PC just now by she who must be obeyed.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
ibapah
PostPosted: Aug 16, 2012 - 08:19 PM
Hangaround


Joined: May 08, 2011
Posts: 228
Location: Tooele/Lake Point/Erda, Utah

JohanEkdahl wrote:

I wasn't my meaning to be condecending. Every time one answers, one has to make some assumption of the knowledge and skill level of the intended receivers/readers. If I missed the mark widely this time, I did that. Period..

Sorry, was not directed at you. The initial reply to my initial question didn't answer my question but did question my understanding.

Quote:
I am a bit uncertain what is meant by "variable declarations" above, but if it is something like
.

Code:
int foo;


Quote:

then this will spell problems when the header file in inluded into more than one source file. The root of the problem isn't the inclusion into two source files, but having the variable definition in the header file. They should go into .c source files just like function implementations.


I should have specified, global variables. I have placed global variables in a .h at times. Most of the time my .h files just have function prototypes, defines and typedefs. But now-a-days, I don't use many .h files. I just put it all in the code.

_________________
I use:
AS6 (under duress)
WinAvr 20100110
Windows 7 & XP
STK 600
AVR ONE!(broken and Atmel won't fix)
JTAGICE3 (only works with AS6)
AVRISP II
So far - '88 '2560
Sometimes my own RTOS
 
 View user's profile Send private message Send e-mail Visit poster's website 
Reply with quote Back to top
JohanEkdahl
PostPosted: Aug 16, 2012 - 09:47 PM
10k+ Postman


Joined: Mar 27, 2002
Posts: 18545
Location: Lund, Sweden

Quote:
I should have specified, global variables. I have placed global variables in a .h at times.

And such a header file can not be included into more than one source file or the linker will emit an error about a multiply defined variable. So, since this file is only included into one source file this should fall under your "rule" about unnecessary header files. You could just as well define that variable in the .c source file.

It all boils down to this: Things that are to be shared between several source files needs to be defined in one of the source files (yes, it could be by way of having it in a header file that just one source file includes). In other source files it must be declared (for a variable this is an extern declaration, for a function this is a function prototype) and this the reasonable approach is to have those declarations in a header file so that the compiler can assert that the definition and the usage does not conflict.

You may do as you wish, and live with the risks of your M.O.. But this had to be said so that C beginners are not led astray when reading this thread.
 
 View user's profile Send private message Visit poster's website 
Reply with quote Back to top
clawson
PostPosted: Aug 17, 2012 - 09:07 AM
10k+ Postman


Joined: Jul 18, 2005
Posts: 62281
Location: (using avr-gcc in) Finchingfield, Essex, England

Quote:

And such a header file can not be included into more than one source file or the linker will emit an error about a multiply defined variable.

Just to note that the header protection (#ifndef _ADC_H_) I mentioned above will not protect against this. Imagine this scenario again but with a modified adc.h:
Code:
// adc.h
#ifndef _ADC_H_
#define _ADC_H_

int ADC_init(void);
uint16_t ADC_read(void);
void ADC_change_channel(uint8_t chan);

uint16_t adc_reading;

#endif // _ADC_H_

That now has an 'adc_reading' variable definition added. Now, sure, if the programmer used this in main.c:
Code:
#include "adc.h"
#include <avr/io.h>
#include "adc.h"

then there still would be no problem as the re-include protection comes into play so the definition of 'adc_reading' like everything else in the header file is only seen once even if adc.h is included more than once.

However main.c is just one "compilation unit". At the time it is compiled then sure only one copy of adc_reading is created within main.o

The problem comes when you also have a motor_control.c that also does:
Code:
#include <avr/io.h>
#include "adc.h"
...

When this compilation unit is compiled (which could even be the Tuesday after main.c was last compiled) it too will see the contents of adc.h and it too will therefore create an entity called adc_reading in motor_control.o

Finally when the linker comes to join main.o and motor_control.o to make myproject.elf it will find two different adc_reading variables and emit an error about "multiply defined".

That is the reason you should never put anything that generates either variable or function bytes into a .h because it almost inevitably leads to multiple definitions from different compilation units.

_________________
 
 View user's profile Send private message  
Reply with quote Back to top
Display posts from previous:     
Jump to:  
All times are GMT + 1 Hour
Post new topic   Reply to topic
View previous topic Printable version Log in to check your private messages View next topic
Powered by PNphpBB2 © 2003-2006 The PNphpBB Group
Credits