/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private variables ---------------------------------------------------------*/
TIM_HandleTypeDef htim2;
volatile uint32_t last_capture = 0;
volatile uint32_t pulse_period = 0;
volatile uint8_t speed = 0; // Speed in km/h
// 7-seg digits segments lookup table for common cathode display
const uint8_t SEGMENT_CODES[10] = {
0x3F, // 0
0x06, // 1
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F // 9
};
#define WHEEL_CIRCUMFERENCE 2.1f // meters (example value)
#define DISPLAY_DIGITS 4
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_TIM2_Init(void);
void Display_Speed(uint8_t speed);
void Display_Digit(uint8_t digit, uint8_t position);
/* USER CODE BEGIN 0 */
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim->Channel == HAL_TIM_ACTIVE_CHANNEL_1)
{
uint32_t capture = HAL_TIM_ReadCapturedValue(htim, TIM_CHANNEL_1);
if(capture > last_capture) // Basic handle rollover if needed
pulse_period = capture - last_capture;
else
pulse_period = (0xFFFF - last_capture) + capture;
last_capture = capture;
if(pulse_period != 0)
{
// Timer frequency depends on APB1 timer clock and prescaler
float timer_freq = HAL_RCC_GetPCLK1Freq() * 2; // TIM2 clock freq (APB1 x2)
float freq = timer_freq / (float)pulse_period;
float speed_mps = freq * WHEEL_CIRCUMFERENCE;
speed = (uint8_t)(speed_mps * 3.6f); // m/s to km/h
}
else
{
speed = 0;
}
}
}
/* USER CODE END 0 */
int main(void)
{
/* MCU Configuration--------------------------------------------------------*/
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM2_Init();
/* Start input capture in interrupt mode */
HAL_TIM_IC_Start_IT(&htim2, TIM_CHANNEL_1);
while (1)
{
Display_Speed(speed);
HAL_Delay(5);
}
}
void Display_Speed(uint8_t speed)
{
uint8_t digits[DISPLAY_DIGITS];
digits[0] = speed / 1000;
digits[1] = (speed / 100) % 10;
digits[2] = (speed / 10) % 10;
digits[3] = speed % 10;
for(uint8_t i=0; i<DISPLAY_DIGITS; i++)
{
Display_Digit(digits[i], i);
HAL_Delay(2);
}
}
void Display_Digit(uint8_t digit, uint8_t position)
{
// GPIO code to enable digit (position) and display segments for digit
// Customize pins based on your hardware wiring here
// Example:
// Set segments pins (PORTx->ODR = SEGMENT_CODES[digit])
// Enable digit select line for 'position'
}
/* TIM2 init function */
static void MX_TIM2_Init(void)
{
TIM_IC_InitTypeDef sConfigIC = {0};
htim2.Instance = TIM2;
htim2.Init.Prescaler = 1799; // Assuming APB1 clock = 36 MHz, gives timer freq = 20 kHz
htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
htim2.Init.Period = 0xFFFF;
htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
if (HAL_TIM_IC_Init(&htim2) != HAL_OK)
{
Error_Handler();
}
sConfigIC.ICPolarity = TIM_INPUTCHANNELPOLARITY_RISING;
sConfigIC.ICSelection = TIM_ICSELECTION_DIRECTTI;
sConfigIC.ICPrescaler = TIM_ICPSC_DIV1;
sConfigIC.ICFilter = 0;
if (HAL_TIM_IC_ConfigChannel(&htim2, &sConfigIC, TIM_CHANNEL_1) != HAL_OK)
{
Error_Handler();
}
}
/* GPIO init function */
static void MX_GPIO_Init(void)
{
/* Configure GPIO pins for 7-seg display segments and digit control */
/* Example for GPIO ports and pins you define for your hardware */
}
/* System Clock Configuration */
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
// Configure PLL and clocks as per your hardware
}
/* Error Handler */
void Error_Handler(void)
{
while(1) {}
}