mems数字麦克风大致都一样,VDD和GND,时钟脚CLK,左右声道选择L/R,数据线DATA,当然这是输出PDM数据的麦克风,也有I2S接口的数字麦克风,他会多一个引脚,就是WS。我使用的是PDM数字麦克风。
该器件根据LR电平,分别在CLK的低电平和高电平时间输出左右声道信号,我这里就L/R接地,只有一个硅麦。实现单声道采集。(连线我就不多讲了,肯定都会)
直接使用CubeMX进行配置
48KHz的采样率,16位数据,CLK的频率就是1.536MHz,
开启DMA采集
配置PDM2PCM
PDM_Filter_Handler_t PDM1_filter_handler;
PDM_Filter_Config_t PDM1_filter_config;
/* Initialize PDM Filter structure */
PDM1_filter_handler.bit_order = PDM_FILTER_BIT_ORDER_LSB;
PDM1_filter_handler.endianness = PDM_FILTER_ENDIANNESS_BE;
PDM1_filter_handler.high_pass_tap = 2136746228; //2104533974; //2136746228; //0.9xx*(2^31-1)
PDM1_filter_handler.out_ptr_channels = 1;
PDM1_filter_handler.in_ptr_channels = 1;
PDM_Filter_Init ( ( PDM_Filter_Handler_t * ) ( &PDM1_filter_handler ) );
PDM1_filter_config.output_samples_number = 32;
PDM1_filter_config.mic_gain = 0;
PDM1_filter_config.decimation_factor = PDM_FILTER_DEC_FACTOR_48; //PCM数据的频率:i2s的clock/抽取因子/2
PDM_Filter_setConfig ( ( PDM_Filter_Handler_t * ) &PDM1_filter_handler, &PDM1_filter_config );
开启I2S的DMA采集
HAL_I2S_Receive_DMA ( &hi2s3, &pdmRxBuf[0], PDM_NUM );
数据存放在pdmRxBuf里,调用转换函数
PDM_Filter ( &pdmRxBuf[0], &MidBuffer[0], &PDM1_filter_handler );
这里MidBuffer里存放的就是PCM数据。当你说话时,可以明显的看到PCM数据变化。
后面就是PCM转dB了,两个方法
1.使用求振幅平均值
/**
* @brief 获取PCM数据分贝值
*
* @param pcm : pcm数据指针
* @param len : pcm数据长度
* @return int : 分贝值 = 20*log10(pcm数据平均值)
* @note Lp = 20*log10(Prms/Pref)dB | Lp:计算结果音频分贝值, Prms:当前声音振幅值,Pref:声音振幅最大值(16bit=65535), 16Bit最大分贝值=20*log10(65535)=96.32(dB)。
*
*/
int komijbox_sound_dB ( const int16_t *pcm, int len )
{
int sum = 0;
int dB = 0;
short tmp = 0;
short *pcmaddr = ( short * ) pcm;
for ( int i = 0; i < len; i++ )
{
memcpy ( &tmp, pcmaddr + i, 2 ); // 获取2字节PCM数据
sum += abs ( tmp ); // 绝对值求和累加
}
sum = sum / ( len ); // 求PCM数据的平均值,2个字节表示一个16Bit PCM采样数据
printf ( "%d\r\n", sum );
if ( sum )
{
dB = ( int ) ( 20 * log10 ( sum ) );
}
return dB;
}
2.均方根
float Process ( const int16_t *data, int length )
{
int sum_square_ = 0;
int sample_count_ = 0;
for ( int i = 0; i < length; i++ )
{
sum_square_ += data[i] * data[i];
}
sample_count_ += length;
float rms = sum_square_ / ( sample_count_ ) ;
//rms=sqrt(rms);//开平方
//printf ( "%f\r\n", rms );
rms = 10 * log10 ( rms );
return rms ;
}
这两种出来的数都是分呗,可以看到明显的声音变化。
有一个问题暂时未解决,转换出来的值失真,底噪的值变化大,在普通环境中的分呗和在消音室里的分呗数一样,我不知道是硬件问题还是PDM转PCM时数据有问题。有想研究的铁子一起探讨!!!