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

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

相关文章

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

树莓派启动python的实现方法

《树莓派启动python的实现方法》本文主要介绍了树莓派启动python的实现方法,文中通过图文介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录一、RASPBerry系统设置二、使用sandroidsh连接上开发板Raspberry Pi三、运

Python利用自带模块实现屏幕像素高效操作

《Python利用自带模块实现屏幕像素高效操作》这篇文章主要为大家详细介绍了Python如何利用自带模块实现屏幕像素高效操作,文中的示例代码讲解详,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1、获取屏幕放缩比例2、获取屏幕指定坐标处像素颜色3、一个简单的使用案例4、总结1、获取屏幕放缩比例from

nginx-rtmp-module模块实现视频点播的示例代码

《nginx-rtmp-module模块实现视频点播的示例代码》本文主要介绍了nginx-rtmp-module模块实现视频点播,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习... 目录预置条件Nginx点播基本配置点播远程文件指定多个播放位置参考预置条件配置点播服务器 192.

基于Python开发PPTX压缩工具

《基于Python开发PPTX压缩工具》在日常办公中,PPT文件往往因为图片过大而导致文件体积过大,不便于传输和存储,所以本文将使用Python开发一个PPTX压缩工具,需要的可以了解下... 目录引言全部代码环境准备代码结构代码实现运行结果引言在日常办公中,PPT文件往往因为图片过大而导致文件体积过大,

使用DeepSeek API 结合VSCode提升开发效率

《使用DeepSeekAPI结合VSCode提升开发效率》:本文主要介绍DeepSeekAPI与VisualStudioCode(VSCode)结合使用,以提升软件开发效率,具有一定的参考价值... 目录引言准备工作安装必要的 VSCode 扩展配置 DeepSeek API1. 创建 API 请求文件2.

基于Python开发电脑定时关机工具

《基于Python开发电脑定时关机工具》这篇文章主要为大家详细介绍了如何基于Python开发一个电脑定时关机工具,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1. 简介2. 运行效果3. 相关源码1. 简介这个程序就像一个“忠实的管家”,帮你按时关掉电脑,而且全程不需要你多做

Java中的Opencv简介与开发环境部署方法

《Java中的Opencv简介与开发环境部署方法》OpenCV是一个开源的计算机视觉和图像处理库,提供了丰富的图像处理算法和工具,它支持多种图像处理和计算机视觉算法,可以用于物体识别与跟踪、图像分割与... 目录1.Opencv简介Opencv的应用2.Java使用OpenCV进行图像操作opencv安装j

多模块的springboot项目发布指定模块的脚本方式

《多模块的springboot项目发布指定模块的脚本方式》该文章主要介绍了如何在多模块的SpringBoot项目中发布指定模块的脚本,作者原先的脚本会清理并编译所有模块,导致发布时间过长,通过简化脚本... 目录多模块的springboot项目发布指定模块的脚本1、不计成本地全部发布2、指定模块发布总结多模

Python中构建终端应用界面利器Blessed模块的使用

《Python中构建终端应用界面利器Blessed模块的使用》Blessed库作为一个轻量级且功能强大的解决方案,开始在开发者中赢得口碑,今天,我们就一起来探索一下它是如何让终端UI开发变得轻松而高... 目录一、安装与配置:简单、快速、无障碍二、基本功能:从彩色文本到动态交互1. 显示基本内容2. 创建链