51 32单片机使用蓝牙测RSSI值定位(包含字符串发送,接收字符串,数据解析发送,中断超时接收等)

首先这是一篇血泪文章,当你看到这篇文章的时候,笔者已经失败了,首先笔者选用了51单片机进行编写,51单片机的一个串口难以进行相应的验证,这是其一;其二,使用AT+CWLAP调回WIFI信息的时候,你会发现字符串的数量过于庞大,验证时间过长;其三RSSI值影响太大了,可以说基本没有精度。下面我会分享我的流程,如果你有幸成功的话,可以在下面留言。同时这篇文章包含字符串的接收和发送等知识,包含中断,超时接收,如何检验帧头帧尾等内容,希望对大家有所帮助。

1,字符串的发送

void SendChar(char Char)//这是发送单个字符的
{
    SBUF=Char;
		while(!TI);
		TI=0;
}

void SendString(char *p)//发送字符串
{
    while(*p!='\0')
    {
			SendChar(*p);
			p++;
    }
}

这个地方笔者不做太多的解释,主要就是利用TI和SBUF,进行单个字符的发送,而字符串的发送则是调用指针的类型然后进行字符串的发送。

2串口的初始化函数(这一部分可以在ISP中进行寻找)

void UsartInit()
{
	SCON=0X50;			//???????1
	TMOD=0X20;			//?????????2
	//PCON=0X80;			//?????
	TH1=0xfd;				//????????,??????9600?
	TL1=0xfd;
	ES=1;						//??????
	EA=1;						//?????
	TR1=1;					//?????
}

不做太多解释

3利用中断进行字符串的接收(本人使用了帧头检验,帧尾检验以及超时接收等)

void Usart() interrupt 4//中断
{
	if(RI)//当检验到数据时
	{
		
		RI = 0;//归0,下次检验
		start_timer = 1;//定时计数器置1
		
		
		temp = SBUF;//这里是定义了一个中间变量,将SBUF的内容传给中间变量,然后对中间变量进行检验
		if(temp != 0x63)//这里本人是用的字符串“c”使用的是16进制,因为单片机接收数据接受的是16进制
		{
			recv_buf[recv_cnt] = temp;//这里讲接收到的一帧放入数组
			recv_cnt++;//recv_cnt进行累加,方便下一次
			if(recv_cnt > MAX_LEN)//当recv_cnt大于规定的最大字符串时,不再进行接收
			{
				recv_cnt = MAX_LEN;
			}
		
		}
		else
		{
			usart_receive_flag = 1;//这是串口接收字符的标志位
			recv_length = 47;//我设置的最大接收区为47(51单片机最多接收128个字符)
			//recv_cnt = 0;
		}
		recv_timer_cnt = 0;//定时器计数归0
	}
}

void Timer0Init(void)		//1??@11.0592MHz
{
	//AUXR &= 0x7F;		//?????12T??
	TMOD &= 0xF0;		//???????
	TL0 = 0x66;		//??????
	TH0 = 0xFC;		//??????
	TF0 = 0;		//??TF0??
	ET0 = 1;
	TR0 = 1;		//???0????
}

void timer0_ISR() interrupt 1
{
	TR0 = 0;
	if(start_timer == 1)
	{
		recv_timer_cnt++;
		if(recv_timer_cnt > MAX_REV_TIME)
		{
			recv_timer_cnt =0;
			recv_cnt = 0;
			usart_receive_flag = 1;
		}
	}
	TL0 = 0x66;		//??????
	TH0 = 0xFC;		//??????
	TR0 = 1;
}

4.清楚数组的数据也就是清除缓存

void clr_recvbuffer(unsigned char *buf)
{
	unsigned char i;
	for(i=0;i<MAX_LEN;i++)
	{
			buf[i] = 0;	
	}		
}	

这里很容易理解,就是利用i来清空每一个数组

5串口中断服务函数

void uart_service(unsigned char *buf)
{
	unsigned char recv_move_index ;//recv_move_index是为了简单,其实这个可以随便定义
	if (usart_receive_flag)//当字符串接收完全后会变为1,然后进入
	{
		usart_receive_flag = 0;//标志位置0
		start_timer = 0;//定时计数器标志位置0
		while((recv_cnt >= 40) && (recv_move_index <= recv_cnt))//recv_cnt为接收的字符串长度
		{
				if(	(buf[recv_move_index+0] == 0X42) && (buf[recv_move_index+1] == 0X31))//这里就是本人的数据位检验,使用的是“B1”采用的是他们的16进制
				{
					a = buf[recv_move_index+5]-48;
					b = buf[recv_move_index+6]-48;
					RSSI1 = a*10+b;
					if(RSSI1 < 40)
					{
							LED=0;
							//SendString("<\r\n");
							//Delay1000ms();
							//SendString("AT+CWLAP\r\n");
							clr_recvbuffer(recv_buf);
					}
					if(RSSI1 >=40)
					{
							LED=1;
							//SendString(">\r\n");
							//Delay1000ms();
						  //SendString("AT+CWLAP\r\n");
							//SendString("AT+RST\r\n");
							
							clr_recvbuffer(recv_buf);//清除数组缓存
							
					}
					
					break;
				}
				recv_move_index++;//这里进行累加是为了进行以后的验证
				
		}		
		recv_cnt = 0;//归0
		//clr_recvbuffer(recv_buf);
	}

}

6关于计算RSSI值

a = buf[recv_move_index+5]-48;//这里是讲字符型数据转化为整数型数据
 b = buf[recv_move_index+6]-48;
 RSSI1 = a*10+b;//计算RSSI值

7关于发送AT+CWLAP的返回内容

注意开头有隐藏的AT+CWLAP指令

AT+CWLAP
+CWLAP:(0,"B1",-32,"ca:c9:a3:78:b6:0b",1,-6,0)
+CWLAP:(4,"feika102",-36,"8c:a6:df:fc:b5:1f",1,30,0)
+CWLAP:(5,"HBU-1X",-79,"d4:61:fe:fd:e7:70",1,-6,0)
+CWLAP:(0,"HBU-WEB",-81,"d4:61:fe:fd:e7:71",1,-4,0)
+CWLAP:(5,"HBU-1X",-66,"d4:61:fe:fe:07:d0",1,-6,0)
+CWLAP:(0,"HBU-WEB",-64,"d4:61:fe:fe:07:d1",1,-6,0)
+CWLAP:(3,"123456789",-40,"66:64:d7:b9:87:eb",5,28,0)
+CWLAP:(4,"ZJBGS",-79,"ec:26:ca:67:ba:89",6,8,0)
+CWLAP:(5,"HBU-1X",-67,"d4:61:fe:fe:0b:90",6,0,0)
+CWLAP:(0,"HBU-WEB",-68,"d4:61:fe:fe:0b:91",6,0,0)
+CWLAP:(5,"HBU-1X",-77,"d4:61:fe:fe:0c:50",1,0,0)
+CWLAP:(4,"kexie203",-40,"5c:02:14:cd:0a:28",11,26,0)
+CWLAP:(0,"HBU-WEB",-77,"d4:61:fe:fe:0c:51",1,0,0)
+CWLAP:(5,"HBU-1X",-85,"d4:61:fe:fe:7b:d0",1,-4,0)
+CWLAP:(0,"HBU-WEB",-85,"d4:61:fe:fe:7b:d1",1,-4,0)
ok

8关于两个蓝牙的设置(一个充当蓝牙一个充当热点)

配置如下:

热点设置
AT+CWSAP?//查询当前AP模式下的参数,返回+CWSAP:,,,;
AT+CWMODE=2设置模式为AP(服务器模式)
AT+CWSAP="B1","aaaaaa",1,0//打开热点设置
AT+CWLIF//查询已经连接的设备ID

蓝牙设置
AT+CWJAP?//查询当前选择的AP,返回+CWJAP:OK
AT+CWMODE=1设置模式为SATION模式
AT+CWJAP="B1","aaaaaa"//连接上述热点
AT+CWLAP//查询连接如下

蓝牙模式
AT+CWMODE=3//两种模式兼顾
AT+CWMODE?//当前模式查询

AT+CIOBAUD=9600//修改为9600波特率

发送所有命令时都需要回车进行换行

9算法(本人也是在CSDN看到的)

算法方面
其中d为距离,单位是m。
RSSI为rssi信号强度,为负数。
A为距离探测设备1m时的rssi值的绝对值,最佳范围在45-49之间。
n为环境衰减因子,需要测试矫正,最佳范围在3.25-4.5之间。

abs()取绝对值
d=10^((ABS(RSSI)-A)/(10*n))

int a = 45
float n = 3.25

RSSI记得取绝对值
距离==10^((abs(RSSI)-A)/(10*n))

使用数学函数记得引用

#include <math.h>

本人全部代码如下  看不懂代码的可以去B站(单片机应用实践篇——单片机串行口定时中断实现超时接收一串数据的编程实现_哔哩哔哩_bilibili)这位老师讲解的很详细还是希望大家能够用心理解

/**************************************************************************************
*		              ??????												  *
????:?????????????,???????9600,???????????????????																			  
***************************************************************************************/
#include "reg52.h"			 //????????????????????
#include "string.h"			//???????
#include <stdio.h>
#include <stdlib.h>
#include <intrins.h>

void clr_recvbuffer(unsigned char *buf);
void uart_service(unsigned char *buf);
void Delay500ms()	;
void Delay2000ms();
void Delay4000ms();
void Delay1000ms();
void Delay5000ms();
void Timer0Init(void);		
sbit LED = P2^6;
#define MAX_LEN 47	  //??????????
#define MAX_REV_TIME 5
unsigned char temp ; 
unsigned char recv_length; 
unsigned char recv_buf[MAX_LEN];
unsigned char recv_cnt;
unsigned char usart_receive_flag = 0;
unsigned char start_timer = 0;
unsigned char recv_timer_cnt;
//unsigned char  RSSI =0;
int a ;
int b ;
int RSSI1 ;

typedef unsigned int u16;	  //???????????
typedef unsigned char u8;

//u8 receiveData[47];			//????,????????//????,????4????????
/*******************************************************************************
* ???         :UsartInit()
* ????		   :????
* ??           : ?
* ??         	 : ?
*******************************************************************************/
void UsartInit()
{
	SCON=0X50;			//???????1
	TMOD=0X20;			//?????????2
	//PCON=0X80;			//?????
	TH1=0xfd;				//????????,??????9600?
	TL1=0xfd;
	ES=1;						//??????
	EA=1;						//?????
	TR1=1;					//?????
}

//??????
void SendChar(char Char)
{
    SBUF=Char;
		while(!TI);
		TI=0;
}

//???????
void SendString(char *p)
{
    while(*p!='\0')
    {
			SendChar(*p);
			p++;
    }
}

/*******************************************************************************
* ? ? ?       : main
* ????		 : ???
* ?    ?       : ?
* ?    ?    	 : ?
*******************************************************************************/
void main()
{	
	LED = 0;
	//SendString("AT+CWLAP\r\n");
	Timer0Init;
	UsartInit();  //	?????
	EA=1;	
	
	//SendString("AT+CWLAP\r\n");
	//SendString("AT+RST\r\n");
	//Delay1000ms();
	while(1)
	{	 
				SendString("AT+CWLAP\r\n");
				Delay4000ms();
			//Delay1000ms();
		  //SendString("AT+CWLAP\r\n");
			uart_service(recv_buf);
		//18   11  12 
			/*if(usart_receive_flag==1 && rxDataBuff[i+7]==','&&rxDataBuff[i]=='B'&&rxDataBuff[i+1]=='1')
		{
			usart_receive_flag=0;	
			rxDataBuff[0]='\0';
			a = rxDataBuff[i+5]-48;
			b = rxDataBuff[i+6]-48;
			RSSI1 = a*10+b;
			SendString("dadawda\r\n");
			
			if(RSSI1 < 100)
			{
				LED = 1;
				SendString("LED=1???\r\n");
		//		usart_receive_flag=0;	
			}
			
			/*if(RSSI1 >= 27)
			{
				LED = 1;
				SendString("LED=0???\r\n");
				
			}*/
		}
}		


/*******************************************************************************
* ???         : Usart() interrupt 4
* ????		  : ????????
* ??           : ?
* ??         	 : ?
*******************************************************************************/
void uart_service(unsigned char *buf)
{
	unsigned char recv_move_index ;
	if (usart_receive_flag)
	{
		usart_receive_flag = 0;
		start_timer = 0;
		while((recv_cnt >= 40) && (recv_move_index <= recv_cnt))
		{
				if(	(buf[recv_move_index+0] == 0X42) && (buf[recv_move_index+1] == 0X31))//A TÑéÖ¤
				{
					a = buf[recv_move_index+5]-48;
					b = buf[recv_move_index+6]-48;
					RSSI1 = a*10+b;
					if(RSSI1 < 40)
					{
							LED=0;
							//SendString("<\r\n");
							//Delay1000ms();
							//SendString("AT+CWLAP\r\n");
							clr_recvbuffer(recv_buf);
					}
					if(RSSI1 >=40)
					{
							LED=1;
							//SendString(">\r\n");
							//Delay1000ms();
						  //SendString("AT+CWLAP\r\n");
							//SendString("AT+RST\r\n");
							
							clr_recvbuffer(recv_buf);
							
					}
					
					break;
				}
				recv_move_index++;
				
		}		
		recv_cnt = 0;
		//clr_recvbuffer(recv_buf);
	}

}

void clr_recvbuffer(unsigned char *buf)
{
	unsigned char i;
	for(i=0;i<MAX_LEN;i++)
	{
			buf[i] = 0;	
	}		
}	

void Timer0Init(void)		//1??@11.0592MHz
{
	//AUXR &= 0x7F;		//?????12T??
	TMOD &= 0xF0;		//???????
	TL0 = 0x66;		//??????
	TH0 = 0xFC;		//??????
	TF0 = 0;		//??TF0??
	ET0 = 1;
	TR0 = 1;		//???0????
}

void timer0_ISR() interrupt 1
{
	TR0 = 0;
	if(start_timer == 1)
	{
		recv_timer_cnt++;
		if(recv_timer_cnt > MAX_REV_TIME)
		{
			recv_timer_cnt =0;
			recv_cnt = 0;
			usart_receive_flag = 1;
		}
	}
	TL0 = 0x66;		//??????
	TH0 = 0xFC;		//??????
	TR0 = 1;
}


void Usart() interrupt 4
{
	if(RI)
	{
		
		RI = 0;
		start_timer = 1;
		
		
		temp = SBUF;
		if(temp != 0x63)//????c
		{
			recv_buf[recv_cnt] = temp;
			recv_cnt++;
			if(recv_cnt > MAX_LEN)
			{
				recv_cnt = MAX_LEN;
			}
		
		}
		else
		{
			usart_receive_flag = 1;
			recv_length = 47;
			//recv_cnt = 0;
		}
		recv_timer_cnt = 0;//
	}
}

void Delay4000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	_nop_();
	i = 169;
	j = 24;
	k = 59;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void Delay5000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	_nop_();
	i = 211;
	j = 30;
	k = 11;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void Delay1000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	_nop_();
	i = 43;
	j = 6;
	k = 203;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}


void Delay2000ms()		//@11.0592MHz
{
	unsigned char i, j, k;
 
	_nop_();
	i = 15;
	j = 2;
	k = 235;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}
void Delay500ms()		//????,??500ms
{
	unsigned char i, j, k;
	i = 4;
	j = 129;
	k = 119;
	do
	{
		do
		{
			while (--k);
		} while (--j);//do while??
	} while (--i);

}

  • 3
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
### 回答1: 蓝牙(RSSI)室内定位是一种基于蓝牙信号强度(RSSI)和距离的室内定位技术,可以在室内环境中实现精确的位置跟踪服务。目前,Android平台提供了许多用于蓝牙定位的API和工具,开发人员可以使用这些工具来实现室内定位功能。 在实现蓝牙(RSSI)室内定位之前,需要先进行站点调查和信号质量试。站点调查可以用于确定信标放置的位置、数量和信号范围等因素。信号质量试可以确定信标的信号强度和覆盖范围,以便更好的设计和优化蓝牙定位系统。 在Android平台中,可以使用BluetoothAdapter API来扫描周围的蓝牙设备,获取设备的RSSI和MAC地址等信息。一旦获取了RSSI,就可以通过算法计算出设备与信标之间的距离和位置信息,并将其显示在用户界面上。具体的算法可以使用基于信号强度指数的方法,例如Path Loss和Trilateration的方法来进行定位计算。 需要注意的是,蓝牙(RSSI)室内定位技术也存在一些挑战和限制。例如,信号强度受环境因素的影响,如环境噪声和干扰等,这可能会导致定位精度不是特别高。此外,室内定位需要多个信标进行多点定位,成本也会相应增加。 总之,在Android开发中,使用蓝牙(RSSI)室内定位技术可以实现室内定位和位置跟踪功能,为商业和社会提供更多可能性。 ### 回答2: 在Android开发中,可以通过蓝牙RSSI(接收信号强度指数)数据实现室内定位RSSI是指接收到的信号强度,通过量不同位置的RSSI,就能够确定设备的位置。 首先需要获取设备的蓝牙信号强度,这可以通过蓝牙扫描获取。然后建立一个基站位置数据库,将不同位置的蓝牙信号强度记录下来。当需要定位时,就可以通过比对当前设备的蓝牙信号强度和基站位置数据库中的信号强度,来确定设备所处的位置。 室内定位的精度受到多种因素影响,比如墙体厚度、金属物体等会影响信号强度。因此在开发中需要进行精细的调试和优化。同时,蓝牙定位也有一些局限性,如需要用户开启蓝牙蓝牙信号强度容易受到干扰等。 总之,蓝牙RSSI室内定位是一种比较成熟的技术,在Android开发中也有较多的应用场景,但仍需要开发者进行精细的调试和优化,来提高室内定位的精度和性能。 ### 回答3: 蓝牙RSSI室内定位,是指通过蓝牙信号强度指示(RSSI)来确定物体或设备在室内的具体位置。这种方法适用于室内定位、追踪和导航等场景,但是有其限制:比如,受到干扰等外部环境因素的影响,精准度往往难以达到预期。 对于Android开发来说,实现蓝牙RSSI室内定位需要使用蓝牙模块,并结合相关的定位算法,如三角定位法、指纹定位法等。一般步骤如下: 1.获取蓝牙设备的RSSI。通过将扫描到的蓝牙设备进行连接,获取其信号强度。 2.建立基站地图。在室内设定多个基站,获取它们的位置信息,并记录其强度。 3.计算物体位置。结合已知的基站位置和它们的强度使用相关算法计算物体位置及其误差范围。 4.优化算法。如增加基站数量、调整基站位置等,提升室内定位精确度。 Android开发中,需要使用一些相关技术包和类库,如蓝牙适配器、手动操作权限等,较为复杂。得注意的是,该技术需要有精确的物理地图、较多的基站数量以及较强的数据处理能力,因此在应用中的实际场景时需要谨慎考虑。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值