Microcontroller: Can the Interrupt System Control an Entire Production Line? This Case Study Amazed Me!

Today, let’s discuss a seemingly simple yet powerful technology that can solve complex problems—the microcontroller interrupt system.In automated production lines, it is often necessary to respond in real-time to multiple sensor signals. How can a small microcontroller accomplish this task? The interrupt system acts as the invisible “master scheduler”.

What is an Interrupt System?

Imagine you are focused on writing code when suddenly your phone rings, and you have to put your work aside to answer it. After the call, you return to your previous task. The microcontroller’s interrupt system works in a similar way!

An interrupt is essentially a mechanism that interrupts the main program, allowing the CPU to pause the currently executing program when a specific event occurs from an external device or within the microcontroller, execute a pre-defined “interrupt service routine”, and then return to continue executing the main program.

Interrupt systems are mainly divided into:

  • External Interrupts: Triggered by external signals, such as button presses or sensor activations.
  • Timer Interrupts: Generated at regular intervals, such as every 1ms.
  • UART Interrupts: Triggered when receiving or sending data.
  • ADC Interrupts: Triggered after analog-to-digital conversion is completed.
  • Watchdog Interrupts: Triggered to reset the system in case of anomalies.

Hardware Connection—Taking STM32 as an Example

For a simple production line monitoring system, we need to connect:

  1. Emergency Stop Button → PA0 (External Interrupt 0)
  2. Material Detection Sensor → PA1 (External Interrupt 1)
  3. Temperature Limit Sensor → PA2 (External Interrupt 2)
  4. Running Indicator Light → PB5 (Normal GPIO Output)
  5. Alarm Indicator Light → PB6 (Normal GPIO Output)

Note: External interrupt pins must have pull-up or pull-down resistors to avoid floating states that can lead to false triggers. I once encountered a project where I forgot this, resulting in random system restarts, and it took me three days to identify the issue!

Code Implementation—Interrupt Configuration and Handling

/* Initialize interrupt configuration */
void Interrupt_Init(void)
{
    // GPIO configuration (basic pin initialization omitted)

    // Interrupt line configuration
    EXTI_InitTypeDef EXTI_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;

    // Connect GPIO to interrupt lines
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); // Emergency Stop
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource1); // Material Detection
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource2); // Temperature Detection

    // Configure interrupt lines
    EXTI_InitStructure.EXTI_Line = EXTI_Line0 | EXTI_Line1 | EXTI_Line2;
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; // Interrupt mode
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; // Falling edge trigger
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);

    // Configure NVIC (Interrupt Controller)
    NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn; // Emergency Stop interrupt channel
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; // Highest preemption priority
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // Highest sub-priority
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    // Material detection interrupt (lower priority)
    NVIC_InitStructure.NVIC_IRQChannel = EXTI1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_Init(&NVIC_InitStructure);

    // Temperature detection interrupt
    NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_Init(&NVIC_InitStructure);
}

/* Emergency Stop Interrupt Service Function */
void EXTI0_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line0) != RESET)
    {
        // Debounce processing
        delay_ms(10);
        if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_0) == 0)
        {
            // Emergency stop processing
            EmergencyStop();
            GPIO_SetBits(GPIOB, GPIO_Pin_6); // Alarm light on
        }
        EXTI_ClearITPendingBit(EXTI_Line0); // Clear interrupt flag
    }
}

/* Material Detection Interrupt Service Function */
void EXTI1_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line1) != RESET)
    {
        static uint32_t last_time = 0;
        uint32_t current_time = GetSystemTick();

        // Important: Debounce processing, at least 50ms between two interrupts
        if(current_time - last_time > 50)
        {
            MaterialDetected();
        }
        last_time = current_time;

        EXTI_ClearITPendingBit(EXTI_Line1);
    }
}

/* Temperature Limit Interrupt Service Function */
void EXTI2_IRQHandler(void)
{
    if(EXTI_GetITStatus(EXTI_Line2) != RESET)
    {
        // Temperature alarm processing
        TemperatureAlert();
        EXTI_ClearITPendingBit(EXTI_Line2);
    }
}

The golden rule of interrupt service routines: Keep the code short and efficient! Never perform time-consuming operations within an interrupt, such as sending large amounts of UART data or using delay functions. The correct approach is to set a flag within the interrupt and handle it in the main loop.

Real-World Application Case of Production Line

In a beverage bottling line project I participated in, we implemented multi-point monitoring through the interrupt system:

  1. Emergency Stop Function: When the operator presses the emergency stop button, it triggers External Interrupt 0, immediately stopping all devices.
  2. Bottle Counting System: A photoelectric sensor detects a bottle passing by, triggering External Interrupt 1 to increase the counter value.
  3. Liquid Level Anomaly Monitoring: A liquid level sensor detects an anomaly, triggering External Interrupt 2 to alarm and pause filling.
  4. Temperature Monitoring: A timer interrupt reads the temperature sensor every 500ms, alarming if it exceeds the threshold.

Such a system, if implemented using polling, would not only complicate the code but also slow down the response time. With interrupts, the CPU spends most of its time executing the main program, only interrupting when specific events need to be handled.

Common Issues and Solutions

  1. Interrupt Bounce Issue

When connecting mechanical buttons or switches to interrupt pins, you may encounter the issue of button bounce causing multiple interrupts to trigger from a single press.

Solutions:

// Hardware solution: RC filter circuit
// Software solution: Debounce delay or timestamp recording
if(current_time - last_interrupt_time > debounce_time)
{
    // Execute interrupt handling
    last_interrupt_time = current_time;
}
  1. Interrupt Priority Confusion

When multiple interrupts occur simultaneously, improper priority settings may lead to important events not being handled in a timely manner.

Solution: Set preemption and sub-priorities reasonably. For example, the interrupt priority for the emergency stop button should be set to the highest.

  1. Excessive Interrupt Handling Time

Performing time-consuming operations within an interrupt service routine can prevent other interrupts from being handled promptly.

Solution: Interrupt service routines should be as short as possible, with the main work done in the main loop.

// Incorrect example
void EXTI0_IRQHandler(void)
{
    delay_ms(500); // Serious error! Do not use delay in interrupts
    SendDataUART("Button pressed detected"); // Error! UART sending may block
}

// Correct approach
volatile uint8_t button_flag = 0;
void EXTI0_IRQHandler(void)
{
    button_flag = 1; // Only set the flag
    EXTI_ClearITPendingBit(EXTI_Line0);
}

// Handle in the main loop
void main(void)
{
    while(1)
    {
        if(button_flag)
        {
            SendDataUART("Button pressed detected");
            button_flag = 0;
        }
        // Other code...
    }
}

Comparison with PLC

The interrupt system of a microcontroller is similar to the interrupt scanning of a PLC. PLCs use interrupt blocks to handle urgent events, but the programming methods differ:

  • Microcontroller: Interrupt service routines are written in C language.
  • PLC: Uses interrupt blocks (such as S area, I area interrupts) or special function blocks.

For simple control tasks, PLC programming is more intuitive; however, for complex real-time responses, the microcontroller’s interrupt system is more flexible and efficient.

Practical Recommendations

  1. Establish an Interrupt Priority Table to clarify the importance and response time requirements of each interrupt.
  2. Use an Oscilloscope to Observe Interrupt Pin Signals, especially to check for bounce issues.
  3. Add Watchdog Protection for Critical Interrupts to prevent program crashes from causing system failures.
  4. Establish an Interrupt Testing Program to verify whether the interrupt response time meets requirements.
  5. Use Interrupt Sharing Wisely: Multiple devices can share one interrupt line, but the source must be distinguished in the interrupt service routine.

To master the interrupt system, start with simple button interrupts, gradually try timer interrupts, ADC interrupts, etc., and ultimately implement a small production line monitoring system. Practical experience is key; only by hands-on debugging can one truly understand the power of the interrupt system.

By effectively utilizing the interrupt system, even 8-bit or 16-bit microcontrollers can achieve efficient control over complex production lines. I hope this article helps you understand the microcontroller interrupt system. See you next time!

Leave a Comment