/**
******************************************************************************
* @file : main.c
* @author : Fernando Hermosillo Reynoso
* @brief : Main program body
******************************************************************************
*/
#include "stm32f103_hal.h"
// --- Variables globales ---
volatile uint32_t t1 = 0;
volatile uint32_t t_motor = 0;
volatile bool flanco_detectado = false;
float temperatura = 0.0;
float dt_us = 0.0;
volatile uint32_t ms_ticks = 0; // Contador de milisegundos para el SysTick
// --- Función Principal ---
int main(void) {
// 1. CONFIGURACIÓN DEL RELOJ (8MHz interno)
//rcc_set_clock(RCC_SYSCLK_HSI, 0);
systick_config(8000, SYSTICK_CLKSRC_AHB);
// 2. CONFIGURACIÓN DEL SENSOR DE CIGÜEÑAL (PB0)
rcc_clock_enable(RCC_GPIOB);
rcc_clock_enable(RCC_AFIO);
gpio_set_input(GPIOB, GPIO_PIN_0, GPIO_INPUT_PU);
exti_set_interrupt(PB0, EXTI_IRQ_FALLING);
nvic_enable_irq(EXTI0_IRQn);
// 3. CONFIGURACIÓN DEL ADC (Temperatura en PA0)
rcc_clock_enable(RCC_GPIOA);
rcc_clock_enable(RCC_ADC1);
gpio_set_input(GPIOA, GPIO_PIN_0, GPIO_INPUT_ANALOG);
ADC1->CR2 |= ADC_CR2_ADON;
for(volatile int i = 0; i < 10000; i++);
ADC1->CR2 |= ADC_CR2_CAL;
while(ADC1->CR2 & ADC_CR2_CAL);
// 4. CONFIGURACIÓN DE LOS TIMERS
rcc_clock_enable(RCC_TIM3);
rcc_clock_enable(RCC_TIM2);
rcc_clock_enable(RCC_TIM4);
// Configurar PB6 como salida de PWM (Timer 4, Canal 1)
gpio_set_output(GPIOB, GPIO_PIN_6, GPIO_OUTPUT_AF_PP, GPIO_SPEED_50MHZ);
// Inicializar cronómetros en microsegundos (Prescaler 7)
timer_init(TIM3, TIMER_MODE_UP, 65535, 7);
timer_init(TIM2, TIMER_MODE_UP, 65535, 7);
timer_start(TIM2,0);
timer_init(TIM1, TIMER_MODE_UP, 65535, 7);
// Habilitar interrupciones de fin de cuenta
timer_set_interrupt(TIM3, TIMER_IRQ_UPDATE, IRQ_ENABLE);
timer_set_interrupt(TIM2, TIMER_IRQ_UPDATE, IRQ_ENABLE);
nvic_enable_irq(TIM3_IRQn);
nvic_enable_irq(TIM2_IRQn);
nvic_enable();
while (1) {
// Todo se maneja por interrupciones
}
}
// --- RUTINAS DE INTERRUPCIÓN (ISRs) ---
// Reloj de Sistema
void SysTick_Handler(void) {
ms_ticks++;
}
// Interrupción PB0 (Cigüeñal 0°)
void EXTI0_IRQHandler(void) {
if (EXTI->PR & EXTI_PR_PR0) {
EXTI->PR = EXTI_PR_PR0;
// 1. Capturamos el valor actual del contador del Timer 2
// TIM2->CNT nos da el tiempo exacto en microsegundos desde la última marca
uint32_t t_actual = TIM2->CNT;
// 2. Calculamos la duración de la vuelta (Periodo)
// El Timer se encarga de decirnos cuánto pasó desde el último 0°
t_motor = t_actual;
// 3. Reiniciamos el contador del Timer 2 para la siguiente vuelta
TIM2->CNT = 0;
// 4. Guardamos la referencia para el cálculo de los 90°
uint32_t delay_90 = t_motor / 4;
// 5. Disparamos el Timer 3 para el retraso de 90°
timer_reset(TIM3);
TIM3->ARR = delay_90;
timer_start(TIM3, TIMER_ONESHOT);
}
}
// Interrupción Timer 3 (90° cumplidos)
void TIM3_IRQHandler(void) {
if (TIM3->SR & TIM_SR_UIF) {
TIM3->SR &= ~TIM_SR_UIF;
// Medir ADC
ADC1->SQR3 = 0;
ADC1->CR2 |= ADC_CR2_ADON;
while(!(ADC1->SR & ADC_SR_EOC));
uint32_t val = ADC1->DR;
temperatura = (val * 330.0f) / 4095.0f;
// Calcular Delta T
dt_us = (t_motor / 85.0f) * (85.0f - temperatura);
// Límites
if (dt_us > (t_motor / 2.0f)) dt_us = t_motor / 2.0f;
if (dt_us < (t_motor / 4.0f)) dt_us = t_motor / 4.0f;
timer_reset(TIM1);
TIM1->ARR = (uint32_t)dt_us;
timer_start(TIM1, TIMER_ONESHOT);
}
}
// Interrupción Timer 1 (Retraso cumplido -> INYECTAR)
void TIM1_IRQHandler(void) {
if (TIM1->SR & TIM_SR_UIF) {
TIM1->SR &= ~TIM_SR_UIF;
// Configuración PWM al 20% (Periodo 10, Alto 2)
timer_init(TIM4, TIMER_MODE_UP, 10, 7);
timer_set_oc_channel(TIM4, TIMER_CHANNEL_1, TIMER_OC_PWM1, TIMER_OC_POLARITY_HIGH, 2, true);
timer_start(TIM4, TIMER_ONESHOT);
}
}Loading
stm32-bluepill
stm32-bluepill