基于STM32F103HAL库的声音定位系统
这是一道学校出的电赛题目,要求在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库的声音定位系统相关推荐
- 基于stm32F103HAL库+cubemx+freertos无感无刷电机BLDC控制程序开发
基于stm32F103HAL库+cubemx+freertos无感无刷电机BLDC控制程序开发 最近在做一个舵机控制项目,控制对象为大功率无感无刷电机,网上搜遍了资源,貌似这方面的资源真得十分匮乏.大 ...
- 基于libmad库的MP3解码简析
基于libmad库的MP3解码简析 MAD (libmad)是一个开源的高精度 MPEG 音频解码库,支持 MPEG-1(Layer I, Layer II 和 LayerIII(也就是 MP3). ...
- Linux下基于SDL库贪吃蛇游戏
Linux下基于SDL库贪吃蛇游戏 SDL(Simple DirectMediaLayer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成.SDL提供了数种控制图像.声音.输出入的函数,让开 ...
- c语言curses小游戏,基于curses库实现弹球游戏
在网上找到,某人在基于Linux终端,用curses库实现的弹球游戏.本人曾经也做过五子棋游戏,分在其它文章中分享. /* * 基于curses库弹球游戏,编译gcc xxx.c -lcurses * ...
- 简单解析C++基于Boost库实现命令行
Boost库中默认自带了一个功能强大的命令行参数解析器,以往我都是自己实现参数解析的,今天偶尔发现这个好东西,就来总结一下参数解析的基本用法,该库需要引入program_options.hpp头文件, ...
- python加密库_python基于pyDes库实现des加密的方法
本文实例讲述了python基于pyDes库实现des加密的方法.分享给大家供大家参考,具体如下: 下载及简介地址:https://twhiteman.netfirms.com/des.html 如需要 ...
- 【Python学习系列十九】基于scikit-learn库进行特征选择
场景:特征选择在模型训练前是非常有意义的,实际上就是先期对特征相关性进行分析. 参考:http://blog.csdn.net/fjssharpsword/article/details/735503 ...
- linux 下基于jrtplib库的实时传送实现
linux 下基于jrtplib库的实时传送实现 一.RTP 是进行实时流媒体传输的标准协议和关键技术 实时传输协议(Real-time Transport Protocol,PRT)是在 Inter ...
- ML之nyoka:基于nyoka库利用LGBMClassifier模型实现对iris数据集训练、保存为pmml模型并重新载入pmml模型进而实现推理
ML之nyoka:基于nyoka库利用LGBMClassifier模型实现对iris数据集训练.保存为pmml模型并重新载入pmml模型进而实现推理 目录 基于nyoka库利用LGBMClassifi ...
最新文章
- 一致性 hash 算法( consistent hashing )
- 线性回归之数学:求导公式
- 苹果服务器消息转发,iphone-与APNS服务器进行交互以将推送通知发...
- 用chattr保护文件系统的安全
- MySQL-查询结果缓存
- SVN错误:SVN Working copy XXX is too old
- Zabbix监控Windows客户端设置
- Java 技术篇-java连接并操作数据库实例演示,执行查询、插入、更新和删除操作
- 典型数据中心能耗分析,空调系统选择很重要,想节能可以这样设计
- python实现b树_B树及2-3树的python实现
- C++文件头,命名空间,new和delete,内联函数,引用,函数重载,构造函数和析构函数,深拷贝和浅拷贝,explict,this指针
- 技术分享 | 一条神奇的曲线——贝塞尔曲线在前端的应用
- 从Java到Go面向对象--继承思想.md
- 打docker镜像_使用docker构建自己的镜像
- mysql 用户与数据_MySQL经验9-用户和数据安全
- python不用中间变量交换值_不使用中间变量,交换int型的 a, b两个变量的值。
- PHP获取随机字符串的两种方法
- 我所理解的Cocos2d-x
- ping命令两种返回信息的区别
- python压缩图片 指定大小