#include <stdio.h>
#include <string.h>
#include <stm32c0xx_hal.h>
#include <stdlib.h> // Para rand()
/* Definições de Hardware */
#define BTN_P1_PIN GPIO_PIN_0 // Botão do jogador 1 (PA0)
#define BTN_P1_PORT GPIOA
#define LED_P1_PIN GPIO_PIN_5 // LED do jogador 1 (PA5) - VERMELHO
#define LED_P1_PORT GPIOA
#define BTN_P2_PIN GPIO_PIN_1 // Botão do jogador 2 (PA1)
#define BTN_P2_PORT GPIOA
#define LED_P2_PIN GPIO_PIN_6 // LED do jogador 2 (PA6) - VERDE
#define LED_P2_PORT GPIOA
// Estados do jogo
typedef enum {
GAME_IDLE, // wait início do game
GAME_ANIMATION, // Animação inicial
GAME_RUNNING, // Jogo em andamento
GAME_ENDED, // Jogo terminado
GAME_RESET // exibi resultado
} GameState;
// Variáveis do jogo
volatile GameState gameState = GAME_IDLE; // define qual o estado atual do jogo
volatile uint32_t scorePlayer1 = 0; //
volatile uint32_t scorePlayer2 = 0;
volatile uint8_t winner = 0; // 0: empate, 1: jogador1, 2: jogador2
uint32_t gameTime = 0; // time do jogo interno
uint32_t gameStartTime = 0; // tempo para iniciar a partida
// Variáveis para debounce na interrupção
volatile uint32_t lastInterruptTimeP1 = 0;
volatile uint32_t lastInterruptTimeP2 = 0;
const uint32_t DEBOUNCE_DELAY = 150; // ms
// Protótipos
void SystemClock_Config(void);
void GPIO_Init(void);
void startGame(void);
void endGame(void);
void resetGame(void);
void showWinner(void);
void updateAnimation(void);
void updateGame(void);
// Chamada automaticamente quando um botão é pressionado
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
uint32_t currentTime = HAL_GetTick();
printf("[INTERRUPÇÃO]\n");
// Lógica para Botão 1
if (GPIO_Pin == BTN_P1_PIN) {
printf("[1 BOTÃO]\n");
// Debounce via Software
if ((currentTime - lastInterruptTimeP1) < DEBOUNCE_DELAY) return;
lastInterruptTimeP1 = currentTime;
if (gameState == GAME_IDLE) {
startGame();
} else if (gameState == GAME_RUNNING) {
scorePlayer1++;
} else if (gameState == GAME_ANIMATION || gameState == GAME_ENDED) {
// Penalidade: Apertou fora de hora
winner = 2; // P2 ganha
gameState = GAME_ENDED;
endGame();
}
}
// Lógica para Botão 2
else if (GPIO_Pin == BTN_P2_PIN) {
printf("[2 BOTÃO]\n");
// Debounce via Software
if ((currentTime - lastInterruptTimeP2) < DEBOUNCE_DELAY) return;
lastInterruptTimeP2 = currentTime;
if (gameState == GAME_IDLE) {
startGame();
} else if (gameState == GAME_RUNNING) {
scorePlayer2++;
} else if (gameState == GAME_ANIMATION || gameState == GAME_ENDED) {
// Penalidade: Apertou fora de hora
winner = 1; // P1 ganha
gameState = GAME_ENDED;
endGame();
}
}
}
int main(void) {
HAL_Init();
SystemClock_Config();
GPIO_Init();
// Teste inicial - indicação de boot
HAL_GPIO_WritePin(LED_P1_PORT, LED_P1_PIN, GPIO_PIN_SET);
HAL_Delay(300);
HAL_GPIO_WritePin(LED_P1_PORT, LED_P1_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED_P2_PORT, LED_P2_PIN, GPIO_PIN_SET);
HAL_Delay(300);
HAL_GPIO_WritePin(LED_P2_PORT, LED_P2_PIN, GPIO_PIN_RESET);
resetGame();
while (1) {
uint32_t currentTime = HAL_GetTick();
// Loop principal apenas gerencia ESTADOS e TEMPO.
// A leitura de botões foi removida daqui e está no Callback acima.
switch (gameState) {
case GAME_ANIMATION:
updateAnimation();
break;
case GAME_RUNNING:
updateGame();
break;
case GAME_ENDED:
if (currentTime - gameStartTime > 2000) {
showWinner();
gameState = GAME_RESET;
gameStartTime = currentTime;
}
break;
case GAME_RESET:
if (currentTime - gameStartTime > 3000) {
resetGame();
}
break;
case GAME_IDLE:
default:
// Pisca Leds lentamente para indicar que está vivo/esperando
HAL_GPIO_TogglePin(LED_P1_PORT, LED_P1_PIN);
HAL_GPIO_TogglePin(LED_P2_PORT, LED_P2_PIN);
HAL_Delay(500);
break;
}
}
}
void SystemClock_Config(void) {
RCC_OscInitTypeDef osc = {0};
RCC_ClkInitTypeDef clk = {0};
osc.OscillatorType = RCC_OSCILLATORTYPE_HSI;
osc.HSIState = RCC_HSI_ON;
osc.HSIDiv = RCC_HSI_DIV1;
osc.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
HAL_RCC_OscConfig(&osc);
clk.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1;
clk.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
clk.AHBCLKDivider = RCC_SYSCLK_DIV1;
clk.APB1CLKDivider = RCC_HCLK_DIV1;
HAL_RCC_ClockConfig(&clk, FLASH_LATENCY_0);
}
void GPIO_Init(void) {
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_InitTypeDef gpio = {0};
// LEDs como saída
gpio.Pin = LED_P1_PIN | LED_P2_PIN;
gpio.Mode = GPIO_MODE_OUTPUT_PP;
gpio.Pull = GPIO_NOPULL;
gpio.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &gpio);
// Botões como INTERRUPÇÃO (Falling Edge) com pull-up
gpio.Pin = BTN_P1_PIN | BTN_P2_PIN;
gpio.Mode = GPIO_MODE_IT_FALLING; // Mudança: Input -> Interrupt Falling
gpio.Pull = GPIO_PULLUP;
gpio.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &gpio);
// Habilita Interrupções no NVIC
// No STM32C031, PA0 e PA1 compartilham a linha EXTI0_1
HAL_NVIC_SetPriority(EXTI0_1_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);
}
void startGame(void) {
// Só inicia se estiver IDLE
if(gameState != GAME_IDLE) return;
gameState = GAME_ANIMATION;
scorePlayer1 = 0;
scorePlayer2 = 0;
winner = 0;
gameStartTime = HAL_GetTick();
// Garante LEDs apagados antes da animação
HAL_GPIO_WritePin(LED_P1_PORT, LED_P1_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED_P2_PORT, LED_P2_PIN, GPIO_PIN_RESET);
}
void updateAnimation(void) {
uint32_t currentTime = HAL_GetTick();
uint32_t elapsed = currentTime - gameStartTime;
if (elapsed >= 1000) { // Fim da animação
gameState = GAME_RUNNING;
gameStartTime = currentTime;
// Define tempo de jogo (3 a 8 segundos)
gameTime = 3000 + (rand() % 5000);
// Acende LEDs fixos para indicar VALENDO!
HAL_GPIO_WritePin(LED_P1_PORT, LED_P1_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(LED_P2_PORT, LED_P2_PIN, GPIO_PIN_SET);
} else {
// Pisca rápido durante animação
if ((elapsed / 100) % 2 == 0) {
HAL_GPIO_WritePin(LED_P1_PORT, LED_P1_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(LED_P2_PORT, LED_P2_PIN, GPIO_PIN_RESET);
} else {
HAL_GPIO_WritePin(LED_P1_PORT, LED_P1_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED_P2_PORT, LED_P2_PIN, GPIO_PIN_SET);
}
}
}
void updateGame(void) {
uint32_t currentTime = HAL_GetTick();
uint32_t elapsed = currentTime - gameStartTime;
if (elapsed >= gameTime) {
gameState = GAME_ENDED;
endGame();
}
}
void endGame(void) {
gameStartTime = HAL_GetTick();
if (winner == 0) {
if (scorePlayer1 > scorePlayer2) winner = 1;
else if (scorePlayer2 > scorePlayer1) winner = 2;
// else empate (0)
}
HAL_GPIO_WritePin(LED_P1_PORT, LED_P1_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED_P2_PORT, LED_P2_PIN, GPIO_PIN_RESET);
}
void showWinner(void) {
if (winner == 1) {
HAL_GPIO_WritePin(LED_P1_PORT, LED_P1_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(LED_P2_PORT, LED_P2_PIN, GPIO_PIN_RESET);
} else if (winner == 2) {
HAL_GPIO_WritePin(LED_P1_PORT, LED_P1_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED_P2_PORT, LED_P2_PIN, GPIO_PIN_SET);
} else {
HAL_GPIO_WritePin(LED_P1_PORT, LED_P1_PIN, GPIO_PIN_SET);
HAL_GPIO_WritePin(LED_P2_PORT, LED_P2_PIN, GPIO_PIN_SET);
}
}
void resetGame(void) {
gameState = GAME_IDLE;
scorePlayer1 = 0;
scorePlayer2 = 0;
winner = 0;
gameTime = 0;
HAL_GPIO_WritePin(LED_P1_PORT, LED_P1_PIN, GPIO_PIN_RESET);
HAL_GPIO_WritePin(LED_P2_PORT, LED_P2_PIN, GPIO_PIN_RESET);
}Loading
st-nucleo-c031c6
st-nucleo-c031c6