//ENTRADAS (DIP switch, pull-up interno, logica ATIVA EM NIVEL BAIXO):
//- bit0 -> PA12 (conector D2)
//- bit1 -> PB0 (conector D3)
//- bit2 -> PB7 (conector D4)
//- bit3 -> PB6 (conector D5)
//
//SAIDAS - espelho dos 4 bits (logica ATIVA EM NIVEL ALTO):
//- LED0 -> PA0 (conector A0)
//- LED1 -> PA1 (conector A1)
//- LED2 -> PA3 (conector A2)
//- LED3 -> PA4 (conector A3)
//
//SAIDA de paridade:
//- LED_PAR -> PA5 (conector A4)
//- LED_PAR ACESO = quantidade PAR de bits
//
//EXTENSAO (valor >= 8): Liga o LED vermelho da placa stm
// =====================================================================
#include <stdint.h>
#define BIT(x) (1UL << (x))
void setup() {
//Habilita o clock dos periféricos GPIOA e GPIOB no barramento AHB
//(registrador RCC->IOPENR)
RCC->IOPENR |= RCC_IOPENR_GPIOAEN | RCC_IOPENR_GPIOBEN;
__asm volatile ("nop"); // pequeno atraso para estabilizacao do clock (RM0377)
//Configura pinos de ENTRADA do DIP switch
//MODER = 00 (entrada) e PUPDR = 01 (pull-up)
//PA12
GPIOA->MODER &= ~(3UL << (12 * 2));
GPIOA->PUPDR &= ~(3UL << (12 * 2));
GPIOA->PUPDR |= (1UL << (12 * 2));
//PB0, PB6, PB7
GPIOB->MODER &= ~((3UL << (0 * 2)) | (3UL << (6 * 2)) | (3UL << (7 * 2)));
GPIOB->PUPDR &= ~((3UL << (0 * 2)) | (3UL << (6 * 2)) | (3UL << (7 * 2)));
GPIOB->PUPDR |= ((1UL << (0 * 2)) | (1UL << (6 * 2)) | (1UL << (7 * 2)));
//Configura pinos de SAIDA (LEDs de espelho + LED de paridade)
//MODER = 01 (saida push-pull)
//PA0, PA1, PA3, PA4, PA5
GPIOA->MODER &= ~((3UL << (0 * 2)) | (3UL << (1 * 2)) | (3UL << (3 * 2)) |
(3UL << (4 * 2)) | (3UL << (5 * 2)));
GPIOA->MODER |= ((1UL << (0 * 2)) | (1UL << (1 * 2)) | (1UL << (3 * 2)) |
(1UL << (4 * 2)) | (1UL << (5 * 2)));
//Extensao: PB3 (LED de usuario / D13) como saida
GPIOB->MODER &= ~(3UL << (3 * 2));
GPIOB->MODER |= (1UL << (3 * 2));
//Garante todas as saidas inicialmente apagadas (BSRR bits altos = reset)
GPIOA->BSRR = (BIT(0) | BIT(1) | BIT(3) | BIT(4) | BIT(5)) << 16;
GPIOB->BSRR = BIT(3) << 16;
}
void loop() {
//Leitura do DIP switch via IDR (Input Data Register)
uint32_t idrA = GPIOA->IDR;
uint32_t idrB = GPIOB->IDR;
//Pino em NIVEL BAIXO = chave fechada (ligada) -> bit logico 1
//(inversao decorrente do uso de pull-up interno)
uint8_t b0 = ((idrA >> 12) & 1UL) ? 0 : 1; // PA12
uint8_t b1 = ((idrB >> 0) & 1UL) ? 0 : 1; // PB0
uint8_t b2 = ((idrB >> 7) & 1UL) ? 0 : 1; // PB7
uint8_t b3 = ((idrB >> 6) & 1UL) ? 0 : 1; // PB6
uint8_t value = (uint8_t)((b3 << 3) | (b2 << 2) | (b1 << 1) | b0);
//Calculo da paridade (quantidade de bits em 1)
uint8_t ones = b0 + b1 + b2 + b3;
uint8_t isEven = (ones % 2 == 0);
//Atualiza LEDs de saida via BSRR (escrita atomica set/reset)
uint32_t setMaskA = 0, resetMaskA = 0;
(value & 0x1) ? (setMaskA |= BIT(0)) : (resetMaskA |= BIT(0));
(value & 0x2) ? (setMaskA |= BIT(1)) : (resetMaskA |= BIT(1));
(value & 0x4) ? (setMaskA |= BIT(3)) : (resetMaskA |= BIT(3));
(value & 0x8) ? (setMaskA |= BIT(4)) : (resetMaskA |= BIT(4));
//LED de paridade: aceso = quantidade PAR de bits em 1
isEven ? (setMaskA |= BIT(5)) : (resetMaskA |= BIT(5));
GPIOA->BSRR = setMaskA | (resetMaskA << 16);
//Extensao: LED onboard (PB3/D13) aceso quando valor >= 8
if (value >= 8) {
GPIOB->BSRR = BIT(3);
} else {
GPIOB->BSRR = BIT(3) << 16;
}
//Pequena espera apenas para suavizar a taxa de amostragem visual.
//NAO e delay() da API Arduino: e um laco de espera manual.
for (volatile uint32_t i = 0; i < 30000; i++) { }
}