/**
******************************************************************************
* @file : main.c
* @author : Auto-generated by STM32CubeIDE
* @brief : Main program body
******************************************************************************
*
* 3. Realice un programa para controlar la velocidad
* de rotación de un motor de DC con PWM.
* a. Para ello deberá configurar un timer para
* generar una señal cuadrada de 10 kHz en un
* pin del timer usando Output Compare.
* b. Su sistema deberá tener dos botones:
* i. Botón UP: Permite subir la velocidad
* ii. Botón DOWN: Permite bajar la velocidad
*
* En este repositorio se encuentra el componente de
* puente H y motor DC con salida de encoder.
*
* El puente H tiene tres entradas:
* - IN1: Entrada de control 1 de puente H
* - IN2: Entrada de control 2 de puente H
* - ENA: Señal de PWM
*
* A fin de elegir el sentido de giro se debe de establecer un nivel logico en
* las señales IN1 e IN2, acorde a la tabla siguiente:
*
* IN1 IN2 | DIR
* --------|---------
* 1 0 | Forward
* 0 1 | Backward
* 0 0 | Stop
* 1 1 | Prohibido
*
* Asi mismo, para controlar la velocidad del motor, se
* debe de generar una señal de PWM de 10kHz, y el ciclo
* de trabajo establecera la velocidad de giro.
*
* El motor tiene 2 salidas:
* QA: Salida de cuadratura A
* QB: Salida de cuadratura B
*
* Estas no se utilizan para este ejercicio.
******************************************************************************
*/
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h> // Necesario para el 'true' en timer_set_oc_channel
#include "stm32f103_hal.h"
#include "lcd.h"
// Variables Globales
volatile int16_t velocidad_motor = 0; // De 0 a 100 (%)
// Funciones requeridas por lcd.c
void delay_ms(uint16_t ms) {
for (uint16_t i = 0; i < ms; i++) {
for (volatile unsigned long t = 0; t < 800; t++);
}
}
void delay_us(uint16_t us) {
for (volatile unsigned int cycles = 0; cycles < us; cycles++);
}
int main(void)
{
char buffer[16];
// 1. Habilitar Relojes
rcc_clock_enable(RCC_GPIOA); // Para el PWM (PA0) y la LCD
rcc_clock_enable(RCC_GPIOB); // Para los botones
rcc_clock_enable(RCC_TIM2); // Timer para el PWM
// 2. Configurar Pines
// MUY IMPORTANTE: Se usa GPIO_OUTPUT_AF_PP (Alternate Function) para que el Timer controle el pin PA0
gpio_set_output(GPIOA, 0, GPIO_OUTPUT_AF_PP, GPIO_SPEED_50MHZ);
// Configurar botones en PB0 y PB1
gpio_set_input(GPIOB, 0, GPIO_INPUT_PU);
gpio_set_input(GPIOB, 1, GPIO_INPUT_PU);
// 3. Inicializar la LCD
LCD_Init();
LCD_SetCursor(0, 0);
LCD_Print("Motor DC (PWM)");
LCD_SetCursor(0, 1);
sprintf(buffer, "Velocidad: %3d%%", velocidad_motor);
LCD_Print(buffer);
// 4. Inicializar Timer 2 para 10 kHz (ARR = 99, PSC = 7)
timer_init(TIM2, TIMER_MODE_UP, 99, 7);
// 5. Configurar PWM usando tu librería HAL
timer_set_oc_channel(
TIM2,
TIMER_CHANNEL_1,
TIMER_OC_PWM1,
TIMER_OC_POLARITY_HIGH,
velocidad_motor,
true
);
// Arrancar el Timer
timer_start(TIM2, TIMER_CONTINUOUS);
uint8_t flag_actualizar_lcd = 0;
while (1)
{
// --- LECTURA DEL BOTÓN UP (PB0) ---
if (!(GPIOB->IDR & (1 << 0)))
{
delay_ms(20); // Debounce
if (!(GPIOB->IDR & (1 << 0)))
{
velocidad_motor += 10;
if (velocidad_motor > 100) velocidad_motor = 100;
// Actualizar la velocidad del PWM usando la función del HAL
timer_set_compare_value(TIM2, TIMER_CHANNEL_1, velocidad_motor);
flag_actualizar_lcd = 1;
while (!(GPIOB->IDR & (1 << 0)));
delay_ms(20);
}
}
// --- LECTURA DEL BOTÓN DOWN (PB1) ---
if (!(GPIOB->IDR & (1 << 1)))
{
delay_ms(20); // Debounce
if (!(GPIOB->IDR & (1 << 1)))
{
velocidad_motor -= 10;
if (velocidad_motor < 0) velocidad_motor = 0;
// Actualizar la velocidad del PWM usando la función del HAL
timer_set_compare_value(TIM2, TIMER_CHANNEL_1, velocidad_motor);
flag_actualizar_lcd = 1;
while (!(GPIOB->IDR & (1 << 1)));
delay_ms(20);
}
}
// --- ACTUALIZACIÓN DE PANTALLA ---
if (flag_actualizar_lcd)
{
flag_actualizar_lcd = 0;
LCD_SetCursor(0, 1);
sprintf(buffer, "Velocidad: %3d%%", velocidad_motor);
LCD_Print(buffer);
}
}
}