Hello button in C, explained

Back

//
// hello.button
//
// test blinking a LED with a button
//
// Jakob Nilsson
// 2017-03-20
//


//SETUP PHASE, stores a list of defined names, contains macros and includes libraries 

#include <avr/io.h> // a library to simplify handling of the I/O ports

//Renaming the different bit registers to improve readabillity, these refer to list of ones and zeros.
#define led_port PORTA //the values of pins, if they are HIGH or LOW. This is a read/write-able list. The LED is connected to pin 6, which is part of the A pin port, on adress PA7.
#define led_pin (1 << PA7) // the compiler knows that we are using a attiny so it looks up the pin number for pin PA7 and puts an 1 in that position in a list of bits and we name this list led_pin for later use. It probably looks like this 1000000 (seventh pin marked).  
#define led_direction DDRA //the direction of pins, a 1 or 0 control if we use them for input or output. We later set the LED pin direction by combining this list whith the one we named led-pin.
#define button_port PORTA //The button pin is also part of Pin Port A, and we already defined PORTA to be the led_port so this means that we later will manipulate different parts of the same registers, we will take care not to ovewrwrite the wrong part of the register.
#define button_direction DDRA //the direction of pins, if we use them for input or output. It is the same register which holds the information about the LED pin.
#define button_pins PINA //the values of pins, if they are HIGH or LOW. This is read only and used for reading the value on a pin, good for buttons :)
#define button_pin (1 << PA3) //The button is connected to pin 10, which has the adress PA3 in the A register (DDRA, PINA and PORTA). So this list probably looks like this 100 (third pin marked). We will use this list of bits later to tell the attiny where we connected our button. 

//Here we setup some macros that (hopefully) makes the code easier to read and which we can reuse to easily do the same things several times
#define output(directions,pin) (directions |= pin) // Set port direction for output pins, we want to set a certain bit to high (1) so that the attiny knows that pin is an output. We do this by taking a list of bits marking the one we want to turn on and cleverly* combining it with the register and then writing it back to the register. 
#define input(directions,pin) (directions &= (~pin)) // Set port direction for input pins, we want to set a certain bit to low (0) so that the attiny knows that pin is an input. We do this by taking a list of bits marking the one we want to turn off and cleverly* combining it with the register and then writing it back to the register.
#define set(port,pin) (port |= pin) // set port pin, this means turn it on by setting it to HIGH or 1.
#define clear(port,pin) (port &= (~pin)) // clear port pin, this means turn it off by setting it to LOW or 0.
#define pin_test(pins,pin) (pins & pin) // test for port pin, this means read if it is high or low.

//*To learn clever C bit manipulation, read this, really, do it http://www.avrfreaks.net/forum/tut-c-bit-manipulation-aka-programming-101?page=all

//THE PROGRAM, this is where we change things.

int main(void) {

    //Set directions of pins, we only need to do this part once.
    output(led_direction,led_pin); //This takes our list with the position of the LED pin (1000000) and combines it with whatever is in the correct direction list (DDRA), it makes sure to turn ON (1) that bit in the pin direction list to indicate that it is to be an OUTPUT and leaves the rest of the list as is.
    input(button_direction,button_pin);  //This takes our list with the position of the BUTTON pin (100) and combines it with whatever is in the correct direction list (DRRA, the same as above), it makes sure to turn OFF (0) that bit in the pin direction list and leaves the rest of the list as is. The pin direction list for pin group A (DDRA) should now look something like this 1xxx0xx, where 'x' markes unknown pin directions, 1 marks outputs and 0 marks inputs.

   while (1) { //Loop forever. While loops run as long as the contents of the () is TRUE. The '1' used in this case will not change so this part will loop forever.  

   while (!pin_test(button_pins,button_pin)){ // the macro pin test will return TRUE when the button is NOT pressed since our pull up resistor pulls the pin HIGH (1). Pressing the button will connect the pin to ground, and make it read LOW (0). The "!" sign inverts TURE to FALSE and makes it break the loop when the button is pressed.

     set(led_port, led_pin);   //turn on the LED by writing a 1 to the correct PORT register spot (setting the bit) which corresponds to this pin. This way several leds could be turned on at once.

    }

       clear(led_port, led_pin);  //turn of the LED by writing a 0 to the correct PORT register spot (clearing the bit) which corresponds to this pin. This way several leds could be turned off at once.

   }
}

Top