实物图

先来给大家看看我们优秀队友建的手持设备实物图的3D模型吧

1  

 中间那块是大的LCD显示屏,旁边4个按键是我们调参用的,伸出来长长的触手一样的东西是用来测试身高的啦,具体的测试方法以及测试原理都在下面哦,别走开~精彩在后面哦!(部分程序参考网络资源,如有侵权请评论,马上删除)  

MPU6050

本系统采用MPU6050六轴陀螺仪传感器,手持子系统的主控开发板STM32F407通过该传感器获得手持设备转动时对应于三维空间的x,y,z轴的姿态角,主要应用于手持子系统在水平位置和头部位置的校准。具体流程就是首先将手持子系统放置于水平面进行标定,让陀螺仪获得2个姿态角的标定参数,因为2条直线确定一个平面,因此在平面上标定了2个角度之后,就相当于标定了水平面。然后再放到用户的头顶上将手持子系统放置于头部轻微旋转,通过比较即可判定手持子系统达到水平面的标定位置。 MPU6050是用IIC驱动的,IIC驱动的特点就是可以有多个从机,然后我们就是用IIC来驱动MPU6050的。  

u8 MPU_Init(void)
{
	u8 res;
	IIC_Init();//初始化IIC总线
	MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X80);	//复位MPU6050
        delay_ms(100);
	MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X00);	//唤醒MPU6050
	MPU_Set_Gyro_Fsr(3);					//陀螺仪传感器,±2000dps
	MPU_Set_Accel_Fsr(0);					//加速度传感器,±2g
	MPU_Set_Rate(1000);						//设置采样率50Hz
	MPU_Write_Byte(MPU_INT_EN_REG,0X00);	//关闭所有中断
	MPU_Write_Byte(MPU_USER_CTRL_REG,0X00);	//I2C主模式关闭
	MPU_Write_Byte(MPU_FIFO_EN_REG,0X00);	//关闭FIFO
	MPU_Write_Byte(MPU_INTBP_CFG_REG,0X80);	//INT引脚低电平有效
	res=MPU_Read_Byte(MPU_DEVICE_ID_REG);
	if(res==MPU_ADDR)//器件ID正确
	{
		MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X01);	//设置CLKSEL,PLL X轴为参考
		MPU_Write_Byte(MPU_PWR_MGMT2_REG,0X00);	//加速度与陀螺仪都工作
		MPU_Set_Rate(1000);						//设置采样率为1000Hz
	}else return 1;
	return 0;
}

我是用标准库进行开发的,所以在MPU6050里面的IIC_Init();用的是标准库的IIC协议。上面的一些程序是对MPU6050的一些唤醒操作,MPU_Set_Rate(1000);是设置采样频率的,频率越高采集的数据的速度也快。 MPU6050的原始数据变化的时候是没有姿态角记录的,只有变化量,所以要结算出来MPU6050的姿态角需要第三方库,我用的是DMP的库。这个库可以用这个mpu_dmp_get_data(&pitch,&roll,&yaw)来获得三个轴的姿态角,然后先在水平面上进行标定2个水平姿态角的大小,就相当于标定了水平面,再放到用户头上的时候就可以找到过用户头顶,和水平面平行的平面,此时再测量手持设备到地的距离其实就等于用户的身高了。  


HC-SR04超声波传感器

当手持子系统再用户头顶标定到水平面,按下STM32F407的外设按键之后,通过伸出头部的HC-SR04超声波传感器测量传感器到地面的距离,即可测出用户的身高。 贴一段超声波测距的代码  

if(TIM5CH1_CAPTURE_STA&0X80)//成功捕获到了一次高电平
{
	tmp=TIM5CH1_CAPTURE_STA&0X3F;
	tmp*=0XFFFFFFFF;		 		//溢出时间总和
	tmp+=TIM5CH1_CAPTURE_VAL;		//得到总的高电平时间
	UltrasonicWave_Distance=tmp*340/2/1000;//计算距离,毫米
	Distance_Temp=(double)UltrasonicWave_Distance;
	Distance_Temp = Distance_Temp/10 + 3;
	TIM5CH1_CAPTURE_STA=0;			//开启下一次捕获
}

STM32F407先开一个1us的定时中断,如果需要开始测距的话需要控制引脚(trig)先给一个不少于10us的高电平脉冲信号,同时拉高模块的信号引脚(echo)电平,使其成为一个高电平,然后模块会发出超声波,当模块接收到反射回来的超声波时,其echo引脚信号会变为低电平,此时由定时器计算出echo引脚高电平持续的时间就可以计算出超声波从发射到反射回来经过的时间啦,测距信号代码和1us中断回调代码如下  

void Ultrasonic_StartMeasure(void)
{
	Trig=1;
	delay_us(15);
	Trig=0;
}
void TIM5_IRQHandler(void)
{ 		    
	u16 tsr;
	tsr=TIM5->SR;
 	if((TIM5CH1_CAPTURE_STA&0X80)==0)//还未成功捕获	
	{
		if(tsr&0X01)//溢出
		{	     
			if(TIM5CH1_CAPTURE_STA&0X40)//已经捕获到高电平了
			{
				if((TIM5CH1_CAPTURE_STA&0X3F)==0X3F)//高电平太长了
				{
					TIM5CH1_CAPTURE_STA|=0X80;		//标记成功捕获了一次
					TIM5CH1_CAPTURE_VAL=0XFFFFFFFF;
				}else TIM5CH1_CAPTURE_STA++;
			}	 
		}
		if(tsr&0x02)//捕获1发生捕获事件
		{	
			if(TIM5CH1_CAPTURE_STA&0X40)		//捕获到一个下降沿 		
			{	  			
				TIM5CH1_CAPTURE_STA|=0X80;		//标记成功捕获到一次高电平脉宽
			    TIM5CH1_CAPTURE_VAL=TIM5->CCR1;	//获取当前的捕获值.
	 			TIM5->CCER&=~(1<<1);			//CC1P=0 设置为上升沿捕获
			}else  								//还未开始,第一次捕获上升沿
			{
				TIM5CH1_CAPTURE_STA=0;			//清空
				TIM5CH1_CAPTURE_VAL=0;
				TIM5CH1_CAPTURE_STA|=0X40;		//标记捕获到了上升沿
				TIM5->CR1&=~(1<<0)		;    	//使能定时器2
	 			TIM5->CNT=0;					//计数器清空
	 			TIM5->CCER|=1<<1; 				//CC1P=1 设置为下降沿捕获
				TIM5->CR1|=0x01;    			//使能定时器2
			}		    
		}			     	    					   
 	}
	TIM5->SR=0;//清除中断标志位   
}

再根据声速就可以计算出来距离啦:计算公式如下:

UltrasonicWave_Distance=tmp*340(声速)/2/1000;

除以1000就是为了把单位转换成毫米而已。 当传感器在用户头上时,超声波传感器朝下的话就可以测试出来用户的身高啦。


测试流程

2  

这个手持模块放到用户头上之后呢,按下按键进入身高测量模式,稍微旋转一下啊(找到过头顶和水平面平行的位置),再按一下相同的按键,就会退出身高测量模式,身高就会显示在LCD上啦~是不是很简单=.= 按键操作的代码贴在最后啦  

                key=KEY_Scan(0);
		if(key != 0){//按一下蜂鸣器响一下
			GPIO_SetBits(GPIOF,GPIO_Pin_8);
			delay_ms(30);
		}else{
			GPIO_ResetBits(GPIOF,GPIO_Pin_8);
		}
		
		if(key==KEY1_PRES){
			part++;
			if(part == 4){
				part = 0;
			}
		}
		switch(key)//不同按键的不同功能
		{
			case KEY2_PRES://左
				if(last_part == 0){

				}else if(last_part == 1){
					id--;
				}else if(last_part == 2){
	//				catch_enable = 1;
				}else if(last_part == 3){
					height = 0;
				}
				break;
			case KEY0_PRES://右
				if(last_part == 0){
					if(!write_enable)
						write_enable = 1;
					else
						write_enable = 0;
					if(write_enable == 1){
						printf("E:%hhx\r\n",write_enable);
						//if(write_enable == 1)
						write_enable = 0;
					}
				}else if(last_part == 1){
					id++;
				}else if(last_part == 2){
					if(!catch_enable)
						catch_enable = 1;
					else
						catch_enable = 0;
				}else if(last_part == 3){
					if(!get_height_enable)
						get_height_enable = 1;
					else
						get_height_enable = 0;
				}
				break;
		}

		switch(part)
		{
			case 0:
			//write_enable
				//LCD_ShowString(80,410,96,16,24,"write_enable");
				Show_Str(198,410,96,24,"写入状态",24,0);
				last_part = part;
				break;
			case 1://id
				//LCD_ShowString(80,410,16,16,24,"id");
				Show_Str(198,410,96,24,"ID        ",24,0);
				last_part = part;
				break;
			case 2://catch_enable
				//LCD_ShowString(80,410,96,16,24,"catch_enable");
				Show_Str(198,410,96,24,"获取状态",24,0);
				last_part = part;
				break;
			case 3://get_height_enable
				//LCD_ShowString(80,410,255,16,24,"get_height_enable");
				Show_Str(198,410,96,24,"高度状态",24,0);
				last_part = part;
				break;

		}

		if(get_height_enable){
			//过头顶的平面标定之后进行身高变量赋值
		}else{
			//height = 0;
		} 

                                               (づ ̄3 ̄)づ╭❤~一键三连,这次一定(๑•̀ㅂ•́)و✧

QQ图片20210126200222