大二暑假的时候做了一次声音定位项目,做成了一个声音导向仪,在德州仪器的TI单片机上实现,运用了广义互相关的算法,简单地寻找了四个方向的角度,并用控制舵机来旋转。
纪念一下。
制作出来的实物图如下:
使用的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提供下载:
Final最终版本工程.rar
(334.72 KB, 下载次数: 35)
|