【英飞凌PSoC 6 RTT开发板试用】语音识别之二:音频采集
2023-07-11 09:35:03 嵌入式USB开发
一. 音频采集原理图

从原理图看到有6路模拟输入,分别对应

P10.0~P10.5, VREF为模拟参考电压。

使用的是MAX4466的MIC,接到ADC0,如下图所示


(资料图片仅供参考)

配置模拟采集引脚代码

Adc.c

#include "cy_pdl.h"#include "cyhal.h"#include "cybsp.h"#include "cy_retarget_io.h"#define VPLUS_CHANNEL_0  (P10_0)/* Conversion factor */#define MICRO_TO_MILLI_CONV_RATIO        (1000u)/* Acquistion time in nanosecond */#define ACQUISITION_TIME_NS              (116680u)/* ADC Scandelay in millisecond */#define ADC_SCAN_DELAY_MS                (200u)/********************************************************************************       Enumerated Types*******************************************************************************//* ADC Channel constants*/enum ADC_CHANNELS{  CHANNEL_0 = 0,  NUM_CHANNELS} adc_channel;/******************************************************************************** Global Variables*******************************************************************************//* ADC Object */cyhal_adc_t adc_obj;/* ADC Channel 0 Object */cyhal_adc_channel_t adc_chan_0_obj;/* Default ADC configuration */const cyhal_adc_config_t adc_config = {        .continuous_scanning=false, // Continuous Scanning is disabled        .average_count=1,           // Average count disabled        .vref=CYHAL_ADC_REF_VDDA,   // VREF forSingle ended channel set to VDDA        .vneg=CYHAL_ADC_VNEG_VSSA,  // VNEG for Single ended channel set to VSSA        .resolution = 12u,          // 12-bit resolution        .ext_vref = NC,             // No connection        .bypass_pin = NC };       // No connection/* Asynchronous read complete flag, used in Event Handler */staticbool async_read_complete = true;#define NUM_SCAN                    (1000)#define NUM_CHANNELS                (1)/* Variable to store results from multiple channels during asynchronous read*/int32_t result_arr[NUM_CHANNELS * NUM_SCAN] = {0};static void adc_event_handler(void* arg, cyhal_adc_event_t event){    if(0u != (event & CYHAL_ADC_ASYNC_READ_COMPLETE))    {        /* Set async read complete flag to true */        async_read_complete = true;    }}int adc_init(void){    /* Variable to capture return value of functions */    cy_rslt_t result;    /* Initialize ADC. The ADC block which can connect to the channel 0 input pin is selected */    result = cyhal_adc_init(&adc_obj, VPLUS_CHANNEL_0, NULL);    if(result != CY_RSLT_SUCCESS)    {        printf("ADC initialization failed. Error: %ld\\n", (long unsigned int)result);        CY_ASSERT(0);    }    /* ADC channel configuration */    const cyhal_adc_channel_config_t channel_config = {            .enable_averaging = false,  // Disable averaging for channel            .min_acquisition_ns = ACQUISITION_TIME_NS, // Minimum acquisition time set to 1us            .enabled = true };          // Sample this channel when ADC performs a scan    /* Initialize a channel 0 and configure it to scan the channel 0 input pin in single ended mode. */    result  = cyhal_adc_channel_init_diff(&adc_chan_0_obj, &adc_obj, VPLUS_CHANNEL_0,                                          CYHAL_ADC_VNEG, &channel_config);    if(result != CY_RSLT_SUCCESS)    {        printf("ADC first channel initialization failed. Error: %ld\\n", (long unsigned int)result);        CY_ASSERT(0);    }    /* Register a callback to handle asynchronous read completion */     cyhal_adc_register_callback(&adc_obj, &adc_event_handler, result_arr);     /* Subscribe to the async read complete event to process the results */     cyhal_adc_enable_event(&adc_obj, CYHAL_ADC_ASYNC_READ_COMPLETE, CYHAL_ISR_PRIORITY_DEFAULT, true);     printf("ADC is configured in multichannel configuration.\\r\\n\\n");     printf("Channel 0 is configured in single ended mode, connected to the \\r\\n");     printf("channel 0 input pin. Provide input voltage at the channel 0 input pin \\r\\n");     return 0;}int adc_samp(void){    /* Variable to capture return value of functions */    cy_rslt_t result;    /* Variable to store ADC conversion result from channel 0 */    int32_t adc_result_0 = 0;        /* Clear async read complete flag */        async_read_complete = false;        /* Initiate an asynchronous read operation. The event handler will be called         * when it is complete. */        memset(result_arr,0,sizeof(result_arr));        cyhal_gpio_write_internal(CYBSP_USER_LED,true);        result = cyhal_adc_read_async_uv(&adc_obj, NUM_SCAN, result_arr);        if(result != CY_RSLT_SUCCESS)        {            printf("ADC async read failed. Error: %ld\\n", (long unsigned int)result);            CY_ASSERT(0);        }        while(async_read_complete == false);        cyhal_gpio_write_internal(CYBSP_USER_LED,false);        /*         * Read data from result list, input voltage in the result list is in         * microvolts. Convert it millivolts and print input voltage         *         */        for(int i=0; i< NUM_SCAN; i++)        {            adc_result_0 = result_arr[i] / MICRO_TO_MILLI_CONV_RATIO;            printf("/*%4ld*/\\r\\n", (long int)adc_result_0);        }    return 0;}

Adc.h

#ifndef ADC_H#define ADC_Hint adc_init(void);int adc_samp(void);#endif

Main.c调用

adc_init();

adc_samp();

时钟

时钟源是100Mhz,12分频=8.33M,满足1.8MHz~18MHz之间的要求

默认是按照8M配置

采样时间

采样前后翻转LED用示波器测量时间

int adc_samp(void){    /* Variable to capture return value of functions */    cy_rslt_t result;    /* Variable to store ADC conversion result from channel 0 */    int32_t adc_result_0 = 0;        /* Clear async read complete flag */        async_read_complete = false;        /* Initiate an asynchronous read operation. The event handler will be called         * when it is complete. */        memset(result_arr,0,sizeof(result_arr));        cyhal_gpio_write_internal(CYBSP_USER_LED,true);        result = cyhal_adc_read_async_uv(&adc_obj, NUM_SCAN, result_arr);        if(result != CY_RSLT_SUCCESS)        {            printf("ADC async read failed. Error: %ld\\n", (long unsigned int)result);            CY_ASSERT(0);        }        while(async_read_complete == false);        cyhal_gpio_write_internal(CYBSP_USER_LED,false);        /*         * Read data from result list, input voltage in the result list is in         * microvolts. Convert it millivolts and print input voltage         *         */        for(int i=0; i< NUM_SCAN; i++)        {            adc_result_0 = result_arr[i] / MICRO_TO_MILLI_CONV_RATIO;            printf("/*%4ld*/\\r\\n", (long int)adc_result_0);        }    return 0;}

采样1000次,分别设置采样时间为2uS和1uS对比。

#define ACQUISITION_TIME_NS (2000u)

10.28mS

#define ACQUISITION_TIME_NS (1000u)

9.32mS

10.28-9.32=0.96mS 1000次约1mS,1次刚好是1uS。

而1000次除去采样时间其他时间为8.32mS,即一次8.32uS。

因为前面设置了时钟为8.33MHz, 从前面时序一节可以看到,除去采样时间,其他转换时间等需要14个CLK,所以需要14/8.33uS=1.7uS. 剩余的8.32-1.7为数据搬运,软件处理等时间。

采样值正确性

1.545V和示波器采集为1.54V差不多是正确的,这里没有高精度万用表就不对测试精度了,只测试了正确性。

音频采集

一次采集1000次然后串口打印,使用SerialStudio可视化显示

int adc_samp(void){    /* Variable to capture return value of functions */    cy_rslt_t result;    /* Variable to store ADC conversion result from channel 0 */    int32_t adc_result_0 = 0;        /* Clear async read complete flag */        async_read_complete = false;        /* Initiate an asynchronous read operation. The event handler will be called         * when it is complete. */        memset(result_arr,0,sizeof(result_arr));        cyhal_gpio_write_internal(CYBSP_USER_LED,true);        result = cyhal_adc_read_async_uv(&adc_obj, NUM_SCAN, result_arr);        if(result != CY_RSLT_SUCCESS)        {            printf("ADC async read failed. Error: %ld\\n", (long unsigned int)result);            CY_ASSERT(0);        }        while(async_read_complete == false);        cyhal_gpio_write_internal(CYBSP_USER_LED,false);        /*         * Read data from result list, input voltage in the result list is in         * microvolts. Convert it millivolts and print input voltage         *         */        for(int i=0; i< NUM_SCAN; i++)        {            adc_result_0 = result_arr[i] / MICRO_TO_MILLI_CONV_RATIO;            printf("/*%4ld*/\\r\\n", (long int)adc_result_0);        }    return 0;}

串口打印到PC,可视化显示如下

审核编辑:汤梓红

最新新闻: