Execute a hardware interrupt

published: 5 June 2019 / updated 26 June 2019

Lire cette page en français

 


Preamble

We have already discussed an interesting example with a traffic light: ARDUINO ports: manage a trafic light.

To be complete, the traffic lights can also be a pedestrian crossing. Such a passage two ways of working:

But we managed our traffic light program through a permanent loop with timers. The worry, with these timers, is one pedestrian asked the fire green during one of these delays, its request will be ignored, except to remain supported long enough for the fire management cycle detected this button support.

The elegant solution, without going through several tasks, is to manage this button through an interruption.

The principle of an interruption is a process independent of the main program. In our example, our flag, like true ATTENTE-PIETON !. Then load the traffic lights management loop to take into account this request and treat it.

In the rest of this article, we will not go back to the management of traffic lights, but simply show how - in FORTH language - we manage a push button by interruption.

ARDUINO board interrupts

On the ARDUINO boards, a certain number of pins can be used in interrupts. Enabling or disabling these pins can trigger independent actions a main loop.

With Flash FORTH, you can execute a word in particular. For our case, here it will be the support of a button that will trigger an action.

Here is the diagram of our assembly:

Mounting an interrupted button

Button management on pin 19

Caution: do not confuse physical connector numbers and pin numbers

On the ARDUINO cards, the physical connectors are marked, some by numbers, others by their function, example: GND, TX, RX, 5V, etc ...

The mapping for associating pin numbers with physical connectors is in this document:
 Pin out map on ARDUINO DUE
 Pin out map on ARDUINO MEGA 2560
 Pin out map on ARDUINO MICRO
 Pin out map on ARDUINO NANO
 Pin out map on ARDUINO UNO
 Pin out map on ARDUINO YUN

For example, the led '13' which is connected to the ARDUINO MEGA board with the physical terminal 13 is related to the PIN 26. In all our texts, the term "pin" will always refer to PIN code XX as referenced in the technical documents of ARDUINO cards. The mention of a physical connector will be done with the term 'terminal'. Example:

  PIN 19 (terminal 53) (penultimate terminal, all at the bottom, left on an ARDUINO MEGA 2560 board)

To learn more about how to program the connectors of the different ARDUINO boards:
Understanding ARDUINO card connectors

The button connected to pin 19 (terminal 53) is managed by PORT B:

37 constant PORTB    \ définition registre PORT du port B
36 constant DDRB     \ définition registre DDR  du port B
35 constant PINB     \ définition registre PIN  du port B

The position of this bread in the PORTB register is the least significant bit:

%00000001 constant pin19   \ masque  pin 19

The word pin19? retrieves the state of this button:

: pin19? ( --- fl)
    PINB c@          \ empile contenu registre PIN du port B
    pin19 and        \ ET logique avec masque PIN12
    0=               \ si nul
    if      false    \ empile FALSE
    else    true     \ empile TRUE
    then ;

Finally, we initialize PORT B:

: init-ddrb ( ---)   \ initialise PORTB en entrée sur tous les bits
    $00 DDRB c!      \ active pins en entrée sur PORT B
  ;

Here's how to test if the button is connected:

init-ddrb  ok<#,ram>
pin19?  ok<#,ram> 0
pin19?  ok<#,ram> 0 65535

This is the copy of the test run: init-ddrb initializes the PORTB. pin19? without pressing the button stacks 0 (false). pin19? with pushbutton button stacks 65535 (true).

Management of the LED on the pin 60 (PC7)

We define the registers of PORT C:

\ PORTC
40 constant PORTC	\ Port C Data Register
39 constant DDRC	\ Port C Data Direction Register
38 constant PINC	\ Port C Input Pins

Then, the position of the pin 60 in the PORTB is determined:

%10000000 constant pin60      \ masque binaire du PIN60 (PC7)

We create the word init-ddrc which will indicate the pin 60 in output:

: init-ddrc ( ---)
    pin60 DDRC mset       \ active pins en sortie sur PORT C
  ;

And finally the words to turn on, turn off and know the state of the LED connected to pin 60:

: pin60on ( ---)
    pin60 PORTC mset
    ;
: pin60off ( ---)
    pin60 PORTC mclr
    ;
: pin60? ( --- fl)      \ récupère état LED connectée au pin 30
    pin60 PORTC mtst
    ;

We test these three new words:

init-ddrc  ok<#,ram>
pin60on  ok<#,ram>  
pin60?  ok<#,ram> 65535
pin60off  ok<#,ram>
pin60?  ok<#,ram> 65535 0

If everything went well, the LED on pin 60 turned on and off.

Bouton géré par interruption

Choice of interruption

According to the ARDUINO card, we have a number of hardware interrupts. For the MEGA2560 R3 card, list of interrupts sayPCINT (P in C change INTerrupt)
  PCINT0 on pin 19 (physical connector 53)
  PCINT1 on pin 20 (physical connector 52)
  PCINT2 on pin 21 (physical connector 51)
  PCINT3 on pin 22 (physical connector 50)
  PCINT4 on pin 23 (physical connector 10)
  PCINT5 on pin 24 (physical connector 11)
  PCINT6 on pin 25 (physical connector 12)
  PCINT7 on pin 26 (physical connector 13)

We initialize the interrupt vector:

\ ATTENTION: spécifique Mega 2560
10  constant PCINT0     \ numéro vecteur interruption 4 pour PCINT0
$6b constant PCMSK0     \ Pin Change Mask Register 0
104 constant PCICR	\ Pin Change Interrupt Control Register $68

We will now exploit this material interruption. But for her is effective, we will generate a waiting loop. This loop does not call to the word ms which generates conflicts with our interruption:

: attente ( n ---)
    for next ;

The word attente creates a small delay, thus limiting the rebound phenomenon generated by physical push buttons. We go now manage the toggle of the LED that will be lit when the button is activated, otherwise off when the button is released:

: toggleLED ( ---)
    di                  \ désactivation interruptions
    10000 attente
    pin19?              \ récupère état bouton poussoir
    if                  \ si enfoncé, on bascule état LED
        pin60?
        if      pin60off \ si allumée, éteint LED
        else    pin60on  \ si éteinte, allume LED
        then  
    then
    ei                  \ réactivation interruption
;i
 
: int-enable
    ['] toggleLED PCINT0 int!
    ei                  \ ei = Enable Interrupt
;
int-enable
%00000001 PCMSK0 mset
%00000111 PCICR  mset
 
init-ddrb
init-ddrc

We do not need to run toggleLED. Just pressing the push button turns the LED on or off.

Note that the definition of toggleLED ends with the word ;i. Any word definition handled by an interrupt must end with ;i on pain of crashing FORTH.

The interrupt vectors are stored in ram. The interrupt vectors in ram are cleared at warm start, so to enable the interrupt int-enable at startup, a initialization word must be used:

' int-enable is turnkey 

Thus, by powering down and restarting the ARDUINO board, the interrupt will be reactivated and operational.