Загрузка данных
#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);
}
}