Загрузка данных


#include "MDR32Fx.h"
#include "MDR32F9Qx_port.h"
#include "MDR32F9Qx_rst_clk.h"

// Светодиоды (порт A, линии 0–7)
#define LED_PORT        MDR_PORTA
#define LED_MASK        0xFF

// Кнопки координат (распределены по портам согласно плате расширения)
// X: биты модуля: PF0(4), PF1(2), PB1(1); знак: PB0
// Y: биты модуля: PD3(4), PB2(2), PB3(1); знак: PB4
// SELECT: PC0

// Глобальная переменная для задержки (используется в SysTick)
volatile uint32_t ms_tick = 0;

// ---------------------------------------------------------------------
// Обработчик прерывания системного таймера (каждые 1 мс)
void SysTick_Handler(void) {
    ms_tick++;
}

// Функция задержки на заданное число миллисекунд
void delay_ms(uint32_t ms) {
    uint32_t start = ms_tick;
    while ((ms_tick - start) < ms);
}

// ---------------------------------------------------------------------
// Инициализация светодиодов (порт A как выход)
void init_leds(void) {
    RST_CLK_PCLKcmd(RST_CLK_PCLK_PORTA, ENABLE);
    
    PORT_InitTypeDef PortInit;
    PortInit.PORT_Pin   = LED_MASK;
    PortInit.PORT_OE    = PORT_OE_OUT;
    PortInit.PORT_FUNC  = PORT_FUNC_PORT;
    PortInit.PORT_MODE  = PORT_MODE_DIGITAL;
    PortInit.PORT_SPEED = PORT_SPEED_SLOW;
    PORT_Init(LED_PORT, &PortInit);
    
    PORT_Write(LED_PORT, 0x00);   // все выключены
}

// ---------------------------------------------------------------------
// Инициализация всех кнопок (с подтяжкой вверх, но фактически
// кнопки на плате замыкают на питание, давая '1' при нажатии)
void init_keys(void) {
    // Включаем тактирование используемых портов
    RST_CLK_PCLKcmd(RST_CLK_PCLK_PORTB | RST_CLK_PCLK_PORTC |
                    RST_CLK_PCLK_PORTD | RST_CLK_PCLK_PORTF, ENABLE);
    
    PORT_InitTypeDef PortInit;
    PortInit.PORT_OE    = PORT_OE_IN;
    PortInit.PORT_FUNC  = PORT_FUNC_PORT;
    PortInit.PORT_MODE  = PORT_MODE_DIGITAL;
    PortInit.PORT_PULL_UP = PORT_PULL_UP_ON;   // используется в рабочем примере
    
    // Порт B: PB0 (знак X), PB1 (X1), PB2 (Y2), PB3 (Y1), PB4 (знак Y)
    PortInit.PORT_Pin = PORT_Pin_0 | PORT_Pin_1 | PORT_Pin_2 | PORT_Pin_3 | PORT_Pin_4;
    PORT_Init(MDR_PORTB, &PortInit);
    
    // Порт C: PC0 (SELECT)
    PortInit.PORT_Pin = PORT_Pin_0;
    PORT_Init(MDR_PORTC, &PortInit);
    
    // Порт D: PD3 (Y4)
    PortInit.PORT_Pin = PORT_Pin_3;
    PORT_Init(MDR_PORTD, &PortInit);
    
    // Порт F: PF0 (X4), PF1 (X2)
    PortInit.PORT_Pin = PORT_Pin_0 | PORT_Pin_1;
    PORT_Init(MDR_PORTF, &PortInit);
}

// ---------------------------------------------------------------------
// Инициализация системного таймера SysTick (прерывания каждые 1 мс)
void init_systick(void) {
    SysTick->LOAD = (8000000 / 1000) - 1;   // HCLK = 8 МГц
    SysTick->VAL  = 0;
    SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |   // источник HCLK
                    SysTick_CTRL_TICKINT_Msk   |   // разрешить прерывание
                    SysTick_CTRL_ENABLE_Msk;       // включить таймер
}

// ---------------------------------------------------------------------
// Мигание всеми светодиодами заданное число раз
// (одна вспышка = все включены на 400 мс, затем все выключены на 400 мс)
void blink_leds(uint8_t times) {
    for (uint8_t i = 0; i < times; i++) {
        PORT_Write(LED_PORT, 0x00);   // выключить все
        delay_ms(400);
        PORT_Write(LED_PORT, 0xFF);   // включить все
        delay_ms(400);
    }
    PORT_Write(LED_PORT, 0x00);       // после всех вспышек гарантированно выключить
}

// ---------------------------------------------------------------------
// Чтение координат X и Y с кнопок
void read_coordinates(int *x, int *y) {
    // Чтение модуля X (веса 4,2,1)
    uint8_t x_abs = 0;
    if (PORT_ReadInputDataBit(MDR_PORTF, PORT_Pin_0) == 1) x_abs += 4;
    if (PORT_ReadInputDataBit(MDR_PORTF, PORT_Pin_1) == 1) x_abs += 2;
    if (PORT_ReadInputDataBit(MDR_PORTB, PORT_Pin_1) == 1) x_abs += 1;
    
    // Знак X (PB0 == 1 → отрицательное)
    int8_t sign_x = (PORT_ReadInputDataBit(MDR_PORTB, PORT_Pin_0) == 1) ? -1 : 1;
    *x = sign_x * x_abs;
    
    // Чтение модуля Y (веса 4,2,1)
    uint8_t y_abs = 0;
    if (PORT_ReadInputDataBit(MDR_PORTD, PORT_Pin_3) == 1) y_abs += 4;
    if (PORT_ReadInputDataBit(MDR_PORTB, PORT_Pin_2) == 1) y_abs += 2;
    if (PORT_ReadInputDataBit(MDR_PORTB, PORT_Pin_3) == 1) y_abs += 1;
    
    // Знак Y (PB4 == 1 → отрицательное)
    int8_t sign_y = (PORT_ReadInputDataBit(MDR_PORTB, PORT_Pin_4) == 1) ? -1 : 1;
    *y = sign_y * y_abs;
}

// ---------------------------------------------------------------------
// Проверка попадания точки (x,y) в заданную область
// Условие: x^2 + y^2 <= 9   И   |x| + |y| >= 2
uint8_t is_inside(int x, int y) {
    int x2 = x * x;
    int y2 = y * y;
    int abs_sum = (x >= 0 ? x : -x) + (y >= 0 ? y : -y);
    
    return (x2 + y2 <= 9) && (abs_sum >= 2);
}

// ---------------------------------------------------------------------
// Главная функция
int main(void) {
    // Инициализация периферии
    init_leds();
    init_keys();
    init_systick();
    
    // Начальное состояние: все светодиоды выключены
    PORT_Write(LED_PORT, 0x00);
    
    uint8_t select_prev = 1;   // предыдущее состояние SELECT (не нажата)
    
    while (1) {
        // Текущее состояние кнопки SELECT (PC0)
        uint8_t select_curr = PORT_ReadInputDataBit(MDR_PORTC, PORT_Pin_0);
        
        // Обработка нажатия (переход из 1 в 0, т.к. SELECT подтянут к питанию и при нажатии даёт 0)
        if (select_prev == 1 && select_curr == 0) {
            int x, y;
            read_coordinates(&x, &y);
            
            if (is_inside(x, y)) {
                blink_leds(1);   // попала – одна вспышка
            } else {
                blink_leds(2);   // не попала – две вспышки
            }
            
            // Ждём отпускания кнопки SELECT, чтобы избежать многократного срабатывания
            while (PORT_ReadInputDataBit(MDR_PORTC, PORT_Pin_0) == 0);
            delay_ms(20);   // небольшой антидребезг
        }
        select_prev = select_curr;
        
        // Небольшая задержка для снижения частоты опроса
        delay_ms(10);
    }
}