Autokey
This module demonstrates the use of a very simple to use but powerful module called ISRTimer. What I did was copy the code from the Keypad module and added a bit of my own. The result as a very simple system to automatically scan the keyboard every 20hz and then provide key latching. Key latching is a term I use to say you can set a key as been seen and you will not be notified until that key is released and pressed again. A typical example being in a menu system where you would normally have to put a big delay in to prevent the menu going through every option before you can blink.
With the key latch in place and the fact you have a 20hz tick you can add an auto repeat function in as all the module has to do is flag the key again as being a fresh key press.
At the bottom is the module and above are 2 examples of it being used.
In this first example we just have a simple autorepeat
Include "usart.bas" Include "AutoKey.bas" Include "convert.bas" Dim temp As Byte Dim counter As Byte Dim counter2 As Byte SetBaudrate(br19200) ' program start... counter = 5 counter2 = 10 AutoRepeatPeriod(counter2) While 1 = 1 If AutoKey.IsNewKey = true Then // Has there been a new key pressed? temp = AutoKey.Value() // Yes so get that Key AutoKey.KeyLatched() // Seen the key so latch it as seen until is Pressed // another key or it auto Repeats USART.Write(DecToStr(temp)) // Convert the no to asscii and write the value out EndIf DelayMS(100) Wend
In this example we show how altering the auto-repeat period we can decrease the delay between auto-repeats
Include "usart.bas" Include "AutoKey.bas" Include "convert.bas" Dim temp As Byte Dim counter As Byte Dim counter2 As Byte SetBaudrate(br19200) ' program start... counter = 5 counter2 = 10 AutoRepeatPeriod(counter2) While 1 = 1 If AutoKey.IsNewKey = true Then // Has there been a new key pressed? temp = AutoKey.Value() // Yes so get that Key AutoKey.KeyLatched() // Seen the key so latch USART.Write(temp + 48) Toggle (PORTD.0) If counter > 0 Then // Now count the number of times a Dec (counter) // new key is seen so we can Else If counter2 > 0 Then Dec (counter2) AutoRepeatPeriod(counter2) // Reduce the auto repeat period USART.Write("S") // Just a note to let me know I have EndIf // reduced the Auto Repeat period counter = 5 EndIf EndIf DelayMS(100) Wend
Finally the module don't forget to save it in the "UserLibrary" folder for safe keeping!
Module AutoKey Include "ISRTimer.bas" // validate data port... #option KEYPAD_PORT = PORTB #if IsOption(KEYPAD_PORT) #if Not IsValidPort(KEYPAD_PORT) #error KEYPAD_PORT, "Invalid option. Keypad must be connected to a valid port name." #endif #option _KEYPAD_PORT_TRIS = GetTRIS(KEYPAD_PORT) #endif // bring PORT and TRIS options into the module Dim FKeyPort As KEYPAD_PORT, FKeyPortTris As _KEYPAD_PORT_TRIS // private variables and aliases... #if KEYPAD_PORT in (PORTB) Dim FPullupsDisabled As INTCON2.Booleans(7), // weak pullups FInterruptFlag As INTCON.Booleans(0), // PORTB interrupt flag FInterruptEnable As INTCON.Booleans(3) // PORTB interrupt enable #endif { **************************************************************************** * Name : EnablePullups (PRIVATE) * * Purpose : Enables MCU weak pullups * **************************************************************************** } Inline Sub EnablePullups() #if KEYPAD_PORT in (PORTB) FPullupsDisabled = false #endif End Sub { **************************************************************************** * Name : Value * * Purpose : Reads and returns the key pressed on a keypad matrix * **************************************************************************** } Function KeyValue() As Byte Const NumberOfRows = 4 Dim RowIndex As Byte EnablePullups // enable weak pullups FKeyPortTris = $F0 // Make the columns bits inputs FKeyPort = 0 // Send row lines low Result = 0 If FKeyPort < $F0 Then RowIndex = NumberOfRows FKeyPort = %11111110 Repeat Inc(Result) // column 1... If FKeyPort.4 = 0 Then Break EndIf Inc(Result) // column 2... If FKeyPort.5 = 0 Then Break EndIf Inc(Result) // column 3... If FKeyPort.6 = 0 Then Break EndIf Inc(Result) // column 4... If FKeyPort.7 = 0 Then Break EndIf // rotate mask... FKeyPort = FKeyPort << 1 FKeyPort.0 = 1 Dec(RowIndex) Until RowIndex = 0 EndIf End Function Public Dim CurrentKey As Byte Public Dim IsNewKey As Boolean Public Dim AutoRepeateActive As Boolean Public Dim AutoRepeatTmrValue As Byte Public Dim AutoRepeatTmr As Byte Public Dim DebounceTmr As Byte Public Dim DebounceTimeValue As Byte Public Dim Lastkey As Byte // OnTimer event... Event OnKeyPadRead() CurrentKey = KeyValue If CurrentKey <> 0 Then If CurrentKey = Lastkey Then If AutoRepeateActive = true Then If AutoRepeatTmr > 0 Then Dec (AutoRepeatTmr) Else IsNewKey = true AutoRepeatTmr = AutoRepeatTmrValue EndIf EndIf Else IsNewKey = true Lastkey = CurrentKey EndIf Else If DebounceTmr > 0 Then Dec (DebounceTmr) Else DebounceTmr = DebounceTimeValue Lastkey = 0 AutoRepeatTmr = AutoRepeatTmrValue EndIf EndIf End Event { **************************************************************************** * Name : Value * * Purpose : Returns the current key being Pressed * **************************************************************************** } Public Inline Function Value() As Byte result = CurrentKey End Function { **************************************************************************** * Name : DebounceTime * * Purpose : Sets the number of times it sees the key at 0 before * * it accepts it as 0 to debounce the key * **************************************************************************** } Public Sub DebounceTime(ByVal Pvalue As Byte) DebounceTimeValue = Pvalue DebounceTmr = Pvalue End Sub { **************************************************************************** * Name : AutoRepeatPeriod * * Purpose : Sets the number of times it sees the same key in sucssesion * * before it notifies by resetting the new IsNewKey flag * **************************************************************************** } Public Sub AutoRepeatPeriod(ByRef Pvalue As Byte) AutoRepeatTmrValue = Pvalue AutoRepeatTmr = Pvalue End Sub { **************************************************************************** * Name : KeyLatched * * Purpose : Clears the IsNewKey flag so you will only be notifed when the * * key changes (or auto repeates) * **************************************************************************** } Public Inline Sub KeyLatched() IsNewKey = false End Sub { **************************************************************************** * Name : EnableAutoRepeate * * Purpose : Enables the autorepeat function * **************************************************************************** } Public Inline Sub EnableAutoRepeate () AutoRepeateActive = true End Sub { **************************************************************************** * Name : DisableAutoRepeat * * Purpose : Disables the autorepeat function * **************************************************************************** } Public Inline Sub DisableAutoRepeat () AutoRepeateActive = False End Sub AutoRepeatTmrValue = 10 IsNewKey = True AutoRepeateActive = true Lastkey = 0 KeyLatched() Timer.Initialize Timer.Items(0).Interval =50 // Scanned at 20hz Timer.Items(0).OnTimer = @OnKeyPadRead // timer event handler Timer.Items(0).Enabled = true Timer.Start End