天天看點

Arduino 接收NEC紅外遙控編碼

使用Arduino接收紅外遙控編碼并列印到序列槽

IR_PIN 預設為2

/*本程式用來接收NEC紅外編碼
 * 程式原理:通過判斷兩次下降沿的周期寬度判斷目前bit是邏輯1還是邏輯0
 * 邏輯1  560+1690=2250us  邏輯0 560+560=1120us
 * 接收到的資料是低位在前,儲存的bit順序為 0->7
 * 
 * 
 * 當收到第1個下降沿時認為程式進入等待前導碼階段,即:9ms低+4.5ms高,
 * 是以可在下一個下降沿時判斷脈寬是否在13.5ms左右,如果是則标記進入收碼階段,否則傳回重新等待新的下降沿
 * 
 * 進入收碼階段後每次下降沿判斷脈寬,得到邏輯1或0并寫入buf,寫滿1個位元組後轉存至全局變量數組中
 * 
 * 接收IO連續高電平100ms以上時認為收碼結束,标記結束
 * loop檢測到收碼結束時列印結果
 * 
 * BH3PXN
 * 2020.05.29
*/

#define IR_PIN 2

#define STEP_FREE 0
#define STEP_WAIT_PRECODE 1
#define STEP_RECV_CODE 2
#define STEP_RECV_OVER 3

unsigned char recvStep = STEP_FREE;
unsigned char irCode[100];
unsigned char idx = 0;
void setup() {
  // put your setup code here, to run once:
  pinMode(IR_PIN, INPUT_PULLUP); //開啟上拉
  Serial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  IR_RECV();
  outputIRCODE();

}
void outputIRCODE() {
  if (recvStep != STEP_RECV_OVER) {
    return;
  }
  recvStep = STEP_FREE; //重置
  Serial.print("IR CODE ");
  Serial.print(" : ");
  for (unsigned char i = 0; i < idx; i++) {
    
    Serial.print(irCode[i],HEX);
    Serial.print(" ");
  }
  Serial.println();
  
  idx = 0;
}

void IR_RECV() {
  static unsigned char lastIR = 1;
  static unsigned char nowIR = 1;
  static unsigned long tus = 0;
  static unsigned long tms = 0;
  static unsigned long nowus = 0;
  static unsigned long t = 0;
  static unsigned char irbuf; // 一個位元組的資料
  static unsigned char i = 0;

  //擷取目前電平
  nowIR = digitalRead(IR_PIN);

  //高電平維持
  if (lastIR && nowIR) {
    //大于100ms時傳回
    if (millis() - tms > 100) {
      t = 0;
      if (recvStep == STEP_RECV_CODE) {
        recvStep = STEP_RECV_OVER; //接收完成,交給主程式
      }
      return;
    }

  }//end lastIR && nowIR

  //上升沿 忽略
  if (!lastIR && nowIR == HIGH) {
    tms = millis();
    lastIR = HIGH;
    //    return;
  }

  //下降沿
  if (lastIR && nowIR == LOW) {
    lastIR = LOW;
    nowus = micros();
    t = nowus - tus;
    tus = nowus;

    //第1個下降沿
    if (recvStep == STEP_FREE) {
      tus = nowus;
      recvStep = STEP_WAIT_PRECODE; //等待前導碼
      return;
    }// end recvStep


    if (recvStep == STEP_WAIT_PRECODE ) {
      if (t >= 12000 && t <= 16000) {
        //Serial.print("ir recv begin");
        //正确的引導碼
        recvStep = STEP_RECV_CODE;
        return;
      } else {
        Serial.print("error pre code,t=");
        Serial.print(t);
        Serial.println();
        recvStep = STEP_FREE;
        delay(1000);
        return;
      }
    }

    //标準NEC碼:邏輯1  560+1690=2250us  邏輯0 560+560=1120us
    //接收到的資料是低位在前,
    //邏輯1
    if (t >= 1800 && t < 2800) {
      irbuf  |= 0x01 << i;
      i++;
    }//end 1

    //邏輯0
    if (t >= 800 && t < 1800) {
      i++;
    }//end 0

    //接收夠1個位元組,寫入編碼緩存
    if (i == 8) {
      irCode[idx++] = irbuf;
      irbuf = 0x00;
      i = 0;
    }// end i==8
  }// end lastIR && IR == LOW

}// end void IR_RECV()

           

繼續閱讀