High Voltage programming/Unbricking for Attiny

Yikes! Invalid device signature

It sometimes happens: you are trying to program an Attiny and you get an error. There might be many causes for errors: you may not have selected the proper board, your programmer might be rotten, you did something wrong or the connections of your programmer are not correct, but sometimes it can be caused by the wrong bits being set in your Attiny: e.g. you set pin 1 (reset) to be an I/O pin. That makes it impossible to program it with ISP, or you set the wrong oscillator. For these cases a High Voltage programmer can be of help.
It happened to me when i was trying to ‘burn the bootloader’ on my attiny85 (there is no bootlaoder for the attiny 85 but this means setting the fuses). My  computer’s memory was kinda full when I  was busy and suddenly something crashed and I got the dreaded error message Yikes! Invalid device signature. As said, often this is because of a bad connection, but another chip didnt have that problem so I knew something was very wrong.
Time to build a High Voltage Programmer
Below you will see such a circuit. It is fairly simple: 6 resistors, a transistor  a DIL foot  and a 12 Volt source from somewhere. As I  didn’t expect to have to use the HVP often, I opted for a battery, but as I displaced it, I ended up using a 75 euroct 5 to 12 Volt converter that I plugged in.

Circuit
Circuit

 

 

 

 

 

 

 

 

 

And this is an easy way to build it on stripboard.

High Voltage programmer Stripboard
On Stripboard
The finished board ready to use
The finished board

 

 

 

 

 

 

 

I have built it such that it sticks into the D8-D13,ground header of an Arduino UNO. The only thing  you need to do is to attach a 12 Volt battery, or an other 12 Volt source.
There are various programs that can reset the bits back to factory setting. Below you will find 2 of them that all  go back to some initial work by Jos Keyzer.
The first one expects you to  set the  factory bits in the program depending on the chip you are using, the 2nd program actually reads what chip you are using, so I ended up using that one. Both programs  start after you send a random character to the serial port.

 

 

 

 

 

 

 

 

 

fuseburningWell, as it turned out, my fuses were set for E4 and DF. That means that the Attiny was expecting a 128 kHz oscillator signal. No idea how that happened as I have disabled that choice in my menu so I guess it happened coz of my computer crashing. We will never know, but the HVP set it back to factory settings: i.e. 8MHz internal oscillator with a prescaler of 8.
After that, I could just program my Attiny again.

In principle this programmer can be used for Attiny 15 and 12 as well, but as far as I recall they have some wires crossed, so you would need to make a hardware change (connect the D12 resistor to pin 3 instead of pin2), but Attiny 13/25/45/85 should work like a charm.
It can also be done on the 24/44/84 series, but they need a 14 pins DIL:
fusebit

 

 

 

5 to 12 Volt converterShould you need a cheap 12 Volt source, consider this 5 to 12 Volt converter

 

 

 

 

 

Program:

// AVR High-voltage Serial Programmer
// Originally created by Paul Willoughby 03/20/2010
// http://www.rickety.us/2010/03/arduino-avr-high-voltage-serial-programmer/
// Inspired by Jeff Keyzer http://mightyohm.com
// Serial Programming routines from ATtiny25/45/85 datasheet

// Desired fuse configuration
#define  HFUSE  0xDF   // Defaults for ATtiny25/45/85
#define  LFUSE  0x62 
// For Attiny13 use
// #define HFUSE 0xFF
// #define LFUSE 0x6A  


#define  RST     13    // Output to level shifter for !RESET from transistor to Pin 1
#define  CLKOUT  12    // Connect to Serial Clock Input (SCI) Pin 2
#define  DATAIN  11    // Connect to Serial Data Output (SDO) Pin 7
#define  INSTOUT 10    // Connect to Serial Instruction Input (SII) Pin 6
#define  DATAOUT  9    // Connect to Serial Data Input (SDI) Pin 5 
#define  VCC      8    // Connect to VCC Pin 8

int inByte = 0;         // incoming serial byte Computer
int inData = 0;         // incoming serial byte AVR

void setup()
{
  // Set up control lines for HV parallel programming
  pinMode(VCC, OUTPUT);
  pinMode(RST, OUTPUT);
  pinMode(DATAOUT, OUTPUT);
  pinMode(INSTOUT, OUTPUT);
  pinMode(CLKOUT, OUTPUT);
  pinMode(DATAIN, OUTPUT);  // configured as input when in programming mode
  
  // Initialize output pins as needed
  digitalWrite(RST, HIGH);  // Level shifter is inverting, this shuts off 12V
  
  // start serial port at 9600 bps:
  Serial.begin(9600);
  
  establishContact();  // send a byte to establish contact until receiver responds 
  
}


void loop()
{
  // if we get a valid byte, run:
  if (Serial.available() > 0) {
    // get incoming byte:
    inByte = Serial.read();
    Serial.println(byte(inByte));
    Serial.println("Entering programming Mode\n");

    // Initialize pins to enter programming mode
    pinMode(DATAIN, OUTPUT);  //Temporary
    digitalWrite(DATAOUT, LOW);
    digitalWrite(INSTOUT, LOW);
    digitalWrite(DATAIN, LOW);
    digitalWrite(RST, HIGH);  // Level shifter is inverting, this shuts off 12V
    
    // Enter High-voltage Serial programming mode
    digitalWrite(VCC, HIGH);  // Apply VCC to start programming process
    delayMicroseconds(20);
    digitalWrite(RST, LOW);   //Turn on 12v
    delayMicroseconds(10);
    pinMode(DATAIN, INPUT);   //Release DATAIN
    delayMicroseconds(300);
    
    //Programming mode
    
    readFuses();
    
    //Write hfuse
    Serial.println("Writing hfuse");
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x40, 0x4C);
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, HFUSE, 0x2C);
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x00, 0x74);
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x00, 0x7C);
    
    //Write lfuse
    Serial.println("Writing lfuse\n");
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x40, 0x4C);
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, LFUSE, 0x2C);
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x00, 0x64);
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x00, 0x6C);

    readFuses();    
    
    Serial.println("Exiting programming Mode\n");
    digitalWrite(CLKOUT, LOW);
    digitalWrite(VCC, LOW);
    digitalWrite(RST, HIGH);   //Turn off 12v
  }
}


void establishContact() {
  while (Serial.available() <= 0) {
    Serial.println("Enter a character to continue");   // send an initial string
    delay(1000);
  }
}

int shiftOut2(uint8_t dataPin, uint8_t dataPin1, uint8_t clockPin, uint8_t bitOrder, byte val, byte val1)
{
	int i;
        int inBits = 0;
        //Wait until DATAIN goes high
        while (!digitalRead(DATAIN));
        
        //Start bit
        digitalWrite(DATAOUT, LOW);
        digitalWrite(INSTOUT, LOW);
        digitalWrite(clockPin, HIGH);
  	digitalWrite(clockPin, LOW);
        
	for (i = 0; i < 8; i++)  {
                
		if (bitOrder == LSBFIRST) {
			digitalWrite(dataPin, !!(val & (1 << i)));
                        digitalWrite(dataPin1, !!(val1 & (1 << i)));
                }
		else {
			digitalWrite(dataPin, !!(val & (1 << (7 - i))));
                        digitalWrite(dataPin1, !!(val1 & (1 << (7 - i))));
                }
                inBits <<=1;
                inBits |= digitalRead(DATAIN);
                digitalWrite(clockPin, HIGH);
		digitalWrite(clockPin, LOW);
                
	}

        
        //End bits
        digitalWrite(DATAOUT, LOW);
        digitalWrite(INSTOUT, LOW);
        digitalWrite(clockPin, HIGH);
        digitalWrite(clockPin, LOW);
        digitalWrite(clockPin, HIGH);
        digitalWrite(clockPin, LOW);
        
        return inBits;
}

void readFuses(){
     //Read lfuse
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x04, 0x4C);
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x00, 0x68);
    inData = shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x00, 0x6C);
    Serial.print("lfuse reads as ");
    Serial.println(inData, HEX);
    
    //Read hfuse
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x04, 0x4C);
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x00, 0x7A);
    inData = shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x00, 0x7E);
    Serial.print("hfuse reads as ");
    Serial.println(inData, HEX);
    
    //Read efuse
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x04, 0x4C);
    shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x00, 0x6A);
    inData = shiftOut2(DATAOUT, INSTOUT, CLKOUT, MSBFIRST, 0x00, 0x6E);
    Serial.print("efuse reads as ");
    Serial.println(inData, HEX);
    Serial.println(); 
}

An other program is:

    // AVR High-voltage Serial Fuse Reprogrammer
    // Adapted from code and design by Paul Willoughby 03/20/2010
    // http://www.rickety.us/2010/03/arduino-avr-high-voltage-serial-programmer/
    // Fuse Calc:
    //   http://www.engbedded.com/fusecalc/

    #define  RST     13    // Output to level shifter for !RESET from transistor
    #define  SCI     12    // Target Clock Input
    #define  SDO     11    // Target Data Output
    #define  SII     10    // Target Instruction Input
    #define  SDI      9    // Target Data Input
    #define  VCC      8    // Target VCC

    #define  HFUSE  0x747C
    #define  LFUSE  0x646C
    #define  EFUSE  0x666E

    // Define ATTiny series signatures
    #define  ATTINY13   0x9007  // L: 0x6A, H: 0xFF             8 pin
    #define  ATTINY24   0x910B  // L: 0x62, H: 0xDF, E: 0xFF   14 pin
    #define  ATTINY25   0x9108  // L: 0x62, H: 0xDF, E: 0xFF    8 pin
    #define  ATTINY44   0x9207  // L: 0x62, H: 0xDF, E: 0xFFF  14 pin
    #define  ATTINY45   0x9206  // L: 0x62, H: 0xDF, E: 0xFF    8 pin
    #define  ATTINY84   0x930C  // L: 0x62, H: 0xDF, E: 0xFFF  14 pin
    #define  ATTINY85   0x930B  // L: 0x62, H: 0xDF, E: 0xFF    8 pin

    void setup() {
      pinMode(VCC, OUTPUT);
      pinMode(RST, OUTPUT);
      pinMode(SDI, OUTPUT);
      pinMode(SII, OUTPUT);
      pinMode(SCI, OUTPUT);
      pinMode(SDO, OUTPUT);     // Configured as input when in programming mode
      digitalWrite(RST, HIGH);  // Level shifter is inverting, this shuts off 12V
      Serial.begin(19200);
    }

    void loop() {
       if (Serial.available() > 0) {
        Serial.read();
        pinMode(SDO, OUTPUT);     // Set SDO to output
        digitalWrite(SDI, LOW);
        digitalWrite(SII, LOW);
        digitalWrite(SDO, LOW);
        digitalWrite(RST, HIGH);  // 12v Off
        digitalWrite(VCC, HIGH);  // Vcc On
        delayMicroseconds(20);
        digitalWrite(RST, LOW);   // 12v On
        delayMicroseconds(10);
        pinMode(SDO, INPUT);      // Set SDO to input
        delayMicroseconds(300);
        unsigned int sig = readSignature();
        Serial.print("Signature is: ");
        Serial.println(sig, HEX);
        readFuses();
        if (sig == ATTINY13) {
          writeFuse(LFUSE, 0x6A);
          writeFuse(HFUSE, 0xFF);
        } else if (sig == ATTINY24 || sig == ATTINY44 || sig == ATTINY84 ||
                   sig == ATTINY25 || sig == ATTINY45 || sig == ATTINY85) {
          writeFuse(LFUSE, 0x62);
          writeFuse(HFUSE, 0xDF);
          writeFuse(EFUSE, 0xFF);
        }
        readFuses();
        digitalWrite(SCI, LOW);
        digitalWrite(VCC, LOW);    // Vcc Off
        digitalWrite(RST, HIGH);   // 12v Off
      }
    }

    byte shiftOut (byte val1, byte val2) {
      int inBits = 0;
      //Wait until SDO goes high
      while (!digitalRead(SDO))
        ;
      unsigned int dout = (unsigned int) val1 << 2;
      unsigned int iout = (unsigned int) val2 << 2;
       for (int ii = 10; ii >= 0; ii--)  {
        digitalWrite(SDI, !!(dout & (1 << ii)));
        digitalWrite(SII, !!(iout & (1 << ii)));
        inBits <<= 1;         inBits |= digitalRead(SDO);
         digitalWrite(SCI, HIGH);
         digitalWrite(SCI, LOW);
       } 
       return inBits >> 2;
    }

    void writeFuse (unsigned int fuse, byte val) {
      shiftOut(0x40, 0x4C);
      shiftOut( val, 0x2C);
      shiftOut(0x00, (byte) (fuse >> 8));
      shiftOut(0x00, (byte) fuse);
    }

    void readFuses () {
      byte val;
            shiftOut(0x04, 0x4C);  // LFuse
            shiftOut(0x00, 0x68);
      val = shiftOut(0x00, 0x6C);
      Serial.print("LFuse "); // this line may show up corrupted in some browsers it is a Serial.print("LFuse: ");
      Serial.print(val, HEX);
            shiftOut(0x04, 0x4C);  // HFuse
            shiftOut(0x00, 0x7A);
      val = shiftOut(0x00, 0x7E);
      Serial.print(", HFuse: ");
      Serial.print(val, HEX);
            shiftOut(0x04, 0x4C);  // EFuse
            shiftOut(0x00, 0x6A);
      val = shiftOut(0x00, 0x6E);
      Serial.print(", EFuse: ");
      Serial.println(val, HEX);
    }

    unsigned int readSignature () {
      unsigned int sig = 0;
      byte val;
      for (int ii = 1; ii < 3; ii++) {
              shiftOut(0x08, 0x4C);
              shiftOut(  ii, 0x0C);
              shiftOut(0x00, 0x68);
        val = shiftOut(0x00, 0x6C);
        sig = (sig << 8) + val;
      }
      return sig;
    }

---

One may find this article interesting as well
If you want to see how this board (in a skightly  more luxurious build) is used in practice you may want to check a youtube video by Ralph Bacon.

Sending wireless data from one Attiny85 to another

schema-manchesterI have struggled a lot with sending RF data between two Attiny85 chips, so I thought it might be helpful if I just explain how I did it. There are a number of such projects being described on the internet, but yet, it didn’t prove to be such a straightforward project, which i found to be mostly due to not using the right libraries and cores.

BOM
Transmitter:
Attiny85 – 0.82 euro/10
10k resistor
433 MHz transmittermodule – 1 euro per set
mini breadboard – 58 cts/piece

Receiver:
Attiny85
10k resistor
433 MHz Receiver module
mini breadboard
Optional: 2 wire LCD

There are two main libraries used to send and receive data on an Arduino platform: VirtualWire and Manchester code.
As Virtualwire is a bit older, no longer supported, and supposedly can only send characters (though there is a way around that) I decided to use Manchester code.

To make a long story short, it didn’t work. I had the MANCHESTER.h and MANCHESTER.cpp file and ran into a lot of trouble, until I discovered that was the wrong/old library, you need the Manchester.h and Manchester.cpp file from here. When I used that I got my transmitter to work, I could send data to an Arduino, that was already a big relief.

However……. whatever I did, I did not get my receiver to work. In testing something on an Attiny it is very frustrating to just stare at an LED that is supposed to light, but doesnt, without knowing what and why and how.
So i decided to add an LCD to the Attiny, so at least I could see what was happening..
However, the LCD on my attiny gave me other problems… and when I solved those, that proved to be the solution for my receive problem as well: I was using the wrong core. I was using the ‘tiny core’ rather than the ‘attiny core’
The latter is the one from Highlowtech.
NOTE: it is generally accepted that the ‘tiny core‘ works with the Manchester code and the attiny core does not, so it is possible that I mixed up the two. However, I had a line added to the Attiny core that I forgot about that will make it work with the Manchester code. Open up  the “variants/tiny8/pins_arduino.h” file and add the line”#define __AVR_Attinyx5__”

attiny_manchester

The build of the transmitter is easy:
send-manchester-breadboard
Plug the attiny chip into your breadboard,
Connect a 433 MHz Transmitter module with its data in to pin PB0 (that is pin 5 on the chip).
Connect Vcc and Ground of the transmitter module to Vcc (pin 8) and ground (pin 4) of the Attiny
Insert a 10 k resistor between pin 1 (Reset) and pin 8 (Vcc)
Connect Vcc and ground to 5 Volt
Take a 17 cm stiff wire and attach that to the antenna hole of the transmitter.
use the following program:

#include <Manchester.h>
/*
  Manchester Transmitter example
  In this example transmitter will send one 16 bit number
  per transmission.
  Try different speeds using these constants, your maximum
  possible speed will depend on various factors like transmitter 
  type, distance, microcontroller speed, ...
  MAN_300 0
  MAN_600 1
  MAN_1200 2
  MAN_2400 3
  MAN_4800 4
  MAN_9600 5
  MAN_19200 6
  MAN_38400 7
*/
  #define TX_PIN 0  //pin where your transmitter is connected
  uint16_t transmit_data = 2761;
  void setup() {
  man.setupTransmit(TX_PIN, MAN_1200);
} 
void loop() {
  man.transmit(transmit_data);
  delay(200);
}

Just a word on the 2716 that I am sending. The program is not mine, I found it as such and since it worked and I was very happy to see the ‘2716’ appear in my Arduino after days of fruitless trying, I decided to leave it there as a tribute. (it might have found it here)

Building the receiver is easy:
receive-manchester-breadboardPut the programmed attiny chip in your breadboard.
Connect a 10 k resistor between pin 1 and pin 8
Put your 433 MHz Receiver module in the breadboard
Connect the datapin (usually either one of the two middle pins) to pin PB1 (physical pin6) on the attiny.
Connect the Vcc and Ground of the transmitter module to Vcc (pin 8) and Ground (pin4) of the Attiny
Connect the LCD interface to pin PB0 (pin 5) (Clock) and pin PB2 (pin 7) (Data/Enable)
Connect Vcc and ground of the LCD to Vcc and Ground.
Attach a 17 cm (1/4 lambda for 433 MHz) to the Receiver module.
Use the following program in your chip:

#include <Manchester.h>
#include <LiquidCrystal_SR.h>
LiquidCrystal_SR lcd(0,2,TWO_WIRE);
/*
  Manchester Receiver for Attiny
  In this example receiver will receive one 16 bit number per
  transmittion to switch a relay on or off. 
  try different speeds using these constants, your maximum possible
  speed will depend on various factors like transmitter type, 
  distance,  microcontroller speed, ...

  MAN_300 0
  MAN_600 1
  MAN_1200 2
  MAN_2400 3
  MAN_4800 4
  MAN_9600 5
  MAN_19200 6
  MAN_38400 7
*/
#define RX_PIN 1 //= pin 6
uint8_t moo = 1;
void setup()
{
lcd.begin(16,2);
lcd.home();
lcd.print("Receive");
lcd.setCursor(0,1);
  man.setupReceive(RX_PIN, MAN_1200);
  man.beginReceive();
}
void loop() {
  if (man.receiveComplete()) {
    uint16_t m = man.getMessage();
    man.beginReceive(); //start listening for next message right
                        //after you retrieve the message
   moo = ++moo % 2;
    lcd.print(m);
  }
}

The LCD is ofcourse optional. You can use an LED that gets the variable ‘moo’ send to its pin and thus will flash on complete receival of the signal, but I just wanted to make sure that what I got was what I sent

lcd-manchesterThe results are good, no garbage is being received, but the reach is about 4-5 meters, with the antennas. The antenna on the receiver only makes a small difference. The one on the Transmitter makes a big difference.
Still, this is surprising as the transmitter module is capable of switching remote switches at greater distances even on different floors.

With regard to the length of the Antennas:

as f * λ= c (frequency * wavelength = lightspeed)
λ=c/f
λ= 299,792,458 /433,920,000
The wavelength is 0.690893386 meters.
Antenna would be λ/4= 0.172723346 meters (17.3 cm)
That is about 6.80013 inches.
If you would be using 315 MHz modules, the antenna would be: 0.238 m or 23.8 cm

You can also use the wavelength calculator.
Supposedly the transmitter module can take 12 Volts and still be steered by a 5 Volt microcontroller pin and will have a further reach then. Increasing the voltage on the receiver of course makes no difference

Once you have established The link between two attiny’s, linking one of them with an arduino should not be a problem. I use mine to send data to an Arduino ( e,g. temperature, or the status of a tripwire), or to receive data from an Arduino to steer a servo or an RGB LED.

If you want to trigger a relay, you would do it like this:

void loop() {
  if (man.receiveComplete()) {
    uint16_t m = man.getMessage();
    man.beginReceive(); //start listening for next message 
                        //right after you retrieve the message
    moo = ++moo % 2;
    lcd.print(m);
    if (m==2761){digitalWrite(Relay,HIGH);}
    if (m==0000){digitalWrite(Relay,LOW);}
  }

Ofcourse you need to define the Relay pin in the ‘setup’

433 MHz system for your Arduino

With ELRO AB440, SelectRemote, Powertran, EverFlourish, Eurodomest, Dimmermodule, ProMax, Kambrook, Etekcity, Sonoff/Slampher, Digoo

Elro AB440
Elro AB440
PowerAcces288
PowerAccess 288

With the price of 433MHz Receivers and Transmitters being so ridiculously low, I figured I couldn’t put of using some any more so i ordered a pair at Dealextreme for less than 2 USD. When they arrived, of course I imediately wanted to test them.

I had an old IKEA set (SELECTREMOTE No. 1728029) also sold by Blokker at one time, and an Old HEMA set (PowerAccess, originally Ewig Industries RF AC socket 288A)) . The Selectremote 1728029 is most likely Equivalent to the Powertran A0342.

As I didnt really have an idea about the codes and as the transmitter of the SelectRemote was broken and the PowerAccess set being a learning one, it seemed best to get a new set.  (Actually, the Power Access turned out work on 419MHz, so no way I could have gotten that to work with my set up)

ELRO AB440

My preferred supplier ‘Action’ didn’t have, so on to ‘Blokker’ (both local stores) that had a set: The AB440 for 15 Euro. Apparently the manufacturer was ‘ELRO’. The chip in the remote control is an HX2262, a common chip in RC systems

I loaded one Arduino with an RF sniffer (Datapin on D2) and pressed ‘A on’ and yes, a code came through. pressed again and a different code came through, pressed again and 3 or 4 codes came through. That actually happened in all channels. One code seemed very frequent and I gathered maybe the protocol required to send more than one code, or maybe one code several times.

I decided to focus on just the one ON and OFF button and with just a gentle press, I seemed to come to two codes for the ON and 2 codes for the OFF button that seemed to recur most frequent.

Then I checked if indeed each of those codes had an actual function with regard to the socket being switched on or off, so with my RF sniffer still running, I prepared one of the switches as channel ‘A’ and tested again.

Behold….. it turned out that the Socket switch -in spite of a number of codes being put out by the remote control- only reacted to one specific code and indeed that was one of the two I had opted for.

Though I could analyse the code I figured that if i would just send the code I received the Switch would react to that and that the library would take care of the timing

So, I quickly adapted the Senddemo program to send the On and Off code for Channel A and plugged it back in. and yes, there it went clicking away, On, Off, On, Off.

So now I did the same for the B and C channel, isolated 2×2 codes that seemed the most likely and actually picked the right one immediately to put into the senddemo program and there it was… the 3 socket switches happily clicking away.

Just a few more remarks. As it shows in the output from the ‘Sniffer’ program, it is a 24 bits code. Of course that doesn’t look like any 24 bits code but that is because it is a decimal value. If I calculate the binary code it looks like this. (On and OFF codes) and u just add leading zero’s to come to 24

A 1049937 000100000000010101010001

A 1049940 000100000000010101010100

B 1053009 000100000001000101010001

B 1053012 000100000001000101010100

C 1053777 000100000001010001010001

C 1053780 000100000001010001010100

separated in ‘trits’ it looks like this (the ’29’ is the set number set by the 1st 4 switches):

on off on on on A B C D na ON/ OFF
00 01 00 00 00 00 01 01 01 01 00 01 29A aan
00 01 00 00 00 00 01 01 01 01 01 00 29A uit
00 01 00 00 00 01 00 01 01 01 00 01 29B aan
00 01 00 00 00 01 00 01 01 01 01 00 29B uit
00 01 00 00 00 01 01 00 01 01 00 01 29C aan
00 01 00 00 00 01 01 00 01 01 01 00 29C uit

The first 4 ‘trits’ represent the position of the dip switches that select the group. In my case that was on-of-on-on-on. ‘on’ is ’00’  which means tied to ground. ‘off’ is ’01’ which means ‘floating’. 10111=’23’  (2⁴ +0+ 2² +2¹+2⁰) but if you see the LSB as being on the right -as the library class does- it becomes ’29’ (2⁴+2³+2²+0+2¹)

The next 4 positions determine the Switch ID. The next trits is not applicable and the last two determine ON or OFF.

For RC use there are 2 main libraries  for the Arduino: the one of fuzzilogic (Randy Simons)  and the RCSwitch from Suat Özgür. As the ELROAB440 set was working with the latter, I initially stuck to the RCSwitch library.

/*
SendDemo - sends RF codes 
hacked from
http://code.google.com/p/rc-switch/ by @justy
*/
#include   
 // Use whatever number you saw in the RF Sniffer Sketch
#define A_aan 1049937
#define A_uit 1049940
#define B_aan 1053009
#define B_uit 1053012
#define C_aan 1053777
#define C_uit 1053780

RCSwitch mySwitch = RCSwitch();
void setup() {

pinMode(7, OUTPUT); // use pin 7 to drive the data pin of the transmitter.

// 
mySwitch.enableTransmit(7);
}
void loop() {

// Send your button's code every 5 seconds.
mySwitch.send(A_aan, 24);
delay(2000);
mySwitch.send(A_uit, 24);
delay(1000);
mySwitch.send(B_aan, 24);
delay(2000);
mySwitch.send(B_uit, 24);
delay(1000);
mySwitch.send(C_aan, 24);
delay(2000);
mySwitch.send(C_uit, 24);
delay(1000);
}
}

Now in hindsight I have been a bit stupid. If I had taken the time to read the documentation of the RCSwicth library, I would have found out that the library caters for 1he ’10 dip switch switches’ such as the ELRO AB440, as is shown in the program ‘TypeA_WithDIPSwitches.pde’

If I would have set the DIP Switches e.g. like “1011100100”, (for device ‘C’) I could have used the statements:

  mySwitch.switchOn("10111","00100");

and

  mySwitch.switchOff("10111","00100");

Well, let’s say ‘I learned a lot’. Just for completeness sake, it is obvious -if you compare it with the previous table- that the DIPSwitch position ‘ON’ doesnt send a ‘1’ but a zero. The code “1011100100”  is that of the  ‘C’ switch from the table above.

I still wondered why I couldn’t get the AB440 to work on the fuzzilogic library. With searching further I came upon an extension of the fuzzilogic library called RemoteSwitch (author Jeroen Meijer). That didnt work for the AB440 in first instance but Jeroen was kind enough to work through my data so it now has a separate class for the AB440. (code now on github).  (No longer on GitHub but here)

SELECTREMOTE

SelectRemote Nr. 1728029
SelectRemote Nr. 1728029

As I couldnt ‘sniff’ the  SELECTREMOTE No. 1728029 for lack of a functioning transmitter, and had no idea what codes it used, (Initially) I couldn’t get it to work yet with the RCSwitch library.

But I did get it to work with the Fuzzilogic RemoteSwitch library, as it was similar to the protocol of  a once popular ‘Blokker transmitter’

The code will look like this:

/*
* Demo for RF remote switch transmitter.
* Setup:
* - Connect a 433MHz transmitter to digital pin 7.
*/
#include 
// Instance of Blokker remote, use pin 7 
BlokkerTransmitter blokkerTransmitter(7);
void setup() {
}

void loop() {  
  // Switch on Blokker-device 1.
  blokkerTransmitter.sendSignal(1,true);
  // Wait 2 seconds
  delay(2000);
  // Switch off Blokker-device 1.
  blokkerTransmitter.sendSignal(1,false);
  // Wait 4 seconds
  delay(4000);
}

(Later on I would find the ON and OFF codes to be:

ON 1 : 0011 1111 0000 0011 0000 0000  //4129536

ON 2 : 0000 1111 0000 0011 0000 0000 //983808

ON 3 : 0011 0011 0000 0011 0000 0000 //3343104

ON 4 : 0000 0011 0000 0011 0000 0000 //197376

OFF 1 : 0011 1111 0000 0000 0000 0000 //4128768

OFF 2 : 0000 1111 0000 0000 0000 0000 //983040

OFF 3 : 0011 0011 0000 0000 0000 0000 //3342336

OFF 4 : 0000 0011 0000 0000 0000 0000 //196608

with “0” is 240us on, 740us off

and “1” is 740us on, 240us off)

It is clear that the 8 MSB determine the device address, whereas bits 8&9 determine the ON and OFF state. These codes can be used with the RCSwitch library

With the RemoteSwitch library the coding is as follows:

#include "RemoteSwitch.h"  
ElroAb440Switch ab440Switch(7); 
BlokkerSwitch3 blokkerTransmitter(7);
 void setup() { } 
void loop() 
{ //Switch on SelectRemote 1728029 device 1 
blokkerTransmitter.sendSignal(1,true); 
//Switch on AB440-device B on system code 29. 
// dip switch 1-5 is on-off-on-on-on = 10111... but is read as 11101='29' 
ab440Switch.sendSignal(29,'B',true); 
delay(2000); blokkerTransmitter.sendSignal(1,false); 
ab440Switch.sendSignal(29,'B',false); 
delay(2000); 
}

Powertran A0342

A0340_2
Powertran

The Powertran A0342 is very akin to the the Selectremote, albeit that it has 8 channels rather than 4, divided over 2 banks that can be selected by a slideswitch on the transmitter. It works with the Blokkerprotocol in the RemoteSwitch library. If you do not want to use a library, because it  adds overhead,you can also use the program below, that will also work with the 4 channel Selectremote

https://codebender.cc/embed/sketch:237833

#define radioPin           // IO number for radio output
void setup() {
pinMode(radioPin, OUTPUT); // set data to transmitter pin to output
}
void loop() {
remoteControl(1,0);                     // Turn Remote 1 off
remoteControl(2,0);                     // Turn Remote 2 off
remoteControl(3,0);                     // Turn Remote 3 off
remoteControl(4,0);                     // Turn Remote 4 off
remoteControl(5,0);                     // Turn Remote 5 off
remoteControl(6,0);                     // Turn Remote 6 off
remoteControl(7,0);                     // Turn Remote 7 off
remoteControl(8,0);                     // Turn Remote 8 off
delay(5000);                            // Delay 5 seconds
remoteControl(1,1);                     // Turn Remote 1 on
remoteControl(2,1);                     // Turn Remote 2 on
remoteControl(3,1);                     // Turn Remote 3 on
remoteControl(4,1);                     // Turn Remote 4 on
remoteControl(5,1);                     // Turn Remote 5 on
remoteControl(6,1);                     // Turn Remote 6 on
remoteControl(7,1);                     // Turn Remote 7 on
remoteControl(8,1);                     // Turn Remote 8 on
delay(5000);                            // Delay 5 seconds
}
void remoteControl(int channelNum, boolean remoteState) {
// Turns on or off remote channel
//
// channelNum  : 1 to 8 remote channel number (set on wireless plugpack
// remoteState : 0 = Off, 1 = On
//
// Sends same packet signal 4 times
// 13 Bit pattern in remoteOn and remoteOff arrays

int longTime              = 740;         // microseconds
int shortTime             = 240;         // microseconds
unsigned int remoteOn[8]  = {0x010E,     // 0000 0001 0000 1110
0x010C,     // 0000 0001 0000 1100
0x010A,     // 0000 0001 0000 1010
0x0108,     // 0000 0001 0000 1000
0x0106,     // 0000 0001 0000 0110
0x0104,     // 0000 0001 0000 0100
0x0102,     // 0000 0001 0000 0010
0x0100};    // 0000 0001 0000 0000
unsigned int remoteOff[8] = {0x000E,     // 0000 0000 0000 1110
0x000C,     // 0000 0000 0000 1100
0x000A,     // 0000 0000 0000 1010
0x0008,     // 0000 0000 0000 1000
0x0006,     // 0000 0000 0000 0110
0x0004,     // 0000 0000 0000 0100
0x0002,     // 0000 0000 0000 0010
0x0000};    // 0000 0000 0000 0000

// "0" is 240us on, 740us off, 240us on, 740us off
// "1" is 740us on, 240us off, 740us on, 240us off
// Send order is bit0, bit1, bit2 ... bit 12

// Now send packet four times
for (int j=0; j<=4; j++) {
if (remoteState) {                  // Turn on
for (int k=0; k<=12; k++) {       // Send 13 bits in total
if (!bitRead(remoteOn[channelNum-1],k)) {
digitalWrite(radioPin, HIGH);           // "0"
delayMicroseconds(shortTime);
digitalWrite(radioPin, LOW);
delayMicroseconds(longTime);
digitalWrite(radioPin, HIGH);
delayMicroseconds(shortTime);
digitalWrite(radioPin, LOW);
delayMicroseconds(longTime);
} else {
digitalWrite(radioPin, HIGH);           // "1"
delayMicroseconds(longTime);
digitalWrite(radioPin, LOW);
delayMicroseconds(shortTime);
digitalWrite(radioPin, HIGH);
delayMicroseconds(longTime);
digitalWrite(radioPin, LOW);
delayMicroseconds(shortTime);
}
}
} else {                            // Turn off
for (int k=0; k<=12; k++) {       // Send 13 bits in total
if (!bitRead(remoteOff[channelNum-1],k)) {
digitalWrite(radioPin, HIGH);           // "0"
delayMicroseconds(shortTime);
digitalWrite(radioPin, LOW);
delayMicroseconds(longTime);
digitalWrite(radioPin, HIGH);
delayMicroseconds(shortTime);
digitalWrite(radioPin, LOW);
delayMicroseconds(longTime);
} else {
digitalWrite(radioPin, HIGH);           // "1"
delayMicroseconds(longTime);
digitalWrite(radioPin, LOW);
delayMicroseconds(shortTime);
digitalWrite(radioPin, HIGH);
delayMicroseconds(longTime);
digitalWrite(radioPin, LOW);
delayMicroseconds(shortTime);
}
}
}
delay(5);              // Short delay between packets
}
delay(10);                // short delay after sending
}

EverFlourish EMW203RW

Another popular RC system is the Chinese EverFlourish EMW203RW from the German DIYMaxeda group  (Praxis, Formido, Brico, Plan-It). It is a sturdy outdoor (green) or indoor (white) switch with a transmitter for 3 switches. They can be set to 4 channels. Were sold as Cotech by Clas-Ohlsson

IMG_20150218_151133
EMW203RW outdoor switch

emw203
EMW203RW indoor switch

The 24 bit codes (for Channels A and B) are as follows: (on-off / decimal-binary)

A1 1381719 1381716 / 000101010001010101010111 000101010001010101010100

A2 1394007 1394004 / 000101010100010101010111 000101010100010101010100

A3 1397079 1397076 / 000101010101000101010111 000101010101000101010100

B1 4527447 4527444 / 010001010001010101010111 010001010001010101010100

B2 4539735 4539732 / 010001010100010101010111 010001010100010101010100

B3 4542807 4542804 / 010001010101000101010111 010001010101000101010100

To make sense of this code, it is easiest to separate them in ‘trits’. Let’s look at the ‘on’ code for ‘A1’ :

00 01 01 01 00 01 01 01 01 01 01 11
A B C D 1 2 3 na na na na ON

The first four trits set the device_address (A-D) with a selected letter grounded (00) and the nonselected floating (01)., the next 3 the Switch id (1-3) then there are 4 non relevant trits and then one trit for on (11=High) or off (00=grounded).

‘B1-ON’, according to that logic, should then be:

01 00 01 01 00 01 01 01 01 01 01 11
A B C D 1 2 3 na na na na ON

which -as we can see in the sniffed code- is correct. This code looks very much like the one for  the ‘Blokker2’ class in the addition Jeroen Meijer made to the fuzzylogic library. It now has a separate class. (Library moved here)

#include "RemoteSwitch.h"
EverFlourishSwitch everswitch(7);
void setup() {
}
void loop() {  
  everswitch.sendSignal('A', 1, true);
  //wait 2 seconds
  delay(2000);
  everswitch.sendSignal('A', 1, false);
  delay(2000);
}

EuroDomest 972080

‘Action’ is currently selling the EuroDomest 972080 system: 3 switches + remote control for 9.99 euro. This is a learning system that will not lose the

eurodomest
Eurodomest 972080

settings if taken out off the wall-socket (at least not for a while. These receivers supposedly can learn the old kaku_switch protocol. They are receptive to remotes of other systems when programmed as such, but I found that they do not always recognize the  codes sent by other remotes during programming  so you may only be able to only switch on or off a lamp when programmed with another remote.

The manual of the Eurodomest is a a bit cryptic in how to program the switches. This is how it is done:

Plug in a switch and  push the ON button on the switch until the led starts flashing slowly. Then  push the ON button on the remote: the LED on the switch now should start to flash quickly. Press the OFF button on the remote toll the LED goes off. Your switch is now programmed. (on second thought, most likely pressing the OFF button isnt even necessary)

The remote (at least in my case)  sends the following codes:

Channel 1 ON/OFF

Received 9588047 / 24bit Protocol: 1   100100100100110101001111

Received 9588046 / 24bit Protocol: 1   100100100100110101001110

Channel 2 ON/OFF

Received 9588045 / 24bit Protocol: 1   100100100100110101001101

Received 9588044 / 24bit Protocol: 1   100100100100110101001100

Channel 3 ON/OFF

Received 9588043 / 24bit Protocol: 1   100100100100110101001011

Received 9588042 / 24bit Protocol: 1   100100100100110101001010

Channel 4 ON/OFF

Received 9588039 / 24bit Protocol: 1   100100100100110101000111

Received 9588038 / 24bit Protocol: 1   100100100100110101000110

Channel ALL ON/OFF

Received 9588034 / 24bit Protocol: 1   100100100100110101000010

Received 9588033 / 24bit Protocol: 1   100100100100110101000001

It is clear to see that the signal only changes by 1 bit, though it is a bit odd that there seems to be an unlogical difference between channel 3 and 4 as one would expect “100100100100110101001001”  for ON and “100100100100110101001000” for OFF.

Also the All ON/OFF seems a bit out of order.

Sending these codes as is with the RCSwitch library works fine. It seems impossible to figure out what the  device code  for a random set would be, so you would need to first sniff the remote control, or, just send a chosen code with a 433MHz transmitter from an Arduino (or other micro controller).

The Eurodomest protocol is very akin to that of the ENER002, that in itself is akin to the Duwi/Everflourish EMW200R. It has the HS2303-PT chip rather than the PT2262. The Eurodomest might be the same as the Bauhn remote switch set. The ENER002 has its own class in the Jeroen Meijer update of the Fuzzilogic library. ( Now on gitlab.)

If you want to use channel 4, make sure you have the most recent update of the Jeroen Meijer library

Program would look like this:

#include "RemoteSwitch.h"
Ener002Switch enerswitch(7);
void setup() {
}
void loop() {
enerswitch.sendSignal(823148, 1, true); //channel 1
delay(1000);
enerswitch.sendSignal(823148, 1, false);
delay(1000);
enerswitch.sendSignal(823148, 2, true); //channel 2
delay(1000); 
enerswitch.sendSignal(823148, 2, false);
delay(1000);
enerswitch.sendSignal(823148, 3, true); //channel 3
delay(1000); 
enerswitch.sendSignal(823148, 3, false); 
delay(1000); 
enerswitch.sendSignal(823148, 4, true); //channel 4
delay(1000); 
enerswitch.sendSignal(823148, 4, false); 
delay(1000);
enerswitch.sendSignal(823148, 7, true); // ALL
delay(1000); 
enerswitch.sendSignal(823148, 7, false); 
delay(1000); 
}

The  ‘823148’is the  decimal form of the first 20 bits that form the set address (for a particular Transmitter)

If you do not have that number… just use any 20 bits number, and  use the arduino to program your  Eurodomest. The ‘7’  means ‘All’. As per Januari 2016 the Eurodomest is phased out at the Action stores and is being replaced by the ProMax. The Eurodomest is the same one as the Efergy remote (Efergy Easy Off).

LED Dimmer

1set-Single-Color-Remote-Control-Dimmer-DC-12V-11keys-Mini-Wireless-RF-LED-Controller-for-led
LED dimmer

The full credit of this goes to Jeroen Meijer who analysed the protocol of a popular RF Led dimmer driver available in Chinese webshops.

The code is very akin to that of the Eurodomest, albeit that it has a 19 bit address and a 5 bit command structure.

His fork of the RemoteSwitch library contains a class -CnLedDim1Switch- to control this dimmer.

The codes are also easy to snif. The left 19 bits forming the base address of the device.

So if pressing the button ‘ON’  generates the code:

on      6670849 / 0110010111001010000 00001,

then ‘0110010111001010000’ or ‘208464’ is the baseaddress and ‘00001’ the command code.

A program would be like this:

#include "RemoteSwitch.h"
CnLedDim1Switch ledDimSwitch(7);
const unsigned long dimaddress = 208464;
const byte pwr = 1;
const byte licht = 4;
const byte BrightUp = 5;
const byte BrightDown = 6;
const byte Full = 7;
const byte Half = 8;
const byte Quart = 9;
const byte Mode = 11;
const byte SpeedUp = 13;
const byte SpeedDown = 15;

void setup(){}

void loop()
{
ledDimSwitch.sendSignal(dimaddress,Quart);
delay(1000);
ledDimSwitch.sendSignal(dimaddress,Half);
delay(1000);
ledDimSwitch.sendSignal(dimaddress,Full);
delay(1000);
}

ProMax 75.006.14 / Elro Flamingo F500S

promax
Promax Intek 75.006.14

The Promax 75.006.14 is currently (early 2016) sold at Action stores (Netherlands) as a follow up for the Eurodomest. It is a sleek design, but appears to be difficult to implement. As it turns out the transmitter sends out several protocols.

.

Although you may find reference on internet that the transmitter of this set sends two codes per key, that is in fact not true: it sends 4 codes per key. Two of those codes can be found with the RCSwitch library sniffer and 1 can be found with the RemoteSwitch library sniffer example. The RC found  protocols are apparently  the ‘AC’ protocol and the HomeEasy EU protocol. The RemoteSwitch-found protocol seems to be a Kaku2 protocol, but sadly none of those codes work on the ProMax Switches. For that you need the 4th code (actually it is the 1st code it doesnt detect).

There are several ways to find that code. You could use the so called “Poor man’s oscilloscope” in which you connect the soundcard of your computer via a voltage divicer to a 433MHz receiver, record the keypushes with Audacity and try to work out from there what the codes of your transmitter are. There is also another way:

As device the ProMax is akin to the Elro Flamingo F500S  therefore it is the Flamingo sniffer program that could be used. This renders 28bits codes, add a zero on the end to make it fit a uint32_t bit word. The Promax is similar to the Elro Flamingo F500S, Mumbi m-FS300 and possibly the SilverCrest 91210.  As the the Promax protocol has rolling code per key, you may find 16 different codes per key. Take one, if that does not work, pick another. As during pairing with your tansmitter you only need to send the ON code, after wich the switch knows how to react to the off code and the master buttons, it is obvious there is a relation between the ON and OFF codes. In fact, the OFFcode can be calculated from the ON code. Each ProMax can be programmed with 5 codes. Be carefull to not program it with randomcodes, because you need the corresponding OFF code to remove the code.There is also another way. Find some working Flamingo codes from the internet and program your switches with those and use this program to send the codes from yr arduino. As the promax has the possibility to store 5 codes per switch, you can also program it with the Remote. That way you have switches that react to the remote as well as to the Arduino. Once you have founde the codes, having your arduino send them to the Switch is fairly easy: First send a sync signal that is HIGH for 300usecand low for 1500usec. Then send a ‘0’ (bit) as  HHHL with a periode of 300uS and the ‘1’  as HLLL. The Class Ohlson Co/Tech 51058×10 is probably similar too, albeit that its sends 4 rolling codes

Beware, the ProMax sold at action is NOT this one.

Flamingo SF-500WD/2

SF-500WD/2In the fall of 2017 Action started selling the Flamingo SF-500WD/2 remote for 9.95 euro whereas regular retail price is arond 17 euro. The SF-500WD/2 is a 2 switches-1 remote Outdoor remote set for which i have not been able to find any codes yet. Apparently it is recognized by RFlink.  A manual is available.

Kambrook RF3399

KambrookRF3672
Kambrook

The Kambrook, made by Ningbo, is a bit of a different RF switch as the RemoteSwitch and RCswitch libraries don’t detect it as it has a 48 bit packet size. A fork of the RCSwitch library has a 4th protocol added to make it work with the Kambrook.

In the Kambrook a short pulse is constructed from a 280uS wide pulse, followed by 300uS off period. The long pulse consisted of a 675uS wide pulse, followed by a 300uS off period. The message is repeated 5 times with a gap of 9850us in between.

The signal consists of  48 bits: it starts with an 8 bit sync signal thart is typically 01010101. That is followed by 24 (3×8) address bits. Then 8 databits, followed by 8 trailing bits, typically 11111111.

The databits determine the switch and wether it is on or off

Unit Data Data (decimal)
A1 ON 00000001 1
A1 OFF 00000010  2
A2 ON 00000011  3
A2 OFF 00000100  4
A3 ON 00000101  5
A3 OFF 00000110  6
A4 ON 00000111  7
A4 OFF 00001000  8
A5 ON 00001001  9
A5 OFF 00001010  10
B1 ON 00000101  17
C1 ON  00100001 33
D1 ON  00000001 49

Arduino code for the Kambrook is here.

Nexa, Proove, Anslut

nexaDetails on how to drive these switches is described here, and here more on the Ikea Ansluta., and the Nexa.

The Nexa looks a lot like the KlikAanKlikUit APA3-1500R, which -in lieue of a transmitter- can be programmed by the transmitter of the Action ProMax 75.006.14 / Elro Flamingo F500S

Kaku APA3 1500R

apa3-1500r-1

This set is a selflearning set, that is catered for in the Remote Switch library. The transmitter can be used to program the receivers, but it is also possible with a program like:

#include "RemoteSwitch.h"
KaKuSwitch kaKuSwitch(11);
void setup() { }
void loop() {
 	kaKuSwitch.sendSignal('A',1,true);
 	delay(2000);
        }

That will set the switch to “Switch A, channel 1” after wich

kaKuSwitch.sendSignal('A',1,true);
kaKuSwitch.sendSignal('A',1,false);

will switch it ON or OFF.

As said above: In lieue of a transmitter, the APA3 1500R can be programmed by the transmitter of the Action ProMax 75.006.14 / Elro Flamingo F500S

Etekcity

etek4Etekcity is a popular brand that has several types. The popular 5Rx-2TX/learning code consist of 5 outlet switches and 2 transmitters. The transmitters have 5 ON and 5 OFF buttons. The coding is rather simple: it has a 24 digit code in which the last 4 bytes signal ON (0011)  or OFF (1100). The next 5 byte pairs (so bit 4 to bit 13) indicate the number of the button (both bytes in pair 1-5 high if button 1-5 is pressed.  bytes 4-7 are always ‘0’ unless the button for that position is pressed, bytes 8-13 are always ’01 unless the button for that position is pressed. The remaining bytes form the base address of the hand transmitter. The pulswidth is 190uS. The below table clarifies it:

Button On/Off address 5 4 3 2 1 Off/On
1 “on” 00 00 01 01 01 01 01 01 00 11 0011
“off” 00 00 01 01 01 01 01 01 00 11 1100
2 “on” 00 00 01 01 01 01 01 01 11 00 0011
“off” 00 00 01 01 01 01 01 01 11 00 1100
3 “on” 00 00 01 01 01 01 01 11 00 00 0011
“off” 00 00 01 01 01 01 01 11 00 00 1100
4 “on” 00 00 01 01 01 01 11 01 00 00 0011
“off” 00 00 01 01 01 01 11 01 00 00 1100
5 “on” 00 00 01 01 01 11 01 01 00 00 0011
“off” 00 00 01 01 01 11 01 01 00 00 1100

As it is a learning remote, one will have to sniff the code of the transmitter, or use the code above.

EtekcityAnother popular Etekcity model has a remote with only 5 buttons for on and off. The code here is fairly simple as well as shown in the table below

button Address 5 4 3 2 1
1. 00 01 11 01 01 01 01 00 00 00 00 11
2. 00 01 11 01 01 01 01 00 00 00 11 00
3. 00 01 11 01 01 01 01 00 00 11 00 00
4. 00 01 11 01 01 01 01 00 11 00 00 00
5. 00 01 11 01 01 01 01 11 00 00 00 00

PulseLength: 162 microseconds Protocol: 1

Intertechno

arc2300The PB3-230 is a remote powerswitch made by Intertechno. The are also sold under the name ARC PB3-2300 or Nexa PB3-2300. There is a library available.

SonOff/Slampher

sonoff-rf_06The Sonoff and Slampher are two devices sold by Itead. They come in several versions either controlled by WiFi, by RF or by both. The transmitter is a 4 button device (beware, it is often sold seprately) that sends out 24 bit codes in which the first 20 bits are the same and the last 4 just indicate binary 1, 2, 8 or 16.

These buttons can control 4 sonoffs as they are meant as toggle buttons rather than On/Off buttons. The set up is as follows: Quickly press “SET” button on Sonoff and Slampher twice, the red LED on Sonoff/Slampher will flash one time, then press one of the ABCD buttons on the controller once for a few seconds for pairing. If you pair it with A, then you can press A to turn on/off your device. The transmitter sends the following codes:

Button Decimal Binary
A 11708433 10110010101010000001 0001
B 11708434 10110010101010000001 0010
C 11708436 10110010101010000001 0100
D 11708440 10110010101010000001 1000

As the WiFi use of the sonoff and slampher is through a specific website, there are many software hacks available (it contains an ESP8266). If you reflash it with new software, there is no garantee that the RF function will be kept.

Digoo RC-13

The Digoo RC-13 Smart Home RF Wireless Remote Control Socket comes with 3 sockets and either a 3 channel or a 5 channel remote.

the remote transmits the following 24 bit codes

1 ON 10001111111000110000 1001
1 OFF 10001111111000110000 0001
2 ON 10001111111000110000 1010
2 OFF 10001111111000110000 0010
3 ON 10001111111000110000 1100
3 OFF 10001111111000110000 0100

It is clear to see that the device number is defined in the last 3 bits, whereas the ON/OFF code is defined in the 4th bit from the right. The first 20 define the ID of the set. The Transmitter is based around the EV1527 chip. The encoding protocol is the same for every EV1527 device. 24bit total, the first 20 bit is the ID or address and the last 4 bit are data.
The timing is the duration of one bit (bit length) and is defined as 256 clock cycli. A resistor and a capacitor define the frequency of the clock oscillator. It is explained in the datasheet.

Some further 433 resources:

RC-Switch Downloads,

A new way to interface with remote power switches

How to operate Low Cost Outlets

askOOK decoding

433 MHz rf module with Arduino Totorial

Decoding and sending 433 MHz Rf codes with Arduino and RC switch,

433 MHz rf module with Arduino Totorial

Some usefull example codes for the Arduino on github:

ninjablocks 433Utils.

Handy RF sniffer (Datapin on D2) and  Senddemo sketch (Datapin on D7).

The Powertran Remote Control.

Measuring light with an Arduino

ldrThe easiest way to measure light with an Arduino is with an LDR.
LDR’s (Light dependend resistors) have a low resistance in bright light and a high resistance in the darkness.
If you would us the LDR as the lower part of a voltage divider, then in darkness there would be a high voltage over the LDR, while in bright light, there would be a low voltage over that resistor.
Ofcourse if you would use it as the upper part of a voltage divider, it would be the reverse: low voltage in the darkness, high voltage in bright light

Doing that on an Arduino Analog port, would give a reading between 0 and 1024, which ofcourse are really non-descriptive numbers.
What you would want is an output in Lux or Lumen
That is possible but mind you that LDR’s are not really accurate for precise readings.
There is a somewhat rough formula that relates the resistance of an LDR to the light in Lux. That is:
Rldr=500/Lux, or
Lux=500/Rldr (in kOhm)

as Rldr is related to the voltage measured over it, reading the Voltage over it, can be used to calculate the Rldr and thus the Lux level
If the LDR is the lower part of a 5 Volt Voltage divider and a 10kOhm resistor the upper part, the Voltage will be:
Vout=(5/(10+Rldr))*Rldr
Vout=5*Rldr/(10+Rldr)
(remember: multiplication before division)
as we do not measure a voltage, but a value between 0 and 1024, every step can be defined by 5/1024=0.0048828125.
=> Vout=Analogreading*0.0048828125
as Rldr=(10Vout)/(5-Vout) (remember Rldr is expressed in kOhm)
=> Lux=(500*(5-Vout))/(10*Vout)
=> Lux=(2500-500*Vout)/(10*Vout)
=> Lux=(2500/Vout-500)/10
=> Lux=(2500/((AnalogRead*0.0048828125)-500))/10

Anyway, in an arduino program that will look like:

//Lux
double Light (int RawADC0){
double Vout=RawADC0*0.0048828125;
//int lux=500/(10*((5-Vout)/Vout));//use this equation if the LDR is in the upper part of the divider
int lux=(2500/Vout-500)/10;
return lux;
}
void setup() {
Serial.begin(115200);
}
void loop() {
Serial.println(int(Light(analogRead(0))));
delay(1000);
}

Anyway, as said, an LDR is not the most accurate to measure light intensity. A photodiode would be better

Full work out of the Formula, for those interested (remember, this expresses Rldr in kiloOhm and is for a 10kOhm reference resistor:
Vout=(5Rldr)/(Rldr+10)
5Rldr=Vout(Rldr+10)        // multiplied both sides with (Rldr+10) and switch left and right
5Rldr=Vout*Rldr+10out     // executed the right side multiplication
5Rldr+(-Vout*Rldr)=(Vout*Rldr+10Vout)+(-Vout*Rldr)   //added equal value (-Vout*Rldr) to both sides
5Rldr+(-Vout*Rldr)=Vout*Rldr+10Vout-Vout*Rldr        // work out right side  additions and subtractions
5Rldr-Vout*Rldr=Vout*Rldr+10Vout-Vout*Rldr           //work out left side additions and subtractions
5Rldr-Vout*Rldr=Vout*Rldr-Vout*Rldr+10Vout           // ditto
5Rldr-Vout*Rldr=10Vout     //ditto
Rldr(5-Vout)=10Vout        //expressed left side as multiplication of Rldr
Rldr=10Vout/(5-Vout)       // divided both sides by equal value (5-Vout)

For a reference resistor other than 10k the soluton is as follows
Rldr=(Rref*Vout)/(5-Vout)
Also.. remember that though we expressed the value of Rldr as a function of Vout, ofcourse the value does not depend on Vout, it is the other way around, but it is necessary to inject the function of Vout into the Lux formula

Identifying and using a stepper motor on Arduino

If you buy a new steppermotor for a project there is usually some documentation telling you how to connect it.
However, we do not always buy steppermotors with documentation: sometimes you have an old one, sometimes you pull it out of an old unused device or get it from a surplus store.
P1040286

I found a steppermotor that I had probably bought 30-35 years ago and never used (over ambitious). It did not offer much info other than: 55SI-25D AWC 7.5 DEG 36 Ohm and that it was from Oct 83 and came from Japan. It had six wires, but other than some handwritten labels mentioning colors and numbers (that were even corrected), it offered no clue on what connection was what. Initially, also the internet offered no help other than some questions about that type of motor (Although I recently found some info [now gone]).

So, how to identify what was what? Well first the number of  connections –6-   (brown, yellow, blue, red, white and white) suggested it was a unipolar steppermotor and I suspected the two white ones to be the common connection. To establish how the rest of the wires where connected it was time for the multimeter and I set up a small table in which I could enter the resistance values I measured:

white 1 white 2 red blue yellow brown
white 1 x 36Ω 36Ω
white 2 x 36Ω 36Ω
red 36Ω x 72Ω
blue 36Ω x 72Ω
yellow 36Ω 72Ω x
brown 36Ω 72Ω x

For those having trouble reading the symbols: ∞ means that there was an infinite resistance (i.e. not connected) and x means that there is no need to measure it as it is the same wire.

If you don’t have a multimeter, it becomes a bit harder but then you can also find which coils belong together: if you short a coil the resistance in manually turning the axis increases

unipolarcoilsObviously this was a motor with 4 coils, that each have a white common connector and the table tells us that red and brown are the coils connected to ‘white 1’ and that yellow and blue are the pair with ‘white 2’ as a common connector.

However, with a unipolar stepper the coils need to be driven in a certain sequence, otherwise the motor won’t turn at all, or will have only little power and though from the table we now know what coils belong to a pair, we still do not know what the sequence of the coils is.

In other words take for instance the red and the brown pair. Is red coil 1 and brown coil 2 or is it the other way around?  Well, that is a bit tricky because even the numbering of the coils is not always standard.

There is a way of measuring which coil is which, by applying voltage to one coil and then adding voltage to another coil, while feeling if the shaft turns at all and what way. But that is actually just as much work as connecting it to an arduino and switching a few pairs of wires to test. Once you have established –as we did in the table above-  what pairs are connected. It is really not that much work anymore.

coilsSo for now let’s forget about coil numbers and look a bit more at the functions and how to drive the coils.
So, for the time being we will just call them coil 1a,1b, 2a and 2b. we don’t know which one is a and b but we do know that it is the red-brown pair vs the blue yellow pair.

As none of the coils belonging to the same pair should be energized at the same time, the sequence must be either:
red yellow brown blue
or
red blue brown yellow.
As it turns out, it is red-yellow-brown blue to turn the motor clockwise and yellow-red-blue-brown to turn the motor counter clockwise

There are in fact 4 ways of  driving a steppermotor:

  • Wave driving (sometimes also called (“one-phase on, full step” ) is the simplest as only one coil is on at any one time. This uses least current but also produces the least amount of torque. The coil activation sequence would be: 1a-2a-2b-1b-1a etc
  • Half stepping is done by alternating between activating a single coil and two coils at the same time. Due to the smaller step angle, this mode provides twice the resolution and smoother operation. Half stepping produces roughly 15% less torque than dual phase full stepping. Modified half stepping eliminates this torque decrease by increasing the current applied to the motor when a single phase is energized. The torque fluctuates between utilising a single coil and both coils. the coil activation sequence would be:
    1a-1a2a-2a-2a1b-1b-1b2b-2b-2b1a,
  • Full stepping (sometimes also called  “two-phase on, full step”) is when two coils are always energised at the same time. This gives the motor maximum torque but will require more current more current. This looks like: 1a2a-2a1b-1b2b-2b1a.
  • Microstepping is a technique that increases motor resolution by controlling both the direction and amplitude of current flow in each winding. Current is proportioned in the windings according to sine and cosine functions. Microstepping is at the expense of drastic loss in torque. On the Arduino microstepping can be achieved  with PWM. However, unless you really need it, I wouldnt bother

To drive the motor continuously, we just apply power to the two windings in sequence. Assuming positive logic, where a 1 means turning on the current through a coil, the following two control sequences will each spin the motor clockwise 24 steps:

  Winding 1a 1000100010001000100010001
  Winding 1b 0010001000100010001000100
  Winding 2a 0100010001000100010001000
  Winding 2b 0001000100010001000100010
              time --->

  Winding 1a 1100110011001100110011001
  Winding 1b 0011001100110011001100110
  Winding 2a 0110011001100110011001100
  Winding 2b 1001100110011001100110011
              time --->

Note that the two halves of each winding are never energized at the same time. Both sequences shown above will rotate a permanent magnet one step at a time. The top sequence only powers one winding at a time, as illustrated in the figure above; thus, it uses less power. The bottom sequence involves powering two windings at a time and generally produces a torque about 1.4 times greater than the top sequence while using twice as much power.

Anyway, a simple program to test the motor would be:

int motorPin1 = 8;
int motorPin2 = 11;
int motorPin3 = 10;
int motorPin4 = 9;
int delayTime = 500;

void setup() {
  pinMode(motorPin1, OUTPUT);
  pinMode(motorPin2, OUTPUT);
  pinMode(motorPin3, OUTPUT);
  pinMode(motorPin4, OUTPUT);
}

void loop() {
  digitalWrite(motorPin4, LOW);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin1, HIGH);
  delay(delayTime);
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin3, HIGH);
  delay(delayTime);
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin4, LOW);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin2, HIGH);
  delay(delayTime);
  digitalWrite(motorPin1, LOW);
  digitalWrite(motorPin2, LOW);
  digitalWrite(motorPin3, LOW);
  digitalWrite(motorPin4, HIGH);
  delay(delayTime);
}

Now you cannot of course run the motor directly from the arduino ports. You can do this with special Motordrive IC’s like the L298D or with discrete components such as power transistors or FET’s, but a fairly cheap and simple IC that can be used is the ULN2003 darlington driver (or the MC1413).

A note though: with 6 wire unipolar steppermotors you can decide to forget about the  middle connectors (the ‘whites’ in this case) and drive them like a bipolar. That is something you cannot do  with a ULN2003, you need an H- bridge for that

If you do not know the voltage of a motor, then just start with 5 Volts and go up. Many steppers are actually 12 V. The ULN2003 can take 50 Volts and deliver 500mA per gate. As the motor I use has a coil resistance of 36 Ohm and the Voltage is 12Volt, that will be 333mA so that should be OK. Nevertheless, if you plan on using the motor at high speed, some cooling of the ULN2003 might be a good idea. There are DIL heat sinks available but you could also epoxy a piece of copper or aluminium U-tube on it. The ULN2003 is not the most efficient chip and the Darlington has a high voltage drop. The chip therefore dissipates a lot of energy.

Wire it up as follows:

uln2003-test

The connections of the header are chosen as above since that was the sequence of the header on the motor (but remember red-brown are a pair and yellow red are a pair).

On using the test program above, the following connections would make the motor step properly:

D8-> red
D11->brown
D10->yellow
D9->blue

This seems as one would expect coz it is the 1a,2a,1b,2b or at least the 1x2x1y2y sequence. Similarly, one would expect that

D8 –>red
D11->blue
D10->yellow
D9->brown

(basically switching ‘1’ and ‘2’)  would make the motor step backwards and it does.

When the motor is used with the ‘Stepper.h’ library from the Arduino (e.g. in the Tom Igoe “Stepper_oneStepAtATime”), we see the same results.

For those interested to try the stronger torque program and try some direct bit manipulation at the same time have a look here:

As the steppermotor takes up 4 of the 7 outputs, you may want to consider using the other 3 to drive relais or a couple of small dc motors. The outputs of the ULN2003 may be parallelled for higher output current. The 3 darlington’s left therefore could drive a 1.5 Amp load.

If you need to drive two steppermotors consider the 2803 as that contains 8 darlington drivers rather than 7.

However, there is something else you can do with the spare gates, Remember the stepping sequence t o drive the motor?

Steps Coil 1 Coil 2 Coil 3 Coil 4
1 1 0 1 0
2 1 0 0 1
3 0 1 0 1
4 0 1 1 0
1 1 0 1 0

There is a pattern in this table: Coil 1 is always the opposite of Coil 2 and the same goes for Coil 3 and 4. It is therefore possible to cut down on the number of pins from the Arduino (or other microcontroller) to just two, by using additional NOT gates.

The ULN2003 can provide these:

uln2003-2lines

Programming then is very easy by toggling the two pins high and low.

If doing work with the Arduino and a stepper motor, consider AccelStepper as a library. It is more flexible.
MOTEUR55SI
Good site here (Spanish) and translated

Driving an Attiny? or here.
here
Steppermotor wiring.

Serial connection for your Arduino / Atmega

A connection between a computer and a self build Arduino (or other microcontroller) is easy to make with a MAX232 chip. The figure below is an almost classic design. It is according to the october 2002 revision of the datasheet: C4 is connected between pin2 and earth, while in other designs it is connected between pin 2 and Vcc (kathode on Vcc). This circuit just worked for me. I guessed that if pin 2 has a higher potential than Vcc, it also has a higher potential than ground. In some circuits you will also find it connected between pin 2 and 6

In principle you could do with only 2 signals (Tx and Rd), but I have added a reset that is connected to the RTS signal on the subD connector (Via the Max232 of course) MAX232

Just for some clarification: Normally with a serial communication set up, the Tx signal of one device, is connected to the Rd pin of the other device. In this circuit, that is taken care of on the SubD connector: Pin 3 is the Tx signal, that goes to the RdIn (pin 8)  of the chip. It is converted in voltage in the chip, then goes to RdOut on pin 9. That pin –though called Rd-  then goes to the Rd pin on the Arduino/Atmega/Pic. The connection between Tx and Rd already has been made, no need to switch that again.
Same for the Tx signal of the microprocessor: It attaches to pin10 on the Max232, is converted and appears on pin 7 of the chip and then is brought to the Rd pin on the SubD connector. The DB9 plug in th epicture is a female plug looked at from the solder side.
If for any reason one would prefer to use an old SubD25 serial connector, the table below shows the corresponding pins between the two. To make things a bit confusing both pin 2 and 3 have exactly opposite functions on these connectors.

DB9 Signal DB25
1 DCD 8
2 Rd 3
3 Tx 2
4 DTR 20
5 SGnd 7
6 DSR 6
7 RTS 4
8 CTS 5
9 Ri 22

The LED’s and  resistors R3 and R4 are not really necessary, they just give a visual indication of the transmitting signals, choose a nice color.

R1 and R2 are in fact also not necessary, but they offer some form of protection should you wire up wrong (like connecting to the wrong pin on your microprocessor)

RS232 naar TTL op stripboard

Once the circuit is build, then first test it before you attach it to your Arduino. The easiest way to test it is to temporarily connect the Tx and Rd pin (so the ends of R1 and R2) with eachother. Apply 5 volts to the chip and connect your serial cable.

Open up the Arduino IDE, select the proper COM port under ‘Tools’, open up the serial monitor and type in some characters and click ‘Send’. The characters should be echo-ed back.

For me this worked with all baud-rates.

Then disconnect the temporary connection you just made and connect Tx and Rd to the corresponding pins on your board/chip.

If that has the bootloader installed, you should be able to upload a program to your board with this serial connection.

Worked like a charm

The finished circuit on stripboard. I opted for a 25DB connector rather than a 9DB connector because that fitted the serial cable I had. Don’t be confused by the double row of headers. Again, that is all I had but a single row would suffice
P1040253
The serial interface, connected to a simple arduino board
diy-arduino2

Note: Many ‘modern’ computers that  still have a serial connector do in fact already not work with the high voltages that we know from true RS232 and then the MAX232 might not be needed, but one could use a levelshifter as e.g. Sparkfun is selling ($6.95) and try to build that yourself. It is not a big circuit, but in my idea, usung the MAX232 is just easier and the RS232Shifter board is actually a bit of a hack and does not seem as reliable.

Lots of RS232 info here. and here

Another one here, and here, and here, and here, and here, and here (Thai)

Max 232
MAX232

RS232-TTL

Program an ATtiny with an Arduino Nano

Many sites already described how to use the Arduino as a programmer for the ATtiny series, but as some people still have some problems with it, it won’t hurt to share my experience in doing this with an Arduino Nano.

The connection between the Arduino and the ATtiny is in essence the same, regardless of what Arduino one has. One needs to connect the ISP hearder between both chips. But for the UNO and the Nano there is a little addition in the form of a capacitor between  ground and the reset pin:
arduino_prog

Most circuits will show a 10uF electrolytic capacitor, but I used a 33uF elco and that worked perfectly.

In order to use the ATtiny 45 or 85 you need to download some software. For the Attiny13 there are other cores. If you are using the Attiny13 core you also need to create a boot.txt file
You will also find a core for the Attiny here. and a number of them here.

Now create a folder called ‘Hardware’ in the folder where your Arduino IDE saves it’s sketches. Unzip this file to the newly created hardware folder. If you had your Arduino IDE running, you need to close it and restart it so it can read the proper files.

Now do the following:

  • Connect Arduino Nano and Attiny85 as described above, but do not connect the capacitor yet.
  • Load the ‘Arduino as ISP sketch’
  • Disconnect USB
  • Insert capacitor
  • Reconnect USB
  • Load Attiny sketch of your choosing in the Arduino IDE (e.g. the ‘blink’ sketch)
  • Choose ‘ATtiny85 with Arduino as ISP’ in yr ‘Tools->boards’
  • Upload
  • Ignore the errors about PAGEL and BS2
  • Remove USB
  • Remove capacitor and at least the line to the reset of the Attiny (the one from pin 1)

Your sketch should now be correctly in your ATtiny.

Configuring the ATtiny to run at 8 MHz (for SoftwareSerial support)

By default, the ATtiny’s run at 1 MHz (the setting used by the unmodified “ATtiny45″, etc. board menu items). You need to do an extra step before the programming to configure the microcontroller to run at 8 MHz – necessary for use of the SoftwareSerial library. Once you have the microcontroller connected, select the appropriate item from the Boards menu (e.g. “ATtiny45 (8 MHz)”). Then, run the “Burn Bootloader” command from the Tools menu. This configures the fuse bits of the microcontroller so it runs at 8 MHz. Note that the fuse bits keep their value until you explicitly change them, so you’ll only need to do this step once for each microcontroller. (Note this doesn’t actually burn a bootloader onto the board; you’ll still need to upload new programs using an external programmer.)

With regard to writing a sketch for the ATtiny85, there is only a limited instruction set:

See also:

Programming an Attiny with Arduino 1.01.

TinyWireM & TinyWireS: Wire (I2C / TWI) library for the ATtiny85 (using USI)

Arduino hardware interrupt

What is an interrupt?

On a very basic level, an interrupt is an signal that interrupts the current processor activity. It may be triggered by an external event (change in pin state) or an internal event (a timer or a software signal).  Once triggered, an interrupt pauses the current activity and causes the program to execute a different function.  This function is called an interrupt handler or an interrupt service routine (ISR).  Once the function is completed, the program returns to what it was doing before the interrupt was triggered.

ISR

If you’re new to the world of software development, you might wonder why all this complication is necessary just to respond to external events.  After all, you can check the state of external pins at any time, or create your own timers.

You certainly can do all of these things in your main code, but interrupts give you a key advantage – they are asynchronous.  An asynchronous event is something that occurs outside of the regular flow of your program – it can happen at any time, no matter what your code is crunching on at the moment.  This means that rather than manually checking whether your desired event has happened, you can let your AVR do the checking for you.

Let’s use a real-world example.  Imagine you’re sitting on your couch, enjoying a frosty brew and watching a movie after a long day.  Life is good.  There’s only one problem: you’re waiting for an incredibly important package to arrive, and you need it as soon as possible.  If you were a normal AVR program or Arduino sketch, you’d have to repeatedly stop your movie, get up, and go check the mailbox every 5 minutes to make sure you knew when the package was there.

Instead, imagine if the package was sent Fedex or UPS with delivery confirmation.  Now, the delivery man will go to your front door and ring the doorbell as soon as he arrives. That’s your interrupt trigger.  Once you get the trigger, you can pause your movie and go deal with the package.  That’s your interrupt service routine.  As soon as you’re done, you can pick up the film where you left off, with no extra time wasted. That’s the power of interrupts.

The AVR chips used in most Arduinos are not capable of parallel processing, i.e. they can’t do multiple things at once.  Using asynchronous processing via interrupts enables us to maximize the efficiency of our code, so we don’t waste any precious clock cycles on polling loops or waiting for things to occur.  Interrupts are also good for applications that require precise timing, because we know we’ll catch our event the moment it occurs, and won’t accidentally miss anything.

Types of Interrupts

There are two main types of interrupts:

  • Hardware interrupts, which occur in response to an external event, such as an input pin going high or low
  • Software interrupts, which occur in response to an instruction sent in software

8-bit AVR processors, like the ones that power most Arduino boards, aren’t capable of software interrupts. So we’ll focus on hardware for now.  Most tutorials out there talk about handling external interrupts like pin state changes.  If you’re using an Arduino, that’s the only type of interrupt the Arduino “language” supports, using the attachInterrupt() function.  That’s fine, but there’s a whole different category of hardware interrupts that rely on the AVR’s built in timers, which can be incredibly useful.  We’ll cover external interrupts in this tutorial, then go over timer interrupts in a follow-up tutorial, since there’s enough information to warrant splitting things up.

How to get an interrupt to do what we want – Interrupt Service Routines

Every AVR processor has a list of interrupt sources, or vectors, which include the type of events that can trigger an interrupt.  When interrupts are enabled and one of these events occur, the code will jump to a specific location in program memory – the interrupt vector.  By writing an ISR and then placing a link to it at the interrupt vector’s memory location, we can tell our code to do something specific when an interrupt is triggered.

Let’s implement this using a simple example: detecting when a pushbutton has been pressed, and performing an action based on that press.

Implementing an interrupt in a program

In order to successfully use an interrupt, we’ll need to do three things:

  1. Set the AVR’s Global Enable Interrupts bit in Status Register
  2. Set the interrupt enable bit for our specific interrupt vector (each vector has it’s own on/off switch)
  3. Write an ISR and attach it to our target interrupt vector

Starting with the first step, we’ll include the interrupt library from avr-libc, then use an avr-libc function to set our global interrupt enable bit.  Next, we need to enable the interrupt we want.  Most 8-bit AVR’s like the ATMega328 have 2 hardware interrupts, INT0 and INT1.  If you’re using a standard Arduino board, these are tied to digital pins 2 and 3, respectively.  Let’s enable INT0 so we can detect an input change on pin 2 from a button or switch.

#include <avr/interrupt.h> //Not really needed for Arduino
void setup(void){sei();  // Enable global interrupts
EIMSK |= (1 << INT0);    // Enable external interrupt INT0

Next, we need to set the sensing method of our interrupt.  For a pin change interrupt, we have four options: rising edge, falling edge, any logical state change, or a low level on the pin.  The default for INT0 and INT1 is to trigger on the pin being low level; you can use the datasheet to read more about how to set each method.  Let’s use falling edge for this example, just to show how it’s done.

EICRA |= (1 << ISC01);    // Trigger INT0 on falling edge

Finally, we’ll define an ISR that performs our desired task.  Every ISR is defined as:

ISR({vector}_vect)
{
// Perform task here
}

where {vector} is the name of our chosen interrupt vector.  Again, the names of these vectors are defined in the processor datasheet; here, the one we want is INT0.  For this example, we’ll use the ISR to toggle the built-in LED on pin 13. With our LED code added, here’s how it looks all together:

#include <avr/interrupt.h> //not really needed for arduino 
//
void setup(void)
{
  pinMode(2, INPUT);
  digitalWrite(2, HIGH); // Enable pull-up resistor
  sei();                 // Enable global interrupts
  EIMSK |= (1 << INT0);  // Enable external interrupt INT0
  EICRA |= (1 << ISC01); // Trigger INT0 on falling edge
}
//
void loop(void)
{
  //
}
//
// Interrupt Service Routine attached to INT0 vector
ISR(INT0_vect)
{
 digitalWrite(13,!digitalRead(13));// Toggle LED on pin 13
}

Note that we can use the program’s main loop() to do anything we want in the meantime, and it won’t affect the functionality of our LED toggle.

Arduino interrupt functionality

There’s an alternative way to implement INT0 and INT1 using the Arduino programming “language”. I put “language” in quotes because although that’s how the Arduino website refers to it, it’s more like a wrapper around avr-libc to make certain things easier. But that’s an article for another day. For our example, we could use the attachInterrupt() function to enable the same interrupt in setup():

setup(void)
{
attachInterrupt(0, pin2ISR, FALLING);
}

In this case, we define our own custom ISR (pin2ISR) and pass it as an argument. pin2ISR() would simply take the place of ISR(EXT_INT0_vect). This is often a bit simpler than using the raw avr-libc functions, and it does abstract away any difference in chip models. However, the AVR methods described earlier can be used with any interrupt vector, while attachInterrupt() only works with external interrupts.

Putting it all together

There are a few final things to keep in mind when implementing interrupts.
First, keep in mind that whatever you use your ISR for, it’s good practice to keep it short, because while the ISR is executing, it’s holding up the rest of your program. If you have lots of interrupts, this can slow things to a crawl. Also, by “the rest of your program”, we do mean everything: Arduino functions like millis() won’t increment, and delay() won’t work within an ISR.
Next, if you want to modify any variables within your ISR, you’ll need to make them global variables and mark them as volatile to ensure that your ISR has proper access to them. For example, instead of globally declaring

int myInterruptVar;

you would declare

volatile int myInterruptVar;

Finally, interrupts are normally globally disabled inside of any ISR (this is why delay() and millis() don’t work). This means that if more interrupt events occur before your ISR has completed, your program won’t catch them. This is another reason to keep ISRs short.

Wrapping up

That’s about it for the basics. If you’re ready to keep going, check out my followup article on timer interrupts. It builds on the concepts discussed here and helps you use the AVR’s built-in timers to do useful things. In the meantime, implement this example and dive into the Atmel datasheets to discover other interrupt vectors. They sky’s the limit!

PCInt and PCChangeInt libraries mentioned on the Arduino site here:   http://www.arduino.cc/playground/Main/PinChangeInt with samples here:  http://arduino.cc/playground/Main/PinChangeIntExample which gives you flexibility to use any pin for an interrupt.

A common example of where you use interrupts is using quadrature encoders on motors.   As the motor spins two signals come in from the encoders which can be captured with interrupts to determine direction, speed, and amount of rotation of your motors.

Sample code can be found here:  http://www.arduino.cc/playground/Main/RotaryEncoders
See also: Newbies guide on timers


	

LED Fade

<!--*
* Code for cross-fading 3 LEDs, red, green and blue, or one tri-color LED, using PWM
* The program cross-fades slowly from red to green, green to blue, and blue to red
*
* Clay Shirky &lt;clay.shirky@nyu.edu&gt;
*/

// Output
int redPin   = 9;   // Red LED,   connected to digital pin 9
int greenPin = 10;  // Green LED, connected to digital pin 10
int bluePin  = 11;  // Blue LED,  connected to digital pin 11

// Program variables
int redVal   = 255; // Variables to store the values to send to the pins
int greenVal = 1;   // Initial values are Red full, Green and Blue off
int blueVal  = 1;

int i = 0;     // Loop counter
int wait = 50; // 50ms (.05 second) delay; shorten for faster fades
int DEBUG = 0; // DEBUG counter; if set to 1, will write values back via serial

void setup()
{
pinMode(redPin,   OUTPUT);   // sets the pins as output
pinMode(greenPin, OUTPUT);
pinMode(bluePin,  OUTPUT);
if (DEBUG) {           // If we want to see the pin values for debugging...
Serial.begin(9600);  // ...set up the serial ouput on 0004 style
}
}

// Main program
void loop()
{
i += 1;      // Increment counter
if (i &lt; 255) // First phase of fades
{
redVal   -= 1; // Red down
greenVal += 1; // Green up
blueVal   = 1; // Blue low
}
else if (i &lt; 509) // Second phase of fades
{
redVal    = 1; // Red low
greenVal -= 1; // Green down
blueVal  += 1; // Blue up
}
else if (i &lt; 763) // Third phase of fades
{
redVal  += 1; // Red up
greenVal = 1; // Green low
blueVal -= 1; // Blue down
}
else // Re-set the counter, and start the fades again
{
i = 1;
}

analogWrite(redPin,   redVal);   // Write current values to LED pins
analogWrite(greenPin, greenVal);
analogWrite(bluePin,  blueVal);

if (DEBUG) { // If we want to read the output
DEBUG += 1;     // Increment the DEBUG counter
if (DEBUG &gt; 10) // Print every 10 loops
{
DEBUG = 1;     // Reset the counter

Serial.print(i);       // Serial commands in 0004 style
Serial.print("\t");    // Print a tab
Serial.print("R:");    // Indicate that output is red value
Serial.print(redVal);  // Print red value
Serial.print("\t");    // Print a tab
Serial.print("G:");    // Repeat for green and blue...
Serial.print(greenVal);
Serial.print("\t");
Serial.print("B:");
Serial.println(blueVal); // println, to end with a carriage return
}
}
delay(wait); // Pause for 'wait' milliseconds before resuming the loop
}

-->