/**
******************************************************************************
* @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"
#include "stm32f103_hal.h"
#include "lcd.h"
void delay_ms(uint16_t ms);
void delay_us(uint16_t us);
const lcd_cfg_t lcd_cfg = {
.interface=LCD_INTERFACE_4BIT,
.timing=LCD_TIMING_DELAY
};
int main(void)
{
//activo los tres sets de pines
rcc_clock_enable(RCC_GPIOA);
rcc_clock_enable(RCC_GPIOB);
// Botón 1 para avanzar en PB0
gpio_set_input(GPIOB, 0, GPIO_INPUT_PUP);
// Botón 2 para seleccionar en PB1
gpio_set_input(GPIOB, 1, GPIO_INPUT_PUP);
LCD_Init(&lcd_cfg);
LCD_SetCursor(0, 0);
uint8_t cursor_pos = 0; //cuando cursor_pos=0, fila 1 seleccionada; cuando cursor_pos=1 fila 2 seleccionada
uint8_t motor_status = 0; // 0 = stop, 1 = run
uint8_t motor_dir = 0; // 0 = left, 1 = right
LCD_Send(LCD_CMD_CLEAR, LCD_MODE_CMD);
delay_ms(500);
while ( 1 )
{
//reviso si se presionó el botón de selección e invierto el valor que contiene
if ((GPIOB->IDR & (1 << 0)) == 0){
delay_ms(50);
if (cursor_pos == 0) {
cursor_pos = 1;
} else {
cursor_pos = 0;
}
LCD_Send(LCD_CMD_CLEAR, LCD_MODE_CMD);
while ((GPIOB->IDR & (1 << 0)) == 0);
}
//evaluamos ahora el botón de acción, pero siempre confirmando dónde se encuentra el cursor
if((GPIOB->IDR & (1<<1)) == 0){
delay_ms(50); // Anti-rebote
if (cursor_pos == 0) {
motor_status = !motor_status; // Invertimos estado (0 a 1, o 1 a 0)
} else if (cursor_pos == 1) {
motor_dir = !motor_dir; // Invertimos dirección
}
// Esperamos a que suelten el botón
while ((GPIOB->IDR & (1 << 1)) == 0);
}
//Escribo en el display de acuerdo a la posición del cursor y los estados actuales.
LCD_SetCursor(0, 0);
//Si me encuentro en la fila 1, entonces las alteraciones posibles serían run/stop.
if(cursor_pos == 0) {
LCD_Print(">");
} else {
LCD_Print(" ");
}
LCD_Print("Status: ");
if(motor_status == 1) {
LCD_Print("Run ");
} else {
LCD_Print("Stop");
}
LCD_SetCursor(0, 1);
//Si me encuentro en la fila 2, entonces las alteraciones posibles serían left/right.
if(cursor_pos == 1) {
LCD_Print(">");
} else {
LCD_Print(" ");
}
LCD_Print("Dir: ");
if(motor_dir == 1) {
LCD_Print("Right");
} else {
LCD_Print("Left ");
}
}
}
void delay_ms(uint16_t ms) {
volatile unsigned long t = 0;
for(uint16_t i = 0; i < ms; i++)
{
for(t = 0; t < 800; t++);
}
}
void delay_us(uint16_t us)
{
for (volatile unsigned int cycles = 0; cycles < us; cycles++);
}