Use of global variables in Embedded Systems
You can use global variables successfully, as long as you keep in mind @Phil's guidelines.
However, here are some nice ways to avoid their issues without making the compiled code less compact.


Use local static variables for persistent state that you only want to access inside one
function.

#include &lt;stdint.h&gt;
void skipper()
{
    static uint8_t skip_initial_cycles = 5;
    if (skip_initial_cycles &gt; 0) {
        skip_initial_cycles -= 1;
        return;
    }
    /* ... */
}

Use a struct to keep related variables together, to make it clearer where they should be
used and where not.

struct machine_state {
     uint8_t level;
     uint8_t error_code;
} machine_state;

struct led_state {
    uint8_t red;
    uint8_t green;
    uint8_t blue;
} led_state;

void machine_change_state()
{
    machine_state.level += 1;
    /* ... */
    /* We can easily remember not to use led_state in this function. */
}

void machine_set_io()
{
    switch (machine_state.level) {
    case 1:
        PIN_MACHINE_IO_A = 1;
        /* ... */
    }
}

Use global static variables to make the variables visible only within the current C file. This prevents accidental access by code in other files due to naming conflicts.

/* time_machine.c */
static uint8_t current_time;
/* ... */

/* delay.c */
static uint8_t current_time; /* A completely separate variable for this C file only. */
/* ... */



As a final note, if you are modifying a global variable within an interrupt routine and reading it elsewhere:


Mark the variable volatile.
Make sure it is atomic for the CPU (i.e. 8-bit for an 8-bit CPU).


OR


Use a locking mechanism to protect access to the variable.