| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113 |
- The Switch, callbacks and interrupts
- ====================================
- The pyboard has 2 small switches, labelled USR and RST. The RST switch
- is a hard-reset switch, and if you press it then it restarts the pyboard
- from scratch, equivalent to turning the power off then back on.
- The USR switch is for general use, and is controlled via a Switch object.
- To make a switch object do::
- >>> sw = pyb.Switch()
- Remember that you may need to type ``import pyb`` if you get an error that
- the name ``pyb`` does not exist.
- With the switch object you can get its status::
- >>> sw.value()
- False
- This will print ``False`` if the switch is not held, or ``True`` if it is held.
- Try holding the USR switch down while running the above command.
- There is also a shorthand notation to get the switch status, by "calling" the
- switch object::
- >>> sw()
- False
- Switch callbacks
- ----------------
- The switch is a very simple object, but it does have one advanced feature:
- the ``sw.callback()`` function. The callback function sets up something to
- run when the switch is pressed, and uses an interrupt. It's probably best
- to start with an example before understanding how interrupts work. Try
- running the following at the prompt::
- >>> sw.callback(lambda:print('press!'))
- This tells the switch to print ``press!`` each time the switch is pressed
- down. Go ahead and try it: press the USR switch and watch the output on
- your PC. Note that this print will interrupt anything you are typing, and
- is an example of an interrupt routine running asynchronously.
- As another example try::
- >>> sw.callback(lambda:pyb.LED(1).toggle())
- This will toggle the red LED each time the switch is pressed. And it will
- even work while other code is running.
- To disable the switch callback, pass ``None`` to the callback function::
- >>> sw.callback(None)
- You can pass any function (that takes zero arguments) to the switch callback.
- Above we used the ``lambda`` feature of Python to create an anonymous function
- on the fly. But we could equally do::
- >>> def f():
- ... pyb.LED(1).toggle()
- ...
- >>> sw.callback(f)
- This creates a function called ``f`` and assigns it to the switch callback.
- You can do things this way when your function is more complicated than a
- ``lambda`` will allow.
- Note that your callback functions must not allocate any memory (for example
- they cannot create a tuple or list). Callback functions should be relatively
- simple. If you need to make a list, make it beforehand and store it in a
- global variable (or make it local and close over it). If you need to do
- a long, complicated calculation, then use the callback to set a flag which
- some other code then responds to.
- Technical details of interrupts
- -------------------------------
- Let's step through the details of what is happening with the switch
- callback. When you register a function with ``sw.callback()``, the switch
- sets up an external interrupt trigger (falling edge) on the pin that the
- switch is connected to. This means that the microcontroller will listen
- on the pin for any changes, and the following will occur:
- 1. When the switch is pressed a change occurs on the pin (the pin goes
- from low to high), and the microcontroller registers this change.
- 2. The microcontroller finishes executing the current machine instruction,
- stops execution, and saves its current state (pushes the registers on
- the stack). This has the effect of pausing any code, for example your
- running Python script.
- 3. The microcontroller starts executing the special interrupt handler
- associated with the switch's external trigger. This interrupt handler
- get the function that you registered with ``sw.callback()`` and executes
- it.
- 4. Your callback function is executed until it finishes, returning control
- to the switch interrupt handler.
- 5. The switch interrupt handler returns, and the microcontroller is
- notified that the interrupt has been dealt with.
- 6. The microcontroller restores the state that it saved in step 2.
- 7. Execution continues of the code that was running at the beginning. Apart
- from the pause, this code does not notice that it was interrupted.
- The above sequence of events gets a bit more complicated when multiple
- interrupts occur at the same time. In that case, the interrupt with the
- highest priority goes first, then the others in order of their priority.
- The switch interrupt is set at the lowest priority.
- Further reading
- ---------------
- For further information about using hardware interrupts see
- :ref:`writing interrupt handlers <isr_rules>`.
|