开源一个SPEEX全双工数字对讲机。用NRF24L01实现了全双工通信,就像打电话一样,目前实现的只是点对点,直线距离测试最远有300M,用了网上那种加了PA的模块。电路采用STM32F103R作为主控制芯片。 注意: 8k采样,是1S/1KB 的数据量,也就是1MS一个B,压缩率真的很高。音质和打电话差不多,噪音很小。其实要传的数据量很小,1S/KB 的数据量,这里选择2.4G的原因是因为要用应答包携带数据来回传数据,不然收发模式切换会很慢,达不到全双工的要求。 无线数字全双工对讲机电路: 无线数字全双工对讲机源码截图: 和大家分享一下SpeexLib使用中的一些小技巧:1. 先讲一讲这个东西怎么用
其实讲到这里,很多人都会想到ST有提供的现成的基于F103系列的库,没错我就是从这个库里面研究起来的,这个库有他的优点:ST专门对几个滤波器函数优化过,使用汇编写的,删除了一些子模式,并且使用定点运算,再这里先贴一下被ST优化过得那几个函数名称:filter_mem16(), inner_prod(),vq_nbest()等等,之所以这样才得以在103上面可以运行起来,缺点嘛:就是被阉割过了,只能使用一个模式,你如果想要更高的语音质量就别想用这个库了,它里面默认的质量是4,最好的质量等级是10,,具体的可以看下面的那个结构体:
初始值
其实如果真做语音压缩一类的话,我推荐用F407,开启FPU。或者DSP,优点嘛有很多,其中我认为最有用的就是里面的VBR了,可以做动态变比,也就是当你有语音信息的时候就会编出比较多的数据,没有语音信息时编出的数据非常少,只有1个Byte,这个也就引出了后面的DTX,它的意思就是说你没有语音信号的时候可以不传数据,想想这是不是很方便呢。好这个先提到这里,后面还有预处理什么的,这个VBR就放到后面来讲。有了上面这些参数的定义我们可以初始化到Speex里面去了,可以这样操作:
在这里特别提醒一下大家,这个库使用了一些内存分配,需要从堆里面去开辟内存,所以你的程序如果一运行到初始化就进入硬件错误,没关系,堆开大点就好了,一般对于编码解码来说 :0x8000的大小就可以了。后面说说怎么编码吧:
这里注意这个Nbyte,不要被ST提供的那个库给迷惑了,正确的用法是这样。
解码是这样:
这里有一些代码是用于缓存语音的,所以自己写了一个环形队列,为了方便大家阅读,我把代码贴出来: /** ****************************************************************************** * @author Luoxianhui R&D Driver Software Team ****************************************************************************** **/ /* 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 今天先说到这里,后续,希望对大家有用。 免责声明:本文素材来源网络,版权归原作者所有。如涉及作品版权问题,请与我联系删除。
|