I am very new to stm32, I have STM32F411RE Nucleo and I work in STM32CubeIDE. First I need to turn on the LED with the first click on the push button, and the LED stays on until the next click. On the second click, the LED starts blinking with a frequency of 10 Hz, then I need a third click, a fourth, and so on. I have written the code for the first one and it works but I don't know how to make the LED do something with every click on the push button. I don't know how to write the program so it recognizes when a button is pressed for the second, third, or fourth time...
So far I have this:
// read the status of the GPIO button pin
button_val = HAL_GPIO_ReadPin(GPIOC, B1_Pin);
// check if it is high or low
if(button_val == PRESSED) // the button is pressed
{
// if pressed - turn led on
HAL_GPIO_WritePin(LD2_GPIO_Port,LD2_Pin, SET);
// if not pressed - turn led off
// HAL_GPIO_WritePin(LD2_GPIO_Port,LD2_Pin, RESET);
}
When I run this the LED lights up when I press the button. Then I have this code for the second press on the button but it doesn't work.
if(button_val == SECONDPRESSED)
{
// turn led on
HAL_GPIO_WritePin(LD2_GPIO_Port,LD2_Pin, SET);
HAL_Delay(1000);
// turn led off
HAL_GPIO_WritePin(LD2_GPIO_Port,LD2_Pin, RESET);
HAL_Delay(1000);
}
This is a general programming question and not really a STM32-specific issue, since the necessary STM32 hardware input/output seems to work already in your case.
In the STM32F4xx HAL driver code it can be seen that HAL_GPIO_ReadPin() returns a value of type GPIO_PinState, which can be in two states, GPIO_PIN_SET
or GPIO_PIN_RESET
, GPIO pins are either in HIGH or LOW state.
Now, to make the program cycle through different program states becomes a matter of software programming, there are no hardware specific functions involved. To realize the desired behavior, a very basic state machine could be used for example, using the following states:
typedef enum {
PROG_STATE_INIT = 0,
PROG_STATE_FIRST_PRESS,
PROG_STATE_SECOND_PRESS,
PROG_STATE_THIRD_PRESS,
PROG_STATE_FOURTH_PRESS,
_PROG_STATE_COUNT
} prog_state;
Then, in the main loop, the program could cycle through the states for example like this:
static prog_state _prog_state = PROG_STATE_INIT;
static GPIO_PinState _pin_state_prev = GPIO_PIN_RESET;
const GPIO_PinState pin_state = HAL_GPIO_ReadPin(GPIOC, B1_Pin);
if (pin_state == GPIO_PIN_SET && pin_state != _pin_state_prev) {
++_prog_state; /* next state */
if (_prog_state >= _PROG_STATE_COUNT) {
_prog_state = PROG_STATE_FIRST_PRESS;
}
}
_pin_state_prev = pin_state;
switch (_prog_state) {
case PROG_STATE_INIT:
/* do nothing here, LED is already off */
break;
case PROG_STATE_FIRST_PRESS:
/* turn LED on and let it stay on */
HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
break;
case PROG_STATE_SECOND_PRESS:
HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
HAL_Delay(50); /* ~10 Hz blinky */
break;
case PROG_STATE_THIRD_PRESS:
/* TODO */
break;
case PROG_STATE_FOURTH_PRESS:
/* TODO */
break;
case _PROG_STATE_COUNT:
default:
/* unexpected */
break;
}
Like already mentioned in the comments above, software/hardware button debouncing might be needed. But for this exercise, it can also be OK to simply add a short delay to the main loop, so that fast GPIO state changes have no effect.
And to expand on the exercise, GPIO EXTI interrupts could be used to react to GPIO state changes. And it might be interesting to set up a timer/counter to let the LED blink precisely at 10 Hz, and control it via the state machine.