目录
[17.1 红外遥控简介](#17.1 红外遥控简介)
[17.2 红外遥控硬件电路](#17.2 红外遥控硬件电路)
[17.3 NEC编码](#17.3 NEC编码)
[17.4 51单片机+红外遥控的硬件连接](#17.4 51单片机+红外遥控的硬件连接)
[17.5 状态机+中断+定时器的红外解码](#17.5 状态机+中断+定时器的红外解码)
[17.5.1 中断模块](#17.5.1 中断模块)
[17.5.2 定时器模块](#17.5.2 定时器模块)
[17.5.3 状态机红外解码模块](#17.5.3 状态机红外解码模块)
[17.6 项目示例1:红外遥控](#17.6 项目示例1:红外遥控)
[✅main.c 主函数:](#✅main.c 主函数:)
[17.7 项目示例2:红外遥控电机调速](#17.7 项目示例2:红外遥控电机调速)
[✅main.c 主函数:](#✅main.c 主函数:)
17.1 红外遥控简介
红外遥控是一种以 红外线(波长约 940nm,不可见光) 为传输介质的短距离无线通信方式,核心由两部分组成:
- 发射端:红外遥控器(内置红外发射管),按下按键时会发送编码后的红外信号;
- 接收端:红外接收头(如 HS0038),接在 51 单片机上,负责接收并解调红外信号,输出单片机可识别的电信号。

17.2 红外遥控硬件电路


红外信号会调制在 38kHz 载波上(抗干扰),接收头会自动解调,输出 "去载波" 后的高低电平信号,单片机只需解析电平的时间长短即可。
17.3 NEC编码

地址码:区分不同遥控器(比如电视 / 空调遥控器,避免串扰)
命令码:对应按键的功能(比如 "1" 键、"+" 键,每个按键对应唯一的 8 位数据);
地址反码与命令反码均是用于校验作用,确保数据接收无误

17.4 51单片机+红外遥控的硬件连接
红外接收头(HS0038)接线极简单,仅需 3 根线,推荐接外部中断引脚(避免轮询占用 CPU):

为什么选外部中断口?因为红外信号的电平变化是 "瞬间的",用中断可以及时捕捉引导码的下降沿,避免数据丢失。

红外信号会调制在 38kHz 载波上(抗干扰),接收头会自动解调,输出 "去载波" 后的高低电平信号,单片机只需解析电平的时间长短即可。

17.5 状态机+中断+定时器的红外解码
17.5.1 中断模块

⭐Int0.c
cpp
#include <REGX52.H> // 52系列单片机寄存器定义头文件,包含IT0、IE0、EX0等中断相关寄存器的定义
/**
* @brief 外部中断0(INT0)初始化函数
* @param 无
* @retval 无
* @note INT0对应单片机P3.2引脚,此函数配置该中断为下降沿触发、开启中断并设置高优先级
*/
void Int0_Init(void)
{
// 1. 配置外部中断0的触发方式
IT0=1; // IT0是TCON寄存器的bit0位:
// IT0=1 → 外部中断0由**下降沿**触发(红外遥控解码常用此方式,捕捉电平突变)
// IT0=0 → 外部中断0由**低电平**触发(适合持续低电平触发的场景)
// 2. 清除外部中断0的中断请求标志
IE0=0; // IE0是TCON寄存器的bit1位:
// IE0=1表示有外部中断0的中断请求,初始化时手动清零,避免误触发
// 3. 开启外部中断0的中断允许
EX0=1; // EX0是IE寄存器的bit0位:
// EX0=1 → 允许外部中断0请求,EX0=0 → 关闭外部中断0
// 4. 开启总中断允许(CPU级)
EA=1; // EA是IE寄存器的bit7位:
// EA=1 → 开启单片机总中断(所有中断的总开关,必须开启否则任何中断都无效)
// EA=0 → 关闭所有中断,即使单个中断允许位开启也无效
// 5. 设置外部中断0的优先级为高优先级
PX0=1; // PX0是IP寄存器的bit0位:
// PX0=1 → 外部中断0为高优先级,PX0=0 → 为低优先级
// 高优先级中断可打断低优先级中断,适合红外解码这种需要及时响应的场景
}
/* 外部触发中断模板
void Int0_Routine(void) interrupt 0
{
// 中断服务函数主体:中断触发后执行的代码(如红外解码逻辑、按键处理等)
// interrupt 0 是固定写法,表示这是外部中断0的中断服务函数(中断号0对应INT0)
}
*/
⭐Int0.h
cpp
#ifndef _INT0_H_
#define _INT0_H_
void Int0_Init(void);
#endif
17.5.2 定时器模块
⭐Timer0.c
cpp
#include <REGX52.H> // 52系列单片机寄存器定义头文件,包含TMOD、TL0、TH0等定时器相关寄存器
/**
* @brief 定时器0初始化函数
* @param 无
* @retval 无
* @note 配置定时器0为16位定时器模式(模式1),晶振为12.000MHz,初始不启动计时
* 12MHz晶振下,定时器0每计数1次耗时1us(机器周期=12/晶振频率=1us)
*/
void Timer0_Init(void) //1毫秒@12.000MHz(注:此处注释仅标注晶振,实际初值为0,需手动设置)
{
// 配置定时器0的工作模式(TMOD寄存器:高4位控制定时器1,低4位控制定时器0)
TMOD &= 0xF0; // 清零定时器0的模式位(bit0~bit3),保留定时器1的配置
TMOD |= 0x01; // 设置定时器0为模式1(16位定时/计数模式,无自动重装)
// 设置定时器初始计数值(此处初始化为0,后续通过Timer0_SetCounter手动设置)
TL0 = 0x00; // 低8位初值设为0
TH0 = 0x00; // 高8位初值设为0
TF0 = 0; // 清除定时器0的溢出标志(TF0=1表示定时器溢出,初始化时清零避免误触发)
TR0 = 0; // 定时器0运行控制位置0 → 初始化后定时器不启动计时
}
/**
* @brief 设置定时器0的计数值
* @param Value:要设置的16位计数值(范围0~65535)
* @retval 无
* @note 将16位数值拆分为高8位(TH0)和低8位(TL0)分别写入定时器寄存器
*/
void Timer0_SetCounter(unsigned char Value) // 注:参数建议改为unsigned int更合理,此处保留原代码
{
TH0 = Value / 256; // 取Value的高8位(除以256等价于右移8位),写入TH0寄存器
TL0 = Value % 256; // 取Value的低8位(对256取余),写入TL0寄存器
}
/**
* @brief 获取定时器0当前的计数值
* @param 无
* @retval 当前16位计数值(TH0<<8 | TL0),范围0~65535
* @note 将高8位(TH0)和低8位(TL0)合并为一个16位整数返回
*/
unsigned int Timer0_GetCounter(void)
{
// TH0左移8位(补全高8位),再与TL0按位或,合并为完整的16位计数值
return (TH0 << 8) | TL0;
}
/**
* @brief 控制定时器0的启停
* @param Flag:启停标志(1=启动定时器,0=停止定时器)
* @retval 无
* @note 通过TR0寄存器控制,TR0=1时定时器开始计数,TR0=0时停止
*/
void Timer_Run(unsigned char Flag)
{
TR0 = Flag; // TR0是定时器0的运行控制位,1启动,0停止
}
⭐Timer0.h
cpp
#ifndef _TIMER0_H_
#define _TIMER0_H_
void Timer0_Init(void);
void Timer0_SetCounter(unsigned char Value);
unsigned int Timer0_GetCounter(void);
void Timer_Run(unsigned char Flag);
#endif
17.5.3 状态机红外解码模块
⭐IR.c
cpp
#include <REGX52.H> // 52系列单片机寄存器定义头文件
#include "Timer0.h" // 定时器0驱动头文件(包含初始化、计数值设置/获取、启停等函数)
#include "Int0.h" // 外部中断0驱动头文件(包含中断初始化等函数)
// 全局变量定义 - 红外解码核心变量
unsigned int IR_Time; // 存储定时器0的计数值,用于计算红外信号电平持续时间
unsigned char IR_State; // 红外解码状态机标志:0-初始态 1-检测引导码 2-接收数据位
unsigned char IR_Data[4];// 存储红外接收的4字节数据:[0]地址码 [1]地址反码 [2]命令码 [3]命令反码
unsigned char IR_pData; // 数据位计数指针(0-31),记录当前接收的是第几位数据
// 功能标志位
unsigned char IR_DataFlag; // 数据接收完成标志:1-接收到有效数据
unsigned char IR_RepeatFlag; // 重复码标志:1-检测到长按重复码
unsigned char IR_Address; // 解析后的有效地址码
unsigned char IR_Command; // 解析后的有效命令码(按键对应的数值)
/**
* @brief 红外遥控初始化函数
* @param 无
* @retval 无
* @note 初始化定时器0(用于计时)和外部中断0(用于捕捉红外信号电平变化)
*/
void IR_Init(void)
{
Timer0_Init(); // 初始化定时器0(需在Timer0.h中实现:定时10us/1us等基础配置)
Int0_Init(); // 初始化外部中断0(需在Int0.h中实现:下降沿触发)
}
/**
* @brief 获取红外数据接收完成标志
* @param 无
* @retval 1-接收到有效数据,0-未接收到
* @note 调用后会清零标志位,避免重复处理同一帧数据
*/
unsigned char IR_GetDataFlag(void)
{
if(IR_DataFlag) // 检测到有效数据
{
IR_DataFlag=0; // 清零标志位
return 1; // 返回1表示有新数据
}else
{
return 0; // 无新数据返回0
}
}
/**
* @brief 获取红外重复码标志(长按按键)
* @param 无
* @retval 1-检测到重复码,0-未检测到
* @note 调用后会清零标志位,避免重复响应长按
*/
unsigned char IR_GetRepeatFlag(void)
{
if(IR_RepeatFlag) // 检测到重复码
{
IR_RepeatFlag=0;// 清零标志位
return 1; // 返回1表示有长按重复
}else
{
return 0; // 无重复码返回0
}
}
/**
* @brief 获取解析后的红外地址码
* @param 无
* @retval 红外地址码(8位)
* @note 需在IR_DataFlag置1后调用,否则数据无效
*/
unsigned char IR_GetAddress(void)
{
return IR_Address; // 返回存储的有效地址码
}
/**
* @brief 获取解析后的红外命令码(按键值)
* @param 无
* @retval 红外命令码(8位)
* @note 需在IR_DataFlag置1后调用,否则数据无效
*/
unsigned char IR_GetCommand(void)
{
return IR_Command; // 返回存储的有效命令码
}
/**
* @brief 外部中断0服务函数(红外信号解码核心)
* @param 无
* @retval 无
* @note 红外接收头输出接P3.2(INT0),下降沿触发此中断,用于捕捉电平变化并解码
*/
void Int0_Routine(void) interrupt 0 // interrupt 0 表示外部中断0中断服务函数
{
// 状态机0:初始态(等待检测引导码)
if(IR_State==0)
{
Timer0_SetCounter(0); // 定时器计数值清零
Timer_Run(1); // 启动定时器0(开始计时)
IR_State=1; // 进入状态1:检测引导码阶段
}
// 状态机1:检测引导码/重复码阶段(判断电平持续时间)
else if(IR_State==1)
{
IR_Time=Timer0_GetCounter(); // 获取定时器计数值(记录上一段电平的持续时间)
Timer0_SetCounter(0); // 定时器计数值清零,准备下一次计时
// 判断是否是NEC协议引导码(9ms高+4.5ms低 = 13500us,允许±500us误差)
if(IR_Time>13500-500 && IR_Time<13500+500)
{
IR_State=2; // 引导码检测成功,进入状态2:接收数据位阶段
}
// 判断是否是NEC协议重复码(9ms高+2.25ms低 = 11250us,允许±500us误差)
else if(IR_Time>11250-500 && IR_Time<11250+500)
{
IR_RepeatFlag=1; // 置位重复码标志(表示长按按键)
Timer_Run(0); // 关闭定时器
IR_State=0; // 回到初始态,等待下一次信号
}
// 既不是引导码也不是重复码,视为无效信号,重新检测
else
{
IR_State=1; // 保持状态1,继续检测
}
}
// 状态机2:接收数据位阶段(解析32位数据:地址码+地址反码+命令码+命令反码)
else if(IR_State==2)
{
IR_Time=Timer0_GetCounter(); // 获取当前电平持续时间
Timer0_SetCounter(0); // 定时器清零
// 判断是否是数据位0(低电平560us+高电平560us ≈ 1120us,允许±500us误差)
if(IR_Time>1120-500 && IR_Time<1120+500)
{
// 对应位清零:IR_pData/8确定字节索引,IR_pData%8确定位索引
IR_Data[IR_pData/8]&=~(0x01<<(IR_pData%8));
IR_pData++; // 数据位指针自增,接收下一位
}
// 判断是否是数据位1(低电平560us+高电平1690us ≈ 2250us,允许±500us误差)
else if(IR_Time>2250-500 && IR_Time<2250+500)
{
// 对应位置1:IR_pData/8确定字节索引,IR_pData%8确定位索引
IR_Data[IR_pData/8]|=(0x01<<(IR_pData%8));
IR_pData++; // 数据位指针自增,接收下一位
}
// 电平时间异常,视为无效数据,重置解码状态
else
{
IR_State=1; // 回到状态1,重新检测引导码
IR_pData=0; // 数据位指针清零
}
// 判断32位数据是否接收完成(0-31位共32位)
if(IR_pData>=32)
{
IR_pData=0; // 数据位指针清零
// 数据校验:地址码=地址反码取反 且 命令码=命令反码取反(确保接收数据无误)
if(IR_Data[0]==~IR_Data[1] && IR_Data[2]==~IR_Data[3])
{
IR_Address=IR_Data[0]; // 存储有效地址码
IR_Command=IR_Data[2]; // 存储有效命令码(按键值)
IR_DataFlag=1; // 置位数据接收完成标志
}
Timer_Run(0); // 关闭定时器
IR_State=0; // 回到初始态,等待下一次红外信号
}
}
}
⭐IR.h
cpp
#ifndef _IR_H_
#define _IR_H_
#define IR_POWER 0x45
#define IR_MODE 0x46
#define IR_MUTE 0x47
#define IR_START_STOP 0x44
#define IR_PREVIOUS 0x40
#define IR_NEXT 0x43
#define IR_EQ 0x07
#define IR_VOL_MINUS 0x15
#define IR_VOL_ADD 0x09
#define IR_0 0x16
#define IR_RPT 0x19
#define IR_USD 0x0D
#define IR_1 0x0C
#define IR_2 0x18
#define IR_3 0x5E
#define IR_4 0x08
#define IR_5 0x1C
#define IR_6 0x5A
#define IR_7 0x42
#define IR_8 0x52
#define IR_9 0x4A
void IR_Init(void);
unsigned char IR_GetDataFlag(void);
unsigned char IR_GetRepeatFlag(void);
unsigned char IR_GetAddress(void);
unsigned char IR_GetCommand(void);
#endif
17.6 项目示例1:红外遥控
✅项目功能:
实现 51 单片机接收红外遥控信号,在 LCD1602 上实时显示红外地址码、命令码,并响应 "音量加 / 减" 按键修改计数变量并显示
✅项目架构:

✅main.c 主函数:
cpp
#include <REGX52.H> // 52系列单片机寄存器定义头文件
#include "Delay.h" // 延时函数驱动头文件(LCD初始化/显示需延时)
#include "LCD1602.h" // LCD1602液晶显示驱动头文件
#include "IR.h" // 红外遥控解码驱动头文件(包含之前编写的IR_Init、IR_GetDataFlag等函数)
// 全局变量定义
unsigned char Address; // 存储红外遥控解析后的地址码
unsigned char Command; // 存储红外遥控解析后的命令码(按键对应的数值)
unsigned char Num; // 用于演示的计数变量(受红外音量±按键控制)
/**
* @brief 主函数(程序入口)
* @param 无
* @retval 无
* @note 初始化LCD和红外后,循环检测红外按键,显示地址码/命令码,并响应音量±按键修改计数变量
*/
void main()
{
// 初始化外设
LCD_Init(); // 初始化LCD1602液晶(配置端口、显示模式等)
IR_Init(); // 初始化红外遥控解码(定时器0+外部中断0)
// LCD显示初始化:固定表头(第一行)
LCD_ShowString(1,1,"ADDR CMD NUM"); // 第1行第1列显示"ADDR CMD NUM",分别对应地址码、命令码、计数变量
LCD_ShowString(2,1,"00 00 00"); // 第2行第1列显示初始值,占位符
// 主循环(程序持续运行)
while(1)
{
// 检测是否接收到红外有效数据(IR_GetDataFlag=1)或长按重复码(IR_GetRepeatFlag=1)
if(IR_GetDataFlag()||IR_GetRepeatFlag())
{
Address=IR_GetAddress(); // 获取解析后的红外地址码
Command=IR_GetCommand(); // 获取解析后的红外命令码(按键值)
// 将地址码/命令码以16进制显示到LCD
LCD_ShowHexNum(2,1,Address,2); // 第2行第1列显示地址码,2位16进制(不足补0)
LCD_ShowHexNum(2,7,Command,2); // 第2行第7列显示命令码,2位16进制(不足补0)
}
// 根据红外命令码执行对应操作(响应音量减/加按键)
if(Command==IR_VOL_MINUS) // IR_VOL_MINUS是红外遥控器"音量减"按键对应的命令码(宏定义在IR.h中)
{
Num--; // 计数变量减1
}else if(Command==IR_VOL_ADD) // IR_VOL_ADD是"音量加"按键对应的命令码
{
Num++; // 计数变量加1
}
// 将计数变量以16进制显示到LCD(第2行第12列,3位,不足补0)
LCD_ShowHexNum(2,12,Num,3);
}
}
17.7 项目示例2:红外遥控电机调速
✅项目功能:
实现 51 单片机通过 按键 和 红外遥控两种方式控制电机转速,同时在数码管上实时显示当前速度档位(0-3 档)
✅项目架构:

⭐Timer1.c
cpp
#include <REGX52.H> // 52系列单片机寄存器定义头文件,包含TMOD、TL1、TH1等定时器1相关寄存器
/**
* @brief 定时器1初始化函数
* @param 无
* @retval 无
* @note 配置定时器1为16位定时器模式(模式1),12.000MHz晶振下定时100微秒,开启中断并启动计时
* 12MHz晶振下,机器周期=1us,定时器每计数1次耗时1us
*/
void Timer1_Init(void) //100微秒@12.000MHz(定时周期为100微秒)
{
// 1. 配置定时器1的工作模式(TMOD寄存器:低4位控制定时器0,高4位控制定时器1)
TMOD &= 0x0F; // 清零定时器1的模式位(bit4~bit7),保留定时器0的配置
TMOD |= 0x10; // 设置定时器1为模式1(16位定时/计数模式,无自动重装)
// 2. 设置定时器1定时初值(实现100us定时,12MHz晶振下计数1次=1us)
// 计算过程:16位计数器最大值=65536,需要计数100次(100us),因此初值=65536-100=65436
// 65436转换为16进制:65436 = 0xFF9C → 高8位TH1=0xFF,低8位TL1=0x9C
TL1 = 0x9C; // 定时器1低8位初值设为0x9C
TH1 = 0xFF; // 定时器1高8位初值设为0xFF
// 3. 清除定时器1的溢出标志
TF1 = 0; // TF1是定时器1的溢出标志(TF1=1表示定时器溢出),初始化时清零避免误触发
// 4. 启动定时器1计数
TR1 = 1; // TR1是定时器1的运行控制位,TR1=1 → 启动定时器1开始计数
// 5. 配置定时器1中断
ET1 = 1; // ET1是定时器1的中断允许位,ET1=1 → 允许定时器1溢出中断
EA = 1; // EA是总中断允许位,EA=1 → 开启单片机所有中断的总开关(必须开启)
PT1 = 0; // PT1是定时器1的优先级控制位,PT1=0 → 低优先级;PT1=1 → 高优先级
}
/*定时器1中断服务函数模板
void Timer1Rountine() interrupt 3
{
// 定义静态变量:函数执行完后值不丢失,用于累计中断次数
static unsigned int T1Count;
// 重装定时初值(模式1无自动重装,溢出后需手动恢复初值,否则下次定时不准)
TL1 = 0x9C; // 恢复低8位初值
TH1 = 0xFF; // 恢复高8位初值
T1Count++; // 每次中断(100us)计数+1
// 累计1000次中断 → 100us×1000=100ms(0.1秒)
if(T1Count>=1000)
{
T1Count=0; // 计数清零,重新累计
// 此处可添加需要每隔100ms执行的代码(如LED闪烁、电机PWM调速等)
}
}
/*
⭐Timer1.h
cpp
#ifndef _TIMER1_H_
#define _TIMER1_H_
void Timer1_Init(void);
#endif
⭐Motor.c
cpp
#include <REGX52.H> // 52系列单片机寄存器定义头文件
#include "Timer1.h" // 定时器1驱动头文件(包含Timer1_Init初始化函数)
// 电机控制引脚定义:P1^0引脚连接电机驱动模块(如三极管/继电器/电机驱动芯片)
sbit Motor = P1^0;
// 全局变量定义(PWM调速核心)
unsigned char Count; // 定时器中断累计计数器(用于PWM周期计数,范围0-99)
unsigned char Compare; // PWM占空比比较阈值(0-100),决定电机转速(0=停止,100=全速)
/**
* @brief 电机初始化函数
* @param 无
* @retval 无
* @note 本质是初始化定时器1(100us中断),为PWM波生成提供定时基础
*/
void Motor_Init(void)
{
Timer1_Init(); // 调用定时器1初始化函数(12MHz晶振下100us触发一次中断)
}
/**
* @brief 设置电机转速
* @param Speed:转速百分比(0-100),0=停止,100=最大转速
* @retval 无
* @note 将转速值赋值给Compare,作为PWM占空比的比较阈值
*/
void Motor_SetSpeed(unsigned char Speed)
{
Compare = Speed; // Speed范围0-100,对应PWM占空比0%-100%
}
/**
* @brief 定时器1中断服务函数(100us触发一次)
* @param 无
* @retval 无
* @note 生成10ms周期的PWM波,通过Count与Compare的比较控制Motor引脚高低电平,实现占空比调节
* 100us×100次=10ms(PWM周期),Count<Compare时Motor=1,否则=0
*/
void Timer1_Rountine() interrupt 3 // interrupt 3 表示定时器1中断服务函数(中断号3)
{
// 重装定时器1初值(模式1无自动重装,必须手动恢复100us定时)
TL1 = 0x9C; // 低8位初值(对应100us定时)
TH1 = 0xFF; // 高8位初值(对应100us定时)
Count++; // 每次中断(100us)计数器+1
Count %= 100; // 计数器取模100,限制范围0-99(累计100次中断=10ms,形成PWM周期)
// PWM占空比控制核心逻辑
if(Count < Compare) // 计数器小于比较阈值 → 电机引脚置1
{
Motor = 1; // Motor引脚高电平,电机驱动电路工作(转速由高电平时长决定)
}else // 计数器大于等于比较阈值 → 电机引脚置0
{
Motor = 0; // Motor引脚低电平,电机驱动电路停止
}
}
⭐Motor.h
cpp
#ifndef _MOTOR_H_
#define _MOTOR_H_
void Motor_Init(void);
void Motor_SetSpeed(unsigned char Speed);
#endif
✅main.c 主函数:
cpp
#include <REGX52.H> // 52系列单片机寄存器定义头文件
#include "Key.h" // 按键驱动头文件(包含Key()函数,用于读取按键值)
#include "NiXie.h" // 数码管驱动头文件(NiXie为"数码"拼音,包含NiXie()显示函数)
#include "IR.h" // 红外遥控解码驱动头文件(红外命令码解析)
#include "Motor.h" // 电机驱动头文件(包含Motor_Init/Motor_SetSpeed函数)
// 全局变量定义
unsigned char KeyNum; // 存储读取到的按键值(由Key()函数返回)
unsigned char Speed; // 电机速度档位(0-3档,对应不同转速)
unsigned char Command; // 存储红外遥控解析后的命令码(按键对应的数值)
/**
* @brief 主函数(程序入口)
* @param 无
* @retval 无
* @note 初始化红外和电机后,循环检测按键/红外信号,控制电机速度并在数码管显示档位
*/
void main()
{
IR_Init(); // 初始化红外遥控解码模块(定时器0+外部中断0)
Motor_Init(); // 初始化电机驱动模块(如PWM输出、电机端口配置等)
// 主循环(程序持续运行)
while(1)
{
KeyNum = Key(); // 读取按键值(Key()函数会扫描按键,返回按下的按键编号,无按键返回0)
// 按键1控制:速度档位循环递增(0→1→2→3→0)
if(KeyNum == 1)
{
Speed++; // 档位自增
Speed %= 4; // 取模4,限制档位范围为0-3(避免超出范围)
// 根据档位设置电机具体转速(0=停止,1=50%转速,2=75%转速,3=100%转速)
if(Speed == 0){Motor_SetSpeed(0);} // 0档:电机停止
if(Speed == 1){Motor_SetSpeed(50);} // 1档:电机50%转速
if(Speed == 2){Motor_SetSpeed(75);} // 2档:电机75%转速
if(Speed == 3){Motor_SetSpeed(100);} // 3档:电机100%转速
}
// 红外遥控控制:检测是否接收到有效红外数据
if(IR_GetDataFlag())
{
Command = IR_GetCommand(); // 获取红外遥控的命令码(如IR_0对应遥控器"0"键)
// 根据红外按键(0/1/2/3)直接设置速度档位
if(Command == IR_0) {Speed = 0;} // 红外"0"键:设置为0档
if(Command == IR_1) {Speed = 1;} // 红外"1"键:设置为1档
if(Command == IR_2) {Speed = 2;} // 红外"2"键:设置为2档
if(Command == IR_3) {Speed = 3;} // 红外"3"键:设置为3档
// 根据新档位更新电机转速(与按键逻辑一致)
if(Speed == 0){Motor_SetSpeed(0);}
if(Speed == 1){Motor_SetSpeed(50);}
if(Speed == 2){Motor_SetSpeed(75);}
if(Speed == 3){Motor_SetSpeed(100);}
}
NiXie(1, Speed); // 数码管显示:第1位显示当前速度档位(0-3)
}
}