alexval2007 | Дата: Воскресенье, 27.06.2010, 14:11 | Сообщение # 1 |
Электро воспламенитель
Группа: Администраторы
Сообщений: 659
Статус: Offline
| Подключение PC AT клавиатуры к AVR Большинство микроконтроллеров, должно иметь какой нибудь интерфейс с человеком. Это приложение описывает в качестве одного из вариантов, использование стандартной PC AT клавиатуры. Рассмотрим подключение стандартной PS/2 клавиатуры к микроконтроллеру AVR. Особенности * Подключается стандартная PC AT клавиатура. Требуется только два I/O вывода. Один из них должен быть входом внешнего прерывания. Не требуется внешних элементов Введение Большинство микроконтроллеров, должно иметь какой нибудь интерфейс с человеком. Это приложение описывает в качестве одного из вариантов, использование стандартной PC AT клавиатуры. Физический интерфейс Физический интерфейс между клавиатурой и микроконтроллером показан на рисунке 1. Используются две сигнальных линии - синхронизации и данных. Сигнальные линии с открытым коллектором и имеют подтягивающие резисторы, расположенные в клавиатуре. Это позволяет как микроконтроллеру, так и клавиатуре формировать на линиях низкий уровень. Существует два типа разъемов, 5-ти штырьковый DIN разъем типа 5D, и миниатюрный 6-ти штырьковый мини-DIN. Расположение выводов показано в таблице 1. Рисунок 1. Интерфейс. Таблица 1. Расположение контактов разъемов PC клавиатуры Разъем DIN41524 6-pin | Mini DIN PS2 | Синхронизация 1 | 5 Данные 2 1 | Не используются | 3 2, 6 Земля GND 4 | 3 Питание +5 В 5 | 4 Экран Оплетка | Оплетка Временные диаграммы Временные диаграммы передачи данных от клавиатуры к микроконтроллеру показаны на рисунке 2. Протокол обмена следующий: один старт бит (всегда 0), восемь бит данных, один бит четности и один стоп бит (всегда 1). Данные действительны в течении низкого уровня сигнала синхронизации. Синхроимпульс формируется клавиатурой с длительностью низкого и высокого уровней по 30-50 мкс. Микроконтроллер также может посылать команды в клавиатуру, устанавливая низкий уровень на линии синхронизации, затем формируя импульс низкого уровня на линии данных (старт бит). После чего линия синхронизации должна быть освобождена микроконтроллером. Затем клавиатура сформирует 10 синхроимпульсов. Данные на линии данных должны быть установлены микроконтроллером до формирования спада сигнала синхронизации. После 10-го бита, клавиатура проверяет наличие высокого уровня на линии данных (стоп бит), и если это так то, в свою очередь формирует низкий уровень. Это указывает микроконтроллеру, что данные приняты клавиатурой. Скан-коды Каждая клавиша АТ клавиатуры имеет свой скан-код. Этот код передается при нажатии клавиши. Если клавиша остается нажатой, то код начинает передаваться повторно. Частота повторения примерно 10 раз в секунду. Когда клавиша отпускается, после скан-кода клавиши передается код "BREAK" ($F0). Для большинства клавиш размер скан-кода составляет один байт. Некоторые клавиши, такие как Home, Insert и Delete имеют расширенный скан-код, от двух до пяти байт. Первый байт всегда $E0. Он также выдается и при формировании "BREAK" кода, то есть E0 F0 xx … АТ клавиатуры могут поддерживать три набора скан-кодов, Второй из которых устанавливается по умолчанию. В примере используется только второй набор. Программное обеспечение Программное обеспечение данного примера применения просто преобразует интерфейс АТ клавиатуры в RS-232 интерфейс. Скан-коды, полученные от клавиатуры преобразуются в соответствующие ASCII коды и передаются при помощи UART. Исходный текст программы написан на С и может быть легко преобразован для использования любым AVR микроконтроллером, имеющим СОЗУ. Замечание: линк-файл (AVR313.xcl), включенный в данный пример применения, должен использоваться вместо стандартного линк-файла. Это делается при помощи меню XLINK - Options. Линк-файл применяется только для микроконтроллера AT90S8515. Алгоритм Прием данных от клавиатуры обрабатывается прерыванием INT0. Прием будет происходить независимо от выполнения остальной программы. Алгоритм довольно прост: сохранение значения линии данных по спаду синхроимпульса. Это проще всего выполняется, если линия синхронизации подключена к INT0 или INT1. Прерывание будет выполняться по каждому фронту и спаду синхроимпульса, данные будут сохраняться по каждому спаду. После получения всех бит, данные можно декодировать. Это осуществляется вызовом функции decode. Для символьных клавиш эта функция сохраняет ASCII код клавиш в буфере. Это позволяет учитывать, удерживалась ли нажатой клавиша shift при нажатии данной клавиши. Другие функциональные клавиши вроде курсорных, ctrl и Alt и т.д. игнорируются. Карта соответствия скан-кодов ASCII кодам обрабатывается с помощью таблиц, одной для клавиш нажатых вместе с shift, а другой без. Изменения и дополнения Если микроконтроллер потеряет синхронизацию с клавиатурой, все остальные принятые биты будут неверны. Один из способов решения этой проблемы это использование тайм аута. Если 11 бит не получены в течении 1,5 мс, значит произошла ошибка. Счетчик битов должен быть сброшен, а поврежденные данные удалены. Для установки таких параметров как скорость и период повтора нажатой клавиши, необходимо посылать данные в клавиатуру. Это можно сделать, как описано выше. Команды можно найти в спецификации производителя клавиатуры. Рисунок 2. Временные диаграммы передачи данных клавиатурой в микроконтроллер. Ниже приведен листинг управляющей программы для AVR микроконтроллера на Си. Code Main.c #include #include #include #include "io8515.h" #include "serial.h" #include "gpr.h" #include "kb.h" void main(void) { unsigned char key; init_uart(); // Инициализация передающего буфера UART init_kb(); // Инициализация приемника клавиатуры while(1) { key=getchar(); putchar(key); delay(100); } }
Low_level_init.c #include #include int __low_level_init(void) { UBRR = 12; // Скорость передачи 19200 бод при частоте 4 МГц UCR = 0x08; // активизация передатчика GIMSK= 0x40; // Разрешение прерывания INT0 _SEI(); return 1; }
Serial.c #include #include #include /* SFR declarations */ #include "serial.h" #define ESC 0x1b #define BUFF_SIZE 64 flash char CLR[] = {ESC, '[','H', ESC, '[', '2', 'J',0}; unsigned char UART_buffer[BUFF_SIZE]; unsigned char *inptr, *outptr; unsigned char buff_cnt; void init_uart(void) { inptr = UART_buffer; outptr = UART_buffer; buff_cnt = 0; } void clr(void) { puts_P(CLR); // Передача команды "очистки экрана" ("clear screen") терминалу VT100 } int putchar(int c) { if (buff_cnt= UART_buffer + BUFF_SIZE) // Просмотр указателя inptr = UART_buffer; UCR = 0x28; // Активизация прерывания при очистке // регистра данных UART return 1; } else { return 0; // Буфер заполнен } } // Управление прерыванием передатчика interrupt [UART_UDRE_vect] void UART_UDRE_interrupt(void) { UDR = *outptr; // Посылка следующего байта outptr++; // Увеличение указателя if (outptr >= UART_buffer + BUFF_SIZE) // Просмотр указателя outptr = UART_buffer; if(--buff_cnt == 0) // Если буфер пуст UCR = UCR && (1< #include "kb.h" #include "serial.h" #include "gpr.h" #include "scancodes.h" #define BUFF_SIZE 64 unsigned char edge, bitcount; // 0 = отриц. 1 = положит. unsigned char kb_buffer[BUFF_SIZE]; unsigned char *inpt, *outpt; unsigned char buffcnt; void init_kb(void) { inpt = kb_buffer; // Инициализация буфера outpt = kb_buffer; buffcnt = 0; MCUCR = 2; // Установка прерывания INT0 по спадающему фронту edge = 0; // 0 = спадающий фронт 1 = нарастающий фронт bitcount = 11; } interrupt [INT0_vect] void INT0_interrupt(void) { static unsigned char data // Захват принятого скан-кода if (!edge) // Вход в подпрограмму по спадающему фронту { if(bitcount < 11 && bitcount > 2) // Биты с 3 по 10 – биты данных { // старт- и стоп- биты игнорируются data = (data >> 1); if(PIND & 8) data = data | 0x80; // Сохранение "1" } MCUCR = 3; // Установка прерывания по нарастающему фронту edge = 1; } else { // Вход в подпрограмму по нарастающему фронту MCUCR = 2; // Установка прерывания по спадающему фронту edge = 0; if(--bitcount == 0) // Все биты получены { decode(data); bitcount = 11; } } } void decode(unsigned char sc) { static unsigned char is_up=0, shift = 0, mode = 0; unsigned char i; if (!is_up) // Последний принятый идентификатор был идентификатором отпускания кнопки { switch (sc) { case 0xF0 :// Идентификатор отпускания кнопки is_up = 1; break; case 0x12 :// Левый SHIFT shift = 1; break; case 0x59 :// Правый SHIFT shift = 1; break; case 0x05 :// F1 if(mode == 0) mode = 1;// Вход в режим скан-кода if(mode == 2) mode = 3;// выход из режима скан-кода break; default: if(mode == 0 || mode == 3) // Если режим ASCII { if(!shift) // Если SHIFT не нажата { // тогда надо просмотреть таблицу for(i = 0; unshifted[i][0]!=sc && unshifted[i][0]; i++); if (unshifted[i][0] == sc) { put_kbbuff(unshifted[i][1]); } } else { // если SHIFT нажата for(i = 0; shifted[i][0]!=sc && shifted[i][0]; i++); if (shifted[i][0] == sc) { put_kbbuff(shifted[i][1]); } } } else{ // режим скан-кода print_hexbyte(sc);// Вывод скан-кода put_kbbuff(' '); put_kbbuff(' '); } break; } } else { is_up = 0; // Два кода 0xF0 в строке невозможно switch (sc) { case 0x12 :// Левый SHIFT shift = 0; break; case 0x59 :// Правый SHIFT shift = 0; break; case 0x05 :// F1 if(mode == 1) mode = 2; if(mode == 3) mode = 0; break; case 0x06 :// F2 clr(); break; } } } void put_kbbuff(unsigned char c) { if (buffcnt= kb_buffer + BUFF_SIZE) // Просмотр указателя inpt = kb_buffer; } } int getchar(void) { int byte; while(buffcnt == 0); // Ожидание данных byte = *outpt; // Получение байта outpt++; // Увеличение указателя if (outpt >= kb_buffer + BUFF_SIZE) // Просмотр указателя outpt = kb_buffer; buffcnt--; // Уменьшение счетчика буфера return byte; }
Gpr.c #include "gpr.h" void print_hexbyte(unsigned char i) { unsigned char h, l; h = i & 0xF0; // Старшая тетрада байта h = h>>4; h = h + '0'; if (h > '9') h = h + 7; l = (i & 0x0F)+'0'; // Младшая тетрада байта if (l > '9') l = l + 7; putchar(h); putchar(l); } void delay(char d) { char i,j,k; for(i=0; i<d; i++) for(j=0; j<40; j++) for(k=0; k<176; k++); }
Pindefs.h //************************* // Файл определения выводов // подключения клавиатуры //************************* #define PIN_KB PIND #define PORT_KB PORTD #define CLOCK 2 #define DATAPIN 3
Scancodes.h // Нижние символы flash unsigned char unshifted[][2] = { 0x0d,9, 0x0e,'|', 0x15,'q', 0x16,'1', 0x1a,'z', 0x1b,'s', 0x1c,'a', 0 x1d,' w', 0 x1e,' 2', 0x21,'c', 0x22,'x', 0x23,'d', 0x24,'e', 0x25,'4', 0x26,'3', 0x29,' ', 0x2a,'v', 0x2b,'f', 0x2c,'t', 0x2d,'r', 0x2e,'5', 0x31,'n', 0x32,'b ', 0 x3 3,'h', 0 x3 4,'g', 0x35,'y', 0x36,'6', 0x39,',', 0x3a,'m', 0x3b,'j', 0x3c,'u', 0x3 d,'7', 0 x3e,'8 ', 0 x41,',', 0x42,'k', 0x43,'i', 0x44,'o', 0x45,'0', 0x46,'9', 0x49,'.', 0 x4a,'-' , 0 x4b, 'l', 0 x4c,'ш', 0x4d,'p', 0x4e,'+', 0x52,'ж', 0x54,'е', 0x55,'\\', 0x5a,13, 0 x5b,'Ё' , 0 x5d, '\'', 0 x61,'<', 0x66,8, 0x69,'1', 0x6b,'4', 0x6c,'7', 0x70,'0', 0x71,',', 0x7 2,'2', 0 x73,'5 ', 0 x74,'6', 0x75,'8', 0x79,'+', 0x7a,'3', 0x7b,'-', 0x7c,'*', 0x7d,'9', 0 ,0 } ; // Верхние символы flash unsigned char shifted[][2] = { 0x0d,9, 0x0e,'§', 0x15,'Q', 0x16,'!', 0x1a,'Z', 0x1b,'S', 0x1c,'A', 0 x1d,' W', 0 x1e,' "', 0x21,'C', 0x22,'X', 0x23,'D', 0x24,'E', 0x25,'¤', 0x26,'#', 0x29,' ', 0x2a,'V', 0x2b,'F', 0x2c,'T', 0x2d,'R', 0x2e,'%', 0x31,'N', 0x32,'B ', 0 x3 3,'H', 0 x3 4,'G', 0x35,'Y', 0x36,'&', 0x39,'L', 0x3a,'M', 0x3b,'J', 0x3c,'U', 0x3d,'/', 0x3e,'(', 0x41,';', 0x42,'K', 0x43,'I', 0x44,'O', 0x45,'=', 0x46,')', 0x49,':', 0x4a,'_ ', 0 x4 b,'L', 0 x4 c,'Ш', 0x4d,'P', 0x4e,'?', 0x52,'Ж', 0x54,'Е', 0x55,'`', 0x5a,13, 0x5b ,'^', 0 x5d,'*' , 0 x61,'>', 0x66,8, 0x69,'1', 0x6b,'4', 0x6c,'7', 0x70,'0', 0x71,',', 0x7 2,'2', 0 x73,'5 ', 0 x74,'6', 0x75,'8', 0x79,'+', 0x7a,'3', 0x7b,'-', 0x7c,'*', 0x7d,'9', 0 ,0 } ; Engl 92Kb Исходный фаил 6Kb Программа Оригинал: www.kazus.ru
|
|
| |