MCP23017 Interrupt Tutorial

This page is all about how to use multiple MCP23017 interrupts. If you are looking for more information on the MCP23017 then goto this page where there is more general information on all aspects of the device including other example code and register descriptions.

In the page link above there is an example of interrupt usage but that is for one device. What prompted me to write this page was a question from Victor, which is shown below:


I have read your excellent work on MCP23017, the best yet on the web! I do need your expertise with my RFID-chessboard project. My prototype uses mcp23017 controlling a matrix of antennae (underneath a chess square) connected to only one RFID reader module. The proof of concept works well with the antennae matrix. Now I need to progress from this stage of the project. To speed up the system I need to put hall-effect switches on each of the chess square. I would need to use 8 mcp23017s, 4 to control the antennae and 4 to monitor the switches.That means I have to use interrupts for the switches.

The help I need is how to I go about monitoring 4 MCPs Interrupts/ BTW I plan on using the Centipede from Macetech.com.

Thanks

Victor Feria

Reprinted with permission.

I had a look at the centipede product and it looks like a useful little board. It has four MCP23017 devices providing I/O capability of 64 pins and you can attach another one onto the I2C bus for a maximum of 128 I/O pins. On the board is a jumper to set the address range of each board.

You can then use the software library provided by macetech to access pins on each board (2 boards maximum for maximum 128 pins) in a similar way to using Arduino functions such as digitalWrite etc.


Assumptions about the board

I don't have one myself so have made some, hopefully reasonable, assumptions about the pcb since the website does not show the actual pcb traces.

Assumptions are:

  • INTA outputs from each MCP23017 interrupt pin are not connected anywhere else on the board.
  • There is no connection to Arduino pin 3 on the centipede board.
  • The board is set to address 0 ( jumper on left side) - meaning that MCP23017 pins 0 - 64 are at address 0 - 64 i.e. low addresses in software.

Wiring mods for centipede board

Wiring schematic for multiple interrupt operation for multiple 23017s

View larger image here.

The wiring is simple:

  1. Make the board start at address 0 : jumper to left side of board.
  2. Connect all INTA pads together and the connect them to pin 3 (an interrupt pin).
  3. Connect a 10k resistor from one of the INTA pads and to 5V.
TIP: I noticed that each board has a set of I2C pullup resistors - If they come pre-fitted then when using 2 boards you only need one set. The lower the resistor value the faster the edge but also the more power is used (higher current). If you leave them on both boards the value of resistor will be in parallel i.e. half the measured R4 or R5. If they are 1k then 500 Ohms is getting a little low - pull down current will be 5/500 = 10mA - not too much but unnecessary.

Pin Mapping to numbers

You can get a bit confused (or at least I did) - just not paying enough attention. Port B is occupying pins 1 to 8 of the chip (see below) and you tend to assume that these are the 1st ports. However port A occupies pins 21 to 28. In the Centipede layout PORT A is used first - this makes sense to use the lowest port identifier first. It is a shame that the 23017 creators did not label 1-8 as Port A.

Therefore when thinking of Arduino 'like' pinouts, pin zero is chip pin 21 of the MCP23017 (and not conveniently pin 1 of the chip!). If you wanted to access pin 20 (this will be the 2nd port (or chip) and will be GPA4 - four pins down on the right hand side of the chip. (GPA0 = Apin 16, GPA1 = Apin 17, GPA2 = Apin 18, GPA3 = Apin 19, GPA4 = Apin 20 - where Apin stands for Arduno 'like' pins ).

mcp23017 pinout

Software Library and versions

Arduino IDE Version

Version : 1.8.5

Library

Macetech provides its own library for the boards (maximum of two connected boards) and this provides arduino-like command functions. Download the library (Centipede.zip) and unzip it in your arduino library folder; Something like: c:/user/Documents/Arduino - create a folder here called Centipede and unzip into that!

Download Centipede.zip from here from http://macetech.com

The library functions for interrupt control in the Centipede library are:

  • portInterrupts
  • portIntPinConfig

The member function portInterrupts, has a hidden operation that sets the MIRROR bit for sub-ports A and B so any interrupt on A or B sub-ports (GPIOA and GPIOB) is also signalled at both INTA and INTB pins.

Incorrect writing of Centipede.cpp function:

Warning: The following Member Function (of Centipede.cpp) is wrong
void Centipede::portIntPinConfig(int port, int drain, int polarity) {

  WriteRegisterPin(port, 1, 0x0A, drain);
  WriteRegisterPin(port, 1, 0x0B, drain);
  WriteRegisterPin(port, 0, 0x0A, polarity);
  WriteRegisterPin(port, 0, 0x0B, polarity);

}

The following is the register description for IOCON:

MCP23017 IOCON Control Register Bits

As identified above bit 0 is an undefined and unused bit. INTPOL should be bit 1, and ODR should be bit 2.

Re-write the function in Centipede.cpp as follows:

TIP: Re-write following Member Function (from Centipede.cpp) as shown below:
void Centipede::portIntPinConfig(int port, int drain, int polarity) {

  WriteRegisterPin(port, 2, 0x0A, drain);
  WriteRegisterPin(port, 2, 0x0B, drain);
  WriteRegisterPin(port, 1, 0x0A, polarity);
  WriteRegisterPin(port, 1, 0x0B, polarity);

}

Missing Centipede Function

The library has not been developed far enough for multiple open drain operation and is missing a member function to detect the state of INTFA and INTFB registers 0x0e and 0x0f. These return an interrupt flag state that allows you to determine which port (device) produced an interrupt (and it could be more than one device).

Add this member function to Centipede.cpp

// JFM: Return port interrupt flags (1=pin interrupted)
uint16_t Centipede::getIntF(int port)  {

  ReadRegisters(port, 0x0e, 2);

  int receivedval = CSDataArray[0];
  receivedval |= CSDataArray[1] << 8;

  return receivedval;
}

Add the member function into centipede.h within the public definitions:

uint16_t getIntF(int port);

Example MCP23017 Interrupt Code

The following example shows how to use multiple interrupts from MCP23017 chips and feed them into one external interrupt on the Arduino. To do this a modified centipede library is used (see above code snippet).

The following code also uses the same principle described in using interrupts on this page. That is, allowing wire-library interrupts while within the MCP23017 interrupt routine.

Note: The routine findPorts() was used because I only used one MCP23017 to test the code. The chip's address was set to '1' meaning it is the 2nd chip out of device addresses 0-3.

Detecting Presence of MCP23017 chips

When retrieving INTF data from each device, if a device is not present then, in my case, the returned data result was 0xffff. This meant that all 16 interrupt bits were high (actually not there at all), so the interrupt flag was detected in error for non-existent chips.

The solution to that was to create the function findPorts() which retrieves the IOCON.MIRROR bit from the device, inverts it and writes it back. Then reads it again. if the returned bit is inverted then the device is present and the relevant index in array portExists[] is set.

Note: you should change portExists[] to a 16 bit integer and use bit manipulation to set and retrieve flag bits if you are worried about saving RAM space. However the array indexing method is fast.

You could find the routine useful for checking :

  1. that all chips are operational,
  2. if a second centipede board is attached.

Multiple MCP23017 Interrupts Setup()

in the setup() routine a serial instance is instantiated (initialised). This is only used for showing the presence of chips as described above - if chips are not present then you could indicate that via the on board LED and remove the serial output. Instead in this code the LED is used to indicate that any key has been pressed. Indicating an error condition is usually made through a serial interface to show more detail information about the error.

For each of 4 ports The following actions are taken:

1. All port pins are set as inputs and all have the pullups enabled.

2. Interrupts are setup by calling portInterrupts() 2 times so that spurious interrupts are not generated (by changing the interrupt register values that then react with existing conditions of the pins). In between these calls, the capture register is invoked to clear interrupts.

3. Finally the open drain output interrupt is enabled.

At the end of setup the external interrupt is enabled.

Multiple MCP23017 Interrupts Toggle_LED()

As it sounds the on board LED (Apin 13) is toggled.

Multiple MCP23017 Interrupts isr()

This is the Interrupt Service Routine (ISR) the is activated by an external interrupt. The external interrupt is selected at the top of the file and uses a macro to insert the code: controlArduinoInt.

In the routine itself interrupts are turned off, the external interrupt is detached (ignored) then interrupts are turned on to enable the wire-library to operate.

Since the interrupt has fired we now need find out which chip gave the interrupt so we loop through 4 ports and read the INTF register (also ignoring chips that are not present using portExists data). When found the LED is toggled.

This means that the only way that the LED is turned on and off is if an interrupt is generated by one of the MCP23017s.

Note: since it is assumed that only one pin is pressed at a time the LED is toggled for which ever INTF register is non-zero - you can use a break statement after toggling - a bit quicker and good practice to show code operation. In practice you will want to use bit maniplulation macros to extract which pin caused the interrupt.

Arduino has the following bit macros:

bitSet(x, nthbit)

bitClear(x, nthbit)

bitRead(x, nthbit)

Multiple MCP23017 Interrupts Loop()

This is a do-nothing loop as we are only interested in the ISR operation. All we do is have a 300ms delay (could be left blank).

// MCP23017 Example: MCP23017 Interrupt operation.
//
// This code sends an interrupt from multiple MCP23017s
//
// www.best-microcntroller-projects.com/mcp23017.html
//
// Copyright : John Main
// Free for non commercial use.
//
// V1.01
//  Descripted interrupt controls in setup.
//  Removed text in intf loop saying stops at 1st int found.
// V1.02
//  Changed to using I2C NACK for chip detecction.
//
#include <Wire.h>
#include <Centipede.h>


// Arduino pins
#define INTPIN 3   // Interrupt on this Arduino Uno pin.
#define LED 13
#define LED_HIGH digitalWrite(LED,HIGH)
#define LED_LOW digitalWrite(LED,LOW)

#define CSAddress 0b0100000 // base address of MCP23017

#define controlArduioInt attachInterrupt(digitalPinToInterrupt(INTPIN),isr,FALLING)

static uint8_t portExists[8]={0,0,0,0,0,0,0,0}; // For single chip debug detect chips.

Centipede CS; // Create Centipede object.

//////////////////////////////////////////////
// Read and change a register bit to see if device is present
uint8_t findPorts(uint8_t port) {
uint8_t err;

   Wire.beginTransmission(CSAddress + port);
   Wire.write((byte)0x0a); // IOCON
   err =  Wire.endTransmission();
   // Since only sending the address can get
   // OK(0), or NACK on address(2), or other error(4).
   // Assume any error = not present.
   if (err==0 )return 1;
   return 0;
}

//////////////////////////////////////////////
void setup(void) {
uint8_t i;

  Serial.begin(115200);
  Serial.println("MCP23017 MULTI");

  pinMode(LED,OUTPUT);
  LED_LOW;

  Wire.begin(); // start I2C

  CS.initialize(); // set all registers to default

  // Check if ports exist.
  for(i=0;i<8;i++) {

     Serial.print("Port: ");Serial.print(i);
     if (findPorts(i)) {
         Serial.println(" Exists: ");
         portExists[i] = 1; // Flag that it exists.
     }
     else Serial.println(" Not found");
  }

  for(i=0;i<4;i++) {
     CS.portMode(i, 0xffff);   // Chip pins on port to inputs.
     CS.portPullup(i, 0xffff); // All pins on port to pullup.

     // Disable interrupt but set conditions for interrupt to occur
     // This stops an intial interrupt firing in error.
     // portInterrupts(int port, int gpinten, int defval, int intconval)
     CS.portInterrupts(i, 0x0000, 0xFFFF, 0X0000);  //
     CS.portCaptureRead(i); // Read capture reg. to clear ints.
     // GPINTEN = 0xffff enabled.
     // DEFVAL  = 0xffff all default to pulled high.
     // INTCON  = 0x0000 all interrupt on change.
     CS.portInterrupts(1, 0xffff, 0xFFFF, 0X0000);

     // Set open drain ( ODR high overrides IPOL)
     // portIntPinConfig(int port, int drain, int polarity) {
     CS.portIntPinConfig(i,1,0);
  }

  controlArduioInt; // Enable Arduino interrupt control.

}

//////////////////////////////////////////////
void toggle_LED(void) {
static uint8_t tog=1;
  tog = !tog;
  if(tog) {
     LED_HIGH;
  } else {
     LED_LOW;
  }
}

//////////////////////////////////////////////
// The interrupt routine handles LED1
// This is the button press since this is the only active interrupt.
void isr(void){
uint8_t i,val;
static uint16_t ledState=0;

   noInterrupts();

   // Stop interrupts from external pin.
   detachInterrupt(digitalPinToInterrupt(INTPIN));
   interrupts(); // re-start interrupts for mcp

   // Find out which port produced the interrupt reg INTFAB 0x0E
   // Assumption is that only one event happens at a time.
   for(i=0;i<4;i++) {

      if ( portExists[i] &&
           CS.getIntF(i)  != 0) {
           CS.portCaptureRead(i); // Read capture reg. to clear ints.
           toggle_LED();
      }
   }

   controlArduioInt;  // Reinstate interrupts from external pin.
}

//////////////////////////////////////////////
void loop(){
  delay(300);
}

Detecting chess piece positions using MCP23017 Interrupts.

A more refined program that identifies piece positions as you would in a chess board 1-8 and a-h. As a switch changes state so a piece is identified as having been placed or removed. Additionally the chess board location is reported.

To complete the chess piece detection you would need an piece identifier;s Victor suggests one way As Victor suggests one way is to use RFID.

The code below is similar to the above code, but adds 'place' and 'remove' detection simulated by a push button input to a pin of the MCP23017.

Debouncing is essential as rapid push button movements cause multiple interrupts so in the isr() routine a 30ms delay is used (new interrupts are ignored for 30ms) while the input settles.

The isr communicates to main code via the variable intFired and only in main code are MCP interrupts reinstated.

A unique pin number is identified by getMultiPin and this is converted to row and column chess notation using divide (/) and mod (%) operators. Note the use of ascii table method to convert to a-h.

// MCP23017 Example: MCP23017 Interrupt operation.
//
// This code sends an interrupt from multiple MCP23017s
// 4 mcp23017S which are used detect placing and removal
// of chess pieces from a board thus requiring 64 (8x8)
// positions These are provided by 4x16 digital inputs
// probably also using reed relays and a magnet in each
// piece.
// Additional h/w is required to identify the pieces
// e.g. RFID h/w
//
// www.best-microcntroller-projects.com/mcp23017-interrupt.html
//
// Copyright : John Main
// Free for non commercial use.
//
// V1.00
//
// Inspired by Victor Feria's Chessboard Project.
//
// CHESSBOARD NOTATION
// Row
//  8 [ ][ ][ ][ ][ ][ ][ ][ ]        GPIOB b0-b7
//  7 [ ][ ][ ][ ][ ][ ][ ][ ]  chip4 GPIOA b0-b7
//  6 [ ][ ][ ][ ][ ][ ][ ][ ]        GPIOB b0-b7
//  5 [ ][ ][ ][ ][ ][ ][ ][ ]  chip5 GPIOA b0-b7
//  4 [ ][ ][ ][ ][ ][ ][ ][ ]        GPIOB b0-b7
//  3 [ ][ ][ ][ ][ ][ ][ ][ ]  chip2 GPIOA b0-b7
//  2 [ ][ ][ ][ ][ ][ ][ ][ ]        GPIOB b0-b7
//  1 [ ][ ][ ][ ][ ][ ][ ][ ]  chip1 GPIOA b0-b7
//  .  a  b  c  d  e  f  g  h ----> Columns
//
#include <Wire.h>
#include <Centipede.h>

// Arduino pins
#define INTPIN 3   // Interrupt on this Arduino Uno pin.
#define LED 13

#define CSAddress 0b0100000 // I2C Base address of chip.

#define controlArduioInt attachInterrupt(digitalPinToInterrupt(INTPIN),isr,FALLING)

static uint8_t portExists[8]={0,0,0,0,0,0,0,0}; // For single chip debug detect chips.
static uint8_t intFired=0;
static uint16_t storeINTF;  // For later processing.
static uint16_t storeCAP;   // For later processing.
static uint8_t storePort;   // For later processing.

Centipede CS; // Create Centipede object.

//////////////////////////////////////////////
// Read and change a register bit to see if device is present(1).
uint8_t findPorts(uint8_t port) {
uint8_t err;

  // Use I2c NACK to detect chip
  Wire.beginTransmission(CSAddress + port);
  Wire.write((byte)0x0a); // IOCON
  err =  Wire.endTransmission();

  if (err==0 )return 1;
  return 0;
}

//////////////////////////////////////////////
void setup(void) {
uint8_t i;

  intFired=0;

  pinMode(LED,OUTPUT);
  digitalWrite(LED,LOW);

  Wire.begin(); // start I2C

  CS.initialize(); // set all registers to default

  Serial.begin(115200);

  // Check if ports exist.
  for(i=0;i<8;i++) {

     Serial.print("Port: ");Serial.print(i);
     if (findPorts(i)) {
         Serial.println(" Exists: ");
         portExists[i] = 1; // Flag that it exists.
     }
     else Serial.println(" Not found");
  }

  for(i=0;i<4;i++) {
     CS.portMode(i, 0xffff);   // Chip pins on port to inputs.
     CS.portPullup(i, 0xffff); // All pins on port to pullup.
     //  port, int on pin, default, int !=default
     // Disable interrupt but set conditions for interrupt to occur
     // This stops an intial interrupt firing in error.
     // portInterrupts(int port, int gpinten, int defval, int intconval)
     CS.portInterrupts(i, 0x0000, 0xFFFF, 0X0000);  //
     CS.portCaptureRead(i); // Read capture reg. to clear ints.
     // GPINTEN = 0xffff enabled.
     // DEFVAL  = 0xffff all default to pulled high.
     // INTCON  = 0x0000 all interrupt on change.
     CS.portInterrupts(i, 0xffff, 0xFFFF, 0X0000);

     // Set open drain ( ODR high overrides IPOL)
     // portIntPinConfig(int port, int drain, int polarity) {
     CS.portIntPinConfig(i,1,0);
  }

  controlArduioInt; // Enable Arduino interrupt control.
}

//////////////////////////////////////////////
void toggle_LED(void) {
static uint8_t tog=0;
  tog = !tog;
  if(tog) {
     digitalWrite(LED,HIGH);
  } else {
     digitalWrite(LED,LOW);
  }
}

//////////////////////////////////////////////
// The interrupt routine handles LED1
// This is the button press since this is the only active interrupt.
void isr(void){
uint8_t i;
uint16_t val;

   noInterrupts();

   // Debounce. This debunce time is essential as you must wait for the
   // input to the MCP23017 to settle - if not multiple interrupts will
   // hang the code.
   // Note: Can not use delay() in interrupt code (not interrupt safe).
   delayMicroseconds(30000);

   // Stop interrupts from external pin.
   detachInterrupt(digitalPinToInterrupt(INTPIN));
   interrupts(); // re-start interrupts for wire library.

   // Find out which port produced the interrupt reg INTFAB 0x0E
   // This stops at 1st interrupt detected
   // Assumption is that only one event happens at a time.

   for(i=0;i<4;i++) {

      if ( portExists[i] &&
         (val=CS.getIntF(i)) != 0) {

          storePort = i;
          storeINTF = val;
          storeCAP =  CS.portCaptureRead(i); // Read capture reg. to clear ints.

          intFired=1; // Indicate low and high changes.

          break;
      }
   }

   toggle_LED();
}

//////////////////////////////////////////////
// Return a unique pin number from multiple MCP23017s
// or return -1 on fail.
//
// Return value can be 0-127 as can return 1 of 128
// pins if 8 chips are used.
//
// valINTF - The MCP interrupt register value.
//
// Note: Only returns 1st found interrupt bit that is high
// for each port not multiple interrupts.
//
int8_t getMultiPin(uint8_t port, uint16_t valINTF) {
uint16_t mask=1;
uint8_t i;

   for (i=0;i<16;i++) {
      if ( (valINTF & mask) !=0 ) break; // i contains index
      mask=mask<<1;
   }
   if (i==16) return -1; // Failed
   return port*16+i;
}

//////////////////////////////////////////////
void loop(){
static uint8_t pin;
uint8_t val,row,col,colChar,i;
uint16_t val_16;
char str[2];

  if (intFired) {

      // Find which pin caused an interrupt.
      pin = getMultiPin(storePort,storeINTF);

      val = CS.digitalRead(pin);

      if (pin != -1) {  // No error so use the pin.

        row = pin / 8 + 1 ; // +1 : index from 1 not zero.
        col = pin % 8;

        colChar = col+'a';  // Convert 0-8 to a-h

        str[0]=colChar; str[1]='\0'; // Convert to string for printing.

        Serial.print("Pin ");Serial.print(pin);
        Serial.print(" row ");Serial.print(row);
        Serial.print(" col ");Serial.print(str);

        if (val==0) Serial.println(" Placed"); else Serial.println(" Removed");
      }

      intFired = 0; // Restart.
      controlArduioInt;  // Reinstate MCP interrupts from external pin.
  }
}

Typical output from above program:

In this case the address was set to 1 so rows 3 and 4 were available

mcp23017 chess piece detection simulation

More questions on code operation for the MCP23017 interrupt

#1. How do I determine which chip hosted the MPC23017 interrupt?

That is the reason that I added the INTF register read function for the port (chip) getIntF().

You cycle through all the expected ports (chips) until you find an interrupt bit set high (i.e. a non zero 16 bit value is returned as the INTF register state).

You need the the INTF read function as this sets a bit high depending on the pin that triggered the interrupt . The capture register tells you the actual state of the pin that caused the interrupt. Since you can set pins to be interrupt active on low or high reading the capture register alone does not show you which interrupt fired.

INTF register always sets a bit high regardless of the polarity of the input trigger.

The following code snippet (from 1st example in the interrupt routine) shows looping through 4 ports of value 0 to 3, and toggling an LED if an interrupt flag is found high. The function CS.getIntF(i) returns the 16 bit interrupt flag register for each chip:

  for(i=0;i<4;i++) {

      if ( portExists[i] &&
           CS.getIntF(i)  != 0) {
           CS.portCaptureRead(i); // Read capture reg. to clear ints.
           toggle_LED();
      }
   }

Note: if you don't care about chips being present remove portExists[i] check as I needed it (not having 4 chips available). When you have got 4 connected the default state is all working!

The MCP code is set to interrupt on change (as discussed in the 1st mcp23017.html page). Therefore to see if a pin was pressed detect an interrupt using intf reg. and check capture reg. to see if low = press, if high = release.

#2 What port bank caused the MCP23017 interrupt

See above code . Since the routine getMultiPin() returns a pin number from 0-127 and you can decode using % and / you don't directly need the port/bank information

#3 Detection of which pin caused an MCP23017 interrupt.

See above code and getMultiPin()

#4. Which method is faster four MCP23017 interrupts or open-drain method?

The open drain method is simply a wire or function and each MCP23017 pulls the open drain down by activating a transistor that has its collector open (or FET where drain is open) emitter ( or FET source) is connected to Ground. So for a falling edge i.e. open drain active the edge speed is fast. On the rising edge the 10k pulls up and is therefore slow (depends on capacitance at that pin) - to speed this up reduce that 10k value. However we are looking for a falling edge so all is good.

Your question is probably about how fast you can react to a switch being made. So I measured the access function for getIntF and capture at 820us 520us for getIntF(). So to scan all 4 chips would take 2ms scanning only with getIntF(). That seems fast enough. If you used 4 interrupts then you can react to each chip in 520us so yes 4 interrupts are faster.

But looking at the system there is no need for speed. Picking up and placing chess pieces takes 100s of milliseconds or more and even in your code there is a 100ms debounce time (do nothing time). For this system there is no need for faster speed. I used 30ms delay within the isr (using microsecond() as you can't use delay() in an interrupt) which seems to be enough time for bouncing to settle (but could be different for your setup) for a push button input.

You would want speed if it was critical to do something in under a millisecond. Even then the I2C bus speed can be increased to 1.7MHz or use a 20MHz SPI version. That does not automatically increase speed to that rate as ultimately the processor needs to do something between I2C or SPI writes but it would help.

For this design it is all about the input rate which is slow. All switches can be read in about 4ms and the interrupt flag tells you which one has changed. You only have to deal with switch bounce.

One other thing when you have 4 interrupts you have to manage code for 4 - that's a lot of code maintenance and each piece of code will be identical to the other! i.e. a pain when it needs changing.

Also note the method of pin number detection and the way to output a digit, which uses a standard ASCII table output trick: i + 'a';

New! Comments

Have your say about what you just read! Leave me a comment in the box below.




Privacy Policy | Contact | About Me

Site Map | Terms of Use


Subscribe to the MicroZine Newsletter and collect your free microcontroller Ebooks, download project code and more...


Visit our Facebook Page:

   Click Here



Recent Articles

  1. How to use a DS18B20 on the Arduino for easy temperature measurement

    How to Easily Use the DS18B20 Maxim One-Wire thermometer with Arduino example code showing external or parasitic power modes.

    Read more

  2. The TCS230 Color Sensing Chip: How it works and how to use it.

    How to use the TCS230 (/TCS3200) Color detector chip and easily add it to any of your projects.

    Read more

  3. Arduino millis

    How to use Arduino millis() for delays but still make the processor do work - Stop using delay()

    Read more

  4. [Arduino Tutorial] : How to use the 74HC595 shift register with shiftOut().

    The Essential Guide to the 74HC595; What it is and how you can easily use one in any of your projects.

    Read more

  5. Pic Programmer Types

    Which pic programmer do you need? This page discusses PIC programmers and gives some essential information on choosing or building your own programmer.

    Read more

  6. Arduino Pulsein: an easy way to measure pulse periods in microseconds.

    learn how to use Arduino pulseIn and pulseInLong to get the most accurate pulse measurement on an Arduino.

    Read more

Readers Comments

"I wanted to thank
you so so so much
for all the information
you have provided in
your site it's

SUPERB and FANTASTIC."

- Ranish Pottath

"This site really is
the best and my favorite.
I find here many useful
projects and tips."

- Milan

bursach<at>gmail.com<

"Awesome site,
very, very easy and nice
to navigate!"


- Matt
matt_tr<at>
wolf359.cjb.net


Learn Microcontrollers

"Interested in
Microcontrollers?"

Sign up for The
Free 7 day guide:

FREE GUIDE : CLICK HERE


"I am a newbie to PIC
and I wanted to say
 how great your
site has been for me."


- Dave

de_scott<at>bellsouth.net

"Your site is a great
and perfect work.
congratulations."


- Suresh

integratredinfosys<at>
yahoo.com

"I couldn't find the correct
words to define
yourweb site.

Very useful, uncovered,
honest and clear.

Thanks so much for
your time and works.
Regards."


- Anon

Back to Top