/**
******************************************************************************
* @file : main.c
* @author : Fernando Hermosillo Reynoso
* @brief : Main program body
******************************************************************************
*
* 2. Cronómetro digital
* a. Botón inicia/detiene el cronómetro
* b. Base de tiempo de 1ms por TIM2
* c. LCD16x2 actualizada cada 10ms → formato mm:ss:millis
* d. Se reinicia cada vez que inicia la cuenta
*/
#include <stdint.h>
#include "stm32f103_hal.h"
#include "lcd.h"
/* Variables --------------------------------------*/
volatile uint32_t millis = 0; // contador de tiempo en ms
volatile uint8_t running = 0; // 0: detenido, 1: corriendo
/* Funciones privadas -----------------------------*/
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++);
}
/* Botón en PB0 → EXTI0, flanco de bajada */
void EXTI0_IRQHandler(void)
{
EXTI->PR = (1 << 0); // limpiar bandera (escribir 1 para borrar)
if (!running)
{
millis = 0; // reiniciar al arrancar
running = 1;
}
else
{
running = 0; // detener
}
}
/* TIM2 → base de tiempo 1ms */
void TIM2_IRQHandler(void)
{
if (TIM2->SR & TIM_SR_UIF)
{
TIM2->SR &= ~TIM_SR_UIF; // limpiar bandera
if (running) millis++; // solo contar si está corriendo
}
}
/* Codigo principal -------------------------------*/
int main(void)
{
// 1. Habilitar relojes
rcc_clock_enable(RCC_GPIOA); // LCD
rcc_clock_enable(RCC_GPIOB); // Botón
rcc_clock_enable(RCC_TIM2);
rcc_clock_enable(RCC_EXTI); // AFIO para EXTI
// 2. Configurar botón PB0 como entrada pull-up
gpio_set_input(GPIOB, GPIO_PIN_0, GPIO_INPUT_PU);
// 3. Configurar EXTI0 en flanco de bajada (botón activo bajo)
exti_set_interrupt(PB0, EXTI_IRQ_FALLING);
nvic_enable_irq(EXTI0_IRQn);
// 4. Configurar TIM2 a 1ms
// Fclk=8MHz, PSC=7 → Ftick=1MHz (1us), ARR=999 → T=1000us=1ms
timer_init(TIM2, TIMER_MODE_UP, 999, 7);
timer_set_interrupt(TIM2, TIMER_IRQ_UPDATE, IRQ_ENABLE);
nvic_enable_irq(TIM2_IRQn);
timer_start(TIM2, TIMER_CONTINUOUS);
// 5. Inicializar LCD
LCD_Init();
LCD_Send(LCD_CMD_CLEAR, LCD_MODE_CMD);
LCD_SetCursor(0, 0);
LCD_Print("00:00:000");
uint32_t last_update = 0;
while (1)
{
uint32_t now = millis; // leer una sola vez
// Actualizar LCD cada 10ms
if (now - last_update >= 10)
{
last_update = now;
// Descomponer tiempo
uint32_t mm = now / 60000;
uint32_t ss = (now % 60000) / 1000;
uint32_t ms = now % 1000;
// Construir string mm:ss:millis sin usar sprintf
char buf[10];
buf[0] = '0' + mm / 10;
buf[1] = '0' + mm % 10;
buf[2] = ':';
buf[3] = '0' + ss / 10;
buf[4] = '0' + ss % 10;
buf[5] = ':';
buf[6] = '0' + ms / 100;
buf[7] = '0' + (ms % 100) / 10;
buf[8] = '0' + ms % 10;
buf[9] = '\0';
LCD_SetCursor(0, 0);
LCD_Print(buf);
}
}
}Loading
stm32-bluepill
stm32-bluepill