Реклама на сайте English version  DatasheetsDatasheets

KAZUS.RU - Электронный портал. Принципиальные схемы, Datasheets, Форум по электронике

Новости электроники Новости Литература, электронные книги Литература Документация, даташиты Документация Поиск даташитов (datasheets)Поиск PDF
  От производителей
Новости поставщиков
В мире электроники

  Сборник статей
Электронные книги
FAQ по электронике

  Datasheets
Поиск SMD
Он-лайн справочник

Принципиальные схемы Схемы Каталоги программ, сайтов Каталоги Общение, форум Общение Ваш аккаунтАккаунт
  Каталог схем
Избранные схемы
FAQ по электронике
  Программы
Каталог сайтов
Производители электроники
  Форумы по электронике
Помощь проекту


Закрытая тема
Опции темы
Непрочитано 09.09.2016, 20:38   #11
supercelt
Прописка
 
Регистрация: 29.03.2007
Сообщений: 185
Сказал спасибо: 11
Сказали Спасибо 1 раз в 1 сообщении
supercelt на пути к лучшему
По умолчанию Re: Оцените алгоритм опроса матричной клавы

Короче сделал ). Нажатия обрабатываются вроде быстро, по крайней мере на глаз тормозов нет. Правда пришлось отказаться от внешних прерываний, подумал, фиг с ним, пусть таймер постоянно тикает. С прерываниями работало медленно + не сбрасывался флаг UIF таймера, хотя дебаггер по нему проходился. Можно посчитать удержание. И символ не печатается повторно при зажатии кнопки. Как-то так

Код:
#include "keyboard.h"

uint8_t timer_flag = 0;
uint8_t count_scan = 0;
uint8_t count_up = 0;
uint8_t count_down = 0;
uint16_t key = 0;
uint16_t old_key = 0;
uint16_t find_key = 0;
unsigned char cols[] = {5,6,7,8};

void TIM2_IRQHandler(void){
		TIM2-›SR = 0; 
		timer_flag = 1;
		
}											 

void KEYBOARD_INI(void){
		RCC-›APB2ENR |= RCC_APB2ENR_IOPBEN | RCC_APB2ENR_AFIOEN;             //CMD PORT B. cmd alt func
		GPIOB-›CRH &= ~(GPIO_CRH_CNF11_0 | GPIO_CRH_CNF12_0 | GPIO_CRH_CNF13_0 | GPIO_CRH_CNF14_0);        //Scan Pins: PB11, PB12, PB13, PB14.
		GPIOB-›CRH |= GPIO_CRH_CNF11_1 | GPIO_CRH_CNF12_1 | GPIO_CRH_CNF13_1 | GPIO_CRH_CNF14_1;         //Input Push-down.
	  GPIOB-›CRL &= ~(GPIO_CRL_CNF5_0 | GPIO_CRL_CNF6_0 | GPIO_CRL_CNF7_0);       //Generate Pins: PB5, PB6, PB7, PB8.
		GPIOB-›CRH &= ~GPIO_CRH_CNF8_0;
		GPIOB-›CRL |= GPIO_CRL_MODE5_1 | GPIO_CRL_MODE6_1 | GPIO_CRL_MODE7_1;        //Output Push-pull.
    GPIOB-›CRH |= GPIO_CRH_MODE8_1;	
		GPIOB-›BSRR = 0x1E0;
	
		//--------Setup TIMER 2---------------------------
		RCC-›APB1ENR |= RCC_APB1ENR_TIM2EN;                    //Enable TIMER 2
		TIM2-›PSC = 0x95F;                     //Prescaler 2400 - 1/ Clock timer 1 kHz
		TIM2-›CR1 &= ~(TIM_CR1_DIR | TIM_CR1_CMS | TIM_CR1_CKD);	                   //Count up, clock division, mode selection
		TIM2-›ARR = 0x32; //0xC8; //0x2710;                      //Count up to 200/	Interrupt/20ms	
		NVIC_EnableIRQ(TIM2_IRQn);	             //Enable interrupt for timer2
		TIM2-›DIER |= TIM_DIER_UIE;                      //Interrupt update counter/ perepolnenie
		TIM2-›SR = 0;
		TIM2-›CR1 |= TIM_CR1_CEN;
		//------------------------------------------------
	
		//test led pc8
		GPIOC-›CRH &= ~GPIO_CRH_CNF8_0;//TEST LED EXTI
	  GPIOC-›CRH |= GPIO_CRH_MODE8_1;
		GPIOC-›BSRR = 0x100;
		//
}

void KEYBOARD_SCAN(void){
		timer_flag = 0;
		if(!GPIOB-›IDR & 0x7800){return;}
		for(count_scan = 0; count_scan ‹ 4; count_scan++){
				GPIOB-›BRR = 0x1E0;
				GPIOB-›BSRR = (1 ‹‹ cols[count_scan]);
				if(count_down ›= 10){
						if(GPIOB-›IDR & 0x7800){
								count_up = 0;
								return;
						} else {
								count_up++;
						}
						if(count_up == 10){
								count_up = 0;
								count_down = 0;
								find_key = 0;
								return;
						}
				} else {
						if(GPIOB-›IDR & 0x7800){
								key = (GPIOB-›IDR & 0x79E0);
								if(key == old_key){
										count_down++;
								} else {
										old_key = key;
								}
						}
						if(count_down == 10){
								old_key = 0;
								find_key = READ_KEY(key);
								return;
						}
				}
		}		
}

char READ_KEY(uint16_t k){
		char c;
		switch(k){
				case 0x820:
						c = '1';
				break;
				case 0x840:
						c = '2';
				break;
				case 0x880:
						c = '3';
				break;
				case 0x900:
						c = 'A';
				break;
				case 0x1020:
						c = '4';
				break;
				case 0x1040:
						c = '5';
				break;
				case 0x1080:
						c = '6';
				break;
				case 0x1100:
						c = 'B';
				break;
				case 0x2020:
						c = '7';
				break;
				case 0x2040:
						c = '8';
				break;
				case 0x2080:
						c = '9';
				break;
				case 0x2100:
						c = 'C';
				break;
				case 0x4020:
						c = '*';
				break;
				case 0x4040:
						c = '0';
				break;
				case 0x4080:
						c = '#';
				break;
				case 0x4100:
						c = 'D';
				break;
				default:
						c = 'E';
				break;
		}
		return c;
}
//Ne uspevaet otrabotat/ count_down ne doschitivaet/ Tolko kogda derzhish knopku podolshe/ Uskorit opros/ Zamenil 0x32 na 0xA/ Poeksperimentirovat
Реклама:
supercelt вне форума  
Непрочитано 04.03.2017, 22:00   #12
supercelt
Прописка
 
Регистрация: 29.03.2007
Сообщений: 185
Сказал спасибо: 11
Сказали Спасибо 1 раз в 1 сообщении
supercelt на пути к лучшему
По умолчанию Re: Оцените алгоритм опроса матричной клавы

Сообщение от NewWriter Посмотреть сообщение
А благодаря выходам Open drain и входам pullup, никаких запредельных токов и без дополнительных элементов, клавиатура подключается непосредственно на порты МК.
Я сделал так и теперь при нажатии кнопки у меня блёкнут символы на LCD дисплее. Это конечно не критично, но на глаз заметно. Запредельных токов нет, но походу идёт просадка напруги через этот Open Drain
supercelt вне форума  
Непрочитано 23.08.2017, 18:10   #13
supercelt
Прописка
 
Регистрация: 29.03.2007
Сообщений: 185
Сказал спасибо: 11
Сказали Спасибо 1 раз в 1 сообщении
supercelt на пути к лучшему
По умолчанию Опрос матричной клавы. Часть2

Всем привет. Помогите пожалуйста разобраться. Код который ниже успешно работал на stm32f100. Теперь я его перенес на f4, естественно поменяв все что нужно. Но работать нормально отказывается. Кто не видел поста раньше, - это опросник матричной клавы 3х4 (оригинал кода немного отличается от того что в прошлом посте). Мне советовали сделать строки в открытый коллектор, перевести выводы в высокоомку и потом при сканировании гонять 0. А строки сделать на вход с подтяжкой к питанию. И на строках ловить ноль, когда нажимаю кнопку. Вобщем логика такая. Сначала идут настройки. Немного а автомате, что бы при смене пинов и портов много не переписывать. Так, значит в начальном состоянии строки настроены как открытый коллектор и я подтянул его к 0. Далее настроил все колонки на внешнее прерывание по спаду. По идее, когда нажмут любую кнопку сработает прерывание. Ну собсно оно так и происходит. Проверял. Значит щас будет таймлапс. Нажали кнопку. Сработало прерывание, вошли в вектор, сбросили флаги, потом выключили все внешние прерывания, что бы не сработало от дребезга. Далее перевели все строки в высокоомку. ну как бы в 1. Запустили таймер, который будет запускать сканирование каждые н милисекунд - указано в параметрах. Так, таймер начал тикать. Попал в прерывание по переполнению, установил start_scan. Далее эта штука ловится в мэйне и вызывает функцию скана. Теперь самое интересное. И так. Открываем цикл скана строк. переводим 1 строку в 0. и ещё циклом перебираем столбы, смотрим есть 0 или нет. Ну дальше идут всякие вычисления по подсчету нажатия кнопки, сколько держали, когда отпустили и расчет на удержание кнопки. В коде к строчкам есть пояснения.
Проблема то в чем, а в том, что на f4 это не работает, хотя должно. Точнее сказать почти работает. К слову я вывожу нажатую кнопку на lcd. Работает только самый нижний ряд клавиатуры, то есть *0#. Остальное не выводится, но в отладчике если смотреть, когда нажимаешь клавишу 1, переменная key будет 4. Если нажать 4, будет 7. То есть со смещением на 1 вниз. И причем на экран так и не выводит, то есть почему-то не засчитывает нажатие.
Далее поэкспериментировав я обнаружил интересную вещь. Если строки при настройках, подтянуть не к 0, а к 1, то начинает работать последний столбец - 3,6,9,#. ну и так же нижний ряд. Остальное не пашет. Потом я вернул подтяжку в 0, так как изначально для реагирования на прерывания по спаду, должен быть 0.
Закралась мне мысль, что эти мещения могут быть от того что кто-то что-то не успевает. И там где в цикле идет установка 0, я поставил задержку. Она закоменчена. И хм.мм.. да надо подержать кнопку подольше, но теперь работают все кнопки. То есть я так понял, что этот 0 на строке не успевает установиться? А я уже проверяю его....При это нижний ряд все так же исправно и быстро работает. Вобщем такая вот проблема.
Листинги:
keyboard.c
Нажмите, чтобы открыть спойлер

Код:
#include "keyboard.h"
#include "delay.h"

uint8_t start_scan = 0, counter_row_scan = 0, counter_col_scan = 0, counter_release = 0, counter_pressed = 0;
char key = 0, old_key = 0, find_key = 0, find_hold_key = 0;
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}; //Запихиваем номера пинов колонок в массив
char keys[ROWS][COLS] = { //Массив кнопок 3х4
		 {'1','2','3'},
		 {'4','5','6'},
		 {'7','8','9'},
		 {'*','0','#'}	
};

void TIM6_DAC_IRQHandler(void){
	if(TIM6-›SR & TIM_SR_UIF){
	        TIM6-›SR &= ~TIM_SR_UIF;
		start_scan = 1;
	}
}

void EXTI15_10_IRQHandler(void){ //Обработчик внешних прерываний с 10 по 15 пинов (при смене пинов, дописать нужные обработчики. Этот не универсален)
	uint8_t i;
	if(EXTI-›PR & (1 ‹‹ 10)){
		EXTI-›PR = (1 ‹‹ 10);
	}
	if(EXTI-›PR & (1 ‹‹ 11)){
		EXTI-›PR = (1 ‹‹ 11);
	}
	if(EXTI-›PR & (1 ‹‹ 12)){
		EXTI-›PR = (1 ‹‹ 12);
	}
	if(EXTI-›PR & (1 ‹‹ 13)){
		EXTI-›PR = (1 ‹‹ 13);
	}
	if(EXTI-›PR & (1 ‹‹ 14)){
		EXTI-›PR = (1 ‹‹ 14);
	}
	if(EXTI-›PR & (1 ‹‹ 15)){
		EXTI-›PR = (1 ‹‹ 15);
	}	
	for(i = 0; i ‹ COLS; i++){
		EXTI-›FTSR &= ~(1 ‹‹ col_pin[i]); //Выкл прерывания путём откл условия срабатывания прерывания (по спаду фронта). Если откл разрешение прерывания, то потом при его вкл, почему-то сразу срабатывает прерывание
	}
	for(i = 0; i ‹ ROWS; i++){
		row_port[i]-›BSRRL = (1 ‹‹ row_pin[i]); //Все пины в 1
	}
	TIM6-›CR1 |= TIM_CR1_CEN;
}

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, 1, 0x02, 0x02); //настройка рядов выходов. Порт, пин, MODER, OTYPER, OSPEEDR, PUPDR
	}
	for(i = 0; i ‹ COLS; i++){
		port_cmd(col_port[i]); //Включаем тактирование порта столбца
		gpio_setup(col_port[i], col_pin[i], 0x00, 0, 0x00, 0x01); //настройка рядов выходов. Порт, пин, MODER, OTYPER, OSPEEDR, PUPDR
	}
	//EXTI
	RCC-›APB2ENR |= RCC_APB2ENR_SYSCFGEN; //Включить тактирование syscfg для доступа к записи в регистры exticr
	for(i = 0; i ‹ COLS; i++){
		exti_setup(col_port[i], col_pin[i]);
	}
	//TIM6
	RCC-›APB1ENR |= RCC_APB1ENR_TIM6EN;
	TIM6-›PSC |= 8399; //F = 10 kHz
	TIM6-›ARR = (10*KEY_SCAN_PERIOD);
	TIM6-›EGR |= TIM_EGR_UG;
	__NOP();
	__NOP();
	TIM6-›SR &= ~(TIM_SR_UIF);
	TIM6-›DIER |= TIM_DIER_UIE;
	NVIC_EnableIRQ(TIM6_DAC_IRQn);
}

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));
}

void exti_setup(GPIO_TypeDef * port, uint8_t pin){
	SYSCFG-›EXTICR[pin ›› 2] |= ((((uint32_t)port - AHB1PERIPH_BASE) ›› 10) ‹‹ ((pin%4) ‹‹ 2));
	EXTI-›IMR |= (1 ‹‹ pin);
	EXTI-›FTSR |= (1 ‹‹ pin);
	switch(pin){
		case 0:
			NVIC_EnableIRQ(EXTI0_IRQn);
		break;
		case 1:
			NVIC_EnableIRQ(EXTI1_IRQn);
		break;
		case 2:
			NVIC_EnableIRQ(EXTI2_IRQn);
		break;
		case 3:
			NVIC_EnableIRQ(EXTI3_IRQn);
		break;
		case 4:
			NVIC_EnableIRQ(EXTI4_IRQn);
		break;
		case 5:
		case 6:
		case 7:
		case 8:
		case 9:
			NVIC_EnableIRQ(EXTI9_5_IRQn);
		break;	
		case 10:
		case 11:
		case 12:
		case 13:
		case 14:
		case 15:
			NVIC_EnableIRQ(EXTI15_10_IRQn);
		break;
	}
}

void keyboard_scan(void){
	int i;
	start_scan = 0; //Сбрасываем флаг, после вызова этой функции
	for(counter_row_scan = 0; counter_row_scan ‹ ROWS; counter_row_scan++){ //Сканирование рядов
		row_port[counter_row_scan]-›BSRRH = (1 ‹‹ row_pin[counter_row_scan]); //Выставляем 0 на текущем пине рядов
		//delay_us(5);
		for(counter_col_scan = 0; counter_col_scan ‹ COLS; counter_col_scan++){ //Сканирование колонок
			if(!(col_port[counter_col_scan]-›IDR & (1 ‹‹ col_pin[counter_col_scan]))){ //Если на текущем пине колонок обнаружился 0
				counter_release = 0; //Обнулить счётчик отпускания кнопки
				key = keys[counter_row_scan][counter_col_scan]; //Записать текущеесостояние кнопки из массива
				if(key == old_key){ //Если текущая кнопка равна кнопке с прошлого сканирования
					if(KEY_COUNT_SCAN == counter_pressed++){ //Если кнопку нажимают в течении количества сканирований, указанных в параметрах, то засчитываем нажатие кнопки + увеличиваем счётчик нажатой кнопки
						find_key = key; //Кнопка найдена
					}
					if(KEY_HOLD_COUNTER_PERIOD == counter_pressed){ //Срабатывание от длительного нажатия кнопки //Если кнопка нажата в течении указанного в параметрах количества секунд
						find_hold_key = key; //Символ пустышка, для опознования, что сработало долгое нажатие определённой кнопки.
					}
				}else{
					old_key = key; //В следующем сканировании, old key это будет значение кнопки просканенное в прошлый раз
				}
			}else{
				if(counter_pressed › KEY_COUNT_SCAN){ //Если количество сканирований нажатой кнопки больше указанных в параметрах
					if((COLS * KEY_COUNT_SCAN) == counter_release++){ //Если количество колонок умноженное на количество, заданное в параметрах, сканирований отпущенной кнопки равно количеству сканирований отпущенной кнопки + попутно сразу инкремент счётчика
						counter_pressed = 0; //Сброс счётчика нажатой кнопки
						counter_release = 0; //Сброс счётчика отпущенной кнопки
						TIM6-›CR1 &= ~TIM_CR1_CEN; //Выключение таймера2
						TIM6-›CNT = 0; //Обнуление счётчика таймера2
						old_key = 0;
						key = 0;
						for(i = 0; i ‹ ROWS; i++){
							row_port[i]-›BSRRH = (1 ‹‹ row_pin[i]); //Все пины рядов обратно в 0
							EXTI-›FTSR |= (1 ‹‹ col_pin[i]); //Включаем прерывания путём вкл условия срабатывания прерывания (по спаду фронта)
						}
						return; //Кнопка отжата, всё выключили, больше в этой функции нечего делать, поэтому принудительно выходим
					}
				}
			}
		}
		row_port[counter_row_scan]-›BSRRL = (1 ‹‹ row_pin[counter_row_scan]); //После скана всех колонок поднимаем лог уровень на текущем ряде в 1
	}
}


keyboard.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 10 //Период сканирования, 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 uint8_t start_scan;
extern char find_key, find_hold_key;

void keyboard_ini(void);
void keyboard_scan(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);
void exti_setup(GPIO_TypeDef * port, uint8_t pin);
#endif


main.c
Нажмите, чтобы открыть спойлер

Код:
//Файлы должны быть в кодировке ANSI! Настройка кодировки Keil - win cp1251

#include "stm32f4xx.h"   
#include "main.h"

int main(void){
	SystemInit();
	SystemCoreClockUpdate();
	__enable_irq();	
	lcd_ini();
	keyboard_ini();
	//lcd_send_string_xy(0,0,"Тест. Ю Ы Ж");
	while(1){
		if(start_scan){
			keyboard_scan();
		}
		if(find_key){
			lcd_send_data(find_key);
			find_key = 0;	
		}
		if(find_hold_key){
			lcd_send_string_xy(0,0,"HOLD");
			find_hold_key = 0;
		}
	}
}

Последний раз редактировалось supercelt; 23.08.2017 в 18:14.
supercelt вне форума  
Непрочитано 23.08.2017, 23:01   #14
bass1981
Гражданин KAZUS.RU
 
Регистрация: 01.09.2007
Сообщений: 898
Сказал спасибо: 278
Сказали Спасибо 57 раз(а) в 54 сообщении(ях)
bass1981 на пути к лучшему
По умолчанию Re: Опрос матричной клавы. Часть2

Странно, на чипе с более медленной тактовой частотой работает, на более мощном чипе не работает....
Хоть ссылку дайте на предыдущий пост, без схемотехники очень трудно что то понять в вашем коде....
bass1981 вне форума  
Непрочитано 24.08.2017, 16:10   #15
supercelt
Прописка
 
Регистрация: 29.03.2007
Сообщений: 185
Сказал спасибо: 11
Сказали Спасибо 1 раз в 1 сообщении
supercelt на пути к лучшему
По умолчанию Re: Опрос матричной клавы. Часть2

Пытаюсь... кусок кода

Код:
void keyboard_scan(void){
	int i;
	static int ii;
	start_scan = 0; //Сбрасываем флаг, после вызова этой функции
	for(counter_row_scan = 0; counter_row_scan ‹ ROWS; counter_row_scan++){ //Сканирование рядов
		row_port[counter_row_scan]-›BSRRH = (1 ‹‹ row_pin[counter_row_scan]); //Выставляем 0 на текущем пине рядов
		//while((row_port[counter_row_scan]-›ODR & (1 ‹‹ row_pin[counter_row_scan])) == 1){}//test
		for(counter_col_scan = 0; counter_col_scan ‹ COLS; counter_col_scan++){ //Сканирование колонок
			if(!(col_port[counter_col_scan]-›IDR & (1 ‹‹ col_pin[counter_col_scan]))){ //Если на текущем пине колонок обнаружился 0
				counter_release = 0; //Обнулить счётчик отпускания кнопки
				key = keys[counter_row_scan][counter_col_scan]; //Записать текущеесостояние кнопки из массива
				ke[ii++] = counter_row_scan;
				if(key == old_key){ //Если текущая кнопка равна кнопке с прошлого сканирования
					if(KEY_COUNT_SCAN == counter_pressed++){ //Если кнопку нажимают в течении количества сканирований, указанных в параметрах, то засчитываем нажатие кнопки + увеличиваем счётчик нажатой кнопки
						find_key = key; //Кнопка найдена
					}
думал, 0 на рядах не успевает устанавливаться, ввел строчку while((row_port[counter_row_scan]-›ODR & (1 ‹‹ row_pin[counter_row_scan])) == 1){}//test
Не помогает. По прежнему работает только нижний ряд. Далее ввел массив ke. и просто заполняю его индексами рядов. То есть при сканировании если нажатие найдено, то индекс ряда к котором это произошло запишется в этот массив.
Результаты этого массива таковы: когда я нажимаю любую кнопку из нижнего 4 ряда, в массиве везде 3. Что и правильно. Но когда я жму любую другую кнопку, в массиве - 0,1,2,3,0,1,2,3,0,1,2,3.
То есть получается на столбце 0 всегда. Не зависимо от того что вообще-то по рядам единицы и 0 поочередно прогоняется. Мистика.
supercelt вне форума  
Непрочитано 24.08.2017, 22:51   #16
supercelt
Прописка
 
Регистрация: 29.03.2007
Сообщений: 185
Сказал спасибо: 11
Сказали Спасибо 1 раз в 1 сообщении
supercelt на пути к лучшему
По умолчанию Re: Оцените алгоритм опроса матричной клавы

Выкинул прерывания, теперь таймер работает постоянно. Скан клавы непрерывано. Тупо гоняем скан. Из кода для проверки выкинул все лишнее, просто посмотреть что записывается в key и ke.
Код:
void keyboard_scan(void){
	//int i;
	start_scan = 0; //Сбрасываем флаг, после вызова этой функции
	for(counter_row_scan = 0; counter_row_scan ‹ ROWS; counter_row_scan++){ //Сканирование рядов
		row_port[counter_row_scan]-›BSRRH = (1 ‹‹ row_pin[counter_row_scan]); //Выставляем 0 на текущем пине рядов
		while((row_port[counter_row_scan]-›ODR & (1 ‹‹ row_pin[counter_row_scan])) == 1){}//test
		for(counter_col_scan = 0; counter_col_scan ‹ COLS; counter_col_scan++){ //Сканирование колонок
			if(!(col_port[counter_col_scan]-›IDR & (1 ‹‹ col_pin[counter_col_scan]))){ //Если на текущем пине колонок обнаружился 0
				key = keys[counter_row_scan][counter_col_scan]; //Записать текущеесостояние кнопки из массива
				ke[ii++] = counter_row_scan;
		        }
		row_port[counter_row_scan]-›BSRRL = (1 ‹‹ row_pin[counter_row_scan]); //После скана всех колонок поднимаем лог уровень на текущем ряде в 1
		while((row_port[counter_row_scan]-›ODR & (1 ‹‹ row_pin[counter_row_scan])) == 0){}//test
	}
}
Даже поставил вайлы для надежности. мало ли бит не успевает железо поставить. Вобщем если ставить точку останова к примеру на if(!(col_port[counter_col_scan]-›IDR & (1 ‹‹ col_pin... и запустить, то при нажатии на кнопку клавиатуры "1" и далее по шагам дойти до key, то оно будет 1. Но если убрать точку останова, запустить и нажать "1", то key будет "*". Опять последний ряд(((
supercelt вне форума  
Непрочитано 25.08.2017, 08:58   #17
6ap6oc
Прописка
 
Регистрация: 02.03.2010
Сообщений: 139
Сказал спасибо: 12
Сказали Спасибо 49 раз(а) в 26 сообщении(ях)
6ap6oc на пути к лучшему
По умолчанию Re: Оцените алгоритм опроса матричной клавы

Вы работаете так: проверили состояние одного пина, прочитав порт, затем проверяете следующий, опять читая порт.
Пожалуй, правильнее будет так:
Установите ряд.
Прочитайте порт строк в переменную и "сканируйте" биты в ней.
Даже так:
Установив ряд, задайте небольшую задержку, емкости реальной схемы никто не отменял.

В вашем случае:
Считывайте значение по установленному в предыдущем такте таймера ряду, а затем меняйте его. Задержка будет не нужна.

Последний раз редактировалось 6ap6oc; 25.08.2017 в 09:06.
6ap6oc вне форума  
Непрочитано 25.08.2017, 10:03   #18
dgrishin
Почётный гражданин KAZUS.RU
 
Регистрация: 12.02.2013
Сообщений: 1,038
Сказал спасибо: 43
Сказали Спасибо 273 раз(а) в 214 сообщении(ях)
dgrishin на пути к лучшему
По умолчанию Re: Оцените алгоритм опроса матричной клавы

Сообщение от supercelt Посмотреть сообщение
Код который ниже успешно работал на stm32f100
А опрашивать клавиатуру со скоростью несколько десятков мегагерц это хорошая идея ??
Про отсутствие защиты от дребезга контактов я уже молчу.
dgrishin вне форума  
Непрочитано 25.08.2017, 10:13   #19
mike-y-k
Модератор
 
Регистрация: 04.08.2010
Адрес: Москва СЗАО
Сообщений: 11,257
Сказал спасибо: 11,170
Сказали Спасибо 3,858 раз(а) в 2,928 сообщении(ях)
mike-y-k на пути к лучшему
По умолчанию Re: Оцените алгоритм опроса матричной клавы

supercelt, может посмотрите это решение на досуге?
В МК останется только код для инициализации, обработки прерывания и считывания результата. И ног гораздо меньше отнимет - всего 4.
А там уже и защита от дребезга, и все остальные плюшки .
Просто время, уже потраченное на изобретение велосипеда, явно гораздо дороже стоит чем комплект разработчика с мешочком чипов по ссылке…
__________________
rtfm forever должно быть основой для каждого. Альтернатива грустна, поскольку метод слепого щенка успешно работает при весьма малом числе вариантов…
mike-y-k вне форума  
Непрочитано 25.08.2017, 14:13   #20
supercelt
Прописка
 
Регистрация: 29.03.2007
Сообщений: 185
Сказал спасибо: 11
Сказали Спасибо 1 раз в 1 сообщении
supercelt на пути к лучшему
По умолчанию Re: Оцените алгоритм опроса матричной клавы

Сообщение от dgrishin Посмотреть сообщение
А опрашивать клавиатуру со скоростью несколько десятков мегагерц это хорошая идея ??
Про отсутствие защиты от дребезга контактов я уже молчу.
У меня таймер настроен на 10 килогерц. То есть функция которая сканит вызывается с этой частотой. Но вот сам скан из вот этих циклов и установок битов, там конечно все происходит со скоростью в мегагерцы. Можно по идее снизить частоту камня до той что у меня была в прошлом чипе, ну а ели мне понадобится полная мощность для чего-нибудь другого что я сюда же подцеплю?
supercelt вне форума  
Закрытая тема

Закладки


Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.

Быстрый переход


Часовой пояс GMT +4, время: 04:44.


Powered by vBulletin® Version 3.8.4
Copyright ©2000 - 2024, Jelsoft Enterprises Ltd. Перевод: zCarot