对讲机联动模块开发(树莓派文字转语音模块对接)

2023-12-09 21:10

本文主要是介绍对讲机联动模块开发(树莓派文字转语音模块对接),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

最近公司方面有个业务需求,因为我们做的是智慧社区项目,有一块涉及到车辆异常出库报警,比如车辆被盗是。
这时候如何能快速的通知到安保人员呢?原来想法是给安保人员配一台PAD,或者在手机上安装个APP,但这样也有很大的弊端。而安保人员人人必备对讲机,所以考虑能不能和对讲机联动。
自然就想到了TTS(TextToSpeech),之前和小i、科大讯飞、华声捷通都用过合作,对这块业务还算比较熟悉,本来打算在树莓派上直接内置一个TTS应用就行了,但这三家都没有免费的SDK,收费的还挺贵,所以这个想法基本就放弃了,但就在最后一刻,发现科大讯飞竟然有TTS芯片!!!
XFS5152CE,科大讯飞中英文语音合成芯片,淘宝搜了一下,竟然发现了做好的模块,一个是科大讯飞自己做的(98元),还有一个是基于SYN6288芯片做的(57元),于是都买回来测试了一下,SYN6288跟XFS5152CE一比简直就是扔货,所以这里就不说关于SYN6288的开发了,如果有时间的话,可以单独做一篇。

废话到此为止,干货在下面!

首先需要准备几样东西
一对对讲机、一条手咪线、一块TTS模块,另外,我还开了一块底板,一会做介绍。


先说TTS模块的对接方式
根据XFS5152CE的开发文档,我们用到RXD、TXD、GND、V3.3、RDY四个引脚,当TTS有语音输出的时候RDY会输出高电平,这块一会我们用来控制手台的信道占用(就是我们手动按下呼叫按钮),严重说一下,这里用的电压是3.3V的,因为后面我们控制继电器的时候用的是5V的,这里千万表混了,要不然98块钱就会化作一缕青烟……

先用TTS模块做测试,科大讯飞也提供测试程序了,我们只要把模块用串口线接到电脑上(TTL电平),用他们的软件测试就行了,还没有做下一步和对讲机联动的,先用个耳机试试声音。
当然那我们这里肯定还是要写程序的。
而且仍然用的是JAVA和RXTX做,如果不清楚树莓派上怎么调试的,出门左转,有一篇专门介绍树莓派3配置串口的文章。

直接上代码
package com.marssoft.jyphon;
import gnu.io.CommPortIdentifier;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.TooManyListenersException;
/**
 * 科大讯飞XFS5152CE芯片语音合成测试程序。
 * @author Mars.CN
 *
 */
public class TTS {
      public static final byte STATE_IDLE =0X4F;        //空闲状态
      public static final byte STATE_USE =0X4E;         //占用中状态
      public static final byte STATE_INITED = 0X4A;    //初始化成功
      public static final byte STATE_SUCCESS = 0X41;   //正确的命令帧
      public static final byte STATE_ERROR = 0X45;     //错误的命令帧
      public static final byte STATE_NULL = 0X00;      //设备空
     
      public static final byte COMMAND_QUERY_STATE = 0X21;           //查询状态命令
      public static final byte COMMAND_POWER_MODE_SAVING =( byte )0X88;  //设置为省点模式
      public static final byte COMMAND_POWER_MODE_USEING =( byte )0XFF;  //设置为唤醒模式
      public static final byte COMMAND_TTS =0X01;                 //语音合成命令
      public static final byte COMMAND_STOP =0X02;                //停止语音合成
      public static final byte COMMAND_SUSPEND =0X03;             //暂停合成
      public static final byte COMMAND_RECOVERY =0X04;            //回复合成
     
     
      private SerialPort port = null ;
      private InputStream in = null ;
      private OutputStream out = null ;
      private TTS() {}
      /**
      * 初始化串口。
      * @param name
      */
      private TTS(String name) {
           //获得本地所有串口列表,这里其实只能获得ttyS开头的串口
          Enumeration<CommPortIdentifier> portList = CommPortIdentifier.getPortIdentifiers();
           while (portList.hasMoreElements()){
               //获得串口的标识符
              CommPortIdentifier portId = portList.nextElement();
               //通过标识符得到串口名字,并判断这个名字是不是我们需要的那个串口
               if (portId.getName().equals( "/dev/" +name)){
                   SerialPort p= null ;
                    try {
                         //如果确实是我们需要的串口,则打开这个串口
                         //open(串口占用进程名称,串口等待超时时间)
                        p = (SerialPort) portId.open( "TTSTest" , 2000);
                         //给串口一个数据到达侦听(触发器)
                        p.addEventListener( new EventListener());
                         //把数据到达通知打开
                        p.notifyOnDataAvailable( true );
                         //设置串口的波特率,参数依次是(波特率,数据位,停止位,校验位)
                        p.setSerialPortParams(9600,SerialPort. DATABITS_8 , SerialPort. STOPBITS_1 ,SerialPort. PARITY_NONE );
                         //获得输入输出流,方便操作。
                         out = p.getOutputStream();
                         in = p.getInputStream();
                         port =p;
                   } catch (PortInUseException e) {
                        e.printStackTrace();
                   } catch (TooManyListenersException e) {
                        e.printStackTrace();
                   } catch (UnsupportedCommOperationException e) {
                        e.printStackTrace();
                   } catch (IOException e) {
                        e.printStackTrace();
                   }
              }
          }
     }
      /**
      * 打开串口
      *
      * @param port
      */
      public static final TTS open(String name) {
          TTS serial = new TTS(name);
           if (serial. port != null ){
               return serial;
          }
           return null ;
     }
     
      /**
      * 发送数据。
      * @param data
      */
      public void send( byte [] data){
           try {
               out .write(data);
               out .flush();
          } catch (IOException e) {
              e.printStackTrace();
          }
     }
     
      /**
      * 播放信息
      * @param msg
      */
      public byte play(String msg){
           if ( port != null ){
               try {
                    //把文字内容转换成GB2312编码的二进制数据(我记得硬件里用的都是GBK,如果有问题的话大家用GBK试试看)
                    byte [] mdata = msg.getBytes( "GB2312" );
                    //根据语音合成指令,协议头三个字节,分别是帧头0XFD,数据长度高字节,数据长度低字节,语音合成命令0X01,编码类型0X00(GB2312),后面是数据
                    byte [] datas = new byte [5+mdata. length ];
                   datas[0]=( byte )0xFD;
                   datas[1]=( byte )((datas. length -3)/256);
                   datas[2]=( byte )((datas. length -3)%256);
                   datas[3]= COMMAND_TTS ;
                   System.arraycopy(mdata, 0, datas, 5, mdata. length );
//                 System.out.println(HexFormat.format(datas));
                    //发送开始合成
                    out .write(datas);
                    return STATE_SUCCESS ;
              } catch (IOException e) {
                   e.printStackTrace();
                    return STATE_ERROR ;
              }
          }
           return STATE_NULL ;
     }
     
      /**
      * 关闭串口。
      */
      public void close(){
           //当然,这里可以做一下事件侦听,再给close加个参数,这样在串口异常报错的时候能能捕获到了。
           port .close();
           port = null ; out = null ; in = null ;
     }
     
      private class EventListener implements SerialPortEventListener{
           @Override
           public void serialEvent(SerialPortEvent event) {
               switch (event.getEventType()) { 
               //这些属性应该跟串口特性有关,我还没搞清楚,暂时不解释
             case SerialPortEvent. BI :
             case SerialPortEvent. OE :
             case SerialPortEvent. FE :
             case SerialPortEvent. PE :
             case SerialPortEvent. CD :
             case SerialPortEvent. CTS :
             case SerialPortEvent. DSR :
             case SerialPortEvent. RI :
             case SerialPortEvent. OUTPUT_BUFFER_EMPTY :
                 break
             case SerialPortEvent. DATA_AVAILABLE :     //获取到串口返回信息 
                int d = 0;
                 do {
                     try {
                         //读取一个串口返回之,并判断这个返回值是什么状态。
                         d = in .read();
                         switch (d){
                         case STATE_INITED :
                             System. out .println( "初始化成功" );
                              break ;
                         case STATE_SUCCESS :
                             System. out .println( "命令正确" );
                              break ;
                         case STATE_ERROR :
                             System. out .println( "命令错误" );
                              break ;
                         case STATE_IDLE :
                             System. out .println( "设备空闲" );
                              break ;
                         case STATE_USE :
                             System. out .println( "语音合成中" );
                              break ;
                         }
                     } catch (IOException e){ 
                         return
                     } 
                 } 
                 while (d != -1);
                 System. out .println( "退出关闭" );
                 close(); //这里一定要用close()方法关闭串口,释放资源 
                 break
             default
                 break
             } 
          }
     }
     
      /**
      * 测试语音
      * @param args
      */
      public static void main(String[] args) {
          TTS tts = TTS.open( "S45" );
           if (tts!= null ){
               //发送测试语音
              tts.play( "sound 101 你好世界 Hello world" );
          } else {
              System. out .println( "串口初始化失败!" );
          }
     }
}

芯片的开发指南
http://www.iflytek.com/upload/contents/2014/07/53be5e3ec4047.pdf

具体其他语音合成的方式,大家可以去参考一下开发文档,包括一些提示音的设置。

现在语音已经可以正常合成了,现在我们看如何做成一个和对讲机联动的成品。
和对讲机联动,用到了RDY引脚,当语音播放的时候,RDY引脚处于高电平,这时候我们给这个引脚加一个继电器,高电平是继电器导通,这样就把手咪线正负极导通了,也就相当于我们手动按下了对讲键,手咪线有四根,按我这个版本,黄色的是PPT(按键),红色的是MIC+,绿色的是负极,蓝色的是耳机线,直接按照这样接线就行了。

为此,我做了一块底板,上面有个继电器,再把讯飞的TTS模块焊上去,左边留下串口接口,右边留下手咪线的接口。
需要注意的是,对讲机的驱动用5V,讯飞TTS模块驱动用3.3V,正好树莓派就提供者两种电压输出,所以在树莓派一段,留的是RX、TX、GND、Vcc5V、Vcc3.3V五个口,依次对应GPIO14(8)、GPIO15(10)、GND(6)、5V(4)、3V(1),不明白的可以度娘一个树莓派3的GPIO图看看。

注意接线的时候,TX对应树莓派的RX,RX对应树莓派的TX

这篇关于对讲机联动模块开发(树莓派文字转语音模块对接)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/475065

相关文章

Python38个游戏开发库整理汇总

《Python38个游戏开发库整理汇总》文章介绍了多种Python游戏开发库,涵盖2D/3D游戏开发、多人游戏框架及视觉小说引擎,适合不同需求的开发者入门,强调跨平台支持与易用性,并鼓励读者交流反馈以... 目录PyGameCocos2dPySoyPyOgrepygletPanda3DBlenderFife

Python标准库datetime模块日期和时间数据类型解读

《Python标准库datetime模块日期和时间数据类型解读》文章介绍Python中datetime模块的date、time、datetime类,用于处理日期、时间及日期时间结合体,通过属性获取时间... 目录Datetime常用类日期date类型使用时间 time 类型使用日期和时间的结合体–日期时间(

使用Python开发一个Ditto剪贴板数据导出工具

《使用Python开发一个Ditto剪贴板数据导出工具》在日常工作中,我们经常需要处理大量的剪贴板数据,下面将介绍如何使用Python的wxPython库开发一个图形化工具,实现从Ditto数据库中读... 目录前言运行结果项目需求分析技术选型核心功能实现1. Ditto数据库结构分析2. 数据库自动定位3

Django开发时如何避免频繁发送短信验证码(python图文代码)

《Django开发时如何避免频繁发送短信验证码(python图文代码)》Django开发时,为防止频繁发送验证码,后端需用Redis限制请求频率,结合管道技术提升效率,通过生产者消费者模式解耦业务逻辑... 目录避免频繁发送 验证码1. www.chinasem.cn避免频繁发送 验证码逻辑分析2. 避免频繁

Spring Boot集成/输出/日志级别控制/持久化开发实践

《SpringBoot集成/输出/日志级别控制/持久化开发实践》SpringBoot默认集成Logback,支持灵活日志级别配置(INFO/DEBUG等),输出包含时间戳、级别、类名等信息,并可通过... 目录一、日志概述1.1、Spring Boot日志简介1.2、日志框架与默认配置1.3、日志的核心作用

Python对接支付宝支付之使用AliPay实现的详细操作指南

《Python对接支付宝支付之使用AliPay实现的详细操作指南》支付宝没有提供PythonSDK,但是强大的github就有提供python-alipay-sdk,封装里很多复杂操作,使用这个我们就... 目录一、引言二、准备工作2.1 支付宝开放平台入驻与应用创建2.2 密钥生成与配置2.3 安装ali

PyQt5 GUI 开发的基础知识

《PyQt5GUI开发的基础知识》Qt是一个跨平台的C++图形用户界面开发框架,支持GUI和非GUI程序开发,本文介绍了使用PyQt5进行界面开发的基础知识,包括创建简单窗口、常用控件、窗口属性设... 目录简介第一个PyQt程序最常用的三个功能模块控件QPushButton(按钮)控件QLable(纯文本

基于Python开发一个图像水印批量添加工具

《基于Python开发一个图像水印批量添加工具》在当今数字化内容爆炸式增长的时代,图像版权保护已成为创作者和企业的核心需求,本方案将详细介绍一个基于PythonPIL库的工业级图像水印解决方案,有需要... 目录一、系统架构设计1.1 整体处理流程1.2 类结构设计(扩展版本)二、核心算法深入解析2.1 自

Python通用唯一标识符模块uuid使用案例详解

《Python通用唯一标识符模块uuid使用案例详解》Pythonuuid模块用于生成128位全局唯一标识符,支持UUID1-5版本,适用于分布式系统、数据库主键等场景,需注意隐私、碰撞概率及存储优... 目录简介核心功能1. UUID版本2. UUID属性3. 命名空间使用场景1. 生成唯一标识符2. 数

Python中re模块结合正则表达式的实际应用案例

《Python中re模块结合正则表达式的实际应用案例》Python中的re模块是用于处理正则表达式的强大工具,正则表达式是一种用来匹配字符串的模式,它可以在文本中搜索和匹配特定的字符串模式,这篇文章主... 目录前言re模块常用函数一、查看文本中是否包含 A 或 B 字符串二、替换多个关键词为统一格式三、提