📄 keypad.c
字号:
//-----------------------------------------------------------------------------
// 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 + -