Подключаем ps/2 клавиатуру к pic

Подключаем PS/2 клавиатуру к PIC

Клавиатура является самым распространенным устройством для ввода информации в компьютер. Поэтому важно знать принцип работы и интерфейс связи клавиатуры.

В данной статье описывается устройство, которое позволяет принимать данные от клавиатуры и отображать нажатые клавиши на устройстве вывода. В качестве примера, мы разработаем простейшее устройство с использованием клавиатуры PS/2, микроконтроллера PIC и семисегментного индикатора.

Идея проекта

Главной целью данного проекта является создание устройства, способного работать с PS/2 девайсами, а конкретно с PS/2 клавиатурой. Клавиатура будет подключена к микроконтроллеру PIC, который в свою очередь будет обрабатывать коды нажатых клавиш и выводить символы клавиш на семисегментный индикатор.

PS/2 — это последовательный интерфейс с тактовым сигналом 10-16 кГц, поэтому в PIC нам надо использовать прерывания, для детектирования заднего фронта импульсов.

Список используемых радиоэлементов

Микроконтроллер PIC18F452 (даташит)
7805 — пятивольтовый регулятор напряжения
Кварцевый резонатор 20 МГц
PS/2 коннектор (мама)
7-ми сегментный индикатор
Резисторы

Дополнительно, потребуется программатор для прошивки PIC, макетная плата и перемычки (ну или протравленная печатная плата).

Схемотехника

Как видно из принципиальной схемы ниже, устройство очень простое и основные детали это: 78L05, PIC18F452 и PS/2 разъем.

В разъеме PS/2 пины 2 и 6 не используются, 4-ый пин — питание +5В, 3-ий пин — общий. 5-ый пин — тактовый сигнал, а 1-ый пин — данные.

7-ми сегментный индикатор я использовал с общим катодом.

Немного теории о PS/2

Как уже было сказано выше, в PS/2 используется последовательный протокол передачи информации с двумя линиями: тактовый сигнал и линия данных.

Назначение выводов 6-pin Mini-DIN (PS/2):
1 — Данные
2 — Не используется
3 — Общий (земля)
4 — Питание (+5V)
5 — Тактовый сигнал
6 — Не используется

На рисунке выше показана распиновка PS/2 разъемов папа (слева) и мама (справа). Обычно, разъем типа «папа» используется на стороне устройства — мышь, клавиатура, а разъем типа «мама» на компьютере. В нашем случае (т.к. у нас приемная сторона) мы будет использовать коннектор типа «мама» (можно вырезать с какой-нибудь сгоревшей материнской платы).

Диаграмма сигналов PS/2

На рисунке выше показана стандартная временная диаграмма выходных данных для PS/2 устройств. Последовательность следующая:
1. Вывод данных устанавливается в низкий логический уровень
2. Вывод тактового сигнала устанавливается в низкий уровень
3. Вывод данных продолжает находиться в низком уровне (стартовый бит)
4. Тактовый сигнал переходит в высокий логический уровень
5. Начинается передача восьми битов с данными
6. Далее идет бит контроля четности
7. А за ним стоповый бит

Все данные принимаются по спаду положительного синхроимпульса.

Скан-коды клавиш

Каждая клавиша клавиатуры содержит свой уникальный код, т.н. скан-код.

Как видно из картинок выше, большинство клавиш клавиатуры содержит 8-ми битные значения (1 байт), однако некоторые клавиши, содержат многобайтовую последовательность.

Рассмотрим пример того, как происходит формирование скан-кодов клавиш. Если на клавиатуре нажимается какая-либо клавиша, то на выходе клавиатуры появляется скан-код нажатой клавишы. Когда клавиша отжимается, то на выходе формируется код 0xF0 и скан-код отжатой клавиши. Т.о. можно определить удерживается ли клавиша нажатой или нет, но нам это пока что не нужно.

На рисунке выше приведена осциллограмма PS/2 при нажатой клавиши «J». Канал 1 (желтый) на осциллограмме это таковый сигнал. Канал 2 (голубой) это сигнал данных. Для наглядности, я нанес вспомогательные линии для детектирования спада синхросигнала.
При данной осциллограмме легко можно определить скан-код нажатой клавиши. Не забываем, что слева находится младший бит (т.е. 0), а справа старший (7 бит). Т.о. в двоичном коде получилось 0011 1011, что в шестнадцатеричном является 0x3B, т.е. это скан-код клавиши «J».

Передача данных в клавиатуру

Другой функцией PS/2 протокола является передача данных обратно в клавиатуру, к примеру можно подать команду на включение/отключение светодиода Caps Lock, Num Lock и др. Но не будем на этом зацикливаться, т.к. это тема другой статьи.

Собранная схема на макетной плате выглядит следующим образом:

Программа для PIC

ПО состоит из двух основных частей: главный цикл Main Loop и обработчика прерываний.

В Main Loop происходит прием данных и их обработка для вывода на индикатор. Ну и собственно сам вывод данных.

Часть кода Main Loop:

Итак, в цикле Main Loop происходит обработка данных, которые поступают в fifo-буфер. В коде, который представлен ниже, происходит прием данных PS/2 по прерыванию, после чего, они помещаются в fifo-буфер. Код 0xF0 игнорируется, нас интересуют только нажатия клавиш.

Код прерываний следующий:

Как видно из кода выше, прерывание захвата скан кода и прерывание timer1 используются вместе, чтобы обеспечить «захват» 8-ми бит, т.к. нам не нужны стартовые, стоповые биты и бит контроля четности.

Как видно из видео выше, устройство прекрасно работает и отображает нажатые цифры и буквы. Единственное, я не стал отображать такие клавиши как W, N и т.п., т.к. на семисегментном индикаторе сделать это не реально.

Подключаем ps/2 клавиатуру к pic

преобразователь скан кода компьютерной клавиатуры PS/2 в UART.
видео камера не высокого разрешения по этому плохо видно как отображаются на экране ноутбука, в программе Hyper Terminal нажатые на клавиатуре кнопки.

Работает следующим образом, данные проходят Клавиатура —> скан код—> микроконтроллер ATmega8—> UART—> MAX232—>COM port—>Hyper Terminal

Исходник на BASCOM AVR

‘ программа kebord—>ascii

‘———-
‘ директивы компилятора
‘———-
$regfile = «m8def.dat» ‘ тип процессора
$crystal = 14318180 ‘ частота кварца
$baud = 9600
‘Config Serialin = Buffered , Size = 16 ‘ скорость связи

‘———-
‘ соответствие электрических цепей выводам портов
‘———-
‘ сеть
‘ направление данных в сети
‘ конечники

Dim B As Byte
Dim B_o As Byte
Dim Y As Byte
Dim C As Byte

Dim V As Bit
Dim O As Bit
Dim P As Bit

Dim In_p As Bit
Dim Caps As Bit

‘======================
===
‘ начало программы
‘———-
‘ вектор прерывания по сбросу (начало программы)
Startmodule:
‘ обрабатываем источник сброса
‘ if MCUCSR.WDRF = 1 then goto ResetWD

Resetwd: ‘ сброс по сторожевому таймеру
‘ resetFlag = MCUCSR
‘ MCUCSR.WDRF = 0

Configmodule:
‘настройка портов ввода/вывода
‘внутреннее сопротивление
‘0 — 100кОм(в микроконтроллер)
‘1- низкое (измикроконтроллера)

‘подтягивание
‘1 — к плюсу
‘0 — на нуле

Ddrb = &B00000000
Ddrc = &B00000000
Ddrd = &B00000010
Portb = &B00000000
Portc = &B00000000
Portd = &B00000000

Ucsrc = &B10111110 ‘2-stop odd-par

Config Int0 = Falling

On Int0 Int0_int

Enable Interrupts ‘ разрешить работу прерываний
Enable Int0

Stop Ac ‘ отключить питание
‘ настройка АЦП
‘ Stop ADC
‘ F_him = 10

‘переходит в режим приёма ожидает начало пакета

‘ Enable Interrupts ‘ разрешить работу прерываний

‘ основной цикл программы
Reset Caps

If B = &H12 Then Set Caps
If B = &H59 Then Set Caps

If B_o = &HF0 Then
If B = &H12 Then Reset Caps
If B = &H59 Then Reset Caps
End If

If Caps = 0 Then
Select Case B

Case &H69 : C = &H31 ‘1
Case &H72 : C = &H32 ‘2
Case &H7A : C = &H33 ‘3
Case &H6B : C = &H34 ‘4
Case &H73 : C = &H35 ‘5
Case &H74 : C = &H36 ‘6
Case &H6C : C = &H37 ‘7
Case &H75 : C = &H38 ‘8
Case &H7D : C = &H39 ‘9
Case &H70 : C = &H30 ‘0

Читайте также  Подключение 4-разрядного led индикатора всего к 4 портам микроконтроллера

Case &H16 : C = &H31 ‘1
Case &H1E : C = &H32 ‘2
Case &H26 : C = &H33 ‘3
Case &H25 : C = &H34 ‘4
Case &H2E : C = &H35 ‘5
Case &H36 : C = &H36 ‘6
Case &H3D : C = &H37 ‘7
Case &H3E : C = &H38 ‘8
Case &H46 : C = &H39 ‘9
Case &H45 : C = &H30 ‘0
Case &H4E : C = &H2D ‘-
Case &H55 : C = &H3D ‘=
Case &H5D : C = &H5C ‘

Case &H15 : C = &H71 ‘q ‘
Case &H1D : C = &H77 ‘w
Case &H24 : C = &H65 ‘e
Case &H2D : C = &H72 ‘r
Case &H2C : C = &H74 ‘t
Case &H35 : C = &H79 ‘y
Case &H3C : C = &H75 ‘u
Case &H43 : C = &H69 ‘i
Case &H44 : C = &H6F ‘o
Case &H4D : C = &H70 ‘p
Case &H54 : C = &H5B ‘[
Case &H5B : C = &H5D ‘]

Case &H1A : C = &H7A ‘z
Case &H22 : C = &H78 ‘x
Case &H21 : C = &H63 ‘c
Case &H2A : C = &H76 ‘v
Case &H32 : C = &H62 ‘b
Case &H31 : C = &H6E ‘n
Case &H3A : C = &H6D ‘m
Case &H41 : C = &H2C ‘,
Case &H49 : C = &H2E ‘.
Case &H4A : C = &H2F ‘/

Case &H29 : C = &H20 ‘» «
Case &H5A : C = &H0D ‘ «enter»
Case &H76 : C = &H1B ‘ «esc»

Case Else : Reset O

End Select
End If

If Caps = 1 Then
Select Case B

Case &H69 : C = &H31 ‘1
Case &H72 : C = &H32 ‘2
Case &H7A : C = &H33 ‘3
Case &H6B : C = &H34 ‘4
Case &H73 : C = &H35 ‘5
Case &H74 : C = &H36 ‘6
Case &H6C : C = &H37 ‘7
Case &H75 : C = &H38 ‘8
Case &H7D : C = &H39 ‘9
Case &H70 : C = &H30 ‘0

Case &H16 : C = &H21 ‘1 !
Case &H1E : C = &H40 ‘2 @
Case &H26 : C = &H23 ‘3 #
Case &H25 : C = &H24 ‘4 $
Case &H2E : C = &H25 ‘5 %
Case &H36 : C = &H5E ‘6 ^
Case &H3D : C = &H26 ‘7 &
Case &H3E : C = &H2A ‘8 *
Case &H46 : C = &H28 ‘9 (
Case &H45 : C = &H29 ‘0 )
Case &H4E : C = &H5F ‘- _
Case &H55 : C = &H2B ‘= +
Case &H5D : C = &H7C ‘ |

Case &H15 : C = &H51 ‘q ‘
Case &H1D : C = &H57 ‘w
Case &H24 : C = &H45 ‘e
Case &H2D : C = &H52 ‘r
Case &H2C : C = &H54 ‘t
Case &H35 : C = &H59 ‘y
Case &H3C : C = &H55 ‘u
Case &H43 : C = &H49 ‘i
Case &H44 : C = &H4F ‘o
Case &H4D : C = &H50 ‘p
Case &H54 : C = &H7B ‘[<
Case &H5B : C = &H7D ‘]>

Case &H1A : C = &H5A ‘z
Case &H22 : C = &H58 ‘x
Case &H21 : C = &H43 ‘c
Case &H2A : C = &H56 ‘v
Case &H32 : C = &H42 ‘b
Case &H31 : C = &H4E ‘n
Case &H3A : C = &H4D ‘m
Case &H41 : C = &H3C ‘,
Case &H4A : C = &H3F ‘/ ?

Case &H29 : C = &H20 ‘» «
Case &H5A : C = &H0D ‘ «enter»
Case &H76 : C = &H1B ‘ «esc»

Объявление

  • Создано: admin
  • Опубликовано: 08.02.2017, 22:43
  • комментариев: 0

    Подключаем PS2 клавиатуру к PIC

    В данной статье описывается устройство, которое позволяет принимать данные от клавиатуры и отображать нажатые клавиши на устройстве вывода. В качестве примера, мы разработаем простейшее устройство с использованием клавиатуры PS/2, микроконтроллера PIC и семисегментного индикатора.

    Идея:
    Главной целью данного проекта является создание устройства, способного работать с PS/2 девайсами, а конкретно с PS/2 клавиатурой. Клавиатура будет подключена к микроконтроллеру PIC, который в свою очередь будет обрабатывать коды нажатых клавиш и выводить символы клавиш на семисегментный индикатор. PS/2 — это последовательный интерфейс с тактовым сигналом 10-16 кГц, поэтому в PIC нам надо использовать прерывания, для детектирования заднего фронта импульсов.
    Список используемых радиоэлементов:

    • Микроконтроллер PIC18F452
    • 7805 — пятивольтовый регулятор напряжения
    • Кварцевый резонатор 20 МГц
    • PS/2 коннектор (мама)
    • 7-ми сегментный индикатор
    • Резисторы
    • Дополнительно, потребуется программатор для прошивки PIC, макетная плата и перемычки (ну или протравленная печатная плата).

    Схемотехника:
    Как видно из принципиальной схемы ниже, устройство очень простое и основные детали это: 78L05, PIC18F452 и PS/2 разъем.

    Назначение выводов 6-pin Mini-DIN (PS/2):

    1. Данные
    2. Не используется
    3. Общий (земля)
    4. Питание (+5V)
    5. Тактовый сигнал
    6. Не используется

    На рисунке выше показана распиновка PS/2 разъемов папа (слева) и мама (справа). Обычно, разъем типа «папа» используется на стороне устройства — мышь, клавиатура, а разъем типа «мама» на компьютере. В нашем случае (т.к. у нас приемная сторона) мы будет использовать коннектор типа «мама» (можно вырезать с какой-нибудь сгоревшей материнской платы).

    Диаграмма сигналов PS/2:

    На рисунке выше показана стандартная временная диаграмма выходных данных для PS/2 устройств. Последовательность следующая:
    1. Вывод данных устанавливается в низкий логический уровень
    2. Вывод тактового сигнала устанавливается в низкий уровень
    3. Вывод данных продолжает находиться в низком уровне (стартовый бит)
    4. Тактовый сигнал переходит в высокий логический уровень
    5. Начинается передача восьми битов с данными
    6. Далее идет бит контроля четности
    7. А за ним стоповый бит
    Все данные принимаются по спаду положительного синхроимпульса.

    Скан-коды клавиш:
    Каждая клавиша клавиатуры содержит свой уникальный код, т.н. скан-код.

    Как видно из картинок выше, большинство клавиш клавиатуры содержит 8-ми битные значения (1 байт), однако некоторые клавиши, содержат многобайтовую последовательность.

    На рисунке выше приведена осциллограмма PS/2 при нажатой клавиши «J». Канал 1 (желтый) на осциллограмме это таковый сигнал. Канал 2 (голубой) это сигнал данных. Для наглядности, я нанес вспомогательные линии для детектирования спада синхросигнала.

    При данной осциллограмме легко можно определить скан-код нажатой клавиши. Не забываем, что слева находится младший бит (т.е. 0), а справа старший (7 бит). Т.о. в двоичном коде получилось 0011 1011, что в шестнадцатеричном является 0x3B, т.е. это скан-код клавиши «J».

    Передача данных в клавиатуру:
    Другой функцией PS/2 протокола является передача данных обратно в клавиатуру, к примеру можно подать команду на включение/отключение светодиода Caps Lock, Num Lock и др. Но не будем на этом зацикливаться, т.к. это тема другой статьи.
    Собранная схема на макетной плате выглядит следующим образом:
    ПО состоит из двух основных частей: главный цикл Main Loop и обработчика прерываний.
    В Main Loop происходит прием данных и их обработка для вывода на индикатор. Ну и собственно сам вывод данных.
    Часть кода Main Loop:

    #include
    #include
    #include
    #include
    //7-Segment Display Output
    #define number_0 0b01111110
    ..
    .
    ..
    #define letter_a 0b11101110
    #define letter_b 0b11111110
    ..
    .
    ..
    void main(void) <
    TRISC = 0xFF;
    TRISD = 0x01;
    PORTB = 0x00;
    PORTC = 0x00;
    //7-Seg LED is Reverse Polarity
    PORTD = 0x00 ^ 0xFF;
    Delay10KTCYx(10);
    INTCON = 0b11000000;
    OpenCapture1( C1_EVERY_FALL_EDGE & CAPTURE_INT_ON );
    OpenTimer1( TIMER_INT_ON & T1_SOURCE_INT & T1_PS_1_1 & T1_16BIT_RW );
    WriteTimer1( 0x0000 );
    while(1)
    <
    if(buf_ready == 1) <
    switch(scan_code_buf[0]) <
    case 0x1C : PORTD = (letter_a ^ 0xFF);
    break;
    .
    .
    ..
    break;
    case 0x45 : PORTD = (number_0 ^ 0xFF);
    break;
    case 0x66 : PORTD = (delete ^ 0xFF);
    break;
    default :
    break;
    >
    //Shift Buffer Forward
    scan_code_buf[0] = scan_code_buf[1];
    scan_code_buf[1] = scan_code_buf[2];
    scan_code_buf[2] = scan_code_buf[3];
    scan_code_buf[3] = scan_code_buf[4];
    scan_code_buf[4] = scan_code_buf[5];
    scan_code_buf[5] = scan_code_buf[6];
    scan_code_buf[6] = scan_code_buf[7];
    scan_code_buf_cnt—;
    if(scan_code_buf_cnt == 0)
    buf_ready = 0;
    >
    Delay10KTCYx(1);
    >
    >

    Итак, в цикле Main Loop происходит обработка данных, которые поступают в fifo-буфер. В коде, который представлен ниже, происходит прием данных PS/2 по прерыванию, после чего, они помещаются в fifo-буфер. Код 0xF0 игнорируется, нас интересуют только нажатия клавиш. Код прерываний следующий:

    void InterruptHandlerHigh(void) // Declaration of InterruptHandler
    <
    //Check If TMR1 Interrupt Flag Is Set
    if(PIR1bits.CCP1IF) <
    if(bit_counter > 1;
    current_scan_code += (PORTDbits.RD0*0b10000000000);
    bit_counter++;
    >
    else if(bit_counter == 10) <
    scan_code_buf[scan_code_buf_cnt]=(current_scan_code>>2)&0xFF;
    scan_code_buf_cnt++;
    buf_ready = 1;
    bit_counter = 0;
    >
    WriteTimer1( 0x0000 );
    //Clear CCP1 Overflow Flag Bit
    PIR1bits.CCP1IF = 0;
    >
    //Check If CCP1 Interrupt Flag Is Set
    else if(PIR1bits.TMR1IF) <
    //Clear Timer1 Overflow Flag Bit
    bit_counter = 0;
    PIR1bits.TMR1IF = 0;
    >
    INTCONbits.GIE = 1;
    >

    Как видно из кода выше, прерывание захвата скан кода и прерывание timer1 используются вместе, чтобы обеспечить «захват» 8-ми бит, т.к. нам не нужны стартовые, стоповые биты и бит контроля четности. Единственное, я не стал отображать такие клавиши как W, N и т.п., т.к. на семисегментном индикаторе сделать это не реально. В архиве по этой ссылке — исходный код и прошивка для микроконтроллера PIC18F452

    Тема: Клавиатура PS/2 PIC контроллер

    Обратные ссылки
    • URL обратной ссылки
    • Подробнее про обратные ссылки
    • Закладки & Поделиться
    • Отправить тему форума в Digg!
    • Добавить тему форума в del.icio.us
    • Разместить в Technorati
    • Разместить в ВКонтакте
    • разместить в Facebook
    • Разместить в MySpace
    • Разместить в Twitter
    • Разместить в ЖЖ
    • Разместить в Google
    • Разместить в Yahoo
    • Разместить в Яндекс.Закладках
    • Разместить в Ссылки@Mail.Ru
    • Reddit!
  • Опции темы
    • Версия для печати

Клавиатура PS/2 PIC контроллер

Всем доброго вечера, есть задача, считать данные с обычной компьютерной клавы PS/2 на PIC контроллер, в каком виде данные идут от клавы?

  • Поделиться
    • Поделиться этим сообщением через
    • Digg
    • Del.icio.us
    • Technorati
    • Разместить в ВКонтакте
    • Разместить в Facebook
    • Разместить в MySpace
    • Разместить в Twitter
    • Разместить в ЖЖ
    • Разместить в Google
    • Разместить в Yahoo
    • Разместить в Яндекс.Закладках
    • Разместить в Ссылки@Mail.Ru
    • Reddit!

Где то видел в тырнете, пороюсь. Найду — выложу.

  • Поделиться
    • Поделиться этим сообщением через
    • Digg
    • Del.icio.us
    • Technorati
    • Разместить в ВКонтакте
    • Разместить в Facebook
    • Разместить в MySpace
    • Разместить в Twitter
    • Разместить в ЖЖ
    • Разместить в Google
    • Разместить в Yahoo
    • Разместить в Яндекс.Закладках
    • Разместить в Ссылки@Mail.Ru
    • Reddit!

  • Поделиться
    • Поделиться этим сообщением через
    • Digg
    • Del.icio.us
    • Technorati
    • Разместить в ВКонтакте
    • Разместить в Facebook
    • Разместить в MySpace
    • Разместить в Twitter
    • Разместить в ЖЖ
    • Разместить в Google
    • Разместить в Yahoo
    • Разместить в Яндекс.Закладках
    • Разместить в Ссылки@Mail.Ru
    • Reddit!

Данные идут последовательно, побитно и каждый бит тактируется синхроимпульсом. Информация двусторонняя т.е. от контроллера на клаву тоже могут поступать команды.
Клава с разъемом PS/2 и со старым DIN ничем по интерфейсу не отличаются.
Реализацию устройства с взаимодействием контроллера с клавой можно помотреть здесь. http://www.rx3akt.narod.ru/psk31_akt.html

  • Поделиться
    • Поделиться этим сообщением через
    • Digg
    • Del.icio.us
    • Technorati
    • Разместить в ВКонтакте
    • Разместить в Facebook
    • Разместить в MySpace
    • Разместить в Twitter
    • Разместить в ЖЖ
    • Разместить в Google
    • Разместить в Yahoo
    • Разместить в Яндекс.Закладках
    • Разместить в Ссылки@Mail.Ru
    • Reddit!

Андрей , не совсем понятно , чего Вы хотите
Любому обычному человеку достаточно набрать в гугле пару фраз — и все будет ясно .

PS Ваш вопрос в теме звучит так — » есть задача — хочу пописать, вопрос — кто меня доведет до туалета?»
Вы предлагаете сделать это Вашим коллегам?
А чО — сами до туалета не дойдете?

Последний раз редактировалось RU3GA; 21.12.2008 в 01:44 .

  • Поделиться
    • Поделиться этим сообщением через
    • Digg
    • Del.icio.us
    • Technorati
    • Разместить в ВКонтакте
    • Разместить в Facebook
    • Разместить в MySpace
    • Разместить в Twitter
    • Разместить в ЖЖ
    • Разместить в Google
    • Разместить в Yahoo
    • Разместить в Яндекс.Закладках
    • Разместить в Ссылки@Mail.Ru
    • Reddit!

Здравсвуйте, спасибо всем тема закрыта, to RU3GA, времени слишком мало, вот и решил спросить у коллег.73!

  • Поделиться
    • Поделиться этим сообщением через
    • Digg
    • Del.icio.us
    • Technorati
    • Разместить в ВКонтакте
    • Разместить в Facebook
    • Разместить в MySpace
    • Разместить в Twitter
    • Разместить в ЖЖ
    • Разместить в Google
    • Разместить в Yahoo
    • Разместить в Яндекс.Закладках
    • Разместить в Ссылки@Mail.Ru
    • Reddit!

Ну ясенно , у Вас времени мало (в поисковике набрать ту же фразу — времени нет) — а у коллег времени полно ?
И они Вам расскажут на 5 страницах (а выйдет никак не меньше ) как посылать биты в клавиатуру — этого ждали ?

PS2 Клавиатура

Снова хочу вернуться к подключению PS2 клавиатуры. Недавно заметил у стандартной библиотеки большой изъян — при чтении(kbd.read()) программа встает намертво, пока не получит символ. Вскрыв код библиотеки, я увидел кучу пустых while-ов:

while (digitalRead(_ps2clk) == HIGH) ; if (digitalRead(_ps2data) == HIGH) < data = data | bit; >while (digitalRead(_ps2clk) == LOW) ; //и еще много таких

После двух мучительных часов, мой мозг выдал следующее:

Перед передачей данных, PS2-устройство проверяет линию Clock. Она должна быть в высоком состоянии >50 мкс, перед передачей. Если она в низком состоянии, то хост запрещает передачу данных и нужно ждать, пока линия не освободится. Т.е. PS2-устройство отправляет бит данных на линию Data когда Clock в высоком состоянии, а хост читает когда Clock в низком состоянии.

Получается, чтобы избежать таких задержек, нужно использовать прерывания и т.п. Я попытался — увы, ничего не получилось.

Чуть позже я нашел отличную замену PS2 библиотеки — PS2KeyboardExt2.

Стандартно клавиатуру нужно подключать так: CLOCK — 3pin(см. дальше), DATA — 2pin. Причем CLOCK пин нельзя изменить! Так как pin-3, у всех «видов» ардуин, — аппаратное прерывание. Давайте рассмотрим стандартный пример библиотеки:

Из этого кода получается почти готовый текстовый редактор. Правда, русских символов там нет. Shift, Capslock — работают. Здесь, функция read() не останавливает программу, так как все работает по прерыванию. Меня огорчило только то, что нельзя читать «чистый» код клавиш и посылать напрямую команды клавиатуре. Я это исправил *Ссылка* Все функции библиотеки:

  • .begin(DATA_PIN, lights) = DATA_PIN — пин DATA, lights — разрешить/запретить управление светодиодами клавиатуры
  • .read() = чтение символов(с учетом кл.SHIFT и т.д.) и некоторых других клавиш по таблице Scan Key 2.
  • .write(DATA) = отправить PS2 команду клавиатуре. Все команды здесь.
  • .read_extra() = читать дополнительные байты информации.
  • .readCode() = читать «чистый» код клавиши. Стандартно в клавиатуре установлен Scan Key 2, но может быть еще и Scan Key 1, Scan Key 3.
  • .readCodeBuf() = Тоже самое, что и .readCode() , но с доп. буфером на 45 код-ов. Для медленных/тормозящих программ.
  • .available() = Сигнализирует о нажатии клавиши или о имеющемся коде в буфере. Возвращает true/false
  • .availableCode() = Аналогично предыдущему, но реагирует на любую поступающую информацию от клавиатуры.
  • .reset() = Сброс/Перезагрузка контроллера клавиатуры.

Заметьте, когда мы нажимаем клавишу и удерживаем, то вначале выводится 1 символ, затем они повторяются, но с небольшой задержкой. Это все хорошо для редактирования текста, для каких-либо действий, нуждающихся в точности. Но как быть с играми или задачами, которым нужна скорость, а не точность? В старом добром QBasic была функция типа: ScanKey, Readkey, KeyCode…

*Некоторые команды от хоста к клавиатуре*

Код команды Название Описание (все команды см.там)
0xFF Reset Клавиатура отвечает “ACK” – 0xFA, и затем переходит в режим сброса
0xF6 Set Default Устанавливает временные задержки клавиш по-умолчанию и включает набор скан-кодов Scan Code Set 2
0xF5 Disable Клавиатура перестаёт сканировать клавиши, устанавливает временные задержки клавиш по-умолчанию, включает набор скан-кодов Scan Code Set 2 и ждёт дальнейших команд
0xF4 Enable Отменяет команду Disable
0xF3 Set Typematic Rate/Delay Устанавливает частоту повтора клавиши при длительном нажатии (typematic rate) и задержку перед началом повторов (delay). За этим байтом следует байт аргументов.
0xF0 Set Scan Code set Клавиатура отвечает “ACK”, потом ждет байт аргумента от компьютера. Если байт аргумента 0×01, 0×02 или 0×03, то устанавливается соответствующий набор скан-кодов Scan Code Set. Если байт 0х00, то клавиатура возвращает номер текущего набора. Затем клавиатура отвечает “ACK.
0xEE Echo Клавиатура отвечает “Echo” (0xEE)
0xF8 Set all keys to make/release Отключает typematic, отправляет только информацию о нажатии и отпускании клавиши.

Последняя команда нам и нужна! Но, есть условие, эта команда работает только со Scan Code 3 , а стандартно устанавливается 2, для этого используем Scan Code set.

Теперь при нажатии и отпускании клавиши мы будем получать следующую картину.

Для удобства можно создать несколько переменных типа boolean, для каждой участвующей клавиши. Нам нужно при нажатии приводить переменную(клавиши) в значение true, и следить за появлением кода 0xF0, при его наличии ждать код клавиши, а затем обнулить соответствующую переменную. Вот реализация: для ENTER, SPACE и стрелок:

Делаем из Raspberry клавиатуру при помощи PS/2 интерфейса

Здравствуйте, уважаемые хабражители!

В этой публикации я расскажу об эмуляции PS/2 клавиатуры при помощи Raspberry Pi.

Недавно в один из жарких вечеров мне позвонил мой старый знакомый и попросил написать для него программу. Необходимо было автоматизировать ввод данных (штрих кодов). Торговая точка, в которой он работал, принадлежала сети итальянских магазинов. Понятно, что и вся работа с товарами велась в итальянской программе. Но по причине того, что в нашей стране основная масса обучена работе на 1С, было принято решение вести продажи на ней, а к концу рабочего дня выгружать результаты продаж в итальянскую систему. Тут то и возникли неудобства.

За день количество проданного товара могло превышать полторы тысячи позиций. Вводить штрих код каждого из них в итальянскую систему стало проблематично. Алгоритм ввода был следующий: ввели штрих код, нажали «Ввод» — и по новой. Договорились встретиться на утро и подробно рассмотреть варианты.

Долго не думая, я написал программу, которая последовательно берет данные с Excel листа и посылает в активное окно. Убедившись, что все работает, пошёл спать.

На следующий день меня ждал сюрприз, о котором я, почему-то, сразу и не подумал. На машине с итальянской программой стояли жёсткие групповые политики, запрещающие запуск сторонних программ по хеш-листу. Админы (тоже итальянцы, кстати) не хотели брать на себя ответственность и разрешать запуск сторонних программ. На обход системы защиты одобрения от местного руководства я не получил. Тут-то и пришла идея решения данной проблемы с аппаратной стороны (ведь никто не запрещает подключать стороннюю клавиатуру). Вспомнил я и про Raspberry Pi, который пылился у меня дома.

Начались поиски документации с описанием PS/2 интерфейса. К счастью, на первом же попавшемся ресурсе (), нашёл всю необходимую информацию.

Распиновка кабеля PS/2 клавиатуры

Как оказалось, необходимыми для всей работы провода было 4.
Черный — земля;
Красный — 5V;
Желтый –пин синхронизации времени (CLOCK);
Белый – пин с данными (DATA).

Цвета могут слегка отличаться. Даже из этих 4-х проводов мне понадобились только два — желтый и белый (в земле и 5v мой аппарат, в отличим от клавиатуры, не нуждался).

Описание работы протокола PS/2 (клавиатура -> хост-контролер)

Определимся с терминологией: если на пине присутствует напряжение — будем считать это состояние как 1, иначе 0.

По умолчанию, когда компьютер в состоянии принимать данные, на обоих пинах (CLOCK и DATA) установлено состояние 1. Его устанавливает хост-контроллер на материнской плате компьютера. Принимаем управление на себя, подавая свое напряжение на оба пина (контроллер м.п. снимет свое напряжение). Для инициализации передачи данных мы должны послать 0-й бит компьютеру (не путать с состоянием 0). Для этого в пине DATA устанавливаем состояние 0 и сразу после этого состояние пина CLOCK тоже переводим на 0 (именно в этом порядке). Мы дали хост-контроллеру понять, что хотим передать первый бит. Теперь, если вернуть состояние пина CLOCK на состояние 1, хост-контролер считает первый бит. Таким образом, будем передавать и все остальные биты.

Первый бит всегда 0, это старт-бит (даем знать, что передаем данные).
Далее передаем 8 бит скан-кода клавиши, которую хотим нажать.
Десятым битом подаем бит четности (если количество единиц четное, то 1, иначе 0).
Последний, 11 бит, это стоп-бит, всегда 1.

Таким образом, один пакет данных формируется из 11 бит.

К примеру, если мы хотим нажать клавишу «0» (скан-код 45h= 1000101 в бинарном виде) на хост-контролер посылается следующий массив бит: 01010001001.

Приняв эти данные, компьютер обработает команду нажатия данной клавиши, но ее еще необходимо отжать. Для этого необходимо сперва послать команду F0h, а после — повторно скан-код клавиши, которую необходимо отжать. Так же, между сменами состояний необходимо удерживать паузу. Опытным путем я установил наиболее подходящее: 0.00020 сек если работать на Python и 1 наносек, если кодить на Java.

Схема подключения к хост-контролеру

Несколько слов о том, почему я подключил аппарат параллельно клавиатуре. При включении компьютера BIOS проводит проверку состояния PS/2 разъемов. Компьютер и клавиатура обмениваются данными о готовности работать. Клавиатура должна провести внутреннюю диагностику и доложить компьютеру о своей готовности. Только после этого биос разрешает работать с PS/2 интерфейсом. Реализовывать чтение команд от компьютера я поленился.

Теперь при включении компьютера клавиатура доложит ему о своей готовности. После этого я включаю Raspberry Pi и как только он примет управление над интерфейсом на себя работа с клавиатуры будет невозможна. При работе никаких конфликтов я не выявил. Все работало как надо, за исключением того, что изредка компьютер некорректно обрабатывал посланные ему данные, а так как мой Raspberry не настроен на получение данных (в данном случае команды повторно послать код клавиши), то ошибка просто игнорировалась. Эта проблема решилась уменьшением частоты передачи данных.

Программная часть

Сперва серверную часть написал на Java, используя библиотеку pi4j, но как показал логический анализатор, Java машина плохо работала с задержками (они получались слишком большие и компьютер очень часто некорректно принимал данные). Python показал себя намного лучше, код выполнялся быстро, а система грузилась в разы меньше.

Вот и сам код на Phyton:

Серверная часть на Java:

Клиентская часть на Java:

Пример оцифрованного сигнала, отправленного с моего аппарата на компьютер. Нижний канал CLOCK, верхний DATA. Сигналы посылаю с Python’а

Заключение

Конечно, использовать Raspberry для такой мелкой задачи чистой воды расточительство. Можно было использовать Arduino или собрать схему на дешевеньком arm процессоре. Но это была просто импровизация, которая первой пришла на ум, да и ждать, пока прибудут все необходимые запчасти из Китая, не особо хотелось.

В общем, надеюсь, кому нибудь пригодится данный опыт. Лично я получил массу удовольствия от всего этого процесса.