⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 keymatrix.c

📁 一个按件扫描程序
💻 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 + -