Newer
Older
matrix4x5 / keypad.c
/**
 *   @file keypad.c
 *
 *   @date 01.02.2015
 * @author Pascal Gollor
 *     web http://www.pgollor.de
 *
 * @copyright Dieses Werk ist unter einer Creative Commons Lizenz vom Typ
 * Namensnennung - Weitergabe unter gleichen Bedingungen 3.0 Deutschland zugänglich.
 * Um eine Kopie dieser Lizenz einzusehen, konsultieren Sie
 * http://creativecommons.org/licenses/by-sa/3.0/de/ oder wenden Sie sich
 * brieflich an Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.
 *
 * -- englisch version --
 * @n This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Germany License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.
 *
 */

#include "keypad.h"

#include <avr/pgmspace.h> // PROGMEM
#include <util/delay.h>   // delay_ms
#ifdef KEYPAD_DEBUG
	#include "defs.h"
	#include "uart.h"
#endif


/**
 * @brief keypad keys
 *
 * for each key you can use everything value from 0-254
 * 255 means: no valid key
 */
PROGMEM const uint8_t g_keypad_key[KEYPAD_ROWS][KEYPAD_COLUMNS] = {
		{'a', 'b', '#', '*'},
		{'1', '2', '3', 'c'},
		{'4', '5', '6', 'd'},
		{'7', '8', '9', 'e'},
		{'<', '0', '>', 'f'}
};


/**
 * @brief init io ports for keypad
 */
void keypad_init(void)
{
  // columns
	KEYPAD_COLUMN_REGISTER |= KEYPAD_COLUMN_BITS; // define columns as output
	KEYPAD_COLUMN_OUT &= ~(KEYPAD_COLUMN_BITS); // set columns to zero

	// rows
	KEYPAD_ROW_REGISTER &= ~(KEYPAD_ROW_BITS); // define rows as input
	KEYPAD_ROW_OUT |= KEYPAD_ROW_BITS; // enable pullup for rows
}


/**
 * @brief get key from keypad
 */
uint8_t keypad_getKey(void)
{
	uint8_t col = KEYPAD_NO_VALID_KEY;
	uint8_t row = 0;

	// read row channels
	row = ((~KEYPAD_ROW_IN) & KEYPAD_ROW_BITS) >> KEYPAD_ROW_FIRST_CHANNEL;
	if (row == 0)
	{
		// no key is pressed
		return KEYPAD_NO_VALID_KEY;
	}

	// wait for debounce
	_delay_ms(10);
	if (row != ((~KEYPAD_ROW_IN) & KEYPAD_ROW_BITS) >> KEYPAD_ROW_FIRST_CHANNEL)
	{
		return KEYPAD_NO_VALID_KEY;
	}

	// set columns to zero
	KEYPAD_COLUMN_OUT &= ~(KEYPAD_COLUMN_BITS);
	_delay_us(1);

	// check for pressed column
	for (uint8_t i = KEYPAD_COLUMN_FIRST_CHANNEL; i < (KEYPAD_COLUMN_FIRST_CHANNEL + KEYPAD_COLUMNS); i++)
	{
		KEYPAD_COLUMN_OUT |= (1 << i);
		_delay_us(1);

		if ((KEYPAD_ROW_IN & KEYPAD_ROW_BITS) == KEYPAD_ROW_BITS)
		{
			// debounce
			_delay_ms(10);

			if ((KEYPAD_ROW_IN & KEYPAD_ROW_BITS) != KEYPAD_ROW_BITS)
			{
				col = KEYPAD_NO_VALID_KEY;
				break;
			}

			col = i - KEYPAD_COLUMN_FIRST_CHANNEL;
			break;
		}

		KEYPAD_COLUMN_OUT &= ~(1 << i);
		_delay_us(1);
	}

	// set columns to zero
	KEYPAD_COLUMN_OUT &= ~(KEYPAD_COLUMN_BITS);

	if (col == KEYPAD_NO_VALID_KEY)
	{
		// no column detected
		return KEYPAD_NO_VALID_KEY;
	}

  // detect row
	for (uint8_t i = 0; i < KEYPAD_ROWS; i++)
	{
		if (row >> i == 1)
		{
			row = i;
			break;
		}
	}

	if (row >= KEYPAD_ROWS)
		return KEYPAD_NO_VALID_KEY;

#ifdef KEYPAD_DEBUG
	printf("row: %i" CR, row);
	printf("column: %i" CR, col);
	uart_flush();
#endif

	// return key from keylist
	return pgm_read_byte(&g_keypad_key[row][col]);
}


/**
 * @brief get key and wait to for loosing
 */
uint8_t keypad_getKeyAndWait(void)
{
	uint8_t key = keypad_getKey();
	uint8_t last_key = KEYPAD_NO_VALID_KEY;

	if (key == KEYPAD_NO_VALID_KEY)
	{
		return KEYPAD_NO_VALID_KEY;
	}

	last_key = key;
	while (key != KEYPAD_NO_VALID_KEY)
	{
		key = keypad_getKey();
	}

	return last_key;
}