这是一道学校出的电赛题目,要求在100*100cm的平面上实现定位实现声音定位。由于一米太大了,我们就做了40cm的,下面的讲解我按照40厘米的写。用到的处理器是stm32f103c8t6接下来分享一下调试心得。
硬件部分需要制作发声装置和接收装置,详细可以参考这个文章.
需要知道的是,扬声器发出的声音经过接收装置,得到的是一个方波信号,所以单片机需要根据这些方波求出距离

解题思路

一.直线

既然我们说,接收模块得到的是方波信号,那么单片机肯定可以检测到方波的下降沿和上升沿,在直线上,声源距离接收模块越近,声音先到达,就先接收到下降沿,相反,声源距离接收模块远,就后接受到下降沿,这样我们可以得到时间差。接下来就是小学数学了(手动狗头),根据两个时间可以算出距离。
用C语言描述就是这样

传入参数:两个下降沿分别到两个接收器之间的时间差
传出参数:距离
float Find_Line(float ltime)
{float S=0,timeall=0,timefst=0;timeall=0.0012;        //单位是秒,根据ltime单位做调整     0.4/346timefst=(timeall+ltime)/2;S=0.4*(timefst/timeall);return S;
}

二.平面

在平面上,就需要三个接收模块,这样就能得出两个时间差。
像下面这幅图

用C语言描述是这样,得到的arv1和arv2就是坐标值,
整个函数就是解方程的思路,用穷举法求出合适的值,我在后面又对得到的值做了求平均处理。

//传入参数:两个时间差
void Find_Square(float ctime1,float ctime2)
{int count,i=0;for(x=0.0; x<=40.0; x++){for(y=0.0; y<=40.0;y++){if(fabs(sqrt(x*x+(y-40)*(y-40))-sqrt(x*x +y*y)-34000*ctime1)<3 && fabs(sqrt(x*x +y*y)-sqrt((40-x)*(40-x)+y*y)-34000*ctime2)<3)  {  a[i]=x;b[i]=y;i++;count =i;printf("x=%.2f  y=%.2f count=%d\n",x,y,count);}  else{printf("方程无解");}}}
//      count=Del_Zero(a,count);
//      Del_Zero(b,count);for(int i=0; i< count; i++){sum1=sum1+a[i];sum2=sum2+b[i];arv1=sum1/count;arv2=sum2/count;printf("a[i]=%.2f  b[i]=%.2f count=%d  %f\n",a[i],b[i],count,sum1);}printf("arv1=%.2f arv2=%.2f\n",arv1,arv2);sum1=0;sum2=0;
}

二.单片机获取时间

其实解题思路不难,难点就在于获取到准确的时间,我使用的获取方法是外部中断,当单片机的一个IO口检测到下降沿,定时器开始计时,另一个IO口检测到下降沿停止计时,这样就得到时间差

1.cubemx配置

1.外部中断


2.定时器
由于晶振是72MHZ,而且接收到下降沿的时间在微秒级别,所以将单位时间设置为100us(72000000/72/100=10000hz)(1/10000=100us)

/*** 函数功能: 按键外部中断回调函数* 输入参数: GPIO_Pin:中断引脚* 返 回 值: 无* 说    明: 无*/
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{if(GPIO_Pin==GPIO_PIN_0)//A{if(time1==0){wosignA=0;HAL_TIM_Base_Start_IT(&htim2); //使能刚刚配置的定时器}else{wosignA=time1+255*time2;//HAL_TIM_Base_Stop_IT(&htim2);}signA=1; }if(GPIO_Pin==GPIO_PIN_1)//B{if(time1==0){wosignB=0;HAL_TIM_Base_Start_IT(&htim2); //使能刚刚配置的定时器}else{wosignB=time1+255*time2;//HAL_TIM_Base_Stop_IT(&htim2);}signB=1;//EXTI->IMR &= ~(GPIO_PIN_1); }if(GPIO_Pin==GPIO_PIN_11)//B{if(time1==0){wosignC=0;HAL_TIM_Base_Start_IT(&htim2); //使能刚刚配置的定时器}else{wosignC=time1+255*time2;//HAL_TIM_Base_Stop_IT(&htim2); //使能刚刚配置的定时器}signC=1;//EXTI->IMR &= ~(GPIO_PIN_1); }}
/*** 函数功能: 定时器中断回调函数* 输入参数: * 返 回 值: 无* 说    明: 无*/
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{if (htim->Instance == htim2.Instance){time1++;   if(time1==255){time2++;time1=0;}//定时器计数255次溢出一次}if (htim->Instance == htim1.Instance){}
}
     key=read_key();if(key==1) {mode=1;OLED_Clear();}if(key==2) {mode=2;OLED_Clear();}if(key==3) {mode=3;OLED_Clear();}if(mode==1){if(signA&&signB){EXTI->IMR &= ~(GPIO_PIN_0);//关闭外部中断EXTI->IMR &= ~(GPIO_PIN_1);HAL_TIM_Base_Stop_IT(&htim2);if(wosignA<wosignB){t1=wosignB;}else  {t1=wosignA;}if(t1>11){t1=11;}s=Find_Line(fabs((float)(t1))*100/1000000);printf("%d   %d    %f   %d   %d  %d %d\n",time1,time2,s,wosignA,wosignB,wosignC,t1);OLED_ShowFloat(0,0,s,2,4,16);HAL_Delay(100);EXTI->IMR |= GPIO_PIN_0; //开启外部中断EXTI->IMR |= GPIO_PIN_1;signA=0;signB=0;time1=0;time2=0;}}
//printf("%d   %d   %d    %d  %d  %d\n",signA,signB,signC,wosignC,wosignA,wosignB);if(mode==2){if(signA&&signB&&signC){EXTI->IMR &= ~(GPIO_PIN_0);EXTI->IMR &= ~(GPIO_PIN_1);EXTI->IMR &= ~(GPIO_PIN_11);HAL_TIM_Base_Stop_IT(&htim2);if((wosignA<wosignB)&&(wosignB<wosignC)){t2=wosignB;t3=wosignC;}if((wosignA<wosignC)&&(wosignB>wosignC)){t2=wosignC;t3=wosignB;}if((wosignB<wosignA)&&(wosignA<wosignC)){t2=wosignA;t3=wosignC;}if((wosignB<wosignC)&&(wosignC<wosignA)){t2=wosignC;t3=wosignA;}if((wosignC<wosignA)&&(wosignA<wosignB)){t2=wosignA;t3=wosignB;}if((wosignC<wosignB)&&(wosignB<wosignA)){t2=wosignB;t3=wosignA;}if(t2>11){t2=11;}if(t3>11){t3=11;}
//                      t2=wosignA-wosignB;
//                      t3=wosignB-wosignC;printf("%d   %d    %f   %d   %d  %d %d %d\n",time1,time2,s,wosignA,wosignB,wosignC,t2,t3);Find_Square((float)t2/10000,(float)t3/10000);OLED_ShowFloat(0,0,arv1,2,4,16);OLED_ShowFloat(0,2,arv2,2,4,16);//HAL_Delay(100);EXTI->IMR |= GPIO_PIN_0; EXTI->IMR |= GPIO_PIN_1;EXTI->IMR |= GPIO_PIN_11;signA=0;signB=0;signC=0;time1=0;time2=0;}}if(mode==3){goto MENU;}}

可以用自己的按键,设置标志位做两个模式,完成持续监测。

成品的误差稍微有些大,不乏温度,湿度,以及硬件误差,和单片机检测误差,没有滤波等等,总的来说,大体方向是对的,我们的作品还能进一步完善。
在调试的时候,单片机PB10引脚接收不到方波信号,拆了板子打电表,查不出问题,结果换了个引脚,好了,,,,,

基于STM32F103HAL库的声音定位系统相关推荐

  1. 基于stm32F103HAL库+cubemx+freertos无感无刷电机BLDC控制程序开发

    基于stm32F103HAL库+cubemx+freertos无感无刷电机BLDC控制程序开发 最近在做一个舵机控制项目,控制对象为大功率无感无刷电机,网上搜遍了资源,貌似这方面的资源真得十分匮乏.大 ...

  2. 基于libmad库的MP3解码简析

    基于libmad库的MP3解码简析  MAD (libmad)是一个开源的高精度 MPEG 音频解码库,支持 MPEG-1(Layer I, Layer II 和 LayerIII(也就是 MP3). ...

  3. Linux下基于SDL库贪吃蛇游戏

    Linux下基于SDL库贪吃蛇游戏   SDL(Simple DirectMediaLayer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成.SDL提供了数种控制图像.声音.输出入的函数,让开 ...

  4. c语言curses小游戏,基于curses库实现弹球游戏

    在网上找到,某人在基于Linux终端,用curses库实现的弹球游戏.本人曾经也做过五子棋游戏,分在其它文章中分享. /* * 基于curses库弹球游戏,编译gcc xxx.c -lcurses * ...

  5. 简单解析C++基于Boost库实现命令行

    Boost库中默认自带了一个功能强大的命令行参数解析器,以往我都是自己实现参数解析的,今天偶尔发现这个好东西,就来总结一下参数解析的基本用法,该库需要引入program_options.hpp头文件, ...

  6. python加密库_python基于pyDes库实现des加密的方法

    本文实例讲述了python基于pyDes库实现des加密的方法.分享给大家供大家参考,具体如下: 下载及简介地址:https://twhiteman.netfirms.com/des.html 如需要 ...

  7. 【Python学习系列十九】基于scikit-learn库进行特征选择

    场景:特征选择在模型训练前是非常有意义的,实际上就是先期对特征相关性进行分析. 参考:http://blog.csdn.net/fjssharpsword/article/details/735503 ...

  8. linux 下基于jrtplib库的实时传送实现

    linux 下基于jrtplib库的实时传送实现 一.RTP 是进行实时流媒体传输的标准协议和关键技术 实时传输协议(Real-time Transport Protocol,PRT)是在 Inter ...

  9. ML之nyoka:基于nyoka库利用LGBMClassifier模型实现对iris数据集训练、保存为pmml模型并重新载入pmml模型进而实现推理

    ML之nyoka:基于nyoka库利用LGBMClassifier模型实现对iris数据集训练.保存为pmml模型并重新载入pmml模型进而实现推理 目录 基于nyoka库利用LGBMClassifi ...

最新文章

  1. 一致性 hash 算法( consistent hashing )
  2. 线性回归之数学:求导公式
  3. 苹果服务器消息转发,iphone-与APNS服务器进行交互以将推送通知发...
  4. 用chattr保护文件系统的安全
  5. MySQL-查询结果缓存
  6. SVN错误:SVN Working copy XXX is too old
  7. Zabbix监控Windows客户端设置
  8. Java 技术篇-java连接并操作数据库实例演示,执行查询、插入、更新和删除操作
  9. 典型数据中心能耗分析,空调系统选择很重要,想节能可以这样设计
  10. python实现b树_B树及2-3树的python实现
  11. C++文件头,命名空间,new和delete,内联函数,引用,函数重载,构造函数和析构函数,深拷贝和浅拷贝,explict,this指针
  12. 技术分享 | 一条神奇的曲线——贝塞尔曲线在前端的应用
  13. 从Java到Go面向对象--继承思想.md
  14. 打docker镜像_使用docker构建自己的镜像
  15. mysql 用户与数据_MySQL经验9-用户和数据安全
  16. python不用中间变量交换值_不使用中间变量,交换int型的 a, b两个变量的值。
  17. PHP获取随机字符串的两种方法
  18. 我所理解的Cocos2d-x
  19. ping命令两种返回信息的区别
  20. python压缩图片 指定大小

热门文章

  1. 香港机房中的BGP线路具有哪些优势
  2. 全部都是好听的DJ嗨曲
  3. rds 主从实例_探索Amazon RDS数据库实例和漏洞
  4. swing标题边框(TitleBorder)
  5. 十个经典Android开源APP项目
  6. GOE:Nintendo Switch™ 对战忍者口香糖动作游戏『Ninjala』首次正式直播中陆续发表最新信息
  7. 京东api接入的几个坑(宙斯) 转载
  8. python--pandas统计分析基础
  9. Optitrack定位系统搭建(仅交换机,无需路由)
  10. 就读体验丨香港科技大学工学院科技领导及创业(TLE)理学硕士学位课程(上)