#include <stdint.h>
#define RCC_BASE 0x40021000
#define GPIOA_BASE 0x50000000
#define RCC_IOPENR (*(volatile uint32_t*)(RCC_BASE + 0x34))
#define GPIOA_MODER (*(volatile uint32_t*)(GPIOA_BASE + 0x00))
#define GPIOA_IDR (*(volatile uint32_t*)(GPIOA_BASE + 0x10))
#define GPIOA_ODR (*(volatile uint32_t*)(GPIOA_BASE + 0x14))
#define SYST_CSR_ENABLE (1U<<0)
#define SYST_CSR_CLKSOURCE (1U<<2)
#define SYST_CSR_COUNTFLAG (1U<<16)
#define SYST_CLK 48000000UL
#define BASE_VALUE ((SYST_CLK/1000)-1)
#define SYSTICK_BASE 0xE000E010UL
#define SYST_CSR (*(volatile uint32_t*)(SYSTICK_BASE + 0x00UL))
#define SYST_RVR (*(volatile uint32_t*)(SYSTICK_BASE + 0x04UL))
#define SYST_CVR (*(volatile uint32_t*)(SYSTICK_BASE + 0x08UL))
#define LISTA_PINOS_BOTOES {7, 8, 9, 10} // [0] Crescente, [1] Decrescente, [2] Set, [3] Reset
#define LISTA_PINOS_DISPLAY {0, 1, 2, 3, 4, 5, 6} // a, b, c, d, e, f, g
// --- NOVA FUNÇÃO DE DELAY DE ALTA PRECISÃO ---
void delayMs(uint32_t delay){
if(delay == 0) return;
uint32_t reload = BASE_VALUE;
if(reload > 0xFFFFFFUL) reload = 0xFFFFFFUL;
SYST_CSR = 0U;
SYST_RVR = reload;
SYST_CVR = 0U;
SYST_CSR = SYST_CSR_CLKSOURCE | SYST_CSR_ENABLE;
while(delay--){
while((SYST_CSR & SYST_CSR_COUNTFLAG) == 0U);
}
SYST_CSR = 0U;
SYST_CVR = 0U;
}
void display(int numero);
int main(void){
// O compilador deduz o tamanho do array automaticamente
const uint8_t pinos_botaos[] = LISTA_PINOS_BOTOES;
const uint8_t pinos_display[] = LISTA_PINOS_DISPLAY;
// Calcula a quantidade de elementos dinamicamente
const int qtd_botoes = sizeof(pinos_botaos) / sizeof(pinos_botaos[0]);
const int qtd_display = sizeof(pinos_display) / sizeof(pinos_display[0]);
int contador = 0;
RCC_IOPENR |= (1U << 0);
// Configuração dos botões
for(int i = 0; i < qtd_botoes; i++){
GPIOA_MODER &= ~(3U << (pinos_botaos[i] * 2));
}
// Configuração do display
for(int i = 0; i < qtd_display; i++){
GPIOA_MODER &= ~(3U << (pinos_display[i] * 2));
GPIOA_MODER |= (1U << (pinos_display[i] * 2));
}
//Inicia com 0
display(contador);
while(1){
// Botão Crescente
if(!(GPIOA_IDR & (1U << pinos_botaos[0]))){
delayMs(100);
contador++;
if(contador > 9){
contador = 0;
}
display(contador);
while(!(GPIOA_IDR & (1U << pinos_botaos[0])));
delayMs(100);
}
// Botão Decrescente
if(!(GPIOA_IDR & (1U << pinos_botaos[1]))){
delayMs(100);
contador--;
if(contador < 0){
contador = 9;
}
display(contador);
while(!(GPIOA_IDR & (1U << pinos_botaos[1])));
delayMs(100);
}
// Botão Set (Vai para 9)
if(!(GPIOA_IDR & (1U << pinos_botaos[2]))){
delayMs(100);
contador = 9;
display(contador);
while(!(GPIOA_IDR & (1U << pinos_botaos[2])));
delayMs(100);
}
// Botão Reset (Vai para 0)
if(!(GPIOA_IDR & (1U << pinos_botaos[3]))){
delayMs(100);
contador = 0;
display(contador);
while(!(GPIOA_IDR & (1U << pinos_botaos[3])));
delayMs(100);
}
}
}
void display(int numero){
// Usa o mesmo define dinâmico aqui
const uint8_t pinos_display[] = LISTA_PINOS_DISPLAY;
const int qtd_display = sizeof(pinos_display) / sizeof(pinos_display[0]);
// 1. Apaga todos os segmentos
for(int i = 0; i < qtd_display; i++){
GPIOA_ODR &= ~(1U << pinos_display[i]);
}
// 2. Acende os segmentos corretos (usando 1U em todos os shifts)
switch (numero) {
case 0: // A, B, C, D, E, F
GPIOA_ODR |= (1U << pinos_display[0]);
GPIOA_ODR |= (1U << pinos_display[1]);
GPIOA_ODR |= (1U << pinos_display[2]);
GPIOA_ODR |= (1U << pinos_display[3]);
GPIOA_ODR |= (1U << pinos_display[4]);
GPIOA_ODR |= (1U << pinos_display[5]);
break;
case 1: // B, C
GPIOA_ODR |= (1U << pinos_display[1]);
GPIOA_ODR |= (1U << pinos_display[2]);
break;
case 2: // A, B, D, E, G
GPIOA_ODR |= (1U << pinos_display[0]);
GPIOA_ODR |= (1U << pinos_display[1]);
GPIOA_ODR |= (1U << pinos_display[3]);
GPIOA_ODR |= (1U << pinos_display[4]);
GPIOA_ODR |= (1U << pinos_display[6]);
break;
case 3: // A, B, C, D, G
GPIOA_ODR |= (1U << pinos_display[0]);
GPIOA_ODR |= (1U << pinos_display[1]);
GPIOA_ODR |= (1U << pinos_display[2]);
GPIOA_ODR |= (1U << pinos_display[3]);
GPIOA_ODR |= (1U << pinos_display[6]);
break;
case 4: // B, C, F, G
GPIOA_ODR |= (1U << pinos_display[1]);
GPIOA_ODR |= (1U << pinos_display[2]);
GPIOA_ODR |= (1U << pinos_display[5]);
GPIOA_ODR |= (1U << pinos_display[6]);
break;
case 5: // A, C, D, F, G
GPIOA_ODR |= (1U << pinos_display[0]);
GPIOA_ODR |= (1U << pinos_display[2]);
GPIOA_ODR |= (1U << pinos_display[3]);
GPIOA_ODR |= (1U << pinos_display[5]);
GPIOA_ODR |= (1U << pinos_display[6]);
break;
case 6: // A, C, D, E, F, G
GPIOA_ODR |= (1U << pinos_display[0]);
GPIOA_ODR |= (1U << pinos_display[2]);
GPIOA_ODR |= (1U << pinos_display[3]);
GPIOA_ODR |= (1U << pinos_display[4]);
GPIOA_ODR |= (1U << pinos_display[5]);
GPIOA_ODR |= (1U << pinos_display[6]);
break;
case 7: // A, B, C
GPIOA_ODR |= (1U << pinos_display[0]);
GPIOA_ODR |= (1U << pinos_display[1]);
GPIOA_ODR |= (1U << pinos_display[2]);
break;
case 8: // Acende todos (A até G)
GPIOA_ODR |= (1U << pinos_display[0]);
GPIOA_ODR |= (1U << pinos_display[1]);
GPIOA_ODR |= (1U << pinos_display[2]);
GPIOA_ODR |= (1U << pinos_display[3]);
GPIOA_ODR |= (1U << pinos_display[4]);
GPIOA_ODR |= (1U << pinos_display[5]);
GPIOA_ODR |= (1U << pinos_display[6]);
break;
case 9: // A, B, C, D, F, G
GPIOA_ODR |= (1U << pinos_display[0]);
GPIOA_ODR |= (1U << pinos_display[1]);
GPIOA_ODR |= (1U << pinos_display[2]);
GPIOA_ODR |= (1U << pinos_display[3]);
GPIOA_ODR |= (1U << pinos_display[5]);
GPIOA_ODR |= (1U << pinos_display[6]);
break;
}
}