Developing in C for the ATmega328P: Hints

3 minute read

This page provides a broad level of short hints and comments as to C programming and AVR programming.

C Best Practices

From Embedded C Coding Standard Barr Group

While the entire book is outstanding, I want to call out some specific practices which I strongly recommend following:


b. Each left brace ({) shall appear by itself on the line below the start of the block it opens. The corresponding right brace (}) shall appear by itself in the same position the appropriate number of lines later in the file.

	if (depth_in_ft > 10) dive_stage = DIVE_DEEP; 		// This is legal...
	else if (depth_in_ft > 0)
		dive_stage = DIVE_SHALLOW; 							// ... as is this.
		dive_stage = DIVE_SURFACE; 							// But using braces is always safer.

By following the above example by always using braces properly, it not only makes your code safer, it becomes much easier to cut and paste specific blocks of code.


I’ve found it best to use // style comments (called single line comments) as compared to using /*…*/ (called traditional C comments) as it is easy to forget the trailing */ or adding a new comment in the middle may cause issues.

Bit-wise manipulation

From Make: AVR Programming Elliot Williams

Bit shifts have the effect of rolling all of the bit positions to the left or right, depending on your command. Bits that fall off either end just disappear, and any new bits added are all zeros. The C language instruction for shifting all the bits in a number to the left or right is « or », respectively. Now let’s see how they’re used.

Bit shift examples:

  • 0b00001110 » 3 = 0b00000001

  • Three new zeros were added to the left, and the bits on the right just rolled off the edge.

  • 0b00001110 « 2 = 0b00111000

  • Two new bits, both zeros, are rolled in from the right.

What this means to you as a programmer is that if you want a single 1 bit in position number three, say, you can start off with the number that has a 1 bit in position zero, and roll it to the left three spaces. The bit-shift roll:

  • 1 = 0b00000001
  • (1 « 0) = 0b00000001
  • (1 « 1) = 0b00000010
  • (1 « 3) = 0b00001000
  • (1 « 7) = 0b10000000

From Programming the Atmel ATmega328P in C

The individual bits in the registers can also be accessed however the bits can not be read or written in the same way as the full registers. To write ones or zeros into bits, use the “|” (OR) and “&” (AND) operators to change the bits. For example, to set bit 3 in PORTB to a one, and clear bit 5 to a zero in PORTD do the following.

PORTB |= (1 << 3); Set the 4th bit in Port B to 1
PORTD &= ~(1 << 5); Set the 6th bit in Port B to 0
The bits in the device registers all have declared names in the “avr/io.h” file and these should be used for setting and clearing bits. TCCR1B |= (1 « WGM12 ); TIMSK1 |= (1 « OCIE1A ); Multiple bits can be set (or cleared) with one statement in the same manner. TCCR1B |= ((1 « CS12) | (1 « CS11)); When writing individual bits in the registers it is important to be aware that this will cause the micro- controller to first read the full eight-bit byte, modify the byte, and then write the full byte back. Some of the internal functions of the microcontroller are affected by reading a register so it is important to be aware of any potential side effects when accessing the registers.

Comments powered by Talkyard.