Pages: [1]   Go Down
Author Topic: MIM 5383H4 Infrared Module with ATtiny85 (UNO set time/date menu sample)  (Read 1347 times)
0 Members and 1 Guest are viewing this topic.
Atlanta, USA
Offline Offline
Edison Member
*
Karma: 34
Posts: 1476
AKA: Ray Burne
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am working on an engine controller and I need to set some soft parameters in EEPROM.  After talking to the person for whom the device is being constructed, we decided to use a dollar store $1 universal remote control and the Sony IR protocol.  The MIM sensor in the Subject line is the one I selected because I happened to have several in my parts box from a PICAXE project.  My sensors came from http://www.goldmine-elec-products.com/prodinfo.asp?number=G16737 at a time when they were on sale for 10x for much less than the qty 1 price.

In researching the Arduino code, I came across a number of Forum posts as well as Adafruit and SparkFun.  The SparkFun code seemed to be usable but upon downloading I noticed they had taken the code from the Forum: http://arduino.cc/forum/index.php/topic,17965.0.html  Thank you pmalmsten and other contributors of that thread.

My design for the engine monitoring uses a Mega2560 and monitors 16 sensors ranging from EGT over SPI to Time/Date over I2C.  I really did not want interrupt driven code, so the function getIRKey() was ideal.  However, to have a decent responsiveness "feel" I did not want to poll the code in the Mega2560.  I thought about using a cheap 328P off-board and then I got the idea of rewriting the code to use the ATtiny85 and the internal 16MHz oscillator fuses.  I selected the Arduino-Tiny hardware core from http://code.google.com/p/arduino-tiny/ and made a few changes to the code to manage the pinout.  The code works and while I am likely to make a few modifications, I wanted to post since there may be others who could benefit from off-loading IR decoding to a separate, inexpensive ATmel uC while still managing the code in the Arduino GUI.

You must select the correct "board" type... ATtiny85@16MHz (internal PLL)
(I have not tried other options... your mileage may vary.)

PLEASE... I am NOT an ATtiny kind of person... so, if you have questions about ATtiny85 and Arduino, please research this Forum and consult the arduino-tiny information on the Google hosting link.  If you still are in need, try posting on the Forum and perhaps the author Coding Badly or another enlightened member will respond with appropriate information.  
http://arduino.cc/forum/index.php?topic=51984.0;wap2
I found that following the instructions provided with the download were sufficient for my needs.

- Ray

OK, the code for the ATtiny85:
(9600BAUD serial output comes off of ATtiny physical pin# 7)
Code:
/*
  IR remote control (Sony) detection for Arduino, M. Burnette
  Binary sketch size: 2,794 bytes (of a 8,192 byte maximum)

  ☺  20130103 MRB Modified for interface to Mega2560
      Europa codebase for menu system
      
  ☺  20121230 MRB Modified for Tiny85 Google Tiny library
      Tiny85 Internal RC 16MHz

  ☺  20121230 MRB modifications to adapt to numeric input, avoid dupes,
      and to generally "behave" consistently
  ☺  Used with Electronic Goldmine IR detector MIM 5383H4
      http://www.goldmine-elec-products.com/prodinfo.asp?number=G16737
  ☺  IR detector:
      Pin 1: To pin D4 on Arduino ATtiny85
      Pin 2: GND
      Pin 3: 5V through 33 Ohm resistor
  
  ☺  This is based on pmalmsten's code found on the Arduino forum from 2007:
      http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1176098434/0

*/
// Pins 2/3 used for Software serial
int irPin     = 4;       //Sensor pin 1 wired to Arduino's pin D4
int statLED   = 0;       //Toggle the status LED every time Power is pressed
int start_bit = 2200;    //Start bit threshold (Microseconds)
int bin_1     = 1000;    //Binary 1 threshold (Microseconds)
int bin_0     = 400;     //Binary 0 threshold (Microseconds)

void setup() {
  pinMode(statLED, OUTPUT);
  digitalWrite(statLED, LOW);

  pinMode(irPin, INPUT);

  Serial.begin(9600);
  Serial.println("IR/Serial Initialized: ");
}

void loop() {
  int key = getIRKey();   //Fetch the key
  
  if(key != 0)            //Ignore keys that are zero
  {
    switch(key)
    {
      case 128: Serial.print("1"); break;
      case 129: Serial.print("2"); break;
      case 130: Serial.print("3"); break;
      case 131: Serial.print("4"); break;
      case 132: Serial.print("5"); break;
      case 133: Serial.print("6"); break;
      case 134: Serial.print("7"); break;
      case 135: Serial.print("8"); break;
      case 136: Serial.print("9"); break;
      case 137: Serial.print("0"); break;
      
      case 144: Serial.print("A"); break;  // CH Up
      case 145: Serial.print("B"); break;  // CH Down
      case 146: Serial.print("C"); break;  // VOL Right
      case 147: Serial.print("D"); break;  // VOL Left
      case 148: Serial.print("E"); break;  // Mute
      case 165: Serial.print("F"); break;  // AV/TV
      case 149: Serial.print("P");         // Power == MENU ACTIVE
        //This toggles the statLED every time power button is hit
        if(digitalRead(statLED) != 1)
          digitalWrite(statLED, HIGH);
        else
          digitalWrite(statLED, LOW);
        break;

      //default: Serial.println(key); // for inspection of keycode
    }

    delay(400);    // avoid double key logging (adjustable)
  }
}

int getIRKey() {
  int data[12];
  int i;

  while(pulseIn(irPin, LOW) < start_bit); //Wait for a start bit
  
  for(i = 0 ; i < 11 ; i++)
    data[i] = pulseIn(irPin, LOW);      //Start measuring bits, I only want low pulses
  
  for(i = 0 ; i < 11 ; i++)             //Parse them
  {    
    if(data[i] > bin_1)                 //is it a 1?
      data[i] = 1;
    else if(data[i] > bin_0)            //is it a 0?
      data[i] = 0;
    else
      return -1;                        //Flag the data as invalid; I don't know what it is! Return -1 on invalid data
  }

  int result = 0;
  for(i = 0 ; i < 11 ; i++)             //Convert data bits to integer
    if(data[i] == 1) result |= (1<<i);

  return result;                        //Return key number
}



* Schematic.JPG (70.74 KB, 1024x768 - viewed 68 times.)
« Last Edit: January 12, 2013, 06:34:28 pm by mrburnette » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hey, thanks for sharing your code, just what I was searching for this morning, for the ATtiny85.
Never though I was going to find this on my first forum search.

Ah, and happy new year too!

Regards, Edmundo.
Logged

Atlanta, USA
Offline Offline
Edison Member
*
Karma: 34
Posts: 1476
AKA: Ray Burne
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Quote
Hey, thanks for sharing your code, just what I was searching for this morning, for the ATtiny85.

For the Arduino open source metaphor to work, sharing is a responsibility.  I only added the C code to handle the numeric keys on my universal-remote control.  Deep thanks goes to those that work on the snippet prior to me.

- Ray

PS:  Remember, when using ATtiny85 with Arduino, you will need to utilize a "burner" of some sort.  I use the Adafruit ZIP 28-pin burner which I have modified for ATtiny 8-pin devices (that is, a switch setting changes from 28 pins to 8 pins.)  This little device has served me faithfully using the Arduino AVR ISP code for the UNO.  https://www.adafruit.com/products/462

You MUST burn the fuses correctly for the board type selected when using the Arduino-ATtiny or the MIT tiny cores.  Generally, this is done through pretending to burn the "bootloader" for the ATtiny; no bootloader is specified so nothing gets downloaded, but the fuses are set correctly.
« Last Edit: January 11, 2013, 08:18:05 pm by mrburnette » Logged

Atlanta, USA
Offline Offline
Edison Member
*
Karma: 34
Posts: 1476
AKA: Ray Burne
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

With DS1307 modules being very inexpensive, I'm finding that they have "cheap" xtals, too.  It is not unusual for my $3 module to gain/lose 20+ seconds per 24 hour period.  As the module is being used for a time+date stamp on an engine monitor that logs once every 2 seconds, I and the end-user were having to make log entries of the 'true' time before every engine run so that the log which is written to SD card could be "adjusted".  What a pain!!!

I considered just adding a keypad and menu button to allow me to set the time every time the engine was run.  But space in the cockpit is at a premium and even a small keypad was ruled not an efficient use of space.  I considered a joy-stick kind of menu where the numbers could be selected and loaded into the DS1307 registers.  Still a pain to use.  Out of this thinking came the IR ATtiny85 demodulator and serial interface to the ATmega2560.  The menu system is enabled on the 2nd OLED dispaly by pressing the On/Off button on a Sony configured universal remote, the $1 dollar store variety.  I extracted the code from the engine monitor, reworked the LCD/OLED for a single 2x16 device, and created this sample code that can be run on a UNO or ATmega2560.  The nesting is such that one can use the On/OFF remote key to "back out" at any point in the menu... thus allowing the setting for Seconds without the need to enter minutes and hours.  Or, seconds and minutes can be set without the need to set hours.  And so on, the same with day, month, and year.  This concept allows for quickly addressing the xtal drift of the inexpensive DS1307 modules.

The code is about 14K characters, so could not do an inline here.  Please see attachments.
 
I wrote the code inline and not as a function or object so that it can be followed easily (mainly for myself.)  Feel free to embellish to your heart's content.  

- Ray

* IR inline OLED-LCD menu for DS1307.zip (2.91 KB - downloaded 14 times.)
« Last Edit: January 11, 2013, 08:23:44 pm by mrburnette » Logged

Pages: [1]   Go Up
Jump to: