树莓派zero 2w i2c操作 rda5807收音机芯片记录(电台差转站点远程监听可行性探讨)

—文章于2022年3月18日0:54重新修改—

  • 哈楼,大家好,我又来弄收音机啦,没办法,从事广播技术行业就只能弄这个。

  • 本人在地级市电视台工作,主要从事广播传输及发射有关方面的技术工作,我们县区站点较多,因为资金上的问题一直没有一套远程监控及监听的系统,闲(mo)暇(yu)之(shi)余(jian),我就在想能不能自己弄一个简单的监听设备,最开始想通过51来实现,后来发现51可能不行,果断放弃,接着又把目光放到了stm32上,但是因本人水平有限,最终还是不了了之。偶然间看到了树莓派,看介绍,这不就是我想要的baby吗,果断开整。

  • 从最开始的c51到后面的stm32,今年在芯片飞涨的时候狠心从js手里买了块树莓派zero 2W,双100网口扩展卡+16g tf卡,一共花了290大洋,闲话不多说了,上干货。

  • 以下是我自己业余时间弄的一些简单记录: 项目完整资源地址->点我啦(略微挣点积分)有兴趣的可以看看。

  • 思路:5807解调电台后, ffmpeg通过声卡采集并推送到流媒体服务器(树莓派自己就行),远程通过vlc或者web网页播放并控制(tea5767在github上有前辈已经弄好了,我也是参照前辈的一些思路,具体项目地址->https://github.com/LinuxCircle/tea5767

  • 需要的东西:树莓派1个(型号随意,带网口就行),rda5807(某宝2-3块钱一大堆,102bc板子和tea5767通用,tea5767输出只有80mv,需要加放大,而且本身就略贵,最便宜的6块多,rda5807可以直接驱动一般的耳机,像苹果手机的有线耳机实测完全没问题,比较划算),usb声卡10来快钱,或者用ti的pcm2902(2902好像停产了,我在网上买的usb声卡就是2902,怪不得便宜)自己做

  • 准备工作:1,我用的python,下载pycharm社区版(这个是免费的!虽然功能不多,够用了),建议在ubuntu下使用,ubuntu软件中心可以直接安装python社区版,win下pip安装模块问题太多。2,树莓派系统安装,进入系统开启i2c,这个一搜一大堆,就不赘述了。3,将5807与树莓派连接好。

  • 树莓派:安装ffmpeg,参照->http://relyn.cn/share/47。安装srs,参照->https://blog.csdn.net/weixin_34197488/article/details/91460318。在这里感谢两位前辈。

  • i2c地址确定:首先安装i2c-tools(这个也是一搜一大堆),通过i2cdetect -y 1,惊喜来了,3个地址…在这里插入图片描述dump一下,只有0x11有数据在这里插入图片描述就是他了。

  • python:使用的python3.8(本人第一次用python,在b站上2倍速一口气看了播放量最高的那个教程200多集,粗略了解了下,够用了,不涉及高端,有不足的地方欢迎大家指正),pip安装smbus2(i2c用的)和tornado(用到websocket,也可以开启http),或者在pycharm设置里为项目安装。

  • 程序设计:导入smbus2,自带了i2c操作相关方法,注意rda5807是16位的寄存器,官方手册上说的是在读取和写入过程中寄存器地址不可见,通过内部自增控制,实测可以直接通过寄存器地址进行读写操作,在读取和写入的时候都是高8位在前,低8位在后

import smbus2
import time


class Rda5807:

    def __init__(self):
        self.add = 0x11
        self.band = 870  #为便于计算,python3的浮点数计算有点奇怪的问题
        self.bus = smbus2.SMBus(1)
        self.mute_flag = 0
        self.on_flag = 0
        self.ready_flag = 0

    def i2c_read(self, reg_add):
        """
        read 2 bytes High byte Low byte
        :param reg_add: reg address
        :return: 16bit
        """
        result = self.bus.read_word_data(self.add, reg_add)
        result_l = result >> 8  # Low byte
        result_h = (result & 0x00ff) << 8  # High byte
        result = result_h + result_l
        return result

    def i2c_write(self, reg_add, data):
        """
        write 2 bytes High byte Low byte
        :param reg_add: reg address
        :param data: 16bit
        """
        data_l = data >> 8  # Low byte
        data_h = (data & 0x00ff) << 8  # High byte
        data = data_h + data_l
        self.bus.write_word_data(self.add, reg_add, data)

其余的控制方法比较简单,参照手册编写就可以了,tornado配置websocket,前端页面采用websocket协议与控制程序通信

from typing import Optional, Awaitable  # 这个是根据pycharm对tornado的提示改的,不懂

import tornado.httpserver
import tornado.websocket
import tornado.ioloop
import tornado.web
import Rda5807
import os
import time


# class MainHandler(tornado.web.RequestHandler):
#     def data_received(self, chunk: bytes) -> Optional[Awaitable[None]]:
#         pass
#
#     def get(self):
#         self.render("rda5807_tornado.html")


def check_push():
    """
    check ffmpeg and srs
    :return: 0 -> not, 1 -> yes
    """
    com_ff = "ps -ef | grep -m 1 ffmpeg | grep -v grep"
    com_srs = "ps -ef | grep -m 1 srs | grep -v grep"
    ffmpeg_pid = os.popen(com_ff, mode="r").readlines()
    srs_pid = os.popen(com_srs, mode="r").readlines()
    if len(ffmpeg_pid) and len(srs_pid):
        return 1
    else:
        return 0


def audio_push():
    """
    begin audio push
    :return: 0 -> stop success,
             1 -> start success,
             2 -> start failed,
             3 -> stop failed
                 """
    com_push = "/etc/init.d/fmstation "
    pid = check_push()
    if pid == 0:
        os.popen(com_push + "start", mode="r")
        time.sleep(10)
        if check_push():
            print("Audio Push Start Success")
            return 1
        else:
            print("Audio Push Start Failed")
            return 2
    else:
        os.popen(com_push + "stop", mode="r")
        time.sleep(10)
        if check_push() == 0:
            print("Audio Push Stop Success")
            return 0
        else:
            print("Audio Push Stop Failed")
            return 3


class Wsocket(tornado.websocket.WebSocketHandler):
    controller = None

    def data_received(self, chunk: bytes) -> Optional[Awaitable[None]]:  # 这里pycharm提示了个什么必须实现所有的什么方法,按照提示改的,不懂
        pass

    def check_origin(self, origin):
        return True

    def open(self):
        print("connecting...")
        try:
            self.controller = Rda5807.Rda5807()
            # self.controller.set_init()
            data = self.info()
            self.write_message(data)
        except Exception as a:
            print(a)

    def on_message(self, message):
        print("Command", message)
        try:
            if message == "up":
                self.controller.seek(1)
            elif message == "down":
                self.controller.seek(0)
            elif message == "v+":
                self.controller.set_volume("+")
            elif message == "v-":
                self.controller.set_volume("-")
            elif message == "mute":
                self.mute()
            elif message == "on":
                self.controller.set_init()
            elif message == "off":
                self.switch()
            # time.sleep(0.2)
            elif message == "push":
                audio_push()
            data = self.info()
            self.write_message(data)
        except Exception as a:
            print(a)

    def on_close(self):
        print("closing socket")
        self.controller = ""

    def info(self):
        """
        websocket data
        :return: data
        """
        status = self.controller.get_status()
        push_flag = check_push()
        data = {"freq": str(self.controller.get_freq()),
                "level": self.controller.get_rssi(),
                "stereo": "stereo" if status[2] else "mono",
                "ready_flag": status[4],
                "mute": self.controller.mute_flag,
                "push_flag": push_flag,
                "vol": str(status[5])}
        print(data)
        return data

    def switch(self):
        """
        turn on or off
        """
        data = self.controller.get_status()
        self.controller.ready_flag = data[4]
        if self.controller.ready_flag:
            self.controller.power_down()
        else:
            self.controller.set_init()

    def mute(self):
        """
        audio out mute
        """
        if self.controller.mute_flag:
            self.controller.set_mute(0)
        else:
            self.controller.set_mute(1)


favicon_path = ""


def make_app():
    return tornado.web.Application([
        # (r'/favicon.ico', tornado.web.StaticFileHandler, {'path': favicon_path}),
        # (r"/images/(.*)", tornado.web.StaticFileHandler, {"path": "./images"},),
        # (r'/static/(.*)', tornado.web.StaticFileHandler, {'path': "./static"}),
        # (r'/', MainHandler),
        (r"/ws", Wsocket),
    ])


if __name__ == "__main__":
    app = make_app()
    print("WebSockets is Running on port 8888")
    app.listen(8888)
    tornado.ioloop.IOLoop.instance().start()

我把srs和ffmpeg的启动整合成了一个shell

#!/bin/bash
# /etc/init.d/fmstation

### BEGIN INIT INFO
# Provides:          fmstation
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: fm ffmpeg to srs
# Description:       none
### END INIT INFO

case "$1" in
    start)
        echo "Starting fmstation"
        sudo /etc/init.d/srs start
        sleep 5s
        nohup ffmpeg -f alsa -ar 48000 -ac 1 -i hw:1 -f flv rtmp://localhost:1935/live/livestream 1>/dev/null 2>&1 &
        ;;
    stop)
        echo "Stopping fmstation"
        sudo kill -9 $(ps aux | grep -m 1 'ffmpeg' | awk '{ print $2 }')
        sudo kill -9 $(ps aux | grep -m 1 'ffmpeg' | awk '{ print $2 }')
        sudo /etc/init.d/srs stop
        ;;
   restart)
        echo "Restarting fmstation"
        sudo kill -9 $(ps aux | grep -m 1 'ffmpeg' | awk '{ print $2 }')
        sudo /etc/init.d/srs restart
        sleep 5s
        nohup ffmpeg -f alsa -ar 48000 -ac 1 -i hw:1 -f flv rtmp://localhost:1935/live/livestream 1>/dev/null 2>&1 &
        ;;

esac
exit 0

注意nohup可以指定标准输出和错误输出为null消失掉,不消失掉的话ffmpeg会一直输出到nohub.out。

最后前端使用bootstrap写了个简单页面
在这里插入图片描述下周去县区安装测试。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值