/**
******************************************************************************
* @file : main.c
* @author : Fernando Hermosillo Reynoso
* @brief : Main program body
******************************************************************************
*
* 4. Realice un programa para controlar un servomotor con ángulo de -90° a 90°.
* a. El sistema contiene un botón:
* i. Botón LIMPIAR: El cual al ser presionado
* simulará por medio del servomotor, un
* limpiaparabrisas (Rotar a 90° -> -90° -> 90° -> 90° -> -90° -> 90°)
* ii. Para cambiar el ángulo contemple que el
* servomotor alimentado a 5V se desplaza a una
* velocidad de 60° en 0.1s. Por lo que deberá
* determinar el tiempo en el cual el servomotor
* se desplaza de 90° a -90° para garantizar que
* alcance la posición deseada antes de cambiar.
*/
#include <stdint.h>
#include <stdbool.h>
#include "stm32f103_hal.h"
// Retardo preciso por SysTick (8MHz)
void delay_ms(uint32_t ms) {
if (ms == 0) return;
SysTick->LOAD = 8000 - 1;
SysTick->VAL = 0;
SysTick->CTRL = 5;
for (uint32_t i = 0; i < ms; i++) {
while (!(SysTick->CTRL & 0x10000));
}
SysTick->CTRL = 0;
}
int main(void) {
// --- TIEMPO DE ESPERA AJUSTABLE ---
// 300 ms por cada 90° le da tiempo de sobra al motor para llegar físicamente
const uint32_t TIEMPO_VIAJE = 300;
// 1. Habilitar Relojes
rcc_clock_enable(RCC_GPIOA);
rcc_clock_enable(RCC_GPIOB);
rcc_clock_enable(RCC_TIM2);
// 2. Configurar Pines
gpio_set_output(GPIOA, 0, GPIO_OUTPUT_AF_PP, GPIO_SPEED_50MHZ);
gpio_set_input(GPIOB, 0, GPIO_INPUT_PU);
// 3. Timer 2: 1 tick = 1us. ARR=19999 para periodo de 20ms (50Hz)
timer_init(TIM2, TIMER_MODE_UP, 19999, 7);
// ESTADO INICIAL: 0 grados (500us)
timer_set_oc_channel(TIM2, TIMER_CHANNEL_1, TIMER_OC_PWM1, TIMER_OC_POLARITY_HIGH, 500, true);
timer_start(TIM2, TIMER_CONTINUOUS);
while (1) {
if (!(GPIOB->IDR & (1 << 0))) { // Si el botón es presionado
delay_ms(20); // Antirrebote del botón
if (!(GPIOB->IDR & (1 << 0))) {
// --- INICIO DE SECUENCIA ---
// Secuencia: 0 -> 90 -> 0 -> 90 -> 180 -> 90 -> 180 -> 0
// 1. Va a 90°
timer_set_compare_value(TIM2, TIMER_CHANNEL_1, 1450);
delay_ms(TIEMPO_VIAJE);
// 2. Va a 0°
timer_set_compare_value(TIM2, TIMER_CHANNEL_1, 500);
delay_ms(TIEMPO_VIAJE);
// 3. Va a 90°
timer_set_compare_value(TIM2, TIMER_CHANNEL_1, 1450);
delay_ms(TIEMPO_VIAJE);
// 4. Va a 180°
timer_set_compare_value(TIM2, TIMER_CHANNEL_1, 2400);
delay_ms(TIEMPO_VIAJE);
// 5. Va a 90°
timer_set_compare_value(TIM2, TIMER_CHANNEL_1, 1450);
delay_ms(TIEMPO_VIAJE);
// 6. Va a 180°
timer_set_compare_value(TIM2, TIMER_CHANNEL_1, 2400);
delay_ms(TIEMPO_VIAJE);
// 7. REGRESA A 0° (Desde 180°)
// Al ser el doble de distancia, le damos el doble de tiempo
timer_set_compare_value(TIM2, TIMER_CHANNEL_1, 500);
delay_ms(TIEMPO_VIAJE * 2);
// Esperar a soltar botón para no repetir accidentalmente
while (!(GPIOB->IDR & (1 << 0)));
delay_ms(20);
}
}
}
}