Код:
program zx_jtk;
var ext : bit; //ext - признак выхода из режима конфигурации кнопок джойстика; button - признак повтора столбца матрицы в массиве k2
rezh : byte; //режим работы устройства: rezh=0 - режим 1 из описания к устройству,
// rezh=1 - режим конфигурации кнопок режима 1,
// rezh=3 - режим 2 из описания к устройству,
// rezh=4 - режим конфигурации кнопок режима 2,
// rezh=5 - режим 3 из описания к устройству.
k1 : array[0..15] of byte; //массив рядов матрицы для каждой кнопки
k2 : array[0..15] of byte; //массив столбцов матрицы для каждой кнопки
a : byte; //буферный байт, содержащий инфу по всем нажатым кнопкам (формирование столбца матрицы)
keyd : word; //слово данных содержащее инфу по всем нажатым кнопкам
turbo1: array[0..15] of byte; //массив с инфой по тому какая кнопка турбо, а какая обычная - для режима "механического" геймпада
turbo2: array[0..15] of byte; //массив с инфой по тому какая кнопка турбо, а какая обычная - для режима NES геймпадов
i,l,m,s,t,z,n,zad: integer; //i,l,m,s,t,z,n - переменные переборов, zad - фактически скорость работы турбокнопки
{var PS2_Data : sbit at PINB.5; //Заготовка для определения пинов подключения PS/2 клавиатуры
PS2_Clock_Input : sbit at PINB.7;
PS2_Clock_Output : sbit at PORTB.7;
PS2_Data_Direction : sbit at DDRB.5;
PS2_Clock_Direction : sbit at DDRB.7;
keydata, special, down : byte;}
begin
Delay_ms(500); //задержка 500 мс после подачи питания
if EEPROM_read(64)=0x00 then //выбор сохраненного режима - 64 байт EEPROM содержит инфу по тому, какой режим был выбран
begin //0x00 - это режим для NES геймпадов (режим 2)
rezh:=3;
for i:=0 to 15 do
begin
k1[i]:= EEPROM_read (i+32); //загрузка конфигурации 16 кнопок из EEPROM
k2[i]:= EEPROM_read (i+48);
turbo1[i]:= EEPROM_read (i+80);
turbo2[i]:= EEPROM_read (i+96);
end;
end;
if EEPROM_read(64)=0xFF then //0xFF - это режим для "механического" геймпада (режим 1)
begin
rezh:=0;
for i:=0 to 15 do
begin
k1[i]:= EEPROM_read (i); //загрузка конфигурации 16 кнопок из EEPROM
k2[i]:= EEPROM_read (i+16);
turbo1[i]:= EEPROM_read (i+80);
turbo2[i]:= EEPROM_read (i+96);
end;
end;
if EEPROM_read(64)=0x11 then //0x11 - это режим для "механического" и первого NES геймпада (режим 3)
begin
rezh:=5;
for i:=0 to 15 do
begin
if i<8 then //Первые 8 кнопок - это кнопки "механического" геймпада
begin
k1[i]:= EEPROM_read (i);
k2[i]:= EEPROM_read (i+16);
end
else //Вторые 8 кнопок - это кнопки первого NES геймпада
begin
k1[i]:= EEPROM_read (i+32-8);
k2[i]:= EEPROM_read (i+48-8);
end;
end;
end;
// Переводим пины 0,1,2,3,4 порта B в режим Hi-Z (для чтения данных с него)
PORTB.0 := 0; // ZXCOL0 0 столбец механической клавиатуры (описание беру из мануала к ZXEVO (раздел 4.12 X12. Механическая клавиатура и джойстик)
PORTB.1 := 0; // ZXCOL1 1 столбец механической клавиатуры
PORTB.2 := 0; // ZXCOL2 2 столбец механической клавиатуры
PORTB.3 := 0; // ZXCOL3 3 столбец механической клавиатуры
PORTB.4 := 0; // ZXCOL4 4 столбец механической клавиатуры
DDRB.0 := 0; // Назначаем эти пины на вход
DDRB.1 := 0; //
DDRB.2 := 0; //
DDRB.3 := 0; //
DDRB.4 := 0; //
// Переводим все пины порта A в режим Hi-Z (для чтения данных с него)
PORTA := 0x00; // ZXROW0..ZXROW7 с нулевого по седьмой ряд механической клавиатуры
DDRA := 0x00; // Назначаем эти пины на вход
// Переводим все пины порта D и C в режим чтения с него с подтяжкой к +5В (если пины порта D висят в воздухе, то на них будет 5 вольт)
PORTD := 0xFF; // На пины порта D и C цепляем кнопки "механического" геймпада
DDRD := 0x00; // Назначаем эти пины на вход
PORTC := 0xFF; //
DDRC := 0x00; //
// Переводим пины E2, E1, B7 в режим выходов со значением по умолчанию "0"
PORTE.2 := 0; // Светодиод LED1 - "0"-режим управления с геймпада, "1"-режим переназначения кнопок гейппадов
DDRE.2 := 1; // Назначаем пин на выход
PORTE.1 := 0; // Светодиоды LED3 и LED2. Режим 1 - горит LED3, режим 2 - горит LED2, режим 3 - горят оба, но чуть тусклее
DDRE.1 := 1; // Назначаем пин на выход
// Переводим пины E0, B6 в режим входов с подтяжкой к +5В - это кнопки управления прибором
PORTE.0 := 1; // Кнопка управления турборежимом BTN1
DDRE.0 := 0; // Назначаем пин на вход
PORTB.6 := 1; // Кнопка выбора режима BTN2 (16-ти кнопочный "мех" гейпад, либо 2 NES гейпадов, либо 8-ми кнопочный "мех" и первый NES геймпады
DDRB.6 := 0; // Назначаем пин на вход
// Тестовая конфигурация для отладки
{k1[0]:= 0; k2[0]:= 0;
k1[1]:= 1; k2[1]:= 1;
k1[2]:= 2; k2[2]:= 2;
k1[3]:= 3; k2[3]:= 3;
k1[4]:= 4; k2[4]:= 4;
k1[5]:= 3; k2[5]:= 0;
k1[6]:= 2; k2[6]:= 6;
k1[7]:= 1; k2[7]:= 7;
k1[8]:= 0; k2[8]:= 6;
k1[9]:= 1; k2[9]:= 5;
k1[10]:= 2; k2[10]:= 4;
k1[11]:= 3; k2[11]:= 2;
k1[12]:= 4; k2[12]:= 2;
k1[13]:= 3; k2[13]:= 1;
k1[14]:= 2; k2[14]:= 0;
k1[15]:= 1; k2[15]:= 1;}
//Обнуление переменных
m:=0;
s:=0;
z:=0;
a:=0x00;
// Основной цикл
while TRUE do
begin
if rezh=0 then // Режим работы с 16-ти кнопочным "мех" геймпадом
begin
PORTE.1:=0; // Порт LED3 и LED2 на выход и устанавливаем "0". Тем самым ток пойдет через LED3
DDRE.1:=1; //
Delay_ms(500); // Задержка 500 мс
keyd:=0xFFFF; // Сбрасываем массив с инфой о нажатых кнопках
PORTC := 0xFF; // Переводим порт C в режим как в установках перед началом основного цикла (строка 79 кода)
DDRC := 0x00; // Порт C на вход с подтяжкой к +5В
z:=0; // Сбрасываем счетчик работы турбокнопок
zad:=EEPROM_read(65); // Вспоминаем, какую скорость турбокнопок мы настроили ранее
//Главный цикл режима 0 - считывание и соотношение кнопок "мех" джоя и клавиш клавы
while (keyd<>%1111111100001111) and (PINB.6<>0) do //Выйти из режима при сочетании кнопок джоя или нажатию кнопки BTN1
begin
For i:=0 to 15 do if i<8 then keyd.i:=PIND.i else keyd.i:=PINC.(i-8); //Формируем массив физически нажатых кнопок джоя
if (PINB.m=0) then //Ловим "бегующий" ноль на m-том столбце матрицы от проца СПЕКТРУМА
begin
a:=0x00; //Сбрасываем буферный байт нажатых кнопок перед его заполнением
For i:=0 to 15 do //Перебор нажатых кнопок джоя
begin
if k1[i]=m then //если для i-той кнопки мы поймали "бегующий" ноль на m-том столбце клавы
begin
if (keyd.i=0) and (turbo1[i]=0x00) then a.k2[i]:=1; //и если эта кнопка вообще нажата и если она не турбо то добавляем её в буферный байт состояния ряда клавы
if (keyd.i=0) and (turbo1[i]=0x01) then //ну а если нажатая кнопка все же турбо
begin
if z>(zad div 2) then a.k2[i]:=1; //и если счетчик тубро больше, чем половина заданной скорости турбо, то тоже добавляем её в буферный байт состояния ряда клавы
z:=z+1; //увеличиваем счетчик турбо на 1
if z=zad then z:=0; //и обнуляем счетчик турбо если он равен заданной скорости турбо
end;
end; //если мы не поймали "бегующий" ноль для i-той кнопки
end;
DDRA:=a; //Физически выставляем состояния нажатых кнопок на ряд клавы путем задачи IO статуса порта A - если кнопка нажата, то бит нужного ряда комутируем жеско на "0", если нет, то пин висит в возухе в том же режиме HI-Z
end;
m:=m+1; //увеличим переменную перебора столбцов клавы на 1
if m=5 then m:=0; //сбросим эту переменную, если все столбцы отпрошены
if PINE.0=0 then //если нажали кнопку BTN0
begin
zad:=zad div 2; //переопределим скорость турбокнопок путем уменьшения zad в 2 раза
if zad=1 then zad:=20;
EEPROM_write(65,zad); //запишем новую скорость турбокнопок в EEPROM
PORTE.2:=1; //мигнем диодом LED1
Delay_ms(200);
PORTE.2:=0;
z:=0; //сбросим счетчик турбо
end;
end;
end;
if (keyd=%1111111100001111) and (rezh=0) then rezh:=1; //Если мы вышли из цикла режима 1 по сочетанию кнопок, то переходим в режим конфигурации
if (PINB.6=0) and (rezh=0) then //Если вышли из цикла режима 1 по BTN2 то
begin
rezh:=3; //Выбираем режим 2
a:=0x00; //Очищаем байт нажатий
DDRA:=0x00; //и порт, отвечающий за ряды спектрума
EEPROM_write(64,0x00); //Пишем выбранный режим в EEPROM
for i:=0 to 15 do //Загружаем в массивы определений кнопок данные для режима
begin
k1[i]:= EEPROM_read (i+32);
k2[i]:= EEPROM_read (i+48);
end;
end;
//Далее буду комментировать только различия от предыдущего кода, так как всё практически повторяет предыдущий режим
if rezh=3 then // Режим работы с 16 кнопками двух NES геймпадов
begin // Порт LED3 и LED2 на выход и устанавливаем "1". Тем самым ток пойдет через LED2
PORTE.1:=1; //
DDRE.1:=1;
Delay_ms(500);
keyd:=0xFFFF;
PORTC.4:=0; //Настраиваем порт C4 для выдачи CLOCK для геймпадов NES
DDRC.4:=1;
PORTC.5:=0; //Настраиваем порт C5 для выдачи LATCH для геймпадов NES
DDRC.5:=1;
PORTC.6:=1; //Настраиваем порт C6 для приема DATA0 первого геймпада NES
DDRC.6:=0;
PORTC.7:=1; //Настраиваем порт C7 для приема DATA1 второго геймпада NES
DDRC.7:=0;
z:=0;
zad:=EEPROM_read(66);
while (keyd<>%1111111110111000) and (PINB.6<>0) do
begin
PORTC.5:=0; //LATCH в "0" - конроллеры NES готовы читать данные по клоку,когда он в ноль
For i:=0 to 7 do //Перебор 16 кнопок NES
begin
keyd.i:=PINC.6; //Читаем i-тую кнопку с DATA0 первого геймпада NES и формируем массив физически нажатых кнопок с 0 по 7
keyd.i+8:=PINC.7; //Читаем i-тую кнопку с DATA1 второго геймпада NES и формируем массив физически нажатых кнопок с 8 по 15
PORTC.4:=1; //CLOCK устанавливаем в "1"
PORTC.4:=0; //CLOCK устанавливаем в "0" - времени достаточно, чтобы контроллер NES отследил это и был готов выдать следующий бит в DATA
end;
PORTC.5:=1; //После перебора LATCH в "1" - передачу DATA от NES зкаончили
if (PINB.m=0) then
begin
a:=0x00;
For i:=0 to 15 do
begin
if k1[i]=m then
begin
if (keyd.i=0) and (turbo2[i]=0x00) then a.k2[i]:=1;
if (keyd.i=0) and (turbo2[i]=0x01) then
begin
if z>(zad div 2) then a.k2[i]:=1;
z:=z+1;
if z=zad then z:=0;
end;
end;
end;
DDRA:=a;
end;
m:=m+1;
if m=5 then m:=0;
if PINE.0=0 then
begin
zad:=zad div 2;
if zad=1 then zad:=40;
EEPROM_write(66,zad);
PORTE.2:=1;
Delay_ms(200);
PORTE.2:=0;
z:=0;
end;
end;
end;
if (keyd=%1111111110111000) and (rezh=3) then rezh:=4; //Если мы вышли из цикла режима 2 по сочетанию кнопок, то переходим в режим конфигурации
if (PINB.6=0) and (rezh=3) then //Если вышли из цикла режима 2 по BTN2 то
begin
rezh:=5; //Выбираем режим 3
a:=0x00;
EEPROM_write(64,0x11);
for i:=0 to 15 do
begin
if i<8 then
begin
k1[i]:= EEPROM_read (i);
k2[i]:= EEPROM_read (i+16);
end
else
begin
k1[i]:= EEPROM_read (i+32-8);
k2[i]:= EEPROM_read (i+48-8);
end;
end;
end;
if rezh=5 then // Режим работы с 8 кнопками "мех" геймпада и первым NES геймпадом
begin
PORTE.1:=0; // Отсоединяем порт (в Hi-Z) от диодов LED3 и LED2. Тем самым сквозной ток пойдет через LED3 и LED2
DDRE.1:=0; //
Delay_ms(500);
keyd:=0xFFFF;
PORTC.4:=0; //Настроим порты C4, C5, C6 для CLOCK, LATCH и DATA для работы с первым NES геймпадом
DDRC.4:=1; //
PORTC.5:=0; //
DDRC.5:=1; //
PORTC.6:=1; //
DDRC.6:=0; //
z:=0;
while (PINB.6<>0) do //Выход из цикла режима только по кнопке переключения режимов
begin
PORTC.5:=0; //Взводим LATCH
For i:=0 to 7 do //Перебор 8 кнопок "механического" и 8 кнопок NES
begin
keyd.i+8:=PINC.6; //Читаем i-тую кнопку с DATA0 первого геймпада NES и формируем массив физически нажатых кнопок с 8 по 15
keyd.i:=PIND.i; //Читаем i-тую кнопку с порта D механического геймпада и формируем массив физически нажатых кнопок с 0 по 7
PORTC.4:=1; //Передергиваем ClOCK
PORTC.4:=0; //
end;
PORTC.5:=1; //Передергиваем LATCH
if (PINB.m=0) then
begin
a:=0x00;
For i:=0 to 15 do if k1[i]=m then if (keyd.i=0) then a.k2[i]:=1; //Игнорируем признаки турбокнопок и просто проверяем все нажатые кнопки
DDRA:=a;
end;
m:=m+1;
if m=5 then m:=0;
end;
end;
if (PINB.6=0) and (rezh=5) then //Если вышли из цикла режима 3 по BTN2 то
begin
rezh:=0; //Режим 1
a:=0x00;
DDRA:=0x00;
EEPROM_write(64,0xFF);
for i:=0 to 15 do
begin
k1[i]:= EEPROM_read (i);
k2[i]:= EEPROM_read (i+16);
end;
end;
if rezh=1 then //Конфигурация кнопок для режима 1
begin
PORTE.2:=1; //LED1 горит
DDRA:=0x00; //Очищаем порт рядов спектрума
Delay_ms(500); //Задержка 500 мс
ext:=0; //обнуляем признак выхода из режима гонфигурации
z:=0; //здесь это признак конфигурации турбокнопок, обнуляем его
i:=0; //обнуляем i (на всякий случай)
while (ext=0) do //Пока признак ext=0, то конфигурируем кнопки
begin
For l:=0 to 7 do //Цикл перебора состояний порта, слушающего ряды спектрума
begin
if PINA.l=0 then //Если обнаружили, что нажата клавиша на l-том ряду клавиатуры спектрума
begin
For m:=0 to 4 do //То перебираем столбцы спектрума
begin
if PINB.m=0 then //Если обнаружили "ноль" на i-том столбце, то
begin
s:=0; //Сбрасываем счетчик перебора кнопок геймпада
Repeat //Перебираем кнопки геймпада
if (PIND.s=0) and (s<8) then //Если нажата s-тая кнопка геймпада, подключеная к D порту (B0..B7) , то
begin
EEPROM_write(s,m); //Пишем в EEPROM столбец m для s-той кнопки
EEPROM_write(s+16,l); //Пишем в EEPROM ряд l для s-той кнопки
EEPROM_write(s+80,z); //Пишем в EEPROM признак турбо для s-той кнопки
i:=i+1; //Счетчик законфигурированных кнопок возрастает на 1
PORTE.2:=0; //Мигнем LED1
Delay_ms(200);
PORTE.2:=1;
z:=0; //Спросим признак конфигурации турбо
end;
if (PINC.(s-8)=0) and (s>=8) then //Если нажата s-тая кнопка геймпада, подключеная к C порту (B8..B15) , то
begin
EEPROM_write(s,m); //аналогично вышенаписанному
EEPROM_write(s+16,l);
EEPROM_write(s+80,z);
i:=i+1;
PORTE.2:=0;
Delay_ms(200);
PORTE.2:=1;
z:=0;
end;
s:=s+1; //счетчик перебора кнопок увеличиваем на 1
if s=16 then s:=0; //если перебрали все кнопки, то сбрасываем счетчик в "0"
Until (PIND=0xFF) and (PINC=0xFF); //заканчиваем перебор, если кнопки геймпада не нажаты
end;
end;
end;
end;
if PINE.0=0 then //Если нажали BTN1 для настройки турбокнопки, то
begin
z:=1; //Признак конфигурации турбокнопки в "1"
PORTE.2:=0; //Мигнем LED1
Delay_ms(200);
PORTE.2:=1;
end;
if (PIND=%00001111) then ext:=1; //Если нажали сочетание кнопок для выхода из конфигурации, то выходим
end;
rezh:=0; //Возвращаемся в режим 1
For i:=0 to 5 do //Мигаем несколько раз LED1
begin
PORTE.2:=NOT(PORTE.2);
Delay_ms(100);
end;
PORTE.2:=0; //Вырубаем LED1
Delay_ms(500); //Задержка 500 мс
for i:=0 to 15 do //Загружаем из EEPROM обновленную конфигурацию кнопок и признаков турбо для режима 1
begin
k1[i]:= EEPROM_read (i);
k2[i]:= EEPROM_read (i+16);
turbo1[i]:=EEPROM_read (i+80);
end;
m:=0; //Обнуляем все
s:=0;
keyd:=0xFFFF;
DDRA:=0x00;
a:=0x00;
end; //Конец конфигурации режима 1
//Далее буду комментировать только различия от предыдущего кода, так как всё практически повторяет предыдущий режим
if rezh=4 then //Конфигурация кнопок для режима 2
begin
PORTE.2:=1;
DDRA:=0x00;
Delay_ms(500);
keyd:=0xFFFF;
ext:=0;
z:=0;
PORTE.2:=1;
i:=0;
while (ext=0) do
begin
For l:=0 to 7 do
begin
if PINA.l=0 then
begin
For m:=0 to 4 do
begin
if PINB.m=0 then
begin
s:=0;
Repeat
PORTC.5:=0; //LATCH в "0" - готовы передавать данные с NES геймпадов
For t:=0 to 7 do //Перебираем все кнопки геймпадов
begin
keyd.t:=PINC.6; //Формируем массив состояний кнопок для первого геймпада NES (кнопки с 0 по 7)
keyd.t+8:=PINC.7; //Формируем массив состояний кнопок для второго геймпада NES (кнопки с 8 по 15)
PORTC.4:=1; //Передергиваем CLOCK
PORTC.4:=0; //
end;
if (keyd.s=0) then //Если нажата s-тая кнокпа геймпадов, то
begin
EEPROM_write(s+32,m); //аналогично режиму конфигурации 1, только адрес EEPROM для режима 2
EEPROM_write(s+48,l);
EEPROM_write(s+96,z);
i:=i+1;
PORTE.2:=0;
Delay_ms(200);
PORTE.2:=1;
z:=0;
end;
s:=s+1;
if s=16 then s:=0;
PORTC.5:=1; //Сбрасываем LATCH в "1";
Until (keyd=0xFFFF); //заканчиваем перебор, если кнопки геймпадов не нажаты
end;
end;
end;
end;
PORTC.5:=0; //LATCH в "0" - готовы передавать данные с NES геймпадов
if PINE.0=0 then
begin
z:=1;
PORTE.2:=0;
Delay_ms(200);
PORTE.2:=1;
end;
For t:=0 to 7 do //Перебираем кнопки геймпадов NES
begin
keyd.t:=PINC.6;
keyd.t+8:=PINC.7;
PORTC.4:=1;
PORTC.4:=0;
end;
PORTC.5:=1;
if (keyd=%1111111110111000) then ext:=1; //Если зажато сочетание кнопок для выхода из режима конфигурации, то выходим
keyd:=0xFFFF;
end;
rezh:=3; //Возвращаемя в режим 2
For i:=0 to 5 do
begin
PORTE.2:=NOT(PORTE.2);
Delay_ms(100);
end;
PORTE.2:=0;
Delay_ms(500);
for i:=0 to 15 do
begin
k1[i]:= EEPROM_read (i+32);
k2[i]:= EEPROM_read (i+48);
turbo2[i]:=EEPROM_read (i+96);
end;
m:=0;
s:=0;
keyd:=0xFFFF;
DDRA:=0x00;
a:=0x00;
end;
end;
end.