1527 芯片¶
芯片定位与调制方式¶
1527 是一颗固定码无线遥控编码芯片,专为低成本的单向遥控设计。典型工作方式:
-
射频频率:315 MHz 或 433 MHz(由外部声表/晶振和发射电路决定)
-
调制方式:OOK (开关键控),即发射载波的有无代表数据
-
数据发送:按下按键后,同一帧数据会以约 10 ms 的间隔重复发送,直到松手
数据结构¶
一帧完整数据由同步头和 24 位数据(20 位地址 + 4 位按键值)组成,每发完一帧会有一段较长的低电平间隙,然后重复下一帧
-
同步头:一个宽高电平脉冲,用来唤醒接收端并标志一帧的开始
-
数据位:24 位,包含 C0~C19(地址码) 和 D0~D3(数据码),不同芯片手册的位序可能不同,但原理一致
编码方式¶
1527 采用脉宽调制来表示一位数据,每一位由 "一个高电平 + 紧随的一个低电平" 组成,高低电平的宽度比例决定逻辑值
以常见的 4T/12T 方案为例(T 为时钟基本周期,由外接振荡电阻决定):
-
逻辑 0:高电平 ≈ 4T,低电平 ≈ 12T(高短低长)
-
逻辑 1:高电平 ≈ 12T,低电平 ≈ 4T(高长低短)
接收端可以通过测量每个高电平的宽度来区分 0/1
有的芯片或接收方案也可能是 1T/3T 或 3T/1T,但本质上都是 "短高长低" 表示 0,"长高短低" 表示 1
地址码与数据码¶
地址码(20 位) - 由芯片的 A0~A19 管脚通过三态编码确定:接地(0)、接正(1)或悬空(浮动)
- 这 20 位决定了遥控器的 "身份",出厂时或现场跳线来设置,保证不同遥控器间不冲突
数据码(4 位)
-
对应 D0~D3 按键输入,通常低电平有效,内部上拉,按下某键后对应位发送 "1" 数据,其余为 "0"。例如按下 D2 键,则数据码为 0100
-
有的 1527 芯片支持组合键,即同时按下多键会送出多位 1
发射与接收流程¶
发射端:按键按下 → 1527 按地址、按键生成数据帧 → 通过 DATA 脚输出编码脉冲 → 控制 433/315 MHz 发射模块(ASK 方式)发射出去
接收端:超再生或超外差接收模块解调出脉冲 → 送至 1527 解码芯片(如 EV1527 配套的解码器,或与 PT2272 类似的方案)或单片机进行软件解码
解码器核对两帧以上地址匹配后,输出对应的按键电平
实战案例¶
工控大楼的道闸怎么坏了¶

EM1527 是常见的 433MHz/315MHz 无线遥控编码芯片协议,经常用于道闸、卷帘门、遥控开关等设备
协议数据一般为 24 bit,也就是 6 个十六进制字符
它通常使用 OOK/ASK 调制,也就是:
题目附件给的是某种原始无线 IQ 采样数据
常见 SDR 原始采样格式是:
用 Python 读取后,将相邻两个字节作为一组 I/Q
为了把 OOK 信号还原成高低电平,需要计算幅度
对幅度做一个简单平滑,然后设置阈值
这样可以得到类似逻辑分析仪中的高低电平序列
本题中观察到的编码方式有点不同
也就是
从信号中截取一帧,统计高低电平长度后,可以得到类似下面的脉冲序列
高 2324 低 853
高 728 低 2416
高 2329 低 854
高 727 低 2416
高 2329 低 854
高 726 低 2414
高 2331 低 861
高 2326 低 857
高 724 低 2417
高 721 低 2414
高 2331 低 860
高 721 低 2415
高 2330 低 857
高 2330 低 859
高 722 低 2413
高 725 低 2412
高 2333 低 859
高 722 低 2411
高 728 低 2415
高 723 低 2420
高 719 低 2413
高 724 低 2414
高 725 低 2412
高 2333 低 857
按规则解码得到 24 位二进制
转 ASCII 码是 AB2C81
所以 flag 就是 flag{ab2c81}
import numpy as np
path = "题目附件"
# 1. 按 signed int8 IQ 读取
raw = np.fromfile(path, dtype=np.int8)
I = raw[0::2].astype(np.int16)
Q = raw[1::2].astype(np.int16)
# 2. 计算幅度平方,OOK 中幅度高表示有载波
mag2 = I * I + Q * Q
# 3. 平滑包络
win = 100
env = np.convolve(mag2, np.ones(win) / win, mode="same")
# 4. 二值化
level = env > 1000
# 5. 统计高低电平 run length
runs = []
cur = level[0]
start = 0
for i, v in enumerate(level[1:], 1):
if v != cur:
runs.append((int(cur), start, i - start))
cur = v
start = i
runs.append((int(cur), start, len(level) - start))
# 过滤掉很短的噪声毛刺
runs = [(v, s, l) for v, s, l in runs if l > 300]
def classify_len(l):
if 500 <= l <= 1100:
return "S" # short
if 1900 <= l <= 2800:
return "L" # long
return "?"
frames = []
# EM1527 一帧 24 bit,每 bit 由 高电平 + 低电平 组成
for i in range(len(runs) - 48):
if runs[i][0] != 1:
continue
bits = []
ok = True
for k in range(24):
vh, sh, lh = runs[i + 2 * k]
vl, sl, ll = runs[i + 2 * k + 1]
if vh != 1 or vl != 0:
ok = False
break
h = classify_len(lh)
l = classify_len(ll)
if h == "L" and l == "S":
bits.append("1")
elif h == "S" and l == "L":
bits.append("0")
else:
ok = False
break
if ok:
bitstr = "".join(bits)
code = f"{int(bitstr, 2):06X}"
frames.append((runs[i][1], bitstr, code))
# 去重输出
seen = set()
for start, bitstr, code in frames:
if code in seen:
continue
seen.add(code)
print("[+] bits:", bitstr)
print("[+] code:", code)
print("[+] flag:", f"flag{{{code.lower()}}}")