📄 keymatrix.c
字号:
//************************************************
//* Matrix keyboard decoder
//* Main driver source file
//*
//* Filename: keymatrix.c
//* Version: 1.0
//*
//* Device: ATmega162
//* Clock: Internal 1.000 MHz RC oscillator
//*
//************************************************
#include <iom162.h>
#include <inavr.h>
#include "keymatrix.h"
#pragma language=extended
/*** Macros and definitions ***/
#define SELECT_POWERDOWN MCUCR |= (1<<SM1) // Macro to select powerdown sleep mode
#define SELECT_IDLESLEEP MCUCR &= ~(1<<SM1) // Macro to select idle sleep mode
#define ENABLE_PCINT GICR |= (1<<PCIE1) // Enable pin change interrupt (pins PCINT8..15)
#define DISABLE_PCINT GICR &= ~(1<<PCIE1) // Disable pin change interrupt
#define COLPORT PORTC // Column io registers
#define COLPIN PINC
#define COLDIR DDRC
#define ROWPORT PORTD // Row io registers
#define ROWPIN PIND
#define ROWDIR DDRD
/*** Global variables ***/
volatile unsigned char key_altState; // Holding current alternation flags
volatile union _key_code key_code; // Scan result structure
/*** Driver initialization ***/
//*
//* Sets up necessary ports and variables.
//* Use this at startup or when
//* restarting the driver after a stop.
//*
void key_init()
{
/* Init global variables */
key_altState = 0; // Clear alternation flags
key_code.complete = 0; // Clear scan result
/* Init ports */
ROWDIR = 0xFF; // Set row lines to output
//ROWPORT = 0x00; // Drive all row lines low
//COLDIR = 0x00; // Set column lines to input
COLPORT = 0xFF; // Pull column lines high
/* Init timer prescaler (CLK/256) */
//*
//* Always set prescaler such that the timer
//* overflow period is greater than 5 ms.
//*
TCCR0 = (1<<CS02) | (0<<CS01) | (0<<CS00); // Interrupt every 8.2 ms @ 8.000 MHz
/* Enable pin change interrupt */
PCMSK1 = 0xFF; // Enable idividual pins
ENABLE_PCINT; // Enable interrupt
/* Allow main application to sleep */
SELECT_POWERDOWN; // Select power down sleep mode
}
/*** Stop keyboard scanning driver ***/
//*
//* Stops the keyboard scanning driver until
//* key_init() is called again. Saves power
//* if keyboard is not needed but may be
//* pressed by the application user.
//*
void key_stop()
{
DISABLE_PCINT; // Disable pin change interrupt
TIMSK &= ~(1<<TOIE0); // Disable timer overflow interrupt
}
/*** Wait for a keypress ***/
//*
//* This waits for the updateflag to
//* be set by the driver.
//* The flag is cleared and the
//* scancode is returned.
//* The user may check the key_code variable
//* for scancode details.
//*
unsigned char key_get()
{
while( !key_code.updated ) // Sleep until update flag set
{
__sleep();
}
key_code.updated = 0; // Clear flag and return scancode
return key_code.scan;
}
/*** Pin change interrupt handler ***/
//*
//* This disables further pin change interrups and
//* initilizes the timer to wait a short delay, letting
//* the keyboard contacts settle. The timer overflow
//* interrupt therefore handles the scanning process.
//*
#pragma vector=PCINT1_vect
__interrupt void pinChange1ISR()
{
DISABLE_PCINT; // Prevent further pin change interrupts
/* Prepare timer delay */
TCNT0 = 0; // Reset timer counter
TIMSK |= (1<<TOIE0); // Enable timer 0 overflow interrupt
SELECT_IDLESLEEP; // Use idle sleep mode for timer delay
}
/*** Process alternation keys ***/
//*
//* This compares generated scancode to
//* predefined alternation codes and
//* updates flags accordingly.
//* Executed from timer overflow interrupt.
//*
#ifdef ALTKEYS
void key_processAltKeys()
{
key_code.flags = key_altState | 0x80; // Save alternation flags
if ( key_code.scan == ALTKEY0 ) key_altState ^= (1<<0);
else if( key_code.scan == ALTKEY1 ) key_altState ^= (1<<1);
else if( key_code.scan == ALTKEY2 ) key_altState ^= (1<<2);
else if( key_code.scan == ALTKEY3 ) key_altState ^= (1<<3);
else if( key_code.scan == LCKKEY0 ) key_altState ^= (1<<4);
else if( key_code.scan == LCKKEY1 ) key_altState ^= (1<<5);
else if( key_code.scan == LCKKEY2 ) key_altState ^= (1<<6);
else // Not alternation key ?
{
key_altState &= ALTLOCKMASK; // Clear one-shot key flags
}
}
#endif
/*** Timer overflow interrupt handler ***/
//*
//* This scans the keyboard and handles any keypresses.
//* The alternation flags are also updated.
//* Finally the pin change interrupt is reenabled
//* to wait for further key changes.
//*
#pragma vector=TIMER0_OVF_vect
__interrupt void timer0OVFISR()
{
/* Local variables */
unsigned char lineResult; // Resulting column and row lines
unsigned char tempScan; // Temporary scancode
PORTB |= 1;
PORTB &= ~1;
/* Disable timer interrupt */
TIMSK &= ~(1<<TOIE0);
/* Find column of keypress */
lineResult = COLPIN; // Get column lines
if( lineResult != 0xFF ) // Any column lines low ?
{
/* Invert port directions */
ROWPORT = 0xFF; // Drive all row lines high
COLPORT = 0x00; // Disable pull-up on column lines
ROWDIR = 0x00; // Set row lines to input, already pulled up
COLDIR = 0xFF; // Set column lines to output, already driven low
tempScan = 0; // Init temp scan code
while( lineResult & 0x01 ) // Loop while column line high
{
lineResult >>= 1; // Next column line into LSB
tempScan++; // Increment column part of scancode
}
/* Find row of keypress */
lineResult = ROWPIN; // Get row lines
/* Set original port directions */
COLPORT = 0xFF; // Drive all column lines high
ROWPORT = 0x00; // Disable pull-up on row lines
COLDIR = 0x00; // Set column lines to input, already pulled up
ROWDIR = 0xFF; // Set row lines to output, alreay driven low
if( lineResult != 0xFF ) // Any row lines low ?
{
while( lineResult & 0x01 ) // Loop while row line high
{
lineResult >>= 1; // Next row line into LSB
tempScan += 8; // Increment row part of scancode
}
/* Process scancode */
key_code.scan = tempScan; // Save scancode
key_code.updated = 1; // Set update flag
#ifdef ALTKEYS
key_processAltKeys(); // Process alternation keys if implemented
#endif
} else
{
key_code.scan = 0xFF; // Indicate no keys pressed
}
} else
{
key_code.scan = 0xFF; // Indicate no keys pressed
}
/* Prepare pin change interrupt */
ENABLE_PCINT; // Reenable pin change interrupt
GIFR |= PCIF1; // Clear interrupt status flag
SELECT_POWERDOWN; // Use power down sleep mode
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -