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 原始采样格式是:

I, Q, I, Q, I, Q ...

用 Python 读取后,将相邻两个字节作为一组 I/Q

raw = np.fromfile(path, dtype=np.int8)

I = raw[0::2]
Q = raw[1::2]

为了把 OOK 信号还原成高低电平,需要计算幅度

# mag2 大时,表示有载波,即高电平;当 mag2 接近 0 时,表示无载波,即低电平
mag2 = I * I + Q * Q

对幅度做一个简单平滑,然后设置阈值

env = np.convolve(mag2, np.ones(100) / 100, mode="same")
level = env > 1000

这样可以得到类似逻辑分析仪中的高低电平序列

高电平  低电平  高电平  低电平 ...

本题中观察到的编码方式有点不同

1 = 长高电平 + 短低电平
0 = 短高电平 + 长低电平

也就是

bit 1: HHH + L
bit 0: H + LLL

从信号中截取一帧,统计高低电平长度后,可以得到类似下面的脉冲序列

高 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 位二进制

101010110010110010000001

转 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()}}}")

评论