Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
264 changes: 264 additions & 0 deletions docs/hc-ics/1527 芯片.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,264 @@
---
comments: true

---

# 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 类似的方案)或单片机进行软件解码

解码器核对两帧以上地址匹配后,输出对应的按键电平

## 实战案例

### 工控大楼的道闸怎么坏了

![](https://pic1.imgdb.cn/item/6a35930c71d0c6ff61485786.png)

EM1527 是常见的 433MHz/315MHz 无线遥控编码芯片协议,经常用于道闸、卷帘门、遥控开关等设备

协议数据一般为 24 bit,也就是 6 个十六进制字符

它通常使用 OOK/ASK 调制,也就是:

```
有载波 = 高电平
无载波 = 低电平
```

题目附件给的是某种原始无线 IQ 采样数据

常见 SDR 原始采样格式是:

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

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

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

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

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

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

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

```python
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}`

```python
import numpy as np

path = "iiiiicccccssssshhhhheeeeexxxxx"

# 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()}}}")
```
Loading