Best Practices on Structural Programming

Modular Programming: Modular programming involves dividing code into smaller, independent modules. Modules can be reused multiple times and are easy to test. Modular programming increases the readability and understandability of the code. Each module should have a clearly defined function and interface. Modules should be independent of each other, which facilitates their modification and development.

Impact of AVR Architecture Variations on Modular Programming

Although AVR microcontrollers share a common 8‑bit RISC architecture, different models often vary in several important aspects. These differences influence how software should be structured, especially when aiming for portability and long‑term maintainability.

1. Differences in Register Addresses

AVR devices frequently place hardware registers at different memory addresses. Even peripherals with identical functionality—such as timers, UART, SPI, or ADC—may be mapped to different I/O locations depending on the specific AVR model. Examples:

Programming Implications

Hard‑coding register addresses or device‑specific constants inside logic modules makes the code non‑portable.To avoid this:


2. Differences in Peripheral Availability

Not all AVR microcontrollers include the same set of peripherals:

Programming Implications

Modules that depend on specific peripherals must be written with flexibility in mind. Recommended practices include:


3. Differences in Interrupt Vector Layout

AVR devices differ in:

Programming Implications

Interrupt‑driven modules must rely on symbolic ISR names rather than fixed vector numbers. Example:Vis mindreKodeblokk er utvidet ISR(TIMER1_COMPA_vect)

This ensures that the correct interrupt is used regardless of the device’s vector table layout.


4. Differences in Memory Size and Addressing

Larger AVR devices (e.g., ATmega128, ATmega2560) require extended addressing mechanisms:

Programming Implications

Modules accessing program memory or large data structures must:

This highlights the importance of isolating memory‑related operations into dedicated modules.


How Modular Programming Helps Manage AVR Differences

A well‑structured modular design allows hardware‑dependent code to be isolated from application logic. This is typically achieved through the following layering:


1. Hardware Abstraction Layer (HAL) *

HAL provides a unified interface to peripherals, regardless of the underlying AVR model.

Example functions:

Internally, HAL uses different registers depending on the device, but the application code remains unchanged.


2. Device‑Specific Configuration Modules

These modules contain:

By placing these in separate files, it becomes easy to adapt the project to a new AVR model.


3. Reusable High‑Level Modules

These modules remain independent of hardware details and include:

Such modules can be reused across many different AVRs.


Summary

Differences between AVR models—register locations, peripheral availability, interrupt structures, memory addressing—directly affect software design. Modular programming provides a robust framework for handling these variations by separating hardware‑specific code from application logic.

This ensures: