While knowledge of GPIO allows for immediate input response in a robot, it is not sufficient on its own. In embedded systems, time management is crucial for tasks such as scheduling, generating PWM signals, and managing delays. The STM32 microcontroller utilizes the Hardware Abstraction Layer (HAL) to handle clock functions efficiently. This section will focus on the system clock and setting up timers for various tasks.
Hardware Abstraction Layer (HAL): A software layer that provides an interface for hardware components, allowing developers to write code without needing to understand the underlying hardware details.
The system clock in STM32 is a critical component that drives the operation of the microcontroller. It provides the timing needed for executing instructions and managing peripheral operations. The HAL library offers convenient functions to interact with the system clock.
uint32_t HAL_GetTick(void);
uint32_t ticks = HAL_GetTick();
// Return how many ms have pass though since the MCU start running
- In STM32, the MCU has introduced an application time base that increments every 1 ms. Using
HAL_GetTick()
returns the time base (in ms) since the mainboard was powered on. - You can think of the MCU as holding a stopwatch that starts when the MCU begins running, and
HAL_GetTick()
is ask the stopwatch what is the counting right now
void HAL_Delay(uint32_t Delay);
- This function pauses program execution for a specified number of milliseconds.
- While straightforward, using
HAL_Delay()
can halt all operations, which is often undesirable in real-time applications. Instead, consider using non-blocking techniques to achieve delays.
-
A LED that toggle every 200ms:
while (1) { static uint32_t last_ticks = 0; //Static attribute keep the value across every iterations while it will not be re-initized //Everything inside this if-statements gets called every 200ms if((HAL_GetTick() - last_ticks) >= 200){ gpio_toggle(LED1); last_ticks = HAL_GetTick(); //Store the tick of last time } }
-
A LED turn on 100ms after u first time press the
BTN1
:while (1) { static uint32_t last_ticks = 0; static uint8_t btn_pressed = 0; if (!btn_pressed && btn_read(BTN1)){ //Only when never pressed btn_pressed = 1; last_ticks = HAL_GetTick(); } if (btn_pressed){ if ((HAL_GetTick() - last_ticks) <= 100){ led_on(LED1); } else { led_off(LED1); } } }
While you might only need to write tens of code to finish different classwork and homework, in real life you would write thousands line of code , and so it is important for you to write your code in different functions.
In today tutorial, you should put all your code in the four function we give to you in tutorial2_hw.c
, here I would provide you an example of how it works
-
Write what you want it to do every loop:
- During the 1 - 2 second:
LED3
is flashing (toggle every 100 ms) - During the 3 - 4 second: Only turn on
LED4
/* tutorial2_hw.c*/ void gpio_classwork(void) { /* Your code start here */ // You should use static uint32_t here, as any variable that defined in main.c cannot call here unless you extern it static uint32_t last_ticks_btn = 0; static uint32_t last_ticks_led = 0; if (HAL_GetTick() - last_ticks_btn <= 2000){ // Inside the Flashing Cycle led_off(LED4); if (HAL_GetTick() - last_ticks_led > 100){ led_toggle(LED3); last_ticks_led = HAL_GetTick(); } } else if ((HAL_GetTick() - last_ticks_btn > 2000) && (HAL_GetTick() - last_ticks_btn < 4000)) { led_off(LED3); led_on(LED4); } else { last_ticks_btn = HAL_GetTick(); } /* Your code end here */ }
- During the 1 - 2 second:
-
After you have written your program in
tutorial2_hw.c
, you would like to call it in your main loop.- Before calling it, you need to have declared this function before the
main
function. - Normally we will do by include a corrsponding
.h
of that.c
, but as we forogr to give you this. - So you can directly put the function prototype (function declaration) in the top of your
main.c
/* main.c */ /* USER CODE BEGIN PFP */ void gpio_classwork(void); /* USER CODE END PFP */
- Before calling it, you need to have declared this function before the
-
After you have done all these, you can directly call the function in your
main.c
:/* main.c::int main() */ /* USER CODE BEGIN WHILE */ while(1){ gpio_classwork(); /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */
Some of you may apply another
while
loop in your function for this purpose:if (btn_read(BTN2)){ static uint32_t last_ticks_BTN = 0; last_ticks_BTN = HAL_GetTick(); while (HAL_GetTick - last_ticks_BTN < 1000){ //Code for Toggle LED } }While the solution work fine under this single task context, it will create problem in a lot of way, consider this, your robot may have a lot of things to do at the same time, for example, Flashing LED and also control the pnematic valve at the same time. Using this code, you cannot do anything when you flashing the LED for 1 second, which is not perferable.
This also the reason we tell you guys to never useHAL_Delay()
To make our code more readable and make things more organized, we have provided separate functions for you to work in.
You should write your code there in the respective functions and call the functions in the main.c
As we have included the function prototype of the
gpio_classwork()
in the previous demo, you don't need do that for this classwork.
- When
BTN1
is held,LED1
should be on. (@1) - When
BTN2
is held,LED1
should be flashing (toggle in 50ms).(@1) - When both
BTN1
andBTN2
are held, the following sequence is conducted:(@2)LED1
on whileLED2
are flashing (toggle in 50ms), for one second.LED1
andLED3
are flashing whileLED2
are on, for one second.- Repeat from step 1.
- Keyword: Finite State Machine