Цитата(sigmaN @ Feb 21 2010, 21:57)

Клавиатура с точки зрения железа как построена?
Лень мне искать аппноут

AVR245: Code Lock with 4x4 Keypad and I2C™ LCDСорри. Неправильно написал. Имел ввиду, что не могу понять, как реализовать обработку повторных нажатий (чтобы их избежать).
Вот как код выглядит.
kbd.c
CODE
#include <avr/io.h>
#include <avr/interrupt.h>
#include "kbd.h"
unsigned char KBD_KeyPressed;
unsigned char KBD_LastKey;
unsigned char KBD_ScanRow;
unsigned char KBD_KeyDown;
//Потом убрать
unsigned char KBD_LastRow;
volatile unsigned char column;
//Обработка переполнения Timer1
ISR(TIMER1_OVF_vect)
{
if (!KBD_KeyDown)
{
KBD_PORT |= (0x10<<KBD_ScanRow);
if (++KBD_ScanRow > 3)
KBD_ScanRow = 0;
KBD_PORT &= ~(0x10<<KBD_ScanRow);
asm("nop");
column = (~KBD_PIN) & 0x0f;
}
}
//Считываем значение Timer1
uint16_t read_TCNT1(void)
{
uint16_t i;
unsigned char sreg;
sreg = SREG; //запоминаем состояние бита I (остальные биты нам в общем то побоку)
asm("cli"); //убедимся что флаг I сброшен
i = TCNT1; //читаем TCNT1
SREG = sreg; //востанавливаем состояние бита I
//(если он был сброшен до входа в процедуру то эта операция не даст никакого эффекта)
return i;
}
unsigned char KBD_GetKey(void)
{
unsigned char sreg;
sreg = SREG;
asm("cli");
switch (column)
{
case 0x00:
KBD_KeyDown = 0;
break;
case 0x01:
KBD_LastKey = KBD_Array[KBD_ScanRow][0];
KBD_LastRow = KBD_ScanRow;
if (!KBD_KeyDown)
KBD_KeyPressed = 1;
KBD_KeyDown = 1;
break;
case 0x02:
KBD_LastKey = KBD_Array[KBD_ScanRow][1];
KBD_LastRow = KBD_ScanRow;
if (!KBD_KeyDown)
KBD_KeyPressed = 1;
KBD_KeyDown = 1;
break;
case 0x04:
KBD_LastKey = KBD_Array[KBD_ScanRow][2];
KBD_LastRow = KBD_ScanRow;
if (!KBD_KeyDown)
KBD_KeyPressed = 1;
KBD_KeyDown = 1;
break;
case 0x08:
KBD_LastKey = KBD_Array[KBD_ScanRow][3];
KBD_LastRow = KBD_ScanRow;
if (!KBD_KeyDown)
KBD_KeyPressed = 1;
KBD_KeyDown = 1;
break;
default:
KBD_LastKey = 0;
KBD_KeyPressed = 0;
}
SREG = sreg;
if (KBD_KeyPressed)
{
KBD_KeyDown = 0;
KBD_KeyPressed = 0;
return (KBD_LastKey);
} else return (NO_KEY);
}
//Конфигурирования контроллера для работы с клавиатурой
void KBD_init(void)
{
//Конфигурируем порт клаваиатуры
KBD_REG |= (X1|X2|X3|X4);
KBD_REG &= ~(Y1|Y2|Y3|Y4);
//Конфигурирем выводы клавиатуры
//X1-X4 - выходы, высокий уровень
//Y1-Y4 - входы, высокий уровень, pull-up активен
KBD_PORT |= (X1|X2|X3|X4|Y1|Y2|Y3|Y4);
//Конфигурация таймеров
TCNT0 = 0x00;
TCNT1 = 0x1FF;
TIMSK = (1<<TOIE1); //Включить прерывание по переполнению для Timer1
TCCR1A = 0x00;
TCCR1B = (1<<CS11); //Включаем делитель /8
//Включаем обработку прерываний
asm("sei");
}
kbd.h
CODE
#ifndef _KBD_H
#define _KBD_H
#endif
#include <avr/io.h>
//Столбцы клавиатуры
#define Y1 (1<<0)
#define Y2 (1<<1)
#define Y3 (1<<2)
#define Y4 (1<<3)
//Строки клавиатуры
#define X1 (1<<4)
#define X2 (1<<5)
#define X3 (1<<6)
#define X4 (1<<7)
//Порт клавиатуры
#define KBD_PORT PORTB
#define KBD_PIN PINB
//Конфигурация порта клавиатуры
#define KBD_REG DDRB
void KBD_init(void);
unsigned char KBD_GetKey(void);
uint16_t read_TCNT1(void);
//Если ни одна клавиша не была нажата, то возвращаем значение -1
static uint8_t NO_KEY = -1;
//Массив определяющий значения клавиш
static uint8_t KBD_Array[4][4]=
{
{'1','2','3','A'},
{'4','5','6','B'},
{'7','8','9','C'},
{'*','0','#','D'}
};
extern volatile unsigned char column;
extern unsigned char KBD_LastRow;
Как я уже сказал, идея в том, что надо нажать кнопку, напечатается один символ. Второй символ напечатается после того, как кнопка будет отпущена. А вот уже этим вторым символом может быть эта же кнопка ну и т.д. Т.е. нужно пройти через факт "одно нажатие - один символ".
Цитата(rezident @ Feb 21 2010, 23:08)

Все правильно вы мыслите.

верной дорогой значит! Автоповтор в принципе я не планирую использовать. Клавиатура используется для прямого ввода значений частоты и управления меню (меню пока ещё на стадии планирования, поэтому пока даже и не рассматривается). Надо переварить супчик

Спасибо за наводку на мысль