1

I have developed a system which reads three lines coming from a 3:8 decoder. This decoder reduces 7 lines mechanical relays to 3 lines. So to sum up it is this way:

              m2        m1        m0        (decoder output)
             exti3    exti2     exti1
   RL01 on    0         0         1
   RL02 on    0         1         0
   RL03 on    0         1         1
   RL04 on    1         0         0
   RL05 on    1         0         1
   RL06 on    1         1         0
   RL07 on    1         1         1

Only one relay will be activated at the same time.

I was trying to figure out a way to read the interrupts and in depending of its values do different things.

I am using a STM32F4 micro and as far as I know, its scheduler works this way:

  • When an interrupt occurs, the program jumps to its ISR, it does what it is inside, and it returns to where it was before.
  • If an interrupt occurs when the program is in another one, it can happens two things. If the priority of the current interrupt is greater than the incoming one, then first it will finish the execution of the current interrupt and then it will jump to the incoming one. If the priority of the incoming one is greater than the actual one, then it will jump to the incoming one and then it will return to the first one.

Taking into account this concepts, I dont know how to do what I want.

Setting global variables as flags in the ISR's and reading them in the main program would not help me, because what I want is to stop a stepper motor when the mechanical relay is pressed, and acording to the two previous concepts, if I set flags, first of all my program will finish to move the stepper motor and then it will stop it, but I want it to be stopped directly.

  1. What I want is to handle every single relay on its own, however I have only 3 interrupts and I am not sure I will be able to do it.
  2. The decoder was used to save some pins for other stuff to be able to handle 7 relays with just 3 pins. At the beginning I thought it would work, but now I am not very sure. I cant change the hardware at this point.

This is the function I use to move my stepper motors, if it helps:

void moveMotorDegrees (uint8_t player, uint16_t degrees)
{
    double steps = 0;
    uint16_t cycles = 0;
    uint16_t i = 0;
    double oneLapSteps = 200;
    double oneLapDegrees = 360;


    steps = degrees * (oneLapSteps/oneLapDegrees);
    cycles = round(2 * steps);

    switch (player)
    {
    case 1:
        HAL_GPIO_WritePin(RESET_M1_GPIO_Port, RESET_M1_Pin, GPIO_PIN_SET);
        break;
    case 2:
        HAL_GPIO_WritePin(RESET_M2_GPIO_Port, RESET_M2_Pin, GPIO_PIN_SET);
        break;
    case 3:
        HAL_GPIO_WritePin(RESET_M3_GPIO_Port, RESET_M3_Pin, GPIO_PIN_SET);
        break;
    case 4:
        HAL_GPIO_WritePin(RESET_M4_GPIO_Port, RESET_M4_Pin, GPIO_PIN_SET);
        break;
    }


    for (i = 0; i < cycles; i++)
          {
              HAL_Delay(5);
              switch (player)
                {
                case 1:
                    HAL_GPIO_TogglePin(STEP_M1_GPIO_Port, STEP_M1_Pin);
                    break;
                case 2:
                    HAL_GPIO_TogglePin(STEP_M2_GPIO_Port, STEP_M2_Pin);
                    break;
                case 3:
                    HAL_GPIO_TogglePin(STEP_M3_GPIO_Port, STEP_M3_Pin);
                    break;
                case 4:
                    HAL_GPIO_TogglePin(STEP_M4_GPIO_Port, STEP_M4_Pin);
                    break;
                }
          }

    HAL_Delay(200);
    switch (player)
    {
    case 1:
        HAL_GPIO_WritePin(RESET_M1_GPIO_Port, RESET_M1_Pin, GPIO_PIN_RESET);
        break;
    case 2:
        HAL_GPIO_WritePin(RESET_M2_GPIO_Port, RESET_M2_Pin, GPIO_PIN_RESET);
        break;
    case 3:
        HAL_GPIO_WritePin(RESET_M3_GPIO_Port, RESET_M3_Pin, GPIO_PIN_RESET);
        break;
    case 4:
        HAL_GPIO_WritePin(RESET_M4_GPIO_Port, RESET_M4_Pin, GPIO_PIN_RESET);
        break;
    }
}

Thanks in advance.

  • do I get it right that exti1 exti2 and exti3 are interrupt lines of MCPU? – Serge Aug 30 '16 at 15:46
  • I do not quite understand 1.) what you want to achieve, 2.) what difficulties you have and 3.) what role does the 3:8 decoder play in this question? If you receive an interrupt to stop the motor, then simply set a global flag—the next time you want to advance the motor by a single step, simply check if that flag is set. – Martin Nyolt Aug 30 '16 at 15:50
  • Yes, you are right, @serge – Sergio Castillo Aug 30 '16 at 15:57
  • Let me edit the text with the points you mention @MartinNyolt, but the key it could be in what you say at the end. Thanks. – Sergio Castillo Aug 30 '16 at 15:58
  • 1
    Then it's a bad idea to drive the 8-to-3 encoder output to interrupt lines. You need to change your design and connect your encoder to IO port of MCPU. To make the thing interrupt-driven you need also to OR all 7 relay "outputs" and connect the OR'ed signal to a single interrupt line of MCPU. Also keep in mind the active level of the interrupt (you would probably need to negate the OR'ed signal if the interrupt line has negative logic) and its sensitivity (edge or level) – Serge Aug 30 '16 at 16:13
  • Do I understand correctly that you want to do 8 different actions, depending on the states of the 8 relays? – Martin Nyolt Aug 30 '16 at 16:40
  • @Serge But with all signals ORed, he won't be able to always detect a change, e.g., from RL01 active to RL02 active. Beware of hazards (the three inputs not coming at the same time instant). To alleviate this, one approach would be to 1.) signal interrupt by flag 2.) wait in the main program a few cycles to check if a new interrupt is available 3.) if no new interrupt is available, do your action. – Martin Nyolt Aug 30 '16 at 16:41
  • @MartinNyolt, see the op: "Only one relay will be activated at the same time.". I assume that first the relay goes "off" and then another goes "on" – Serge Aug 30 '16 at 16:52
  • @serge though your idea seems good, I would like to avoid as much as possible any change at hardware level. – Sergio Castillo Aug 30 '16 at 18:10
  • @SergioCastillo I undrestand you but it's bad design. Not in terms of taste or style, but in terms of feasibility to use. – Serge Aug 30 '16 at 18:15

1 Answers1

0

According previous conversation with @serge and @MartinNyolt, I think this could work:

void moveMotorDegrees (uint8_t player, uint16_t degrees)
{
    double steps = 0;
    uint16_t cycles = 0;
    uint16_t i = 0;
    double oneLapSteps = 200;
    double oneLapDegrees = 360;


    steps = degrees * (oneLapSteps/oneLapDegrees);
    cycles = round(2 * steps);

    switch (player)
    {
    case 1:
        HAL_GPIO_WritePin(RESET_M1_GPIO_Port, RESET_M1_Pin, GPIO_PIN_SET);
        break;
    case 2:
        HAL_GPIO_WritePin(RESET_M2_GPIO_Port, RESET_M2_Pin, GPIO_PIN_SET);
        break;
    case 3:
        HAL_GPIO_WritePin(RESET_M3_GPIO_Port, RESET_M3_Pin, GPIO_PIN_SET);
        break;
    case 4:
        HAL_GPIO_WritePin(RESET_M4_GPIO_Port, RESET_M4_Pin, GPIO_PIN_SET);
        break;
    }


    for (i = 0; i < cycles; i++)
          {
              HAL_Delay(5);
              switch (player)
                {
                case 1:
                    if ((MA2_Flag != 1 && MA1_Flag != 1 && MA0_Flag != 1) || (MA2_Flag != 1 && MA1_Flag != 1 && MA0_Flag != 0))
                    {
                        HAL_GPIO_TogglePin(STEP_M1_GPIO_Port, STEP_M1_Pin);
                    }
                    break;
                case 2:
                    if ((MA2_Flag != 1 && MA1_Flag != 0 && MA0_Flag != 0) || (MA2_Flag != 1 && MA1_Flag != 0 && MA0_Flag != 1))
                    {
                        HAL_GPIO_TogglePin(STEP_M2_GPIO_Port, STEP_M2_Pin);
                    }
                    break;
                case 3:
                    if ((MA2_Flag != 0 && MA1_Flag != 1 && MA0_Flag != 0) || (MA2_Flag != 0 && MA1_Flag != 1 && MA0_Flag != 1))
                    {
                        HAL_GPIO_TogglePin(STEP_M3_GPIO_Port, STEP_M3_Pin);
                    }
                        break;
                case 4:
                    if ((MA2_Flag != 0 && MA1_Flag != 0 && MA0_Flag != 1) || (MAAux_Flag != 1))
                    {
                        HAL_GPIO_TogglePin(STEP_M4_GPIO_Port, STEP_M4_Pin);
                    }
                    break;
                }
          }

    MAAux_Flag = 0;
    MA2_Flag = 0;
    MA1_Flag = 0;
    MA0_Flag = 0;

    HAL_Delay(200);
    switch (player)
    {
    case 1:
        HAL_GPIO_WritePin(RESET_M1_GPIO_Port, RESET_M1_Pin, GPIO_PIN_RESET);
        break;
    case 2:
        HAL_GPIO_WritePin(RESET_M2_GPIO_Port, RESET_M2_Pin, GPIO_PIN_RESET);
        break;
    case 3:
        HAL_GPIO_WritePin(RESET_M3_GPIO_Port, RESET_M3_Pin, GPIO_PIN_RESET);
        break;
    case 4:
        HAL_GPIO_WritePin(RESET_M4_GPIO_Port, RESET_M4_Pin, GPIO_PIN_RESET);
        break;
    }
}

Inside each case statement I have two if conditions. Each one according one different relay (see image below). Inside the ISR's I set the flags.

Truth Table of encoder 8:3

Maybe more than one step is executed but at 1.8 degrees each one that wont be a problem.

I wanted to do a function in the main program to stop one motor or another in depending of the flags, but managing the flags directly inside the moveMotorsDistance function it is the best solutions because actually it stops moving the stepper motor.