switch + timer question

取消
显示结果 
显示  仅  | 搜索替代 
您的意思是: 
已解决

switch + timer question

跳至解决方案
2,934 次查看
irob
Contributor V

Hey everyone.  I’m about to start a new software project which requires a human UI with switches.

 

This particular UI will require two buttons.  Each button must capture a sense of “acceleration”, in that the longer the user presses the button, different stuff happens.

 

The MCU I was looking at, the JS16, only has one MTIM.  I’ve already allocated all the I/O pins, so I can’t dedicate any to input capture or output compare (the latter feature, I was under the impression could only be implemented by tying to an I?O pin).

 

My thought was to run a state machine for each switch.  When key #1 is pressed, it looks up the MTIM free running clock value as a reference point.  Then keep track of the TOFs to see just how long it was pressed.

 

Does that sound reasonable?  I’d rather to take advantage of the output compare, but can that feature be used internally instead of with a pin?

标签 (1)
0 项奖励
回复
1 解答
2,033 次查看
bigmac
Specialist III

Hello irob,

 

Another thought is that there is probably little point in executing each state machine any more frequently than every 10-20 milliseconds.  On this basis, the decrement of the timing counters can be done within these functions, rather than within the overflow ISR.

 

The ISR would need only to set a flag that would be visible within the main loop or the state machine functions, to determine that the state machine code be executed, rather than skipped.  Static local variables could now be used for the timing counters.

 

 

if (OF_flag)  {

   OF_flag = 0;

   FSM_button1();

   FSM_button2();

}

 

 

 

Regards,

Mac

 

在原帖中查看解决方案

0 项奖励
回复
11 回复数
2,033 次查看
bigmac
Specialist III

Hello irob,

 

For detection of manually actuated switch closures, where closure periods are likely to extend to "hundreds of milliseconds", and generally timing periods are not particularly critical, I would typically use a polling approach with respect to the closure timing.  This is usually consistent with the testing of other inputs required by a state machine.  Here, I would simply use an overflow interrupt associated with a TPM module, maybe 10-20 milliseconds period, and base my timing intervals on multiples of this amount.  Then, for each independent timing function required, to provide a suitable variable which would decrement within the overflow ISR, provided it is a non-zero value.

 

if (var1)  var1--;

if (var2)  var2--;

 

 

The state machine can then test for a zero value to determine the next state required for a timeout condition.  With the debounce timing built into the state machine itself, it is possible to utilize the same variable, as for the other timing intervals required.  In your case, you might possibly need only two variables, one for each pushbutton.

 

Following debounce timing, you would set the variable to correspond with the first timing threshold, and then subsequently test whether release occurred prior to timeout.  If no release, then set the variable for the next timing threshold (minus the first threshold value), and so on.

 

Regards,

Mac

 

0 项奖励
回复
2,033 次查看
irob
Contributor V

Great ideas, guys.  Thanks for the input. Bigmac, all of my human UI projects with switches have been state machine driven, so I'm more inclined to steer toward your suggestions.  Rocco, your idea sounds fairly sophisticated, but I wouldn't mind seeing your example code for reference.

 

Thanks!

0 项奖励
回复
2,034 次查看
bigmac
Specialist III

Hello irob,

 

Another thought is that there is probably little point in executing each state machine any more frequently than every 10-20 milliseconds.  On this basis, the decrement of the timing counters can be done within these functions, rather than within the overflow ISR.

 

The ISR would need only to set a flag that would be visible within the main loop or the state machine functions, to determine that the state machine code be executed, rather than skipped.  Static local variables could now be used for the timing counters.

 

 

if (OF_flag)  {

   OF_flag = 0;

   FSM_button1();

   FSM_button2();

}

 

 

 

Regards,

Mac

 

0 项奖励
回复
2,033 次查看
irob
Contributor V

bigmac, I went your direction and it's working very nicely for me.  Thanks!

0 项奖励
回复
2,033 次查看
rocco
Senior Contributor II

Sorry for the delay, but I haven't been back to the office to pack-up these files.

 

Maybe in a few hours.

0 项奖励
回复
2,033 次查看
rocco
Senior Contributor II

Here is the keypad debounce routine. The scheduler is to follow.

 

Don't hesitate to ask if anything is unclear.

0 项奖励
回复
2,033 次查看
rocco
Senior Contributor II

Here is the scheduler. It's small, but does need one byte of ram to support eight tasks.

 

Each task is just a subroutine. You put the subroutine's name in the task list, highest priority task first. Everything is built at compile-time by a couple of macros, so priorities are static.

 

You can request a task to be run with the line:

 

         QUE        SubroutineName

 

Where "SubroutineName" is the same subroutine that was put in the task list with:

 

         TASK      SubroutineName

 

Each "TASK" line will use two byte of flash for a pointer, and assign one bit of ram for a semaphore. Each "QUE" line will generate one "BSET" instruction to set the semaphore.

 

Usually, an ISR or another task would QUE the task to run in order for it to do subsequent processing. Some examples might be the serial-port ISR requesting a command-line parser to run when a <CR> has been received, or a timer-interrupt scheduling a keypad to be scanned. The keypad-scanning task might then QUE a key-processing task to run once a key-press is detected.

 

I'm sure I'm forgetting important information, so just ask . . .

0 项奖励
回复
2,033 次查看
rocco
Senior Contributor II

Hi Rob,

 

I have something that might help a little.

 

I have a module that scans two ports for button press/release (sixteen buttons). It uses an interrupt to "que" the scan "task" subroutine at some interval. I typically use 200 microseconds per scan, but sometimes piggie-back the scheduling of the scan off of some other periodic interrupt, like the ADC, to save a timer.

 

The scan task has a debounce counter that you can set. It will not register a change until the IO-input has been stable for N sample periods. It then sticks the button "events" in a queue, for another "task" to extract and process.

 

The button events are:

KeyPressed:         the key was pressed down
KeyClicked:           the key was pressed and released quickly
KeyHeld:                the key has been pressed long enough to be 'Held'
KeyRepeat:           the key has been down for an additional 1/4 second
KeyHoldEnd:         the key was 'Held', but is now released
KeyReleased:       the key was let back up

For your application, the "KeyHeld" and "KeyRepeat" code might be able to be used as is, or modified to suit your needs.

 

I know this might be more than you need, but let me know if you want to try it. I use a little pico-scheduler for my "tasks", and can include that if you would like.

0 项奖励
回复
2,033 次查看
marbomb
Contributor I

Hi Rocco,

I would like to try your code also.

 

Thanks,

 

Dan

0 项奖励
回复
2,033 次查看
rocco
Senior Contributor II

Hi Rob and Dan,

 

Yet again, I forgot to mention that the code is written in assembly language, and not C (which is why we are still using HC08/S08).

 

Let me know if you still want it, and if you do, whether you want the pico-scheduler, which is macro-based.

0 项奖励
回复
2,033 次查看
marbomb
Contributor I

Yes Rocco,

I would like both.

Thanks,

Dan

0 项奖励
回复