认识红外线
可见光、红外线和电波,都是电磁波的一种,
远红外线和近红外线,人体在常温下所释放的红外线波长约10um(微米)。靠近可见光部分的近红外线,几乎不会散发热能,通常用于红外线通信、遥控和距离传感器。
人体红外线传感器
传感器上头的白色半透明PE透镜黏在电路板上,里面有一个热释电型传感器,热释电(pyroelectric)代表该模块会随着温度变化产生电子信号。传感器模块上的IC电路将会接收并处理传感器信号,以高电位或低电位的形式输出。人体红外线侦测模块,相当于电子开关,平常输出低电位(0V),侦测到人体移动时,变成高电位(3.3V)。
此传感器全名为被动式(Passive)红外移动传感器,红外线(Infrared)英文简称IR,所以此传感器又称为PIR移动传感器,一般通称为“人体红外线传感器”,所谓“被动式”侦测,代表这种传感器跟超声波传感器不同,它不会发出侦测信号,而是被动地接收红外线源。这种传感器内部有两个侦测“窗口”,被侦测物体必须要水平移动,它才能比较出红外线的变化,若朝向它的正面移动,就比较不容易被侦测到。
热释电型传感器,热释电(pyroelectric)代表该模块会随着温度变化产生电子信号。传感器模块上的IC电路将会接收并处理传感器的信号,以高电位或低电位的形式输出。总之,人体红外线侦测模块,相当于电子开关,平常输出低电位(0V),侦测到人体移动时,变成高电位(3.3V)。
动手做12-1 监测人体移动
实验说明: 使用人体红外线传感器来点亮位于Arduino板子13端口的LED
**程序:**由于人体红外线传感器模块只会返回0与1两种状态值。
const byte pirPin = 12; //红外线传感器信号端口
const byte ledPin = 13; //LED端口
void setup() {
pinMode(pirPin, INPUT);
pinMode(ledPin, OUTPUT); //LED端口设定成“输出”
}
void loop(){
boolean val = digitalRead(pirPin); //读取传感器值
if (val) {
digitalWrite(ledPin, HIGH);
} else {
digitalWrite(ledPin, LOW);
}
}
红外线遥控
红外线遥控接收器,都只对特定的频率信号(正确的名字叫做载波,通常是36kHZ或38kHZ)和“通关密语”有反应。这个“通关密语”称为协议。
红外线遥控接收元器件
红外线遥控接收元器件,它的内部包含红外线接收元器件以及信号处理IC,常见的型号是TSOP4836和TSOP4838(后面两个数字代表载波频率)。
普通的红外线接收元器件不含信号处理IC,其主要规格是感应的红外线波长范围。
红外线接收元器件的外观像一般的LED,通常用在障碍物检测及距离感测,
动手做12-2 使用IRremote扩展库解析红外线遥控值
实验说明: 将组装一个Arduino万用红外线遥控接收器,并通过Ken Shirriff写的IRremote扩展库(网址:https://github.com/shirriff/Arduino-IRremote),读取各大品牌的红外线遥控器信号。
程序: 请先把“IRremote”扩展库文件复制到Arduino的libraries文件夹。选择文件→示例→IRremote→IRrecvDemo。
#include <IRremote.h>
int RECV_PIN = 11;
IRrecv irrecv(RECV_PIN); //声明一个红外接收对象,名叫irrecv,接收端口是11
decode_results results; // 声明一个存储接收值得变量
void setup() {
Serial.begin(9600);
irrecv.enableIRIn(); //启动红外接收功能
}
void loop() {
//解析红外接收值,若decode()返回true,代表有收到新的数据。
if (irrecv.decode(&results)) {
Serial.println(results.value, HEX); //读取解析后的数字,并以16进位格式输出。
irrecv.resume(); //准备进行接收下一组数据
}
}
读取红外线原始(raw)格式
IRremote扩展库提供另一个“IRrecvDump”示例程序,能辨别并显示红外线遥控信号的格式名称,并输出接收器所收到的原始数据。
//------------------------------------------------------------------------------
// Include the IRremote library header
//
#include <IRremote.h>
//------------------------------------------------------------------------------
// Tell IRremote which Arduino pin is connected to the IR Receiver (TSOP4838)
//
int recvPin = 11;
IRrecv irrecv(recvPin);
//+=============================================================================
// Configure the Arduino
//
void setup ( )
{
Serial.begin(9600); // Status message will be sent to PC at 9600 baud
irrecv.enableIRIn(); // Start the receiver
}
//+=============================================================================
// Display IR code
//
void ircode (decode_results *results)
{
// Panasonic has an Address
if (results->decode_type == PANASONIC) {
Serial.print(results->address, HEX);
Serial.print(":");
}
// Print Code
Serial.print(results->value, HEX);
}
//+=============================================================================
// Display encoding type
//
void encoding (decode_results *results)
{
switch (results->decode_type) {
default:
case UNKNOWN: Serial.print("UNKNOWN"); break ;
case NEC: Serial.print("NEC"); break ;
case SONY: Serial.print("SONY"); break ;
case RC5: Serial.print("RC5"); break ;
case RC6: Serial.print("RC6"); break ;
case DISH: Serial.print("DISH"); break ;
case SHARP: Serial.print("SHARP"); break ;
case JVC: Serial.print("JVC"); break ;
case SANYO: Serial.print("SANYO"); break ;
case MITSUBISHI: Serial.print("MITSUBISHI"); break ;
case SAMSUNG: Serial.print("SAMSUNG"); break ;
case LG: Serial.print("LG"); break ;
case WHYNTER: Serial.print("WHYNTER"); break ;
case AIWA_RC_T501: Serial.print("AIWA_RC_T501"); break ;
case PANASONIC: Serial.print("PANASONIC"); break ;
case DENON: Serial.print("Denon"); break ;
}
}
//+=============================================================================
// Dump out the decode_results structure.
//
void dumpInfo (decode_results *results)
{
// Check if the buffer overflowed
if (results->overflow) {
Serial.println("IR code too long. Edit IRremoteInt.h and increase RAWBUF");
return;
}
// Show Encoding standard
Serial.print("Encoding : ");
encoding(results);
Serial.println("");
// Show Code & length
Serial.print("Code : ");
ircode(results);
Serial.print(" (");
Serial.print(results->bits, DEC);
Serial.println(" bits)");
}
//+=============================================================================
// Dump out the decode_results structure.
//
void dumpRaw (decode_results *results)
{
// Print Raw data
Serial.print("Timing[");
Serial.print(results->rawlen-1, DEC);
Serial.println("]: ");
for (int i = 1; i < results->rawlen; i++) {
unsigned long x = results->rawbuf[i] * USECPERTICK;
if (!(i & 1)) { // even
Serial.print("-");
if (x < 1000) Serial.print(" ") ;
if (x < 100) Serial.print(" ") ;
Serial.print(x, DEC);
} else { // odd
Serial.print(" ");
Serial.print("+");
if (x < 1000) Serial.print(" ") ;
if (x < 100) Serial.print(" ") ;
Serial.print(x, DEC);
if (i < results->rawlen-1) Serial.print(", "); //',' not needed for last one
}
if (!(i % 8)) Serial.println("");
}
Serial.println(""); // Newline
}
//+=============================================================================
// Dump out the decode_results structure.
//
void dumpCode (decode_results *results)
{
// Start declaration
Serial.print("unsigned int "); // variable type
Serial.print("rawData["); // array name
Serial.print(results->rawlen - 1, DEC); // array size
Serial.print("] = {"); // Start declaration
// Dump data
for (int i = 1; i < results->rawlen; i++) {
Serial.print(results->rawbuf[i] * USECPERTICK, DEC);
if ( i < results->rawlen-1 ) Serial.print(","); // ',' not needed on last one
if (!(i & 1)) Serial.print(" ");
}
// End declaration
Serial.print("};"); //
// Comment
Serial.print(" // ");
encoding(results);
Serial.print(" ");
ircode(results);
// Newline
Serial.println("");
// Now dump "known" codes
if (results->decode_type != UNKNOWN) {
// Some protocols have an address
if (results->decode_type == PANASONIC) {
Serial.print("unsigned int addr = 0x");
Serial.print(results->address, HEX);
Serial.println(";");
}
// All protocols have data
Serial.print("unsigned int data = 0x");
Serial.print(results->value, HEX);
Serial.println(";");
}
}
//+=============================================================================
// The repeating section of the code
//
void loop ( )
{
decode_results results; // Somewhere to store the results
if (irrecv.decode(&results)) { // Grab an IR code
dumpInfo(&results); // Output the results
dumpRaw(&results); // Output the results in RAW format
dumpCode(&results); // Output the results as source code
Serial.println(""); // Blank line between entries
irrecv.resume(); // Prepare for the next value
}
}
动手做12-3 使用红外线遥控器控制舵机
实验说明:取得红外线遥控器的句柄之后,你就可以用遥控器来控制Arduino,本例将示范通过红外线遥控舵机。
实验程序:将依据遥控器的左、右箭头键,调整舵机的旋转角度,以及“录像”按键打开或关闭板子上第13脚的LED。
#include <IRremote.h>
#include <Servo.h>
Servo servo;
const byte RECV_PIN = 11; //
const byte LED_PIN = 13; //
const byte SERVO_PIN = 8; //
boolean sw = false; //
byte servoPos = 90; //
IRrecv irrecv(RECV_PIN); //
decode_results results; //
void setup() {
irrecv.enableIRIn(); //
pinMode(LED_PIN, OUTPUT); //
servo.attach(SERVO_PIN); //
servo.write(servoPos); //
}
void loop() {
if (irrecv.decode(&results)) { //
switch (results.value) { //
case 0xC1C7C03F: //若此数值等于“录像”
sw = !sw; //
digitalWrite(LED_PIN, sw); //
break;
case 0xC1C7C43B: //
if (servoPos > 10) { //
servoPos -= 10; //
servo.write(servoPos); //
}
break;
case 0xC1C744BB:
if (servoPos < 170) {
servoPos += 10; //
servo.write(servoPos); //
}
break;
}
irrecv.resume(); //
}
}
动手做12-4 从Arduino发射红外线遥控电器
实验说明: IRremote扩展库也具备发射红外线遥控信号的功能,本单元将组装一个Arduino红外线遥控发射器,并从“串口监视器”指挥它来遥控家电
实验电路: 根据IRremote扩展库的设定,红外线发射LED必须接在第3端口,而且最好先串联一个330Ω电阻保护LED。
实验程序: 使用IRremote扩张库发射红外线信号之前,必须先声明一个“I”类型的对象IRsend irsend;
,程序将通过此对象发射制定格式的信号,以发出NEC红外线为例,指令:irsend.sendNEC(红外线编码, 位数);
示例: 从串口获得任何字符时,Arduino发射红外线上面的信号;
#include <IRremote.h>
IRsend irsend;
void setup(){
Serial.begin(9600);
}
void loop() {
if (Serial.read() != -1) {
irsend.sendNEC(0xC1C7C03F, 32);
Serial.println("Action!");
}
}