I built a Human Response Timer to measure exactly how fast a person can react to a light turning on. The board turns on a built-in RGB LED, and my job is to press the onboard button (SW1) as quickly as I can.
This project helped me understand how to catch sudden real-world events instantly using External Interrupts (EXTI). Instead of making the program freeze and waste energy waiting for a human to move, interrupts let the microchip do other work until the exact microsecond I press the button. It is a really cool way to see just how incredibly fast a processor runs compared to human reaction time.
To follow along with my project, you will need the following items:
Hardware:
RT-Thread RT-Spark Development Board: The main microcontroller board.
Onboard Switch (SW1): The button used to test my reaction time.
Onboard RGB LED: The light that signals when to press the button.
USB Type-C Cable & Windows PC: For powering the board and uploading code.
Oscilloscope: for checking the exact timing, voltage levels, and shapes of electrical signals
in your circuit.
Software:
STM32CubeIDE and MX: The software where I configured the pins and wrote the code.
/* USER CODE BEGIN Header *//** ****************************************************************************** * @file : main.c * @brief : Main program body ****************************************************************************** * @attention * * Copyright (c) 2026 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 ---------------------------------------------------------*/RNG_HandleTypeDefhrng;/* USER CODE BEGIN PV */volatileuint8_tflag=0;/* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/voidSystemClock_Config(void);staticvoidMX_GPIO_Init(void);staticvoidMX_RNG_Init(void);/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*//* USER CODE BEGIN 0 */voidHAL_GPIO_EXTI_Callback(uint16_tGPIO_Pin){if(GPIO_Pin==GPIO_PIN_0){flag=1;}}/* USER CODE END 0 *//** * @brief The application entry point. * @retval int */intmain(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();MX_RNG_Init();/* USER CODE BEGIN 2 */uint32_tcounter=0;uint32_ttime=0;uint32_tsum=0;uint32_tavgresponsetime=0;uint8_titerations=0;/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while(1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0|GPIO_PIN_3|GPIO_PIN_2,GPIO_PIN_RESET);counter=0;if(HAL_RNG_GenerateRandomNumber(&hrng,&counter)==HAL_OK){time=(counter%(2001))+1000;}HAL_Delay(time);counter=0;HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0|GPIO_PIN_3|GPIO_PIN_2,GPIO_PIN_SET);while(flag==0){counter++;}HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0|GPIO_PIN_3|GPIO_PIN_2,GPIO_PIN_RESET);if(counter<500000){HAL_GPIO_WritePin(GPIOA,GPIO_PIN_2,GPIO_PIN_SET);/* RED */}elseif(counter>=500000&&counter<2000000){HAL_GPIO_WritePin(GPIOA,GPIO_PIN_3,GPIO_PIN_SET);/* GREEN */}else{HAL_GPIO_WritePin(GPIOA,GPIO_PIN_0,GPIO_PIN_SET);/* BLUE */}iterations++;sum=sum+counter;if(iterations==10){avgresponsetime=sum/10;iterations=0;sum=0;}flag=0;HAL_Delay(5000);}/* USER CODE END 3 */}/** * @brief System Clock Configuration * @retval None */voidSystemClock_Config(void){RCC_OscInitTypeDefRCC_OscInitStruct={0};RCC_ClkInitTypeDefRCC_ClkInitStruct={0};/** Configure the main internal regulator output voltage */__HAL_RCC_PWR_CLK_ENABLE();__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);/** 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_ON;RCC_OscInitStruct.PLL.PLLSource=RCC_PLLSOURCE_HSI;RCC_OscInitStruct.PLL.PLLM=16;RCC_OscInitStruct.PLL.PLLN=192;RCC_OscInitStruct.PLL.PLLP=RCC_PLLP_DIV2;RCC_OscInitStruct.PLL.PLLQ=4;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 RNG Initialization Function * @param None * @retval None */staticvoidMX_RNG_Init(void){/* USER CODE BEGIN RNG_Init 0 *//* USER CODE END RNG_Init 0 *//* USER CODE BEGIN RNG_Init 1 *//* USER CODE END RNG_Init 1 */hrng.Instance=RNG;if(HAL_RNG_Init(&hrng)!=HAL_OK){Error_Handler();}/* USER CODE BEGIN RNG_Init 2 *//* USER CODE END RNG_Init 2 */}/** * @brief GPIO Initialization Function * @param None * @retval None */staticvoidMX_GPIO_Init(void){GPIO_InitTypeDefGPIO_InitStruct={0};/* USER CODE BEGIN MX_GPIO_Init_1 */__HAL_RCC_GPIOA_CLK_ENABLE();/* USER CODE END MX_GPIO_Init_1 *//* GPIO Ports Clock Enable */__HAL_RCC_GPIOC_CLK_ENABLE();/*Configure GPIO pin : PC0 */GPIO_InitStruct.Pin=GPIO_PIN_0;GPIO_InitStruct.Mode=GPIO_MODE_IT_FALLING;GPIO_InitStruct.Pull=GPIO_PULLUP;HAL_GPIO_Init(GPIOC,&GPIO_InitStruct);/* EXTI interrupt init*/HAL_NVIC_SetPriority(EXTI0_IRQn,0,0);HAL_NVIC_EnableIRQ(EXTI0_IRQn);/* USER CODE BEGIN MX_GPIO_Init_2 *//*Configure GPIO pin : PA0, PA3, PA2 */GPIO_InitStruct.Pin=GPIO_PIN_0|GPIO_PIN_3|GPIO_PIN_2;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);/* 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 */voidError_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 */voidassert_failed(uint8_t*file,uint32_tline){/* 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 */
Comments