• PicŪ Basic

  • Debouncing 8 inputs by interrupt

    There are hundreds of ways for debouncing the readings of a mechanical sensor. The use of vertical counters has held my attention because they are very efficient and fast.
    Find the good solution depends on 3 factors:
    1 - Knowing how to choose the right mechanical sensor for each application and define correctly the parameters of use to calculate the filter components values, it is the most important.
    2 - A good filtering of these inputs in the proper connector and a good PCB design.
    3 - An efficient code for the PIC.

    I will dedicate myself only to describe a well-known code based on vertical counters. (Part-3)
    Normally I used this code inserted it in my projects and adapted it the best in each case. To write a library for all PDS users is little more complicated.
    It could be considered that the Parts 1 and 2 have been resolved and passed to Part 3, the PIC code.
    Basically the debounce routine reads all inputs at the same time (his advantage) and delivers stable values after 4 readings, i.e. this code runs as digitally low pass filter. For more details read the "Debounce Int.inc" file header.
    That takes a timer whose value is configurable by the user to suit the conditions of the rebounds.
    The interruptions period is 4ms only because it is the maximum value that can be obtained with a 64 MHz FOSC (Amicus18 board). From this value the actual reading period of the debounce code is calculated. That's why the final value of time is a multiple of 4 ms. In each period of 4 mS interrupts a counter will only increment, it is a little thing. I guess the user will find some interesting code to insert every 4 mS.

    The value of the Timer is set by the followed command.
    In this case the debounce routine is reading the inputs every 40 mS. As discussed above, the stable signal is achieved after 4 samples, ie 40 x 4 = 160mS.
    This value (40ms) depends on the study you have to do on the connected sensor.
    The Timer2 has been chosen to be standard in all PICs and is also very easy to configure. Of course every other timer could be used. The Timer2 settings have been prepared for several FOSC frequencies (4, 8, 16, 20 and 64MHz). For other FOSC frequencies add the necessary parameters in the file "DebounceInt.inc".

    Declaration of Inputs:
    There are 2 virtual PORTS used for the debounce routine, one for all hardware inputs and other for output filter.
    All inputs conected to one PORT only is the best solution for the EMC compliance.

    Case of all inputs conected in one PORT.
    The PDS user must configure 3 parameters: The PORT, the idle state of every pin of this PORT, and define the PORT to set to digital mode if necessary (of course). For example %11111111, means all bits have a pullup to VDD at idle state.

    $define InputPORT PORTB
    $define VirtualPORT_IdleState %11111111
    $define AnselPORT ANSELH

    Include "DebounceInt.inc"

    Case of inputs are conected in several PORTs.
    Choose the PORT where the most sensors are connected. (for example: 4 in pin0, pin1, pin2 and pin3 in PORTB)

    $define InputPORT PORTB
    Include "DebounceInt.inc"

    Set the idle state of these 4 pins.

    $define InputPORT PORTB
    $define VirtualPORT_IdleState %11111111

    Include "DebounceInt.inc"

    Introduce the others individual pins. (from pin 0 to pin 7)
    The Pin7 could have an idle state low, correct it in the VirtualPORT_IdleState parameter.
    All pins must to be declared to digital using the $define AnselPinx function.
    '    $define InputPin0 PORTB.0    ' Already define with PORTB
        $define AnselPin0 ANSELH.4  ' It is analog/digital pin   
    '    $define InputPin1 PORTB.1  ' Already define with PORTB
        $define AnselPin1 ANSELH.2  ' It is analog/digital pin
    '    $define InputPin2 PORTB.2  ' Already define with PORTB
        $define AnselPin2 ANSELH.0  ' It is analog/digital pin
    '    $define InputPin3 PORTB.3  ' Already define
        $define AnselPin3 ANSELH.1  ' It is analog/digital pin
        $define InputPin4 PORTA.0   ' New pin
        $define AnselPin4 ANSEL.0   ' It is analog/digital pin
        $define InputPin5 PORTC.0   ' New pin
    '    $define AnselPin5          ' It is a digital pin only
        $define InputPin6 PORTC.1   ' New pin
    '    $define AnselPin6          ' It is a digital pin only
        $define InputPin7 PORTC.2   ' New pin
    '    $define AnselPin7          ' It is a digital pin only
        $define InputPORT PORTB  
        $define VirtualPORT_IdleState %01111111
        Include "DebounceInt.inc"
    The idle state is used to define how the vertical counter has to initialize. If it would not be prepared a false response will occur when the PIC program starts.

    Declaration of the output virtual PORT:
    Now how will inputs be used by the PDS user?
    Dim SW0 As DebounceOut.0
    Dim SW1 As DebounceOut.1    
    Dim SW2 As DebounceOut.2    
    Dim SW3 As DebounceOut.3
    Dim SW4 As DebounceOut.4    
    Dim SW5 As DebounceOut.5    
    Dim SW6 As DebounceOut.6
    Dim SW7 As DebounceOut.7
    Example of use:
           If SW0 = 0 Then
                HRSOut "SW0 pressed!", CR    
            If SW1 = 0 Then
                HRSOut "SW1 pressed!", CR    
            If SW2 = 0 Then
                HRSOut "SW2 pressed!", CR    
            If SW3 = 0 Then
                HRSOut "SW3 pressed!", CR    
            If SW4 = 0 Then
                HRSOut "SW4 pressed!", CR    
            If SW5 = 0 Then
                HRSOut "SW5 pressed!", CR    
            If SW6 = 0 Then
                HRSOut "SW6 pressed!", CR    
            If SW7 = 1 Then
                HRSOut "SW7 pressed!", CR    
    Any questions could be answered in the WIKI forum.
    I hope to write something for the Part-2 and Part-1, coming soon.
    Enjoy using the debounce routine.

    23/03/2016 update Version 1.1
    I added a code to detect events, rising and falling edges of the sensors. The lines of code needed are few and worth incorporating in the interrupt handler. The user can enabled each of the options individually, and the bits to be detected must to be enabled too.

    $define RisingEdgeMask %00001111
    $define FallingEdgeMask %11110000

    $define _FallingEdgesDetect_
    $define _RisingEdgesDetect_

    Include "DebounceInt.inc"

    In the main program, the events must be deleted after being read. Thus the "Debounce" rutine can not erase the data in case the main program is running slow.
            ' The events must to be clear (bit by bit) after read by the user in the main code.
            $ifdef _FallingEdgesDetect_
            If FallingEdgeDetectedBits > 0 Then
                If FallingEdgeDetectedBits.0 = 1 Then
                    HRSOut "Falling Detect SW0", CR
                    FallingEdgeDetectedBits.0 = 0       ' Clear the bit after it is already read.
                If FallingEdgeDetectedBits.1 = 1 Then
                    HRSOut "Falling Detect SW1", CR
                    FallingEdgeDetectedBits.1 = 0
                If FallingEdgeDetectedBits.2 = 1 Then
                    HRSOut "Falling Detect SW2", CR
                    FallingEdgeDetectedBits.2 = 0
                If FallingEdgeDetectedBits.3 = 1 Then
                    HRSOut "Falling Detect SW3", CR
                    FallingEdgeDetectedBits.3 = 0
                If FallingEdgeDetectedBits.4 = 1 Then
                    HRSOut "Falling Detect SW4", CR
                    FallingEdgeDetectedBits.4 = 0
                If FallingEdgeDetectedBits.5 = 1 Then
                    HRSOut "Falling Detect SW5", CR
                    FallingEdgeDetectedBits.5 = 0
                If FallingEdgeDetectedBits.6 = 1 Then
                    HRSOut "Falling Detect SW6", CR
                    FallingEdgeDetectedBits.6 = 0
                If FallingEdgeDetectedBits.7 = 1 Then
                    HRSOut "Falling Detect SW7", CR
                    FallingEdgeDetectedBits.7 = 0
            $ifdef _RisingEdgesDetect_
            ' The events must to be clear (bit by bit) after read by the user in the main code.
            If RisingEdgeDetectedBits > 0 Then
                If RisingEdgeDetectedBits.0 = 1 Then
                    HRSOut "Rise Detect SW0", CR
                    RisingEdgeDetectedBits.0 = 0
                If RisingEdgeDetectedBits.1 = 1 Then
                    HRSOut "Rise Detect SW1", CR
                    RisingEdgeDetectedBits.1 = 0
                If RisingEdgeDetectedBits.2 = 1 Then
                    HRSOut "Rise Detect SW2", CR
                    RisingEdgeDetectedBits.2 = 0
                If RisingEdgeDetectedBits.3 = 1 Then
                    HRSOut "Rise Detect SW3", CR
                    RisingEdgeDetectedBits.3 = 0
                If RisingEdgeDetectedBits.4 = 1 Then
                    HRSOut "Rise Detect SW4", CR
                    RisingEdgeDetectedBits.4 = 0
                If RisingEdgeDetectedBits.5 = 1 Then
                    HRSOut "Rise Detect SW5", CR
                    RisingEdgeDetectedBits.5 = 0
                If RisingEdgeDetectedBits.6 = 1 Then
                    HRSOut "Rise Detect SW6", CR
                    RisingEdgeDetectedBits.6 = 0
                If RisingEdgeDetectedBits.7 = 1 Then
                    HRSOut "Rise Detect SW7", CR
                    RisingEdgeDetectedBits.7 = 0
    I guess that will make life easier for PDS users.

    Download the code HERE