#include "stm32f1xx_hal.h"
#include <stdio.h>
#include <stdint.h>
//--------------------------------------------------------
// Configuration
#define BUTTON_DEBOUNCE_MS 10U
#define LED_PIN GPIO_PIN_5
#define BUTTON_PIN GPIO_PIN_0
#define GPIO_PORT GPIOA
//--------------------------------------------------------
// Button events
typedef enum
{
BUTTON_EVENT_NONE,
BUTTON_EVENT_PRESSED,
BUTTON_EVENT_RELEASED
} ButtonEvent_t;
//--------------------------------------------------------
// HAL peripheral handle
UART_HandleTypeDef huart1;
//--------------------------------------------------------
// Function prototypes
void SystemClock_Config(void);
static void GPIO_Init(void);
static void USART1_Init(void);
//void Error_Handler(void);
ButtonEvent_t Button_GetEvent(void);
//--------------------------------------------------------
// printf redirection to USART1
int _write(int file, char *ptr, int len){
(void)file;
if (HAL_UART_Transmit(&huart1, (uint8_t *)ptr, (uint16_t)len, HAL_MAX_DELAY) != HAL_OK) return 0;
return len;
}
//--------------------------------------------------------
// Main
int main(void){
HAL_Init();
/*
* The default STM32F1 HAL startup clock is normally HSI.
* This configuration explicitly selects HSI at 8 MHz.
*/
SystemClock_Config();
GPIO_Init();
USART1_Init();
printf("App init ---\r\n");
while (1){
//printf("Btn pressed\r\n");
ButtonEvent_t event = Button_GetEvent();
switch (event){
case BUTTON_EVENT_PRESSED: HAL_GPIO_WritePin(GPIO_PORT, LED_PIN, GPIO_PIN_SET); printf("Btn pressed\r\n"); break;
case BUTTON_EVENT_RELEASED: HAL_GPIO_WritePin(GPIO_PORT, LED_PIN, GPIO_PIN_RESET); printf("Btn released\r\n"); break;
case BUTTON_EVENT_NONE:
default: break;
}
}
}
//--------------------------------------------------------
// System clock configuration
void SystemClock_Config(void){
RCC_OscInitTypeDef oscConfig = {0};
RCC_ClkInitTypeDef clkConfig = {0};
// Use internal 8 MHz HSI oscillator
oscConfig.OscillatorType = RCC_OSCILLATORTYPE_HSI;
oscConfig.HSIState = RCC_HSI_ON;
oscConfig.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
oscConfig.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&oscConfig) != HAL_OK)
{
//Error_Handler();
}
// HCLK = SYSCLK = 8 MHz
// PCLK1 = HCLK / 1
// PCLK2 = HCLK / 1
clkConfig.ClockType = RCC_CLOCKTYPE_HCLK |
RCC_CLOCKTYPE_SYSCLK |
RCC_CLOCKTYPE_PCLK1 |
RCC_CLOCKTYPE_PCLK2;
clkConfig.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
clkConfig.AHBCLKDivider = RCC_SYSCLK_DIV1;
clkConfig.APB1CLKDivider = RCC_HCLK_DIV1;
clkConfig.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&clkConfig, FLASH_LATENCY_0) != HAL_OK)
{
//Error_Handler();
}
}
//--------------------------------------------------------
// GPIO initialization
static void GPIO_Init(void){
GPIO_InitTypeDef GPIO_InitStruct = {0};
//
__HAL_RCC_GPIOA_CLK_ENABLE();
// PA5: LED output, push-pull
GPIO_InitStruct.Pin = LED_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIO_PORT, &GPIO_InitStruct);
// Start with LED OFF
HAL_GPIO_WritePin(GPIO_PORT, LED_PIN, GPIO_PIN_RESET);
// PA0: Button input with internal pull-up
GPIO_InitStruct.Pin = BUTTON_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIO_PORT, &GPIO_InitStruct);
}
//--------------------------------------------------------
// USART1 initialization
static void USART1_Init(void){
__HAL_RCC_USART1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef GPIO_InitStruct = {0};
// PA9: USART1_TX, alternate-function push-pull
GPIO_InitStruct.Pin = GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// PA10: USART1_RX, input
GPIO_InitStruct.Pin = GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
//Error_Handler();
}
}
//--------------------------------------------------------
// Button event detection with debounce
ButtonEvent_t Button_GetEvent(void){
static uint8_t initialized = 0;
static uint8_t stableState = 0;
static uint8_t lastRawState = 0;
static uint32_t changeTime = 0;
// Active-low button:
// 1 = pressed, 0 = released
uint8_t currentState = (HAL_GPIO_ReadPin(GPIO_PORT, BUTTON_PIN) == GPIO_PIN_RESET);
//uint32_t now = HAL_GetTick();
// Initialize states on the first call
if (!initialized){
initialized = 1U;
stableState = currentState;
lastRawState = currentState;
changeTime = HAL_GetTick();
printf("Button event init: %u\r\n", stableState);
return BUTTON_EVENT_NONE;
}
// Detect a raw state change
if (currentState != lastRawState){
lastRawState = currentState;
changeTime = HAL_GetTick();
return BUTTON_EVENT_NONE;
}
// Wait for the input to remain stable for 50 ms
//
if ((uint32_t)(HAL_GetTick() - changeTime) >= BUTTON_DEBOUNCE_MS){
//printf("Waiting for stable input... ----- %d \r\n", currentState);
//if((now - changeTime) >= BUTTON_DEBOUNCE_MS)
if (stableState != lastRawState){
stableState = lastRawState;
if (stableState != 0U){
printf("PRESSED\r\n");
return BUTTON_EVENT_PRESSED;
} else {
printf("RELEASED\r\n");
return BUTTON_EVENT_RELEASED;
}
}
}
return BUTTON_EVENT_NONE;
}
//--------------------------------------------------------
// Error handler
// void Error_Handler(void)
// {
// __disable_irq();
// while (1)
// {
// // Stay here if initialization fails
// }
// }
// static uint8_t Button_PressedEvent(void){
// static uint8_t stableState;
// static uint8_t lastRawState;
// static uint32_t changeTime;
// //read current state
// uint8_t currentState = (HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN) == GPIO_PIN_RESET);
// // Detect press
// if(currentState != lastRawState){
// changeTime = HAL_GetTick();
// lastRawState = currentState;
// // Wait for 50 ms to check if the state is stable
// if((HAL_GetTick() - changeTime) >= 50){
// currentState = (HAL_GPIO_ReadPin(BUTTON_PORT, BUTTON_PIN) == GPIO_PIN_RESET);
// if(currentState == lastRawState){
// stableState = currentState;
// //pressEvent: generate event only on RELEASED → PRESSED transition
// if(stableState == 1){
// return 1;
// }
// }
// }
// }
// return 0;
// }