RSS

External Interrupts on the STM8S

In a previous post we looked at the GPIO pins and how we could set the pins to either input or output but we concentrated on output. In this post we will look at using interrupts to detect input from the user and an output to indicate that the input has been detected. Our objective is:

  1. Create a circuit which can register when a button has been pressed.
  2. Toggle a LED when the button is pressed

Should be simple, so let’s give it a go.

Hardware

For the hardware we will need three components:

  1. STM8S Circuit
  2. Switch
  3. LED

STM8S Circuit

For the STM8S we need the STM8S103F3 connected to 3.3V and ground. We will also need to add two ceramic capacitors, a 100nF between Vss and Vdd (pins 7 and 9) and a 1uF between Vss and Vcap (pins 7 and 8).

Switch Circuit

For the switch circuit we need a switch and a pull-up resistor. We will pull the input line to the STM8S high through the pull-up resistor. Pressing the switch will pull the input line low. This part of the circuit looks like this:

This circuit will have the pin held high until the switch is pressed. All we need to do is to detect the falling edge of the input to the STM8S and we have a way to detecting when the user presses the switch.

One thing to note here is that we will be ignoring switch bounce and so we are likely to get the odd spurious message. We will come back to this later.

LED Circuit

This circuit is a simple transistor circuit which is used to switch on a LED. By applying a low current to the base of a transistor we can switch on a larger current to drive the LED. A quick simple circuit looks like this:

By setting a GPIO pin connected to the base of the transistor to high we can turn on a LED.

Putting it all together, we connect the switch to PD4 and the LED to PD3.

Software

The software is a simple extension of the previous post on GPIO pins. Here we are going to use the same port (port D) for both input and output. The full code is:

#include <intrinsics.h>
#include <iostm8s103f3.h>

//
//  Process the interrupt generated by the pressing of the button on PD4.
//
#pragma vector = 8
__interrupt void EXTI_PORTD_IRQHandler(void)
{
    PD_ODR_ODR3 = !PD_ODR_ODR3;     //  Toggle Port D, pin 3.
}

//
//  Main program loop.
//
void main()
{
    //
    //  Initialise the system.
    //
    __disable_interrupt();
    PD_ODR = 0;             //  All pins are turned off.
    PD_DDR = 0xff;          //  All pins are outputs.
    PD_CR1 = 0xff;          //  Push-Pull outputs.
    PD_CR2 = 0xff;          //  Output speeds up to 10 MHz.
    //
    //  Now configure the input pin.
    //
    PD_DDR_DDR4 = 0;        //  PD4 is input.
    PD_CR1_C14 = 0;         //  PD4 is floating input.
    //
    //  Set up the interrupt.
    //
    EXTI_CR1_PDIS = 2;      //  Interrupt on falling edge.
    EXTI_CR2_TLIS = 0;      //  Falling edge only.
    __enable_interrupt();

    while (1)
    {
        __wait_for_interrupt();
    }
}

So let’s start and break the program down. The first thing you will notice is that we initially configure all of the pins on port D as outputs as we have previously seen:

PD_ODR = 0;             //  All pins are turned off.
PD_DDR = 0xff;          //  All pins are outputs.
PD_CR1 = 0xff;          //  Push-Pull outputs.
PD_CR2 = 0xff;          //  Output speeds up to 10 MHz.

The next thing we do is to set up the system to allow PD4 as an input pin:

PD_DDR_DDR4 = 0;        //  PD4 is input.
PD_CR1_C14 = 0;         //  PD4 is floating input.

The final step of the configuration is to set the external interrupt for the port to detect the falling edge of the signal:

EXTI_CR1_PDIS = 2;      //  Interrupt on falling edge.
EXTI_CR2_TLIS = 0;      //  Falling edge only.

The final part of the main program is to wait for an interrupt. This is repeated infinitely:

while (1)
{
    __wait_for_interrupt();
}

The interesting part of the problem is the interrupt routine as this is where the real work is actually done. The code is simple enough you just have to make sure that you declare the method correctly:

#pragma vector = 8
__interrupt void EXTI_PORTD_IRQHandler(void)
{
    PD_ODR_ODR3 = !PD_ODR_ODR3;     //  Toggle Port D, pin 3.
}

The first two lines declare the method as an Interrupt Service Routine (ISR). The #pragma vector = 8 tells the compiler which interrupt this method will be servicing. In this case, this method will be called to process the interrupts for Port D. We will look into ISRs a little more in a later post.

Putting it all Together

If we wire all of the hardware together on a breadboard we end up with something like the following:

and a quick video of it working:

Switch Bounce

As noted earlier, mechanical switches are susceptible to switch bounce. This is caused by the mechanical contacts not closing perfectly when the switch is pressed. You can notice an example of bounce in the above video. When the switch is pressed the second time you can see that the LED is switched off but it is then switched on straight away. This is the effect of the switch contacts causing multiple signals. If a scope is hooked up to a switch you see something like the following:

In this case the switch is held down and then released. Notice the spike; this is caused by the switch bounce. If the signal is large enough then the microcontroller will think that the switch has been pressed twice rather than once – in fact that is what happened in the above video. There are a few ways to solve this but I’ll leave that as an exercise to the reader.

You can find the full source for the above project here. This application has been tested on tmy reference platform, the Variable Labs Protomodule and the STM8S Discovery board.

Compatibility

System Compatible?
STM8S103F3 (Breadboard)
Variable Lab Protomodule
STM8S Discovery

Tags: , , , ,

Thursday, August 16th, 2012 at 8:36 pm • Electronics, STM8RSS 2.0 feed Both comments and pings are currently closed.

Comments are closed.