Search code examples
cembeddedstm32

Ordering the interrupts in STM32


I want to do a calculator on STM32 with my 4x4 Keypad and SSD ( 7 seg. display). I'll use A as the addition on the keypad and let's say I will calculate this: 9 + 8 = 17. I'm using interrupts for getting the numbers from the keypad, so the interrupts I used for these numbers are:

//INTERRUPT FOR NUMBER 9

void EXTI0_1_IRQHandler(void){ // Interrupt from PB0
    GPIOB->ODR ^= (1U << 9); //PB9
    if ((GPIOB->IDR >> 0) & 1){
        //9
        setSSD(9);
    }
GPIOB->ODR ^= (1U << 9); //PB9
}

//INTERRUPT FOR NUMBER 8
void EXTI2_3_IRQHandler(void){// Interrupt from PB2

    GPIOB->ODR ^= (1U << 9); //PB9
    if ((GPIOB->IDR >> 2) & 1){
        //8
        setSSD(8);
    }
}

//INTERRUPT FOR A 
void EXTI4_15_IRQHandler(void){
        if ((GPIOA->IDR >> 9) & 1){
            //A
            addition (x,y);
        }
        GPIOB->ODR ^= (1U << 4); //PB4
}

Here's my problem: In a normal C language, I would ask the user to give the number with scanf and put the number to the variable x, and then take another number, put it into the y. And define A as x + y, so the calculation would be done.

But in here, there is no scanf like function, so how can I order the interrupts? Like the first interrupt (the first number pressed) should be x and the second interrupt (the second number pressed) should be y.

Sorry, my mind is messed up, I would be very happy if you can come up with any solution.


Solution

  • You need to revise your design, and not conflate I/O with the application. Get your I/O working with switch debouncing etc. first (which may or may not use interrupts); then write the calculator application. You have already considered how you would do that with stdio, and just as scanf() does not update the display or perform the calculation, neither should your keypad driver.

    S suitable keypad driver would detect key presses, perform debouncing, then place the key press in a ring-buffer or queue. Your calculator application may then be implemented in the normal processing thread rather then in interrupt handlers.

    You then need to break the calculator application down into subroutines for each possible key press. For example below I have assumed a simple four function calculator.

    The answer to your question specifically is to use a simple "state-machine", where the state is incremented when an operator key is pressed, and use that "state" to determine which operator is being updated. You only need two "registers", because rather than A = x + y, a real calculator performs x = x + y, so that the answer can be used as an operand in further operands.

    // Variables to store the operands and operator
    int operand[2] = 0 ;
    int operand_idx = 0 ;
    typedef enum
    {
        ADD,SUB,MUL,DIV
    } eOperator ;
    
    eOperator operator ;
    
    // Call for each digit key pressed
    void addDigit( int d )
    {
        operand[operand_idx] *= 10 ;
        operand[operand_idx] += d ;
        display( operand[operand_idx] ) ;
    }
    
    // Call when an operator key is pressed
    void setOperator( eOperator op )
    {
        if( operator == 0 )
        {
            operator = op ;
            operand_idx = 1 ;
        }
        else
        {
            calculate() ;
        }
    }
    
    // Call when "=" / answer key pressed
    void calculate()
    {
        switch( operator )
        {
            case ADD :  operand[0] = operand[0] + operand[1] ; break ;
            case SUB :  operand[0] = operand[0] - operand[1] ; break ;
            case MUL :  operand[0] = operand[0] * operand[1] ; break ;
            case DIV :  operand[0] = operand[0] / operand[1] ; break ;
        }
    
        display( operand[0] ) ;
        operand[1] = 0 ;
    }
    
    // Call to clear calculation
    void clear()
    {
        operand[0] = 0 ;
        operand[1] = 0 ;
        operand_idx = 0 ;
    }
    
    

    Then assuming you implement a suitable keypad driver with a getKey() function then the calculator itself would look like:

    for(;;)
    {
        char key = getKey() ;
    
        if( isdigit( key ) )
        {
            addDigit( key - '0' ) ;
        }
        else
        {
            switch( key )
            {
                 case 'A' : setOperator( ADD ) ; break ;
                 case 'B' : setOperator( SUB ) ; break ;
                 case 'C' : setOperator( MUL ) ; break ;
                 case 'D' : setOperator( DIV ) ; break ;
                 case 'E' : calculate() ; break ;
                 case 'F' : clear() ; break ;
            }
        }
    }