/**
******************************************************************************
* @file : main.c
* @author : Auto-generated by STM32CubeIDE
* @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.
*
******************************************************************************
*/
#include <stdint.h>
#include "stm32f103xb.h"
// Función para retardos (ajustada para el reloj interno por defecto)
void delay_ms(uint16_t t) {
volatile unsigned long l;
for(uint16_t i = 0; i < t; i++)
for(l = 0; l < 6000; l++) { }
}
int main() {
// 1. Habilitar relojes para Puerto A y Puerto B (Registro APB2ENR)
// Bit 2: IOPA, Bit 3: IOPB. 0x0C habilita ambos.
RCC->APB2ENR |= 0x0C;
// 2. Configuración de GPIOA (Pines PA0 a PA7)
// PA0 y PA1: Entradas con Pull-up/down (Modo 1000b = 8 hex)
// PA2 a PA7: Salidas 50MHz para el display (Modo 0011b = 3 hex)
// Registro CRL = 0x33333388
GPIOA->CRL = 0x33333388;
// 3. Configuración de GPIOA (Pin PA8 para el segmento 'g' del display)
// PA8: Salida 50MHz (Modo 0011b = 3 hex)
// Registro CRH: los primeros 4 bits controlan el pin 8
GPIOA->CRH = (GPIOA->CRH & 0xFFFFFFF0) | 0x00000003;
// 4. Configurar Pull-down en PA0 y PA1
// Para pull-down, los bits correspondientes en ODR deben ser 0
GPIOA->ODR &= ~((1 << 0) | (1 << 1));
// 5. Configuración de GPIOB (PB0 y PB1 para el Puente H)
// PB0 y PB1: Salidas 50MHz (Modo 0011b = 3 hex)
GPIOB->CRL = (GPIOB->CRL & 0xFFFFFF00) | 0x00000033;
// Variables de estado
uint8_t motor_on = 0; // 0: Stop, 1: Run
uint8_t motor_dir = 0; // 0: Izquierda, 1: Derecha
while(1) {
// --- BOTÓN RUN / STOP (PA1) ---
if (GPIOA->IDR & (1 << 1)) { // Si PA1 es ALTO
delay_ms(20); // Antirrebote (Debounce)
if (GPIOA->IDR & (1 << 1)) {
motor_on = !motor_on; // Cambia estado de marcha
while(GPIOA->IDR & (1 << 1)); // Espera a que suelte el botón
}
}
// --- BOTÓN DIRECCIÓN (PA0) ---
if (GPIOA->IDR & (1 << 0)) { // Si PA0 es ALTO
delay_ms(20); // Antirrebote
if (GPIOA->IDR & (1 << 0)) {
// REQUISITO: DEAD TIME de 10ms al cambiar dirección
GPIOB->ODR &= ~0x03; // Apaga motor (PB0 y PB1 a 0)
delay_ms(10); // Espera de seguridad
motor_dir = !motor_dir; // Cambia sentido de giro
while(GPIOA->IDR & (1 << 0)); // Espera a que suelte
}
}
// --- LÓGICA DE SALIDAS (MOTOR Y DISPLAY) ---
if (!motor_on) {
// ESTADO: STOP
GPIOB->ODR &= ~0x03; // Motor apagado
// Mostrar 'S' (a,c,d,f,g encendidos -> 0x6D)
// Desplazamos 2 bits porque el display empieza en PA2
GPIOA->ODR = (GPIOA->ODR & 0xFE03) | (0x6D << 2);
}
else {
if (motor_dir == 0) {
// ESTADO: IZQUIERDA (L)
GPIOB->ODR = (GPIOB->ODR & ~0x02) | 0x01; // PB1=0, PB0=1
// Mostrar 'L' (d,e,f encendidos -> 0x38)
GPIOA->ODR = (GPIOA->ODR & 0xFE03) | (0x38 << 2);
}
else {
// ESTADO: DERECHA (R)
GPIOB->ODR = (GPIOB->ODR & ~0x01) | 0x02; // PB0=0, PB1=1
// Mostrar 'r' (e,g encendidos -> 0x50)
GPIOA->ODR = (GPIOA->ODR & 0xFE03) | (0x50 << 2);
}
}
}
}