// =============================================================================
// CPET133 Lab 5 - Combination Lock Controller
// STM32F103C8 (Blue Pill) simulated on Wokwi
//
// HARDWARE SUMMARY:
// 8 slide switches -> PA0..PA7 (RIGHT = 1, LEFT = 0)
// LOCK_IN button -> PB0 (press to submit combination)
// RESTART button -> PB1 (press to start over)
// LED1 (yellow) -> PB5
// LED2 (yellow) -> PB6
// LED3 (yellow) -> PB7
// PASS (green) -> PB8
// FAIL (red) -> PB9
//
// SWITCH ORDER (left to right on screen):
// SW7 SW6 SW5 SW4 SW3 SW2 SW1 SW0
// MSB LSB
//
// HOW THE LOCK WORKS:
// The user must enter three correct 8-bit binary numbers in sequence.
// Each number is entered by setting the 8 switches and pressing LOCK_IN.
// A correct entry lights the next LED and advances to the next check.
// Any wrong entry immediately lights FAIL and waits for RESTART.
// Pressing RESTART at any time returns to Check1.
// =============================================================================
#include "stm32f1xx.h"
#include <stdint.h>
#include <stdbool.h>
// =============================================================================
// TODO 1 — Personal combination numbers
// Num1 = birth day (5) + 100 = 105
// Num2 = last digit of student number = 3
// Num3 = grade on last exam = 100
// =============================================================================
#define Num1 105
#define Num2 3
#define Num3 100
// =============================================================================
// TODO 2 — Pin bit masks
// LED1=PB5, LED2=PB6, LED3=PB7, PASS=PB8, FAIL=PB9
// LOCKIN=PB0, RESTART=PB1
// =============================================================================
#define LED1_PIN (1U << 5)
#define LED2_PIN (1U << 6)
#define LED3_PIN (1U << 7)
#define PASS_PIN (1U << 8)
#define FAIL_PIN (1U << 9)
#define ALL_LEDS (LED1_PIN | LED2_PIN | LED3_PIN | PASS_PIN | FAIL_PIN)
#define LOCKIN_PIN (1U << 0)
#define RESTART_PIN (1U << 1)
// =============================================================================
// State machine
// =============================================================================
typedef enum { Check1, Check2, Check3, Pass, Fail } State_t;
// =============================================================================
// PROVIDED — delay_ms()
// =============================================================================
static void delay_ms(uint32_t ms)
{
volatile uint32_t n = ms * 8000U;
while (n--) { __NOP(); }
}
// =============================================================================
// PROVIDED — gpio_init()
// =============================================================================
static void gpio_init(void)
{
RCC->APB2ENR |= RCC_APB2ENR_IOPAEN | RCC_APB2ENR_IOPBEN;
GPIOA->CRL = 0x44444444U; // PA0-PA7: floating inputs (switches)
GPIOB->CRL = 0x22244488U; // PB0-1: pull-up inputs, PB2-4: float, PB5-7: outputs
GPIOB->ODR |= (LOCKIN_PIN | RESTART_PIN); // activate pull-UPs on buttons
GPIOB->CRH = 0x44444422U; // PB8-9: outputs, PB10-15: float
GPIOB->ODR &= ~ALL_LEDS; // all LEDs off
GPIOB->ODR |= (LOCKIN_PIN | RESTART_PIN); // restore pull-ups
}
// =============================================================================
// PROVIDED — USART / serial print functions
// =============================================================================
static void usart_init(void)
{
RCC->APB2ENR |= RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPAEN;
GPIOA->CRH &= ~(0xFU << 4);
GPIOA->CRH |= (0xBU << 4);
USART1->BRR = 0x0341U;
USART1->CR1 = USART_CR1_TE | USART_CR1_UE;
}
static void usart_putchar(char c)
{
while (!(USART1->SR & USART_SR_TXE)) {}
USART1->DR = (uint8_t)c;
}
static void usart_print(const char *s)
{
while (*s) { usart_putchar(*s++); }
}
static void usart_print_dec(uint32_t val)
{
if (val == 0) { usart_putchar('0'); return; }
char buf[10]; int i = 0;
while (val > 0) { buf[i++] = '0' + (val % 10); val /= 10; }
for (int j = i - 1; j >= 0; j--) { usart_putchar(buf[j]); }
}
static void usart_print_bin8(uint8_t val)
{
for (int b = 7; b >= 0; b--)
usart_putchar((val & (1U << b)) ? '1' : '0');
}
static void print_status(const char *name, uint8_t entered, uint8_t expected)
{
usart_print("["); usart_print(name); usart_print("] Entered: ");
usart_print_dec(entered); usart_print(" ("); usart_print_bin8(entered);
usart_print(") Expected: ");
usart_print_dec(expected); usart_print(" ("); usart_print_bin8(expected);
usart_print(")\r\n");
}
// =============================================================================
// PROVIDED — wait_for_restart()
// =============================================================================
static void wait_for_restart(void)
{
while ( (GPIOB->IDR & RESTART_PIN)) {}
while (!(GPIOB->IDR & RESTART_PIN)) {}
delay_ms(200);
while (!(GPIOB->IDR & LOCKIN_PIN)) {}
delay_ms(50);
}
// =============================================================================
// TODO 3 — set_leds()
// Step 1: clear all LED bits without touching others
// Step 2: set only the requested LED bits (masked to ALL_LEDS for safety)
// Step 3: restore button pull-up bits
// =============================================================================
static void set_leds(uint32_t mask)
{
// Step 1 — clear all LED bits
GPIOB->ODR &= ~ALL_LEDS;
// Step 2 — set the requested LED bits
GPIOB->ODR |= (mask & ALL_LEDS);
// Step 3 — restore button pull-up bits
GPIOB->ODR |= (LOCKIN_PIN | RESTART_PIN);
}
// =============================================================================
// TODO 4 — read_switches()
// Mask off upper 24 bits of IDR, return lower 8 bits as uint8_t
// =============================================================================
static uint8_t read_switches(void)
{
return (uint8_t)(GPIOA->IDR & 0xFF);
}
// =============================================================================
// PROVIDED — wait_for_lockin()
// =============================================================================
static uint8_t wait_for_lockin(void)
{
while ((GPIOB->IDR & LOCKIN_PIN) && (GPIOB->IDR & RESTART_PIN)) {}
if (!(GPIOB->IDR & RESTART_PIN)) {
while (!(GPIOB->IDR & RESTART_PIN)) {}
delay_ms(200);
while (!(GPIOB->IDR & LOCKIN_PIN)) {}
delay_ms(50);
return 0xFF;
}
uint8_t sw_val = read_switches();
while (!(GPIOB->IDR & LOCKIN_PIN)) {}
delay_ms(50);
return sw_val;
}
// =============================================================================
// Main
// =============================================================================
int main(void)
{
gpio_init();
usart_init();
State_t state = Check1;
usart_print("\r\n=== Combination Lock Ready ===\r\n");
usart_print("Num1="); usart_print_dec(Num1);
usart_print(" ("); usart_print_bin8((uint8_t)Num1); usart_print(")\r\n");
usart_print("Num2="); usart_print_dec(Num2);
usart_print(" ("); usart_print_bin8((uint8_t)Num2); usart_print(")\r\n");
usart_print("Num3="); usart_print_dec(Num3);
usart_print(" ("); usart_print_bin8((uint8_t)Num3); usart_print(")\r\n");
usart_print("SW order: SW7(MSB)...SW0(LSB) RIGHT=1 LEFT=0\r\n");
usart_print("==============================\r\n\r\n");
while (1)
{
switch (state)
{
// =================================================================
// Check1 — first combination entry, no LEDs lit
// =================================================================
case Check1:
// TODO 5a: no LEDs on in this state
set_leds(0);
usart_print(">> Check1: enter ");
usart_print_dec(Num1);
usart_print(" ("); usart_print_bin8((uint8_t)Num1);
usart_print(") then press LOCK_IN\r\n");
{
uint8_t sw = wait_for_lockin();
if (sw == 0xFF) { state = Check1; break; }
print_status("Check1", sw, (uint8_t)Num1);
// TODO 5b: XOR compare sw with Num1
if ((sw ^ (uint8_t)Num1) == 0) {
usart_print(" MATCH -> Check2\r\n\r\n");
state = Check2;
} else {
usart_print(" MISMATCH -> FAIL\r\n\r\n");
state = Fail;
}
}
break;
// =================================================================
// Check2 — second combination entry, LED1 lit
// =================================================================
case Check2:
// TODO 6a: LED1 on in this state
set_leds(LED1_PIN);
usart_print(">> Check2: enter ");
usart_print_dec(Num2);
usart_print(" ("); usart_print_bin8((uint8_t)Num2);
usart_print(") then press LOCK_IN\r\n");
{
uint8_t sw = wait_for_lockin();
if (sw == 0xFF) { state = Check1; break; }
print_status("Check2", sw, (uint8_t)Num2);
// TODO 6b: XOR compare sw with Num2
if ((sw ^ (uint8_t)Num2) == 0) {
usart_print(" MATCH -> Check3\r\n\r\n");
state = Check3;
} else {
usart_print(" MISMATCH -> FAIL\r\n\r\n");
state = Fail;
}
}
break;
// =================================================================
// Check3 — third combination entry, LED1 and LED2 lit
// =================================================================
case Check3:
// TODO 7a: LED1 and LED2 on in this state
set_leds(LED1_PIN | LED2_PIN);
usart_print(">> Check3: enter ");
usart_print_dec(Num3);
usart_print(" ("); usart_print_bin8((uint8_t)Num3);
usart_print(") then press LOCK_IN\r\n");
{
uint8_t sw = wait_for_lockin();
if (sw == 0xFF) { state = Check1; break; }
print_status("Check3", sw, (uint8_t)Num3);
// TODO 7b: XOR compare sw with Num3
if ((sw ^ (uint8_t)Num3) == 0) {
usart_print(" MATCH -> Pass\r\n\r\n");
state = Pass;
} else {
usart_print(" MISMATCH -> FAIL\r\n\r\n");
state = Fail;
}
}
break;
// =================================================================
// Pass — all three combinations correct
// =================================================================
case Pass:
// TODO 8: all yellow LEDs + PASS LED on
set_leds(LED1_PIN | LED2_PIN | LED3_PIN | PASS_PIN);
usart_print("*** ACCESS GRANTED - PASS ***\r\n");
usart_print("Press RESTART to try again\r\n\r\n");
wait_for_restart();
usart_print("Restarting...\r\n\r\n");
state = Check1;
break;
// =================================================================
// Fail — a wrong combination was entered
// =================================================================
case Fail:
// TODO 9: only FAIL LED on
set_leds(FAIL_PIN);
usart_print("*** ACCESS DENIED - FAIL ***\r\n");
usart_print("Press RESTART to try again\r\n\r\n");
wait_for_restart();
usart_print("Restarting...\r\n\r\n");
state = Check1;
break;
default:
state = Check1;
break;
}
}
}Loading
stm32-bluepill
stm32-bluepill