©2019 Robotics for COMPLETE Beginners

16

C Programming Electronics

 

Today is the BIG DAY...

HUGE.

It is time to learn the basics of C programming for the AVR chips.

The concepts of which will be applicable to programming other brands and types of microcontrollers/microchips with this powerful language.

 

These fundamentals will unlock near infinite possibilities for you in terms of building electronics, robots, and prepare you for object oriented programming and high level programming if you choose to go that route.

Why program in c?

 

You will understand what is happening with the hardware and why, better than other languages.

C is the foundation for most of the commonly used languages (C++, Java, C#, etc.)

It was developed to provide an easier way for programmers to speak with machines.

Arduino language is a wrapping on top of C++ which is a wrapping on top of C.

Many people can make cool projects but they will never be the badass you are destined to be!

Wax that mustache, roll up your pants, and pull them velcro straps tight!

You are getting down and dirty with hardware and there is no turning back.

 

You will know how to make things that calculate, move objects, and perform work.

 

The greatest part about this is you don't even have to be good at it.

 

You just need to know what to do and where.

 

The rest will come over time through experience, just like learning an instrument.

 

Shall we learn how to play this one?

That's what I thought!

Look at this screenshot of a C program for the AVR.

I like white on black better and a little green to remind me of my roots playing on old IBM machines.

Can you tell what any of this means?

Do you know what it can do?

Can you identify the hardware involved?

No? Yes? Maybe? You think you know?

Let's take a look!

"Enhance that image..."

At the top of the screen we have what are called header files.

These files include references to commonly needed jobs which are referred to as functions.

Imagine you are in a restaurant.

Functions do jobs for you. You are their manager.

They can cook, clean, take care of incoming and outgoing customers.

Count money for you, mix drinks and solve problems, etc.

Another way to think is that functions are actors and you are their director.

You tell them when and where to go on the stage and what to do for how long, etc.

It would be time consuming and annoying to have to flesh out all of the various functions which are commonly used, as well as difficult to learn how to program them on their most basic level.

The good news is, some nice people have done this all for you already and you don't need to reinvent the wheel.

We can use any of the functions simply by calling their name when we type out our code.

You can also make your own functions which I will show you how to do later.

The most crucial, predefined C language functions for the AVR chip are included simply by typing:

 

#include <avr/io.h>

include means...include of course!

avr means....AVR of course!

"/" you often see in the address path of files on your computer right?

How about "io"? What could that mean?

Input Output.

AHA! Pretty easy! This is why we use C or some other language to program the AVR chip instead of Assembly or Hex (please no). 

 

It's easier for us to learn, type, and understand which means faster, more powerful creations.

So, all of the vital input / output functions concerning the Data Direction (Input/Output) Register, DDR for short, as well as the actual pins themselves in the PORT register, PORT, are addressed in this and are ready for you to use which will be learned over time, don't try and memorize them all yet.

If you want, check out more details about what the <avr/io.h> includes.

You will notice in the source code that it includes other header files.

Ok. Now, let's look at the second included header file:

#include <util/delay.h>

This is a utility for the delay functions that someone has provided for you to use.

This comes in handy when we need to add a slight delay after a function to prevent the code from running all over itself.

That is all we needed for this program/code!

In the next tutorial I will show you how to make your own header files and libraries which can be included similarly.

The next section of code is shown below.

What could this section be called?

Hmmmmmmmmm!

Could it be.....MAIN?

Ding ding ding! That's correct.

We outline the main function of our code by including the terminology:

  int main(void) {

  }

Want to know what main has in common with you?

There can only be one.

"int" is telling the type of data to be returned with this main function.

Int means integer.

This term is used because after the code executes it will return a '0' or a '1'.

The '0' meaning there were no errors, a '1' meaning there were errors.

Pretty cool huh?

"main" is the name of the function. It should remain as "main".

 

When making your own functions you can make the name of them anything you want but leave this one as "main".

So, we want an integer to be returned from this function, it's named "main" and within "main" we have parentheses with the word "void", (void).

The ( ) are the parameters main expects to from the "caller" which is the startup code which we don't see here so don't worry about it.

The "void" means that this function name "main" doesn't expect any parameters to be defined by the startup code.

It doesn't expect anything, it's unconditional love, just execute through, no terms.

Ok, that might take a little while to settle in your mind.

Now we have those curly brackets {   }.

Think of these as doors you open and close.

{ = open door

} = close door

You MUST close all the doors you open before you leave the house which is your program!

Notice that the door is left open in the in main(void) function.

This is because it leads to the next part we see below!

The LOOP!

Let's recap, there are 3 key parts to a program:

1. Include files

2. Main

3. Loop

Just before we head down there we need to understand what

DDRB |= (0b00000001); means.

This is easy to understand but hard to explain.

The DDRB, if you remember, is the Data Direction Register B, which is linked to the PORT B Pins, or PB pins for short.

By turning ON that first bit we set the entire 'B' register to OUTPUT.

It's like flicking on a switch for all the lights in a room.

Another way to do this is write it like DDRB |= (0xff);

0xff is hexadecimal for turning it all ON.

The |= is an operator which we will cover in detail later on down the road where you will take a deep dive with me into C programming.

Don't worry, I'll make it easy.

 

Another cool thing about code in general being there are different ways to do the same thing.

This means the pins associated with 'B' are all going to send electricity out.

All incoming electricity will be ignored.

We are going full on Blitzkrieg with these pins.

We set the stage in the main part of our code.

The loop is where most of the work gets done.

We use the function "while" which means exactly what it does.

 

The parameters, the expectations, of "while" are (1).

Can you guess what 1 means? 

 

Hint: We covered what it means to computers before.

That's right, it means ON or while TRUE or while YES.

So, the while(1) {

               }

...means that it will execute through this area of the code from beginning to end over and over and over and over.

So, we put the work to be repeated right in between those brackets.

For example, you could put code to set a register of pins to be all OUTPUT and also set the state of a specific pin as ON or OFF in the Main section of your code.

 

You would also be able to set up your sensor or servo position, etc and the AVR hardware to talk with it in "main".

 

Then the actual work to be done each time the AVR chip loops through the code in the while(1) section.

Each chip, whether it be the Atmel AVR chips, PIC series chips, Raspberry Pi chips, Intel, AMD, etc. all have a maximum frequency that they display in Hertz (Hz), remember?

This is how many times the chip goes through the loop each second.

You learned that an 8 Megahertz chip is 8,000,000 Hertz.

8,000,000 loops per second.

Blazingly fast.

Home PCs and handheld devices are even faster reaching Gigahertz.

To a chip, our world seems to barely move while it lives, dies and repeats 8 million times or more in a second.

During each of those life cycles it carries out the jobs (functions) that you told it to do.

It turns on and turns off pins and calculates all sorts of math for you.

When it comes back to life in the next loop it does it all over again and makes decisions that you told it to.

For example, to send electricity to a pin which moves a motor if a button press allows voltage to come in through a different pin and store the number of times the button was pressed and keep adding to that number each time it is pressed in subsequent loops.

By SLOWING DOWN your understanding you will INCREASE your SPEED of learning.

WHEW!

This may be very new to you. I have explained it in the simplest way possible. Just breath and re-read you will get it.

Remember, the #include section gives us access to books with our characters and scripts.

The main section sets the stage.

The while(1) loop section performs the actual play.

Now, we are going to actually send out electricity on PB0.

Remember, computer chips start counting with 0.

The chip we have is an 8 bit chip which is the same as saying it is 1 byte.

8bits = 1 byte

Think of these bits as a row of 8 black boxes.

When we turn the on by writing a 1 for example, it changes the associated box to white.

You can see the PB0 bit set to ON as it is at the address 0b0000001.

Just think of it as an address for PB0's house and DDRB is the street it lives on.

There are other ways to write this address that are simpler but it's important for you to understand that you are flipping 1 bit to access the pin.

PB1 is located at 0b000010 and PB2 is located at 0b0000100 etc.

If you wanted to turn on all of these three pins all you have to do is...

0b0000111

We tell the program to write the value with |= in the middle.

The ; at the end is like a period at the end of a sentence.

It tells the compiler that your statement is over for that portion of the program.

In this while(1) loop we tell the pin to turn on, wait 1000 milliseconds, then turn off.

When the loop soes back to the top of the loop and starts again.

The Main is only executed one time on power up so it doesn't need to go back up there.

If you want it to just disconnect and reconnect the power or if you are using the Aruduino or similar boards there should be a reset button.

More important than knowing all the code that can go in here is knowing where your code needs to go.

Let's review one more time.

Pre-made files which contain useful functions are included for reference at the top.

They are included with the # symbol followed by <nameofthefile>.

Some of these are built into the compiler you install under a file in a standard C language library called libC.

For AVR users there is a flavor of this standard libC library designed to better suite the chips called AVR-Libc.

We will cover header files and library creation more in depth in the next lesson.

Also, check out the Microchip website itself for a surprisingly simple site with simple explanations of AVR-Libc entire toolchain and process.

Additional functions can be designed by you before the Main section.

The Main sets the state of everything and calls all actors in and sets the stage.  This is where you set the state of pins and perform a role call for your functions you need.

The Loop is where the actual work gets done.

Take another look at the loop here.

You know the loop starts with while(1) {

Look at what is in the loop.

We have PORTB which is associated with the 'B' pins on the chip which were all set as OUTPUT in the Main section of our code.

In PORTB we are going to flip ON PB0 which is the first pin, remember computers start counting from 0.

We can turn on PB0 by flipping its bit in the 8 bit block by saying PORTB = 0b00000001.

Remember after the 'b' are our bits.  PB0 is the 1st bit on the far right.

What is next in the loop code?

A delay!

Remember we included the <util/delay.h> file in the top of our code?

It allows us to use the function delay_ms( ) to keep the PB0 pin ON for 1000 milliseconds.

 

Feel free to change this value and play with it.

Then you can see we turn PB0 OFF by saying PORTB = 0b00000000.

After that we put in the delay again to give us time to see it actually OFF.

Then the loop goes back to the beginning and starts all over again, and again, and again, and again, and again, and again, and again, and again...

Simple, right?

There are sexier ways of doing this just as there are many ways of saying the same thing when speaking a language.

Never forget that all of this programming is merely flipping bits on and off and there are  certain pins and preprogrammed work that can be done merely by flipping the right bits in the right places.

This is all programming is and all you need to remember when programming your terminator.

Remember, we need to close all of the doors that we opened!

So we have to include:

We close the door of the loop aka while(1) and insert a return(0) which is standard C practice but never actually reached in the AVR.

Finally, we close the door of Main.

If you put your cursor next to each bracket in Programmer's Notepad or similar program it will show you which door they are paired with.

That's it!

Congratulations!

You are now a badass C programmer.

 

The world is your oyster!

 

You'll do great kid.

Get my favorite books on programming AVR chips I use.

Equip yourself with the most dependable, no hassle, quality usb programmer I use daily.

Make sure you have a basic kit. Arduino is fine, it contains the removable AVR 328p chip we will use.

 

I started with something very similar.

Summary

This is your most important lesson in your life up to this point.

You were destined to learn this and to put it to good use.

You have the foundation for building C programs which are still a highly profitable business.

You also know how to program a microcontroller and the overall layout of the program which its 3 major parts.

I am so excited for you and for the future of us all here.

We have the power to create incredible machines both simple and complex, helpful and ....well you know...

Someone who is dead once said "...with great power comes great ..."

I can't remember the rest...

I think it was "great tacos" or "great grandmas"...something like that.