#include "stm32f103xb.h"
#include <stdint.h>
// ===============================================================================
// 1. FUNCIÓN DE DELAY (Bucle simple para evitar errores de compilación)
// ===============================================================================
void Delay_ms(uint32_t time)
{
// Ciclo aproximado: 1ms = ~4000 ciclos a 72MHz
for(uint32_t i = 0; i < time * 4000; i++)
{
; // Bucle vacío
}
}
// ===============================================================================
// 2. FUNCIÓN PRINCIPAL
// ===============================================================================
int main(void)
{
// ---------------------------------------------------------------------------
// A. HABILITACIÓN DE RELOJES Y CORRECCIÓN DE PINES JTAG
// ---------------------------------------------------------------------------
// 1. Habilitar reloj para Puertos A, B y AFIO (¡AFIO es CRÍTICO para el display!)
RCC->APB2ENR |= (1 << 2); // Puerto A
RCC->APB2ENR |= (1 << 3); // Puerto B
RCC->APB2ENR |= (1 << 0); // AFIO (Funciones Alternativas)
// 2. DESHABILITAR JTAG PARA LIBERAR PB3 Y PB4
// Esto "desconecta" el depurador de esos pines y te deja usarlos para el display.
// Escribimos '010' en los bits SWJ_CFG (bits 24-26) del registro MAPR.
AFIO->MAPR &= ~(7 << 24); // Limpiamos bits 24, 25, 26
AFIO->MAPR |= (2 << 24); // Configuramos modo: JTAG-Disable, SWD-Enable
// ---------------------------------------------------------------------------
// B. CONFIGURACIÓN DE PINES (GPIO)
// ---------------------------------------------------------------------------
// --- PUERTO A (Motor y Botones) ---
// PA0, PA1: Salidas (Motor)
GPIOA->CRL &= ~(15 << 0); GPIOA->CRL |= (2 << 0);
GPIOA->CRL &= ~(15 << 4); GPIOA->CRL |= (2 << 4);
// PA2, PA3: Entradas con Pull-Down (Botones)
// Se asume que el botón conecta 3.3V al pin cuando se presiona.
GPIOA->CRL &= ~(15 << 8); GPIOA->CRL |= (8 << 8); // PA2: Input Pull-up/down
GPIOA->ODR &= ~(1 << 2); // ODR=0 -> Pull-Down
GPIOA->CRL &= ~(15 << 12); GPIOA->CRL |= (8 << 12); // PA3: Input Pull-up/down
GPIOA->ODR &= ~(1 << 3); // ODR=0 -> Pull-Down
// --- PUERTO B (Display 7 Segmentos) ---
// Mapeo corregido: a=PB0, b=PB1, d=PB3, e=PB4, f=PB5, g=PB6, c=PB7 (Saltamos PB2)
GPIOB->CRL &= ~(15 << 0); GPIOB->CRL |= (2 << 0); // PB0 (a)
GPIOB->CRL &= ~(15 << 4); GPIOB->CRL |= (2 << 4); // PB1 (b)
// PB3 y PB4 ahora funcionarán gracias al bloque AFIO de arriba
GPIOB->CRL &= ~(15 << 12); GPIOB->CRL |= (2 << 12); // PB3 (d)
GPIOB->CRL &= ~(15 << 16); GPIOB->CRL |= (2 << 16); // PB4 (e)
GPIOB->CRL &= ~(15 << 20); GPIOB->CRL |= (2 << 20); // PB5 (f)
GPIOB->CRL &= ~(15 << 24); GPIOB->CRL |= (2 << 24); // PB6 (g)
GPIOB->CRL &= ~(15 << 28); GPIOB->CRL |= (2 << 28); // PB7 (c)
// ---------------------------------------------------------------------------
// C. VARIABLES DE ESTADO
// ---------------------------------------------------------------------------
int estado = 0; // 0: STOP, 1: DERECHA, 2: IZQUIERDA
int direccion_sig = 1; // Memoria: 1 (Derecha) por defecto
// ---------------------------------------------------------------------------
// D. BUCLE INFINITO
// ---------------------------------------------------------------------------
while(1)
{
// === 1. CONTROL DE SALIDAS ===
if (estado == 0) // STOP
{
GPIOA->ODR &= ~(3 << 0); // Apagar Motor (PA0, PA1)
// Mostrar 'S' completa (a,c,d,f,g)
// Pines: PB0, PB7, PB3, PB5, PB6. (PB3 ya funciona).
// Valor Decimal: 233
GPIOB->ODR = (GPIOB->ODR & 65280) | 233;
}
else if (estado == 1) // DERECHA
{
GPIOA->ODR &= ~(1 << 1); // Apagar Izq
GPIOA->ODR |= (1 << 0); // Prender Der
// Mostrar 'R' (e,g) -> PB4, PB6
// Valor Decimal: 80
GPIOB->ODR = (GPIOB->ODR & 65280) | 80;
}
else if (estado == 2) // IZQUIERDA
{
GPIOA->ODR &= ~(1 << 0); // Apagar Der
GPIOA->ODR |= (1 << 1); // Prender Izq
// Mostrar 'L' (d,e,f) -> PB3, PB4, PB5
// Valor Decimal: 56
GPIOB->ODR = (GPIOB->ODR & 65280) | 56;
}
// === 2. CONTROL DE ENTRADAS (BOTONES) ===
// --- BOTÓN RUN / STOP (PA3) ---
// Verifica si hay voltaje (3.3V) en el pin
if ((GPIOA->IDR & (1 << 3)) != 0)
{
Delay_ms(20); // Anti-rebote
// Verifica de nuevo para asegurar que no fue ruido
if ((GPIOA->IDR & (1 << 3)) != 0)
{
if (estado == 0) {
estado = direccion_sig; // Arrancar
} else {
estado = 0; // Parar
}
// Esperar a que el usuario SUELTE el botón para no ciclarse
while((GPIOA->IDR & (1 << 3)) != 0);
}
}
// --- BOTÓN CAMBIO DE DIRECCIÓN (PA2) ---
// Verifica si hay voltaje (3.3V) en el pin
if ((GPIOA->IDR & (1 << 2)) != 0)
{
Delay_ms(20);
if ((GPIOA->IDR & (1 << 2)) != 0)
{
// Seguridad: Si se mueve, parar primero
if (estado != 0) {
estado = 0;
GPIOA->ODR &= ~(3 << 0);
Delay_ms(10);
}
// Cambiar memoria
if (direccion_sig == 1) direccion_sig = 2;
else direccion_sig = 1;
// Re-arranque automático
estado = direccion_sig;
// Esperar a soltar
while((GPIOA->IDR & (1 << 2)) != 0);
}
}
}
}