Netduino home hardware projects downloads community

Jump to content


The Netduino forums have been replaced by new forums at community.wildernesslabs.co. This site has been preserved for archival purposes only and the ability to make new accounts or posts has been turned off.
Photo

OnInterrupt firing multiple times


  • Please log in to reply
6 replies to this topic

#1 Frank T

Frank T

    New Member

  • Members
  • Pip
  • 4 posts
  • LocationAtlanta, GA

Posted 17 October 2012 - 11:07 PM

I'm trying to use an LCD (16x2) to show entries from a log (really just an array of strings). The LCD is wired exactly like this: (http://geekswithblog...id_crystal.aspx) and I'm using his LCD library. The LCD is working perfectly.

The issue is that I've got a pair of "page up / page down" buttons on the breadboard to allow me to scroll thru the log and whenever you push one of the buttons (doesn't matter which one), the interrupt for that button will fire 2 or more times. It only happens about half the time, usually with 1 extra interrupt, but other times several in a row.

I read about someone else on these forums last June having a similar issue and he'd reported it as a bug in the .NetMF. His issue was marked resolved about a month later so I figured I'd try upgrading the firmware. I did that yesterday with the latest from tese forums and the problem still exists.

I've also read from people who have experienced this with noisy switches or sensors, so I whipped out the oscilloscope and had it do single shot traces until the issue reared it's ugly head (which didn't take long). I've attached the results. It looks like a rather clean square waveform to me.

Here is the code for my logging class:

using System;
using System.Collections;
using MicroLiquidCrystal;
using Microsoft.SPOT.Hardware;

namespace Hs.LcdLogger
{
    public class LcdLogger
    {
        private readonly Lcd _lcd;
        public Lcd LoggerLcd { get { return _lcd;  } }

        private readonly ArrayList _logList; 
        private Int32 _logIndex;
        private readonly Int32 _logSize;

        private static InterruptPort _btnPreviousPage;
        private static InterruptPort _btnNextPage;

        public LcdLogger(SPI.SPI_module spiBus, Cpu.Pin latchPin, Int32 logSize, Cpu.Pin previousPin, Cpu.Pin nextPin)
        {
            // Create the transfer provider.
            Shifter74Hc595LcdTransferProvider lcdProvider = new Shifter74Hc595LcdTransferProvider(spiBus, latchPin, Shifter74Hc595LcdTransferProvider.BitOrder.MSBFirst);

            // Create the LCD interface.
            _lcd = new Lcd(lcdProvider);

            // Set up the LCD's number of columns and rows. 
            _lcd.Begin(16, 2);
            _lcd.Backlight = false; // The plug-in module will have it's own switch for the backlight.

            // Initialize log array.
            _logSize = logSize;
            _logList = new ArrayList { Capacity = logSize };

            // Set up navigation pins.
            _btnPreviousPage = new InterruptPort(previousPin, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
            _btnPreviousPage.OnInterrupt += BtnPreviousPage_OnInterrupt;
            _btnNextPage = new InterruptPort(nextPin, false, Port.ResistorMode.Disabled, Port.InterruptMode.InterruptEdgeLow);
            _btnNextPage.OnInterrupt += BtnNextPage_OnInterrupt;
        }

        public void BtnPreviousPage_OnInterrupt(uint port, uint state, DateTime time)
        {
            PreviousPage();
        }

        public void BtnNextPage_OnInterrupt(uint port, uint state, DateTime time)
        {
            NextPage();
        }

        public void LastPage()
        {
            if (_logList.Count == 0)
                return;

            if (_logList.Count > 1)
                _logIndex = _logList.Count - 2;
            else
                _logIndex = _logList.Count - 1;

            UpdateDisplay();
        }

        public void NextPage()
        {
            if (_logList.Count == 0)
                return;

            if (_logList.Count > 2)
            {
                _logIndex += 2;

                // If we went past the last page, set to the last page.
                if (_logIndex > _logList.Count - 2)
                    _logIndex = _logList.Count - 2;
            }
            else
                _logIndex = 0;

            UpdateDisplay();
        }

        public void PreviousPage()
        {
            if (_logList.Count == 0)
                return;

            if (_logList.Count > 2)
            {
                _logIndex -= 2;

                // If we went past the first page, set to the first page.
                if (_logIndex < 0)
                    _logIndex = 0;
            }
            else
                _logIndex = 0;

            UpdateDisplay();
        }

        private void UpdateDisplay()
        {
            _lcd.Clear();

            // First line
            if (_logList.Count > 0)
            {
                _lcd.SetCursorPosition(0, 0);
                _lcd.Write(_logList[_logIndex].ToString());
            }

            // Second line
            if (_logList.Count > 1)
            {
                _lcd.SetCursorPosition(0, 1);
                _lcd.Write(_logList[_logIndex + 1].ToString());
            }
        }

        public void AddLogLine(String logLine)
        {
            // If adding a line will exceed our max log size, remove the first entry (first in, first out).
            if (_logList.Count > _logSize)
                _logList.RemoveAt(0);

            // Add the first 16 chars
            _logList.Add(logLine.Length > 16 ? logLine.Substring(0, 16) : logLine);

            // If it's longer than 16 chars, dump the remaining chars (up to 16) to another line.
            if (logLine.Length > 16)
            {
                // If adding a line will exceed our max log size, remove the first entry (first in, first out).
                if (_logList.Count > _logSize)
                    _logList.RemoveAt(0);

                // Add a ">" char to indicate word-wrapped line.
                logLine = String.Concat(">", logLine.Substring(16, 15));
                _logList.Add(logLine);
            }
        }

    }
}


And here's the sample program I'm using to test it:

using System.Threading;
using Hs.LcdLogger;
using Microsoft.SPOT.Hardware;
using SecretLabs.NETMF.Hardware.Netduino;

namespace NetduinoApplication1
{
    public class Program
    {

        static private InputPort _pinEndButton = new InputPort(Pins.ONBOARD_SW1, false, Port.ResistorMode.Disabled);

        public static void Main()
        {
            LcdLogger logger = new LcdLogger(SPI_Devices.SPI1, Pins.GPIO_PIN_D10, 20, Pins.GPIO_PIN_D2, Pins.GPIO_PIN_D3);

            logger.AddLogLine("Page 1, Line 1");
            logger.AddLogLine("Page 1, Line 2");
            logger.AddLogLine("Page 2, Line 1");
            logger.AddLogLine("Page 2, Line 2");
            logger.AddLogLine("Page 3, Line 1");
            logger.AddLogLine("Page 3, Line 2");
            logger.AddLogLine("Page 4, Line 1");
            logger.AddLogLine("Page 4, Line 2");
            logger.AddLogLine("Page 5, Line 1");
            logger.AddLogLine("Page 5, Line 2");

            while (!_pinEndButton.Read())
            {
                
            }

            logger.LoggerLcd.Clear();
        }

    }
}


Any help with this issue would be greatly appreciated!

Thanks in advance!

Frank

Attached Files



#2 Coding Smackdown

Coding Smackdown

    Advanced Member

  • Members
  • PipPipPip
  • 78 posts
  • LocationLewisville, TX USA

Posted 18 October 2012 - 01:30 PM

You are running into switch bounce which is a common problem. You can get rid of it by using The time passed into the function to check when the last time the button was pressed and ensure you reject any interrupts within a predefined period of time. Below is an example I'm using for my Brew Controller, I will only act on the interrupt if it has been more than 200 milliseconds since the last time I acted upon it.

public static void EngageHeaterButton_OnInterrupt(uint data1, uint data2, DateTime time) 
{
  if (engageHeaterButtonLastPushed.AddMilliseconds(200) > time)
    return;
  // button press state received in data2
  // 0 = open, 1 = pressed
  if (data2 == 1)
  {
    PinManagement.heaterEngaged = true;
  }
  _displayHelper.DisplayText("Heater|Engaged");
  engageHeaterButtonLastPushed = time;
}

Hope this helps you out.
Brewing Award Winning Beer with a Netduino!
http://diybrewery.com

#3 Frank T

Frank T

    New Member

  • Members
  • Pip
  • 4 posts
  • LocationAtlanta, GA

Posted 18 October 2012 - 01:36 PM

Thanks for your quick reply! :-)

You are running into switch bounce which is a common problem.


That was my first thought, but wouldn't that show up on the oscilloscope trace though? When I saw the trace I'd figured that bounce wasn't the issue.

Perhaps I'm just not understanding what constitutes a bounce. My understanding is that it was a voltage fluctuation on the button press or button release, but if that's the case, it'd have shown up on the trace.

#4 Coding Smackdown

Coding Smackdown

    Advanced Member

  • Members
  • PipPipPip
  • 78 posts
  • LocationLewisville, TX USA

Posted 18 October 2012 - 01:55 PM

You are correct about the bounce being a voltage fluctuation. The other part is how the Netduino determines an edge change from low to high. As I understand it, The Netduino will look at voltages below 1.6V as a logic low and those above as a logic high. So if your trace isn't showing a pronounced bounce it could be that the signal is varying just enough to be seen as fluctuating from low to high causing the Netduino to trigger the interrupt multiple times. Hope that helps
Brewing Award Winning Beer with a Netduino!
http://diybrewery.com

#5 Frank T

Frank T

    New Member

  • Members
  • Pip
  • 4 posts
  • LocationAtlanta, GA

Posted 18 October 2012 - 02:49 PM

What you're saying makes sense, but with a 1.2ms rise time, and as clear as the signal appears to be on the scope, I just don't know if that's what's happening. I'll use your workaround for now, but I'm still curious as to why this is happening.

#6 CW2

CW2

    Advanced Member

  • Members
  • PipPipPip
  • 1592 posts
  • LocationCzech Republic

Posted 18 October 2012 - 02:55 PM

In addition to what Coding Smackdown said, if you don't have external pull-up resistors, you might want to enable Netduino built-in ones when using falling edges (ResistorMode.PullUp instead of .Disabled).

#7 Frank T

Frank T

    New Member

  • Members
  • Pip
  • 4 posts
  • LocationAtlanta, GA

Posted 18 October 2012 - 03:39 PM

In addition to what Coding Smackdown said, if you don't have external pull-up resistors, you might want to enable Netduino built-in ones when using falling edges (ResistorMode.PullUp instead of .Disabled).


Yea, I've got pulldown resistors on the buttons already (pin state is low by default, not high). Everything I'm seeing on the scope indicates that the buttonpress signals received by the netduino are solid.

I do appreciate all of you guys' suggestions on this issue!

Regards,

Frank




0 user(s) are reading this topic

0 members, 0 guests, 0 anonymous users

home    hardware    projects    downloads    community    where to buy    contact Copyright © 2016 Wilderness Labs Inc.  |  Legal   |   CC BY-SA
This webpage is licensed under a Creative Commons Attribution-ShareAlike License.