Подключаем 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

ПО состоит из 2-х основных частей: главный цикл 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 < 10){
current_scan_code = current_scan_code >> 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 и т.п., т.к. на семисегментном индикаторе сделать это не реально.


Список радиоэлементовОбозначение
Тип
Номинал
Количество
ПримечаниеМагазинМой блокнот

МК PIC 8-битPIC18F45201

Линейный регуляторLM78051

Электролитический конденсатор47 мкФ1

Резистор330 Ом7

Кварц20 МГц1

Семисегментный индикатор1

РазъемPS21

Батарея9 В1
Добавить все

Скачать список элементов (PDF)

Оригинал статьи

Прикрепленные файлы:

Добавить комментарий

Ваш адрес email не будет опубликован.