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

📄 keypad.c

📁 LV24000的单片机DEMO程序
💻 C
📖 第 1 页 / 共 2 页
字号:
//-----------------------------------------------------------------------------
//   File:      Keypad.c
//   Contents:  Process keypad-key
//
//   Copyright (c) 2004 ItoM Semiconductor. All rights reserved
//-----------------------------------------------------------------------------
#include <stdio.h>
#include "common.h"
#include "Lv24Ekit.h"
#include "KeypadDef.h"
#include "LcdDef.h"

//-----------------------------------------------------------------------------
// Key function table for the keypad dispatcher
//-----------------------------------------------------------------------------
// Menu ID
//#define MNU_SCAN	0
#define MNU_MANUAL	1
//#define MNU_RSETTING1	2
//#define MNU_RSETTING2	3
KPMENU_FUNC _rom g_KpMenuTable[] = 
{
	KpMenu0,	// 0 - Preset and scanning
	KpMenu1,	// 1 - Manual input
	KpMenu2,	// 2 - Radio settings
	KpMenu3,	// 3 - Radio settings
};
#define KP_MENU_CNT (sizeof(g_KpMenuTable)/sizeof(g_KpMenuTable[0]))

char * _rom g_MenuName[]=
{
	//0123456789012345
	 "Preset & Scan   ",	// Menu 0
	 "Manual          ",	// Menu 1
	 "Settings 1      ",	// Menu 2
	 "Settings 2      ",	// Menu 3
};

//-----------------------------------------------------------------------------
// Feature strings for displaying
//-----------------------------------------------------------------------------
#ifdef USE_LCD
char * _rom g_szValOnOff[] = 
{
	"Off",	// 0
	"On",	// 1
};
char * _rom g_szValStereo[] = 
{
	"Mono",		// 0
	"Stereo",	// 1
};
char * _rom g_szValRadioBand[] = 
{
	"Off",	// 0
	"FM",	// 1
	"AM",	// 2
};

char * _rom g_szRegion[]=
{
	"None",		// 0
	"Europe",  	// 1
	"Japan",	// 2
	"USA",		// 3
	"JapanW",	// 4
};

char * _rom g_szWrapOption[]=
{
	"None",		// 0
	"Once",		// 1
	"Cont.",	// 2
};

#ifdef USE_EXTCLK
char * _rom g_szExtClock[]=
{
	" None",	// 0
	" 12MHz",	// 1
	" 32kHz",	// 2
};
#endif //USE_EXTCLK

#endif //USE_LCD

// ---- Feature value type
#define FV_NUMBER_WRAP		((BYTE)0)	// Numberic value (Wrapping low/high limit allowed)
#define FV_NUMBER_NOWRAP	((BYTE)1)	// Numberic value (Wrapping low/high limit not allowed)
#define FV_ON_OFF		((BYTE)2)	// On/Off value (wrapping allowed)
#define FV_STEREO		((BYTE)3)	// Stereo/Mono specific
#define FV_RBAND		((BYTE)4)	// Off, FM, AM
#define FV_BFREQ		((BYTE)5)	// Buzzer frequency specific
#define FV_REGION		((BYTE)6)	// Radio region specific
#define FV_FWRAP_OPTION		((BYTE)7)	// "None", "Once", "Cont."
#define FV_EXTCLK		((BYTE)8)	// "None", "12MHz", "32MHz"
// ---- Feature data for display purposes
typedef struct
{
	BYTE byFeatureId;	// Feature ID
	char *szName;		// Feature name
	BYTE byValType;		// Value type
} LV_FEAT_DISP_DATA;

LV_FEAT_DISP_DATA _rom g_Lv24FeatName[] = 
{
				//0123456789012345
	IHCAP_TUNERPWR,		 "Power",	FV_ON_OFF,
	IHCAP_VOLUME,		 "Volume",	FV_NUMBER_NOWRAP,
	IHCAP_AMUTE,		 "Mute",	FV_ON_OFF,
	IHCAP_ATREBLE,		 "Treble",	FV_NUMBER_NOWRAP,
	IHCAP_ABASS,		 "Bass",	FV_NUMBER_NOWRAP,
	IHCAP_DYNBASSBOOST,	 "DBB",		FV_NUMBER_WRAP,
	IHCAP_SMUTE,		 "S-mute",	FV_NUMBER_WRAP,

	IHCAP_STEREO,		 "Stereo",	FV_STEREO,
	IHCAP_SOFT_ST,		 "S-stereo",	FV_NUMBER_WRAP,

	IHCAP_RADIOSOURCE,	 "Radio", 	FV_RBAND,	// Radio source: 0=Radio off, 1=FM, 2=AM
	IHCAP_EXTSOURCE,	 "Ext src", 	FV_ON_OFF, 	// External source: 0=off, 1=on
	IHCAP_BEEPSOURCE,	 "Buzzer", 	FV_BFREQ,	// Beep tone: 0=off, 1=Freq1, 2=Freq2, 3=Freq3
	//IHCAP_AFC	       	 1,		FV_ON_OFF,	// AFC (automatic frequency control)
	IHCAP_HPA,		 "Headphone",	FV_ON_OFF,	// Headphone amplifier

	IHCAP_SCANLVL,		 "Scan level",	FV_NUMBER_WRAP,
	IHCAP_SCANWRP,		 "Scan wrap",   FV_FWRAP_OPTION,
	IHCAP_REGION,		 "Region",	FV_REGION,
	IHCAP_BEEPVOL,		 "Beep Vol.",	FV_NUMBER_NOWRAP,
#ifdef USE_EXTCLK
	IHCAP_EXTCLK,		 "Ext. Clock",  FV_EXTCLK,	// 0=no external clock, 1=12MHz, 2=32kHz
#endif //USE_EXTCLK
};
#define LV_FEATNAME_LSIZE (sizeof(g_Lv24FeatName)/sizeof(g_Lv24FeatName[0]))

//-----------------------------------------------------------------------------
// Key code translation table (Convert scan code to numeric key)
// ( Index in the table is the numeric value of the key)
//-----------------------------------------------------------------------------
BYTE _rom g_KpNumeric[]=
{
	KP_0,		// index 0
	KP_1,		// index 1
	KP_2,		// index 2
	KP_3,		// index 3
	KP_4,		// index 4
	KP_5,		// index 5
	KP_6,		// index 6
	KP_7,		// index 7
	KP_8,		// index 8
	KP_9,		// index 9
	//KP_DOWN	
	//KP_LEFT	
	//KP_RIGHT	
	//KP_UP		
	//KP_S		
	//KP_H		
	//KP_NO_KEY,	// End of table
};
#define KP_NUMTAB_CNT (sizeof(g_KpNumeric)/sizeof(g_KpNumeric[0]))

// Conversion numeric to feature ID (Radio settings 1 menu)
BYTE _rom g_NumToFeat_A[10]=
{
	IHCAP_TUNERPWR,		// Key 0
	IHCAP_ATREBLE,		// Key 1
	IHCAP_ABASS,		// Key 2
	IHCAP_DYNBASSBOOST,	// Key 3
	IHCAP_SMUTE,		// Key 4
	IHCAP_STEREO,		// Key 5
	IHCAP_SOFT_ST,		// Key 6
	IHCAP_RADIOSOURCE,	// Key 7
	IHCAP_EXTSOURCE,	// Key 8
	IHCAP_HPA,		// Key 9
};

// Conversion numeric to feature ID (Radio settings 2 menu)
BYTE _rom g_NumToFeat_B[]=
{
	IHCAP_SCANLVL,		// Key 0: Scan level
	IHCAP_SCANWRP,		// Key 1: scan wrapping
	IHCAP_REGION,		// Key 2: Region
	IHCAP_BEEPVOL,		// Key 3: Beep volume
#ifdef USE_EXTCLK
	IHCAP_EXTCLK,		// Key 4: External clock
#endif //USE_EXTCLK
	// Key 5...9: reserved
};
#define KP_FEATB_CNT (sizeof(g_NumToFeat_B)/sizeof(g_NumToFeat_B[0]))

//-----------------------------------------------------------------------------
// Keypad Irq (to be called by interrupt handler)
//-----------------------------------------------------------------------------
void KeypadIrq(BYTE byRow)
{
	BYTE byCol;
	BYTE byTmp;

	// Disable keypad interrupt (also clear interrupt)
	_I01CR &= (BYTE)(~0x33);	// INT0/INT1
	_I23CR &= (BYTE)(~0x33);	// INT2/INT3

	// Avoid key bouncing
	byTmp=0;
	byCol = (KB_ROW_PORT & KB_ROW_MASK);
	do
	{
		if ( byCol != (KB_ROW_PORT & KB_ROW_MASK) )
		{
			byCol = (KB_ROW_PORT & KB_ROW_MASK);
			byTmp=0;
		}
		else
			byTmp++;
	} while (byTmp<15);

	// Start key scan - clear current key code
	g_byPressedKey = KP_NO_KEY;

	// Determine how the interrupt was enabled:
	//	- Falling edge: a key is pressed (perform key scan)
	//	- Rising edge: a key is released (No key scan)
	if (  (_I01CR & 0xCC)==0x00 ) // INT0/1 were enabled for falling edge
	{
		if ( (KB_ROW_PORT & KB_ROW_MASK) != KB_ROW_MASK)	// If a key is pressed
		{
			// Scan for column
			byTmp = KB_COLUMN_PORT & LCD_CTRLPIN_MASK; 	// Fetch current value of column port (don't destroy LCD control pin state)
			for (byCol=KB_COL_0;  byCol<=KB_COL_3; byCol++)
			{
				// Write mask to drive the scan-column high - behold the LCD control setting
				KB_COLUMN_PORT = (KB_COL_MASK_0<<byCol)| byTmp;

				// Check if this is the column of the pressed key
				if ( (KB_ROW_PORT & KB_ROW_MASK) == KB_ROW_MASK)
				{
					g_byPressedKey = byRow | byCol;
					break;
				}
			}
			// Scanning done. Make sure that all keypad columns are low (for next interrupt)
			KB_COLUMN_PORT = byTmp;
		}
	}

	// Re-arm the keypad interrupt: when a key is pressed, re-arm it for rising edge (key released)
	// When no key is pressed, arm it for falling edge (accept new key)
	if (g_byPressedKey != KP_NO_KEY)
	{
	 	// Enable for rising edge (also clear interrupt flag)
	 	_I01CR = 0x99;	// INT0/INT1: rising edge - interrupt enabled
	 	_I23CR = 0x99;	// INT2/INT3: rising edge - interrupt enabled
	}
	else
	{
		// Enable for falling edge (also clear interrupt flag)
		_I01CR = 0x11;	// INT0/INT1: falling edge - interrupt enabled
		_I23CR = 0x55;	// INT2/INT3: falling edge - interrupt enabled
	}
} // End KeyPadIrq

//-----------------------------------------------------------------------------
// Keypad menu displatcher
//	Input:  keypad code
//  	Output: Status
//-----------------------------------------------------------------------------
BYTE ProcessKey(BYTE byKey)
{
	BYTE byTmp;

	// Detect long key
	byTmp = 0;
	while ( (KB_ROW_PORT & KB_ROW_MASK) != KB_ROW_MASK) // wait key released
	{
		DelayUs(DLT_5ms);
		byTmp++;
		if (byTmp>100)
		{
			byKey|=KP_LONG;
			break;
		}
	}

	// Inform user (Feedback)
	if (byKey & KP_LONG)
		AudioFeedback(AUDFB_TYPE2);
	else
		AudioFeedback(AUDFB_TYPE1);

#ifdef PCB_L2
	// Wait key released
	while ( (KB_ROW_PORT & KB_ROW_MASK) != KB_ROW_MASK); 

	// Enable keypad interrupt before processing key
	_I01CR = 0x11;	// INT0/INT1: falling edge - interrupt enabled
	_I23CR = 0x55;	// INT2/INT3: falling edge - interrupt enabled
#endif //PCB_L2

	// Process menu keys
	switch (byKey)
	{
	case KP_UP:		// Arrow up: increase volume
	case KP_DOWN:		// Arrow down: decrease volume
		if ( byKey == KP_UP )
			AdjustHwFeature(IHCAP_VOLUME, 0x01);		// Increase volume
		else
			AdjustHwFeature(IHCAP_VOLUME, 0xFF);		// Decrease volume
		break;

	case (KP_UP|KP_LONG):	// Arrow up (long): toggle stereo state
		AdjustHwFeature(IHCAP_STEREO, 0x01);
		break;

	case (KP_DOWN|KP_LONG): // Arrow down (long): toggle audio mute
		AdjustHwFeature(IHCAP_AMUTE, 0x01);
		break;

	case (KP_S|KP_LONG):	// '*' long: return to menu 0
		g_byMenu = 0;
	#ifdef USE_LCD
		InitKeypadMenu();
	#endif //USE_LCD
		break;

	case KP_S:		// '*' key: change menu
		g_byMenu++;
		if (g_byMenu>=KP_MENU_CNT)
			g_byMenu = 0;
	#ifdef USE_LCD
		InitKeypadMenu();
	#endif //USE_LCD
		break;

	default:
		if (g_byMenu < KP_MENU_CNT)
			byTmp = g_KpMenuTable[g_byMenu](byKey);
		else
			byTmp = LVLS_INV_KPMENU_ERR;
		break;
	} // EndSwitch

	return(byTmp);
} // End ProcessKey

BYTE GetNumKeyValue(BYTE byKeyCode)
{
	BYTE i;

	for (i=0; i<KP_NUMTAB_CNT; i++)
	{
		if (byKeyCode == g_KpNumeric[i] )
			return(i);
	}
	return(KP_NO_KEY);
} // End GetNumKeyValue

//-----------------------------------------------------------------------------
// Keypad menu 0: preset and scan
//-----------------------------------------------------------------------------
BYTE KpMenu0(BYTE byKey)
{
	BYTE byTmp;

#ifdef USE_PRESET
	// Check Numberic keys
	byTmp = GetNumKeyValue(byKey & (BYTE)(~KP_LONG));
	if (byTmp != KP_NO_KEY)	// A numberic key is pressed
	{
		g_byCurPreset = ((BYTE)(g_byCurPreset/10))*10 + byTmp; // patch new key to current preset
		if (byKey & KP_LONG)
		{
			// Long key -> Store preset
			KpPresetHandling(TRUE);
		}
		else
		{
			// Short key -> Recall preset
			KpPresetHandling(FALSE);
		}
		return(LVLS_NO_ERROR);
	}
#endif //USE_PRESET

	// Other keys
	switch (byKey)
	{
	case KP_H:	// Shift preset location with 10 - Changing AM/FM
	#ifdef USE_PRESET
		g_byCurPreset += 10;
		byTmp = RBAND_OFF;	// Default radio band
		if (g_byCurPreset >= PRESET_CNT)
		{
			g_byCurPreset %= 10;	// Wrap to 0x

			// Switching AM/FM when hardware support AM
			if ( GetHwFeatureLimit(IHCAP_RADIOSOURCE) >= RBAND_AM)
			{
				if (GetHwFeatureValue(IHCAP_RADIOSOURCE) == RBAND_AM)
					byTmp = RBAND_FM;	// Assign to off to indicate changing band is required (switch to FM)
				else
					byTmp = RBAND_AM;
			}
		}

		// Perform radio band switch
		if (byTmp != RBAND_OFF)	// Band switch needed
			SetHwFeatureValue(IHCAP_RADIOSOURCE, byTmp);
		byTmp = GetHwFeatureValue(IHCAP_RADIOSOURCE);	// Read back the current band

	#ifdef USE_LCD
		// Clear current status line
		ClearLcdPos(LCDPOS_STATUS, LCDLEN_STATUS);
		// Show number of station found
		PrintString(LCDPOS_ACTNAME, "Preset ");
		if (byTmp != RBAND_OFF)
			PrintString(CURS_CURPOS, g_szValRadioBand[byTmp]);
		PrintDword(LCDPOS_ACTSTAT, (DWORD)(g_byCurPreset/10)); 
		PrintString(CURS_CURPOS, "x");
	#endif //USE_LCD
	#endif //USE_PRESET
		break;

	case (KP_H|KP_LONG):		// Auto scan
	#ifdef USE_PRESET
		ClearPresetStorage();	// Clear current preset
	#ifdef USE_LCD
		ShowScanStart(SCANSTN_NEXT|SCANSTN_AUTO);
	#endif //USE_LCD
		byTmp = ScanStation(SCANSTN_NEXT|SCANSTN_AUTO);
	#ifdef USE_LCD
		if (byTmp == LVLS_RFFREQ_ENDOFBAND_ERR) // end of band reached
		{
			// Show number of station found
			PrintString(LCDPOS_ACTSTAT, "Fnd ");
			PrintDword(CURS_CURPOS, (DWORD)GetNextSavePresetLocation()); 
		}
		else	
		{
			// Other errors: show it
			ShowResult(byTmp);
		}
	#endif //USE_LCD
	#endif //USE_PRESET
		break;

	case KP_LEFT:
	case KP_RIGHT:
	#ifdef USE_PRESET
		// Scroll preset
		byTmp = GetNextSavePresetLocation();	// Determine max. preset
		if (byTmp > 0)	// Next save location is 1 higher than valid location
			byTmp--;
		if ( byKey == KP_LEFT )
		{
			g_byCurPreset--;
			if (g_byCurPreset == 0xFF) // wrap from 0 to -1
				g_byCurPreset = byTmp;	// Wrap to max
		}
		else
		{
			g_byCurPreset++;
			if ( g_byCurPreset > byTmp )	// wrap to 0
				g_byCurPreset = 0;
		}
		KpPresetHandling(FALSE);
	#endif //USE_PRESET
		break;

	case (KP_LEFT|KP_LONG):
	case (KP_RIGHT|KP_LONG):
		if ( byKey == (KP_LEFT|KP_LONG) )
			byTmp = SCANSTN_PREV;
		else
			byTmp = SCANSTN_NEXT;
	#ifdef USE_LCD
		ShowScanStart(byTmp);
	#endif //USE_LCD
		byTmp = ScanStation(byTmp);
	#ifdef USE_LCD
		ShowResult(byTmp);
	#endif //USE_LCD
		break;
	default:
		break;
	} // EndSwitch
	return(LVLS_NO_ERROR);
} // End KpMenu0

//-----------------------------------------------------------------------------
// Keypad menu 1: manual input
//	Input string format:
//		012345  -> cursor position
//		104.40 MHz (FM)
//		 1500  kHz (AM)
//-----------------------------------------------------------------------------
BYTE KpMenu1(BYTE byKey)
{
	WORD wDisplayFreq;
	BYTE byTmp, i;

	// Discard long key (We don't know long key for this menu)
	byKey &= (BYTE)(~KP_LONG);

	// Check if a numeric key is pressed
	byTmp = GetNumKeyValue(byKey);
	if (byTmp != KP_NO_KEY)
	{
	#ifdef SUPPORT_AMFM
		if ( (g_byStnFlag & STN_AM_MODE) == STN_AM_MODE )
		{
			g_byaInp[0]=0; // AM input is 4 digits - skip the 1st one
			if ( g_byInpPos <= 1)
			{
				g_byInpPos = 1;
				if (byTmp>1)	// First input must be 0 or 1 for AM
				{
					g_byaInp[1]=0;
					g_byInpPos = 2;
				}
			}
		}
		else // FM mode
		{
			// Some smart input (!)
			// The first digit can only be 0 or 1, so move to 2nd position is input >1
			if ( g_byInpPos == 0)
			{
				if (byTmp>1)
				{
					g_byaInp[0]=0;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -