#include "stm32f103xb.h"
#include <stdint.h>
#include <stdio.h>
#include "stm32f103_hal.h"
#include "lcd.h"
// Variables interrupción
volatile uint16_t captura_anterior = 0;
volatile uint16_t captura_actual = 0;
volatile uint16_t periodo_us = 0;
volatile uint8_t nueva_lectura = 0;
// RETARDOS LCD
#ifdef __cplusplus
extern "C" {
#endif
void delay_us(uint32_t us) { for(volatile int i=0; i<us; i++) __asm("NOP"); }
void delay_ms(uint32_t ms) { for(volatile int i=0; i<ms*1000; i++) __asm("NOP"); }
#ifdef __cplusplus
}
#endif
// Pin de lectura al PB1, por lo que usamos la interrupción EXTI1
void EXTI1_IRQHandler(void) {
// Verificamos si la interrupción vino del pin 1
if (EXTI->PR & (1 << 1)) {
EXTI->PR |= (1 << 1); // Limpiamos la bandera
// Leemos el valor del Timer 2 (nuestro cronómetro libre)
captura_actual = TIM2->CNT;
periodo_us = captura_actual - captura_anterior;
captura_anterior = captura_actual;
nueva_lectura = 1; // Avisamos al main
}
}
// Encapsulamos para un código más limpio
void Configurar_Hardware(void) {
// 1. Relojes
rcc_clock_enable(RCC_GPIOA);
rcc_clock_enable(RCC_GPIOB);
rcc_clock_enable(RCC_AFIO);
rcc_clock_enable(RCC_TIM2);
rcc_clock_enable(RCC_TIM3);
// 2. Pantalla LCD (Pines PA1 a PA11)
for(int pin = 1; pin <= 11; pin++) {
gpio_set_output(GPIOA, pin, GPIO_OUTPUT_PP, GPIO_SPEED_2MHZ);
}
LCD_Init();
LCD_SetCursor(0, 0);
LCD_Print(">> Frecuencia <<"); // Título rediseñado
// 3. GENERADOR DE SEÑAL (Ahora en PB0 usando TIM3)
// Generará 10kHz (Arr = 99, Psc = 7)
gpio_set_output(GPIOB, 0, GPIO_OUTPUT_AF_PP, GPIO_SPEED_10MHZ);
timer_init(TIM3, TIMER_MODE_UP, 99, 7);
timer_set_oc_channel(TIM3, TIMER_CHANNEL_3, TIMER_OC_PWM1, TIMER_OC_POLARITY_HIGH, 50, true);
timer_start(TIM3, TIMER_CONTINUOUS);
// 4. CRONÓMETRO LIBRE (Ahora usamos TIM2) -> Cuenta a 1 MHz
timer_init(TIM2, TIMER_MODE_UP, 0xFFFF, 7);
timer_start(TIM2, TIMER_CONTINUOUS);
// 5. LECTOR EXTI (Ahora en PB1)
gpio_set_input(GPIOB, 1, GPIO_INPUT_FLOAT);
exti_set_interrupt(PB1, EXTI_IRQ_RISING);
// Habilitamos las interrupciones
nvic_enable_irq(EXTI1_IRQn);
nvic_enable();
}
int main(void) {
// Llamamos a nuestra nueva función organizadora
Configurar_Hardware();
uint32_t frecuencia_hz = 0;
char texto_pantalla[16]; // Buffer ajustado a 16 caracteres de la pantalla
while(1) {
if (nueva_lectura) {
nueva_lectura = 0;
// Calculamos matemáticamente la frecuencia
if (periodo_us > 0) {
frecuencia_hz = 1000000 / periodo_us;
} else {
frecuencia_hz = 0;
}
LCD_SetCursor(0, 1);
// Mostrar los datos en la pantalla
if(frecuencia_hz >= 1000) {
// Si es mayor a 1000, mostramos formato "X.X kHz"
snprintf(texto_pantalla, 16, " %lu.%lu kHz ", frecuencia_hz / 1000, (frecuencia_hz % 1000) / 100);
} else {
// Si es menor a 1000, mostramos "Hz" normal
snprintf(texto_pantalla, 16, " %lu Hz ", frecuencia_hz);
}
LCD_Print(texto_pantalla);
}
delay_ms(150);
}
}