超再生模块

  • 介绍
超再生接收机价格低廉(2~3块一对),经济实惠,而且接收灵敏度高,但是缺点也很明显,那就是频率受温度漂移大,抗干扰能力差。 再超生模块可以用于315MHz、433MHz等频率。
  • 接收模块正面图
[caption id="attachment_1285" align="alignnone" width="300"] 超再生模块_第1张图片 超再生接收模块正面-S[/caption]  
  • 接收模块背面图
[caption id="attachment_1286" align="alignnone" width="200"] 超再生接收模块背面-S[/caption]  
  • 发送模块正面图
[caption id="attachment_1290" align="alignnone" width="150"] 超再生模块_第2张图片 QQ图片20150329112657-S[/caption]  
  • 发送模块背面图
[caption id="attachment_1291" align="alignnone" width="150"] QQ图片20150329112702-S[/caption]  
  • Arduino控制
使用Arduino的话,主要使用通过 PWM来实现的。这里采用修改过的IRremote库来做实验。注意,接收模块接线时,从背面数data标志下第二个接口连接到Arduino的11上。发送模块的DATA接到Arduino的3上。 下面是发送端代码: [codesyntax lang="cpp"]
#include <IRremote315.h>
#include <IRremoteInt315.h>

IRsend irsend;

void setup(){
  Serial.begin(9600);
  
  pinMode(3, OUTPUT);
}

void loop(){
  Serial.println("sendi");
  
  irsend.sendNEC(0x765585, 32);
  
  delay(1000);
}
[/codesyntax] 下面是接收端代码: [codesyntax lang="cpp"]
#include <IRremote315.h>
#include <IRremoteInt315.h>

int RECV_PIN = 11;
int LED1 = 2;
long on1 = 0x00FF906F;
int sta = 1;

IRrecv irrecv(RECV_PIN);
decode_results results;

void dump(decode_results *results){
  int count = results->rawlen;
  
  Serial.print("count : ");
  Serial.println(count);
  
  if(results->decode_type == UNKNOWN){
    Serial.println("count not decode message");
  }else{
    if(results->decode_type == NEC){
      Serial.print("decode nec:");
      
      Serial.print(results->value, HEX);
      Serial.print(" (");
      Serial.print(results->bits, DEC);
      Serial.println("bits)");
    }
    
    Serial.print("raw (");
    Serial.print(count, DEC);
    Serial.print(")");
    
    for(int i = 0; i < count; i++){
      if((i % 2) == 1){
        Serial.print(results->rawbuf[i] * USECPERTICK, DEC);
      }else{
        Serial.print(-(int)results->rawbuf[i] * USECPERTICK, DEC);
      }
      
      Serial.print(" ");
    }
    
    Serial.println("");
  }
}

void setup(){
  Serial.begin(9600);
  
  pinMode(RECV_PIN, INPUT);
  pinMode(LED1, OUTPUT);
  pinMode(13, OUTPUT);
  
  irrecv.enableIRIn();
}

int on = 0;
unsigned long last = millis();

void loop(){
  if(irrecv.decode(&results)){
    if(millis() - last > 250){
      on = !on;
      digitalWrite(13, on ? HIGH : LOW);
      dump(&results);
    }
    
    if(results.value = on1){
      if(sta == 1){
        digitalWrite(LED1, HIGH);
        sta = 0;
      }else{
        digitalWrite(LED1, LOW);
        sta = 1;
      }
    }
    
    last = millis();
    irrecv.resume();
  }
}
[/codesyntax] 下面是库文件IRremote315/IRremote315.h: [codesyntax lang="cpp"]
class IRsend
{
public:
  IRsend() {}
  void sendNEC(unsigned long data, int nbits);

  void sendRaw(unsigned int buf[], int len, int hz);
  // private:
  void enableIROut(int khz);
  VIRTUAL void mark(int usec);
  VIRTUAL void space(int usec);
}
;

// Some useful constants

#define USECPERTICK 50  // microseconds per clock interrupt tick
#define RAWBUF 76 // Length of raw duration buffer

// Marks tend to be 100us too long, and spaces 100us too short
// when received due to sensor lag.
#define MARK_EXCESS 50

#endif
[/codesyntax] 下面是库文件IRremote315/IRremote315.cpp: [codesyntax lang="cpp"]
* IRremote

* Version 0.11 August, 2009

* Copyright 2009 Ken Shirriff

* For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html

*

* Interrupt code based on NECIRrcv by Joe Knapp

* http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556

* Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/

*/



#include "IRremote315.h"

#include "IRremoteInt315.h"



// Provides ISR

#include <avr/interrupt.h>



volatile irparams_t irparams;



// These versions of MATCH, MATCH_MARK, and MATCH_SPACE are only for debugging.

// To use them, set DEBUG in IRremoteInt.h

// Normally macros are used for efficiency

#ifdef DEBUG

int MATCH(int measured, int desired) {

	Serial.print("Testing: ");

	Serial.print(TICKS_LOW(desired), DEC);

	Serial.print(" <= ");

	Serial.print(measured, DEC);

	Serial.print(" <= ");

	Serial.println(TICKS_HIGH(desired), DEC);

	return measured >= TICKS_LOW(desired) && measured <= TICKS_HIGH(desired);

}



int MATCH_MARK(int measured_ticks, int desired_us) {

	Serial.print("Testing mark ");

	Serial.print(measured_ticks * USECPERTICK, DEC);

	Serial.print(" vs ");

	Serial.print(desired_us, DEC);

	Serial.print(": ");

	Serial.print(TICKS_LOW(desired_us), DEC);

	Serial.print(" <= ");

	Serial.print(measured_ticks, DEC);

	Serial.print(" <= ");

	Serial.println(TICKS_HIGH(desired_us), DEC);

	return measured_ticks >= TICKS_LOW(desired_us) && measured_ticks <= TICKS_HIGH(desired_us);




}



int MATCH_SPACE(int measured_ticks, int desired_us) {

	Serial.print("Testing space ");

	Serial.print(measured_ticks * USECPERTICK, DEC);

	Serial.print(" vs ");

	Serial.print(desired_us, DEC);

	Serial.print(": ");

	Serial.print(TICKS_LOW(desired_us), DEC);

	Serial.print(" <= ");

	Serial.print(measured_ticks, DEC);

	Serial.print(" <= ");

	Serial.println(TICKS_HIGH(desired_us), DEC);

	return measured_ticks >= TICKS_LOW(desired_us) && measured_ticks <= TICKS_HIGH(desired_us);

}

#endif



void IRsend::sendNEC(unsigned long data, int nbits)

{

	enableIROut(38);

	mark(NEC_HDR_MARK);

	space(NEC_HDR_SPACE);

	for (int i = 0; i < nbits; i++) {

		if (data & TOPBIT) {

			mark(NEC_BIT_MARK);

			space(NEC_ONE_SPACE);

		}

		else {

			mark(NEC_BIT_MARK);

			space(NEC_ZERO_SPACE);

		}

		data <<= 1;

	}

	mark(NEC_BIT_MARK);

	space(0);

}







void IRsend::mark(int time) {

	// Sends an IR mark for the specified number of microseconds.

	// The mark output is modulated at the PWM frequency.

	TCCR2A |= _BV(COM2B1); // Enable pin 3 PWM output

	delayMicroseconds(time);

}



/* Leave pin off for time (given in microseconds) */

void IRsend::space(int time) {

	// Sends an IR space for the specified number of microseconds.

	// A space is no output, so the PWM output is disabled.

	TCCR2A &= ~(_BV(COM2B1)); // Disable pin 3 PWM output

	delayMicroseconds(time);

}



void IRsend::enableIROut(int khz) {

	// Enables IR output.  The khz value controls the modulation frequency in kilohertz.

	// The IR output will be on pin 3 (OC2B).

	// This routine is designed for 36-40KHz; if you use it for other values, it's up to you

	// to make sure it gives reasonable results.  (Watch out for overflow / underflow / rounding.)

	// TIMER2 is used in phase-correct PWM mode, with OCR2A controlling the frequency and OCR2B

	// controlling the duty cycle.

	// There is no prescaling, so the output frequency is 16MHz / (2 * OCR2A)

	// To turn the output on and off, we leave the PWM running, but connect and disconnect the output pin.

	// A few hours staring at the ATmega documentation and this will all make sense.

	// See my Secrets of Arduino PWM at http://arcfn.com/2009/07/secrets-of-arduino-pwm.html for details.





	// Disable the Timer2 Interrupt (which is used for receiving IR)

	TIMSK2 &= ~_BV(TOIE2); //Timer2 Overflow Interrupt



	pinMode(3, OUTPUT);

	digitalWrite(3, LOW); // When not sending PWM, we want it low



	// COM2A = 00: disconnect OC2A

	// COM2B = 00: disconnect OC2B; to send signal set to 10: OC2B non-inverted

	// WGM2 = 101: phase-correct PWM with OCRA as top

	// CS2 = 000: no prescaling

	TCCR2A = _BV(WGM20);

	TCCR2B = _BV(WGM22) | _BV(CS20);



	// The top value for the timer.  The modulation frequency will be SYSCLOCK / 2 / OCR2A.

	OCR2A = SYSCLOCK / 2 / khz / 1000;

	OCR2B = OCR2A / 3; // 33% duty cycle

}



IRrecv::IRrecv(int recvpin)

{

	irparams.recvpin = recvpin;

	irparams.blinkflag = 0;

}



// initialization

void IRrecv::enableIRIn() {

	// setup pulse clock timer interrupt

	TCCR2A = 0;  // normal mode



	//Prescale /8 (16M/8 = 0.5 microseconds per tick)

	// Therefore, the timer interval can range from 0.5 to 128 microseconds

	// depending on the reset value (255 to 0)

	cbi(TCCR2B, CS22);

	sbi(TCCR2B, CS21);

	cbi(TCCR2B, CS20);



	//Timer2 Overflow Interrupt Enable

	sbi(TIMSK2, TOIE2);



	RESET_TIMER2;



	sei();  // enable interrupts



	// initialize state machine variables

	irparams.rcvstate = STATE_IDLE;

	irparams.rawlen = 0;





	// set pin modes

	pinMode(irparams.recvpin, INPUT);

}



// enable/disable blinking of pin 13 on IR processing

void IRrecv::blink13(int blinkflag)

{

	irparams.blinkflag = blinkflag;

	if (blinkflag)

		pinMode(BLINKLED, OUTPUT);

}



// TIMER2 interrupt code to collect raw data.

// Widths of alternating SPACE, MARK are recorded in rawbuf.

// Recorded in ticks of 50 microseconds.

// rawlen counts the number of entries recorded so far.

// First entry is the SPACE between transmissions.

// As soon as a SPACE gets long, ready is set, state switches to IDLE, timing of SPACE continues.

// As soon as first MARK arrives, gap width is recorded, ready is cleared, and new logging starts

ISR(TIMER2_OVF_vect)

{

	RESET_TIMER2;



	uint8_t irdata = (uint8_t)digitalRead(irparams.recvpin);



	irparams.timer++; // One more 50us tick

	if (irparams.rawlen >= RAWBUF) {

		// Buffer overflow

		irparams.rcvstate = STATE_STOP;

	}

	switch (irparams.rcvstate) {

	case STATE_IDLE: // In the middle of a gap

		if (irdata == MARK) {

			if (irparams.timer < GAP_TICKS) {

				// Not big enough to be a gap.

				irparams.timer = 0;

			}

			else {

				// gap just ended, record duration and start recording transmission

				irparams.rawlen = 0;

				irparams.rawbuf[irparams.rawlen++] = irparams.timer;

				irparams.timer = 0;

				irparams.rcvstate = STATE_MARK;

			}

		}

		break;

	case STATE_MARK: // timing MARK

		if (irdata == SPACE) {   // MARK ended, record time

			irparams.rawbuf[irparams.rawlen++] = irparams.timer;

			irparams.timer = 0;

			irparams.rcvstate = STATE_SPACE;

		}

		break;

	case STATE_SPACE: // timing SPACE

		if (irdata == MARK) { // SPACE just ended, record it

			irparams.rawbuf[irparams.rawlen++] = irparams.timer;

			irparams.timer = 0;

			irparams.rcvstate = STATE_MARK;

		}

		else { // SPACE

			if (irparams.timer > 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

				irparams.rcvstate = STATE_STOP;

			}

		}

		break;

	case STATE_STOP: // waiting, measuring gap

		if (irdata == MARK) { // reset gap timer

			irparams.timer = 0;

		}

		break;

	}



	if (irparams.blinkflag) {

		if (irdata == MARK) {

			PORTB |= B00100000;  // turn pin 13 LED on

		}

		else {

			PORTB &= B11011111;  // turn pin 13 LED off

		}

	}

}



void IRrecv::resume() {

	irparams.rcvstate = STATE_IDLE;

	irparams.rawlen = 0;

}







// Decodes the received IR message

// Returns 0 if no data ready, 1 if data ready.

// Results of decoding are stored in results

int IRrecv::decode(decode_results *results) {

	results->rawbuf = irparams.rawbuf;

	results->rawlen = irparams.rawlen;

	if (irparams.rcvstate != STATE_STOP) {

		return ERR;

	}

#ifdef DEBUG

	Serial.println("Attempting NEC decode");

#endif

	if (decodeNEC(results)) {

		return DECODED;

	}



	

	if (results->rawlen >= 6) {

		// Only return raw buffer if at least 6 bits

		results->decode_type = UNKNOWN;

		results->bits = 0;

		results->value = 0;

		return DECODED;

	}

	// Throw away and start over

	resume();

	return ERR;

}



long IRrecv::decodeNEC(decode_results *results) {

	long data = 0;

	int offset = 0; // Skip first space

	// Initial mark

	if (!MATCH_MARK(results->rawbuf[offset], NEC_HDR_MARK)) {

		return ERR;

	}

	offset++;

	// Check for repeat

	if (irparams.rawlen == 4 &&

		MATCH_SPACE(results->rawbuf[offset], NEC_RPT_SPACE) &&

		MATCH_MARK(results->rawbuf[offset + 1], NEC_BIT_MARK)) {

		results->bits = 0;

		results->value = REPEAT;

		results->decode_type = NEC;

		return DECODED;

	}

	if (irparams.rawlen < 2 * NEC_BITS + 4) {

		return ERR;

	}

	// Initial space  

	if (!MATCH_SPACE(results->rawbuf[offset], NEC_HDR_SPACE)) {

		return ERR;

	}

	offset++;

	for (int i = 0; i < NEC_BITS; i++) {

		if (!MATCH_MARK(results->rawbuf[offset], NEC_BIT_MARK)) {

			return ERR;

		}

		offset++;

		if (MATCH_SPACE(results->rawbuf[offset], NEC_ONE_SPACE)) {

			data = (data << 1) | 1;

		}

		else if (MATCH_SPACE(results->rawbuf[offset], NEC_ZERO_SPACE)) {

			data <<= 1;

		}

		else {

			return ERR;

		}

		offset++;

	}

	// Success

	results->bits = NEC_BITS;

	results->value = data;

	results->decode_type = NEC;

	return DECODED;

}





// Gets one undecoded level at a time from the raw buffer.

// The RC5/6 decoding is easier if the data is broken into time intervals.

// E.g. if the buffer has MARK for 2 time intervals and SPACE for 1,

// successive calls to getRClevel will return MARK, MARK, SPACE.

// offset and used are updated to keep track of the current position.

// t1 is the time interval for a single bit in microseconds.

// Returns -1 for error (measured time interval is not a multiple of t1).

int IRrecv::getRClevel(decode_results *results, int *offset, int *used, int t1) {

	if (*offset >= results->rawlen) {

		// After end of recorded buffer, assume SPACE.

		return SPACE;

	}

	int width = results->rawbuf[*offset];

	int val = ((*offset) % 2) ? MARK : SPACE;

	int correction = (val == MARK) ? MARK_EXCESS : -MARK_EXCESS;



	int avail;

	if (MATCH(width, t1 + correction)) {

		avail = 1;

	}

	else if (MATCH(width, 2 * t1 + correction)) {

		avail = 2;

	}

	else if (MATCH(width, 3 * t1 + correction)) {

		avail = 3;

	}

	else {

		return -1;

	}



	(*used)++;

	if (*used >= avail) {

		*used = 0;

		(*offset)++;

	}

#ifdef DEBUG

	if (val == MARK) {

		Serial.println("MARK");

	}

	else {

		Serial.println("SPACE");

	}

#endif

	return val;

}
[/codesyntax] 下面是库文件IRremote315/IRremoteInt315.h: [codesyntax lang="cpp"]
/*
 * IRremote
 * Version 0.1 July, 2009
 * Copyright 2009 Ken Shirriff
 * For details, see http://arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
 *
 * Interrupt code based on NECIRrcv by Joe Knapp
 * http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1210243556
 * Also influenced by http://zovirl.com/2008/11/12/building-a-universal-remote-with-an-arduino/
 */

#ifndef IRremoteint_h
#define IRremoteint_h

#include <Arduino.h>

#define CLKFUDGE 5      // fudge factor for clock interrupt overhead  时钟中断开销
#define CLK 256      // max value for clock (timer 2)
#define PRESCALE 8      // timer2 clock prescale
#define SYSCLOCK 16000000  // main Arduino clock
#define CLKSPERUSEC (SYSCLOCK/PRESCALE/1000000)   // timer clocks per microsecond

#define ERR 0
#define DECODED 1

#define BLINKLED 13

// defines for setting and clearing register bits
#ifndef cbi
#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit))
#endif
#ifndef sbi
#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))
#endif

// clock timer reset value
#define INIT_TIMER_COUNT2 (CLK - USECPERTICK*CLKSPERUSEC + CLKFUDGE)//此处是为timer2计数器赋予初值
#define RESET_TIMER2 TCNT2 = INIT_TIMER_COUNT2        //TCNT是一个标记器,它标记了timer2的初值,此处的意义是让计数器从开始计算到值256的时间正好是50μs,

// pulse parameters in usec
#define NEC_HDR_MARK	9000
#define NEC_HDR_SPACE	4500
#define NEC_BIT_MARK	560
#define NEC_ONE_SPACE	1600
#define NEC_ZERO_SPACE	560
#define NEC_RPT_SPACE	2250



#define TOLERANCE 50  // percent tolerance in measurements <<---增加了容错率
#define LTOL (1.0 - TOLERANCE/100.) 
#define UTOL (1.0 + TOLERANCE/100.) 

#define _GAP 5000 // Minimum map between transmissions
#define GAP_TICKS (_GAP/USECPERTICK)

#define TICKS_LOW(us) (int) (((us)*LTOL/USECPERTICK))
#define TICKS_HIGH(us) (int) (((us)*UTOL/USECPERTICK + 1))

#ifndef DEBUG
#define MATCH(measured_ticks, desired_us) ((measured_ticks) >= TICKS_LOW(desired_us) && (measured_ticks) <= TICKS_HIGH(desired_us))
#define MATCH_MARK(measured_ticks, desired_us) MATCH(measured_ticks, (desired_us) + MARK_EXCESS)
#define MATCH_SPACE(measured_ticks, desired_us) MATCH((measured_ticks), (desired_us) - MARK_EXCESS)
// Debugging versions are in IRremote.cpp
#endif

// receiver states
#define STATE_IDLE     2
#define STATE_MARK     3
#define STATE_SPACE    4
#define STATE_STOP     5

// information for the interrupt handler
typedef struct {
  uint8_t recvpin;           // pin for IR data from detector
  uint8_t rcvstate;          // state machine
  uint8_t blinkflag;         // TRUE to enable blinking of pin 13 on IR processing
  unsigned int timer;     // state timer, counts 50uS ticks.
  unsigned int rawbuf[RAWBUF]; // raw data
  uint8_t rawlen;         // counter of entries in rawbuf
} 
irparams_t;

// Defined in IRremote.cpp
extern volatile irparams_t irparams;

// IR detector output is active low
#define MARK  0
#define SPACE 1

#define TOPBIT 0x80000000

#define NEC_BITS 32


#endif
[/codesyntax]
  • 参考
http://www.geek-workshop.com/thread-12589-1-1.html

你可能感兴趣的:(PWM,超再生接收模块,433m,超再生,315m)