Good practice to use header file for all projects?

Go To Last Post
44 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Is it a good practice to create a .h file even if you only put your prototypes and constants in it?  To date, I've only ever put my prototypes in the main.c file.  But my sense is that's not "proper."  I've read Dean Camera's tutorial on modularizing projects and while I like it (I used to do that in Visual Studio with my VB projects), I'm a little confused by it.  Is it dated?  The talk of makefiles seems like an advanced optional step given that AS7 does all that automatically behind the scenes?  I've also read the avrgcc docs toolchain section.  But at this stage in my learning, if AS7 is doing everything I need, I feel my learning efforts are better spent on the language and AVRs.

 

Please correct me if I'm wrong:

1) header files are especially necessary when modularizing multiple source files that need to include the data.

2) for projects using only a single source file, header files are unnecessary

3) adding a "main.h" file to a project is good practice even if it only stores prototypes and constants as it creates less clutter in the main.c file.

 

Any false assumptions there?
 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

for all but the most basic programs I try to modularize into specific components (Uart, Generic Spi, LCD,etc.)
I usually have a .h file that defines the cpu pin usage and a .h file I use for common macros I have developed. I have never used a main.h file as it seems unecessary (YMMV).

David (aka frog_jr)

Last Edited: Sat. Aug 6, 2016 - 02:52 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1.yes
2. Probably
3. See 2
Header file etiquitte has been around longer than Dean, so i don't think it dates.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

1) yes (in fact they are fundamental to modular code)

2) I guess though even there I think I'd divide the interface and the implementation .

3) on the whole a .h file advertises and documents the functions that one or more .c files offer. In that sense I guess it's not needed in your single main.c scenario, but why break the habit of a lifetime.

As for make files,you are right a modern IDE auto generates them so you don't need to worry but they do let an advanced programmer take more control of the build though a truly advanced programmer would likely be using CMake anyway.

Last Edited: Sat. Aug 6, 2016 - 02:54 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I usually have a .h file that defines the cpu pin usage and a .h file I use for common macros I have developed.

This.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It's a real confidence impediment not knowing for certain.  Thanks for the confirmation.

 

@joey or @frog, (or anyone else) would you mind sharing your implementation (.h files) for pin usage and macros??  I'd like to see how you're using them. 

 

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I would be happy to; however, I am on vacation and will not have access to them till late next week...

David (aka frog_jr)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

That would be great.  Now, step away from the electronic device and go enjoy your vacation!  ;)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

chipz wrote:

That would be great.  Now, step away from the electronic device and go enjoy your vacation!  ;)

Trust me I am, but some of being on vacation is waiting on my family to get ready for the next "thing"!

David (aka frog_jr)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I tend to make programs with many small source files.

The largest known prime number: 282589933-1

It's easy to stop breaking the 10th commandment! Break the 8th instead. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I tend to make projects with one c file. A project can be modular at the c source level, or at the compiled c object code level, or at the binary level. A million line program with a dozen programmers might break this model. The advantage is: configuration management. There is a one to one correspondence between the c source and the hex file.

It wasnt possible to compile a large program when the development computer had limited memory. Computers were slow, and it took a long time to recompile all those uart subroutines that were known to work. They link all the relocatable object files together, because reading the files from disk is faster than recompiling them. All that hardware restriction is a moot point now. Someone with a million line c file ought to compare compile time for the one file and one hundred c and h file version. I'd be surprised if the hundreds of files version was faster. On avrs, I'd like a report on whether the popular avr c compilers use a call or an rcall between separately compiled modules. My favorite compiler uses a call for every library function, and an rcall for every function in the Big C File. What does CV, IAR and GCC do?

 

Imagecraft compiler user

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:
On avrs, I'd like a report on whether the popular avr c compilers use a call or an rcall between separately compiled modules. My favorite compiler uses a call for every library function, and an rcall for every function in the Big C File. What does CV, IAR and GCC do?

The linker in GCC has an option called -relax. When used it causes it to analyse the code (after linking) and wherever a JMP or CALL is in range (less than 4K in either direction) it replaces it with RCALL/RJMP but if the offset is large it leaves it as CALL/JMP. Studio 7 chooses to turn on "relax" by default so most avr-gcc programs benefit from using this.

 

While we're talking about linkers - does your one implement dead code and dead data removal? The GCC compile can be (and in AS7 is) invoked with -ffunction-sections and -fdata-sections which basically means "build every function and every data object into its own individual section". The linker then has an option (-gc-sections) to "garbage collect sections" and when it has linked all the code and all the data from all the individual linker inputs into one block it checks the reference count on each function and data section. Any that have a 0 reference (nothing calls them or uses the data) are removed from the final binary. So this means that if you use "library" code and perhaps your uart.c has 10 functions available but on this occasion only 7 of them are actually called then the other 3 will not waste space in the flash.

 

Over and above all this GCC now has a fairly recent technology called "link time optimization" (LTO). In the past all optimization was done on individual compilation units at compile time (actually that still occurs) but now there is a potential for "complete program optimisation" that can be done once all the individual link objects are joined so it could, for example, have the potential to spot common epilogue code and just emit one copy that is jumped to by multiple functions rather than repeating that code in each instance. Other optimizations like this may be performed.

 

Truly there is no penalty for splitting code into functional modules in separate source. The days when you had to put it all in one source to "help the compiler" and "avoid the need for linking" passed about 3 or 4 decades ago. This is 2016 not 1976.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Remember, Bob, compared to what we learned programming on, these are supercomputers that run the compiler and linker. Shoot, even some of these AVRs are supercomputers compared to what we had in those days.

The largest known prime number: 282589933-1

It's easy to stop breaking the 10th commandment! Break the 8th instead. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

To summarize points made elsewhere:

Present day toolchains are fast enough that build times ought not

be an issue when deciding how to organize a project.

Project organization should be selected to help the developers.

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

Last Edited: Mon. Aug 8, 2016 - 04:39 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

skeeve wrote:
Project organization should be selected to help the developer.

Personally I think it should be designed to help the maintainer (who may not necessarily be the developer and that's when clear design really becomes important!)

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

clawson wrote:
skeeve wrote:
Project organization should be selected to help the developer.

Personally I think it should be designed to help the maintainer (who may not necessarily be the developer and that's when clear design really becomes important!)

I regard maintainer as a special case of developer.

Perhaps I should have written developers.

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Imagecraft has common prologs and epilogs, but every function in another compilation unit is a call. I can see this in the listing file, so I guess gcc is better than imagecraft in regard to rcalls to other modules. I guess the reason I use the Bob Gardner Configuration Management System of A Dir Named X has a c file with a main in it named X.c and a hex file in it named X.hex and a bunch of .o files and .lis files and .lst files and a map file. A complete snapshot of the project at compile time. If I had a half dozen programmers, all editing and compiling the same font files for the graphics lcds, this would break down and I'd need a version control system. Right now I have redundant font files copied into every dir with every oled program that uses my different fonts. If I put all the font c files in a font dir and compile em all, then I compile my current program, its All Good so far. Lets say I ship that program out. Now I have another customer and I write another program, and I edit one of the font files to put a stroke in the zero or something to make it look like the display he is trying to copy. BZZZZT. Configuration Management Buzzer. I cant alter the c source for a sold program in the common fonts dir. Back in the CPM and floppy days, I tried Real Hard to not have redundant copies of files. I now have a drive with a thousand gigabytes on it. I'll never fill that bad boy up. I'd still like to know if a hundred module program with a page of c for each module compiles and links faster than a hundred page c file (5000 lines? Puny.). I get about 5 assembler instructions for each 'line of c' where the expression in an if is a line, ea statement in the block is a line etc. I dont have a lot of extra vertical whitespace, so lets say a 5000 line c file has 25000 instructions or 50000 words. Program would fit in a mega64. I guess I could cobble up some ersatz example of a hundred little stupid modules and try it.

 

 

Imagecraft compiler user

Last Edited: Mon. Aug 8, 2016 - 07:54 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 1

I typically have a single .c file.  Perhaps 2 or 3 if the complexity warrants it.  More often than not, the extra .c files are host-side helpers used to generate code or LUTs which would be difficult to generate by hand.  I do make frequent use of my own custom libraries and header files, though.

 

@joey or @frog, (or anyone else) would you mind sharing your implementation (.h files) for pin usage and macros??  I'd like to see how you're using them. 

They vary, depending upon the project.  However in general I have a project-wide .h which is included by every .c file compiled for that project.

 

For example, I have a DMX fixture library which makes use of a number of macros for configuration (some required, some optional), among them:

DMX_RX_BUFFER_SIZE
DMX_TIMER_TO_USE 0
DMX_ENABLE_ERROR_COUNTER
DMX_ENFORCE_DMX512A_MAB
DMX_ENFORCE_DMX512_MAB
DMX_NO_MAB_ENFORCEMENT

The macros must be defined when compiling the .c file associated with the library.  This is achieved by defining these macros in the project-wide header file, and using -include when calling avr-gcc.  In this way, every compilation unit has access to all of the project-specific configuration information, and all of that information is collected into a single file for easy viewing and maintenance.  As can be expected, much of that project-specific configuration pertains to I/O pin assignments.  For that reason I have a number of templates which I use for that purpose, each one tailored to a specific AVR.  For example, here's one I use for the m328p.  It includes the Arduino pin assignments, as I frequently use an UNO for rapid prototyping, testing, or just noodling around:

/************ Pin assignments ATmega328P and friends ******************************************************************

ARDUINO / DIP / QFP / BIT / PIN CHA / INT  / COMM / ANALG / TIMER / TCLOK / CLOCK || PERIF | PERIF | PERIF || NOTES
--------/-----/-----/ ----/---------/------/------/-------/-------/-------/ ------||-------|-------|-------||----------
 0      /   2 /  30 / PD0 / PCINT16 /      / RXD  /       /       /       /       ||       |       |       ||
 1      /   3 /  31 / PD1 / PCINT17 /      / TXD  /       /       /       /       ||       |       |       ||
 2      /   4 /  32 / PD2 / PCINT18 / INT0 /      /       /       /       /       ||       |       |       ||
 3      /   5 /   1 / PD3 / PCINT19 / INT1 /      /       / OC2B  /       /       ||       |       |       ||
 4      /   6 /   2 / PD4 / PCINT20 /      / XCK  /       /       / T0    /       ||       |       |       ||
 5      /  11 /   9 / PD5 / PCINT21 /      /      /       / OC0B  / T1    /       ||       |       |       ||
 6      /  12 /  10 / PD6 / PCINT22 /      /      / AIN0  / OC0A  /       /       ||       |       |       ||
 7      /  13 /  11 / PD7 / PCINT23 /      /      / AIN1  /       /       /       ||       |       |       ||
 8      /  14 /  12 / PB0 / PCINT0  /      /      /       / ICP1  /       / CLKO  ||       |       |       ||
 9      /  15 /  13 / PB1 / PCINT1  /      /      /       / OC1A  /       /       ||       |       |       ||
10      /  16 /  14 / PB2 / PCINT2  /      / SS   /       / OC1B  /       /       ||       |       |       ||
11      /  17 /  15 / PB3 / PCINT3  /      / MOSI /       / OC2A  /       /       ||       |       |       ||
12      /  18 /  16 / PB4 / PCINT4  /      / MISO /       /       /       /       ||       |       |       ||
13      /  19 /  17 / PB5 / PCINT5  /      / SCK  /       /       /       /       ||       |       |       ||
        /   9 /   7 / PB6 / PCINT6  /      /      /       /       / TOSC1 / XTAL1 ||       |       |       ||
        /  10 /   8 / PB7 / PCINT7  /      /      /       /       / TOSC2 / XTAL2 ||       |       |       ||
14 + A0 /  23 /  23 / PC0 / PCINT8  /      /      / ADC0  /       /       /       ||       |       |       ||
15 + A1 /  24 /  24 / PC1 / PCINT9  /      /      / ADC1  /       /       /       ||       |       |       ||
16 + A2 /  25 /  25 / PC2 / PCINT10 /      /      / ADC2  /       /       /       ||       |       |       ||
17 + A3 /  26 /  26 / PC3 / PCINT11 /      /      / ADC3  /       /       /       ||       |       |       ||
18 + A4 /  27 /  27 / PC4 / PCINT12 /      / SDA  / ADC4  /       /       /       ||       |       |       ||
19 + A5 /  28 /  28 / PC5 / PCINT13 /      / SCL  / ADC5  /       /       /       ||       |       |       ||
        /   1 /  29 / PC6 / PCINT14 /      /      /       /       /       / RESET ||       |       |       ||
20 + A6 /     /  19 /     /         /      /      / ADC6  /       /       /       ||       |       |       ||
21 + A7 /     /  22 /     /         /      /      / ADC7  /       /       /       ||       |       |       ||

**********************************************************************************************************************/

It's an easy way to see at a glance how everything fits together, and can be helpful when planning I/O pin assignments for multiple peripherals.  The three columns labelled 'PERIF' I use to keep notes on specific assignments to external peripherals, and there's room for additional notes.   This one is sorted by Arduino pin number.  I occasionally sort by other criteria, like DIP, or BIT.

 

It is from these templates that I start building a project-wide header file.  The template also includes place holders for many of the required or optional macros for my frequently used libraries.  I generally keep the above table in the newly created header file for quick reference when working on a project, and to remind myself of important details when I drag out a project after six months of doing other things.

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

Last Edited: Tue. Aug 9, 2016 - 03:44 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

chipz wrote:
@joey or @frog, (or anyone else) would you mind sharing your implementation (.h files) for pin usage and macros??  I'd like to see how you're using them.
The originals did not use variadic macros.

Interesting things happen when using the ## operator with variadic macros,

I had the opportunity to reduce the naming of the pin to a single #define

and to have port, ddr and pin macros that worked the same wherever used.

The ## operator makes things rather esoteric.

Fortunately fairly thorough and convincing testing is possible.

On a linux or unix machine in a terminal in the same directory as namepins.h , bowling.c , and bowling.sh ,

type sh bowling.sh .

It should make bowling.i , but not emit anything to standard out.

 

Edit: bowling.tgz corrected

Attachment(s): 

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

Last Edited: Tue. Aug 30, 2016 - 04:26 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@Joey: this is a super neat table. Is it automatically generated? I can't believe you've created it manually for each and every chip…

 

@skeeve: I use something very similar. I push it a step further (sort of) by using C4 instead of C,4 (I think it looks cleaner) with an additional define:

#define C4   C,4

My pin direction macros are named output(pin) and input(pin) instead of dset() and dclr(). I find that clearer as well (and more Arduino-people friendly) but I suppose that's a matter of taste.

One thing I very much love is my variadic bit() macro:

#define bit(bits...)   ...

bit(ADEN, ADSC, ADIE)  =>  1<<ADEN | 1<<ADSC | 1<<ADIE
(protective parens not shown for clarity)

On the same principle I have variadic  get(), set(), is_set(), is_clr() and so on, that works with any variable/SFR, as well as pin-centric equivalents: high(), is_high()

 

EDIT: added attachment.

Attachment(s): 

ɴᴇᴛɪᴢᴇᴎ

Last Edited: Tue. Aug 9, 2016 - 08:09 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

bobgardner wrote:
Imagecraft has common prologs and epilogs, but every function in another compilation unit is a call. I can see this in the listing file, so I guess gcc is better than imagecraft in regard to rcalls to other modules.

I believe LTO has moved GCC way over that issue. In fact, it can even inline a function from another module/object file when it makes sense.

I had sort of an "argument" with theusch recently about exactly this. Old habits that were relevant some time ago and just stick around because you haven't challenged them in a while…

I'm still looking forward to explore this in a dedicated thread and see how it goes with different toolchains.

 

EDIT: I just ran cat proj.lss | grep "call" on a project consisting in at least a good dozen object files and it came up with rcalls only (and one icall).

ɴᴇᴛɪᴢᴇᴎ

Last Edited: Tue. Aug 9, 2016 - 08:03 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

My own, very personal viewpoint is that, for simple projects, there is a move to split everything up into smaller source modules for no good reason. This has the effect that you spend your whole life searching for some #define that will give you a clue as to what some constant does. OK, certain IDEs will allow you to search the entire project, but it still takes time. Coming originally from an assembler-on-a-computer-with-verylittleRAM, I am probably at the other end of the spectrum, but one thing I notice is that, although everthing is #defined, and #typedefed and wrapped and obsfuscated to death, so that you need to have 28 source files open just to follow a simple routine that sets an output pin high, the purpose, obviously, being to try and use as much memory and processor time as possible(and give me a headache), most source code has virtually no useful commenting. Which is inexcusable in these days of infinite hard disk space.

 

I am referring here to API code and the like supplied by chip manufacturers specifically, but it seems to be contagious.

 

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John_A_Brown wrote:
My own, very personal viewpoint is that, for simple projects, there is a move to split everything up into smaller source modules for no good reason. This has the effect that you spend your whole life searching for some #define that will give you a clue as to what some constant does. OK, certain IDEs will allow you to search the entire project, but it still takes time.

Any decent IDE allows you to CTRL+click (or similar) on an identifier, and will then open the file and jump to the line where it was defined. It is much faster than looking for it yourself, even in a single file. So, to me, that's about the worst reason not to encapsulate stuff in their own modules. You're free to do as you wish, but I can't let you spread that sort of falsehoods to people who come here for help and information.

 

John_A_Brown wrote:
one thing I notice is that, although everthing is #defined, and #typedefed and wrapped and obsfuscated to death, so that you need to have 28 source files open just to follow a simple routine that sets an output pin high, the purpose, obviously, being to try and use as much memory and processor time as possible(and give me a headache)

The whole point of encapsulation is that you do not have to know what's in the black box to use it. After my last message I feel sort of targeted by this part. As you mention, these are all preprocessor defines, which means they consume exactly zero memory and processor time: they're resolved at compile time (assuming you're talking about the only memory and processor time that matters: the MCU's).

ɴᴇᴛɪᴢᴇᴎ

Last Edited: Tue. Aug 9, 2016 - 11:47 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Netizen wrote: "After my last message I feel sort of targeted by this part."

 

Please don't. I didn't even read your post.

 

Yes, I know the preprocessor defines don't impact the memory or speed of the target(although the wrapping and over wrapping does), but when I was gainfully employed, I had to try to understand what was going on, as the manufacturer's supplied APIs generally assumed a Linux based system, whereas I was attempting to shoehorn the functionallity into an XMega chip.

 

While I agree that, in some cases, "The whole point of encapsulation is that you do not have to know what's in the black box to use it.", I would have used the italics on the word "have", rather than "not".

 

Four legs good, two legs bad, three legs stable.

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John_A_Brown wrote:
Please don't. I didn't even read your post.

Alright. Not that you have to agree with me anyway. :)

 

John_A_Brown wrote:
when I was gainfully employed, I had to try to understand what was going on, as the manufacturer's supplied APIs generally assumed a Linux based system, whereas I was attempting to shoehorn the functionallity into an XMega chip.

I'm not disputing that, but it would have been worth mentioning from the start: the OP has no way to know you're not answering his question from a general standpoint.

 

John_A_Brown wrote:
While I agree that, in some cases, "The whole point of encapsulation is that you do not have to know what's in the black box to use it.", I would have used the italics on the word "have", rather than "not".

You're right.

ɴᴇᴛɪᴢᴇᴎ

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@Joey: this is a super neat table. Is it automatically generated? I can't believe you've created it manually for each and every chip…

By hand.  Not that big a deal.  I have ten fingers.  And I don't work with very many different AVR.

 

I like your variadic bit() macro and friends.

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Regarding black boxes:

I suspect some readers find my namepins.h obscure beyond all recognition.

The test code is simple and should be enough to demonstrate its trustworthiness.

Long chains of #defines and typedefs not known to be trustworthy can doubtless be frustrating.

At least with a .i file, one can remove one source of frustration.

 

 

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

Last Edited: Tue. Aug 9, 2016 - 03:56 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

John_A_Brown wrote:

... you spend your whole life searching for some #define that will give you a clue as to what some constant does.

 

I regards #DEFINEs as project-wide 'things' and as such they go into main.h.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Brian Fairchild wrote:

I regards #DEFINEs as project-wide 'things' and as such they go into main.h.

 

And in a similar vein all globals go into global.c/global.h.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

@skeeve, 'namepins.h' eludes me.  Where is it to be found?  I assume it is of your own creation...?

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

And I also have version.h which #defines an ASCII version string and copyright message to embed into the flash as well as comments to detail changes from version to version.

#1 This forum helps those that help themselves

#2 All grounds are not created equal

#3 How have you proved that your chip is running at xxMHz?

#4 "If you think you need floating point to solve the problem then you don't understand the problem. If you really do need floating point then you have a problem you do not understand." - Heater's ex-boss

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

For most of my AVR projects I have a xxx.c file with main() and any logic functions needed, along with another init.c file with support driver functions for all of the devices I'm using like TWI, USART, timers, ADC, etc...  along with one .h file for needed "define"s for h/w pins, constants etc....   then most of my targets tend to be t25/45/85 or m48/88/168/328's.

so code size tends to be a few pages long at the most.

Project directory:

 

sensor.c

init.c

init.h

project.h

 

 

Jim

edit: added init.h that gets included in sensor.c

 

Click Link: Get Free Stock: Retire early! PM for strategy

share.robinhood.com/jamesc3274
https://www.onegold.com/join/7134f67c2b814c5ca8144a458eccfd61

 

 

 

Last Edited: Tue. Aug 9, 2016 - 04:45 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
@skeeve, 'namepins.h' eludes me.  Where is it to be found?  I assume it is of your own creation...?
In the attachment to #19,

along with bowling.c , bowling.i0 and bowling.sh .

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

It doesn't appear to:

$ tar tzf bowling_0-1.tgz 
bowling.c
bowling.sh
bowling.i0
$

 

"Experience is what enables you to recognise a mistake the second time you make it."

"Good judgement comes from experience.  Experience comes from bad judgement."

"Wisdom is always wont to arrive late, and to be a little approximate on first possession."

"When you hear hoofbeats, think horses, not unicorns."

"Fast.  Cheap.  Good.  Pick two."

"We see a lot of arses on handlebars around here." - [J Ekdahl]

 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

netizen wrote:
One thing I very much love is my variadic bit() macro:

#define bit(bits...)   ...

bit(ADEN, ADSC, ADIE)  =>  1<<ADEN | 1<<ADSC | 1<<ADIE
(protective parens not shown for clarity)

I'd been trying to do somewhat the same, but kept coming up with unstoppable recursion.

Now that I know how to count arguments, this seems tidier to me:

/* Author: Michael Hennebry
   counting mechanism courtesy AVRfreak netizen
*/

/*
 For 1..8 total arguments, mkmask produces
 a parenthesized expression equivalent to
     n
     | (1UL<<(arg_j)
    j=1
 where n is the number of arguments and arg_j is the jth argument

 With a GNU extension, mkmask() produces an expression equivalent to 0UL,
 otherwise a syntax error.
*/

#define mkmask(...)  _mkmask(dummy , ##__VA_ARGS__ , 8,7,6,5,4,3,2,1,0)

#define _mkmask(dummy, a1, a2, a3, a4, a5, a6, a7, a8, count, ...) ( \
    ((count>=1)? 1UL<<(a1) : 0) | \
    ((count>=2)? 1UL<<(a2) : 0) | \
    ((count>=3)? 1UL<<(a3) : 0) | \
    ((count>=4)? 1UL<<(a4) : 0) | \
    ((count>=5)? 1UL<<(a5) : 0) | \
    ((count>=6)? 1UL<<(a6) : 0) | \
    ((count>=7)? 1UL<<(a7) : 0) | \
    ((count>=8)? 1UL<<(a8) : 0)  )

 

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

Last Edited: Tue. Aug 9, 2016 - 05:56 PM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

On further thought, if one does not need the empty case,

this is even tidier:

// Author: Michael Hennebry

/*
 For 1..8 total arguments, mkmask produces
 a parenthesized expression equivalent to
     n
     | (1UL<<(arg_j)
    j=1
 where n is the number of arguments and arg_j is the jth argument.

 The ninth and subsequent arguments, if any, are quietly ignored.
*/

#define mkmask(...) _mkmask(  \
    __VA_ARGS__, \
    __VA_ARGS__, \
    __VA_ARGS__, \
    __VA_ARGS__, \
    __VA_ARGS__, \
    __VA_ARGS__, \
    __VA_ARGS__, \
    __VA_ARGS__  )

#define _mkmask(a1, a2, a3, a4, a5, a6, a7, a8, ...) ( \
    (1UL<<(a1)) |  \
    (1UL<<(a2)) |  \
    (1UL<<(a3)) |  \
    (1UL<<(a4)) |  \
    (1UL<<(a5)) |  \
    (1UL<<(a6)) |  \
    (1UL<<(a7)) |  \
    (1UL<<(a8)) )

 

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I usually have a config.h where all the defines go. It describes the project. Any module I write then includes config.h. For example, my character LCD code includes config.h, where I put what port pins do what. Each library I use includes samples in a comment of what it expects to find in config.h. Config.c has the project's setup functions for setting pin direction and the like.

The largest known prime number: 282589933-1

It's easy to stop breaking the 10th commandment! Break the 8th instead. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

skeeve wrote:
On further thought, if one does not need the empty case, this is even tidier

Yeah, I get your point.

Personally I want the generated code to look like "normal" code: I tend to use avr-gcc's -E option at times. The simple fact that generated code has the right number of flags (as opposed to several duplicates that will later get simplified by the compiler) is valuable information I do not want to lose.

But to each their own… :-)

ɴᴇᴛɪᴢᴇᴎ

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

netizen wrote:
skeeve wrote:
On further thought, if one does not need the empty case, this is even tidier

Yeah, I get your point.

Personally I want the generated code to look like "normal" code: I tend to use avr-gcc's -E option at times. The simple fact that generated code has the right number of flags (as opposed to several duplicates that will later get simplified by the compiler) is valuable information I do not want to lose.

But to each their own… :-)

#define mkmask1(a)       (1<<(a))
#define mkmask2(a,b)   ( (1<<(a)) | (1<<(b)) )
#define mkmask3(a,b,c) ( (1<<(a)) | (1<<(b)) | (1<<(c)) )
...

 

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Ok, but then: how it is any tidier than the original code?

Thinking about mkmask8() makes me shiver… ;)

ɴᴇᴛɪᴢᴇᴎ

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

joeymorin wrote:
It doesn't appear to:

$ tar tzf bowling_0-1.tgz 
bowling.c
bowling.sh
bowling.i0
$

Fixed at last.

Don't know why I didn't notice this post sooner.

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

skeeve wrote:
On further thought, if one does not need the empty case

But the empty case is of paramount importance!

Typically you'd have code like this:

// use ADC5
#define ADC_MUX   MUX2, MUX0
...
ADMUX = bit(ADC_MUX);

What if you need to use ADC0? You'd have to change the first line into:

#define ADC_MUX

And it would break your code for no good reason.

 

Note: I personally have a NONE define to make such cases more explicit:

#define NONE
...
// use ADC0
#define ADC_MUX   NONE

 

ɴᴇᴛɪᴢᴇᴎ

Last Edited: Thu. Sep 1, 2016 - 11:36 AM
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I hadn't considered the case where one might want to

specify an integer as a possibly empty list of one bits.

When the target bits are contiguous, I use something like integer<<MUX0 .

That said, I am aware of cases where the bits are not contiguous.

My recollection is that the avr-gcc library goes through

some contortions to get the wdt time interval bits right.

"SCSI is NOT magic. There are *fundamental technical
reasons* why it is necessary to sacrifice a young
goat to your SCSI chain now and then." -- John Woods

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

I sometimes use a pre-processor to handle these bits.

It rewrites words between double-brackets to the usual bit-shift expansion.

I can't get this HTML editor to show double brackets, so pretend there's no spaces between each [ and ] below.

It changes this

[ [ A B C ] ]

to this

((1<<(A))|(1<<(B))|(1<<(C)))

I'm sure I'll be ridiculed for this!

Attachment(s): 

Mike

Last Edited: Thu. Sep 1, 2016 - 05:41 PM