#include "main.h"
#include "tm1637.h"
#include "keyboard.h"
volatile uint32_t tickCount;
// Режимы отображения
typedef enum {
MODE_BIN = 0,
MODE_DEC = 1,
MODE_HEX = 2
} DisplayMode;
DisplayMode currentMode = MODE_BIN;
// --- SysTick прерывание ---
void osSystickHandler(void) {
tickCount++;
}
// --- Инициализация GPIO ---
void initGPIO(void) {
// Включаем тактирование портов A, B, C
RCC->AHBENR |= RCC_AHBENR_GPIOAEN
| RCC_AHBENR_GPIOBEN
| RCC_AHBENR_GPIOCEN;
// PA5 - встроенный LED
GPIOA->MODER = (GPIOA->MODER & ~(3U << (5 * 2))) | (1U << (5 * 2));
GPIOA->OTYPER &= ~(1U << 5);
GPIOA->OSPEEDR |= (1U << (5 * 2));
// Светодиоды режимов:
// BIN - PA15
// DEC - PA9
// HEX - PC7
GPIOA->MODER = (GPIOA->MODER & ~(3U << (15 * 2))) | (1U << (15 * 2));
GPIOA->OTYPER &= ~(1U << 15);
GPIOA->OSPEEDR |= (1U << (15 * 2));
GPIOA->MODER = (GPIOA->MODER & ~(3U << (9 * 2))) | (1U << (9 * 2));
GPIOA->OTYPER &= ~(1U << 9);
GPIOA->OSPEEDR |= (1U << (9 * 2));
GPIOC->MODER = (GPIOC->MODER & ~(3U << (7 * 2))) | (1U << (7 * 2));
GPIOC->OTYPER &= ~(1U << 7);
GPIOC->OSPEEDR |= (1U << (7 * 2));
// Входы от DIP-переключателя (8 каналов):
// ch0 - PA12, ch1 - PA11, ch2 - PB1, ch3 - PA4,
// ch4 - PA1, ch5 - PA0, ch6 - PC14, ch7 - PC13
GPIOA->MODER &= ~(3U << (12 * 2) |
3U << (11 * 2) |
3U << (4 * 2) |
3U << (1 * 2) |
3U << (0 * 2));
GPIOB->MODER &= ~(3U << (1 * 2));
GPIOC->MODER &= ~(3U << (14 * 2) |
3U << (13 * 2));
// Подтяжка вниз (так как верхние выводы DIP сидят на 3V3)
GPIOA->PUPDR = (GPIOA->PUPDR &
~(3U << (12 * 2) |
3U << (11 * 2) |
3U << (4 * 2) |
3U << (1 * 2) |
3U << (0 * 2)))
| (2U << (12 * 2)) // pull-down
| (2U << (11 * 2))
| (2U << (4 * 2))
| (2U << (1 * 2))
| (2U << (0 * 2));
GPIOB->PUPDR = (GPIOB->PUPDR & ~(3U << (1 * 2)))
| (2U << (1 * 2));
GPIOC->PUPDR = (GPIOC->PUPDR &
~(3U << (14 * 2) |
3U << (13 * 2)))
| (2U << (14 * 2))
| (2U << (13 * 2));
}
// --- USART2 под printf() ---
void initUSART2(void) {
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
// PA2/PA3 - альтернативная функция (AF1)
GPIOA->MODER = (GPIOA->MODER & ~(0xFU << 4)) | (0xAU << 4);
GPIOA->AFR[0] = (GPIOA->AFR[0] & ~(0xFFU << 8)) | (1U << 8) | (1U << 12);
USART2->BRR = 417; // 48MHz / 115200
USART2->CR1 = USART_CR1_TE | USART_CR1_UE;
}
int _write(int file, uint8_t *ptr, int len) {
(void)file;
for (int i = 0; i < len; i++) {
while (!(USART2->ISR & USART_ISR_TXE));
USART2->TDR = ptr[i];
}
return len;
}
// --- SysTick 1 мс ---
void initSysTick(void) {
SysTick->LOAD = 47999; // 1 мс при 48 МГц
SysTick->VAL = 0;
SysTick->CTRL = (1U << 2) | (1U << 1) | (1U << 0);
}
// --- Отладочное мигание встроенным светодиодом ---
void checkTickCount(void) {
if ((tickCount % 2000U) == 0U) { // раз в 2 секунды
GPIOA->ODR ^= (1U << 5);
printf("tickCount = %lu\n", (unsigned long)tickCount);
}
}
// --- Чтение 8-ми дискретных входов ---
static uint8_t readInputs(void) {
uint8_t value = 0;
if (GPIOA->IDR & (1U << 12)) value |= (1U << 0); // ch0
if (GPIOA->IDR & (1U << 11)) value |= (1U << 1); // ch1
if (GPIOB->IDR & (1U << 1)) value |= (1U << 2); // ch2
if (GPIOA->IDR & (1U << 4)) value |= (1U << 3); // ch3
if (GPIOA->IDR & (1U << 1)) value |= (1U << 4); // ch4
if (GPIOA->IDR & (1U << 0)) value |= (1U << 5); // ch5
if (GPIOC->IDR & (1U << 14)) value |= (1U << 6); // ch6
if (GPIOC->IDR & (1U << 13)) value |= (1U << 7); // ch7
return value;
}
// --- Светодиоды режимов ---
static void updateModeLEDs(void) {
// Гасим все
GPIOA->BRR = (1U << 15) | (1U << 9);
GPIOC->BRR = (1U << 7);
switch (currentMode) {
case MODE_BIN:
GPIOA->BSRR = (1U << 15); // BIN
break;
case MODE_DEC:
GPIOA->BSRR = (1U << 9); // DEC
break;
case MODE_HEX:
GPIOC->BSRR = (1U << 7); // HEX
break;
}
}
// --- Обработка нажатий клавиш B / D / H ---
static void handleKey(char key) {
switch (key) {
case 'B':
currentMode = MODE_BIN;
printf("Mode: BIN\n");
break;
case 'D':
currentMode = MODE_DEC;
printf("Mode: DEC\n");
break;
case 'H':
currentMode = MODE_HEX;
printf("Mode: HEX\n");
break;
default:
return;
}
updateModeLEDs();
}
// реагируем только на изменение lastKey
static void processKeyboard(void) {
static char prevKey = '\0';
if (lastKey != prevKey) {
if (lastKey != '\0') {
handleKey(lastKey);
}
prevKey = lastKey;
}
}
// --- Обновление индикации TM1637 ---
static void updateDisplay(void) {
static uint32_t lastInputScan = 0;
static uint8_t lastValue = 0;
static uint8_t currentChannel = 0;
// Считываем входы примерно раз в 10 мс
if ((tickCount - lastInputScan) >= 10U) {
lastInputScan = tickCount;
lastValue = readInputs();
}
// Обновляем дисплей
if ((tickCount - last_display_update) >= 250U) { // 4 Гц
last_display_update = tickCount;
switch (currentMode) {
case MODE_BIN: {
uint8_t bit = (lastValue >> currentChannel) & 0x01;
tm1637_display_channel_state(currentChannel, bit);
currentChannel = (currentChannel + 1) & 0x07; // 0..7 по кругу
break;
}
case MODE_DEC:
tm1637_display_number(lastValue); // 0..255
break;
case MODE_HEX:
tm1637_display_hex(lastValue);
break;
}
}
}
// --- main() ---
int main(void) {
initGPIO();
initUSART2();
initSysTick();
initKeyboard();
tm1637_init();
printf("Oh shi here we go again\n");
// Включаем встроенный LED
GPIOA->ODR |= (1U << 5);
updateModeLEDs(); // по умолчанию BIN
while (1) {
checkTickCount();
scanKeyboard(); // обновляет lastKey
processKeyboard(); // переключает режимы
updateDisplay(); // показывает состояние 8 входов
}
return 0;
}
Установка режима
B - двоичный
D - десятичный
H - шестнадцатеричный
BIN
DEC
HEX