/**
******************************************************************************
* @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 "stm32f103xb.h"
// ================= SEGMENTOS =================
#define SEG_A 0 // PA0
#define SEG_B 1 // PA1
#define SEG_C 8 // PB8
#define SEG_D 0 // PB0
#define SEG_E 1 // PB1
#define SEG_F 3 // PB3
#define SEG_G 4 // PB4
// ================= MOTOR =====================
#define IN1 10 // PB10
#define IN2 11 // PB11
// ================= BOTONES ===================
#define BTN_RUN 2 // PA2
#define BTN_DIR 3 // PA3
// ================= ESTADOS ===================
typedef enum {
STOP,
RIGHT,
LEFT
} motor_state_t;
motor_state_t current_state = STOP;
motor_state_t direction = RIGHT;
// ================= DELAY =====================
void delay_ms(uint16_t t)
{
for(uint16_t i = 0; i < t; i++)
for(volatile uint32_t j = 0; j < 8000; j++);
}
// ================= MOTOR =====================
void motor_stop(void)
{
GPIOB->ODR &= ~(1<<IN1);
GPIOB->ODR &= ~(1<<IN2);
}
void motor_right(void)
{
GPIOB->ODR |= (1<<IN1);
GPIOB->ODR &= ~(1<<IN2);
}
void motor_left(void)
{
GPIOB->ODR &= ~(1<<IN1);
GPIOB->ODR |= (1<<IN2);
}
// ================= DISPLAY =================== anodo comun
void display_off(void)
{
GPIOA->ODR |= (1<<SEG_A) | (1<<SEG_B) | (1<<SEG_C);
GPIOB->ODR |= (1<<SEG_D) | (1<<SEG_E) | (1<<SEG_F) | (1<<SEG_G);
}
// S STOP
void display_S(void)
{
display_off();
GPIOA->ODR &= ~(1<<SEG_A);
GPIOB->ODR &= ~(1<<SEG_C);
GPIOB->ODR &= ~(1<<SEG_D);
GPIOB->ODR &= ~(1<<SEG_F);
GPIOB->ODR &= ~(1<<SEG_G);
}
// R RIGHT
void display_R(void)
{
display_off();
GPIOA->ODR &= ~(1<<SEG_A);
GPIOA->ODR &= ~(1<<SEG_B);
GPIOB->ODR &= ~(1<<SEG_E);
GPIOB->ODR &= ~(1<<SEG_F);
GPIOB->ODR &= ~(1<<SEG_G);
}
// LEFT
void display_L(void)
{
display_off();
GPIOB->ODR &= ~(1<<SEG_C);
GPIOB->ODR &= ~(1<<SEG_D);
GPIOB->ODR &= ~(1<<SEG_E);
GPIOB->ODR &= ~(1<<SEG_F);
}
// ================= MAIN ======================
int main(void)
{
// ----- CLOCKS -----
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;
RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
// ----- DISPLAY OUTPUTS -----
// PA0 y PA1 (Segmentos A y B)
GPIOA->CRL &= ~((0xF << 0) | (0xF << 4));
GPIOA->CRL |= ((0x2 << 0) | (0x2 << 4));
// PB8 (Segmento C)
GPIOB->CRH &= ~(0xF << 0);
GPIOB->CRH |= (0x2 << 0);
//------Puertos B
//PB0, PB1, PB3, PB4
GPIOB->CRL &= ~((0xF << 0) | (0xF << 4) | (0xF << 12) | (0xF << 16));
GPIOB->CRL |= ((0x2 << 0) | (0x2 << 4) | (0x2 << 12) | (0x2 << 16));
// ----- MOTOR OUTPUTS ----- // IN1 = B10 IN2 = B11 (Push-Pull 2 mHz)
GPIOB->CRH &= ~(GPIO_CRH_MODE10 | GPIO_CRH_CNF10 |
GPIO_CRH_MODE11 | GPIO_CRH_CNF11);
GPIOB->CRH |= GPIO_CRH_MODE10_0 | GPIO_CRH_MODE11_0;
// ----- BOTONES INPUT PULL-DOWN -----
GPIOA->CRL &= ~(GPIO_CRL_MODE2 | GPIO_CRL_CNF2 |
GPIO_CRL_MODE3 | GPIO_CRL_CNF3);
GPIOA->CRL |= GPIO_CRL_CNF2_1 | GPIO_CRL_CNF3_1;
GPIOA->ODR &= ~((1<<BTN_RUN) | (1<<BTN_DIR));
// ----- ESTADO INICIAL -----
motor_stop();
display_S();
while(1)
{
// ===== RUN / STOP =====
if(GPIOA->IDR & (1<<BTN_RUN)) //si el botón está presionado
{
delay_ms(20); // debounce
while(GPIOA->IDR & (1<<BTN_RUN));
if(current_state == STOP)
{
motor_stop();
delay_ms(10);
if(direction == RIGHT)
{
motor_right();
display_R();
current_state = RIGHT;
}
else
{
motor_left();
display_L();
current_state = LEFT;
}
}
else
{
motor_stop();
display_S();
current_state = STOP;
}
}
// ===== CAMBIO DE DIRECCIÓN =====
if(GPIOA->IDR & (1<<BTN_DIR))
{
delay_ms(20);
while(GPIOA->IDR & (1<<BTN_DIR)); //si el botón está presionado
direction = (direction == RIGHT) ? LEFT : RIGHT;
if(current_state != STOP)
{
motor_stop();
delay_ms(10);
if(direction == RIGHT)
{
motor_right();
display_R();
current_state = RIGHT;
}
else
{
motor_left();
display_L();
current_state = LEFT;
}
}
}
}
}