On Thu, 28 Aug 1997, Bob Fehrenbach wrote: > I frequently am involved in the design of products having programmable > parameters. Up/Down keys are used to set the values. It is generally > desireable to allow the user to press and hold Up or Down and to > make the scroll rate faster, the longer the key is held. > > (method omitted) > > The problem with this approach is that, even after juggling min_period, > max_period and delta, I have never arrived at a combination that "felt > good". While I understand that this is a subjective call, I am > curious how others handle this problem and what they though of their > results. It would seem that there is a better way. I've only done this sort of up/down key action in Z8 code, but it seems to work well. I'll try to impart the essentials... First off, I use a 2ms interrupt timer to call the key (and display driver) routine. (Or use TMR0 in this case to wait on 2ms ticks and do other stuff while waiting). KEY_INT: Save previous key Read to see if a key is currently pressed If pressed: (if not pressed fall through to CLR_KEYCOUNT) Inc key-down tick count (R1 and R0 as a 16-bit counter) If current key = previous key skip CLR_KEYCOUNT -- goto INCDEC_MODE CLR_KEYCOUNT: ; ; Some info on the counter/flags: RR0 (two 8-bit registers, R0 and R1, ; which can also be addressed as a single 16-bit register for certain ; operations) does 3 things: 1) it gets counted up to 3 for initial key ; down events ( a sort of debounce feature) such that a key must be held ; down 8ms or more to actually be counted as a valid key. 2) For keys held ; down a "long time", it will count all the way around to R1=3 (256 times ; later) so an "auto key-repeat" will happen every 256 * 2ms = 0.512 sec. ; 3) The high byte (R0) tells the INC/DEC routines how many half-seconds ; have elapsed with the key held down (this is what determines when it ; switches from slow inc/dec to fast inc/dec). ; ; Oh, there is a single bit-flag used to indicate whether inc/dec is ;fast or slow. ; ; For PIC code for the counter, RR0 would have to be created in ; software, but this fairly simple. ; Clear key delay counter (high byte of RR0 = R0) Clear key down counter (low byte of RR0 = R1) Reset the 'fast/slow' inc/dec flag to 'slow' INCDEC_MODE: ; ; how big a number R1 is checked for determines how fast the auto-key ; repeat happens--voila, a fast/slow inc-dec. In this case, a slow repeat ; happens approx. every 0.5 seconds (2Hz) and a fast repeat (8 times ; faster) at every 64ms (16Hz). If 'fast/slow' flag = fast: If key down counter R1 has rolled over a modulo-32 boundary: Goto DO_KEY Else If key down counter R1=3 (initial valid key time or 256+3 slow repeat) Goto DO_KEY Goto DO_OTHER_THINGS ;meaning, done with key stuff for now, do other ;interrupt routine things, if any. DO_KEY: ; ; Here is where which key was pressed determines what action is taken ; (i.e., inc vs. dec vs. whatever). Also, the data for the key action is ; picked up. ; Get data to be inc/dec'd Look at current key code and goto appropriate action routine. DEC_VAL: ; ; Action routine example to show how slow-to-fast flag is set. ; Decrement data value at a rate of 2Hz for about 2.5 seconds, and if the ; key is still down at a rate of 16Hz. ; If in fast mode already: Goto DECREMENT Else If key delay counter R0 >= 5 ;(After five 0.5 sec repeats, go faster) Set 'fast/slow' flag = fast DECREMENT: Do actual decrement here Goto DO_OTHER_THINGS INC_VAL: SOME_OTHER_KEY: ;(other key-action routines as needed) YET_ANOTHER_KEY: . . . DO_OTHER_THINGS: . . . Return from interrupt END ***** Hope that isn't too confusing ^^;;; It leaves out things like how to pick up the correct parameter to inc/dec, but it does show the core of how I do the slow/fast key repeat action. --Scott /**/