21.09.2017, 20:50
|
|
Прописка
Регистрация: 29.03.2007
Сообщений: 185
Сказал спасибо: 11
Сказали Спасибо 1 раз в 1 сообщении
|
Re: Оцените алгоритм опроса матричной клавы
Чё-то я поторопился... Не фул тач там(. Но до 3 кнопок вместе нажатых должен определить. Переменная key 8 бит. 0-3 бит - это для колонок, с 4 по 7 - для строк. То есть если нажали кнопки вместе 7,8,6, то код будет такой: 0x37
|
|
|
|
21.09.2017, 23:37
|
|
Вид на жительство
Регистрация: 10.06.2007
Сообщений: 429
Сказал спасибо: 34
Сказали Спасибо 51 раз(а) в 47 сообщении(ях)
|
Re: Оцените алгоритм опроса матричной клавы
Сообщение от supercelt
|
Переменная key 8 бит. 0-3 бит - это для колонок, с 4 по 7 - для строк. То есть если нажали кнопки вместе 7,8,6, то код будет такой: 0x37
|
Я правильно понял, что если в какой-то колонке есть нажатая кнопка, то в соответствующем ей разряде в переменной key будет 1? Если используются три колонки - значит бит 3 будет всегда 0?
И так-же со строками - если в какой-то строке есть нажатая кнопка, то в соответствующем разряде key, будет 1?
Или я неправильно понял?
Потому что если клавиатура такая:
Код:
|
1 2 3
4 5 6
7 8 9
* 0 # |
и нумерация колонок слева направо (разряды 0-2), а нумерация строк сверху вниз (разряды 4-7) то не получается 0x37 (0b00110111) при нажатых 7, 8, 6. А получается 0x67 (0b01100111).
|
|
|
|
21.09.2017, 23:46
|
|
Прописка
Регистрация: 29.03.2007
Сообщений: 185
Сказал спасибо: 11
Сказали Спасибо 1 раз в 1 сообщении
|
Re: Оцените алгоритм опроса матричной клавы
поняли правильно. 0бит - 1 столб, 1б - 2с, 2б - 3с. 4б - 1 строка, 5б - 2 строка, 6б - 3 строка, 7б - 4 строка. Всё правильно. С кодом может напутал)
|
|
|
|
22.09.2017, 00:59
|
|
Вид на жительство
Регистрация: 10.06.2007
Сообщений: 429
Сказал спасибо: 34
Сказали Спасибо 51 раз(а) в 47 сообщении(ях)
|
Re: Оцените алгоритм опроса матричной клавы
supercelt, ну тогда, с таким представлением скан-кода всей клавиатуры, не получится различать даже две любые одновременно нажатые кнопки, не говоря уже о трёх. Потому что, например, скан-код зажатых кнопок 4 и 2 будет точно такой-же как и зажатых кнопок 1 и 5, а именно 0x33 (0b00110011) и различить два этих разных состояния по такому скан-коду невозможно. Ну или я что-то упускаю.
|
|
|
|
22.09.2017, 23:02
|
|
Прописка
Регистрация: 29.03.2007
Сообщений: 185
Сказал спасибо: 11
Сказали Спасибо 1 раз в 1 сообщении
|
Re: Оцените алгоритм опроса матричной клавы
Сообщение от H4LF
|
supercelt, ну тогда, с таким представлением скан-кода всей клавиатуры, не получится различать даже две любые одновременно нажатые кнопки, не говоря уже о трёх. Потому что, например, скан-код зажатых кнопок 4 и 2 будет точно такой-же как и зажатых кнопок 1 и 5, а именно 0x33 (0b00110011) и различить два этих разных состояния по такому скан-коду невозможно. Ну или я что-то упускаю.
|
Да, надо придумывать что-то другое....
|
|
|
|
24.09.2017, 22:28
|
|
Прописка
Регистрация: 29.03.2007
Сообщений: 185
Сказал спасибо: 11
Сказали Спасибо 1 раз в 1 сообщении
|
Re: Оцените алгоритм опроса матричной клавы
Сделал мультитач. Расчитано на 16 кнопок. Но можно увеличить до 32. Короче все зависит от разрядности переменной, в которую будет записываться код кнопок. Смысл в том, что если нажата кнопка 3, то и смещаем бит на 3 в переменной. Если кнопка 9, то смещаем на 9. Таким образом можно получить уникальные коды одновременно нажатых кнопок. Теперь 2+4 не то же самое что 1+5.
C
Нажмите, чтобы открыть спойлер
Код:
|
#include "keyboard.h"
#include "delay.h"
uint16_t old_key = 0, find_key = 0, find_hold_key = 0;
//uint8_t key = 0, old_key = 0, find_key = 0, find_hold_key = 0;//test
//uint8_t state = 0, count_row = 0;//test
//uint16_t count_scan = 0;//test
uint16_t debounce = 10 * KEY_SCAN_DELAY;
GPIO_TypeDef * row_port[ROWS] = {KEY_ROW1_PORT, KEY_ROW2_PORT, KEY_ROW3_PORT, KEY_ROW4_PORT}; //Запихиваем названия портов рядов в массив
uint8_t row_pin[ROWS] = {KEY_ROW_PIN1, KEY_ROW_PIN2, KEY_ROW_PIN3, KEY_ROW_PIN4}; //Запихиваем номера пинов рядов в массив
GPIO_TypeDef * col_port[COLS] = {KEY_COL1_PORT, KEY_COL2_PORT, KEY_COL3_PORT}; //Запихиваем названия портов колонок в массив
uint8_t col_pin[COLS] = {KEY_COL_PIN1, KEY_COL_PIN2, KEY_COL_PIN3}; //Запихиваем номера пинов колонок в массив
key_struct keytable[18] = {
{0,0x11,0x1,'1'},
{1,0x12,0x2,'2'},
{2,0x14,0x4,'3'},
{3,0x18,0x8,'A'},
{4,0x21,0x10,'4'},
{5,0x22,0x20,'5'},
{6,0x24,0x40,'6'},
{7,0x28,0x80,'B'},
{8,0x41,0x100,'7'},
{9,0x42,0x200,'8'},
{10,0x44,0x400,'9'},
{11,0x48,0x800,'C'},
{12,0x81,0x1000,'*'},
{13,0x82,0x2000,'0'},
{14,0x84,0x4000,'#'},
{15,0x88,0x8000,'D'},
{16,0x00,0x12,0xB},//2.4
{17,0x00,0x21,0xC},//1.5
};
void keyboard_ini(void){
uint8_t i;
//GPIO
for(i = 0; i ‹ ROWS; i++){
port_cmd(row_port[i]); //Включаем тактирование порта ряда
gpio_setup(row_port[i], row_pin[i], 0x01, 0, 0x01, 0x02); //настройка рядов выходов. Порт, пин, MODER, OTYPER, OSPEEDR, PUPDR
row_port[i]-›BSRRL = (1 ‹‹ row_pin[i]); //устанавливаем на всех строках - 1
}
for(i = 0; i ‹ COLS; i++){
port_cmd(col_port[i]); //Включаем тактирование порта столбца
gpio_setup(col_port[i], col_pin[i], 0x00, 0, 0x01, 0x02); //настройка рядов выходов. Порт, пин, MODER, OTYPER, OSPEEDR, PUPDR
}
//test led
GPIOB-›MODER &= ~(GPIO_MODER_MODER0 ‹‹ (14*2));//PB14 (35)
GPIOB-›MODER |= (1 ‹‹ (14*2));
GPIOB-›OTYPER &= ~((GPIO_OTYPER_OT_0) ‹‹ 14);
GPIOB-›OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR0 ‹‹ (14*2));
GPIOB-›PUPDR &= ~(GPIO_PUPDR_PUPDR0 ‹‹ (14*2));
GPIOB-›PUPDR |= (0x02 ‹‹ (14*2));
//TIM6
RCC-›APB1ENR |= RCC_APB1ENR_TIM6EN;
TIM6-›PSC |= 8399; //F = 10 kHz; Fmax TIM6 = 84 mHz
TIM6-›ARR = 65535;
TIM6-›EGR |= TIM_EGR_UG;
__NOP();
__NOP();
TIM6-›SR &= ~(TIM_SR_UIF);
}
void port_cmd(GPIO_TypeDef * port){ //функция для включения тактирования портов клавиатуры
if(port == GPIOA){
RCC-›AHB1ENR |= RCC_AHB1ENR_GPIOAEN;
}
if(port == GPIOB){
RCC-›AHB1ENR |= RCC_AHB1ENR_GPIOBEN;
}
if(port == GPIOC){
RCC-›AHB1ENR |= RCC_AHB1ENR_GPIOCEN;
}
if(port == GPIOD){
RCC-›AHB1ENR |= RCC_AHB1ENR_GPIODEN;
}
if(port == GPIOE){
RCC-›AHB1ENR |= RCC_AHB1ENR_GPIOEEN;
}
if(port == GPIOF){
RCC-›AHB1ENR |= RCC_AHB1ENR_GPIOFEN;
}
if(port == GPIOG){
RCC-›AHB1ENR |= RCC_AHB1ENR_GPIOGEN;
}
if(port == GPIOH){
RCC-›AHB1ENR |= RCC_AHB1ENR_GPIOHEN;
}
if(port == GPIOI){
RCC-›AHB1ENR |= RCC_AHB1ENR_GPIOIEN;
}
}
void gpio_setup(GPIO_TypeDef * port, uint8_t pin, uint8_t moder, uint8_t otyper, uint8_t ospeedr, uint8_t pupdr){
port-›MODER &= ~(GPIO_MODER_MODER0 ‹‹ (pin*2));
port-›MODER |= (moder ‹‹ (pin*2));
if(moder & 0x03){ //Если настроено как выход
port-›OTYPER &= ~((GPIO_OTYPER_OT_0) ‹‹ pin);
port-›OTYPER |= (otyper ‹‹ pin);
port-›OSPEEDR &= ~(GPIO_OSPEEDER_OSPEEDR0 ‹‹ (pin*2));
port-›OSPEEDR |= (ospeedr ‹‹ (pin*2));
}
port-›PUPDR &= ~(GPIO_PUPDR_PUPDR0 ‹‹ (pin*2));
port-›PUPDR |= (pupdr ‹‹ (pin*2));
}
int keyboard_any_key(void){
int i;
for(i = 0; i ‹ COLS; i++){
if(col_port[i]-›IDR & (1 ‹‹ col_pin[i])){
return 1;
}
}
return 0;
}
uint16_t keyboard_write_key(char k){
uint8_t i;
uint16_t s = 0;
for(i = 0; i ‹ sizeof(keytable); i++){
if(keytable[i].key_key == k){
s = keytable[i].key_code;
return s;
}
}
return 0;
}
char keyboard_find_key(uint16_t get_key){
uint8_t i;
char key_value;
for(i = 0; i ‹ sizeof(keytable); i++){
if(keytable[i].key_code == get_key) {
key_value = keytable[i].key_symbol;
return key_value;
}
}
return 0;
}
void keyboard_handler(void){
static uint8_t state = 0, count_row = 0, key = 0;
static uint16_t count_scan = 0, key_code = 0;
uint8_t i = 0;
switch(state){
case 0: //Ничего не нажато
if(keyboard_any_key()){
for(i = 0; i ‹ ROWS; i++){
row_port[i]-›BSRRH = (1 ‹‹ row_pin[i]); //устанавливаем на всех строках - 0
}
state = 1;
TIM6-›CR1 |= TIM_CR1_CEN;
}
break;
case 1: //Обнаружили какое-то нажатие
if(TIM6-›CNT ›= debounce){
state = 2;
debounce = 10 * KEY_SCAN_PERIOD; // 1ms
row_port[count_row]-›BSRRL = (1 ‹‹ row_pin[count_row]); //первый ряд установка в 1
TIM6-›CNT = 0;
}
break;
case 2: //Скан
if(TIM6-›CNT ›= debounce){
for(i = 0; i ‹ COLS; i++){
if(col_port[i]-›IDR & (1 ‹‹ col_pin[i])){
key = (1 ‹‹ i)|(1 ‹‹ 4 ‹‹ count_row);
key_code |= keyboard_write_key(key);
}
}
row_port[count_row]-›BSRRH = (1 ‹‹ row_pin[count_row]); //0
count_row++;
if(ROWS != count_row){
row_port[count_row]-›BSRRL = (1 ‹‹ row_pin[count_row]); //1
}else{
if(!key_code){
TIM6-›CR1 &= ~TIM_CR1_CEN;
for(i = 0; i ‹ ROWS; i++){
row_port[i]-›BSRRL = (1 ‹‹ row_pin[i]); //устанавливаем на всех строках - 1
}
state = 0;
key_code = 0;
count_row = 0;
count_scan = 0;
old_key = 0;
debounce = 10 * KEY_SCAN_DELAY; // debounce delay 20 ms
}else{
if(!old_key){
old_key = key_code;
count_row = 0;
key_code = 0;
row_port[count_row]-›BSRRL = (1 ‹‹ row_pin[count_row]); //1
}else{
if(key_code != old_key){
TIM6-›CR1 &= ~TIM_CR1_CEN;
for(i = 0; i ‹ ROWS; i++){
row_port[i]-›BSRRL = (1 ‹‹ row_pin[i]); //устанавливаем на всех строках - 1
}
state = 0;
key_code = 0;
count_row = 0;
count_scan = 0;
old_key = 0;
debounce = 10 * KEY_SCAN_DELAY; // debounce delay 20 ms
}else{
if(count_scan == KEY_COUNT_SCAN){
count_scan = 0;
find_key = key_code;
key_code = 0;
state = 3;
count_row = 0;
row_port[count_row]-›BSRRL = (1 ‹‹ row_pin[count_row]); //1
}else{
key_code = 0;
count_scan++;
count_row = 0;
row_port[count_row]-›BSRRL = (1 ‹‹ row_pin[count_row]); //1
}
}
}
}
}
TIM6-›CNT = 0;
}
break;
case 3: //Удержание кнопки + отпускание
if(TIM6-›CNT ›= debounce){
for(i = 0; i ‹ COLS; i++){
if(col_port[i]-›IDR & (1 ‹‹ col_pin[i])){
key = (1 ‹‹ i)|(1 ‹‹ 4 ‹‹ count_row);
key_code |= keyboard_write_key(key);
}
}
row_port[count_row]-›BSRRH = (1 ‹‹ row_pin[count_row]); //0
count_row++;
if(ROWS != count_row){
row_port[count_row]-›BSRRL = (1 ‹‹ row_pin[count_row]); //1
}else{
if(key_code != old_key){
TIM6-›CR1 &= ~TIM_CR1_CEN;
for(i = 0; i ‹ ROWS; i++){
row_port[i]-›BSRRL = (1 ‹‹ row_pin[i]); //устанавливаем на всех строках - 1
}
state = 0;
key_code = 0;
count_row = 0;
count_scan = 0;
old_key = 0;
debounce = 10 * KEY_SCAN_DELAY; // debounce delay 20 ms
}else{
count_scan++;
if(count_scan == (KEY_HOLD_PERIOD / 3)){
find_hold_key = key_code;
}
count_row = 0;
row_port[count_row]-›BSRRL = (1 ‹‹ row_pin[count_row]); //1
key_code = 0;
}
}
TIM6-›CNT = 0;
}
break;
}
} |
H
Нажмите, чтобы открыть спойлер
Код:
|
#ifndef KEYOARD_H
#define KEYOARD_H
#include "stm32f4xx.h"
#define ROWS 4 //Объявляем, что на клаве 4 ряда кнопок
#define COLS 3 //Объявляем, что на клаве 3 колонки кнопок
#define KEY_COUNT_SCAN 5 //Количество полных сканирований клавы, после которых принимается решение, что нажатие и отпускание кнопки засчитано.
#define KEY_SCAN_PERIOD 1 //полный прогон клавиатуры каждые.... мс
#define KEY_SCAN_DELAY 20 //Задержка в ms, перед началом сканирования (пропуск дребезга контактов)
#define KEY_HOLD_PERIOD 1000 //ms Продолжительность времени, за которое засчитываем удержание кнопки. Т.е. Длительное нажатие.
#define KEY_LED 0 //Если объявлен этот дефайн, то используется светодоид подтверждения нажатия клавиш. Если не используется, закомментировать строку. 0 - если светодиод включается подачей нуля на пин, 1 - если подачей единицы на пин
#define KEY_BUZZER 1 //Если объявлен этот дефайн, то используется буззер подтверждения нажатия клавиш. Если не используется, закомментировать строку. 0 - если буззер включается подачей нуля на пин, 1 - если подачей единицы на пин
#define KEY_ROW1_PORT GPIOB //Порт 1 ряда
#define KEY_ROW2_PORT GPIOB //Порт 2 ряда
#define KEY_ROW3_PORT GPIOB //Порт 3 ряда
#define KEY_ROW4_PORT GPIOB //Порт 4 ряда
#define KEY_ROW_PIN1 5 //Пин 1 ряда
#define KEY_ROW_PIN2 6 //Пин 2 ряда
#define KEY_ROW_PIN3 7 //Пин 3 ряда
#define KEY_ROW_PIN4 8 //Пин 4 ряда
#define KEY_COL1_PORT GPIOC //Порт 1 колонки
#define KEY_COL2_PORT GPIOC //Порт 2 колонки
#define KEY_COL3_PORT GPIOC //Порт 3 колонки
//#define KEY_COL4_PORT GPIOx //Порт 4 колонки
#define KEY_COL_PIN1 10 //Пин 1 колонки
#define KEY_COL_PIN2 11 //Пин 2 колонки
#define KEY_COL_PIN3 12 //Пин 3 колонки
//#define KEY_COL_PIN4 X //Пин 4 колонки
//#define KEY_HOLD_COUNTER_PERIOD (KEY_HOLD_PERIOD / KEY_SCAN_PERIOD)
extern uint16_t find_key, find_hold_key;
typedef struct{
uint8_t key_item;
uint8_t key_key;
uint16_t key_code;
char key_symbol;
}key_struct;
void keyboard_ini(void);
void port_cmd(GPIO_TypeDef * port);
void gpio_setup(GPIO_TypeDef * port, uint8_t pin, uint8_t moder, uint8_t otyper, uint8_t ospeedr, uint8_t pupdr);
int keyboard_any_key(void);
char keyboard_find_key(uint16_t);
void keyboard_handler(void);
uint16_t keyboard_write_key(char keytable);
#endif |
|
|
|
|
25.09.2017, 02:46
|
|
Вид на жительство
Регистрация: 10.06.2007
Сообщений: 429
Сказал спасибо: 34
Сказали Спасибо 51 раз(а) в 47 сообщении(ях)
|
Re: Оцените алгоритм опроса матричной клавы
supercelt, ну да - каждой кнопке свой бит - тогда будет только аппаратное ограничение на комбинации кнопок (и дальше можно думать над фильтрацией, если есть необходимость или желание).
Этот код проверяли - работает как нужно? Мельком просмотрел и есть пара замечаний:
1) зачем массив keytable размещать в ОЗУ?
2) вот тут
PHP код:
|
for(i = 0; i ‹ sizeof(keytable); i++){
if(keytable[i].key_key == k){
s = keytable[i].key_code;
return s;
}
}
|
sizeof( keytable) вернёт размер массива структур в байтах(108 байт в данном случае?), а не количество элементов.
ЗЫ: ещё мне кажется сильным переусложнением вот это:
PHP код:
|
key_code |= keyboard_write_key(key);
|
т.е. заполнение key_code таким странным образом через функцию keyboard_write_key. Неужели нельзя просто сдвигать key_code, допустим, влево и после этого устанавливать её младший разряд в 1 если текущий столбец в нуле (кнопка нажата). Будет проще, понятнее, быстрее, а результат (в переменной key_code) тот же.
|
|
|
|
25.09.2017, 09:52
|
|
Прописка
Регистрация: 29.03.2007
Сообщений: 185
Сказал спасибо: 11
Сказали Спасибо 1 раз в 1 сообщении
|
Re: Оцените алгоритм опроса матричной клавы
1. Мне право не ловки ибо я не настолько глубоко шарю в этом деле. Я не знаю что значит хранить в ОЗУ или ещё где-то. Если вы расскажет хотя бы немного, буду очень признателен.
2. Хммм. А я думал оно вернет количество элементов. И как тогда получается что все работает???
3. А вот насчёт переусложнения. Вы имеете ввиду сделать так : key_code |= (1 ‹‹ key);???
Но кеу то тогда все равно надо вытащить из структуры, функцией...
|
|
|
|
25.09.2017, 14:38
|
|
Вид на жительство
Регистрация: 10.06.2007
Сообщений: 429
Сказал спасибо: 34
Сказали Спасибо 51 раз(а) в 47 сообщении(ях)
|
Re: Оцените алгоритм опроса матричной клавы
supercelt, 1) ну хоть что такое это самое ОЗУ (RAM) и что такое флешь (flash) надеюсь знаете, иначе не представляю, как можно вообще программировать под МК не зная этого. В ОЗУ хранятся всякие переменные, а так же обычно расположен стек, т.е. данные которые могут или должны изменяться. Ваш же массив изменять во время выполнения не надо, а значит его можно разместить во флешь и сэкономить ОЗУ (в F4 RAM относительно много, но лучше сразу учиться не разбрасываться ей без необходимости). Чтобы разместить этот массив во флешь в STM32 достаточно объявить его как const.
2) нет, не количество элементов, почитайте о sizeof внимательнее. Чтобы получить количество элементов, нужно, видимо, сделать так: sizeof(keytable)/sizeof(key_struct). А работает почему - ну так посмотрите в отладчике, разве не интересно? Получается, что i считает от 0 до 107, но так как нужный key_key есть в массиве, то цикл закончится раньше, чем выйдет за пределы массива. Но то же самое есть и в функции keyboard_find_key() которая может пойти дальше и найти где-то в памяти то, чего нет. Надеюсь теперь понятно, что есть такие ошибки, когда всё вроде бы работает, но иногда перестаёт (и это очень неприятные ошибки). Так что написать надёжный софт не так просто, как может показаться.
3) не так, а как-то так:
PHP код:
|
for(i = 0; i ‹ COLS; i++){
key_code = key_code ‹‹ 1;
if(col_port[i]-›IDR & (1 ‹‹ col_pin[i])){
key_code |= 1;
}
}
|
т.е. не нужно ничего вытаскивать из структуры, и key_key соответственно тоже не нужно, как и функция keyboard_write_key(), зачем лишние сущности?
|
|
|
|
25.09.2017, 22:19
|
|
Прописка
Регистрация: 29.03.2007
Сообщений: 185
Сказал спасибо: 11
Сказали Спасибо 1 раз в 1 сообщении
|
Re: Оцените алгоритм опроса матричной клавы
Про const ваще из головы вылетело.
Цитата:
|
Код:
|
for(i = 0; i ‹ COLS; i++){
key_code = key_code ‹‹ 1;
if(col_port[i]-›IDR & (1 ‹‹ col_pin[i])){
key_code |= 1;
}
} |
|
Допустим я нажимаю на кнопку - 9. Надо бит сместить на 9 влево. А тут он сместится на 2.
|
|
|
|
Ваши права в разделе
|
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения
HTML код Выкл.
|
|
|
Часовой пояс GMT +4, время: 05:28.
|
|