电子产业一站式赋能平台

PCB联盟网

搜索
查看: 2894|回复: 4
收起左侧

(分享)无线数字全双工对讲机电路+源码

[复制链接]

17

主题

59

帖子

407

积分

一级会员

Rank: 1

积分
407
发表于 2021-8-17 21:04:06 | 显示全部楼层 |阅读模式
开源一个SPEEX全双工数字对讲机。用NRF24L01实现了全双工通信,就像打电话一样,目前实现的只是点对点,直线距离测试最远有300M,用了网上那种加了PA的模块。电路采用STM32F103R作为主控制芯片。
注意:
8k采样,是1S/1KB 的数据量,也就是1MS一个B,压缩率真的很高。音质和打电话差不多,噪音很小。其实要传的数据量很小,1S/KB 的数据量,这里选择2.4G的原因是因为要用应答包携带数据来回传数据,不然收发模式切换会很慢,达不到全双工的要求。
无线数字全双工对讲机电路:
图片1.png
无线数字全双工对讲机源码截图:


和大家分享一下SpeexLib使用中的一些小技巧:
1. 先讲一讲这个东西怎么用
    其实讲到这里,很多人都会想到ST有提供的现成的基于F103系列的库,没错我就是从这个库里面研究起来的,这个库有他的优点:ST专门对几个滤波器函数优化过,使用汇编写的,删除了一些子模式,并且使用定点运算,再这里先贴一下被ST优化过得那几个函数名称:filter_mem16(), inner_prod(),vq_nbest()等等,之所以这样才得以在103上面可以运行起来,缺点嘛:就是被阉割过了,只能使用一个模式,你如果想要更高的语音质量就别想用这个库了,它里面默认的质量是4,最好的质量等级是10,,具体的可以看下面的那个结构体:

初始值

其实如果真做语音压缩一类的话,我推荐用F407,开启FPU。或者DSP,优点嘛有很多,其中我认为最有用的就是里面的VBR了,可以做动态变比,也就是当你有语音信息的时候就会编出比较多的数据,没有语音信息时编出的数据非常少,只有1Byte,这个也就引出了后面的DTX,它的意思就是说你没有语音信号的时候可以不传数据,想想这是不是很方便呢。好这个先提到这里,后面还有预处理什么的,这个VBR就放到后面来讲。有了上面这些参数的定义我们可以初始化到Speex里面去了,可以这样操作:

在这里特别提醒一下大家,这个库使用了一些内存分配,需要从堆里面去开辟内存,所以你的程序如果一运行到初始化就进入硬件错误,没关系,堆开大点就好了,一般对于编码解码来说 0x8000的大小就可以了。后面说说怎么编码吧:

这里注意这个Nbyte,不要被ST提供的那个库给迷惑了,正确的用法是这样。
解码是这样:

这里有一些代码是用于缓存语音的,所以自己写了一个环形队列,为了方便大家阅读,我把代码贴出来:
/**
  ******************************************************************************
  * @file    MemQueue.C
  * @Author  Luoxianhui R&D Driver Software Team
  * @version V1.0.0
  * @date    06/09/2013
  * @brief   MemQueue»·DζóáD»o′æ
  ******************************************************************************
**/
  
/* Includes ------------------------------------------------------------------*/
#include "MemQueue.h"
#include "define.h"
#include "includes.h"
/** @addtogroup MemQueue_Driver
  * @{
  */
/** @addtogroup Mem
  * @{
  */
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
SqQueueChar TestQueue;
// SqQueueChar RxQueue;
// SqQueueChar TxQueue;
SqJitterQueueChar RxQueue;
SqQueueShort AdQueue;
SqQueueShort DaQueue;
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
void InitQueueChar(SqQueueChar *Q, INT32U F, INT32U E);
INT16U QueueLenthChar(SqQueueChar *Q);
SqQueueSta EnQueueChar(SqQueueChar *Q, INT8U Data);
SqQueueSta DeQueueChar(SqQueueChar *Q, INT8U *Data);
SqQueueSta EnQueueStrChar(SqQueueChar *Q, INT8U *Data,INT16U No);
SqQueueSta DeQueueStrChar(SqQueueChar *Q, INT8U *Data,INT16U No);
void InitQueueShort(SqQueueShort *Q, INT32U F, INT32U E);
INT16U QueueLenthShort(SqQueueShort *Q);
SqQueueSta EnQueueShort(SqQueueShort *Q, INT16S Data);
SqQueueSta DeQueueShort(SqQueueShort *Q, INT16S *Data);
SqQueueSta EnQueueStrShort(SqQueueShort *Q, INT16S *Data,INT16U No);
SqQueueSta DeQueueStrShort(SqQueueShort *Q, INT16S *Data,INT16U No);
void InitJitterQueueChar(SqJitterQueueChar *Q, INT32U F, INT32U E);
INT16U JitterQueueLenthChar(SqJitterQueueChar *Q);
SqQueueSta DeJitterQueueChar(SqJitterQueueChar *Q, INT8U *Data, INT16U *No);
SqQueueSta EnJitterQueueChar(SqJitterQueueChar *Q, INT8U *Data, INT16U No);
void InitQueueShort(SqQueueShort *Q, INT32U F, INT32U E)
{
        Q->sRear  = 0;
        Q->sFront = 0;
        Q->BufFullShortScal = F;
        Q->BufEmptyShortScal = E;
      
}
INT16U QueueLenthShort(SqQueueShort *Q)
{
        return(((Q->sRear) - (Q->sFront) + BufSizeShort) % BufSizeShort);
}
SqQueueSta EnQueueShort(SqQueueShort *Q, INT16S Data)
{
        if((((Q->sRear)+1) % BufSizeShort) ==  (Q->sFront))  return FALSE;
        (*Q).gBuf[Q->sRear] = Data;
        Q->sRear = (Q->sRear + 1) % BufSizeShort;
        return TRUE;
}
SqQueueSta DeQueueShort(SqQueueShort *Q, INT16S *Data)
{
        if(Q->sRear == Q->sFront) return FALSE;
      
        *Data = (*Q).gBuf[Q->sFront];
        Q->sFront = (Q->sFront + 1) % BufSizeShort;
        return TRUE;
}
SqQueueSta EnQueueStrShort(SqQueueShort *Q, INT16S *Data,INT16U No)
{
        OS_CPU_SR cpu_sr=0;
        INT16U i = 0;
        INT16U Len = 0;
        Len = QueueLenthShort(Q);
        if(Len >= Q->BufFullShortScal)
        {
                Q->BufEmpty = BufFull;
        }
        if(Len <= Q->BufEmptyShortScal)
        {
                Q->BufEmpty = BufEmpty;
        }
        if( Len >= (BufSizeShort-No)) return FALSE;      
        OS_ENTER_CRITICAL();
        for(i=0; i<No; i++)
  {
                EnQueueShort(Q,Data);
  }      
        OS_EXIT_CRITICAL();
        return TRUE;
      
}
SqQueueSta DeQueueStrShort(SqQueueShort *Q, INT16S *Data,INT16U No)
{
        INT16U i = 0;
        INT16U Len = 0;
        OS_CPU_SR cpu_sr=0;
        Len = QueueLenthShort(Q);
        if(Len >= Q->BufFullShortScal)
        {
                Q->BufEmpty = BufFull;
        }
        if(Len <= Q->BufEmptyShortScal)
        {
                Q->BufEmpty = BufEmpty;
        }
        if(Len <= No) return FALSE;
  OS_ENTER_CRITICAL();
        for(i=0; i<No; i++)
        {      
          DeQueueShort(Q,&(Data));
        }
        OS_EXIT_CRITICAL();
        return TRUE;
}
void InitQueueChar(SqQueueChar *Q, INT32U F, INT32U E)
{
        Q->sRear  = 0;
        Q->sFront = 0;
        Q->BufFullCharScal = F;
        Q->BufEmptyCharScal = E;
}
INT16U QueueLenthChar(SqQueueChar *Q)
{
        return(((Q->sRear) - (Q->sFront) + BufSizeChar) % BufSizeChar);
}
SqQueueSta EnQueueChar(SqQueueChar *Q, INT8U Data)
{
        if((((Q->sRear)+1) % BufSizeChar) ==  (Q->sFront))  return FALSE;
        (*Q).gBuf[Q->sRear] = Data;
        Q->sRear = (Q->sRear + 1) % BufSizeChar;
        return TRUE;
}
SqQueueSta DeQueueChar(SqQueueChar *Q, INT8U *Data)
{
        if(Q->sRear == Q->sFront) return FALSE;
      
        *Data = (*Q).gBuf[Q->sFront];
        Q->sFront = (Q->sFront + 1) % BufSizeChar;
        return TRUE;
}
SqQueueSta EnQueueStrChar(SqQueueChar *Q, INT8U *Data,INT16U No)
{
        INT16U i = 0;
        INT16U Len = 0;
        OS_CPU_SR cpu_sr=0;
        Len = QueueLenthChar(Q);
        if(Len >= Q->BufFullCharScal)
        {
                Q->BufEmpty = BufFull;
        }
        if(Len <= Q->BufEmptyCharScal)
        {
                Q->BufEmpty = BufEmpty;
        }
        if(Len >= (BufSizeChar-No)) return FALSE;      
        OS_ENTER_CRITICAL();
        for(i=0; i<No; i++)
  {
                EnQueueChar(Q,Data);
  }      
        OS_EXIT_CRITICAL();
        return TRUE;
}
SqQueueSta DeQueueStrChar(SqQueueChar *Q, INT8U *Data,INT16U No)
{
        INT16U i = 0;
        INT16U Len = 0;
        OS_CPU_SR cpu_sr=0;
        Len = QueueLenthChar(Q);
        if(Len >= Q->BufFullCharScal)
        {
                Q->BufEmpty = BufFull;
        }
        if(Len <= Q->BufEmptyCharScal)
        {
                Q->BufEmpty = BufEmpty;
        }
        if(Len <= No) return FALSE;
  OS_ENTER_CRITICAL();
        for(i=0; i<No; i++)
        {      
          DeQueueChar(Q,&(Data));
        }
        OS_EXIT_CRITICAL();  
        return TRUE;
}
void InitJitterQueueChar(SqJitterQueueChar *Q, INT32U F, INT32U E)
{
        Q->sRear  = 0;
        Q->sFront = 0;
        Q->BufFullJitterCharScal = F;
        Q->BufEmptyJitterCharScal = E;
}
INT16U JitterQueueLenthChar(SqJitterQueueChar *Q)
{
        return(((Q->sRear) - (Q->sFront) + BufSizeJitterChar) % BufSizeJitterChar);
}
SqQueueSta EnJitterQueueChar(SqJitterQueueChar *Q, INT8U *Data, INT16U No)
{
        INT16U i = 0;
        INT16U Len = 0;
        if((((Q->sRear)+1) % BufSizeJitterChar) ==  (Q->sFront))  return FALSE;
      
        Len = JitterQueueLenthChar(Q);
      
        if(Len >= Q->BufFullJitterCharScal)
        {
                Q->BufEmpty = BufFull;
        }
        if(Len <= Q->BufEmptyJitterCharScal)
        {
                Q->BufEmpty = BufEmpty;
        }
      
        (*Q).gBuf[Q->sRear][0] = No;
        for(i=0; i<No; i++)
  {
         (*Q).gBuf[Q->sRear][i + 1] = Data;
        }
        Q->sRear = (Q->sRear + 1) % BufSizeJitterChar;
        return TRUE;
}
SqQueueSta DeJitterQueueChar(SqJitterQueueChar *Q, INT8U *Data, INT16U *No)
{
        INT16U i = 0;
        INT16U Len = 0;
        if(Q->sRear == Q->sFront) return FALSE;
      
        Len = JitterQueueLenthChar(Q);
      
        if(Len >= Q->BufFullJitterCharScal)
        {
                Q->BufEmpty = BufFull;
        }
        if(Len <= Q->BufEmptyJitterCharScal)
        {
                Q->BufEmpty = BufEmpty;
        }
        *No = (*Q).gBuf[Q->sFront][0];
        for(i=0; i<(*Q).gBuf[Q->sFront][0]; i++)
        {
                Data = (*Q).gBuf[Q->sFront][i + 1];
        }
        Q->sFront = (Q->sFront + 1) % BufSizeJitterChar;
        return TRUE;
}
下面是头文件
#ifndef _MEMQUEUE_H_
#define _MEMQUEUE_H_
#include "define.h"
#define BufSizeChar    2160
#define BufSizeShort   3200
#define BufFullChar     BufSizeChar - 920
#define BufFullShort    BufSizeShort - 960
#define BufEmptyChar     60
#define BufEmptyShort    640
#define BufSizeJitterChar     250
#define FramSizeJitterChar    70
#define BufFullJitterChar     BufSizeJitterChar - 200
#define BufEmptyJitterChar     10
typedef enum {FALSE, TRUE, BufFull, BufEmpty} SqQueueSta;
typedef struct _SqJitterQueueChar
{
        INT8U  gBuf[BufSizeJitterChar][FramSizeJitterChar];
        INT16U  sFront;
        INT16U  sRear;
        INT32U  BufFullJitterCharScal;
        INT32U  BufEmptyJitterCharScal;
  SqQueueSta BufEmpty;      
}SqJitterQueueChar;
typedef struct _SqQueueChar
{
        INT8U  gBuf[BufSizeChar];
        INT16U  sFront;
        INT16U  sRear;
        INT32U  BufFullCharScal;
        INT32U  BufEmptyCharScal;
  SqQueueSta BufEmpty;      
}SqQueueChar;
typedef struct _SqQueueShort
{
        INT16S  gBuf[BufSizeShort];
        INT16U  sFront;
        INT16U  sRear;      
        INT32U  BufFullShortScal;
        INT32U  BufEmptyShortScal;
        SqQueueSta BufEmpty;
      
}SqQueueShort;
extern SqQueueChar TestQueue;
// extern SqQueueChar RxQueue;
// extern SqQueueChar TxQueue;
extern SqJitterQueueChar RxQueue;
// extern SqJitterQueueChar TxQueue;
extern SqQueueShort AdQueue;
extern SqQueueShort DaQueue;
void InitQueueChar(SqQueueChar *Q, INT32U F, INT32U E);
INT16U QueueLenthChar(SqQueueChar *Q);
SqQueueSta EnQueueChar(SqQueueChar *Q, INT8U Data);
SqQueueSta DeQueueChar(SqQueueChar *Q, INT8U *Data);
SqQueueSta EnQueueStrChar(SqQueueChar *Q, INT8U *Data,INT16U No);
SqQueueSta DeQueueStrChar(SqQueueChar *Q, INT8U *Data,INT16U No);
void InitQueueShort(SqQueueShort *Q, INT32U F, INT32U E);
INT16U QueueLenthShort(SqQueueShort *Q);
SqQueueSta EnQueueShort(SqQueueShort *Q, INT16S Data);
SqQueueSta DeQueueShort(SqQueueShort *Q, INT16S *Data);
SqQueueSta EnQueueStrShort(SqQueueShort *Q, INT16S *Data,INT16U No);
SqQueueSta DeQueueStrShort(SqQueueShort *Q, INT16S *Data,INT16U No);
void InitJitterQueueChar(SqJitterQueueChar *Q, INT32U F, INT32U E);
INT16U JitterQueueLenthChar(SqJitterQueueChar *Q);
SqQueueSta DeJitterQueueChar(SqJitterQueueChar *Q, INT8U *Data, INT16U *No);
SqQueueSta EnJitterQueueChar(SqJitterQueueChar *Q, INT8U *Data, INT16U No);
#endif
今天先说到这里,后续,希望对大家有用。
免责声明:本文素材来源网络,版权归原作者所有。如涉及作品版权问题,请与我联系删除。

图片4.png
图片3.png
图片2.png
回复

使用道具 举报

0

主题

9

帖子

58

积分

一级会员

Rank: 1

积分
58
发表于 2021-10-26 15:50:39 | 显示全部楼层
不错的资料 谢谢
回复 支持 反对

使用道具 举报

0

主题

7

帖子

74

积分

一级会员

Rank: 1

积分
74
发表于 2021-10-26 22:04:58 | 显示全部楼层
谢谢分享,看看先
回复 支持 反对

使用道具 举报

0

主题

27

帖子

107

积分

一级会员

Rank: 1

积分
107
发表于 2023-8-22 11:41:41 | 显示全部楼层
有点复杂,需要慢慢看
回复 支持 反对

使用道具 举报

0

主题

104

帖子

421

积分

一级会员

Rank: 1

积分
421
发表于 2023-10-4 09:54:40 | 显示全部楼层
这些都是高档货
回复 支持 反对

使用道具 举报

发表回复

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

站长推荐上一条 /1 下一条


联系客服 关注微信 下载APP 返回顶部 返回列表