Difference between revisions of "STM32 LED Pulse"
Line 1: | Line 1: | ||
[[Category:C]] [[Category:STM32 Development]] [[Category:STM32CubeMX]] [[Category:STM32CubeIde]] [[Category:Embedded]] [[Category:STM32]] {{metadesc|Pulse a LED using STM32}} | [[Category:C]] [[Category:STM32 Development]] [[Category:STM32CubeMX]] [[Category:STM32CubeIde]] [[Category:Embedded]] [[Category:STM32]] {{metadesc|Pulse a LED using STM32}} | ||
− | Imagine you had the requirement to turn on a [[LED]] for a specific length of time at the press of a button. | + | Imagine you had the requirement to turn on a [[LED]] for a specific length of time at the press of a button (or some other event). |
Obviously, responding to a button press could be easily handled by an external interrupt, so one could come up with something like: | Obviously, responding to a button press could be easily handled by an external interrupt, so one could come up with something like: |
Revision as of 02:26, 5 May 2021
Imagine you had the requirement to turn on a LED for a specific length of time at the press of a button (or some other event).
Obviously, responding to a button press could be easily handled by an external interrupt, so one could come up with something like:
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == BTN_Pin) // If the button { HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET); // Switch LED ON HAL_Delay(500); // Wait 500 ms HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET); // Switch LED OFF } }
It should be equally obvious why this is a really piss poor idea. The function will block for half a second, leaving the processor unable to do anything else for that period.
A much better idea would be to use a timer (of which most stm32 processors have quite a lot) to handle the delay.
First, let us configure a timer for this use.
In this example, the timer clock is 100 MHz.
And the User Variables LED_PRE and LED_CNT are configured like this:
In other words, once started, the timer should count down from 9999 to 0 at a frequency of 100 MHz / 10000 = 10 kHz (10000 per second). Since the LED_CNT is set to 9999, the timer will run for exactly 1 second and then fire an interrupt.
We can now improve on the above code:
/* USER CODE BEGIN 0 */ void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) { if (htim->Instance == TIM5) { HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET); // Off LED HAL_TIM_Base_Stop(&htim5); // Kill the Timer } } void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if (GPIO_Pin == BTN_Pin) // If the button { HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET); // Switch LED ON if (__HAL_TIM_GET_COUNTER(&htim5) == LED_CNT) { // Check if Timer is running - sort of HAL_TIM_Base_Start_IT(&htim5); // Start the timer if not running } else { __HAL_TIM_SET_COUNTER(&htim5, LED_CNT); // Reset the timer IF running } } } /* USER CODE END 0 */
The HAL_TIM_PeriodElapsedCallback is pretty obvious. The button interrupt is a little more complex. We are only using one timer, so we have to check if it is already running and only start the timer if it is not. If the timer is running we simply reset it to a full second again.
And that is about it - no (or very few at least) CPU cycles wasted leaving the processor to do other thing while waiting to switch the LED off.
Source code is in github: https://github.com/lbthomsen/blackpill/tree/master/btnpulse