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.
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: