Важная информация

User Tag List

Показано с 1 по 6 из 6

Тема: Устройство ZX Joy To Key - подключение джойстиков к ZX Spectrum и назначение клавиш

  1. #1
    Junior
    Регистрация
    16.08.2020
    Адрес
    г. Саров
    Сообщений
    14
    Спасибо Благодарностей отдано 
    1
    Спасибо Благодарностей получено 
    4
    Поблагодарили
    1 сообщение
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию Устройство ZX Joy To Key - подключение джойстиков к ZX Spectrum и назначение клавиш

    Устройство ZX Joy To Key

    Всем привет! Если кому интересно, выкладываю свое устройство ZX Joy To Key для удобного управления в играх с геймпадов на спектруме. Можно подключить самодельные или NES (Денди) геймпады к спектруму, за 10 секунд назначить на геймпад клавиши клавиатуры спектрума и играть! Также можно назначить турбокнопки.

    Данное устройство служит для назначения клавиш механической клавиатуры спектрума на кнопки самодельного геймпада (где от каждой кнопки выведены два провода) и на кнопки одного/двух NES (Денди) геймпадов (не требуют никаких переделок). Пока реализовано только назначение клавиш именно с механической клавиатуры, которая подключена к спектруму и устройству. В дальнейшем планирую сделать назначение клавиш на кнопки с использованием PS/2 клавиатуры (например, для ZX Evolution, так как, я думаю, не многие используют механическую клавиатуру для работы на этом компе). В данной ревизии ZX Joy To Key может работать с любым ZX Spectrum, имеющим механическую клавиатуру (подключенную по контактам 5 столбцов и 8 рядов к спектруму).

    Устройство реализовано на микроконтроллере ATMega162 с 35-ю портами ввода-вывода. ZX Joy To Key можно собрать на любой ATMega с аналогичными портами ввода-вывода (порты A, B, C, D, E0..2). Прошивка должна работать с ними, но я проверял только с ATMega162.


    К пинам B0, B1, B2, B3, B4 ATMega подключены столбцы ZXCOL0 – ZXCOL4 разъема механической клавиатуры.

    К порту A ATMega подключены ряды ZXROW0 – ZXROW7 разъема механической клавиатуры.

    К пинам XTAL2 и XTAL1 необходимо подключить кварцевый резонатор на 16 МГц и 2 конденсатора на 22 пФ согласно даташиту на ATMega162.

    К порту D и C ATMega подключаем самодельный геймпад (с каждой кнопки выведены 2 провода – один на пин порта D или C, другой на землю). Таким образом можно подключить до 16 кнопок (обозначение их на схеме B0-B15) самодельного геймпада. Я сделал себе 2 геймпада – один сеговский (12 кнопок), другой дендевский (8 кнопок). Можно подключить оба, если на сеговском выкинуть 4 кнопки. Тут кому как нравится.

    Также к пинам C4, C5, C6, C7 ATMega можно подключить 2 денди (NES) геймпада без всяких переделок (CLOCK, LATCH,DATA0 - подключение 1-ого геймпада NES (Денди), CLOCK, LATCH, DATA1 - подключение 2-ого геймпада). Следовательно с данным устройством можно работать в следующих режимах ввода:
    1. Осуществлять управление с самодельных геймпадов (до 16 кнопок, можно меньше, другие просто будут не задействованы);
    2. Осуществлять управление с одного или двух NES (Денди) геймпадов;
    3. Осуществлять управление с самодельного геймпада (до 8 кнопок) и первого NES (Денди) геймпада.

    Эти три режима переключаются кнопкой BTN2, подключенной к пину B6 ATMega.

    ВНИМАНИЕ! Если устройство работает в режиме 2, но к пинам C4, C5 подключены кнопки самодельного геймпада и если их нажать, то эти пины закоротятся на землю и могут быть повреждены, так как в режиме 2 они настроены на выход и управляют геймпадами NES.

    К пину E1 подключены светодиоды LED2 и LED3 для индикации текущего режима (режим 1 – горит диод LED3, режим 2 – горит диод LED2, режим 3 – горят оба).

    К пину E2 подключен светодиод LED1 индикации режима конфигурации и работы с турборежимом.

    К пину E0 подключена кнопка BTN1 для управления турбо режимом.

    Описание работы устройства.
    После подачи питания на устройство, включается последний выбранный режим работы, загружается последняя конфигурация кнопок, информация о турбокнопках и последняя выбранная скорость турбо режима (после прошивки – режим 1, клавиши не назначены, турбо режим не назначен, скорость турбо самая медленная, светодиод LED3 горит, LED2 и LED1 не горят).

    Назначение клавиш на кнопки самодельного геймпада в режиме 1.
    Для конфигурации самодельного геймпада в режиме 1, необходимо нажать одновременно 4 кнопки (B4, B5, B6, B7), подключенные к пинам D4, D5, D6, D7. При этом светодиод LED1 загорится.
    Для назначения клавиш необходимо зажать и не отпускать требуемую клавишу на клавиатуре, затем нажать и отпустить ту кнопку на геймпаде, на которую хотите назначить зажатую клавишу клавиатуры, диод LED1 мигнет, значит клавиша назначена.
    Проделать эту процедуру для всех требуемых клавиш.
    Если требуется назначить турбокнопку: нажать разово кнопку BTN1 (при этом диод LED1 мигнет), зажать и не отпускать требуемую клавишу на клавиатуре, затем нажать и отпустить ту кнопку на геймпаде, на которую хотите назначить зажатую клавишу клавиатуры, диод LED1 мигнет.
    После назначения требуемых клавиш, необходимо нажать одновременно 4 кнопки (B4, B5, B6, B7), подключенные к пинам D4, D5, D6, D7, после этого диод LED1 мигнет несколько раз.
    При назначении клавиш и турбокнопок конфигурация пишется в EEPROM микроконтроллера и сохраняется после выключения питания.
    После выхода из режима конфигурации можно работать с самодельным геймпадом.
    Для смены режима и работы с NES (Денди) геймпадами необходимо нажать на кнопку BTN2. После этого светодиод LED3 погаснет, а LED2 загорится.


    Назначение клавиш на кнопки NES (Денди) геймпада в режиме 2.
    Для конфигурации NES(Денди) геймпада в режиме 2, необходимо нажать одновременно 4 кнопки [A, B, Select, Влево] на первом геймпаде, при этом светодиод LED1 загорится.
    Конфигурация клавиш для режима 2 аналогична конфигурации для режима 1. Если подключены оба геймпада NES, можно назначать кнопки обоих в любом порядке.
    Назначение турбокнопок в режиме 2 для геймпадов NES (Денди) производится аналогично назначению турбокнопок в режиме 1.
    После назначения требуемых клавиш, необходимо нажать одновременно 4 кнопки [A, B, Select, Влево] на первом геймпаде, после этого диод LED1 мигнет несколько раз.
    При назначении клавиш и турбокнопок конфигурация пишется в EEPROM микроконтроллера и сохраняется после выключения питания.
    После выхода из режима конфигурации можно работать с обоими геймпадами NES (Денди).
    Для смены режима и работы с 8-ми кнопками самодельного геймпада и первым NES (Денди) геймпадом необходимо нажать на кнопку BTN2. После этого светодиод LED3 загорится, а LED2 продолжит гореть, но оба будут гореть чуть тусклее.

    В режиме 3 нельзя переопределять кнопки геймпадов. Самодельный геймпад будет работать с назначенными 8-ю кнопоками, подключенными к порту D микроконтроллера, также будут работать назначения клавиш на кнопки первого NES (Денди) геймпада.
    Турбокнопки на всех геймпадах будут работать как обычные кнопки. Турбокнопки в режиме 3 я посчитал ненужными.

    Работа с турбокнопками.
    После конфигурации турбокнопок в режимах 1 и 2 можно менять скорость турборежима путем нажатия на кнопку BTN1, после чего мигнет светодиод LED1, значит скорость увеличилась в 2 раза. После нескольких нажатий на BTN1 скорость сбросится на первую и так по кругу. Для режимов 1 и 2 можно выставить разную скорость турборежима и она сохранится после выключения питания.


    Программа для МК написана на MikroPascal, код с комментариями представлен ниже.
    Прошивать EEPROM не нужно.
    Перед прошивкой ATMega162 нужно запрограммировать Fuse биты: CLKDIV8=0 (убираем делитель тактовой частоты на 8), JTAGEN=0 (отключаем JTAG), CKSEL0=1, CKSEL1=1, CKSEL2=1, CKSEL3=1, SUT0=1, SUT1=1 (переводим МК в режим работы от внешнего кварцевого резонатора более 8 МГц). Перед программированием Fuse битов лучше еще раз свериться с даташитом (раздел работы МК от внешнего кварца более 8 МГц)!


    P.S. Для проверки работы геймпадов и отладки программы очень удобно использовать программу для ZX Spectrum "zxkeybtest.tap". Советую использовать её, для наглядного отображения того, что принимает спектрум по клавиатурному интерфейсу.

    Электрическая схема:
    Нажмите на изображение для увеличения. 

Название:	sheet.jpg 
Просмотров:	78 
Размер:	52.2 Кб 
ID:	75241


    Код программы на MikroPascal для МК. Все линейно, без процедур и переходов - памяти МК хватает для этого, к тому же так нагляднее.
    Внесены исправления некоторых багов (ложные нажатия на ближних колонках например), доработан код. Пока багов не обнаружил.

    Скрытый текст

    Код:
    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.
    [свернуть]


    Архив ZIP с прошивкой (JTK.hex), программой для проверки клавы (zxkeybtest.tap), схемой (Схема.jpg), описанием (Описание.doc) и проектом для MikroPascal (папка "PROJECT_Pascal_ZXJTK")
    ZXJTK_v1.2.zip
    Последний раз редактировалось Charlie; 24.04.2021 в 09:26.

  2. Эти 4 пользователя(ей) поблагодарили Charlie за это полезное сообщение:

    Black Cat / Era CG (18.04.2021), IL_DECAMERON (21.04.2021), izzx (18.04.2021), Rusazar (18.04.2021)

  3. #1
    С любовью к вам, Yandex.Direct
    Размещение рекламы на форуме способствует его дальнейшему развитию

  4. #2
    Veteran
    Регистрация
    15.07.2009
    Адрес
    Череповец
    Сообщений
    1,542
    Спасибо Благодарностей отдано 
    30
    Спасибо Благодарностей получено 
    28
    Поблагодарили
    21 сообщений
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    На ZX-Evo назначение COL и ROW линий наоборот относительно других клонов. Тут это каким-либо образом учтено?
    ZX-Evo Rev. C4 (Double-config) / VDAC2 / ZiFi / ZX-TEE (NeoGS / ZXM-Soundcard Extreme) / SMUC (SD-IDE + CF-IDE)

  5. #3
    Junior
    Регистрация
    16.08.2020
    Адрес
    г. Саров
    Сообщений
    14
    Спасибо Благодарностей отдано 
    1
    Спасибо Благодарностей получено 
    4
    Поблагодарили
    1 сообщение
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Я думаю тут нет проблем: COL - это линии, которых 5 штук, ROW - линии, которых 8 штук. Я не знал, что на evo назначение этих линий наоборот. Ну а в общем, все также, как на этой схеме
    Нажмите на изображение для увеличения. 

Название:	i25_keyb1.jpg 
Просмотров:	32 
Размер:	25.0 Кб 
ID:	75250
    KD0-KD4 это у меня COL0-COL4
    A08-A15 это у меня ROW0-ROW7

  6. #4
    Member Аватар для nemo
    Регистрация
    20.01.2020
    Адрес
    г. Калуга
    Сообщений
    95
    Спасибо Благодарностей отдано 
    6
    Спасибо Благодарностей получено 
    14
    Поблагодарили
    11 сообщений
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Если я правильно понимаю то цепляется параллельно клавиатуре. Думается заработает и с адаптерами PS/2 с выводом на разъем мех. клавиатуры. ИМХО FUSE лучше давать в формате LOW-HIGT BYTE во избежании разночтения.

  7. #5
    Junior
    Регистрация
    16.08.2020
    Адрес
    г. Саров
    Сообщений
    14
    Спасибо Благодарностей отдано 
    1
    Спасибо Благодарностей получено 
    4
    Поблагодарили
    1 сообщение
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    nemo, да, должно работать с этими адаптерами. Насчёт fuse согласен, сколько МК я загнал в неправильный режим из-за корявого программирования fuse, потом реанимировал. Поэтому я и советую свериться с даташитом, нужен режим для работы от внешнего кварца, частотой более 8 МГц. В даташите так и прописано.

  8. #6
    Junior
    Регистрация
    16.08.2020
    Адрес
    г. Саров
    Сообщений
    14
    Спасибо Благодарностей отдано 
    1
    Спасибо Благодарностей получено 
    4
    Поблагодарили
    1 сообщение
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    По умолчанию

    Мой вариант исполнения ZX Joy To Key
    Нажмите на изображение для увеличения. 

Название:	k3PIeINuZGo.jpg 
Просмотров:	51 
Размер:	83.0 Кб 
ID:	75274

Информация о теме

Пользователи, просматривающие эту тему

Эту тему просматривают: 1 (пользователей: 0 , гостей: 1)

Похожие темы

  1. ZX-VGA-JOY review - VGA interface for any ZX Spectrum
    от dakidski в разделе Изображение
    Ответов: 0
    Последнее: 27.09.2019, 01:43
  2. Pentagon-128k+AY+Kempston Joy: SU 78
    от xolod в разделе Pentagon
    Ответов: 2
    Последнее: 04.03.2018, 15:49
  3. Много сломанных джойстиков
    от ArtemKuchin в разделе Барахолка (архив)
    Ответов: 10
    Последнее: 10.07.2012, 00:42
  4. Ответов: 7
    Последнее: 02.05.2011, 11:45
  5. Распиновки джойстиков
    от F0lken в разделе Устройства ввода
    Ответов: 13
    Последнее: 05.05.2010, 20:50

Ваши права

  • Вы не можете создавать новые темы
  • Вы не можете отвечать в темах
  • Вы не можете прикреплять вложения
  • Вы не можете редактировать свои сообщения
  •