STC单片机无线遥控器解码程序
一、系统概述
本程序针对常见的PT2262/PT2272编码格式无线遥控器进行解码,适用于STC89C52/STC12C5A60S2等系列单片机。
1.1 PT2262/PT2272编码格式
┌─────────────────────────────────────────────────────────────┐
│ PT2262 编码帧格式 │
├─────────────────────────────────────────────────────────────┤
│ 同步码 │ 地址码A0-A11 │ 数据码D0-D3 │ 同步码 │
│ (1位) │ (12位) │ (4位) │ (1位) │
└─────────────────────────────────────────────────────────────┘
脉冲宽度定义(典型值):
• 同步码:低电平4ms + 高电平124ms
• 数据位0:高电平0.5ms + 低电平0.5ms
• 数据位1:高电平1.5ms + 低电平0.5ms
1.2 硬件连接
无线接收模块 → STC单片机
─────────────────────────
DATA引脚 → P3.2 (INT0外部中断)
VCC → 5V电源
GND → 电源地
二、完整代码实现
2.1 主程序代码
/**
* @file main.c
* @brief STC单片机无线遥控器解码程序
* @author AI Assistant
* @date 2024
*/
#include "reg52.h"
#include "intrins.h"
// 硬件定义
sbit RF_DATA = P3^2; // 无线接收数据引脚 (INT0)
sbit LED = P1^0; // 指示灯
sbit RELAY = P1^1; // 继电器控制
// 解码参数定义
#define SYNC_LOW_MIN 3500 // 同步码低电平最小时间(us)
#define SYNC_LOW_MAX 4500 // 同步码低电平最大时间(us)
#define SYNC_HIGH_MIN 120000 // 同步码高电平最小时间(us)
#define SYNC_HIGH_MAX 130000 // 同步码高电平最大时间(us)
#define BIT0_HIGH_MIN 400 // 数据位0高电平最小时间(us)
#define BIT0_HIGH_MAX 600 // 数据位0高电平最大时间(us)
#define BIT1_HIGH_MIN 1400 // 数据位1高电平最小时间(us)
#define BIT1_HIGH_MAX 1600 // 数据位1高电平最大时间(us)
#define BIT_LOW_MIN 400 // 数据位低电平最小时间(us)
#define BIT_LOW_MAX 600 // 数据位低电平最大时间(us)
#define MAX_BITS 24 // 最大位数 (12地址+4数据+8校验)
#define TIMEOUT_US 500000 // 超时时间(us)
// 全局变量
unsigned long pulse_start_time = 0;
unsigned long pulse_end_time = 0;
unsigned long pulse_width = 0;
unsigned char bit_count = 0;
unsigned char decode_complete = 0;
unsigned char decode_error = 0;
// 解码结果
unsigned char address_high = 0; // 地址高字节
unsigned char address_low = 0; // 地址低字节
unsigned char data_code = 0; // 数据码
unsigned char decode_valid = 0; // 解码有效标志
// 定时器0初始化(1us计数)
void Timer0_Init(void) {
TMOD &= 0xF0; // 清除T0控制位
TMOD |= 0x01; // 设置T0为模式1(16位定时器)
TH0 = 0x00; // 设置初始值
TL0 = 0x00;
ET0 = 1; // 使能T0中断
EA = 1; // 使能总中断
TR0 = 1; // 启动T0
}
// 获取当前时间(us)
unsigned long Get_Time_Us(void) {
unsigned long time_val;
time_val = TH0;
time_val = (time_val << 8) | TL0;
return time_val;
}
// 延时函数
void Delay_Ms(unsigned int ms) {
unsigned int i, j;
for(i = ms; i > 0; i--)
for(j = 110; j > 0; j--);
}
// 外部中断0初始化
void External_Int0_Init(void) {
IT0 = 1; // 设置INT0为下降沿触发
EX0 = 1; // 使能INT0中断
EA = 1; // 使能总中断
}
// 解码同步码
unsigned char Decode_Sync_Pulse(unsigned long high_width, unsigned long low_width) {
// 检查同步码低电平
if(low_width < SYNC_LOW_MIN || low_width > SYNC_LOW_MAX) {
return 0;
}
// 检查同步码高电平
if(high_width < SYNC_HIGH_MIN || high_width > SYNC_HIGH_MAX) {
return 0;
}
return 1; // 同步码有效
}
// 解码数据位
unsigned char Decode_Data_Bit(unsigned long high_width, unsigned long low_width) {
unsigned char bit_value = 0xFF; // 0xFF表示无效
// 检查低电平宽度
if(low_width < BIT_LOW_MIN || low_width > BIT_LOW_MAX) {
return 0xFF;
}
// 检查高电平宽度,判断是0还是1
if(high_width >= BIT0_HIGH_MIN && high_width <= BIT0_HIGH_MAX) {
bit_value = 0; // 数据位0
}
else if(high_width >= BIT1_HIGH_MIN && high_width <= BIT1_HIGH_MAX) {
bit_value = 1; // 数据位1
}
return bit_value;
}
// 外部中断0服务程序
void External_Int0_ISR(void) interrupt 0 {
static unsigned char last_state = 1;
unsigned char current_state;
unsigned char bit_value;
current_state = RF_DATA;
if(last_state == 1 && current_state == 0) { // 下降沿
pulse_end_time = Get_Time_Us();
if(pulse_start_time > 0) {
pulse_width = pulse_end_time - pulse_start_time;
if(decode_complete == 0 && decode_error == 0) {
// 解码同步码
if(bit_count == 0) {
if(Decode_Sync_Pulse(pulse_width, 0)) {
bit_count = 1;
}
}
// 解码数据位
else if(bit_count <= MAX_BITS) {
bit_value = Decode_Data_Bit(pulse_width, 0);
if(bit_value != 0xFF) {
// 存储解码结果
if(bit_count <= 12) { // 地址位
if(bit_count <= 8) {
address_low >>= 1;
if(bit_value) address_low |= 0x80;
} else {
address_high >>= 1;
if(bit_value) address_high |= 0x80;
}
} else if(bit_count <= 16) { // 数据位
data_code >>= 1;
if(bit_value) data_code |= 0x08;
}
bit_count++;
// 检查是否解码完成
if(bit_count > 16) {
decode_complete = 1;
decode_valid = 1;
}
} else {
decode_error = 1; // 解码错误
}
}
}
}
pulse_start_time = pulse_end_time;
}
last_state = current_state;
}
// 定时器0中断服务程序
void Timer0_ISR(void) interrupt 1 {
static unsigned long timeout_counter = 0;
timeout_counter++;
// 超时检测(约500ms)
if(timeout_counter >= (TIMEOUT_US / 65536)) {
if(decode_complete == 0 && bit_count > 0) {
decode_error = 1; // 解码超时
}
timeout_counter = 0;
}
// 重装初值
TH0 = 0x00;
TL0 = 0x00;
}
// 验证解码结果
unsigned char Verify_Decode_Result(void) {
// 简单的地址验证(可根据实际需要修改)
if(address_high == 0x00 && address_low == 0x00) {
return 0; // 无效地址
}
// 数据码验证
if(data_code > 0x0F) {
return 0; // 无效数据
}
return 1; // 验证通过
}
// 执行解码结果
void Execute_Decode_Result(void) {
if(decode_valid && Verify_Decode_Result()) {
LED = 0; // 点亮指示灯
// 根据数据码执行相应动作
switch(data_code & 0x0F) {
case 0x01: // 按键1 - 开灯
RELAY = 1;
break;
case 0x02: // 按键2 - 关灯
RELAY = 0;
break;
case 0x04: // 按键3 - 继电器开
RELAY = 1;
break;
case 0x08: // 按键4 - 继电器关
RELAY = 0;
break;
default:
break;
}
Delay_Ms(100);
LED = 1; // 熄灭指示灯
// 重置解码状态
decode_complete = 0;
decode_valid = 0;
bit_count = 0;
}
}
// 主函数
void main(void) {
// 初始化
Timer0_Init();
External_Int0_Init();
LED = 1; // 关闭指示灯
RELAY = 0; // 关闭继电器
// 显示启动信息
LED = 0;
Delay_Ms(500);
LED = 1;
Delay_Ms(500);
while(1) {
// 检查解码完成
if(decode_complete) {
Execute_Decode_Result();
}
// 解码错误处理
if(decode_error) {
LED = 0;
Delay_Ms(50);
LED = 1;
Delay_Ms(50);
// 重置解码状态
decode_error = 0;
decode_complete = 0;
bit_count = 0;
decode_valid = 0;
}
Delay_Ms(10);
}
}
2.2 优化版本(支持更多编码格式)
/**
* @file rf_decoder_advanced.c
* @brief 增强版无线解码程序(支持PT2262/PT2272/EV1527)
*/
#include "reg52.h"
// 支持的编码格式
typedef enum {
CODEC_PT2262 = 0,
CODEC_PT2272,
CODEC_EV1527,
CODEC_UNKNOWN
} CodecType;
// 解码配置结构体
typedef struct {
CodecType codec_type;
unsigned long sync_low_min;
unsigned long sync_low_max;
unsigned long sync_high_min;
unsigned long sync_high_max;
unsigned long bit0_high_min;
unsigned long bit0_high_max;
unsigned long bit1_high_min;
unsigned long bit1_high_max;
unsigned long bit_low_min;
unsigned long bit_low_max;
unsigned char total_bits;
} DecodeConfig;
// 解码结果结构体
typedef struct {
unsigned long address;
unsigned char data;
unsigned char repeat_count;
unsigned char valid;
} DecodeResult;
// 全局变量
DecodeConfig decode_config;
DecodeResult decode_result;
static unsigned char decode_state = 0;
static unsigned char bit_position = 0;
static unsigned long last_sync_time = 0;
// 初始化解码配置
void Init_Decode_Config(CodecType codec) {
switch(codec) {
case CODEC_PT2262:
decode_config.codec_type = CODEC_PT2262;
decode_config.sync_low_min = 3500;
decode_config.sync_low_max = 4500;
decode_config.sync_high_min = 120000;
decode_config.sync_high_max = 130000;
decode_config.bit0_high_min = 400;
decode_config.bit0_high_max = 600;
decode_config.bit1_high_min = 1400;
decode_config.bit1_high_max = 1600;
decode_config.bit_low_min = 400;
decode_config.bit_low_max = 600;
decode_config.total_bits = 24;
break;
case CODEC_EV1527:
decode_config.codec_type = CODEC_EV1527;
decode_config.sync_low_min = 300;
decode_config.sync_low_max = 500;
decode_config.sync_high_min = 8000;
decode_config.sync_high_max = 12000;
decode_config.bit0_high_min = 300;
decode_config.bit0_high_max = 500;
decode_config.bit1_high_min = 900;
decode_config.bit1_high_max = 1100;
decode_config.bit_low_min = 300;
decode_config.bit_low_max = 500;
decode_config.total_bits = 24;
break;
default:
break;
}
}
// 解码单帧数据
unsigned char Decode_Single_Frame(unsigned long pulse_width) {
static unsigned long frame_start_time = 0;
static unsigned char frame_bits = 0;
static unsigned long frame_address = 0;
static unsigned char frame_data = 0;
unsigned char bit_value;
unsigned char result = 0;
if(decode_state == 0) {
// 等待同步码
if(pulse_width >= decode_config.sync_low_min &&
pulse_width <= decode_config.sync_low_max) {
frame_start_time = Get_Time_Us();
decode_state = 1;
frame_bits = 0;
frame_address = 0;
frame_data = 0;
}
}
else if(decode_state == 1) {
// 检查同步码高电平
if(pulse_width >= decode_config.sync_high_min &&
pulse_width <= decode_config.sync_high_max) {
decode_state = 2;
} else {
decode_state = 0; // 同步失败
}
}
else if(decode_state == 2) {
// 解码数据位
if(pulse_width >= decode_config.bit0_high_min &&
pulse_width <= decode_config.bit0_high_max) {
bit_value = 0;
}
else if(pulse_width >= decode_config.bit1_high_min &&
pulse_width <= decode_config.bit1_high_max) {
bit_value = 1;
}
else {
decode_state = 0; // 数据位解码失败
return 0;
}
// 存储数据位
if(frame_bits < 20) { // 地址位
frame_address >>= 1;
if(bit_value) frame_address |= 0x80000;
}
else { // 数据位
frame_data >>= 1;
if(bit_value) frame_data |= 0x08;
}
frame_bits++;
// 检查是否解码完成
if(frame_bits >= decode_config.total_bits) {
decode_result.address = frame_address;
decode_result.data = frame_data & 0x0F;
decode_result.repeat_count++;
decode_result.valid = 1;
result = 1;
decode_state = 0;
}
}
return result;
}
2.3 学习模式程序
/**
* @file learning_mode.c
* @brief 遥控器学习模式程序
*/
#include "reg52.h"
#define LEARN_BUTTON P1^2 // 学习按钮
#define LEARN_LED P1^3 // 学习指示灯
typedef struct {
unsigned long learned_address[10]; // 学习的地址
unsigned char learned_data[10]; // 学习的数据
unsigned char learn_count; // 学习数量
unsigned char learning_mode; // 学习模式标志
} LearningData;
LearningData learning_data;
// 进入学习模式
void Enter_Learning_Mode(void) {
unsigned char i;
if(LEARN_BUTTON == 0) {
Delay_Ms(50);
if(LEARN_BUTTON == 0) {
learning_data.learning_mode = 1;
LEARN_LED = 0; // 点亮学习指示灯
// 等待遥控器按键
for(i = 0; i < 10; i++) {
// 等待解码完成
while(!decode_result.valid);
// 存储学习结果
learning_data.learned_address[learning_data.learn_count] = decode_result.address;
learning_data.learned_data[learning_data.learn_count] = decode_result.data;
learning_data.learn_count++;
// 闪烁指示灯表示学习成功
LEARN_LED = 1;
Delay_Ms(100);
LEARN_LED = 0;
Delay_Ms(100);
// 清除解码结果
decode_result.valid = 0;
// 检查是否学习完成
if(learning_data.learn_count >= 10) {
break;
}
}
learning_data.learning_mode = 0;
LEARN_LED = 1; // 熄灭学习指示灯
}
}
}
// 匹配学习结果
unsigned char Match_Learned_Code(unsigned long address, unsigned char data) {
unsigned char i;
for(i = 0; i < learning_data.learn_count; i++) {
if(learning_data.learned_address[i] == address &&
learning_data.learned_data[i] == data) {
return 1; // 匹配成功
}
}
return 0; // 未匹配
}
三、应用示例
3.1 四路遥控开关
/**
* @file four_channel_switch.c
* @brief 四路遥控开关应用
*/
#include "rf_decoder.c"
// 继电器控制引脚
sbit RELAY1 = P1^0;
sbit RELAY2 = P1^1;
sbit RELAY3 = P1^2;
sbit RELAY4 = P1^3;
// 状态指示
sbit LED1 = P2^0;
sbit LED2 = P2^1;
sbit LED3 = P2^2;
sbit LED4 = P2^3;
void main(void) {
unsigned char relay_state[4] = {0, 0, 0, 0}; // 继电器状态
// 初始化
Timer0_Init();
External_Int0_Init();
// 关闭所有继电器
RELAY1 = 0; RELAY2 = 0; RELAY3 = 0; RELAY4 = 0;
LED1 = 1; LED2 = 1; LED3 = 1; LED4 = 1;
while(1) {
if(decode_valid && Verify_Decode_Result()) {
// 根据数据码控制继电器
switch(data_code & 0x0F) {
case 0x01: // A键 - 继电器1
relay_state[0] = !relay_state[0];
RELAY1 = relay_state[0];
LED1 = !relay_state[0];
break;
case 0x02: // B键 - 继电器2
relay_state[1] = !relay_state[1];
RELAY2 = relay_state[1];
LED2 = !relay_state[1];
break;
case 0x04: // C键 - 继电器3
relay_state[2] = !relay_state[2];
RELAY3 = relay_state[2];
LED3 = !relay_state[2];
break;
case 0x08: // D键 - 继电器4
relay_state[3] = !relay_state[3];
RELAY4 = relay_state[3];
LED4 = !relay_state[3];
break;
case 0x0F: // *键 - 全部关闭
relay_state[0] = 0; relay_state[1] = 0;
relay_state[2] = 0; relay_state[3] = 0;
RELAY1 = 0; RELAY2 = 0; RELAY3 = 0; RELAY4 = 0;
LED1 = 1; LED2 = 1; LED3 = 1; LED4 = 1;
break;
case 0x00: // #键 - 全部打开
relay_state[0] = 1; relay_state[1] = 1;
relay_state[2] = 1; relay_state[3] = 1;
RELAY1 = 1; RELAY2 = 1; RELAY3 = 1; RELAY4 = 1;
LED1 = 0; LED2 = 0; LED3 = 0; LED4 = 0;
break;
}
// 重置解码状态
decode_complete = 0;
decode_valid = 0;
bit_count = 0;
}
Delay_Ms(10);
}
}
参考代码 STC解码无线遥控器程序 www.youwenfan.com/contentcnv/60425.html
四、调试与优化建议
4.1 调试方法
- 串口输出:添加串口输出解码过程中的脉冲宽度和状态
- LED指示:用LED闪烁模式表示不同的解码状态
- 示波器观察:用示波器观察无线信号的波形
4.2 抗干扰优化
// 添加连续解码验证
unsigned char continuous_decode_check = 0;
unsigned char last_address = 0;
unsigned char last_data = 0;
if(decode_valid) {
if(address_high == last_address && data_code == last_data) {
continuous_decode_check++;
if(continuous_decode_check >= 3) { // 连续3次相同才确认
Execute_Decode_Result();
continuous_decode_check = 0;
}
} else {
continuous_decode_check = 0;
}
last_address = address_high;
last_data = data_code;
}
4.3 常见问题解决
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 无法解码 | 脉冲宽度参数不匹配 | 用示波器测量实际脉冲宽度,调整参数 |
| 解码不稳定 | 信号干扰 | 添加连续解码验证,增加滤波电容 |
| 误触发 | 环境噪声 | 添加地址过滤,只响应特定地址 |
| 距离近 | 天线问题 | 增加天线长度,优化PCB布局 |
浙公网安备 33010602011771号