Language: C (SDCC Compiler/C99 Standard)
Read the C99 Coding Guidelines document first.
Moving from Python to C requires a shift in mindset. In C, you are managing the hardware directly. There is no automatic memory management, and safety features must be added by you, the programmer.
.h file must be wrapped in generic include guards to prevent recursive inclusion.< >) go first, followed by project headers (" ").//) for general notes and descriptions. Avoid multi-line C-style comments (/* ... */) unless commenting out large blocks of code.#ifndef SENSOR_H
#define SENSOR_H
#include <stdint.h>
#include <stdbool.h>
#include "hardware_map.h"
// Prototypes go here
#endif
Bad (Hard to read/debug):
if (ready) { go = true; } else { go = false; }
Good:
if (ready) {
go = true;
} else {
go = false;
}
}) must vertically align with the line that opens the brace ({)
Why: This maintains clear visual block structure and prevents the “dangling else” error where the else accidentally attaches to the wrong if statement.Bad (Dangling Else Risk):
if (a > 0)
if (b > 0)
c = 1;
else
c = 0; // This 'else' attaches to the second 'if (b > 0)'!
Good: Correctly resolves the ambiguity by making the compiler’s default choice explicit.
if (a > 0) {
if (b > 0) {
c = 1;
} else {
c = 0;
}
}
if-else:When else is immediately followed by if, it is a good idea to not use { right after else, as this can make the code hard to read:
Good: easy to understand:
if (bitcoin >= 20) {
class = PLATINUM;
} else if (bitcoin >= 10) {
class = GOLD;
} else if (bitcoin >= 5) {
class = SILVER;
} else {
class = REGULAR;
}
Bad: indentation makes it hard to read:
if (bitcoin >= 20) {
class = PLATINUM;
} else {
if (bitcoin >= 10) {
class = GOLD;
} else {
if (bitcoin >= 5) {
class = SILVER;
} else {
class = REGULAR;
}
}
}
Do not use generic int or long. In embedded systems, we need to know exactly how many bits a number uses.
Always include
| Type | Description | Use Case |
|---|---|---|
uint8_t |
Unsigned 8-bit (0 to 255) | Hardware registers, bytes, flags. |
int8_t |
Signed 8-bit (-128 to 127) | Small math values. |
uint16_t |
Unsigned 16-bit (0 to 65,535) | Counters, memory addresses. |
bool |
Boolean (true/false) | Logical checks. |
void |
Empty/Nothing | Functions returning nothing. |
Variables should be immutable (const) by default. Only remove const if the variable must change (e.g., a counter or accumulator).
const.const uint8_t max_retries = 5; // Good: This is a fixed setting
uint8_t current_retry = 0; // Good: This changes in a loop
uint8_t sensor_value;void read_data(void);#define MAX_BUFFER 255const uint8_t LED_PIN_INDEX = 1U;*) to the variable name.
uint8_t *data_ptr;uint8_t* data_ptr;* const), place the asterisk immediately before the const keyword.
uint8_t * const lcd_buffer = (uint8_t *)0xE000U;void.
int32_t calculate_sum(void);// Use explicit assignment (i = i + 1) to comply with the rule against composite operators.
for (uint8_t i = 0; i < 10; i = i + 1) {
// ...
}
.h) before use in a source file (.c). C is compiled sequentially, unlike Python.| Feature | Python | C99 Guideline |
|---|---|---|
| Blocks | Indentation | Curly Braces { } (Indentation is purely visual) |
| True/False | True / False |
true / false (requires <stdbool.h>) |
| Variables | Dynamic (x = 5) | Static (const uint8_t x = 5;) |
| Strings | “Hello” | Array of chars (const char msg[] = "Hello";) |
| Printing | print("Val:", x) |
uart_transmit_byte(x); |
| Main | if __name__ == "__main__": |
void main(void) { ... } |