#include "stm32f103xb.h"
#include <stdint.h>
// Función de retardo simple
void Delay_ms(uint32_t time)
{
// Ajustado para simulación y hardware real
for(uint32_t i = 0; i < time * 4000; i++)
{
// Instrucción vacía para consumir tiempo
__NOP();
}
}
int main(void)
{
// =========================================================
// 1. CONFIGURACIÓN INICIAL (SETUP)
// =========================================================
// Habilitar Relojes: Puerto A (Bit 2), Puerto B (Bit 3) y AFIO (Bit 0)
RCC->APB2ENR |= (1 << 2) | (1 << 3) | (1 << 0);
// DESHABILITAR JTAG para liberar PB3 y PB4
// Esto es CRÍTICO para que el display funcione bien
AFIO->MAPR &= ~(7 << 24); // Limpiar bits SWJ_CFG
AFIO->MAPR |= (2 << 24); // Modo: JTAG-Disable, SWD-Enable
// --- CONFIGURAR PUERTO A (Motor y Botones) ---
// PA0 y PA1: SALIDAS (Motor)
// Mode=10 (Output 2MHz), CNF=00 (Push-Pull) -> 0x2
GPIOA->CRL &= ~(0xFF); // Limpiar configuración PA0, PA1
GPIOA->CRL |= 0x22; // Configurar PA0 y PA1 como Salida
// PA2 y PA3: ENTRADAS (Botones)
// Mode=00 (Input), CNF=10 (Pull-up/down) -> 0x8
GPIOA->CRL &= ~(0xFF00); // Limpiar configuración PA2, PA3
GPIOA->CRL |= 0x8800; // Configurar PA2 y PA3 como Entrada con Pull
// Configurar Pull-Down (ODR=0) para PA2 y PA3
// Esto asegura que lean 0V si no se presionan
GPIOA->ODR &= ~((1 << 2) | (1 << 3));
// --- CONFIGURAR PUERTO B (Display) ---
// PB0 a PB7: SALIDAS (Display 7 segmentos)
// Configuramos todo el registro bajo como salida push-pull 2MHz
GPIOB->CRL = 0x22222222;
// =========================================================
// 2. VARIABLES DE ESTADO
// =========================================================
int estado = 0; // 0: STOP, 1: DERECHA, 2: IZQUIERDA
int memoria = 1; // 1: Derecha, 2: Izquierda (Por defecto Derecha)
// =========================================================
// 3. BUCLE INFINITO
// =========================================================
while(1)
{
// -----------------------------------------------------
// PARTE A: CONTROL DE SALIDAS
// -----------------------------------------------------
if (estado == 0) // STOP
{
// Apagar Motor: PA0=0, PA1=0
GPIOA->ODR &= ~(3);
// Display 'S': Encender segmentos a,c,d,f,g (PB0,7,3,5,6)
// Valor decimal: 233
// Usamos una máscara (0xFF00) para no borrar los pines PB8-15
GPIOB->ODR = (GPIOB->ODR & 0xFF00) | 233;
}
else if (estado == 1) // DERECHA
{
// Motor Derecha: PA0=1, PA1=0
GPIOA->ODR |= (1 << 0);
GPIOA->ODR &= ~(1 << 1);
// Display 'R': Segmentos e,g (PB4, PB6)
// Valor decimal: 80
GPIOB->ODR = (GPIOB->ODR & 0xFF00) | 80;
}
else if (estado == 2) // IZQUIERDA
{
// Motor Izquierda: PA0=0, PA1=1
GPIOA->ODR &= ~(1 << 0);
GPIOA->ODR |= (1 << 1);
// Display 'L': Segmentos d,e,f (PB3,4,5)
// Valor decimal: 56
GPIOB->ODR = (GPIOB->ODR & 0xFF00) | 56;
}
// -----------------------------------------------------
// PARTE B: LEER BOTONES
// -----------------------------------------------------
// --- BOTÓN RUN/STOP (PA3) ---
// Verificamos si el bit 3 del registro de entrada (IDR) es 1
if ((GPIOA->IDR & (1 << 3)) != 0)
{
Delay_ms(20); // Anti-rebote
// Confirmamos si sigue presionado
if ((GPIOA->IDR & (1 << 3)) != 0)
{
if (estado == 0) {
estado = memoria; // Arrancar
} else {
estado = 0; // Parar
}
// Esperar a soltar el botón
while((GPIOA->IDR & (1 << 3)) != 0);
}
}
// --- BOTÓN CAMBIO DE DIRECCIÓN (PA2) ---
// Verificamos si el bit 2 del registro de entrada (IDR) es 1
if ((GPIOA->IDR & (1 << 2)) != 0)
{
Delay_ms(20); // Anti-rebote
// Confirmamos si sigue presionado
if ((GPIOA->IDR & (1 << 2)) != 0)
{
// TIEMPO MUERTO: Si se mueve, parar primero
if (estado != 0)
{
estado = 0;
GPIOA->ODR &= ~(3); // Apagar motor ya
// Esperar 20ms para proteger transistores (Requisito >10ms)
Delay_ms(20);
}
// Cambiar memoria
if (memoria == 1) memoria = 2;
else memoria = 1;
// Re-arranque automático
estado = memoria;
// Esperar a soltar el botón
while((GPIOA->IDR & (1 << 2)) != 0);
}
}
}
}