大二暑假的時候做了一次聲音定位項目,做成了一個聲音導向儀,在德州儀器的TI單片機上實現,運用了廣義互相關的算法,簡單地尋找了四個方向的角度,并用控制舵機來旋轉。
紀念一下。
制作出來的實物圖如下:
IMG_1622(20210102-221323).JPG (2.63 MB, 下載次數: 58)
下載附件
2021-4-12 16:30 上傳
使用的M4核tm4c1294ncpdt芯片
單片機源程序如下:
- #include <stdbool.h>
- #include <stdlib.h>
- #include <stdint.h>
- #include <string.h>
- #include "inc/hw_memmap.h"
- #include "inc/hw_types.h"
- #include "inc/hw_gpio.h"
- #include "inc/tm4c1294ncpdt.h"
- #include "inc/hw_epi.h"
- //#include "inc/hw_ints.h" //和"inc/tm4c1294ncpdt.h"里面的宏定義重復了
- #include "driverlib/epi.h"
- #include "driverlib/gpio.h"
- #include "driverlib/sysctl.h"
- #include "driverlib/rom.h"
- #include "driverlib/rom_map.h"
- #include "driverlib/pin_map.h"
- #include "driverlib/pwm.h"
- #include "driverlib/systick.h"
- #include "driverlib/interrupt.h"
- #include "driverlib/ssi.h"
- #include "driverlib/fpu.h"
- #include "driverlib/adc.h"
- #include "utils/uartstdio.h"
- #include "TFTinit/TFT_400x240_OTM4001A_16bit.h"
- //#include "TFTinit/picture.h"
- #include "TOUCHinit/TOUCH_TSC2046.h"
- #include "EPIinit/EPIinit.h"
- //Todo
- #include "math.h"
- #include "driverlib/timer.h"
- #include "utils/uartstdio.h"
- //Todo
- /*項目分類*/
- typedef enum{
- noun,//空
- return_main,//返回
- pj1,//顯示時鐘
- pj2,//音樂播放器
- pj3,//聲音定位
- wrong,//錯誤選擇,
- } Project;
- /*自定義變量*/
- //Todo
- #define _NOP() _nop()
- #define SLAVE_ADDRESS_W 0x3A //寫ADXL345L時的從機地址
- #define SLAVE_ADDRESS_R 0x3B //讀ADXL345L時的從機地址
- double tem,tem_tmp;//溫度(*100)
- Project choose_pj = noun;
- volatile uint32_t show_flag=0;//是否顯示了時鐘
- volatile uint32_t start_flag=0;//是否進入主頁
- volatile uint32_t musicplay_once=0,musicplay_rotate=0;//單次演奏和循環演奏
- volatile uint32_t time = 0,time1=0,time2=0;;//時間
- volatile uint32_t mg[3]={0x00,0x00,0x00};
- volatile uint32_t touch_cnt=0;
- #define touch_cnt_max 5
- uint32_t page=1;
- uint32_t array_num;
- //*****************************************************************************
- //
- // System clock rate in Hz.
- //
- //*****************************************************************************
- uint32_t g_ui32SysClock;
- extern uint32_t GetData[21];
- uint32_t TouchXData[21];
- uint32_t TouchYData[21];
- //Todo
- /*舵機初始化*/
- void ServoInit()//對所有PWM generator進行初始化
- {
- SysCtlPeripheralEnable(SYSCTL_PERIPH_PWM0);//PWM0模塊使能
- SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOF);//GPIOF模塊使能
- GPIOPinConfigure(GPIO_PF1_M0PWM1);//設置引腳復用功能為PWM
- // GPIOPinConfigure(GPIO_PK4_M0PWM6);
- // GPIOPinConfigure(GPIO_PK5_M0PWM7);
- GPIOPinTypePWM(GPIO_PORTF_BASE, GPIO_PIN_1);//配置相應引腳用于PWM功能
- // GPIOPinTypePWM(GPIO_PORTK_BASE, GPIO_PIN_4);//外擴引腳
- // GPIOPinTypePWM(GPIO_PORTK_BASE, GPIO_PIN_5);
- PWMGenConfigure(PWM0_BASE, PWM_GEN_0, PWM_GEN_MODE_DOWN |PWM_GEN_MODE_NO_SYNC);//配置PWM發生器為減計數、立即更新方式
- PWMGenConfigure(PWM0_BASE, PWM_GEN_1, PWM_GEN_MODE_DOWN | PWM_GEN_MODE_NO_SYNC);
- // PWMGenConfigure(PWM0_BASE, PWM_GEN_2, PWM_GEN_MODE_DOWN | PWM_GEN_MODE_NO_SYNC);
- // PWMGenConfigure(PWM0_BASE, PWM_GEN_3, PWM_GEN_MODE_DOWN | PWM_GEN_MODE_NO_SYNC);
- PWMGenPeriodSet(PWM0_BASE, PWM_GEN_0, 60000);//配置PWM工作頻率為120MHz/8/120000=125Hz
- // PWMGenPeriodSet(PWM0_BASE, PWM_GEN_1, 120000);
- // PWMGenPeriodSet(PWM0_BASE, PWM_GEN_2, 50000);
- // PWMGenPeriodSet(PWM0_BASE, PWM_GEN_3, 50000);
- PWM0_CC_R = PWM_CC_USEPWM | PWM_CC_PWMDIV_8;
- PWMOutputState( PWM0_BASE, PWM_OUT_1_BIT, true);
- //PWMOutputState(PWM0_BASE, PWM_OUT_1_BIT | PWM_OUT_2_BIT | PWM_OUT_3_BIT, true);//使能PWM輸出信號
- //PWMOutputState(PWM0_BASE, PWM_OUT_4_BIT | PWM_OUT_5_BIT | PWM_OUT_6_BIT, true);//使能PWM輸出信號
- PWMGenEnable(PWM0_BASE, PWM_GEN_0);//使能相應PWN發生器模塊
- // PWMGenEnable(PWM0_BASE, PWM_GEN_1);
- // PWMGenEnable(PWM0_BASE, PWM_GEN_2);
- // PWMGenEnable(PWM0_BASE, PWM_GEN_3);
- }
- //Todo
- //聲音定位
- /** * adc采集數據長度 */
- #define ADC_DATA_LEN 2048
- /* * adc采集完成標志位 */
- volatile uint8_t AdcFinishFlag = 0;
- /* * adc雙buff緩沖區 緩沖完成的區域序號 */
- volatile uint8_t AdcBuffIndex = 0;
- /** adc數組下標 */
- volatile uint32_t adcCount = 0;
- /* * ADC數據 adc0 1 2 3 采集麥克風信號
- *
- * 2 1
- *
- * 3 0 */
- __attribute__ ((aligned(256))) volatile int16_t g_adc0Data[2][ADC_DATA_LEN];
- __attribute__ ((aligned(256))) volatile int16_t g_adc1Data[2][ADC_DATA_LEN];
- __attribute__ ((aligned(256))) volatile int16_t g_adc2Data[2][ADC_DATA_LEN];
- //__attribute__ ((aligned(256))) volatile int16_t g_adc3Data[2][ADC_DATA_LEN];
- /* * 互相關結果 */
- float g_acor1[2][30];
- float g_acor2[2][30];
- //float g_acor3[2][30];
- //float g_acor4[2][30];
- /* * 聲音角度 */
- float g_Angle = 0;
- /* * ADC數據 adc0 1 2 3 采集麥克風信號
- *
- * 2 1
- *
- * 3 0
- *
- * PD2 PB5
- *
- * (PK1) PB4
- * */
- //引腳對應通道、通道連接采樣序列、采樣序列使能
- void VoiceInit(void)
- {
- // 初始化ADC0/ 初始化PB4、PB5為TypeADC
- SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC0);
- SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOB);
- GPIOPinTypeADC(GPIO_PORTB_BASE, GPIO_PIN_4);
- GPIOPinTypeADC(GPIO_PORTB_BASE, GPIO_PIN_5);
- // 初始化ADC1/ 初始化PK0、PK1TypeADC
- SysCtlPeripheralEnable(SYSCTL_PERIPH_ADC1);
- SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOD);
- GPIOPinTypeADC(GPIO_PORTD_BASE, GPIO_PIN_2);
- // GPIOPinTypeADC(GPIO_PORTK_BASE, GPIO_PIN_1);
- // 配置ADC0的采集序列2給PB4 //配置ADC0采樣序列2的步驟0,PB4的模擬通道是AIN10(ADC_CTL_CH10)
- ADCSequenceConfigure(ADC0_BASE, 2, ADC_TRIGGER_PROCESSOR, 0);
- ADCSequenceStepConfigure(ADC0_BASE, 2, 0, ADC_CTL_CH10 | ADC_CTL_END | ADC_CTL_IE);
- //配置ADC0的采集序列1給PB5 //配置ADC0采樣序列1的步驟0,PB5的模擬通道是AIN11(ADC_CTL_CH11)
- ADCSequenceConfigure(ADC0_BASE, 1, ADC_TRIGGER_PROCESSOR, 0);
- ADCSequenceStepConfigure(ADC0_BASE, 1, 0, ADC_CTL_CH11 | ADC_CTL_END | ADC_CTL_IE);
- //
- // // 配置ADC1的采集序列2給PD2 //配置ADC1采樣序列2的步驟0,PK0的模擬通道是AIN13(ADC_CTL_CH13)
- ADCSequenceConfigure(ADC1_BASE, 0, ADC_TRIGGER_PROCESSOR, 0);
- ADCSequenceStepConfigure(ADC1_BASE, 0, 0, ADC_CTL_CH13 | ADC_CTL_END | ADC_CTL_IE);
- // //配置ADC0的采集序列1給PK1 //配置ADC1的采樣序列1的步驟0,PK1的模擬通道是AIN17(ADC_CTL_CH17)
- // ADCSequenceConfigure(ADC1_BASE, 1, ADC_TRIGGER_PROCESSOR, 0);
- // ADCSequenceStepConfigure(ADC1_BASE, 1, 0, ADC_CTL_CH17 | ADC_CTL_END | ADC_CTL_IE);
- // 使能ADC采集序列 //清中斷
- ADCSequenceEnable(ADC0_BASE, 2);
- ADCSequenceEnable(ADC0_BASE, 1);
- ADCSequenceEnable(ADC1_BASE, 0);
- // ADCSequenceEnable(ADC1_BASE, 1);
- ADCIntClear(ADC0_BASE, 2);
- ADCIntClear(ADC0_BASE, 1);
- ADCIntClear(ADC1_BASE, 0);
- // ADCIntClear(ADC1_BASE, 1);
- // CCU6_InitConfig(CCU60, CCU6_Channel0, 100); //100us進入一次中斷 中斷中采集adc數據
- }
- /*! * @brief 采集中斷服務函數 聲音信號采集 * @date 2020/4/28 */
- void VoiceGetSample(void)
- {
- static uint8_t adcIndex = 0;
- if(adcCount >= ADC_DATA_LEN)
- {
- adcCount = 0;
- AdcFinishFlag = 1;
- /* 切換buff緩沖區 */
- if(adcIndex == 0)
- {
- adcIndex = 1;
- AdcBuffIndex = 0;
- }
- else
- {
- adcIndex = 0;
- AdcBuffIndex = 1;
- }
- }
- // 觸發采集
- ADCProcessorTrigger(ADC0_BASE, 2);
- ADCProcessorTrigger(ADC0_BASE, 1);
- ADCProcessorTrigger(ADC1_BASE, 0);
- // ADCProcessorTrigger(ADC1_BASE, 1);
- // 等待采集結束 // 獲取采集結果
- while(!ADCIntStatus(ADC0_BASE, 2, false)) ;
- ADCSequenceDataGet(ADC0_BASE, 2, &g_adc0Data[adcIndex][adcCount]);
- while(!ADCIntStatus(ADC0_BASE, 1, false)) ;
- ADCSequenceDataGet(ADC0_BASE, 1, &g_adc1Data[adcIndex][adcCount]);
- while(!ADCIntStatus(ADC1_BASE, 0, false)) ;
- ADCSequenceDataGet(ADC1_BASE, 0, &g_adc2Data[adcIndex][adcCount]);
- //
- // while(!ADCIntStatus(ADC1_BASE, 1, false)) ;
- // ADCSequenceDataGet(ADC1_BASE, 1, &g_adc3Data[adcIndex][adcCount]);
- adcCount++;
- }
- /*!
- * @brief 歸一化處理
- *
- * @param x : 要處理數據
- * @param len : 要處理數據長度
- * @date 2020/4/28
- */
- void Normal(int16_t *x, uint16_t len)
- {
- float sum = 0;
- int i;
- for(i = 0; i < len; i++)
- {
- sum += x[i];
- }
- sum = sum / len;
- for(i = 0; i < len; i++)
- {
- x[i] -= sum;
- }
- }
- /*!
- * @brief 互相關
- *
- * @param acor1: y0 y1 互相關結果
- * @param acor2: y1 y2互相關結果
- * @param acor3: y0 y2互相關結果
- * @param acor4: y1 y3互相關結果
- * @param y0 : 互相關數據 y0
- * @param y1 : 互相關數據 y1
- * @param y2 : 互相關數據 y2
- * @param y3 : 互相關數據 y3
- * @param len : 互相關數據長度
- * @date 2020/4/28
- */
- //void Xcorr(float *acor1, float *acor2, float *acor3, float *acor4, int16_t *y0, int16_t *y1, int16_t *y2, int16_t *y3, uint16_t len)
- void Xcorr(float *acor1, float *acor2, int16_t *y0, int16_t *y1, int16_t *y2, uint16_t len)
- {
- // float sum3 = 0;
- // float sum4 = 0;
- float sum1 = 0;
- float sum2 = 0;
- int delay, i, j;
- for(delay = -15; delay < 15; delay++) //30個互相關的值
- // for(delay = -len + 1; delay < len; delay++) //len個互相關的值
- {
- sum1 = 0;
- sum2 = 0;
- // sum3 = 0;
- // sum4 = 0;
- for(i = 0; i < len; i++)
- {
- j = i + delay;
- if((j < 0))
- {
- sum1 += 0.0001f * y0[j + len] * y1[i]; //縮小一定倍數,防止溢出
- sum2 += 0.0001f * y1[j + len] * y2[i];
- // sum3 += 0.0001f * y0[j + len] * y2[i];
- // sum4 += 0.0001f * y1[j + len] * y3[i];
- }
- else if ((j >= len))
- {
- sum1 += 0.0001f * y0[j - len] * y1[i];
- sum2 += 0.0001f * y1[j - len] * y2[i];
- // sum3 += 0.0001f * y0[j - len] * y2[i];
- // sum4 += 0.0001f * y1[j - len] * y3[i];
- }
- else
- {
- sum1 += 0.0001f * y0[j] * y1[i];
- sum2 += 0.0001f * y1[j] * y2[i];
- // sum3 += 0.0001f * y0[j] * y2[i];
- // sum4 += 0.0001f * y1[j] * y3[i];
- }
- }
- acor1[15 + delay] = (float)sum1;
- acor2[15 + delay] = (float)sum2;
- // acor3[15 + delay] = (float)sum3;
- // acor4[15 + delay] = (float)sum4;
- }
- }
- /*!
- * @brief 得到最大相關位置
- *
- * @param acor1: 互相關結果
- * @param acor2: 互相關結果
- * @param acor3: 互相關結果
- * @param acor4: 互相關結果
- * @param len : 數據長度 (與delay 對應)
- * @param index: 存放相關結果最大值下標
- * @date 2020/4/28
- */
- void SeekMaxAcor(float * acor1, float * acor2, int16_t len, int16_t *index)
- {
- int16_t i = 0;
- index[0] = 0;
- index[1] = 0;
- // index[2] = 0;
- // index[3] = 0;
- for(i = 1; i < len; i++)
- {
- if(acor1[i] > acor1[index[0]])
- {
- index[0] = i;
- }
- if(acor2[i] > acor2[index[1]])
- {
- index[1] = i;
- }
- // if(acor3[i] > acor3[index[2]])
- // {
- // index[2] = i;
- // }
- // if(acor4[i] > acor4[index[3]])
- // {
- // index[3] = i;
- // }
- }
- index[0] = len/2 - index[0]; //下標結果變成負數的關鍵!
- index[1] = len/2 - index[1];
- // index[2] = len/2 - index[2];
- // index[3] = len/2 - index[3];
- }
- /*!
- * @brief 麥克風數據處理 獲取角度信息
- *
- * @param 無
- *
- * @return 最大相關位置
- *
- * @note 無
- *
- * @see
- *
- * @date 2020/4/28
- */
- void VoiceProcess(void)
- {
- // if(AdcFinishFlag)
- // {
- // /* 數據處理 */
- // Normal((int16_t *)g_adc0Data[AdcBuffIndex], ADC_DATA_LEN);
- // Normal((int16_t *)g_adc1Data[AdcBuffIndex], ADC_DATA_LEN);
- // Normal((int16_t *)g_adc2Data[AdcBuffIndex], ADC_DATA_LEN);
- // Normal((int16_t *)g_adc3Data[AdcBuffIndex], ADC_DATA_LEN);
- //
- // for(int i = 0; i < ADC_DATA_LEN; i ++)
- // {
- // /* 上報匿名上位機 看原始數據波形 */
- // ANO_DT_send_int16(g_adc0Data[AdcBuffIndex][i], g_adc1Data[AdcBuffIndex][i], g_adc2Data[AdcBuffIndex][i], g_adc3Data[AdcBuffIndex][i], 0, 0, 0, 0);
- // }
- //
- // AdcFinishFlag = 0;
- // }
- if(AdcFinishFlag)
- {
- //存放相關峰值下標
- int16_t acorIndex[4];
- // 記錄時間
- // uint32_t nowTime = STM_GetNowUs(STM0);
- // 數據處理
- Normal((int16_t *)g_adc0Data[AdcBuffIndex], ADC_DATA_LEN);
- Normal((int16_t *)g_adc1Data[AdcBuffIndex], ADC_DATA_LEN);
- Normal((int16_t *)g_adc2Data[AdcBuffIndex], ADC_DATA_LEN);
- // Normal((int16_t *)g_adc3Data[AdcBuffIndex], ADC_DATA_LEN);
- // 互相關
- Xcorr((float *)&g_acor1[AdcBuffIndex], (float *)&g_acor2[AdcBuffIndex], (int16_t *)&g_adc0Data[AdcBuffIndex], (int16_t *)&g_adc1Data[AdcBuffIndex], (int16_t *)&g_adc2Data[AdcBuffIndex], ADC_DATA_LEN);
- // g_acor1: 麥克風0 麥克風1 互相關結果
- // g_acor2: 麥克風1 麥克風2 互相關結果
- // 獲取最大相關峰值
- SeekMaxAcor((float *)&g_acor1[AdcBuffIndex], (float *)&g_acor2[AdcBuffIndex], 30, acorIndex);
- //acorIndex[0]存放g_acor1峰值的下標
- //acorIndex[1]存放g_acor1峰值的下標
- //acorIndex[2]存放g_acor1峰值的下標
- //acorIndex[3]存放g_acor1峰值的下標
- // pidVoice_error=acorIndex[1];//下標偏差
- // 四組相關數據 最大最小結果下標
- uint8_t IndexMax = 0, IndexMin = 0;
- //找到絕對值最小和最大的值下標
- uint8_t i = 0;
- for(i = 1; i < 2; i++)
- {
- if(abs(acorIndex[i]) >= abs(acorIndex[IndexMax])) //絕對值最小
- {
- IndexMax = i;
- }
- if(abs(acorIndex[i]) <= abs(acorIndex[IndexMin]))
- {
- IndexMin = i;
- }
- }
- // 判斷大致方位
- if(IndexMin == 0)
- {
- if(acorIndex[1] > 0)
- {g_Angle = 0;}
- else
- {g_Angle = 180;}
- }
- else if(IndexMin == 1)
- {
- if(acorIndex[0] > 0)
- {g_Angle = 270 ;}
- else
- {g_Angle = 90;}
- }
- // else if(IndexMin == 2)
- // {
- // if(acorIndex[3] > 0)
- // {g_Angle = 45;}
- // else
- // {g_Angle =225;}
- // }
- //
- // else if(IndexMin == 3)
- // {
- // if(acorIndex[2] > 0)
- // {g_Angle =315;}
- // else
- // {g_Angle=135;}
- // }
- // nowTime = STM_GetNowUs(STM0) - nowTime;
- // VoiceCalculatorTime=nowTime;
- // TFTLCD_ShowData(138,90,(int)g_Angle,WHITE,BLACK);//
- AdcFinishFlag = 0;
- }
- }
- /****用于聲音采集,0.1ms一次****/
- void Timer2BIntHandler()
- {
- unsigned long Status;
- TimerDisable(TIMER2_BASE, TIMER_B);
- Status=TimerIntStatus(TIMER2_BASE,true);
- if(Status==TIMER_TIMB_TIMEOUT)
- {
- VoiceGetSample();
- }
- TimerIntClear(TIMER2_BASE, Status);//計時清零
- TimerLoadSet(TIMER2_BASE, TIMER_B, 0.1*g_ui32SysClock/1000);//控制計時器的計時長度100us,0.1ms
- TimerEnable(TIMER2_BASE, TIMER_B);//定時器使能
- }
- void Timer3BIntHandler()
- {
- unsigned long Status;
- TimerDisable(TIMER3_BASE, TIMER_B);
- Status=TimerIntStatus(TIMER3_BASE,true);
- if(Status==TIMER_TIMB_TIMEOUT)
- {
- if(g_Angle==0)
- {
- PWMPulseWidthSet(PWM0_BASE, PWM_OUT_1,7500);
- PWMPulseWidthSet(PWM0_BASE, PWM_OUT_1,36500);
- ……………………
- …………限于本文篇幅 余下代碼請從51黑下載附件…………
復制代碼
51hei.png (6.27 KB, 下載次數: 68)
下載附件
2021-4-13 05:25 上傳
所有代碼51hei提供下載:
Final最終版本工程.rar
(334.72 KB, 下載次數: 36)
2021-4-12 16:28 上傳
點擊文件名下載附件
聲音定位源碼 下載積分: 黑幣 -5
|