katolicki-tjednik.com
Menu
RSS
September 6, 2025

Five 8051 Timer Hacks That Will Revolutionize Your Designs – Embedded Flakes

maximios ⋅ IT

In the world of microcontroller-based designs, the 8051 family continues to be a popular choice for many engineers and hobbyists. One of the most powerful features of the 8051 is its versatile timer system. In this article, we’ll explore five ingenious timer hacks that will take your 8051 designs to the next level. These techniques will not only improve the efficiency of your projects but also open up new possibilities for creative solutions.

Table of Contents

When it comes to measuring frequencies with high precision, the 8051’s timer capture mode is a game-changer. By utilizing the timer in capture mode, we can accurately measure the period of an incoming signal and calculate its frequency with remarkable accuracy.

Here’s a C code example demonstrating how to set up Timer 1 in capture mode for frequency measurement:

#include 

unsigned long measure_frequency(void) {
    unsigned int t1, t2;
    unsigned long freq;

    TMOD = 0x10;  // Timer 1, Mode 1 (16-bit timer)
    TR1 = 1;      // Start Timer 1

    while (!TF1); // Wait for timer overflow
    TF1 = 0;      // Clear overflow flag

    while (!TF1); // Wait for next overflow
    t1 = TH1;
    t1 = (t1  0) {
        delay_count--;
    }
}

void main(void) {
    init_timer2();

    while(1) {
        P1 = 0xFF;   // Turn on LEDs
        delay_ms(500);
        P1 = 0x00;   // Turn off LEDs
        delay_ms(500);
    }
}

This code sets up Timer 2 to generate an interrupt every 1ms. The delay_ms() function uses this timer to create precise delays without busy-waiting, allowing the CPU to perform other tasks during the delay period.

The 8051’s timers can be used as counters, allowing us to count external events or divide frequencies. This is particularly useful in applications such as tachometers or frequency synthesizers.

Here’s a C code example that demonstrates how to use Timer 0 as an event counter:

#include 

volatile unsigned long event_count = 0;

void init_counter(void) {
    TMOD |= 0x05;  // Timer 0, Mode 1 (16-bit), external event counting
    TH0 = 0;
    TL0 = 0;
    ET0 = 1;       // Enable Timer 0 interrupt
    EA = 1;        // Enable global interrupts
    TR0 = 1;       // Start Timer 0
}

void timer0_isr(void) __interrupt(1) {
    event_count++;
    TH0 = 0;
    TL0 = 0;
}

void main(void) {
    init_counter();

    while(1) {
        // Main program loop
        if(event_count >= 1000) {
            P1_0 = !P1_0;  // Toggle LED every 1000 events
            event_count = 0;
        }
    }
}

This code configures Timer 0 to count external events on the T0 pin. Each time the timer overflows, the interrupt increments a counter. This technique can be used to measure frequencies, count revolutions, or implement frequency dividers.

One of the most powerful applications of timers in microcontroller designs is task scheduling. By using a timer to generate regular interrupts, we can create a simple real-time operating system that executes different tasks at specific intervals.

Here’s a C code example that demonstrates a basic task scheduler using Timer 2:

#include 

#define MAX_TASKS 5

typedef struct {
    void (*task)(void);
    unsigned int period;
    unsigned int counter;
} Task;

Task task_list[MAX_TASKS];
unsigned char task_count = 0;

void init_scheduler(void) {
    T2CON = 0x00;   // Timer 2 in 16-bit auto-reload mode
    TH2 = 0xFF;     // Set high byte of auto-reload value
    TL2 = 0xF7;     // Set low byte of auto-reload value (1ms @ 12MHz)
    ET2 = 1;        // Enable Timer 2 interrupt
    EA = 1;         // Enable global interrupts
    TR2 = 1;        // Start Timer 2
}

void add_task(void (*task)(void), unsigned int period) {
    if(task_count < MAX_TASKS) {
        task_list[task_count].task = task;
        task_list[task_count].period = period;
        task_list[task_count].counter = 0;
        task_count++;
    }
}

void timer2_isr(void) __interrupt(5) {
    unsigned char i;
    TF2 = 0;  // Clear Timer 2 interrupt flag

    for(i = 0; i < task_count; i++) {
        task_list[i].counter++;
        if(task_list[i].counter >= task_list[i].period) {
            task_list[i].task();
            task_list[i].counter = 0;
        }
    }
}

// Example tasks
void task1(void) {
    P1_0 = !P1_0;  // Toggle LED 1
}

void task2(void) {
    P1_1 = !P1_1;  // Toggle LED 2
}

void main(void) {
    init_scheduler();
    add_task(task1, 500);  // Run task1 every 500ms
    add_task(task2, 1000); // Run task2 every 1000ms

    while(1) {
        // Main program loop
    }
}

This code implements a simple task scheduler that can manage multiple tasks with different execution periods. Tasks are added to the scheduler using the add_task() function, and the timer interrupt ensures that each task is executed at its specified interval.

These five 8051 timer hacks demonstrate the versatility and power of the 8051’s timer system. By mastering these techniques, we can create more efficient, precise, and feature-rich designs. From accurate frequency measurement to sophisticated task scheduling, the possibilities are endless.

As we’ve seen, the key to unlocking the full potential of the 8051 lies in creative use of its timer resources. By combining these timer hacks with other 8051 features, we can develop robust and innovative solutions for a wide range of applications.

Remember, the examples provided here are just the beginning. We encourage you to experiment with these techniques, combine them in new ways, and push the boundaries of what’s possible with the 8051 microcontroller. Happy coding!

September 6, 2025

Decoding the Language of Machines: J1939 Diagnostic Messages Explained – Embedded Flakes

maximios ⋅ IT

In this comprehensive guide, we delve deep into the world of SAE J1939 diagnostic messages, specifically focusing on DM1 through DM16. We explore the intricacies of each diagnostic message, their significance in vehicle communication systems, and how they contribute to efficient troubleshooting and maintenance. This article provides a thorough understanding of J1939 protocols, empowering technicians, engineers, and enthusiasts with the knowledge to interpret and utilize these crucial diagnostic tools effectively.

Table of Contents

The Society of Automotive Engineers (SAE) J1939 standard has revolutionized communication in heavy-duty vehicles and equipment. At the heart of this standard lies a sophisticated system of diagnostic messages that enable machines to communicate their status, issues, and performance metrics. These messages, ranging from DM1 to DM16, form the backbone of modern vehicle diagnostics.

Before we dive into specific diagnostic messages, it’s crucial to understand the foundation of the J1939 protocol. This standard utilizes a Controller Area Network (CAN) to facilitate communication between various components within a vehicle. The protocol defines a standardized method for transmitting data, ensuring compatibility across different manufacturers and systems.

The Importance of Diagnostic Messages in Vehicle Maintenance

Diagnostic messages play a pivotal role in predictive maintenance, real-time monitoring, and efficient troubleshooting. By decoding these messages, technicians can quickly identify issues, prevent potential failures, and optimize vehicle performance. This proactive approach significantly reduces downtime and maintenance costs.

DM1 messages are the frontline soldiers in the battle against vehicle malfunctions. These messages provide real-time information about active faults within the system. Key aspects of DM1 include:

  • Continuous Transmission: DM1 messages are sent periodically, ensuring up-to-date fault information.
  • Fault Prioritization: Critical faults are given priority in transmission.
  • Lamp Status Indication: DM1 includes information about warning lamps, aiding in visual diagnostics.

While DM1 focuses on current issues, DM2 messages provide a historical context. These messages contain information about:

  • Resolved Faults: Issues that were once active but have since been addressed.
  • Intermittent Problems: Faults that occur sporadically, aiding in identifying recurring issues.

DM3 serves as the eraser for diagnostic history. Its primary functions include:

  • Clearing Stored DTCs: Removes previously active fault codes from memory.
  • Resetting Diagnostic Systems: Prepares the system for fresh diagnostic data collection.

DM4 messages capture a snapshot of vehicle parameters at the moment a fault occurs. This includes:

  • Environmental Data: Temperature, pressure, and other relevant conditions.
  • Vehicle State Information: Speed, engine load, and other operational metrics.

DM5 focuses on the readiness of onboard diagnostic systems. It provides information on:

  • System Status: Whether diagnostic systems are fully operational.
  • Monitoring Completion: Indicates if all required diagnostic tests have been performed.

Building upon DM5, DM6 offers more detailed readiness information:

  • Specific System Readiness: Status of individual diagnostic systems.
  • Test Completion Rates: Percentage of diagnostic tests completed for each system.

DM7 allows for on-demand diagnostic testing. Key features include:

  • Test Initiation: Ability to start specific diagnostic tests manually.
  • Custom Testing: Enables technicians to focus on particular areas of concern.

Following DM7, DM8 provides the outcomes of manually initiated tests:

  • Detailed Test Results: Specific findings from the requested diagnostics.
  • Pass/Fail Indications: Clear status of each conducted test.

DM9 is used to gather essential vehicle data:

  • VIN Retrieval: Requests the Vehicle Identification Number.
  • Component Information: Details about specific vehicle components and systems.

DM10 messages deal with persistent fault codes:

  • Non-Erasable DTCs: Faults that cannot be cleared without resolving the underlying issue.
  • Regulatory Compliance: Often used for emissions-related issues to ensure proper repairs.

Similar to DM3, but focused on active faults:

  • Active Fault Clearing: Attempts to reset current diagnostic trouble codes.
  • System Reset: Initiates a reset of active diagnostic systems.

DM12 specifically addresses emissions-related issues:

  • Emissions System Faults: Identifies active problems in emissions control systems.
  • Regulatory Reporting: Aids in compliance with emissions regulations.

DM13 manages the diagnostic communication process:

  • Broadcast Control: Initiates or halts the transmission of specific diagnostic messages.
  • Communication Acknowledgement: Confirms receipt and processing of diagnostic commands.

DM14 enables access to stored diagnostic data:

  • Data Retrieval: Requests specific information from the vehicle’s memory.
  • Custom Queries: Allows for targeted data extraction based on specific parameters.

In response to DM14, DM15 delivers the requested data:

  • Detailed Memory Contents: Provides the specific information requested.
  • Data Formatting: Presents the retrieved data in a standardized format.

DM16 facilitates the transfer of large amounts of diagnostic data:

  • Efficient Data Transmission: Enables quick transfer of complex diagnostic information.
  • Firmware Updates: Often used for updating system software or transferring large diagnostic files.

Understanding these diagnostic messages is crucial for various applications:

Fleet Management and Maintenance

  • Proactive Maintenance Scheduling: Utilizing DM1 and DM2 messages to predict and prevent breakdowns.
  • Efficiency Optimization: Analyzing freeze frame data (DM4) to improve vehicle performance.
  • Emissions Monitoring: Using DM12 to ensure vehicles meet environmental standards.
  • Safety Checks: Leveraging various DMs to conduct comprehensive vehicle safety assessments.
  • Performance Analysis: Utilizing detailed diagnostic data for vehicle design improvements.
  • Failure Mode Studies: Analyzing DTC patterns to enhance vehicle reliability.

To truly master J1939 diagnostics, consider these advanced techniques:

  • Identifying Recurring Issues: Analyzing patterns in DM1 and DM2 messages to spot systemic problems.
  • Predictive Fault Analysis: Using historical data to predict potential future faults.
  • Real-Time Monitoring: Combining J1939 data with GPS and other telematics for comprehensive fleet management.
  • Data-Driven Decision Making: Utilizing integrated data for optimized route planning and maintenance scheduling.
  • Automated Diagnostics: Developing AI systems to interpret complex diagnostic patterns.
  • Predictive Maintenance Models: Creating algorithms to forecast maintenance needs based on diagnostic trends.

While J1939 diagnostic messages offer powerful tools, there are challenges and ongoing developments:

  • Data Protection: Ensuring the security of sensitive diagnostic information.
  • Tamper-Proof Systems: Developing methods to prevent unauthorized manipulation of diagnostic data.
  • Interoperability Challenges: Addressing variations in implementation across different vehicle manufacturers.
  • Universal Diagnostic Tools: Creating diagnostic tools capable of interpreting data from various makes and models.
  • Electric and Hybrid Vehicles: Adapting J1939 diagnostics for new powertrain technologies.
  • Autonomous Systems: Expanding diagnostic capabilities to support self-driving vehicle technologies.

The SAE J1939 diagnostic messages, from DM1 to DM16, form a comprehensive language that allows machines to communicate their status and needs effectively. By mastering this language, we unlock the potential for unprecedented levels of vehicle maintenance, performance optimization, and technological advancement in the automotive and heavy equipment industries.

As we continue to push the boundaries of vehicle technology, the role of these diagnostic messages will only grow in importance. They are not just codes and data points; they are the key to understanding and improving the complex machines that drive our world forward.

September 6, 2025

WHAT IS PRINTED CIRCUIT BOARD? – Embedded Flakes

maximios ⋅ IT

This article shall serve as an introductory document for beginners. There are several good practices and rules to follow. There are hundreds of CAD software packages available in the market; open source, freeware, shareware, and expensive full version.

To understand manufacturing process of PCB, refer to this article.

Table of Contents

Printed Circuit Boards (PCBs) are the most common way of assembling modern electronic circuits. With the increasing use of modern electronics and increasingly growing complexity of electronic circuits, the design of the layout of printed circuit board is as demanding as the design of electronic circuits. Many companies set up their own dedicated printed circuit board design departments. This is not surprising, considering that it often takes a great deal of knowledge and talent to position hundreds of components and thousands of tracks into an intricate (artistic) design that meets a whole set of physical and electrical requirements. Proper printed circuit board design is very often an integral part of a design. In many designs (high speed digital, low-level analog and RF to name a few) the printed circuit board layout may make or break the operation and electrical performance of the design. It is also important to notice that printed circuit board traces have resistance, inductance, and capacitance, just like your circuit does.

There are industry standards for almost every aspect of PCB design. These standards are controlled by the former Institute for Interconnecting and Packaging Electronic Circuits, who is now known simply as the IPC (www.ipc.org). There is an IPC standard for every aspect of PCB design, manufacture, testing, and anything else that you could ever need. The major document that covers PCB design standards is IPC-2221, “Generic Standard on Printed Board Design”. This standard superseded the old IPC-D-275 standard (also Military Std 275) which has been used for the last half-century.

Printed circuit boards are mechanical structures that support components and provide electrical conduction paths between circuits. Simple PCB consists of a layer of a non-conductive substrate, which is coated with conductive copper laminate on both sides. This copper layer is etched away to leave desired copper traces, which provides conduction paths between circuit components.

A substrate is a base element of PCB, typically an insulator material. This is also known as laminate. Variety of materials is used as a substrate. It is important to have the right mechanical properties of PCB that suit your application. Substrates of different grades are available. These grades primarily describe flammability, high-temperature stability and moisture absorption of the board.

Grades Material
FR-1 Paper/phenolic: room temperature punchable, poor moisture resistance.
FR-2 Paper/phenolic: suitable for single-sided PCB consumer equipment, good moisture resistance.
FR-3 Paper/epoxy: designed for the balance of good mechanical and electrical characteristics.
FR-4 Glass cloth/epoxy: excellent mechanical and electrical properties.
FR-5 Glass cloth/epoxy: excellent mechanical and electrical properties.
G10 Glass cloth/epoxy: high insulation resistance, the highest bond strength of glass laminates, high humidity resistance.
G11 Glass cloth/epoxy: high flexural strength retention at high temperature, extreme resistance to solvents.

FR–4 is commonly used in industrial-quality equipment, while FR–2 is used in high-volume consumer applications. These two board materials appear to be industry standards. Deviating from these standards can limit the number of raw board material suppliers and PCB houses that can fabricate the board because their tooling is already set up for these materials. Nevertheless, there are applications in which one of the other grades may make sense. It may even be necessary to consider Teflon or even ceramic board substrate for very high-frequency applications. One thing can be counted on, however: the more exotic the board substrate, the more expensive it will be.

Several thickness options are available. Most commonly used thicknesses are 0.062” and 0.031”.

Moisture absorption of the material is one of the important aspects while selecting a board material. Just about every desirable performance characteristic of the board will be negatively impacted by moisture. This includes the surface resistance of the board, dielectric leakage, high-voltage breakdown and arcing, and mechanical stability. Also, pay attention to the operating temperature. High operating temperatures can occur in unexpected places, such as in proximity to large digital ICs that are switching at high speeds. The PCB and circuit characteristics may vary with the temperature.

PCB Core

A core is formed by the substrate and conducting layers of copper. Typically consists of two sheets of copper laminated over both sides of the substrate. There are two main methods used for copper lamination, rolling and electroplating. Many copper thickness options are also available. Thicknesses of conductors are specified in terms of its weights in ounces per square foot.

The term “weight” refers to the weight in ounces per square foot.

2oz      =    70 um        = 0.0024”1oz      =    35 um        = 0.0012”0.5oz   =    17.5 um     = 0.0006”

0.25oz =    8.75 um    = 0.0003”

For most applications, 1-ounce copper is sufficient. If the circuit consumes a lot of power, 2-ounce may be better.

September 6, 2025

ADC Mastery with 8051: Convert Your Way to Success – Embedded Flakes

maximios ⋅ IT

In the realm of microcontroller-based systems, mastering Analog-to-Digital Conversion (ADC) is a crucial skill that can elevate your projects to new heights. At the heart of this journey lies the venerable 8051 microcontroller, a powerhouse of versatility and reliability. We’re here to guide you through the intricacies of ADC implementation using the 8051, ensuring you’re well-equipped to tackle any conversion challenge that comes your way.

Table of Contents

Before we dive into the world of ADC, let’s briefly explore the 8051 microcontroller. This 8-bit marvel has stood the test of time, remaining a popular choice for embedded systems designers worldwide. Its robust architecture, extensive instruction set, and wide availability make it an ideal platform for learning and implementing ADC techniques.

  • 8-bit CPU with a variety of addressing modes
  • 64KB program memory address space
  • 64KB data memory address space
  • 4KB on-chip ROM (in some variants)
  • 128 bytes of on-chip RAM
  • 32 I/O pins organized as four 8-bit ports
  • Two 16-bit timer/counters
  • Full-duplex UART serial port
  • 5-source interrupt structure with two priority levels

These features provide a solid foundation for implementing ADC functionality, allowing us to interface with various analog sensors and create sophisticated data acquisition systems.

At its core, Analog-to-Digital Conversion is the process of transforming continuous analog signals into discrete digital values. This conversion is essential for microcontrollers like the 8051 to interpret and process real-world analog data, such as temperature, pressure, or light intensity.

  1. Sampling: The analog signal is sampled at regular intervals.
  2. Quantization: Each sample is assigned a discrete value from a finite set of levels.
  3. Encoding: The quantized value is converted into a binary code.

Understanding this process is crucial for implementing effective ADC solutions with the 8051 microcontroller.

While the 8051 doesn’t have a built-in ADC module, we can easily interface it with external ADC chips to achieve our conversion goals. Let’s explore a practical example using the popular ADC0804 chip.

The ADC0804 is an 8-bit ADC that works well with the 8051. Here’s a step-by-step guide to interfacing these two components:

  • Connect the ADC0804’s CS and RD pins to ground (always enabled).
  • Connect the WR pin to one of the 8051’s I/O pins (e.g., P3.2).
  • Connect the INTR pin to another I/O pin (e.g., P3.3).
  • Connect the 8-bit data bus (DB0-DB7) to Port 1 of the 8051.
#include 

sbit WR = P3^2;
sbit INTR = P3^3;

void initADC() {
    WR = 1;
    INTR = 1;
}

unsigned char readADC() {
    WR = 0;
    WR = 1;
    while(INTR == 1);
    return P1;
}

void main() {
    unsigned char adcValue;
    initADC();
    while(1) {
        adcValue = readADC();
        // Process adcValue as needed
    }
}

This code demonstrates the basic structure for reading ADC values using the 8051 and ADC0804. The initADC() function sets up the initial state, while readADC() triggers a conversion and returns the result.

As we progress in our ADC mastery, let’s explore some advanced techniques that can enhance our 8051-based projects.

Many applications require monitoring multiple analog inputs. We can achieve this by using a multiplexer in conjunction with our ADC setup. Here’s an example using the 74HC4051 8-channel analog multiplexer:

#include 

sbit WR = P3^2;
sbit INTR = P3^3;
sbit S0 = P3^4;
sbit S1 = P3^5;
sbit S2 = P3^6;

void selectChannel(unsigned char channel) {
    S0 = channel & 0x01;
    S1 = (channel >> 1) & 0x01;
    S2 = (channel >> 2) & 0x01;
}

unsigned char readADC(unsigned char channel) {
    selectChannel(channel);
    WR = 0;
    WR = 1;
    while(INTR == 1);
    return P1;
}

void main() {
    unsigned char adcValues[8];
    unsigned char i;

    while(1) {
        for(i = 0; i < 8; i++) {
            adcValues[i] = readADC(i);
        }
        // Process adcValues array as needed
    }
}

This setup allows us to read from 8 different analog inputs using a single ADC, greatly expanding our data acquisition capabilities.

While the ADC0804 provides 8-bit resolution, we can achieve higher effective resolution through oversampling. This technique involves taking multiple samples and averaging them to reduce noise and increase precision.

#include 

sbit WR = P3^2;
sbit INTR = P3^3;

#define OVERSAMPLING_FACTOR 16

unsigned int readADCOversampled() {
    unsigned int sum = 0;
    unsigned char i;

    for(i = 0; i < OVERSAMPLING_FACTOR; i++) {
        WR = 0;
        WR = 1;
        while(INTR == 1);
        sum += P1;
    }

    return sum / OVERSAMPLING_FACTOR;
}

void main() {
    unsigned int adcValue;
    while(1) {
        adcValue = readADCOversampled();
        // Process adcValue as needed
    }
}

This implementation takes 16 samples and averages them, effectively increasing our resolution by 2 bits (√16 = 4, which corresponds to 2 bits).

Let’s explore some practical applications where our ADC mastery with the 8051 can shine:

Create a temperature monitoring system using an LM35 temperature sensor and our 8051 ADC setup:

#include 

sbit WR = P3^2;
sbit INTR = P3^3;

float readTemperature() {
    unsigned char adcValue;
    float temperature;

    WR = 0;
    WR = 1;
    while(INTR == 1);
    adcValue = P1;

    temperature = (adcValue * 500.0) / 255.0; // LM35 gives 10mV per degree Celsius
    return temperature;
}

void main() {
    float currentTemp;
    while(1) {
        currentTemp = readTemperature();
        // Use currentTemp for display or control purposes
    }
}

This system can form the basis of a smart thermostat or industrial temperature control system.

Combine a photoresistor with our ADC setup to create an automated plant watering system:

#include 

sbit WR = P3^2;
sbit INTR = P3^3;
sbit PUMP = P3^7;

#define LIGHT_THRESHOLD 128 // Adjust based on your environment

void waterPlant() {
    PUMP = 1;
    // Add delay for watering duration
    PUMP = 0;
}

unsigned char readLightLevel() {
    WR = 0;
    WR = 1;
    while(INTR == 1);
    return P1;
}

void main() {
    unsigned char lightLevel;
    while(1) {
        lightLevel = readLightLevel();
        if(lightLevel > LIGHT_THRESHOLD) {
            waterPlant();
        }
        // Add delay to prevent overwatering
    }
}

This system demonstrates how ADC can be used in smart agriculture applications.

To squeeze the most out of our ADC implementations, consider these optimization techniques:

Instead of polling the INTR pin, use the 8051’s interrupt capabilities for more efficient ADC reading:

#include  sbit WR = P3^2;
volatile unsigned char adcValue; void initADC() { EA = 1; // Enable global interrupts
    EX0 = 1; // Enable external interrupt 0
    IT0 = 1; // Set interrupt 0 to trigger on falling edge
    WR = 1;
}

void startConversion() {
    WR = 0;
    WR = 1;
}

void interrupt_ADC() __interrupt(0) {
    adcValue = P1;
    // Process adcValue as needed
}

void main() {
    initADC();
    while(1) {
        startConversion();
        // Other tasks can be performed here while waiting for ADC
    }
}

This approach allows the 8051 to perform other tasks while waiting for the ADC conversion to complete.

Enhance the quality of your ADC readings by implementing digital filters:

#include 

#define FILTER_SIZE 8

sbit WR = P3^2;
sbit INTR = P3^3;

unsigned char readADC() {
    WR = 0;
    WR = 1;
    while(INTR == 1);
    return P1;
}

unsigned char movingAverageFilter() {
    static unsigned char readings[FILTER_SIZE];
    static unsigned char index = 0;
    unsigned int sum = 0;
    unsigned char i;

    readings[index] = readADC();
    index = (index + 1) % FILTER_SIZE;

    for(i = 0; i < FILTER_SIZE; i++) {
        sum += readings[i];
    }

    return sum / FILTER_SIZE;
}

void main() {
    unsigned char filteredValue;
    while(1) {
        filteredValue = movingAverageFilter();
        // Use filteredValue for smoother readings
    }
}

This moving average filter helps reduce noise and provides more stable ADC readings.

As we’ve journeyed through the world of ADC mastery with the 8051 microcontroller, we’ve uncovered a wealth of possibilities. From basic implementations to advanced techniques like multi-channel sampling and oversampling, the 8051 proves to be a capable platform for analog-to-digital conversion tasks.

By leveraging the power of ADC, we open doors to a myriad of applications – from environmental monitoring to industrial control systems. The practical examples and optimization techniques we’ve explored serve as a springboard for your own innovative projects.

Remember, the key to success lies in understanding the fundamentals, practicing with real-world applications, and continuously refining your approach. As you apply these concepts, you’ll find yourself well-equipped to tackle even the most challenging ADC scenarios.

Embrace the ADC revolution with your 8051 microcontroller, and watch as your projects transform from mere ideas into sophisticated, responsive systems that bridge the analog and digital worlds. The journey of ADC mastery is ongoing, and with each conversion, you’re one step closer to unlocking the full potential of your embedded systems.

September 6, 2025

The Ultimate 8051 Pin Configuration Guide: Never Get Lost Again – Embedded Flakes

maximios ⋅ IT

Welcome to our comprehensive guide on the 8051 microcontroller pin configuration. As seasoned experts in embedded systems and microcontroller architecture, we’re here to demystify the intricacies of the 8051’s pinout. Whether you’re a budding engineer or a seasoned professional, this guide will equip you with the knowledge to navigate the 8051’s pins with confidence and precision.

Table of Contents

The 8051 microcontroller, first introduced by Intel in 1981, has stood the test of time, remaining a popular choice for embedded systems due to its simplicity and versatility. Before diving into the pin configuration, let’s briefly review the 8051’s core architecture.

  • 8-bit CPU with a Harvard architecture
  • 4 KB of on-chip ROM (can vary in different variants)
  • 128 bytes of on-chip RAM
  • Four 8-bit ports for I/O operations
  • Two 16-bit timers
  • Full-duplex UART for serial communication
  • 64 KB each of external code and data memory

To truly understand the 8051’s capabilities, we must first familiarize ourselves with its pin diagram. The standard 8051 comes in a 40-pin DIP (Dual In-line Package) configuration. Let’s break down this diagram into logical sections for easier comprehension.

[Insert a detailed pin diagram of the 8051 here]

  • Pin 40 (VCC): This pin connects to the positive voltage supply, typically 5V.
  • Pin 20 (GND): The ground pin, connected to 0V.
  • Pin 31 (EA/VPP): External Access input, determines whether the microcontroller uses internal or external program memory.
  • Pin 18 (XTAL2): Output from the on-chip oscillator
  • Pin 19 (XTAL1): Input to the oscillator

The crystal oscillator, typically ranging from 11.0592 MHz to 24 MHz, connects across these pins to provide the system clock.

  • Pin 9 (RST): The reset input, active high. A logic 1 on this pin for two machine cycles resets the microcontroller.

The 8051 features four 8-bit I/O ports, each serving dual purposes:

  • Pins 32-39: Dual-purpose port, can be used for both input/output and as the multiplexed address/data bus for external memory.
  • Pins 1-8: General-purpose I/O port, also used for special functions in some variants.
  • Pins 21-28: Another dual-purpose port, used for I/O and the high address byte when accessing external memory.
  • Pins 10-17: Multifunctional port with the following alternate functions:
  • P3.0 (RXD): Serial input port
  • P3.1 (TXD): Serial output port
  • P3.2 (INT0): External interrupt 0
  • P3.3 (INT1): External interrupt 1
  • P3.4 (T0): Timer 0 external input
  • P3.5 (T1): Timer 1 external input
  • P3.6 (WR): External data memory write strobe
  • P3.7 (RD): External data memory read strobe
  • Pin 29 (PSEN): Program Store Enable, used when accessing external program memory.
  • Pin 30 (ALE): Address Latch Enable, used to demultiplex the address/data bus on Port 0.

Now that we’ve covered the pin layout, let’s explore how to configure and utilize these pins in your 8051 projects. We’ll provide code snippets and explanations for common tasks.

To use a port for input or output, you’ll need to configure it appropriately. Here’s an example of setting Port 1 for output:

MOV P1, #0FFH  ; Set all bits of Port 1 to 1 (input mode)
MOV P1, #00H   ; Set all bits of Port 1 to 0 (output mode)

The 8051’s ports are controlled through Special Function Registers. Here’s how you might configure Port 3 for its alternate functions:

MOV TMOD, #20H  ; Set Timer 1 in Mode 2 (8-bit auto-reload)
MOV TH1, #-3    ; Set baud rate to 9600 for 11.0592 MHz crystal
MOV SCON, #50H  ; Configure UART in Mode 1, enable receiver
SETB TR1        ; Start Timer 1

This code snippet configures the UART for serial communication using P3.0 (RXD) and P3.1 (TXD).

When using external memory, Port 0 and Port 2 are used to multiplex the address and data. Here’s a simplified example of how this works:

  1. The high byte of the address is output on Port 2.
  2. The low byte of the address is output on Port 0.
  3. The ALE signal is pulsed to latch the address.
  4. For a write operation, data is then output on Port 0. For a read operation, Port 0 is configured as input to receive data.

The 8051’s interrupt pins (INT0 and INT1) can be configured for either level-triggered or edge-triggered interrupts. Here’s how you might set up an external interrupt:

SETB IT0        ; Set INT0 to trigger on falling edge
SETB EX0        ; Enable external interrupt 0
SETB EA         ; Enable global interrupt system
  1. Always initialize ports: At the start of your program, explicitly set the direction and initial state of all ports you plan to use.
  2. Use pull-up resistors: When configuring pins as inputs, consider using internal or external pull-up resistors to ensure stable logic levels.
  3. Mind the current limits: Each I/O pin can typically source or sink up to 20mA. Be cautious when driving LEDs or other current-hungry devices directly from pins.
  4. Protect input pins: When connecting to external circuitry, use series resistors to protect input pins from overcurrent conditions.
  5. Decouple power supply: Always use appropriate decoupling capacitors near the VCC and GND pins to reduce noise and ensure stable operation.

Even with careful planning, you may encounter issues related to pin configuration. Here are some common problems and their solutions:

  1. Floating inputs: If input pins are left unconnected, they may float between logic levels, causing erratic behavior. Always tie unused inputs to a defined logic level.
  2. Port contention: Ensure that you’re not trying to use a pin for both its general I/O function and its alternate function simultaneously.
  3. Incorrect oscillator configuration: If your system clock isn’t behaving as expected, double-check your crystal connections and capacitor values.
  4. Reset issues: If the microcontroller isn’t resetting properly, verify the RC network connected to the RST pin.
  5. Memory access problems: When using external memory, ensure that the EA pin is correctly configured and that your address/data multiplexing is correct.

Mastering the 8051 pin configuration is crucial for designing efficient and reliable embedded systems. By understanding the role of each pin and how to properly configure them, you’ll be well-equipped to tackle a wide range of microcontroller projects.

Remember, the key to success with the 8051 lies in careful planning, proper initialization, and adherence to best practices. Whether you’re building a simple LED blinker or a complex control system, the principles we’ve covered in this guide will serve as your foundation for 8051 excellence.

As you continue your journey with the 8051, don’t hesitate to experiment with different pin configurations and explore the full potential of this versatile microcontroller. Happy coding!

September 6, 2025

Twenty 8051 Math Operations That Will Make You a Calculation Wizard – Embedded Flakes

maximios ⋅ IT

In the realm of microcontrollers, the 8051 family stands as a venerable titan, renowned for its versatility and enduring relevance. At the heart of its capabilities lie a set of powerful mathematical operations that, when mastered, can transform any programmer into a true calculation wizard. In this comprehensive guide, we’ll delve deep into 20 essential 8051 math operations that will elevate your coding prowess and optimize your microcontroller projects.

Table of Contents

Let’s begin with the cornerstone of all mathematical operations: addition. In 8051 assembly language, addition is straightforward yet powerful. Here’s a simple example:

MOV A, #10   ; Load 10 into the accumulator
ADD A, #20   ; Add 20 to the accumulator

This operation adds 20 to 10, resulting in 30 stored in the accumulator. It’s a fundamental building block for more complex calculations.

Subtraction in 8051 is equally important. Consider this code snippet:

MOV A, #50   ; Load 50 into the accumulator
SUBB A, #30  ; Subtract 30 from the accumulator

The SUBB instruction not only subtracts but also considers the borrow from previous operations, making it versatile for multi-byte subtractions.

The 8051 provides a dedicated MUL AB instruction for multiplication:

MOV A, #5    ; Load 5 into the accumulator
MOV B, #4    ; Load 4 into the B register
MUL AB       ; Multiply A and B

This operation multiplies 5 by 4, storing the result in the BA register pair.

Division is handled by the DIV AB instruction:

MOV A, #20   ; Load 20 into the accumulator
MOV B, #3    ; Load 3 into the B register
DIV AB       ; Divide A by B

After this operation, A contains the quotient (6), and B holds the remainder (2).

Incrementing values is a common operation in loops and counters:

MOV R0, #99  ; Load 99 into R0
INC R0       ; Increment R0

This simple yet powerful instruction adds 1 to the value in R0.

The counterpart to increment, decrement is equally important:

MOV R1, #100 ; Load 100 into R1
DEC R1       ; Decrement R1

This operation subtracts 1 from the value in R1.

BCD operations are crucial for applications involving decimal display:

MOV A, #25H  ; Load BCD 25 into A
ADD A, #37H  ; Add BCD 37
DA A         ; Decimal adjust for BCD result

The DA instruction ensures the result remains in valid BCD format.

Logical operations are fundamental in microcontroller programming:

MOV A, #0F5H ; Load 11110101 into A
ANL A, #0AAH ; AND with 10101010

This operation results in 10100000, demonstrating bitwise control.

The OR operation is used to set specific bits:

MOV A, #55H  ; Load 01010101 into A
ORL A, #0F0H ; OR with 11110000

The result is 11110101, showing how OR can be used to selectively set bits.

XOR is powerful for toggling bits and finding differences:

MOV A, #55H  ; Load 01010101 into A
XRL A, #0FFH ; XOR with 11111111

This operation inverts all bits in A, resulting in 10101010.

Rotation operations are useful for manipulating bit patterns:

MOV A, #0ABH ; Load 10101011 into A
RL A         ; Rotate left

After this operation, A contains 01010111, with the leftmost bit moved to the right.

Similarly, rotating right is equally important:

MOV A, #0ABH ; Load 10101011 into A
RR A         ; Rotate right

This results in 11010101, with the rightmost bit moved to the left.

For operations involving multiple bytes, rotating through carry is essential:

MOV A, #0ABH ; Load 10101011 into A
SETB C      ; Set carry flag
RLC A        ; Rotate left through carry

This operation considers the carry flag, allowing for multi-byte rotations.

The counterpart to RLC, RRC rotates right through carry:

MOV A, #0ABH ; Load 10101011 into A
CLR C       ; Clear carry flag
RRC A        ; Rotate right through carry

This instruction is crucial for multi-byte shift operations.

The SWAP instruction quickly exchanges the upper and lower nibbles of a byte:

MOV A, #0ABH ; Load 10101011 into A
SWAP A       ; Swap nibbles

After this operation, A contains 10111010, demonstrating rapid byte reorganization.

The CPL instruction complements (inverts) all bits in a register:

MOV A, #55H  ; Load 01010101 into A
CPL A        ; Complement A

This results in 10101010, showing how CPL can be used for bit manipulation.

While not a direct instruction, this operation is crucial for BCD subtraction:

MOV A, #50H  ; Load BCD 50 into A
SUBB A, #25H ; Subtract BCD 25
MOV R1, A    ; Save result temporarily
MOV A, #00H  ; Clear A
SUBB A, #00H ; Subtract 0 with borrow
CPL A        ; Complement A
ADD A, R1    ; Add to previous result
DA A         ; Decimal adjust

This sequence ensures correct BCD subtraction results.

While not a single instruction, this operation is vital for digital signal processing:

MOV A, #5    ; Load 5 into A
MOV B, #4    ; Load 4 into B
MUL AB       ; Multiply A and B
ADD A, R2    ; Add result to R2
MOV R2, A    ; Store back in R2

This sequence multiplies two numbers and adds the result to an accumulator, essential for complex mathematical operations.

Although the 8051 doesn’t have a direct square root instruction, we can approximate it:

MOV R0, #0   ; Initialize result
MOV R1, #81  ; Number to find square root of
MOV R2, #1   ; Initial odd number

LOOP:
MOV A, R1
SUBB A, R2
JC DONE
MOV R1, A
INC R0
INC R2
INC R2
SJMP LOOP

DONE:
; R0 now contains the integer square root

This algorithm approximates the square root using successive subtractions.

For our final operation, let’s tackle exponential calculation:

MOV R0, #2   ; Base
MOV R1, #5   ; Exponent
MOV R2, #1   ; Result

LOOP:
MOV A, R2
MOV B, R0
MUL AB
MOV R2, A
DJNZ R1, LOOP

This code calculates 2^5, demonstrating how complex operations can be built from simpler instructions.

By mastering these 20 8051 math operations, we’ve unlocked a world of computational power within this classic microcontroller. From basic arithmetic to complex algorithms, the 8051 proves its versatility and enduring relevance in the realm of embedded systems.

Remember, the true power of these operations lies not just in their individual capabilities, but in how we combine them to solve real-world problems. As you integrate these techniques into your projects, you’ll find yourself approaching challenges with newfound confidence and creativity.

Whether you’re optimizing code for speed, implementing complex control systems, or pushing the boundaries of what’s possible with limited resources, these math operations form the foundation of your 8051 programming toolkit. Practice them, experiment with them, and watch as your microcontroller projects reach new heights of efficiency and sophistication.

As we continue to explore the depths of 8051 programming, let these mathematical building blocks be your guide. With each line of code, you’re not just calculating – you’re crafting, innovating, and truly becoming a calculation wizard in the world of embedded systems.

September 6, 2025

8051 vs. PIC: The Microcontroller Battle of the Century – Embedded Flakes

maximios ⋅ IT

In the world of embedded systems and microcontrollers, two titans have long stood at the forefront: the venerable 8051 and the versatile PIC (Peripheral Interface Controller). These microcontroller families have shaped the landscape of embedded design for decades, each bringing its unique strengths to the table. In this comprehensive analysis, we’ll dive deep into the intricacies of both architectures, exploring their histories, capabilities, and real-world applications to determine which might reign supreme in various scenarios.

Table of Contents

The 8051 microcontroller, first introduced by Intel in 1980, has become one of the most popular microcontrollers of all time. Its 8-bit architecture and robust design have stood the test of time, with numerous manufacturers continuing to produce variants with enhanced features.

Key milestones in 8051 evolution:

  • 1980: Original 8051 introduced by Intel
  • 1990s: Third-party manufacturers begin producing enhanced 8051 variants
  • 2000s: Introduction of high-speed 8051 cores and advanced peripherals

Microchip Technology’s PIC microcontrollers entered the scene in the mid-1970s, originally designed as a peripheral controller for the CP1600 CPU. The PIC architecture has since evolved into a diverse family of microcontrollers, ranging from 8-bit to 32-bit designs.

PIC evolution highlights:

  • 1975: First PIC device developed
  • 1985: General availability of PIC devices
  • Late 1990s: Introduction of PIC16 and PIC18 series
  • 2000s: Launch of 16-bit and 32-bit PIC microcontrollers

8051 Memory Structure:

  • Harvard architecture
  • Separate program and data memory
  • 64KB program memory
  • 256 bytes of internal RAM

PIC Memory Structure:

  • Modified Harvard architecture
  • Separate program and data memory
  • Program memory size varies by model (up to several MB in high-end devices)
  • Data memory size varies (from a few bytes to several KB)

8051 Instruction Set:

  • CISC (Complex Instruction Set Computing)
  • 255 instructions
  • Variable instruction length (1 to 3 bytes)

PIC Instruction Set:

  • RISC (Reduced Instruction Set Computing)
  • Fewer instructions (35 for PIC16, 75 for PIC18)
  • Fixed instruction length (typically 14 bits for PIC16, 16 bits for PIC18)

The 8051 and PIC families offer a wide range of clock speeds, depending on the specific model and manufacturer. However, we can make some general comparisons:

8051 Performance:

  • Traditional 8051 cores: 1-33 MHz
  • Enhanced 8051 cores: Up to 100 MHz or more

PIC Performance:

  • Low-end PICs: 4-20 MHz
  • High-performance PICs: Up to 200 MHz or more

It’s important to note that clock speed alone doesn’t tell the whole story. The RISC architecture of PICs often allows them to execute instructions more efficiently, potentially offering better performance at lower clock speeds.

8051 microcontrollers are typically programmed in C or Assembly. The robust ecosystem around the 8051 has led to the development of numerous IDEs and toolchains.

Sample 8051 C code for blinking an LED:

#include 
#include 

void delay(unsigned int count)
{
    unsigned int i;
    for(i=0;i
September 6, 2025

The Dark Art of 8051 Self-Programming: Code That Writes Itself – Embedded Flakes

maximios ⋅ IT

In the realm of embedded systems, the 8051 microcontroller family has long been a stalwart workhorse. Its simplicity and versatility have made it a favorite among engineers for decades. However, there’s a lesser-known capability lurking within this venerable chip that pushes the boundaries of what’s possible in the world of microcontrollers: self-programming.

We’re about to embark on a journey into the fascinating world of code that can modify itself. This isn’t just an academic exercise; it’s a powerful technique that can lead to more flexible, adaptable, and efficient embedded systems. Let’s dive deep into the dark art of 8051 self-programming and uncover the secrets of code that truly writes itself.

Table of Contents

Before we delve into the intricacies of self-programming, it’s crucial to understand the basic architecture of the 8051 microcontroller. At its core, the 8051 uses a Harvard architecture, which means it has separate memory spaces for program and data. This separation is key to understanding how self-programming works.

The 8051’s program memory is typically implemented as flash memory, which can be electrically erased and reprogrammed. This is the canvas on which our self-modifying code will work its magic. The data memory, on the other hand, is volatile RAM used for temporary storage during program execution.

To perform self-programming, we need to bridge these two worlds. We’ll use special instructions and techniques to read from and write to the program memory space, effectively allowing our code to rewrite itself.

To embark on our self-programming adventure, we’ll need a few essential tools in our arsenal:

  1. MOVC instruction: This allows us to read from program memory.
  2. MOVX instruction: This lets us write to external memory, which we’ll use as an intermediary step.
  3. IAP (In-Application Programming) routines: These are built-in functions provided by many 8051 variants for erasing and writing to flash memory.

With these tools at our disposal, we’re ready to start exploring the dark art of self-programming.

Let’s break down the self-programming process into manageable steps:

  1. Read the existing code: Use MOVC to read the current contents of program memory.
  2. Modify the code: Perform the desired modifications in RAM.
  3. Erase the target flash sector: Use IAP routines to erase the section of flash we want to update.
  4. Write the new code: Use IAP routines to write the modified code back to flash.

Now, let’s look at each of these steps in more detail, complete with code snippets and circuit diagrams where appropriate.

To read from program memory, we’ll use the MOVC instruction. Here’s a simple function that reads a byte from a specified address in program memory:

READ_PROG_MEM:
    MOV DPTR, #TARGET_ADDRESS  ; Set DPTR to the address we want to read
    CLR A                      ; Clear the accumulator
    MOVC A, @A+DPTR            ; Read byte from program memory into A
    RET                        ; Return with the byte in A

This function sets up the DPTR (data pointer) with our target address, then uses MOVC to read the byte at that address into the accumulator (A).

Once we’ve read the existing code, we need to modify it. This step is highly dependent on what changes we want to make. For simplicity, let’s say we want to increment every byte in a certain range. We’ll do this in RAM:

void modify_code(uint8_t *buffer, uint16_t length) {
    for (uint16_t i = 0; i < length; i++) {
        buffer[i]++;  // Increment each byte
    }
}

This C function takes a buffer (which we’ve previously filled with data read from program memory) and increments each byte.

Before we can write our modified code back to flash, we need to erase the target sector. This is where we’ll use the IAP routines. The exact implementation varies depending on the specific 8051 variant, but here’s a general pseudo-code outline:

void erase_flash_sector(uint16_t sector_address) {
    disable_interrupts();
    setup_iap_command(ERASE_SECTOR);
    set_iap_address(sector_address);
    trigger_iap();
    wait_for_iap_complete();
    enable_interrupts();
}

This function disables interrupts (crucial for flash operations), sets up the IAP command for sector erase, specifies the address, triggers the operation, and waits for completion.

Finally, we’re ready to write our modified code back to flash. Again, we’ll use IAP routines:

void write_flash(uint16_t address, uint8_t *data, uint16_t length) {
    disable_interrupts();
    for (uint16_t i = 0; i < length; i++) {
        setup_iap_command(WRITE_BYTE);
        set_iap_address(address + i);
        set_iap_data(data[i]);
        trigger_iap();
        wait_for_iap_complete();
    }
    enable_interrupts();
}

This function writes the modified code byte by byte to the specified flash address.

Now that we’ve covered the individual steps, let’s look at a complete example of a self-modifying function. This function will read its own code, modify it, and write the changes back to flash:

void self_modifying_function(void) {
    uint8_t buffer[256];
    uint16_t start_address = (uint16_t)&self_modifying_function;

    // Step 1: Read our own code
    for (uint16_t i = 0; i < sizeof(buffer); i++) {
        buffer[i] = read_prog_mem(start_address + i);
    }

    // Step 2: Modify the code (increment each byte)
    modify_code(buffer, sizeof(buffer));

    // Step 3: Erase our own flash sector
    erase_flash_sector(start_address);

    // Step 4: Write the modified code back to flash
    write_flash(start_address, buffer, sizeof(buffer));

    // The next time this function is called, it will be different!
}

This function demonstrates the complete self-modification cycle. It reads its own code, modifies it, erases its flash sector, and writes the modified version back. The next time this function is called, it will behave differently!

When working with self-programming techniques, it’s crucial to consider the hardware implications. Here’s a simplified circuit diagram showing the key connections for an 8051 microcontroller set up for self-programming:

        +---------------------+
        |                     |
        |    8051             |
        |    Microcontroller  |
        |                     |
+-------|RESET               |
|       |                    |
|  +----| P3.6 (WR#)         |
|  |  +-| P3.7 (RD#)         |
|  |  | |                    |
|  |  | |                    |
|  |  | |                    |
|  |  | |   Flash Memory     |
|  |  | |    +----------+    |
|  |  | +----|WE#       |    |
|  |  +------|OE#       |    |
|  +----------|CE#       |    |
|             |          |    |
|             +----------+    |
|                             |
+-----------------------------+

In this diagram:

  • The RESET line is crucial for initializing the microcontroller and potentially triggering bootloader mode for initial programming.
  • P3.6 (WR#) and P3.7 (RD#) are connected to the Write Enable (WE#) and Output Enable (OE#) pins of the flash memory, respectively.
  • The Chip Enable (CE#) of the flash is also controlled by the microcontroller.

This setup allows the microcontroller to directly control the read and write operations to the flash memory, which is essential for self-programming.

While we’ve covered the basics of 8051 self-programming, there are several advanced techniques and considerations to keep in mind:

A common application of self-programming is in bootloader design. A bootloader is a small program that runs at startup and can update the main application code. This allows for firmware updates without needing specialized programming hardware.

Here’s a simplified bootloader flow:

  1. Check for update flag or signal (e.g., a specific pin state or data in EEPROM)
  2. If update needed, enter programming mode:
  • Receive new firmware data (e.g., via UART)
  • Erase existing application code
  • Write new firmware to flash
  1. If no update needed (or after update), jump to main application code

Sometimes, we need to execute code from RAM instead of flash. This can be useful when modifying the flash sector that contains the currently executing code. Here’s a technique for relocating code to RAM:

// Function to copy code to RAM
void copy_to_ram(uint8_t *dest, uint8_t *src, uint16_t len) {
    for (uint16_t i = 0; i < len; i++) {
        dest[i] = src[i];
    }
}

// Function to execute in RAM
void __ram_func ram_function(void) {
    // Function body
}

// Usage
uint8_t ram_buffer[256];
copy_to_ram(ram_buffer, (uint8_t*)ram_function, sizeof(ram_buffer));
((void (*)())ram_buffer)();  // Execute the function from RAM

This technique copies the function to RAM and then executes it from there, allowing us to safely modify the flash sector containing the original function.

When working with self-modifying code, robust error handling is crucial. A failed write or unexpected power loss could leave the system in an unbootable state. Here are some strategies to mitigate this risk:

  1. Checksum verification: Always verify the integrity of the newly written code before executing it.
  2. Dual-bank approach: Maintain two copies of the firmware, only updating one at a time. If an update fails, the system can fall back to the other copy.
  3. Watchdog timers: Use watchdog timers to detect if the system hangs during the update process and trigger a reset.

Here’s a simple checksum function that can be used for verification:

uint16_t calculate_checksum(uint8_t *data, uint16_t len) {
    uint16_t sum = 0;
    for (uint16_t i = 0; i < len; i++) {
        sum += data[i];
    }
    return sum;
}

While self-programming offers powerful capabilities, it also opens up potential security vulnerabilities. An attacker who gains control of a self-programming system could potentially inject malicious code. Here are some security considerations:

  1. Code signing: Implement a digital signature system to verify the authenticity of any code before it’s written to flash.
  2. Secure boot: Use a hardware-backed secure boot process to ensure only trusted code is executed at startup.
  3. Memory protection: Utilize memory protection units (MPUs) if available to restrict write access to critical memory regions.

We’ve journeyed deep into the dark art of 8051 self-programming, uncovering the techniques that allow code to write itself. From the basic principles to advanced considerations, we’ve explored the power and complexity of this fascinating capability.

Self-programming opens up a world of possibilities: dynamic firmware updates, adaptive algorithms, and resilient systems that can repair themselves. However, with great power comes great responsibility. The ability to modify running code demands careful design, robust error handling, and a keen awareness of security implications.

As we push the boundaries of what’s possible with embedded systems, techniques like self-programming will play an increasingly important role. By mastering these skills, we equip ourselves to create the next generation of intelligent, adaptable, and resilient embedded systems.

The 8051, despite its age, continues to surprise us with its capabilities. Who knows what other secrets this venerable microcontroller family might still be hiding? The journey of discovery in embedded systems never truly ends – it simply opens new doors to explore.

September 6, 2025

Elevating Embedded Systems with Agile Mastery – Embedded Flakes

maximios ⋅ IT

In the rapidly evolving world of technology, embedded systems have become the backbone of countless products and services, from household gadgets to complex industrial machinery. However, managing projects in the realm of embedded systems can present unique challenges, particularly when it comes to the intricate hardware-software interactions, real-time constraints, and the need for precision and reliability.

This is where Agile methodologies come into play, offering a flexible and efficient approach to managing these complex projects. Agile is characterized by a set of values and principles that prioritize flexibility, collaboration, and customer feedback, allowing teams to adapt to changing requirements and deliver high-quality results.

Table of Contents

At the heart of the Agile methodology lies the Agile Manifesto, a seminal document that outlines the core values and principles that define the Agile approach to software development. Established in 2001 by a group of software development experts, the Agile Manifesto has since become a guiding light for organizations across various industries, transcending its origins in the tech sector.

The Agile Manifesto articulates four core values that form the foundation of the Agile methodology:

  1. Individuals and Interactions over processes and tools
  2. Working Software over comprehensive documentation
  3. Customer Collaboration over contract negotiation
  4. Responding to Change over following a plan

These values emphasize the importance of prioritizing people, working solutions, customer engagement, and adaptability over rigid processes, extensive documentation, formal contracts, and static plans. This shift in mindset is crucial in today’s fast-paced, ever-changing business environment.

Complementing the core values, the Agile Manifesto outlines twelve guiding principles that further define the Agile approach:

  1. Customer Satisfaction: Agile emphasizes delivering valuable software to customers early and continuously, ensuring their needs are met.
  2. Embrace Change: Agile recognizes that requirements can change, and embraces flexibility to respond to evolving customer needs.
  3. Frequent Delivery: Agile promotes delivering working software frequently, from a couple of weeks to a couple of months, with a preference for the shorter timescale.
  4. Collaboration: Agile values close collaboration between business stakeholders and developers throughout the project.
  5. Trust and Empower: Agile teams are self-organizing and cross-functional, with team members trusted to get the job done.
  6. Face-to-Face Communication: Agile emphasizes the importance of in-person communication and collaboration over written documentation.
  7. Working Software: Agile measures progress primarily by the delivery of working software, rather than comprehensive documentation.
  8. Sustainable Pace: Agile discourages overtime and “crunch time”, advocating for a constant, maintainable pace of development.
  9. Technical Excellence: Agile promotes technical excellence and good design to enhance agility.
  10. Simplicity: Agile seeks to maximize the amount of work not done, focusing on essential features and minimizing waste.
  11. Self-Reflection: Agile teams regularly reflect on how to become more effective, then tune and adjust their behavior accordingly.
  12. Continuous Improvement: Agile encourages teams to continuously improve their processes and practices, fostering a culture of learning and growth.

Adopting Agile methodologies in embedded systems project management offers several tangible benefits:

  1. Improved Time-to-Market: Agile’s iterative approach, as seen in Scrum’s sprint cycles, accelerates development cycles, enabling faster delivery of functional products, which is crucial in the fast-paced embedded systems market.
  2. Enhanced Product Quality: Frequent testing and integration, as emphasized in Agile practices, help ensure robust and reliable embedded systems, meeting the stringent safety and reliability standards required in sectors like automotive and healthcare.
  3. Increased Stakeholder Satisfaction: By involving stakeholders throughout the development process, as in Scrum’s sprint reviews, Agile ensures that the final embedded system product meets or exceeds expectations, leading to higher customer satisfaction.
  4. Greater Team Morale and Productivity: Agile empowers teams to take ownership of their work, fostering a sense of accomplishment and motivation, which is particularly important in the complex and challenging field of embedded systems development.

While Agile has its roots in software development, its principles and practices can be tailored to suit the unique demands of embedded systems projects. Here’s how:

  1. Iterative Development and Prototyping: Agile’s iterative approach, exemplified by Scrum’s sprint cycles, allows teams to develop prototypes and test components incrementally, which is particularly beneficial in embedded systems where hardware and software integration can be complex.
  2. Cross-Functional Teams: Agile methodologies, like Scrum, encourage the formation of cross-functional teams, bringing together hardware and software engineers, testers, and other stakeholders. This collaborative environment fosters better communication and problem-solving, crucial for addressing the challenges of embedded systems development.
  3. Continuous Integration and Testing: By continuously integrating software with hardware components and conducting regular testing, teams can identify and resolve issues early in the development cycle, reducing risks and improving quality. This is particularly important in embedded systems, where real-time constraints and safety requirements are paramount.
  4. Adaptation and Flexibility: Agile methodologies, such as Kanban, allow teams to adapt to new requirements or changes in project scope quickly, which is crucial in the fast-paced world of technology, where embedded systems are constantly evolving.
  5. Customer Collaboration: Regular feedback from stakeholders and end-users ensures that the project remains aligned with customer needs and expectations, a crucial aspect of embedded systems development where the end-user experience is often paramount.

To effectively implement Agile in the embedded systems domain, teams must address the unique challenges, such as hardware dependencies, real-time constraints, and safety and reliability requirements. [1]

One key approach is to focus on Agile practices that emphasize incremental development, continuous integration, and close collaboration between hardware and software teams. This could involve techniques like:

  • Scrum
  • Kanban
  • Scrumban
  • Extreme Programming (XP)
  • DevSecOps

Scrum is a widely adopted Agile framework that emphasizes iterative and incremental development, cross-functional teamwork, and a focus on delivering working software. At its core, Scrum is designed to help teams address complex problems and adapt to changing requirements in a flexible and efficient manner.

The key elements of the Scrum methodology include:

  1. The Scrum Team: Scrum teams are self-organizing and cross-functional, typically consisting of a Product Owner, Scrum Master, and Development Team.
  2. Product Backlog: The Product Backlog is a prioritized list of features, requirements, and tasks that the team works on, with the highest-priority items at the top.
  3. Sprint: Scrum projects are divided into time-boxed iterations called Sprints, typically lasting 2-4 weeks. During each Sprint, the team works to deliver a potentially shippable increment of the product.
  4. Sprint Planning: At the start of each Sprint, the team plans which Product Backlog items they will work on and how they will accomplish the work.
  5. Daily Scrum: The team holds a 15-minute daily meeting to synchronize their work, identify any impediments, and plan the day’s activities.
  6. Sprint Review: At the end of each Sprint, the team demonstrates the completed work to stakeholders and seeks feedback.
  7. Sprint Retrospective: The team reflects on the past Sprint, identifies areas for improvement, and plans process changes for the next Sprint.

Kanban is an Agile project management methodology that focuses on visualizing the workflow, limiting work in progress, and maximizing efficiency. Here’s a detailed summary of the Kanban framework:

  1. Visualize the Workflow: Kanban emphasizes creating a visual representation of the work, typically using a Kanban board. This board consists of columns that represent the different stages of the workflow, such as “To Do,” “In Progress,” and “Done.”
  2. Limit Work in Progress (WIP): Kanban places a strict limit on the number of tasks that can be in progress at any given time. This helps to avoid overloading the team and ensures that work is completed in a timely manner.
  3. Manage Flow: Kanban focuses on optimizing the flow of work through the system, ensuring that tasks move smoothly from one stage to the next without bottlenecks or delays.
  4. Make Policies Explicit: Kanban requires that the team’s policies, such as the definition of “done” for a task or the criteria for moving work between columns, are clearly defined and communicated.
  5. Implement Feedback Loops: Kanban encourages regular retrospectives and other feedback mechanisms to identify areas for improvement and continuously optimize the workflow.

Scrumban is a hybrid Agile methodology that combines the core elements of Scrum and Kanban, making it a powerful approach for managing the unique challenges of embedded systems development.

Scrumban takes the best practices from both Scrum and Kanban, creating a flexible and adaptive framework that is well-suited for projects with complex hardware-software integration and resource constraints.

Scrumban retains the key Scrum elements, and integrates Kanban’s workflow-based approach, such as:

  1. Time-Boxed Sprints: Short, iterative development cycles that allow for rapid prototyping and testing.
  2. Cross-Functional Teams: Bringing together hardware engineers, software developers, and other stakeholders to foster collaboration.
  3. Product Backlog: A prioritized list of features and requirements to be delivered.
  4. Daily Standups: Brief daily meetings to discuss progress, blockers, and plan the day’s work.
  5. Sprint Review and Retrospective: Opportunities to gather customer feedback and continuously improve the team’s processes.
  6. Continuous Delivery: Emphasis on delivering small, incremental changes to the product regularly.
  7. Visualization of Work: Using a Kanban board to track the status of tasks and identify bottlenecks.
  8. Work-in-Progress (WIP) Limits: Establishing limits on the number of tasks that can be in progress at any given time.
  9. Pull-Based System: Team members “pull” work from the backlog as they have capacity, rather than having work “pushed” to them.

Extreme Programming (XP) is an Agile software development methodology that emphasizes a set of values, principles, and practices aimed at improving software quality and responsiveness to changing customer requirements. XP was initially introduced in the late 1990s by Kent Beck, and it has since become one of the most well-known and widely adopted Agile approaches.

  1. The Simplicity Principle: XP encourages teams to implement the simplest solution that meets the current requirements, avoiding unnecessary complexity.
  2. The Communication Principle: XP emphasizes frequent and effective communication among team members, as well as with the customer, to ensure a shared understanding of the project’s goals and requirements.
  3. The Feedback Principle: XP promotes rapid and continuous feedback loops, where the development team receives regular feedback from the customer and the customer receives working software frequently.
  4. The Courage Principle: XP requires team members to have the courage to make changes, refactor code, and address technical debt, even if it means challenging existing practices or assumptions.
  5. The Respect Principle: XP fosters an environment of mutual respect, where team members value each other’s contributions and work collaboratively to achieve the project’s goals.
  1. Pair Programming: XP encourages developers to work in pairs, where two developers collaborate on the same code, providing real-time feedback and improving code quality.
  2. Test-Driven Development (TDD): XP emphasizes writing automated tests before writing the actual code, ensuring that the code meets the specified requirements and reducing the risk of introducing bugs.
  3. Continuous Integration: XP teams integrate their work frequently, often multiple times a day, to detect and address integration issues early in the development process.
  4. Refactoring: XP encourages teams to continuously refactor their codebase to improve its structure, maintainability, and flexibility, without changing its external behavior.
  5. Collective Code Ownership: In XP, the entire team is responsible for the codebase, and anyone can make changes to any part of the code, promoting shared ownership and accountability.
  6. On-Site Customer: XP requires the customer to be actively involved in the development process, providing constant feedback and clarification on requirements.
  7. Sustainable Pace: XP advocates for a sustainable pace of development, discouraging long work hours and promoting a healthy work-life balance for the team.

DevSecOps is an Agile approach that integrates security practices and considerations into the software development lifecycle. It builds upon the principles of DevOps, which emphasizes the collaboration between development and operations teams, and extends it by making security a shared responsibility across the entire organization.

The key goal of DevSecOps is to shift security “left” – that is, to introduce security activities earlier in the development process, rather than treating it as a separate, siloed concern at the end of the lifecycle. This allows security issues to be identified and addressed proactively, reducing risk and improving the overall quality and resilience of the final product.

  1. Security as Code: DevSecOps treats security as an integral part of the application code, with security controls and policies defined and managed as infrastructure-as-code.
  2. Continuous Security: Security testing, monitoring, and remediation are performed continuously throughout the development lifecycle, rather than as a one-time, end-of-cycle activity.
  3. Shared Responsibility: Everyone involved in the software development process, from developers to operations to security teams, shares the responsibility for security.
  4. Automation: DevSecOps heavily relies on automated security tools and processes to ensure consistency, scalability, and speed.
  5. Collaboration and Communication: DevSecOps fosters a culture of open communication and collaboration between development, operations, and security teams.

A: Yes, Agile can be effectively adapted to embedded systems development by focusing on practices like iterative prototyping, continuous integration, and cross-functional collaboration. The key is to tailor Agile principles, such as those found in Scrum and Kanban, to address the unique challenges of hardware-software integration.

A: Agile practices like frequent testing, continuous integration, and close stakeholder collaboration can help embedded systems teams address safety and reliability requirements. Techniques like DevSecOps and Extreme Programming can also be integrated to further strengthen these aspects.

A: Some key factors include the project’s complexity, the team’s experience with Agile, the level of hardware-software integration, and the need for real-time performance and safety. Methodologies like Scrumban, which combines Scrum and Kanban, XP, and DevSecOps may be particularly well-suited, depending on the project’s unique requirements.

A: Scrum’s iterative sprint cycles, cross-functional teams, and focus on continuous integration can be particularly valuable for embedded systems projects. However, teams may need to adapt Scrum practices to better manage hardware-software dependencies, real-time constraints, and safety requirements. This could involve incorporating Kanban techniques, such as visual task boards and continuous workflow, to create a “Scrumban” hybrid approach.

A: Kanban’s emphasis on continuous workflow, visual task management, and just-in-time delivery can help embedded systems teams address challenges like hardware dependencies and resource constraints. Kanban’s flexibility allows teams to quickly adapt to changing requirements, a crucial capability in the fast-paced world of embedded systems. When combined with Scrum’s iterative practices, the resulting Scrumban approach can provide a powerful Agile framework for embedded systems development.

A: XP practices like pair programming, test-driven development, and continuous feedback can help embedded systems teams address the unique challenges of hardware-software integration and real-time performance. By fostering close collaboration and enabling rapid feedback loops, XP can complement the Agile principles of flexibility and customer-centricity that are essential for successful embedded systems projects.

The Agile values and principles outlined in the Agile Manifesto provide a powerful framework for teams and organizations to navigate the complexities of today’s business landscape. By embracing these fundamental tenets, teams can unlock the true potential of Agile, delivering innovative products, adapting to change, and ultimately achieving greater success. As the world continues to evolve at a rapid pace, the Agile approach remains a proven and invaluable tool for organizations seeking to stay ahead of the curve.

Incorporating Agile methodologies into embedded systems project management can transform the way teams handle the complexities of hardware-software integration, real-time processing, and resource constraints. By fostering collaboration, adaptability, and continuous improvement, Agile enables teams to deliver innovative and high-quality embedded systems that meet the growing demands of today’s technology landscape. As the world continues to rely on embedded systems for smarter solutions, Agile provides a proven framework for managing these projects effectively and efficiently.

Agile Manifesto

The Twelve Principles of Agile Software

September 6, 2025

How Scrum Roles Adapt for Embedded Systems Development? – Embedded Flakes

maximios ⋅ IT

Over the last two decades, I’ve worked on embedded systems projects ranging from automotive ECUs and industrial automation controllers to IoT devices and medical instruments. One pattern I’ve seen repeatedly is this: teams love the idea of agility, but they struggle when trying to apply pure Scrum in environments where hardware, firmware, and software all have to come together seamlessly.

The reality is that embedded systems development isn’t just “software with extra steps.” We deal with long hardware lead times, lab availability issues, simulation immaturity, and certifications that don’t care about your sprint cadence. Still, Scrum can bring enormous value if you adapt the roles and responsibilities to fit this unique world.

This article isn’t theory—it’s drawn from real project trenches. Let’s explore how Scrum roles evolve in embedded systems, what additional responsibilities are needed, and what practices make the difference between just doing Scrum and actually delivering working embedded products on time.

Table of Contents

The Product Owner role is where I’ve seen the biggest shift in embedded projects. In a typical software setup, the PO focuses on backlog priorities, roadmap, and vision. In embedded, the PO has to juggle two worlds—hardware and software—without letting either side dominate.

In one automotive controller project I worked on, the PO had to make tough calls: should we delay a critical feature because a chipset was on backorder, or should we redesign the feature set to fit available components? These aren’t decisions you’ll find in a Scrum textbook—but they’re daily reality in embedded development.

  • Vision & Roadmap
    • Define a roadmap that respects both hardware lifecycles and software iteration speed.
    • Understand that once hardware is frozen, you can’t “patch it” like software.
  • Unified Backlog Management
    • Keep one backlog that covers both hardware and software work.
    • Factor in hardware lead times, vendor dependencies, and certification tasks.
  • Integration Alignment
    • Constantly sync with architects and hardware engineers.
    • Validate hardware-software compatibility early—catching issues late is extremely costly.
  • Stakeholder Balance
    • Manage expectations across marketing, engineering, compliance, and suppliers.
    • I’ve often seen marketing push features that simply didn’t fit hardware limits—POs need the courage to say “not feasible.”
  • Risk Awareness
    • Watch out for component obsolescence (biggest headache in long projects).
    • Monitor certification timelines—delays here can kill market entry.
  • Quality & Acceptance
    • Define acceptance criteria that cover performance, safety, and compliance, not just functionality.

In my experience, a strong PO is the glue holding all disciplines together. Weak backlog management or poor stakeholder alignment at this role often means months of rework later.

I’ve often joked that the Scrum Master in embedded projects needs the patience of a coach and the resourcefulness of a firefighter. Things go wrong—prototypes arrive late, test equipment is overbooked, vendors slip timelines—and it’s usually the SM helping the team adapt without losing momentum.

In one IoT project, the prototype boards were delayed by 6 weeks. Instead of throwing up their hands, the SM worked with the team to set up simulation-based testing so firmware development didn’t stall. That’s what makes embedded SMs different—they need to be resourceful problem-solvers, not just ceremony facilitators.

  • Agile Coaching with Context
    • Adapt daily standups to include hardware/validation status.
    • Teach teams to balance agility with necessary documentation (compliance won’t accept sticky notes as evidence).
  • Sprint Facilitation
    • Align planning with hardware delivery schedules and lab availability.
    • Ensure sprint goals are realistic given external dependencies.
  • Impediment Removal
    • Resolve blockers like missing lab setups, unavailable boards, or broken toolchains.
    • Coordinate with suppliers or test teams when dependencies stall progress.
  • Dependency & Risk Tracking
    • Keep an eye on external dependencies (suppliers, cert labs, manufacturing).
    • Facilitate mitigation strategies before risks hit hard.
  • Continuous Improvement
    • Lead retrospectives with focus on integration efficiency and cross-team collaboration.

A good SM in embedded is less about “following Scrum by the book” and more about helping the team stay productive in the face of hardware realities.

Embedded Scrum teams are naturally cross-functional. Unlike pure software teams, you almost always need specialists across:

  • Firmware engineers (bootloaders, drivers, middleware)
  • Software engineers (application logic, protocols, UI)
  • Hardware engineers (schematics, PCB, FPGA, verification)
  • Test engineers (system-level, HIL, compliance, performance)
  • Quality engineers (standards, documentation, root cause analysis)

Their challenge? Deliver integrated increments at the end of each sprint. That might mean a running firmware demo on a prototype board, a hardware-software co-simulation, or a partial prototype validated in the lab.

In practice, the best embedded Scrum teams I’ve worked with are those where firmware, hardware, and test engineers sit together (or at least collaborate daily). Silos kill agility.

The Development Team in embedded systems projects requires a diverse mix of specialists who collaborate to deliver integrated hardware-software solutions. Each role brings specific expertise while working as part of a cross-functional team. Depending on organization structure and agile team composition one or more of following roles will be part of same scrum team.

  • Develop and maintain bootloader code
  • Implement hardware abstraction layers
  • Create device drivers and middleware
  • Optimize code for resource-constrained environments
  • Implement power management features
  • Handle real-time operating system integration
  • Design and implement device drivers
  • Create hardware interface protocols
  • Optimize driver performance
  • Implement interrupt handlers
  • Manage device initialization sequences
  • Handle power state transitions
  • Implement business logic and features
  • Design user interfaces for embedded displays
  • Create communication protocols
  • Implement data processing algorithms
  • Develop diagnostic features
  • Handle error management and recovery
  • Develop automated test frameworks
  • Create continuous integration pipelines
  • Implement hardware-in-the-loop testing
  • Design stress testing scenarios
  • Create performance testing tools
  • Maintain test infrastructure
  • Design analog and digital circuits
  • Select components and create schematics
  • Perform circuit analysis and simulation
  • Optimize power consumption
  • Ensure signal integrity
  • Handle electromagnetic compatibility
  • Create PCB layouts and stackups
  • Optimize component placement
  • Manage thermal considerations
  • Ensure manufacturing feasibility
  • Handle high-speed design requirements
  • Implement design for testing features
  • Design digital logic systems
  • Implement hardware acceleration features
  • Create custom interfaces and protocols
  • Optimize resource utilization
  • Handle timing constraints
  • Implement debug features
  • Verify hardware designs
  • Create verification test benches
  • Perform timing analysis
  • Validate power requirements
  • Check regulatory compliance
  • Document verification results
  • Design system-level test strategies
  • Create integration test plans
  • Validate system requirements
  • Perform end-to-end testing
  • Verify system performance
  • Document test results and findings
  • Develop hardware test procedures
  • Create custom test fixtures
  • Perform environmental testing
  • Validate hardware specifications
  • Conduct reliability testing
  • Handle compliance testing
  • Create software test plans
  • Implement unit test frameworks
  • Perform integration testing
  • Validate software requirements
  • Conduct performance testing
  • Handle security testing
  • Define quality metrics and standards
  • Review test coverage and results
  • Perform root cause analysis
  • Track and analyze defect trends
  • Validate requirement compliance
  • Maintain quality documentation
  • Consider hardware availability (boards, chips, test rigs).
  • Plan integration tasks carefully—these often take longer than expected.
  • Account for supplier lead times and certification steps.
  • Surface integration issues early.
  • Track hardware readiness (is the board even available?).
  • Discuss test bench schedules—shared equipment can bottleneck teams.
  • Don’t just demo software features—show hardware prototypes in action.
  • Highlight integration milestones, not just isolated progress.
  • Collect feedback from stakeholders across disciplines.
  • Documentation: Keep specs, compliance docs, and test results up to date. Regulators will ask for it.
  • Testing Strategy: Use simulation + hardware-in-the-loop to avoid waiting for prototypes.
  • Risk Management: Watch for component obsolescence, long lead times, and regulatory hurdles.

One thing I always remind teams: testing isn’t optional in embedded—it’s your insurance against recalls, compliance failures, or safety risks.

Track progress using:

  • Sprint velocity considering hardware dependencies
  • Integration milestone completion rates
  • Defect detection and resolution metrics
  • Hardware availability metrics
  • Team productivity measures

Monitor quality through:

  • Code coverage for firmware
  • Hardware verification coverage
  • System performance metrics
  • Reliability measurements
  • Customer satisfaction data

Retrospectives should focus on:

  • Hardware-software collaboration effectiveness.
  • Efficiency of test setups and labs.
  • Integration pain points.
  • Documentation gaps.

Process Adaptation tips:

  • Adjust sprint length if hardware cycles demand it.
  • Define “Done” for hardware components (e.g., schematic reviewed, prototype validated).
  • Refine release planning to sync hardware/software timelines.

Implementing Scrum in embedded systems is not about “copy-paste” from software—it’s about adapting the principles to a world where hardware and software must move in lockstep.

In my experience, successful embedded Scrum teams share three things:

  1. Clear role definitions with extra attention on PO and SM responsibilities.
  2. Tight collaboration across hardware, firmware, and software (no silos).
  3. Pragmatism—knowing when to tailor Scrum rules to handle realities without losing the spirit of agility.

When done right, Scrum doesn’t just make embedded teams more agile—it helps them deliver safer, more reliable, and market-ready products without the chaos that often plagues complex hardware-software projects.

‹ 1 2 3 4›»

Recent Posts

  • 8051 Oscillator Circuits: The Heartbeat of Your Microcontroller – Embedded Flakes
  • Easily Make Plots in MATLAB in 5 Minutes – Embedded Flakes
  • TOP 5 OPEN SOURCE SOLUTIONS FOR VERSION CONTROL – Embedded Flakes
  • 8051 LCD Interfacing Secrets: Display Like a Champion – Embedded Flakes
  • About – Embedded Flakes

Recent Comments

No comments to show.

Archives

  • December 2025
  • September 2025
  • August 2025
  • July 2025
  • December 2024
  • September 2024
  • August 2024
  • June 2024
  • February 2024
  • December 2023
  • September 2023
  • January 2023
  • July 2022
  • August 2018
  • January 2018
  • January 2017

Categories

  • IT