#include <Arduino.h>
#include <stm32c0xx_hal.h>
#define EXT_LED_PIN GPIO_PIN_1
#define EXT_LED_PORT GPIOA
#define STATUS_LED_PIN GPIO_PIN_5
#define STATUS_LED_PORT GPIOA
#define PIR_PIN GPIO_PIN_0
#define PIR_PORT GPIOA
UART_HandleTypeDef huart2;
TIM_HandleTypeDef htim3;
char uartBuffer[20];
uint8_t uartIndex = 0;
typedef enum {
SYSTEM_DISABLED,
SYSTEM_IDLE,
SYSTEM_ACTIVE
} SystemState;
SystemState currentState = SYSTEM_DISABLED;
uint32_t motionEndTime = 0;
uint32_t lastPIRCheck = 0;
uint8_t lastPIRState = 0;
uint32_t lastStatusBlink = 0;
uint8_t statusLedState = 0;
#define MOTION_TIMEOUT_MS 10000
#define STATUS_BLINK_INTERVAL 200
// ========== ТАЙМЕР TIM3 (явная настройка для отчёта) ==========
void MX_TIM3_Init(void) {
__HAL_RCC_TIM3_CLK_ENABLE();
htim3.Instance = TIM3;
htim3.Init.Prescaler = 7999; // 8 МГц / 8000 = 1000 Гц = 1 мс
htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
htim3.Init.Period = 0xFFFF;
htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
HAL_TIM_Base_Init(&htim3);
HAL_TIM_Base_Start(&htim3);
}
uint32_t GetSystemTick(void) {
return __HAL_TIM_GET_COUNTER(&htim3);
}
// ========== UART (опрос, без прерываний) ==========
void MX_USART2_UART_Init(void) {
__HAL_RCC_USART2_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef gpio = {0};
gpio.Mode = GPIO_MODE_AF_PP;
gpio.Pull = GPIO_PULLUP;
gpio.Speed = GPIO_SPEED_FREQ_LOW;
gpio.Alternate = GPIO_AF1_USART2;
gpio.Pin = GPIO_PIN_2 | GPIO_PIN_3;
HAL_GPIO_Init(GPIOA, &gpio);
huart2.Instance = USART2;
huart2.Init.BaudRate = 14400;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
HAL_UART_Init(&huart2);
}
// ========== GPIO ==========
void MX_GPIO_Init(void) {
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef gpio = {0};
gpio.Mode = GPIO_MODE_OUTPUT_PP;
gpio.Pull = GPIO_NOPULL;
gpio.Speed = GPIO_SPEED_FREQ_LOW;
gpio.Pin = EXT_LED_PIN;
HAL_GPIO_Init(EXT_LED_PORT, &gpio);
HAL_GPIO_WritePin(EXT_LED_PORT, EXT_LED_PIN, GPIO_PIN_RESET);
gpio.Pin = STATUS_LED_PIN;
HAL_GPIO_Init(STATUS_LED_PORT, &gpio);
HAL_GPIO_WritePin(STATUS_LED_PORT, STATUS_LED_PIN, GPIO_PIN_RESET);
gpio.Mode = GPIO_MODE_INPUT;
gpio.Pull = GPIO_PULLDOWN;
gpio.Pin = PIR_PIN;
HAL_GPIO_Init(PIR_PORT, &gpio);
}
// ========== ТАКТИРОВАНИЕ ==========
void SystemClock_Config(void) {
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSIDiv = RCC_HSI_DIV1;
HAL_RCC_OscConfig(&RCC_OscInitStruct);
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.SYSCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.AHBCLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_APB1_DIV1;
HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1);
}
// ========== SETUP ==========
void setup() {
HAL_Init();
SystemClock_Config();
MX_GPIO_Init();
MX_TIM3_Init(); // Явная инициализация таймера TIM3
MX_USART2_UART_Init();
char* msg = "Smart Lighting Ready. Commands: ON / OFF\r\n";
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), 1000);
}
// ========== LOOP ==========
void loop() {
uint32_t now = GetSystemTick(); // Используем наш таймер TIM3
// Приём UART (опрос)
char c;
if (HAL_UART_Receive(&huart2, (uint8_t*)&c, 1, 100) == HAL_OK) {
HAL_UART_Transmit(&huart2, (uint8_t*)&c, 1, 100);
if (c == '\r' || c == '\n') {
if (uartIndex > 0) {
uartBuffer[uartIndex] = '\0';
if (strcmp(uartBuffer, "ON") == 0 || strcmp(uartBuffer, "on") == 0) {
if (currentState == SYSTEM_DISABLED) {
currentState = SYSTEM_IDLE;
char* response = " -> System ENABLED\r\n";
HAL_UART_Transmit(&huart2, (uint8_t*)response, strlen(response), 1000);
} else {
char* response = " -> Already ENABLED\r\n";
HAL_UART_Transmit(&huart2, (uint8_t*)response, strlen(response), 1000);
}
}
else if (strcmp(uartBuffer, "OFF") == 0 || strcmp(uartBuffer, "off") == 0) {
if (currentState != SYSTEM_DISABLED) {
currentState = SYSTEM_DISABLED;
HAL_GPIO_WritePin(EXT_LED_PORT, EXT_LED_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(STATUS_LED_PORT, STATUS_LED_PIN, GPIO_PIN_RESET);
char* response = " -> System DISABLED\r\n";
HAL_UART_Transmit(&huart2, (uint8_t*)response, strlen(response), 1000);
} else {
char* response = " -> Already DISABLED\r\n";
HAL_UART_Transmit(&huart2, (uint8_t*)response, strlen(response), 1000);
}
}
else {
char* response = " -> Unknown command\r\n";
HAL_UART_Transmit(&huart2, (uint8_t*)response, strlen(response), 1000);
}
uartIndex = 0;
}
} else if (uartIndex < 19) {
uartBuffer[uartIndex++] = c;
}
}
// Опрос PIR
if (now - lastPIRCheck >= 50) {
lastPIRCheck = now;
uint8_t currentPIRState = HAL_GPIO_ReadPin(PIR_PORT, PIR_PIN);
if (currentPIRState == GPIO_PIN_SET && lastPIRState == GPIO_PIN_RESET) {
if (currentState == SYSTEM_IDLE) {
currentState = SYSTEM_ACTIVE;
HAL_GPIO_WritePin(EXT_LED_PORT, EXT_LED_PIN, GPIO_PIN_SET);
char* msg = "[PIR] Motion detected! LED ON\r\n";
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), 1000);
}
}
if (currentPIRState == GPIO_PIN_SET && currentState == SYSTEM_ACTIVE) {
motionEndTime = now + MOTION_TIMEOUT_MS;
}
lastPIRState = currentPIRState;
}
// Таймаут движения
if (currentState == SYSTEM_ACTIVE && now >= motionEndTime) {
currentState = SYSTEM_IDLE;
HAL_GPIO_WritePin(EXT_LED_PORT, EXT_LED_PIN, GPIO_PIN_RESET);
char* msg = "[PIR] Timeout. LED OFF\r\n";
HAL_UART_Transmit(&huart2, (uint8_t*)msg, strlen(msg), 1000);
}
// Статусный светодиод
switch (currentState) {
case SYSTEM_DISABLED:
HAL_GPIO_WritePin(STATUS_LED_PORT, STATUS_LED_PIN, GPIO_PIN_RESET);
break;
case SYSTEM_IDLE:
HAL_GPIO_WritePin(STATUS_LED_PORT, STATUS_LED_PIN, GPIO_PIN_SET);
break;
case SYSTEM_ACTIVE:
if (now - lastStatusBlink >= STATUS_BLINK_INTERVAL) {
lastStatusBlink = now;
statusLedState = !statusLedState;
HAL_GPIO_WritePin(STATUS_LED_PORT, STATUS_LED_PIN,
statusLedState ? GPIO_PIN_SET : GPIO_PIN_RESET);
}
break;
}
}