IR remote test, based on Arduino IRRemote lib.

Dependencies:   mbed

IR remote test, based on Arduino IRremote lib.

https://www.pjrc.com/teensy/td_libs_IRremote.html

Uses PWM for carrier and timer for 50us sensor reads. for k64f, one could use CMT.

main.cpp

Committer:
manitou
Date:
2016-04-13
Revision:
1:af81e02b8c7b
Parent:
0:785739d5a30a

File content as of revision 1:af81e02b8c7b:

/*
  IRtest
     hack of maple version
      http://www.arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
    use PWM to generate mark/space at 38Khz
     IR LED xmit   pin to 100ohm to +IR  - to grnd (short/flat)
    use timer 50us to count mark/space on input
    is it possible to run both xmit and recv?
*/
#include "mbed.h"
#include "IRremote.h"

Ticker ticker;

// K64F pins 
#define RecvPin D7
#define PWMPin D6
#define TestPin D13

PwmOut pwm(PWMPin);
DigitalIn recvpin(RecvPin);
DigitalOut testpin(TestPin);    // jumper to RecvPin for test
DigitalOut myled(LED1);

volatile unsigned long myticks;
int rawbuf[RAWBUF], rawlen;
uint8_t rcvstate;
int results_decode_type; // NEC, SONY, RC5, UNKNOWN
unsigned long results_value;
int results_bits; // Number of bits in decoded value


void timer_ISR() {
    // interrupt every 50us
    uint8_t irdata = recvpin;   // read IR sensor
    myticks++;


  if (rawlen >= RAWBUF) {
    // Buffer overflow
    rcvstate = STATE_STOP;
  }
  switch(rcvstate) {
  case STATE_IDLE: // In the middle of a gap
    if (irdata == MARK) {
      if (myticks < GAP_TICKS) {
        // Not big enough to be a gap.
        myticks = 0;
      }
      else {
        // gap just ended, record duration and start recording transmission
        rawlen = 0;
        rawbuf[rawlen++] = myticks;
        myticks = 0;
        rcvstate = STATE_MARK;
      }
     }
    break;
  case STATE_MARK: // timing MARK
    if (irdata == SPACE) {   // MARK ended, record time
      rawbuf[rawlen++] = myticks;
      myticks = 0;
      rcvstate = STATE_SPACE;
    }
    break;
  case STATE_SPACE: // timing SPACE
    if (irdata == MARK) { // SPACE just ended, record it
      rawbuf[rawlen++] = myticks;
      myticks = 0;
      rcvstate = STATE_MARK;
    }
    else { // SPACE
      if (myticks > GAP_TICKS) {
        // big SPACE, indicates gap between codes
        // Mark current code as ready for processing
        // Switch to STOP
        // Don't reset timer; keep counting space width
        rcvstate = STATE_STOP;
      }
    }
    break;
  case STATE_STOP: // waiting, measuring gap
    if (irdata == MARK) { // reset gap timer
      myticks = 0;
    }
    break;
  }

}

// set up recv timer
void enableIRIn(){
    ticker.attach_us(&timer_ISR,50);
    rcvstate = STATE_IDLE;
    rawlen = 0;
}

void irrecv_resume() {
    rcvstate = STATE_IDLE;
    rawlen = 0;
}

long decodeSony() {
  long data = 0;
  if (rawlen < 2 * SONY_BITS + 2) {
    return ERR;
  }
  int offset = 1; // Skip first space
  // Initial mark
  if (!MATCH_MARK(rawbuf[offset], SONY_HDR_MARK)) {
    return ERR;
  }
  offset++;

  while (offset + 1 < rawlen) {
    if (!MATCH_SPACE(rawbuf[offset], SONY_HDR_SPACE)) {
      break;
    }
    offset++;
    if (MATCH_MARK(rawbuf[offset], SONY_ONE_MARK)) {
      data = (data << 1) | 1;
    }
    else if (MATCH_MARK(rawbuf[offset], SONY_ZERO_MARK)) {
      data <<= 1;
    }
    else {
      return ERR;
    }
    offset++;
  }

  // Success
  results_bits = (offset - 1) / 2;
  if (results_bits < 12) {
    results_bits = 0;
    return ERR;
  }
  results_value = data;
  results_decode_type = SONY;
  return DECODED;
}

void enableIROut(int khz) {
    int freq = 1000 * khz;
    pwm.period(1./freq);
    pwm.write(0);  //  start PWM with low
}

void mark(int time) {
    pwm.write(0.5);  // PWM on
    testpin=0;          // test   invert
    wait_us(time);
}

void space(int time) {
    pwm.write(0);  // off
    testpin=1;
    wait_us(time);
}

void sendSony(unsigned long data, int nbits) {
  enableIROut(40);
  mark(SONY_HDR_MARK);
  space(SONY_HDR_SPACE);
  data = data << (32 - nbits);
  for (int i = 0; i < nbits; i++) {
    if (data & TOPBIT) {
      mark(SONY_ONE_MARK);
      space(SONY_HDR_SPACE);
    }
    else {
      mark(SONY_ZERO_MARK);
      space(SONY_HDR_SPACE);
    }
    data <<= 1;
  }
}

void sendRaw(unsigned int buf[], int len, int khz)
{
  enableIROut(khz);
  for (int i = 0; i < len; i++) {
    if (i & 1) {
      space(buf[i]);
    }
    else {
      mark(buf[i]);
    }
  }
  space(0); // Just to be sure
}

main() {
  long sonycmd[] = {0xA9A,0x91A,0x61A}; // power 0 7
  

  pwm.period(1.);
  pwm.write(0);  //  when no PWM, want pin low

  enableIRIn();
  while(true) {   
        printf("xmit\n");
        myled=1;
        sendSony(sonycmd[0],SONY_BITS); 
        myled=0;
        wait(.006);   // let gap time grow

        if (rcvstate == STATE_STOP) {
            if (decodeSony() ) {
                printf("sony decoded. value %0x  %d bits\n",results_value, results_bits);
            }
            printf("rawlen %d\n",rawlen);

            for (int i=0; i < rawlen; i++) {
                if (i%2) printf(" ");
                printf("%d\n",rawbuf[i]*USECPERTICK);
            }
            irrecv_resume();
        } 

        wait(2.0);
  }
}