单片机:实现红外接收(完整源码)

单片机实现红外接收功能详解

作者:Katie
代码日期:2025-03-28


目录

  1. 项目简介
    1.1 项目背景
    1.2 项目目标与意义
    1.3 红外接收模块概述

  2. 相关理论与基础知识
    2.1 红外通信原理
    2.2 红外编码与调制技术
    2.3 常见红外接收模块工作原理
    2.4 红外信号解码方法
    2.5 单片机红外接收中的关键技术

  3. 系统设计与实现思路
    3.1 系统总体架构
    3.2 硬件设计
    3.2.1 红外接收模块电路设计
    3.2.2 单片机接口与连接方案
    3.2.3 供电及干扰抑制设计
    3.3 软件系统设计
    3.3.1 红外信号捕捉与计时
    3.3.2 红外信号解码算法
    3.3.3 数据处理与输出接口
    3.4 整体数据流程图

  4. 详细代码实现
    4.1 代码整体结构
    4.2 完整代码(整合版)

  5. 代码解读
    5.1 系统初始化与外设配置
    5.2 红外信号捕捉与计时实现
    5.3 红外信号解码算法实现
    5.4 数据处理与结果输出

  6. 系统调试与测试
    6.1 硬件调试方法
    6.2 软件调试与信号验证
    6.3 实际应用测试与优化建议

  7. 项目总结与心得
    7.1 项目成果总结
    7.2 项目中的挑战与收获
    7.3 后续改进与扩展方向

  8. 参考资料与扩展阅读


1. 项目简介

1.1 项目背景

在现代嵌入式系统中,红外通信因其成本低、功耗低、实现简单等优点被广泛应用于遥控、数据传输、安防监控等场景。红外接收模块作为红外通信的重要组成部分,能够捕捉并解码遥控器等设备发出的红外信号,为系统提供用户输入和控制信号。对于资源受限的单片机系统来说,如何准确捕捉和解码红外信号是一项具有挑战性且十分实用的技术。

1.2 项目目标与意义

本项目旨在利用单片机实现红外接收功能,重点解决以下问题:

  • 捕捉并测量红外信号的脉冲宽度与间隔;

  • 解码红外信号(例如NEC、RC5等常见协议);

  • 将解码后的数据传递给主系统用于进一步控制或显示;

  • 设计高抗干扰能力的接收电路,确保在强噪声环境中依然能够准确接收信号。

项目的意义在于通过实践掌握红外信号采集、计时与解码技术,提升系统对外部遥控器等设备的兼容性,同时为后续复杂的无线通信和遥控系统开发奠定基础。

1.3 红外接收模块概述

红外接收模块通常包含一个红外接收头(带有内置滤光片和放大解调电路)和外围电路。常见的红外接收模块如VS1838B,其主要特点包括:

  • 自动解调红外信号,将载波调制信号转换为数字信号;

  • 输出为高/低电平信号,脉冲宽度和间隔对应遥控信号的编码;

  • 内置滤波和放大电路,增强抗干扰能力。

本项目将以红外接收模块为基础,结合单片机的定时器和外部中断,实现红外信号的捕捉和解码。


2. 相关理论与基础知识

2.1 红外通信原理

红外通信利用红外光(波长约700nm~1mm)进行数据传输。基本原理是:

  • 发送端通过红外LED发射调制后的红外光信号;

  • 接收端通过红外接收管捕捉信号,并经过内置滤波和解调电路处理,输出数字信号;

  • 通过对输出信号的脉冲宽度、间隔等进行解码,恢复出原始数据。

2.2 红外编码与调制技术

常用红外编码协议包括NEC、RC5、Sony SIRC等。不同协议在编码方式、调制频率(通常为38kHz)以及数据位数上有所不同。

  • 调制技术:为避免环境光干扰,红外信号通常采用载波调制,发送端在38kHz左右频率上调制信号;

  • 编码技术:协议规定了每一位信号的时间宽度和间隔,例如NEC协议采用脉冲间隔编码,通过长脉冲和短脉冲区别0和1。

2.3 常见红外接收模块工作原理

以VS1838B为例,其内部集成了光电探测、信号放大、载波滤波及解调电路。模块工作流程:

  • 接收端接收到调制的红外信号后,内部电路会滤除环境光,放大信号并进行解调;

  • 输出端提供数字信号,信号的脉冲宽度与原始编码信息对应,供单片机后续处理。

2.4 红外信号解码方法

红外信号解码主要依赖于定时器精确计时脉冲宽度和间隔。基本步骤为:

  1. 捕捉红外接收模块输出的高低电平信号;

  2. 利用定时器或外部中断记录每个脉冲的持续时间;

  3. 根据协议规定,判断每个脉冲代表的数据位(如0或1);

  4. 按顺序组合数据位,恢复完整的数据。

2.5 单片机红外接收中的关键技术

在单片机实现红外接收过程中,关键技术包括:

  • 外部中断/定时器捕捉:用于精确记录红外信号的脉冲宽度;

  • 信号去抖与滤波:防止噪声和抖动干扰计时,确保解码准确;

  • 协议解析算法:根据具体红外协议解析脉冲序列,还原出遥控器命令。


3. 系统设计与实现思路

3.1 系统总体架构

本系统主要包括三个部分:

  1. 红外信号采集模块:利用红外接收模块获取遥控器发出的红外信号,通过外部中断或定时器捕捉信号变化。

  2. 红外信号解码模块:根据捕捉的脉冲宽度数据,按照选定的红外协议(例如NEC)进行解码,恢复出按键数据。

  3. 数据处理与输出模块:将解码后的数据传递给主系统,进行显示(例如通过串口输出或LCD显示),并触发相应的控制逻辑。

3.2 硬件设计

3.2.1 红外接收模块电路设计
  • 红外接收头:选择常用型号(如VS1838B),连接至单片机数字输入口(例如P3.2或其他支持外部中断的引脚)。

  • 滤波与抗干扰:在红外接收模块电路中增加适当的滤波电容和抗干扰设计,确保在强环境光干扰下仍能正常工作。

  • 供电:确保红外接收模块稳定供电,通常为5V直流电源。

3.2.2 单片机接口与连接方案
  • 外部中断接口:选择支持外部中断的引脚,用于捕捉红外信号的上升沿和下降沿;

  • 定时器接口:利用定时器实现高精度计时,记录脉冲持续时间;

  • 通信接口:配置串口或其他显示接口,用于输出解码后的数据和调试信息。

3.2.3 供电及干扰抑制设计
  • 稳压电路:采用稳压器和滤波电容,确保整个系统稳定工作;

  • 抗干扰设计:布置良好的接地、屏蔽设计以及滤波电路,降低外部电磁干扰对红外信号接收的影响。

3.3 软件系统设计

3.3.1 红外信号捕捉与计时
  • 采用外部中断触发捕捉,记录红外接收模块输出信号变化的时间戳;

  • 利用定时器实现精确计时,将每个脉冲的高电平和低电平宽度存储在缓冲区中,供后续解码。

3.3.2 红外信号解码算法
  • 根据选定的红外协议(例如NEC协议),分析捕捉到的脉冲宽度数据;

  • 设定各个数据位对应的时间阈值,判断每个脉冲表示0或1;

  • 将所有数据位组合成完整的数据包,进行校验和解析,获得遥控器按键码。

3.3.3 数据处理与输出接口
  • 将解码后的红外数据传递给主控制系统,进行逻辑判断与控制动作;

  • 通过串口、LCD或其他方式将红外数据和调试信息输出,便于实时监控和调试;

  • 支持系统错误检测,必要时记录异常信号供后续分析。

┌────────────────────────┐
│      系统上电初始化      │
└────────────┬───────────┘
             │
             ▼
┌────────────────────────┐
│   红外接收模块捕捉信号    │
│(外部中断、定时器计时)   │
└────────────┬───────────┘
             │
             ▼
┌────────────────────────┐
│  红外信号数据存储与缓冲   │
└────────────┬───────────┘
             │
             ▼
┌────────────────────────┐
│ 红外信号解码(协议解析)  │
└────────────┬───────────┘
             │
             ▼
┌────────────────────────┐
│  数据处理与逻辑判断      │
└────────────┬───────────┘
             │
             ▼
┌────────────────────────┐
│  数据输出与控制响应      │
└────────────────────────┘

3.5 软件模块划分

软件部分主要分为:

  • 初始化模块:配置单片机I/O、定时器、外部中断、串口等。

  • 红外信号采集模块:捕捉红外信号、记录脉冲时间数据。

  • 红外信号解码模块:根据红外协议对捕捉数据进行解析。

  • 数据输出模块:通过串口或LCD输出解码数据,便于调试。

  • 错误检测与调试模块:记录异常信号,支持系统稳定性检测。


4. 详细代码实现

下面给出完整代码(整合版),代码中将红外信号采集、解码与数据输出功能整合到一起。所有函数均在同一文件中实现,并附有非常详细的注释,便于后续理解和扩展。

4.1 完整代码(整合版)

/*
 * 单片机实现红外接收功能
 * 作者:Katie
 * 代码日期:2025-03-28
 *
 * 本程序实现了一个基于单片机的红外接收系统,主要功能包括:
 * 1. 捕捉红外接收模块输出信号,通过外部中断和定时器记录脉冲宽度;
 * 2. 根据常见红外协议(例如NEC协议)对捕捉到的信号进行解码,恢复出遥控器按键信息;
 * 3. 将解码后的数据通过串口输出,用于调试和后续控制。
 *
 * 硬件说明:
 * - 红外接收模块(例如VS1838B)连接到单片机的外部中断引脚P3.2;
 * - 定时器用于实现微秒级计时,记录信号脉冲宽度;
 * - 串口(UART)用于将解码结果输出到PC调试工具。
 */

#include <reg51.h>
#include <stdio.h>
#include <string.h>

// -------------------- 宏定义 --------------------
#define FOSC 12000000UL    // 系统时钟12MHz
#define TIMER_RELOAD (256 - (FOSC/12/1000000UL))  // 定时器重载值,用于1微秒延时
#define IR_RECEIVE_PIN P3_2 // 红外接收模块连接到P3.2(外部中断0)

// 红外协议相关(以NEC协议为例)
#define NEC_HEADER_HIGH 9000  // 9ms 高电平
#define NEC_HEADER_LOW 4500   // 4.5ms 低电平
#define NEC_BIT_MARK 560      // 560us 高电平标记
#define NEC_ONE_SPACE 1690    // 1表示的空格约1690us
#define NEC_ZERO_SPACE 560    // 0表示的空格约560us
#define NEC_REPEAT_SPACE 2250 // 重复码空格约2250us

// 允许误差范围
#define TOLERANCE 200

// -------------------- 全局变量 --------------------
// 用于红外信号计时与数据存储
volatile unsigned long pulseWidth[100]; // 存储捕捉到的每个脉冲宽度(单位微秒)
volatile unsigned char pulseCount = 0;  // 捕捉到的脉冲个数
volatile bit receiving = 0;             // 标志位:当前是否正在接收红外信号
volatile unsigned long lastCaptureTime = 0;  // 上次捕获的时间(微秒),用于计算间隔

// 记录系统时间(微秒级),通过定时器中断更新
volatile unsigned long systemTime = 0;

// 解码后的红外数据
volatile unsigned long irData = 0;
volatile bit irDataValid = 0;

// -------------------- 函数原型声明 --------------------
void SystemInit(void);
void Timer0_Init(void);
void UART_Init(void);
void Delay_us(unsigned int us);
void Delay_ms(unsigned int ms);
void Start_IR_Receive(void);
void Process_IR_Data(void);
void UART_SendChar(char c);
void UART_SendString(const char *str);
void UART_SendHex(unsigned long data);

// 外部中断0服务函数,用于红外信号捕捉
void EX0_ISR(void) interrupt 0;

// 定时器0中断服务函数,用于系统时间更新
void Timer0_ISR(void) interrupt 1;

// -------------------- 主函数 --------------------
void main(void)
{
    SystemInit();  // 系统初始化
    Timer0_Init(); // 初始化定时器0,用于微秒级计时
    UART_Init();   // 初始化UART,波特率9600
    EA = 1;        // 允许全局中断

    // 主循环:周期性检查是否接收到完整红外数据,并输出
    while(1)
    {
        // 如果红外数据有效,处理数据
        if (irDataValid)
        {
            UART_SendString("IR Data: 0x");
            UART_SendHex(irData);
            UART_SendString("\r\n");
            irDataValid = 0;  // 清除标志,等待下一组数据
        }
        Delay_ms(50);
    }
}

// -------------------- 系统初始化函数 --------------------
void SystemInit(void)
{
    // 初始化系统时间及变量
    systemTime = 0;
    pulseCount = 0;
    receiving = 0;
    irData = 0;
    irDataValid = 0;
}

// -------------------- 定时器0初始化函数 --------------------
void Timer0_Init(void)
{
    TMOD &= 0xF0;         // 清除定时器0控制位
    TMOD |= 0x01;         // 定时器0模式1(16位定时器)
    TH0 = TIMER_RELOAD;   // 加载初值
    TL0 = TIMER_RELOAD;
    ET0 = 1;              // 允许定时器0中断
    TR0 = 1;              // 启动定时器0
}

// -------------------- UART初始化函数 --------------------
void UART_Init(void)
{
    SCON = 0x50;   // 串口模式1,8位数据,REN允许接收
    TMOD &= 0x0F;
    TMOD |= 0x20;  // 定时器1模式2(8位自动重载)
    TH1 = 0xFD;    // 波特率9600(12MHz晶振)
    TL1 = 0xFD;
    TR1 = 1;       // 启动定时器1
}

// -------------------- 延时函数 --------------------
void Delay_us(unsigned int us)
{
    unsigned int i;
    for(i = 0; i < us; i++)
    {
        _nop_(); _nop_(); _nop_(); _nop_();
    }
}

void Delay_ms(unsigned int ms)
{
    unsigned int i, j;
    for(i = 0; i < ms; i++)
        for(j = 0; j < 120; j++);
}

// -------------------- 外部中断0服务函数 --------------------
/*
 * EX0_ISR函数用于捕捉红外接收模块输出信号的下降沿,
 * 每当检测到信号从高电平跳变为低电平时触发中断,
 * 配合系统定时器记录脉冲时间,用于红外协议解码。
 */

void EX0_ISR(void) interrupt 0
{
    unsigned long currentTime;
    // 获取当前系统时间(微秒)
    currentTime = systemTime;
    
    // 如果不是接收状态,则标记开始接收
    if (!receiving)
    {
        receiving = 1;
        pulseCount = 0;
    }
    else
    {
        // 计算上一次信号到当前的时间差,即脉冲宽度
        pulseWidth[pulseCount] = currentTime - lastCaptureTime;
        pulseCount++;
        // 如果脉冲数量超过缓冲区大小,则不再记录(防止溢出)
        if(pulseCount >= 100) pulseCount = 99;
    }
    // 更新最后捕获时间
    lastCaptureTime = currentTime;
    
    // 若超过一定时间未检测到信号(例如>10ms),则认为接收结束
    if ( (currentTime - lastCaptureTime) > 10000 )
    {
        receiving = 0;
        Process_IR_Data();
    }
}

// -------------------- 定时器0中断服务函数 --------------------
void Timer0_ISR(void) interrupt 1
{
    // 重载定时器0
    TH0 = TIMER_RELOAD;
    TL0 = TIMER_RELOAD;
    systemTime++; // 每1微秒加1(实际误差可忽略)
}

// -------------------- 红外数据处理与解码函数 --------------------
/*
 * Process_IR_Data函数根据捕捉到的脉冲宽度数据,
 * 按照NEC协议进行解码,组合成32位红外数据。
 * 若解码成功,将数据存入全局变量irData,并置irDataValid标志。
 */
void Process_IR_Data(void)
{
    unsigned char i;
    unsigned long data = 0;
    
    // NEC协议:第一段为9ms高电平、4.5ms低电平(头部),然后32位数据
    // 本示例中简单校验头部时间(可扩展校验机制)
    if (pulseCount < 2) return; // 数据不足
    
    // 校验头部:假设pulseWidth[0]为头部高电平,pulseWidth[1]为头部低电平
    if ( (pulseWidth[0] < (NEC_HEADER_HIGH - TOLERANCE)) || (pulseWidth[0] > (NEC_HEADER_HIGH + TOLERANCE)) )
        return;
    if ( (pulseWidth[1] < (NEC_HEADER_LOW - TOLERANCE)) || (pulseWidth[1] > (NEC_HEADER_LOW + TOLERANCE)) )
        return;
    
    // 从第三个脉冲开始为数据(共32位,每位由一个高电平标记和一个低电平间隔组成)
    // pulseWidth[2] ~ pulseWidth[65] 代表32位数据的标记和空格
    if (pulseCount < 66) return; // 数据不完整
    
    // 循环解析每一位数据
    for (i = 0; i < 32; i++)
    {
        // 对应的低电平间隔存储在pulseWidth[2 + i*2 + 1]
        if (pulseWidth[2 + i*2 + 1] > (NEC_ZERO_SPACE + TOLERANCE))
            data = (data << 1) | 1;  // 认为为1
        else
            data = (data << 1);      // 认为为0
    }
    
    irData = data;
    irDataValid = 1;
    
    // 重置脉冲计数,准备下一次接收
    pulseCount = 0;
}

// -------------------- UART发送函数 --------------------
void UART_SendChar(char c)
{
    SBUF = c;
    while(!TI);
    TI = 0;
}

void UART_SendString(const char *str)
{
    while(*str)
    {
        UART_SendChar(*str++);
    }
}

void UART_SendHex(unsigned long data)
{
    char buffer[9];
    sprintf(buffer, "%08lX", data);
    UART_SendString(buffer);
}

5. 代码解读

本文代码主要分为以下几个部分:

5.1 系统初始化与外设配置

  • SystemInit:初始化全局变量,包括系统时间、脉冲计数和红外数据变量,确保系统处于初始状态。

  • Timer0_Init:配置定时器0为16位模式,用于实现微秒级时间测量,更新全局变量systemTime。

  • UART_Init:初始化串口用于日志输出和调试,设置波特率为9600。

5.2 红外信号捕捉与计时实现

  • EX0_ISR(外部中断0服务函数):利用外部中断捕捉红外接收模块输出信号的上升沿和下降沿,记录每个脉冲宽度,存入pulseWidth数组,同时更新pulseCount和lastCaptureTime。

  • Timer0_ISR:定时器0中断服务函数,每1微秒更新systemTime,为捕捉脉冲宽度提供精确时间基准。

5.3 红外信号解码算法实现

  • Process_IR_Data:当检测到红外信号结束(长时间无信号)后,对存储的脉冲宽度数据按照NEC协议进行解码。首先校验头部信号,再解析32位数据,判断每个位是0还是1,最终组合成一个32位数据存入irData,并置标志irDataValid。

5.4 数据处理与结果输出

  • 主循环:周期性检查全局变量irDataValid,若数据有效,则通过UART_SendString与UART_SendHex将解码后的红外数据输出到串口,便于调试和后续处理。

  • 延时函数:Delay_us与Delay_ms用于生成微秒级和毫秒级延时,确保时间测量和信号捕捉的精度。


6. 系统调试与测试

6.1 硬件调试方法

  • 红外模块信号检测:利用示波器检测红外接收模块的输出信号,验证触发、载波和解调效果。

  • 外部中断验证:观察外部中断引脚的电平变化,确保能准确捕捉红外信号的上升沿和下降沿。

  • 定时器精度校准:使用标准信号源或逻辑分析仪验证定时器0中断周期是否满足微秒级要求。

6.2 软件调试与信号验证

  • 脉冲宽度数据检查:通过调试器观察pulseWidth数组中存储的各脉冲宽度,验证是否符合NEC协议规定的时序。

  • 数据解码测试:将已知红外遥控器发出的信号数据作为输入,检查Process_IR_Data函数是否能正确解码出按键信息。

  • 串口输出验证:通过串口调试工具观察UART输出信息,确保解码后的数据格式正确。

6.3 实际应用测试与优化建议

  • 多环境测试:在不同光照和背景噪声环境下测试红外接收效果,优化抗干扰设计。

  • 信号平均处理:若解码不稳定,可考虑加入多次采样平均处理或数据滤波算法,提高解码精度。

  • 系统延时与中断响应优化:调整延时函数与中断处理,确保系统实时性不受影响,同时降低CPU占用。


7. 项目总结与心得

7.1 项目成果总结

本项目成功实现了基于单片机的红外接收系统,主要成果包括:

  • 利用外部中断与定时器实现了红外信号的精确捕捉,记录每个脉冲的宽度。

  • 结合NEC协议,对捕捉到的信号进行解码,恢复出32位红外数据。

  • 通过UART输出调试信息,便于验证系统工作状态和数据准确性。

  • 系统结构清晰,软件模块划分合理,便于后续扩展(如增加LCD显示、存储功能等)。

7.2 项目中的挑战与收获

  • 信号捕捉精度:由于红外信号的脉冲宽度微秒级别,如何准确捕捉信号并消除干扰是本项目的关键。通过外部中断和定时器配合,实现了较高的计时精度。

  • 解码算法设计:针对不同红外协议设计相应的解码算法具有一定难度。本项目以NEC协议为例,掌握了解码流程和关键时间参数的确定。

  • 抗干扰与系统稳定性:红外信号易受环境光和电磁干扰影响。通过硬件滤波和软件校验机制,提高了系统鲁棒性。

  • 模块化设计:项目实现过程中,分模块设计不仅便于调试,也为后续功能扩展提供了良好的基础。

7.3 后续改进与扩展方向

  • 支持多种红外协议:扩展系统支持RC5、Sony SIRC等其他红外编码协议,提高系统兼容性。

  • 数据存储与实时显示:增加LCD显示屏或SD卡存储功能,将接收的红外数据实时显示或保存,以便于远程监控和数据分析。

  • 无线传输:结合无线模块,将红外数据通过无线网络传输至远程终端,实现远程控制和监控。

  • 软件优化:针对高频中断处理和数据解码,进一步优化代码效率,降低CPU占用率,保证系统实时性。


8. 参考资料与扩展阅读

  1. 《嵌入式系统原理与接口技术》——详细介绍了51单片机的硬件资源、外部中断和定时器配置方法。

  2. 《红外通信原理与实践》——阐述了红外信号调制、编码及常见协议的理论与应用。

  3. 《C语言嵌入式系统开发》——涵盖了数据结构、模块化设计和中断编程等技术,是实现本项目的理论基础。

  4. 各大技术论坛(如CSDN、51单片机论坛)中的红外接收案例和讨论,为本项目提供了大量实践经验和优化建议。


结语

本文从理论基础、系统架构设计,到详细代码实现、代码解读、系统调试与测试,再到项目总结与后续改进建议,全面详实地介绍了如何利用单片机实现红外接收功能。通过本项目,读者不仅可以掌握红外信号捕捉、计时与解码的关键技术,还能了解到如何设计抗干扰和高稳定性的红外接收系统。该系统适用于遥控、安防、家电控制等多个应用场景,为嵌入式系统开发提供了有力技术支持。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值