开头先说明一下,这是一篇进阶内容,如果你没有将家庭影院接入HomeAssistant控制的需求,或者对自己控制CEC没有兴趣,那么可以跳过这篇。
自从我选择了先锋VSX-835之后,我就有个想法,因为这个型号并没有网络控制之类的功能,而我又有组智能家居的计划,刚好我有喜欢折腾,就诞生了这个计划,使用树莓派控制整个家庭影院。
首先,成本控制下,首选树莓派Zero 2W,有这么多GPIO,又有HDMI接口,又小巧便宜,果断选择。然后是系统选择,我没有选官方系统,选了轻量级的DietPi,反正都是要自己开发,越轻量越好,还能减小发热。
但是!买回来调试了一下,我就发现了一个大坑,博通的HDMI控制器里面的CEC部分是不能完整访问的,暴露给系统的只有跟树莓派的HDMI接口有关的CEC信号,这就导致无法监听整条CEC链路上面的行为,所以就需要接下来的魔改。

图中箭头指向的就是CEC信号线,在GND铺铜的旁边,用小刀把它刮开,飞线到任意GPIO(我自己是飞到了GPIO5),涂点绿油,做好绝缘防护。硬件的魔改就这一点。
接下来就是内核的魔改,也是最大的一个坑。树莓派的内核里面默认是没有cec-gpio模块的,也没有暴露有关cec的符号,所以就需要自己重新编译内核。先看看你的内核版本
root@DietPi:~# uname -r
6.12.34+rpt-rpi-v8
然后就去树莓派官方的内核仓库找你的内核对应的tag,比如我这个对应的就是stable_20250702(有一个简单的方法,点进去一个tag,翻commit记录,找到最近的类似这样的记录 Linux 6.12.34 ,那这个tag对应的linux内核版本就是这个)。接着用一台x86的pc编译内核。
# 安装需要的软件包
sudo apt update
sudo apt install bc bison flex libssl-dev make libc6-dev libncurses5-dev gcc-arm-linux-gnueabihf gcc-aarch64-linux-gnu git
# 把内核源码clone到本地
git clone --depth=1 --branch stable_20250702 https://github.com/raspberrypi/linux
# 如果有需要,把这个commit合并一下,修一下vc4-hdmi的cec的小问题
https://github.com/raspberrypi/linux/commit/daa2acdbc94db93af4d5bc4e756cb66536fc774b
# 准备工作
cd linux
KERNEL=kernel8
make -j$(nproc) ARCH=arm64 CROSS_COMPILE=/usr/bin/aarch64-linux-gnu- O=OUT/ bcm2711_defconfig
make -j$(nproc) ARCH=arm64 CROSS_COMPILE=/usr/bin/aarch64-linux-gnu- O=out/ menuconfig
# 进入menuconfig,General setup ---> Local version - append to kernel release,删除掉原本的-v8
# Device Drivers ---> CEC support ---> HDMI CEC drivers ---> Generic GPIO-based CEC driver 设置为M,也就是构建为内核模块,返回上级,打开Enable CEC error injection support
# 保存退出
# 编译内核
make -j$(nproc) ARCH=arm64 CROSS_COMPILE="/usr/bin/aarch64-linux-gnu-" O=OUT/ LOCALVERSION=+rpt-rpi-v8 Image modules dtbs
编译完成之后,将以下文件复制出来备用
OUT\arch\arm64\boot\Image
OUT\drivers\media\cec\core\cec.ko
OUT\drivers\media\cec\platform\cec-gpio\cec-gpio.ko
OUT\drivers\gpu\drm\vc4\vc4.ko
OUT\arch\arm64\boot\dts\broadcom\*.dtb
OUT\arch\arm64\boot\dts\overlays\*.dtb*
进入树莓派的shell,创建一个dtoverlay,命名为cec-gpio-overlay.dts
/dts-v1/;
/plugin/;
/ {
compatible = "brcm,bcm2835", "brcm,bcm2710", "brcm,bcm2711";
fragment@0 {
target-path = "/";
__overlay__ {
cec_gpio: cec-gpio@5 {
compatible = "cec-gpio";
cec-gpios = <&gpio 5 6>;
status = "okay";
};
};
};
};
自行根据自己的魔改修改GPIO编号(不要动6,那个是配置功能的)。
dtc -@ -I dts -O dtb -o cec-gpio-overlay.dtbo cec-gpio-overlay.dts
编译完之后,用刚才编译的所有东西替换系统的文件。
Image -> /boot/firmware/kernel8.img
cec.ko -> /lib/modules/6.12.34+rpt-rpi-v8/kernel/drivers/media/cec/core/cec.ko
cec-gpio.ko -> /lib/modules/6.12.34+rpt-rpi-v8/kernel/drivers/media/cec/platform/cec-gpio/cec-gpio.ko
vc4.ko -> /lib/modules/6.12.34+rpt-rpi-v8/kernel/drivers/gpu/drm/vc4/vc4.ko
broadcom\*.dtb -> /boot/firmware
overlays\*.dtb* -> /boot/firmware/overlays
修改/boot/config.txt,加上一行dtoverlay=cec-gpio-overlay
然后创建一个文件/etc/modprobe.d/cec-gpio-softdep.conf,用于调整cec设备的注册顺序。
# Ensure vc4 loads before the GPIO CEC driver so vc4 becomes /dev/cec0
softdep cec-gpio pre: vc4
softdep cec_gpio pre: vc4
然后运行这条命令。
depmod -a
重启之后,查看/dev下是否有两个cec设备,如果都有,那么就成功了。如果没有vc4-hdmi,去dietpi-config -> Display Options -> Display Resolution,调整为vc4-kms-v3d。如果没有cec-gpio,确定一下上面的步骤都没问题,看看dmesg,问问GPT吧。
接下来安装用于控制CEC的软件包,并检查两个cec设备。
sudo apt update
sudo apt install v4l-utils
cec-ctl -d /dev/cec0
cec-ctl -d /dev/cec1
然后介绍一些常用的功能
初始化CEC设备,并显示链路中其他设备的信息
cec-ctl -d /dev/cec0 --playback -o pi_cec_test -S
cec-ctl -d /dev/cec1 --playback -o pi_cec_gpio_test -p 2.2.0.0 -S
# -d 指定使用的设备 -o 设置自己的osd名称 -p 设置自己的物理地址
# cec-ctl可以从EDID获取自己的物理地址,所以使用vc4-hdmi时可以不指定物理地址,而cec-gpio没有绑定自己的HDMI接口,所以需要指定物理地址
# --playback 将自己设定为播放设备,以下是cec里面的所有设备类型
--tv 电视/显示设备
--record 录像机
--tuner 调谐器
--playback 播放设备
--audio 音响/AV功放等
--processor 视频处理器,如madvr
--switch 路由设备,HDMI切换器
--cdc-only 控制设备,只用于CEC控制
--unregistered 未注册设备
搞完cec的部分,然后搞IR控制,这个也踩了不少坑。不要自己用 Python 解析原始 GPIO 波形(我一开始就是这么干,被稳定性和时序坑惨了)。Linux 内核已经有成熟的 gpio-ir / gpio-ir-tx 驱动,走内核稳定、效率高、能直接被上层工具识别。
根据chatgpt的推荐,红外接收器用了TSOP38236,发射器用了TSAL6400,下面是chatgpt完整的推荐方案。
红外发射二极管:TSAL6400(940 nm) ×1
MOSFET:AO3400A / IRLML6344 / 2N7002E 不推荐(2N7002导通电阻偏大),建议 AO3400A
限流电阻:18 Ω / 1 W(5 V 供电、目标脉冲电流≈200 mA)
栅极串联电阻:220 Ω
栅极下拉电阻:100 kΩ(防上电误触发)
去耦:10 µF 电解/钽 + 0.1 µF X7R(靠近 LED 与电源点)
供电与引脚(树莓派 40Pin 头):
- 5 V:Pin 2(或 Pin 4)
- GND:Pin 6(任一 GND 都可)
- GPIO18(硬件 PWM):Pin 12
TSOP38236(Vishay,36 kHz 接收头,脚序:1=OUT,2=GND,3=VS)
电容:0.1 µF(X7R)×1 + 4.7 µF(钽/电解)×1(靠近接收头引脚)
电阻:
- R_V:100 Ω(VS 端串联,抑制电源尖峰,可选但推荐)
- R_G:1 kΩ(GPIO 串联保护,可选)
若走线很长,可在 OUT 到 GND 串 RC(~1 k+100 pF) 做轻微去毛刺(通常不需要)。
搭好之后,继续改/boot/config.txt,加上两行
dtoverlay=gpio-ir-tx,gpio_pin=12
dtoverlay=gpio-ir,gpio_pin=你连的那个
加好后重启。重启后内核会创建对应的 rc 设备(如 /sys/class/rc/rc0 或 /dev/lirc0 / /dev/rc0,不同内核/驱动有细微差异),可以通过 dmesg 查看内核日志确认驱动加载情况。
用apt安装ir-keytable python3-pip,测试接收器能否识别信号。
sudo ir-keytable -t
按遥控器键,看内核是否有扫描到 scancode。如果没有,检查 /boot/config.txt 的 overlay、GPIO 接线与电源去耦。
去我的repo搞个程序下来,运行ir_rec.py,一个个记录你的遥控器的红外码,只支持NEC,其他的自己研究把。
搞完之后会生成一个keymap.json,用来记录你的遥控器的红外编码,自己再改一下key_layout.json,改一下键位,运行ir_web.py,就能在内网运行一个树莓派遥控器了。
如果要在Windows上执行cec-ctl命令的话,我写了一个cec-ssh,把cec-ctl命令转发到树莓派上,可以跟本地一样控制,详细看我的repo。
接入homeassistant的等我搞完再慢慢写。。。。。
發佈留言
很抱歉,必須登入網站才能發佈留言。