coolibin 0 28 февраля, 2008 Опубликовано 28 февраля, 2008 · Жалоба Помогите сделать матричную клаву. Моя не пашет(((беру готовую рабочую схему, пишу програмулину, всё вроде делаю по примеру, а она всё равно не пашет, прерывание не срабатывает. Кто нить может поделиться соображениями/кодом реализации матричной клавиатуры через прерывание. Поиском пользовался, кое что нашел, но это только подтвердило что всё должно работать, но...((( Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Nanobyte 0 28 февраля, 2008 Опубликовано 28 февраля, 2008 · Жалоба А что за схема? Как соединены выводы? Можно поподробнее? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vet 0 28 февраля, 2008 Опубликовано 28 февраля, 2008 · Жалоба и зачем именно через прерывание? клавиатура - весьма медленное устройство ввода, для её обслуживания прекрасно подходит периодический опрос её состояния. или планируется, что устройство будет просыпаться по прерыванию от клавиатуры? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
SapegoAL 0 28 февраля, 2008 Опубликовано 28 февраля, 2008 · Жалоба И как вы вообще прерывание от клавы делаете? Завели все опросные линии на отдельные Int или объединили их каким нибудь способом? И к чему всё это поясните? Я в библиотеки выкладывал рабочую библиотеку 3х4 с возможностью динамического ввода и даже с вводом букв по принципу сотового телефона. Возьмите - пользуйтесь. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
fate 0 28 февраля, 2008 Опубликовано 28 февраля, 2008 · Жалоба по прерываниям :) #include <stdlib.h> #include <avr/io.h> #include <avr/interrupt.h> #define byte uint8_t #define word uint16_t #define KEY_SHORT 10 #define KEY_LONG 6000 volatile byte scan = 0; volatile byte scan_stop = 0; volatile byte scan_code = 0; volatile word key_age = 0; volatile byte key_pressed = 0; volatile byte key_long = 0; ISR(TIMER1_COMPA_vect) { if (!scan_stop) PORTL = ~_BV(++scan & 7); else { key_age += (key_age == 0xFFFF) ? 0 : 1; if (key_age == KEY_SHORT) key_pressed = 1; else if (key_age == KEY_LONG) key_long = 1; } PCICR |= _BV(PCIE2); } ISR(PCINT2_vect) { register byte i, p; if ((p = PINK) != 0xFF) { // key pressed for (i = 0; i != 8; i++) if(!(p & _BV(i))) break; scan_code = (scan << 3) + i; PCMSK2 = _BV(i); scan_stop = 1; key_age = 0; } else { // key released PCMSK2 = 0xFF; scan_stop = 0; } PCICR &= ~_BV(PCIE2); } word getkey() { word key; for (;;) { if (key_pressed) { key_pressed = 0; // // do something // break; } else if (key_long) { key_long = 0; // // do something // break; } } return (key); } void init(void) { // timer initialization PRR0 &= ~_BV(PRTIM1); // enable timer 1 TCCR1A = 0; TCCR1B = _BV(WGM12) | _BV(CS11); TIMSK1 = _BV(OCIE1A); TCNT1 = 0; OCR1A = 2000; // setup button interrupts PCMSK2 = 0xFF; sei(); } int main(void) { word i; init(); for (;;) { i = getkey(); // // do something // } exit(0); } Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
rezident 0 28 февраля, 2008 Опубликовано 28 февраля, 2008 · Жалоба Не вдаваясь в разбор вашего исходника, попробую пояснить на "пальцах". Для обслуживания матричной клавиатуры нужно реализовать как минимум три функции. Функция №1. Сканирование матрицы, устранение дребезга, определение нажатых/отпущенных клавиш, формирование соответствующих скан-кодов, помещение скан-кодов в буфер клавиатуры. Функция №2. Выдача текущего скан-кода без извлечения его из буфера. Функция №3. Выдача текущего скан-кода с извлечением его из буфера. Функция №1 обычно вызывается по прерыванию от таймера с равномерным интервалом времени (от 5мс до 100мс). Чаще, чем 200 раз в секунду вызывать ее нет смысла: а) никакая супер-пупер-машинистка не сможет с такой частотой колотить по клавишам; б) дребезг многих кнопок как раз порядка 1мс...10мс. Реже 10 раз в секунду тоже вызывать не желательно, т.к. будет значительная задержка генерации скан-кодов, а пользователю придется довольно долго удерживать клавиши для устойчивого определения нажатия их в программе. Лично я использую период 10...20мс. Буфер нужен в любом случае. Хотя бы даже из одного байта буфер. Потому, что процесс опроса матрицы клавиш и процесс использования полученного скан-кода в общем случае асинхронные. Асинхронные процессы синхронизируются с помощью буферов. Буфер для кодов клавиатуры может быть линейным или циклическим. В первом случае используются две переменных: счетчик количества скан-кодов, находящихся в буфере и указатель на текущий скан-код. Во-втором случае нужны три переменных: тоже счетчик скан-кодов, указатель на позицию скан-кода, предназначенного для извлечения из буфера и указатель на позицию для записи следующего скан-кода. В первом случае необходимо строго следить за атомарностью (одновременностью) обнуления счетчика и указателя при извлечении всех скан-кодов. Потому, что Функции №2, 3 (чтение/извлечение скан-кода из буфера) могут быть прерваны Функцией №1. Попробуйте пока осознать хотя бы это краткое описание. И на его основе реализовать свою программу. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
coolibin 0 29 февраля, 2008 Опубликовано 29 февраля, 2008 · Жалоба На ATmega16, на асме, код коцаный перекоцаный: .include "m16def.inc" .equ LCD_RS = 5 .equ LCD_E = 7 .def temp = r16 .def argument= r17 ;argument for calling subroutines .def return = r18 ;return value from subroutines .CSEG .org 0 jmp RESET ; Reset jmp EXT_INT1 reti jmp EXT_INT1 nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop RESET: clr r16 out GICR, r16 ;Disable external interrupt out DDRA, r16 ;All in out DDRB, r16 out DDRC, r16 out DDRD, r16 out PORTA, r16 ; All Tri-state out PORTB, r16 out PORTC, r16 out PORTD, r16 ldi r16, 0b00100000 out DDRA, r16 ; ????? out A ldi r16, 0xFF out DDRB, r16 ; ????? out B ldi r16, 0xFF out DDRC, r16 ; ????? out C ldi r16, 0b10100000 out DDRD, r16 ; ????? out D ldi r16, 0x00 ;PORTA5 is RS out PORTA, r16 ldi r16, 0b00110000 out PORTB, r16 ldi r16, 0x00 out PORTC, r16 ldi r16, 0x00 ;PORTD7 is E out PORTD, r16 ldi r16, LOW(RAMEND) ;Stack Pointer out SPL, r16 ldi r16, HIGH(RAMEND) out SPH, r16 ldi r16, 0x00 out SFIOR, r16 ldi r16, 0x0B out MCUCR, r16 ldi r16, 0x10 out WDTCR, r16 rcall LCD_init rcall LCD_delay ldi r16, 0x80 out GICR, r16 ;rcall text_out LOOP: sei rjmp LOOP EXT_INT1: rcall text_out ;MUST WORK!((((((((((((((( reti lcd_command8: ;used for init (we need some 8-bit commands to switch to 4-bit mode!) ;in temp, DDRD ;we need to set the high nibble of DDRD while leaving ;the other bits untouched. Using temp for that. ;sbr temp, 0b11110000 ;set high nibble in temp ;out DDRD, temp ;write value to DDRD again in temp, PortC ;then get the port value andi temp, 0x0F andi argument, 0xF0 ;then clear the low nibble of the argument ;so that no control line bits are overwritten or temp, argument ;then set the data bits (from the argument) in the ;Port value out PortC, temp ;and write the port value. cbi PortA, LCD_RS sbi PortD, LCD_E ;now strobe E nop nop nop nop nop nop nop nop cbi PortD, LCD_E ;cbi PortA, LCD_RS ret lcd_putchar: push argument ;save the argmuent (it's destroyed in between) in temp, PortC ;then get the data from PortD ;push temp andi temp, 0x0F ;clear ALL LCD lines (data and control!) andi argument, 0xF0 ;we have to write the high nibble of our argument first ;so mask off the low nibble or temp, argument ;now set the argument bits in the Port value out PortC, temp ;and write the port value sbi PortA, LCD_RS ;now take RS high for LCD char data register access sbi PortD, LCD_E ;strobe Enable nop nop nop nop nop nop nop nop cbi PortD, LCD_E pop argument ;restore the argument, we need the low nibble now... andi temp, 0x0F ;clear the data bits of our port value swap argument ;we want to write the LOW nibble of the argument to ;the LCD data lines, which are the HIGH port nibble! andi argument, 0xF0 ;clear unused bits in argument or temp, argument ;and set the required argument bits in the port value out PortC, temp ;and write the port value sbi PortA, LCD_RS ;now take RS high for LCD char data register access sbi PortD, LCD_E ;strobe Enable nop nop nop nop nop nop nop nop cbi PortD, LCD_E ;pop temp ;out PortC, temp ret lcd_command: ;same as LCD_putchar, but with RS low! push argument ;save the argmuent (it's destroyed in between) in temp, PortC ;then get the data from PortD andi temp, 0x0F ;clear ALL LCD lines (data and control!) andi argument, 0xF0 ;we have to write the high nibble of our argument first ;so mask off the low nibble or temp, argument ;now set the argument bits in the Port value out PortC, temp ;and write the port value cbi PortA, LCD_RS ;now take RS high for LCD char data register access sbi PortD, LCD_E ;strobe Enable nop nop nop nop nop nop nop nop cbi PortD, LCD_E pop argument ;restore the argument, we need the low nibble now... andi temp, 0x0F ;clear the data bits of our port value swap argument ;we want to write the LOW nibble of the argument to ;the LCD data lines, which are the HIGH port nibble! andi argument, 0xF0 ;clear unused bits in argument or temp, argument ;and set the required argument bits in the port value out PortC, temp ;and write the port value cbi PortA, LCD_RS ;now take RS high for LCD char data register access sbi PortD, LCD_E ;strobe Enable nop nop nop nop nop nop nop nop cbi PortD, LCD_E ret LCD_wait: ldi r18, 0x03 LCD_wait_l1: clr r19 LCD_wait_l2: dec r19 brne LCD_wait_l2 dec r18 brne LCD_wait_l1 ret LCD_delay: clr r2 LCD_delay_outer: clr r3 LCD_delay_inner: dec r3 brne LCD_delay_inner dec r2 brne LCD_delay_outer ret LCD_init: rcall LCD_delay ;first, we'll tell the LCD that we want to use it ldi argument, 0x20 ;in 4-bit mode. rcall LCD_command8 ;LCD is still in 8-BIT MODE while writing this command!!! rcall LCD_delay ldi argument, 0x28 ;NOW: 2 lines, 5*7 font, 4-BIT MODE! rcall LCD_command ; rcall LCD_delay ldi argument, 0x0F ;now proceed as usual: Display on, cursor on, blinking rcall LCD_command rcall LCD_delay ldi argument, 0x01 ;clear display, cursor -> home rcall LCD_command rcall LCD_delay ldi argument, 0x06 ;auto-inc cursor rcall LCD_command ret text_out: ldi Zl, LOW(2*line1) ldi Zh, HIGH(2*line1) text_out_l1: lpm adiw Zl, 1 tst r0 breq text_out_l2 mov argument, r0 rcall LCD_putchar rcall LCD_wait rjmp text_out_l1 text_out_l2: ldi argument, 0x80 ori argument, 0x40 rcall LCD_command rcall LCD_wait ldi Zl, LOW(2*line2) ldi Zh, HIGH(2*line2) text_out_l3: lpm adiw Zl, 1 tst r0 breq text_out_l4 mov argument, r0 rcall LCD_putchar rcall LCD_wait rjmp text_out_l3 text_out_l4: ret line1: .db ' ',' ',' ','G','R','E','A','T','I','N','G','S','!',' ',' ',' ',0 line2: .db ' ',' ',' ','V','I','C','E',' ','C','I','T','Y','!',' ',' ',' ',0 ...как тэг кода ставить? не подскажете? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vet 0 29 февраля, 2008 Опубликовано 29 февраля, 2008 · Жалоба coolibin, как приведённый код соотносится с обсуждаемой темой? ...как тэг кода ставить? не подскажете?давим кнопку "Ответить"; обращаем внимание на спецкнопочки над полем ввода сообщения. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
coolibin 0 29 февраля, 2008 Опубликовано 29 февраля, 2008 (изменено) · Жалоба как приведённый код соотносится с обсуждаемой темой? Это собственно и есть моя программа которая не работает, прерывание не происходит(( Изменено 29 февраля, 2008 пользователем coolibin Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
GDI 0 29 февраля, 2008 Опубликовано 29 февраля, 2008 · Жалоба ...как тэг кода ставить? не подскажете? можно и в окне быстрого ответа просто написать (code)тут ваш код(/code), только скобочки квадратные поставить []. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vet 0 29 февраля, 2008 Опубликовано 29 февраля, 2008 · Жалоба Это собственно и есть моя программа которая не работает, прерывание не происходит(( так про матричную клавиатуру в коде ни единого намека :) а прерывание не происходит, потому что вектор прописан неправильно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
=GM= 0 29 февраля, 2008 Опубликовано 29 февраля, 2008 · Жалоба а прерывание не происходит, потому что вектор прописан неправильно Поправлю, для INT0 - правильно, а для INT1 - неправильно. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
coolibin 0 29 февраля, 2008 Опубликовано 29 февраля, 2008 · Жалоба так про матричную клавиатуру в коде ни единого намека :) а прерывание не происходит, потому что вектор прописан неправильно. Ну, задумывалась она как матричная клава. Дальше прерывания не дошёл. А что в векторе прерываний не правильно? Дело в том что это моя первая прога раньше никогда не писал под микропроцы Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
vet 0 29 февраля, 2008 Опубликовано 29 февраля, 2008 · Жалоба А что в векторе прерываний не правильно?не на месте. разрешено INT1, а инициализирован вектор INT0. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
coolibin 0 1 марта, 2008 Опубликовано 1 марта, 2008 · Жалоба не на месте. разрешено INT1, а инициализирован вектор INT0. Вы имеете ввиду нужно так: jmp RESET; Reset nop jmp EXT_INT1 ? Я так сначала и делал, но результат не изменился((( Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться