Controlling External LED Using a Pushbutton with STM32 CubeIDE
Introduction
Embedded systems often require user interaction, and one of the most common ways to achieve this is through pushbuttons. In my previous article, I explained in detail how to control multiple external leds but, in this article, we will explore how to control an external LED using a pushbutton with STM32 CubeIDE. This project will demonstrate how to set up the pushbutton as an input and use it to toggle the state of an LED connected to an STM32 microcontroller. STM32 CubeIDE will be our development environment of choice, providing a streamlined development process for this project.
Understanding STM32 CubeIDE
STM32 CubeIDE is a powerful and user-friendly integrated development environment tailored specifically for STM32 microcontrollers. It combines various tools, such as STM32CubeMX for peripheral configuration and STM32CubeHAL for low-level abstraction, making it easy to develop applications for STM32 devices. Before we begin, make sure you have installed CubeIDE, which can be downloaded from the STMicroelectronics website. In my previous article, I explained in detail how to download and install CubeIDE.
About STM32f103c8t6 Blue Pill:
The STM32F103C8T6, commonly known as the “Blue Pill,” is a popular microcontroller board based on the STM32F103C8T6 microcontroller from STMicroelectronics. It has gained widespread popularity due to its affordability, ease of use, and strong performance. Let’s explore some key features and characteristics of the STM32F103C8T6 Blue Pill board:
- Microcontroller: The Blue Pill is powered by the STM32F103C8T6 microcontroller, which is part of the STM32F1 series. This 32-bit ARM Cortex-M3 microcontroller operates at a clock speed of up to 72 MHz and provides a wide range of peripherals, including GPIOs, timers, UART, SPI, I2C, ADC, and more.
- Flash Memory and RAM: The STM32F103C8T6 has 64KB of Flash memory for program storage and 20KB of SRAM for data storage. This memory capacity allows for the implementation of complex applications and firmware.
- Board Layout: The Blue Pill board is a compact, single-sided board with a standard 2.54mm pitch, making it compatible with breadboards and various other prototyping setups. It features various GPIO pins, power pins, and debug/programming interface pins.
- Power Supply: The board can be powered either via USB (5V). It incorporates a 3.3V voltage regulator to power the STM32 microcontroller and other components on the board.
- USB-to-UART Interface: The board is equipped with a built-in USB-to-UART converter, which allows for easy communication and programming via the USB interface.
- Integrated LED: The board includes an integrated LED connected to PA1, which can be used for simple visual feedback during testing and debugging.
- Programming and Debugging: The Blue Pill board supports several programming and debugging options, including ST-LINK/V2, which is an embedded debugger/programmer. It allows users to program and debug the microcontroller using the STM32CubeIDE or other compatible tools.
- Community Support: Due to its popularity, the Blue Pill board has a large and active community of developers and enthusiasts. This community provides ample resources, tutorials, and libraries to support beginners and experienced users alike.
Applications:
The STM32F103C8T6 Blue Pill is versatile and well-suited for a wide range of applications, including but not limited to:
- Home automation and smart home projects
- Industrial control and automation systems
- Robotics and automation projects
- Data logging and monitoring systems
- IoT (Internet of Things) devices
- Sensor interfacing and data processing applications
- DIY electronics projects and prototypes
Creating Stm32 CubeIDE Project:
open your STM32 CubeIDE. Click on “File” in the menu, then choose “New,” and under “New,” click on “STM32 Project.”
In the “Target Selection” window, search for the specific STM32 microcontroller you are using. I am using the STM32F103C8T6, so I entered this in the “Commercial Part Number” field. Select your STM32 board and click “Next.”
In the “Setup STM32 Project” window, choose a name for your project. I selected “Pushbutton,” and left the other options as default. After that, click “Finish.”
In the “Pinout and Configuration” window, click on the “System Core” tab. Under “System Core,” click on “SYS,” and choose “Serial Wire” as the debug mode.
I have connected an LED to PA1, so I will select PA1 as an output GPIO.
Additionally, I connected a pushbutton to PB1, so I selected PB1 as an input GPIO.
After selecting the GPIO pins, click on the “Save” button to generate the code.
Led and Pushbutton with STM32 Circuit diagram:
In this circuit diagram, we have a pushbutton and an LED connected to an STM32 microcontroller. The pushbutton is connected to the PB1 pin of the STM32, along with a 10k-ohm resistor. The pushbutton is a two-terminal mechanical switch, and one terminal is connected to the ground pin of the STM32, while the other is connected to the resistor. The resistor’s second leg is connected to the 3.3V supply, providing a pull-up effect. When the pushbutton is not pressed, the pull-up resistor pulls the PB1 pin to a logic HIGH state, maintaining a stable input.
On the other side of the circuit, we have an LED connected to the A1 pin of the STM32, along with a 330-ohm resistor. The LED is a two-terminal component, and one terminal is connected to the A1 pin through the resistor, while the other is connected to the ground (GND). This arrangement ensures that the LED is properly current-limited to protect it from excessive current flow and potential damage. When the A1 pin is set to a logic HIGH state, the LED turns ON, and when it is set to a logic LOW state, the LED turns OFF.
Together, this simple circuit allows us to control the LED’s state using the pushbutton. When the pushbutton is pressed, it changes the PB1 pin’s state to logic LOW, turning OFF the LED. And when the pushbutton is released, the pull-up resistor restores the PB1 pin’s state to logic HIGH, turning ON the LED. This circuit is a basic example of how to use a pushbutton to control an LED with an STM32 microcontroller.
Controlling led with pushbutton using stm32 CubeIDE Program:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
/* USER CODE BEGIN Header */ /** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2023 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); /* USER CODE BEGIN PFP */ /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* USER CODE BEGIN 1 */ /* USER CODE END 1 */ /* MCU Configuration--------------------------------------------------------*/ /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* USER CODE BEGIN Init */ /* USER CODE END Init */ /* Configure the system clock */ SystemClock_Config(); /* USER CODE BEGIN SysInit */ /* USER CODE END SysInit */ /* Initialize all configured peripherals */ MX_GPIO_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ /* Infinite loop */ /* USER CODE BEGIN WHILE */ // Variable to store the previous button state GPIO_PinState prevButtonState = GPIO_PIN_SET; while (1) { // Read the current button state GPIO_PinState currentButtonState = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1); // Check if the button state has changed if (currentButtonState != prevButtonState) { // Debounce the button HAL_Delay(50); // Read the button state again currentButtonState = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1); // Update the previous button state prevButtonState = currentButtonState; // Check if the button is pressed (active LOW) if (currentButtonState == GPIO_PIN_RESET) { // Toggle the LED state HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_1); } } /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ } /* USER CODE END 3 */ } /** * @brief System Clock Configuration * @retval None */ void SystemClock_Config(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; /** Initializes the RCC Oscillators according to the specified parameters * in the RCC_OscInitTypeDef structure. */ RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } /** Initializes the CPU, AHB and APB buses clocks */ RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI; RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK) { Error_Handler(); } } /** * @brief GPIO Initialization Function * @param None * @retval None */ static void MX_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; /* USER CODE BEGIN MX_GPIO_Init_1 */ /* USER CODE END MX_GPIO_Init_1 */ /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_GPIOB_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET); /*Configure GPIO pin : PA1 */ GPIO_InitStruct.Pin = GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); /*Configure GPIO pin : PB1 */ GPIO_InitStruct.Pin = GPIO_PIN_1; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* USER CODE BEGIN MX_GPIO_Init_2 */ /* USER CODE END MX_GPIO_Init_2 */ } /* USER CODE BEGIN 4 */ /* USER CODE END 4 */ /** * @brief This function is executed in case of error occurrence. * @retval None */ void Error_Handler(void) { /* USER CODE BEGIN Error_Handler_Debug */ /* User can add his own implementation to report the HAL error return state */ __disable_irq(); while (1) { } /* USER CODE END Error_Handler_Debug */ } #ifdef USE_FULL_ASSERT /** * @brief Reports the name of the source file and the source line number * where the assert_param error has occurred. * @param file: pointer to the source file name * @param line: assert_param error line source number * @retval None */ void assert_failed(uint8_t *file, uint32_t line) { /* USER CODE BEGIN 6 */ /* User can add his own implementation to report the file name and line number, ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */ /* USER CODE END 6 */ } #endif /* USE_FULL_ASSERT */ |
Program Explanation:
This is our main code the rest of the code in STM32 CubeIDE is automatically generated.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
GPIO_PinState prevButtonState = GPIO_PIN_SET; while (1) { // Read the current button state GPIO_PinState currentButtonState = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1); // Check if the button state has changed if (currentButtonState != prevButtonState) { // Debounce the button HAL_Delay(50); // Read the button state again currentButtonState = HAL_GPIO_ReadPin(GPIOB, GPIO_PIN_1); // Update the previous button state prevButtonState = currentButtonState; // Check if the button is pressed (active LOW) if (currentButtonState == GPIO_PIN_RESET) { // Toggle the LED state HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_1); } } |
This code snippet demonstrates a simple program in STM32 CubeIDE for debouncing a button and controlling an LED based on its state. The main loop runs indefinitely, constantly monitoring the button connected to GPIO_PIN_1 of GPIOB (GPIO port B). It uses the variable prevButtonState to store the previous state of the button, initialized to GPIO_PIN_SET (indicating the button is released).
During each iteration of the loop, it reads the current state of the button into the variable currentButtonState. If there is a change in the button state compared to the previous state, the program proceeds with debouncing. It introduces a 50-millisecond delay to allow for any mechanical noise or bouncing to settle. After the delay, it reads the button state again to ensure a stable and accurate input.
If the button is detected as being pressed (active low) after debouncing, the program toggles the state of the LED connected to GPIO_PIN_1 of GPIOA (GPIO port A). This means if the LED was off, it will be turned on, and if it was on, it will be turned off.
The debouncing technique ensures that the LED’s state changes only when the button press or release is stable, ignoring any transient noise. By doing so, the program prevents unintended and rapid toggling of the LED, providing a more reliable user experience with the button-LED interface.
Copy the full code or just copy the “while” section code and paste it.
Stm32 CubeIDE Project Uploading:
Before uploading the project code, ensure to connect the ST-Link V2 with the STM32 microcontroller. The connection diagram is provided below:
Connect the SWDIO (Serial Wire Debug Input/Output) pin of the ST-Link V2 to the SWDIO pin on the STM32 microcontroller. This allows bidirectional communication between the ST-Link V2 and the microcontroller.
Connect the SWCLK (Serial Wire Clock) pin of the ST-Link V2 to the SWCLK pin on the STM32 microcontroller. This clock signal synchronizes data transmission between the two devices.
Establish a common ground reference by connecting the GND pin of the ST-Link V2 to the GND pin on the STM32 microcontroller.
Provide power to the STM32 microcontroller by connecting the 3.3V pin of the ST-Link V2 to the 3.3V power supply on the STM32 board.
Once the connection between Jab ST-Link V2 and STM32 is complete, connect the ST-Link V2 to your PC or laptop, and then click on the “build” button.
Once the build processing is complete, click on the green play button. After clicking the play button, the “Edit Launch Configuration Properties” window will open.
In this window, navigate to the “Debugger” menu and select “Debug Probe” as “ST-Link (OpenOCD).”
Then, click on the “Show Generator Options” button and choose “Software System Reset” as the reset mode.
Once you’ve made these selections, click on the “Apply” button to save all the changes. Finally, press the “OK” button to upload the program.
When you see the message “shutdown command invoked” on your console, disconnect the ST-Link V2 from your PC or laptop. Then, reconnect it to your PC, laptop, or any other 5V power source. Afterward, proceed to practically test your project.
Conclusion
In this article, we explored how to control an external LED using a pushbutton with STM32 CubeIDE. We discussed the project setup, the code required to read the pushbutton state, and how to toggle the LED accordingly. With the versatility and ease-of-use of STM32 CubeIDE, you can now integrate user interactions into your STM32-based embedded systems effortlessly. This opens up a wide range of possibilities for creating interactive and responsive applications.