资讯详情

基于stm32的车辆减速灯项目——MPU6050或ADXL345

本实验例程采用,模拟车辆减速时的模拟,以此起到。(我也采用过ADXL345实现项目源码程序,文章结尾

基于stm32车辆减速灯项目有很多学校作为期末考核或毕业项目,整体比较简单。主要用途MPU6050亦或是ADXL345等姿态测量传感器测量,利用获得的数据来判断条件。满足预设条件后,LED灯按要求呼吸闪烁(有些朋友可能会,但我觉得PWM呼吸效果不起作用。故应该采用)。

STM32F103ZET6;MPU6050;LED

一、MPU6050简介

MPU6050 是 InvenSense 该公司推出了世界上第一家集成公司 6 轴运动处理组件,相较于多组件方案,免除了组合陀螺仪与加速器时之轴间差的问题,减少了安装空间。

MPU6050 内部整合了 ,还有一个,可用于连接外部磁力传感器,并使用自己的数字运动处理器(DMP: Digital Motion Processor)硬件加速引擎,,完全输出到应用端 9 轴融合计算数据。 DMP,我们可以用 InvenSense 公司提供的运动处理数据库实现姿态解决非常方便,降低了运动处理运算对操作系统的负荷,大大降低了开发难度。

① 以数字形式旋转矩阵,四元数(quaternion)、欧拉角格式(Euler Angle forma)整合计算数据() ② 具有 131 LSBs/°/sec 敏感性和全格感 ③ 集成可程序控制, ④ 移除加速器与陀螺仪轴之间的敏感性,减少设置和传感器漂移的影响 ⑤ ⑥ 内部施工运行时间偏差和磁力传感器校正计算技术,消除了客户需要额外校正的需求 ⑦ ⑧ 带数字输入同步引脚(Sync pin)支持视频电子影相稳定技术 GPS ⑨ 中断程序控制(interrupt),支持姿势识别、摇晃、放大和缩小图片、滚动、快速下降和中断high-G 中断、零动作感应、触摸感应、摇动感应功能 ⑩ VDD 供电电压为 ? 陀螺仪工作电流:5mA,陀螺仪待机电流:5uA;加速器工作电流:500uA,加速器省电模式电流:40uA@10Hz ? ? 高达 400Khz 的 ? 超小包装尺寸:4x4x0.9mm(QFN)

MPU6050 传感器的如图所示:

MPU6050 的如图所示:

其中,SCL 和 SDA 是连接 MCU 的 IIC 接口,MCU 通过这个 IIC 接口来控制 MPU6050,还有一个 IIC 接口:AUX_CL 和 AUX_DA,该接口可用于连接外部设备, 是从 IIC 接口(接 MCU)的,该引脚控制 IIC 地址地址。如果连接。 GND,则 MPU6050 的 IIC 地址是:,如果接 ,则是 ,注:这里的地址不包括数据传输的最低位(最低位用于读写)!

接下来,让我们介绍一下使用 STM32F1 读取 MPU6050 加速度和角度传感器数据(非中断方式)需要哪些初始化步骤:

        该部分主要在MPU6050.C文件中有详细解释与编写过程,MPU6050主要采用

        我们可以读出 MPU6050 的的原始数据。不过这些原始数据,对想搞四轴之类的初学者来说,用处不大,我们期望得到的是,也就是。有了这三个角,我们就可以得到当前四轴的姿态,这才是我们想要的结果。(由于本项目比较简单并不需要欧拉角作为减速的判定依据,所以这里不过多介绍,代码中也没有使用到。为了满足读者各种需求,开源的代码中会放置DMP的可移植程序供大家参考)

        笔者前文有介绍,很多老师亦或是学生会习惯性直接使用PWM调节LED灯达到呼吸效果,来作为车辆减速灯的效果。但是,笔者认为PWM呼吸灯。这里给大家介绍一种模拟PWM呼吸的闪烁警示灯。这种闪烁警示灯的编程原理有点类似于中也很常见类似的编程效果。

        总所周知,PWM调节时利用占空比去,通过与设定的阈值比较后重装载来实现的效果。而这里则是利用delay延迟的us秒数去亮灭LED灯来实现该功能。

        其中,HAL库只提供了。所以这里需要自己去使用定时器TIM去编写一个的延迟函数。

        该方法思路是将定时器设置为,定时器计一个数就是1us,实现如下:

#define DLY_TIM_Handle (&htim4)
void delay_us(uint16_t nus)
{
	__HAL_TIM_SET_COUNTER(DLY_TIM_Handle, 0);
	__HAL_TIM_ENABLE(DLY_TIM_Handle);
	while (__HAL_TIM_GET_COUNTER(DLY_TIM_Handle) < nus)
	{
	}
	__HAL_TIM_DISABLE(DLY_TIM_Handle);
}

        实现的代码函数:breathing_led()函数

void breathing_led()
{
		if(flag == 0)
		{
		  for(i = 0 ; i <= 10 ; i++){
			HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,0);
			HAL_Delay(t);
			HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,1);
			HAL_Delay(41-t);
		}
		t++;
		if(t == 40) flag = 1;
	}	
		if(flag == 1)
			{
			for(i = 0 ; i <= 10 ; i++){
				HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,0);
				HAL_Delay(t);
				HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,1);
				HAL_Delay(41-t);
			}
		t--;
		if(t == 1) flag = 0;
	}
}

三、CubexMX配置

       

       

         3、GPIO设置PE5(LED灯的引脚)

       

         

         

         为了方便大家对的理解,这里利用较为简单常用的串口通讯对MPU6050输出的进行打印。当然这里大家也可以使用进行显示数据。

四、代码

4.1 MPU6050驱动

        

#ifndef __MPU6050_H
#define __MPU6050_H

//#include "stm32f4xx_hal.h"		
#include "stm32f1xx_hal.h"	用什么系列就是什么									  	  


//#define MPU_ACCEL_OFFS_REG		0X06	//accel_offs寄存器,可读取版本号,寄存器手册未提到
//#define MPU_PROD_ID_REG			0X0C	//prod id寄存器,在寄存器手册未提到
#define MPU_SELF_TESTX_REG		0X0D	//自检寄存器X
#define MPU_SELF_TESTY_REG		0X0E	//自检寄存器Y
#define MPU_SELF_TESTZ_REG		0X0F	//自检寄存器Z
#define MPU_SELF_TESTA_REG		0X10	//自检寄存器A
#define MPU_SAMPLE_RATE_REG		0X19	//采样频率分频器
#define MPU_CFG_REG			0X1A	//配置寄存器
#define MPU_GYRO_CFG_REG		0X1B	//陀螺仪配置寄存器
#define MPU_ACCEL_CFG_REG		0X1C	//加速度计配置寄存器
#define MPU_MOTION_DET_REG		0X1F	//运动检测阀值设置寄存器
#define MPU_FIFO_EN_REG			0X23	//FIFO使能寄存器
#define MPU_I2CMST_CTRL_REG		0X24	//IIC主机控制寄存器
#define MPU_I2CSLV0_ADDR_REG	        0X25	//IIC从机0器件地址寄存器
#define MPU_I2CSLV0_REG			0X26	//IIC从机0数据地址寄存器
#define MPU_I2CSLV0_CTRL_REG	        0X27	//IIC从机0控制寄存器
#define MPU_I2CSLV1_ADDR_REG	        0X28	//IIC从机1器件地址寄存器
#define MPU_I2CSLV1_REG			0X29	//IIC从机1数据地址寄存器
#define MPU_I2CSLV1_CTRL_REG	        0X2A	//IIC从机1控制寄存器
#define MPU_I2CSLV2_ADDR_REG	        0X2B	//IIC从机2器件地址寄存器
#define MPU_I2CSLV2_REG			0X2C	//IIC从机2数据地址寄存器
#define MPU_I2CSLV2_CTRL_REG	        0X2D	//IIC从机2控制寄存器
#define MPU_I2CSLV3_ADDR_REG	        0X2E	//IIC从机3器件地址寄存器
#define MPU_I2CSLV3_REG			0X2F	//IIC从机3数据地址寄存器
#define MPU_I2CSLV3_CTRL_REG	        0X30	//IIC从机3控制寄存器
#define MPU_I2CSLV4_ADDR_REG	        0X31	//IIC从机4器件地址寄存器
#define MPU_I2CSLV4_REG			0X32	//IIC从机4数据地址寄存器
#define MPU_I2CSLV4_DO_REG		0X33	//IIC从机4写数据寄存器
#define MPU_I2CSLV4_CTRL_REG	        0X34	//IIC从机4控制寄存器
#define MPU_I2CSLV4_DI_REG		0X35	//IIC从机4读数据寄存器

#define MPU_I2CMST_STA_REG		0X36	//IIC主机状态寄存器
#define MPU_INTBP_CFG_REG		0X37	//中断/旁路设置寄存器
#define MPU_INT_EN_REG			0X38	//中断使能寄存器
#define MPU_INT_STA_REG			0X3A	//中断状态寄存器

#define MPU_ACCEL_XOUTH_REG		0X3B	//加速度值,X轴高8位寄存器
#define MPU_ACCEL_XOUTL_REG		0X3C	//加速度值,X轴低8位寄存器
#define MPU_ACCEL_YOUTH_REG		0X3D	//加速度值,Y轴高8位寄存器
#define MPU_ACCEL_YOUTL_REG		0X3E	//加速度值,Y轴低8位寄存器
#define MPU_ACCEL_ZOUTH_REG		0X3F	//加速度值,Z轴高8位寄存器
#define MPU_ACCEL_ZOUTL_REG		0X40	//加速度值,Z轴低8位寄存器

#define MPU_TEMP_OUTH_REG		0X41	//温度值高八位寄存器
#define MPU_TEMP_OUTL_REG		0X42	//温度值低8位寄存器

#define MPU_GYRO_XOUTH_REG		0X43	//陀螺仪值,X轴高8位寄存器
#define MPU_GYRO_XOUTL_REG		0X44	//陀螺仪值,X轴低8位寄存器
#define MPU_GYRO_YOUTH_REG		0X45	//陀螺仪值,Y轴高8位寄存器
#define MPU_GYRO_YOUTL_REG		0X46	//陀螺仪值,Y轴低8位寄存器
#define MPU_GYRO_ZOUTH_REG		0X47	//陀螺仪值,Z轴高8位寄存器
#define MPU_GYRO_ZOUTL_REG		0X48	//陀螺仪值,Z轴低8位寄存器

#define MPU_I2CSLV0_DO_REG		0X63	//IIC从机0数据寄存器
#define MPU_I2CSLV1_DO_REG		0X64	//IIC从机1数据寄存器
#define MPU_I2CSLV2_DO_REG		0X65	//IIC从机2数据寄存器
#define MPU_I2CSLV3_DO_REG		0X66	//IIC从机3数据寄存器

#define MPU_I2CMST_DELAY_REG	        0X67	//IIC主机延时管理寄存器
#define MPU_SIGPATH_RST_REG		0X68	//信号通道复位寄存器
#define MPU_MDETECT_CTRL_REG	        0X69	//运动检测控制寄存器
#define MPU_USER_CTRL_REG		0X6A	//用户控制寄存器
#define MPU_PWR_MGMT1_REG		0X6B	//电源管理寄存器1
#define MPU_PWR_MGMT2_REG		0X6C	//电源管理寄存器2 
#define MPU_FIFO_CNTH_REG		0X72	//FIFO计数寄存器高八位
#define MPU_FIFO_CNTL_REG		0X73	//FIFO计数寄存器低八位
#define MPU_FIFO_RW_REG			0X74	//FIFO读写寄存器
#define MPU_DEVICE_ID_REG		0X75	//器件ID寄存器,who am i寄存器
 
//如果AD0脚(9脚)接地,IIC地址为0X68(不包含最低位).
//如果接V3.3,则IIC地址为0X69(不包含最低位).
#define MPU_ADDR				0X68

//因为MPU6050的AD0接GND,所以则读写地址分别为0XD1和0XD0
//            (如果AD0接VCC,则读写地址分别为0XD3和0XD2)  
#define MPU_READ    0XD1
#define MPU_WRITE   0XD0

uint8_t MPU_Init(void); 						//初始化MPU6050
uint8_t MPU_Write_Len(uint8_t reg,uint8_t len,uint8_t *buf);                           //IIC连续写
uint8_t MPU_Read_Len(uint8_t reg,uint8_t len,uint8_t *buf);                         //IIC连续读 
uint8_t MPU_Write_Byte(uint8_t reg,uint8_t data);				//IIC写一个字节
uint8_t MPU_Read_Byte(uint8_t reg);					//IIC读一个字节

uint8_t MPU_Set_Gyro_Fsr(uint8_t fsr);
uint8_t MPU_Set_Accel_Fsr(uint8_t fsr);
uint8_t MPU_Set_LPF(uint16_t lpf);
uint8_t MPU_Set_Rate(uint16_t rate);
uint8_t MPU_Set_Fifo(uint8_t sens);

float MPU_Get_Temperature(void);
uint8_t MPU_Get_Gyroscope(short *gx,short *gy,short *gz);
uint8_t MPU_Get_Accelerometer(short *ax,short *ay,short *az);

#endif

       

#include "mpu6050.h" 
#include "stdio.h"

//初始化MPU6050
//返回值:0,成功
//    其他,错误代码
uint8_t MPU_Init(void)
{ 
  uint8_t res;
  extern I2C_HandleTypeDef hi2c1;
  HAL_I2C_Init(&hi2c1);
  MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X80);	//复位MPU6050
  MPU_Write_Byte(MPU_PWR_MGMT1_REG,0X00);	//唤醒MPU6050 
  MPU_Set_Gyro_Fsr(3);					//陀螺仪传感器,±2000dps
  MPU_Set_Accel_Fsr(0);					//加速度传感器,±2g
  MPU_Set_Rate(50);						//设置采样率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);
	printf("\r\nMPU6050:0x%2x\r\n",res);
  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(50);						//设置采样率为50Hz
  }else 
		return 1;
  return 0;
}
//设置MPU6050陀螺仪传感器满量程范围
//fsr:0,±250dps;1,±500dps;2,±1000dps;3,±2000dps
//返回值:0,设置成功
//    其他,设置失败 
uint8_t MPU_Set_Gyro_Fsr(uint8_t fsr)
{
	return MPU_Write_Byte(MPU_GYRO_CFG_REG,fsr<<3);//设置陀螺仪满量程范围  
}
//设置MPU6050加速度传感器满量程范围
//fsr:0,±2g;1,±4g;2,±8g;3,±16g
//返回值:0,设置成功
//    其他,设置失败 
uint8_t MPU_Set_Accel_Fsr(uint8_t fsr)
{
	return MPU_Write_Byte(MPU_ACCEL_CFG_REG,fsr<<3);//设置加速度传感器满量程范围  
}
//设置MPU6050的数字低通滤波器
//lpf:数字低通滤波频率(Hz)
//返回值:0,设置成功
//    其他,设置失败 
uint8_t MPU_Set_LPF(uint16_t lpf)
{
	uint8_t data=0;
	if(lpf>=188)data=1;
	else if(lpf>=98)data=2;
	else if(lpf>=42)data=3;
	else if(lpf>=20)data=4;
	else if(lpf>=10)data=5;
	else data=6; 
	return MPU_Write_Byte(MPU_CFG_REG,data);//设置数字低通滤波器  
}
//设置MPU6050的采样率(假定Fs=1KHz)
//rate:4~1000(Hz)
//返回值:0,设置成功
//    其他,设置失败 
uint8_t MPU_Set_Rate(uint16_t rate)
{
	uint8_t data;
	if(rate>1000)rate=1000;
	if(rate<4)rate=4;
	data=1000/rate-1;
	data=MPU_Write_Byte(MPU_SAMPLE_RATE_REG,data);	//设置数字低通滤波器
 	return MPU_Set_LPF(rate/2);	//自动设置LPF为采样率的一半
}

//得到温度值
//返回值:温度值(扩大了100倍)
float MPU_Get_Temperature(void)
{
  unsigned char  buf[2]; 
  short raw;
  float temp;
  
  MPU_Read_Len(MPU_TEMP_OUTH_REG,2,buf); 
  raw=(buf[0]<<8)| buf[1];  
  temp=(36.53+((double)raw)/340)*100;  
//  temp = (long)((35 + (raw / 340)) * 65536L);
  return temp/100.0f;
}
//得到陀螺仪值(原始值)
//gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
//返回值:0,成功
//    其他,错误代码
uint8_t MPU_Get_Gyroscope(short *gx,short *gy,short *gz)
{
    uint8_t buf[6],res;  
	res=MPU_Read_Len(MPU_GYRO_XOUTH_REG,6,buf);
	if(res==0)
	{
		*gx=((uint16_t)buf[0]<<8)|buf[1];  
		*gy=((uint16_t)buf[2]<<8)|buf[3];  
		*gz=((uint16_t)buf[4]<<8)|buf[5];
	} 	
    return res;
}
//得到加速度值(原始值)
//gx,gy,gz:陀螺仪x,y,z轴的原始读数(带符号)
//返回值:0,成功
//    其他,错误代码
uint8_t MPU_Get_Accelerometer(short *ax,short *ay,short *az)
{
    uint8_t buf[6],res;  
	res=MPU_Read_Len(MPU_ACCEL_XOUTH_REG,6,buf);
	if(res==0)
	{
		*ax=((uint16_t)buf[0]<<8)|buf[1];  
		*ay=((uint16_t)buf[2]<<8)|buf[3];  
		*az=((uint16_t)buf[4]<<8)|buf[5];
	} 	
    return res;;
}


//IIC连续写
uint8_t MPU_Write_Len(uint8_t reg,uint8_t len,uint8_t *buf)
{
  extern I2C_HandleTypeDef hi2c1;
  HAL_I2C_Mem_Write(&hi2c1, MPU_WRITE, reg, I2C_MEMADD_SIZE_8BIT, buf, len, 0xfff);
  HAL_Delay(100);
  
  return 0;
}
//IIC连续读
//addr:器件地址
//reg:要读取的寄存器地址
//len:要读取的长度
//buf:读取到的数据存储区
//返回值:0,正常
//    其他,错误代码
uint8_t MPU_Read_Len(uint8_t reg,uint8_t len,uint8_t *buf)
{ 
  extern I2C_HandleTypeDef hi2c1;
  HAL_I2C_Mem_Read(&hi2c1, MPU_READ, reg, I2C_MEMADD_SIZE_8BIT, buf, len, 0xfff);
  HAL_Delay(100);
  
  return 0;	
}
//IIC写一个字节 
//reg:寄存器地址
//data:数据
//返回值:0,正常
//    其他,错误代码
uint8_t MPU_Write_Byte(uint8_t reg,uint8_t data) 				 
{ 
  extern I2C_HandleTypeDef hi2c1;
  unsigned char W_Data=0;

  W_Data = data;
  HAL_I2C_Mem_Write(&hi2c1, MPU_WRITE, reg, I2C_MEMADD_SIZE_8BIT, &W_Data, 1, 0xfff);
  HAL_Delay(100);
  
  return 0;
}
//IIC读一个字节 
//reg:寄存器地址 
//返回值:读到的数据
uint8_t MPU_Read_Byte(uint8_t reg)
{
  extern I2C_HandleTypeDef hi2c1;
  unsigned char R_Data=0;
  
  HAL_I2C_Mem_Read(&hi2c1, MPU_READ, reg, I2C_MEMADD_SIZE_8BIT, &R_Data, 1, 0xfff);
  HAL_Delay(100);
  
  return R_Data;		
}

4.2 模拟PWM的闪烁警示灯

        1、breath.h代码

#ifndef __BREATH_H
#define __BREATH_H

void breathing_led();
void unled();
void delay_us(int nus);

#endif

        2、breath.c代码

#include "breath.h" 
#include "stdio.h"
#include "stm32f1xx_hal.h"	
#include "gpio.h"
#include "tim.h"

#define DLY_TIM_Handle (&htim5)

unsigned int t,i;
unsigned char flag = 0;

//定时TIM5变us延迟函数
void delay_us(int nus)
{
	__HAL_TIM_SET_COUNTER(DLY_TIM_Handle, 0);
	__HAL_TIM_ENABLE(DLY_TIM_Handle);
	while (__HAL_TIM_GET_COUNTER(DLY_TIM_Handle) < nus)
	{
	}
	__HAL_TIM_DISABLE(DLY_TIM_Handle);
}

///模拟PwM的呼吸闪烁警示灯
void breathing_led()
{
		if(flag == 0)
		{
		  for(i = 0 ; i <= 10 ; i++){
			HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,0);
			HAL_Delay(t);
			HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,1);
			HAL_Delay(41-t);
		}
		t++;
		if(t == 40) flag = 1;
	}	
		if(flag == 1)
			{
			for(i = 0 ; i <= 10 ; i++){
				HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,0);
				HAL_Delay(t);
				HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,1);
				HAL_Delay(41-t);
			}
		t--;
		if(t == 1) flag = 0;
	}
}

//非刹车状态下的LED灯
void unled()
{
	HAL_GPIO_WritePin(GPIOE,GPIO_PIN_5,1);
}

4.3 UART串口通讯 

        usart.c代码的printf重写

/* USER CODE BEGIN 0 */
//重定义fputc函数 
int fputc(int ch, FILE *f)
{      
	HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);   
	return ch;
}
/* USER CODE END 0 */

4.4 主函数mian

        部分添加代码:

/* USER CODE BEGIN Includes */
#include "mpu6050.h"
#include "stdio.h"
#include "breath.h"
/* USER CODE END Includes */

/* USER CODE BEGIN PV */
	short x;
	short y;
	short z;
	short ax;
	short ay;
	short az;
/* USER CODE END PV */

/* USER CODE BEGIN 2 */
	MPU_Init();
/* USER CODE END 2 */

  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	MPU_Get_Gyroscope(&x,&y,&z);
	MPU_Get_Accelerometer(&ax,&ay,&az);
//	HAL_Delay(100);
		
	if(az>500)
	{
		breathing_led();
	}
		
	if(az<500 && 0<az)
	{
		unled();
	}
	
	printf("\r\nx=%d,y=%d,z=%d",x,y,z);
	printf("\r\nax=%d,ay=%d,az=%d",ax,ay,az);
  }
  /* USER CODE END 3 */

五、实验效果

5.1 串口通讯

 5.2 减速灯视频

MPU6050减速灯视频

        如果读者有所疑问和见解欢迎在评论区指出!!!希望笔者的内容能给予你一点帮助!        

链接:https://pan.baidu.com/s/1jCYHd2KvZ_ka-I98Ur0WAQ 提取码:efy9

链接:https://pan.baidu.com/s/1j5zhWChrnyK6lB8d90p6_w 提取码:ucvf

标签: 传感器adxl001空间三轴磁传感器stm32三轴加速度传感器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台