[应用相关] 利用stm32f4单片机的mpu6050六轴加速度传感器

[复制链接]
5175|92
 楼主| 自动化陈稳 发表于 2022-4-30 12:26 | 显示全部楼层
然后再看 MPU_Get_Temperature、 MPU_Get_Gyroscope 和 MPU_Get_Accelerometer 等三个
函数,源码如下:
 楼主| 自动化陈稳 发表于 2022-4-30 12:28 | 显示全部楼层
  1. //得到温度值
  2. //返回值:温度值(扩大了 100 倍)
  3. short MPU_Get_Temperature(void)
  4. {
  5. u8 buf[2];
  6. short raw; float temp;
  7. MPU_Read_Len(MPU_ADDR,MPU_TEMP_OUTH_REG,2,buf);
  8. raw=((u16)buf[0]<<8)|buf[1];
  9. temp=36.53+((double)raw)/340;
  10. return temp*100;;
  11. }
  12. //得到陀螺仪值(原始值)
  13. //gx,gy,gz:陀螺仪 x,y,z 轴的原始读数(带符号)
  14. //返回值:0,成功
  15. // 其他,错误代码
  16. u8 MPU_Get_Gyroscope(short *gx,short *gy,short *gz)
  17. {
  18. u8 buf[6],res;
  19. res=MPU_Read_Len(MPU_ADDR,MPU_GYRO_XOUTH_REG,6,buf);
  20. if(res==0)
  21. {
  22. *gx=((u16)buf[0]<<8)|buf[1];
  23. *gy=((u16)buf[2]<<8)|buf[3];
  24. *gz=((u16)buf[4]<<8)|buf[5];
  25. }
  26. return res;;
  27. }
  28. //得到加速度值(原始值)
  29. //gx,gy,gz:陀螺仪 x,y,z 轴的原始读数(带符号)
  30. //返回值:0,成功
  31. // 其他,错误代码
  32. u8 MPU_Get_Accelerometer(short *ax,short *ay,short *az)
  33. {
  34. u8 buf[6],res;
  35. res=MPU_Read_Len(MPU_ADDR,MPU_ACCEL_XOUTH_REG,6,buf);
  36. if(res==0)
  37. {
  38. *ax=((u16)buf[0]<<8)|buf[1];
  39. *ay=((u16)buf[2]<<8)|buf[3];
  40. *az=((u16)buf[4]<<8)|buf[5];
  41. }
  42. return res;;
  43. }
 楼主| 自动化陈稳 发表于 2022-4-30 12:29 | 显示全部楼层
其中 MPU_Get_Temperature 用于获取 MPU6050 自带温度传感器的温度值,然后MPU_Get_Gyroscope 和 MPU_Get_Accelerometer 分别用于读取陀螺仪和加速度传感器的原始数据。
 楼主| 自动化陈稳 发表于 2022-4-30 12:29 | 显示全部楼层
最后看 MPU_Write_Len 和 MPU_Read_Len 这两个函数,代码如下
//IIC 连续写
//addr:器件地址 reg:寄存器地址
//len:写入长度 buf:数据区
//返回值:0,正常 其他,错误代码
u8 MPU_Write_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{
u8 i;
IIC_Start();
IIC_Send_Byte((addr<<1)|0);//发送器件地址+写命令
if(IIC_Wait_Ack()){IIC_Stop();return 1;}//等待应答
IIC_Send_Byte(reg); //写寄存器地址
IIC_Wait_Ack(); //等待应答
for(i=0;i<len;i++)
{
IIC_Send_Byte(buf[i]); //发送数据
if(IIC_Wait_Ack()) {IIC_Stop();return 1;}//等待 ACK
}
IIC_Stop();
return 0;
}
//IIC 连续读
//addr:器件地址 reg:要读取的寄存器地址
//len:要读取的长度 buf:读取到的数据存储区
//返回值:0,正常 其他,错误代码
u8 MPU_Read_Len(u8 addr,u8 reg,u8 len,u8 *buf)
{
IIC_Start();
IIC_Send_Byte((addr<<1)|0); //发送器件地址+写命令
if(IIC_Wait_Ack()){ IIC_Stop();return 1; } //等待应答
IIC_Send_Byte(reg); //写寄存器地址
IIC_Wait_Ack(); //等待应答
IIC_Start();
IIC_Send_Byte((addr<<1)|1);//发送器件地址+读命令
IIC_Wait_Ack(); //等待应答
while(len)
{
if(len==1)*buf=IIC_Read_Byte(0);//读数据,发送 nACK
else *buf=IIC_Read_Byte(1); //读数据,发送 ACK
len--; buf++;
}
IC_Stop(); //产生一个停止条件
return 0;
}
 楼主| 自动化陈稳 发表于 2022-4-30 12:30 | 显示全部楼层
MPU_Write_Len 用于指定器件和地址,连续写数据,可用于实现 DMP 部分的: i2c_write函数。而 MPU_Read_Len 用于指定器件和地址,连续读数据,可用于实现 DMP 部分的: i2c_read函数。 DMP 移植部分的 4 个函数,这里就实现了 2 个,剩下的 delay_ms 就直接采用我们 delay.c里面的 delay_ms 实现, get_ms 则直接提供一个空函数即可。
 楼主| 自动化陈稳 发表于 2022-4-30 12:31 | 显示全部楼层
关于 mpu6050.c 就介绍到这。

最后看看 main.c 代码如下:
  1. //串口 1 发送 1 个字符
  2. //c:要发送的字符
  3. void usart1_send_char(u8 c)
  4. {
  5. while(USART_GetFlagStatus(USART1,USART_FLAG_TC)==RESET);
  6. USART_SendData(USART1,c);
  7. }
  8. //传送数据给匿名四轴上位机软件(V2.6 版本)
  9. //fun:功能字. 0XA0~0XAF
  10. //data:数据缓存区,最多 28 字节!!
  11. //len:data 区有效数据个数
  12. void usart1_niming_report(u8 fun,u8*data,u8 len)
  13. {
  14. u8 send_buf[32],i;
  15. if(len>28)return; //最多 28 字节数据
  16. send_buf[len+3]=0;//校验数置零
  17. send_buf[0]=0X88;//帧头
  18. send_buf[1]=fun; //功能字
  19. send_buf[2]=len; //数据长度
  20. for(i=0;i<len;i++)send_buf[3+i]=data[i]; //复制数据
  21. for(i=0;i<len+3;i++)send_buf[len+3]+=send_buf[i]; //计算校验和
  22. for(i=0;i<len+4;i++)usart1_send_char(send_buf[i]); //发送数据到串口 1
  23. }
  24. //发送加速度传感器数据和陀螺仪数据
  25. //aacx,aacy,aacz:x,y,z 三个方向上面的加速度值
  26. //gyrox,gyroy,gyroz:x,y,z 三个方向上面的陀螺仪值
  27. void mpu6050_send_data(short aacx,short aacy,short aacz,short gyrox,short gyroy,short gyroz)
  28. {
  29. u8 tbuf[12];
  30. tbuf[0]=(aacx>>8)&0XFF; tbuf[1]=aacx&0XFF;
  31. tbuf[2]=(aacy>>8)&0XFF; tbuf[3]=aacy&0XFF;
  32. tbuf[4]=(aacz>>8)&0XFF; tbuf[5]=aacz&0XFF;
  33. tbuf[6]=(gyrox>>8)&0XFF; tbuf[7]=gyrox&0XFF;
  34. tbuf[8]=(gyroy>>8)&0XFF; tbuf[9]=gyroy&0XFF;
  35. tbuf[10]=(gyroz>>8)&0XFF; tbuf[11]=gyroz&0XFF;
  36. usart1_niming_report(0XA1,tbuf,12);//自定义帧,0XA1
  37. }
  38. //通过串口 1 上报结算后的姿态数据给电脑
  39. //aacx,aacy,aacz:x,y,z 三个方向上面的加速度值
  40. //gyrox,gyroy,gyroz:x,y,z 三个方向上面的陀螺仪值
  41. //roll:横滚角.单位 0.01 度。 -18000 -> 18000 对应 -180.00 -> 180.00 度
  42. //pitch:俯仰角.单位 0.01 度。 -9000 - 9000 对应 -90.00 -> 90.00 度
  43. //yaw:航向角.单位为 0.1 度 0 -> 3600 对应 0 -> 360.0 度
  44. void usart1_report_imu(short aacx,short aacy,short aacz,short gyrox,short gyroy,
  45. short gyroz,short roll,short pitch,short yaw)
  46. {
  47. u8 tbuf[28];
  48. u8 i;
  49. for(i=0;i<28;i++)tbuf[i]=0;//清 0
  50. tbuf[0]=(aacx>>8)&0XFF; tbuf[1]=aacx&0XFF;
  51. tbuf[2]=(aacy>>8)&0XFF; tbuf[3]=aacy&0XFF;
  52. tbuf[4]=(aacz>>8)&0XFF; tbuf[5]=aacz&0XFF;
  53. tbuf[6]=(gyrox>>8)&0XFF; tbuf[7]=gyrox&0XFF;
  54. tbuf[8]=(gyroy>>8)&0XFF; tbuf[9]=gyroy&0XFF;
  55. tbuf[10]=(gyroz>>8)&0XFF; tbuf[11]=gyroz&0XFF;
  56. tbuf[18]=(roll>>8)&0XFF; tbuf[19]=roll&0XFF;
  57. tbuf[20]=(pitch>>8)&0XFF; tbuf[21]=pitch&0XFF;
  58. tbuf[22]=(yaw>>8)&0XFF; tbuf[23]=yaw&0XFF;
  59. usart1_niming_report(0XAF,tbuf,28);//飞控显示帧,0XAF
  60. }
  61. int main(void)
  62. {
  63. u8 t=0,report=1; //默认开启上报
  64. u8 key;
  65. float pitch,roll,yaw; //欧拉角
  66. short aacx,aacy,aacz; //加速度传感器原始数据
  67. short gyrox,gyroy,gyroz;//陀螺仪原始数据
  68. short temp; //温度
  69. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组 2
  70. delay_init(168); //初始化延时函数
  71. uart_init(500000); //初始化串口波特率为 500000
  72. LED_Init(); //初始化 LED
  73. KEY_Init(); //初始化按键
  74. LCD_Init(); //LCD 初始化
  75. MPU_Init(); //初始化 MPU6050
  76. POINT_COLOR=RED;//设置字体为红色
  77. LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");
  78. LCD_ShowString(30,70,200,16,16,"MPU6050 TEST");
  79. LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
  80. LCD_ShowString(30,110,200,16,16,"2014/5/9");
  81. while(mpu_dmp_init())
  82. { LCD_ShowString(30,130,200,16,16,"MPU6050 Error"); delay_ms(200);
  83. LCD_Fill(30,130,239,130+16,WHITE); delay_ms(200);
  84. }
  85. LCD_ShowString(30,130,200,16,16,"MPU6050 OK");
  86. LCD_ShowString(30,150,200,16,16,"KEY0:UPLOAD ON/OFF");
  87. POINT_COLOR=BLUE;//设置字体为蓝色
  88. LCD_ShowString(30,170,200,16,16,"UPLOAD ON ");
  89. LCD_ShowString(30,200,200,16,16," Temp: . C");
  90. LCD_ShowString(30,220,200,16,16,"Pitch: . C");
  91. LCD_ShowString(30,240,200,16,16," Roll: . C");
  92. LCD_ShowString(30,260,200,16,16," Yaw : . C");
  93. while(1)
  94. {
  95. key=KEY_Scan(0);
  96. if(key==KEY0_PRES)
  97. {
  98. report=!report;
  99. if(report)LCD_ShowString(30,170,200,16,16,"UPLOAD ON ");
  100. else LCD_ShowString(30,170,200,16,16,"UPLOAD OFF");
  101. }
  102. if(mpu_dmp_get_data(&pitch,&roll,&yaw)==0)
  103. {
  104. temp=MPU_Get_Temperature(); //得到温度值
  105. MPU_Get_Accelerometer(&aacx,&aacy,&aacz); //得到加速度传感器数据
  106. MPU_Get_Gyroscope(&gyrox,&gyroy,&gyroz); //得到陀螺仪数据
  107. if(report)mpu6050_send_data(aacx,aacy,aacz,gyrox,gyroy,gyroz);
  108. //用自定义帧发送加速度和陀螺仪原始数据
  109. if(report)usart1_report_imu(aacx,aacy,aacz,gyrox,gyroy,gyroz,(int)(roll*100),
  110. (int)(pitch*100),(int)(yaw*10));
  111. if((t%10)==0)
  112. {
  113. if(temp<0)
  114. {
  115. LCD_ShowChar(30+48,200,'-',16,0); //显示负号
  116. temp=-temp; //转为正数
  117. }else LCD_ShowChar(30+48,200,' ',16,0); //去掉负号
  118. LCD_ShowNum(30+48+8,200,temp/100,3,16); //显示整数部分
  119. LCD_ShowNum(30+48+40,200,temp%10,1,16); //显示小数部分
  120. temp=pitch*10;
  121. if(temp<0)
  122. {
  123. LCD_ShowChar(30+48,220,'-',16,0); //显示负号
  124. temp=-temp; //转为正数
  125. }else LCD_ShowChar(30+48,220,' ',16,0); //去掉负号
  126. LCD_ShowNum(30+48+8,220,temp/10,3,16); //显示整数部分
  127. LCD_ShowNum(30+48+40,220,temp%10,1,16); //显示小数部分
  128. temp=roll*10;
  129. if(temp<0)
  130. {
  131. LCD_ShowChar(30+48,240,'-',16,0); //显示负号
  132. temp=-temp; //转为正数
  133. }else LCD_ShowChar(30+48,240,' ',16,0); //去掉负号
  134. LCD_ShowNum(30+48+8,240,temp/10,3,16); //显示整数部分
  135. LCD_ShowNum(30+48+40,240,temp%10,1,16); //显示小数部分
  136. temp=yaw*10;
  137. if(temp<0)
  138. {
  139. LCD_ShowChar(30+48,260,'-',16,0); //显示负号
  140. temp=-temp; //转为正数
  141. }else LCD_ShowChar(30+48,260,' ',16,0); //去掉负号
  142. LCD_ShowNum(30+48+8,260,temp/10,3,16); //显示整数部分
  143. LCD_ShowNum(30+48+40,260,temp%10,1,16); //显示小数部分
  144. t=0; LED0=!LED0;//LED 闪烁
  145. }
  146. }
  147. t++;
  148. }
  149. }
 楼主| 自动化陈稳 发表于 2022-4-30 12:32 | 显示全部楼层
  1. 此部分代码除了 main 函数,还有几个函数,用于上报数据给上位机软件,利用上位机软件显示传感器波形,以及 3D 姿态显示,有助于更好的调试 MPU6050。上位机软件推荐使用: ANO_Tech匿名四轴上位机_V2.6.exe。 usart1_niming_report 函数用于将数据打包、计算校验和,然后上报给匿名四轴上位机软件。mpu6050_send_data 函数用于上报加速度和陀螺仪的原始数据,可用于波形显示传感器数据,通过 A1 自定义帧发送。而 usart1_report_imu 函数,则用于上报飞控显示帧,可以实时 3D 显示
  2. MPU6050 的姿态,传感器数据等。
 楼主| 自动化陈稳 发表于 2022-4-30 12:33 | 显示全部楼层
这里, main 函数是比较简单的,大家看代码即可,不过需要注意的是,为了高速上传数据,
这里将串口 1 的波特率设置为 500Kbps 了,测试的时候要注意下。
 楼主| 自动化陈稳 发表于 2022-4-30 12:34 | 显示全部楼层
最后,将 MPU_Write_Byte、 MPU_Read_Byte 和 MPU_Get_Temperature 等三个函数加入 USMART 控制,这样,我们就可以通过串口调试助手,改写和读取 MPU6050 的寄存器数据了,并可以读取温度传感器的值,方便大家调试(注意在 USMART 调试的时候,最好通过按KEY0,先关闭数据上传功能,否则会受到很多乱码,妨碍调试)。
至此,我们的软件设计部分就结束了。
 楼主| 自动化陈稳 发表于 2022-4-30 12:34 | 显示全部楼层
下载验证:

在代码编译成功之后,我们通过下载代码到 ALIENTEK 探索者 STM32F4 开发板上,可以
看到 LCD 显示如图 :
22297626cbc559db68.png
 楼主| 自动化陈稳 发表于 2022-4-30 12:35 | 显示全部楼层
屏幕显示了 MPU6050 的温度、俯仰角(pitch)、横滚角(roll)和航向角(yaw)的数值。
然后,可以晃动开发板,看看各角度的变化。
 楼主| 自动化陈稳 发表于 2022-4-30 12:36 | 显示全部楼层
另外,通过按 KEY0 可以开启或关闭数据上报,开启状态下,我们可以打开: ANO_Tech
匿名四轴上位机_V2.6.exe(该软件双击后,会弹出一个蓝色的小界面,直接关闭即可。
 楼主| 自动化陈稳 发表于 2022-4-30 12:37 | 显示全部楼层
然后才
会进入主界面),这个软件,接收 STM32F4 上传的数据,从而图形化显示传感器数据以及飞行
姿态,如图 :
传感器数据波形显示:
2441626cbce705380.png
 楼主| 自动化陈稳 发表于 2022-4-30 12:38 | 显示全部楼层
飞控状态显示:
23491626cbd2d47d14.png
 楼主| 自动化陈稳 发表于 2022-4-30 12:38 | 显示全部楼层
也可以通过串口调试助手,读取数据,保存数据,对数据进行后续处理。
天空大海 发表于 2022-8-11 17:38 | 显示全部楼层
厉害了,学习学习
51xlf 发表于 2022-10-1 12:30 | 显示全部楼层
可以使用dmp实现数据的读取吗?                                 
Uriah 发表于 2022-10-1 14:30 | 显示全部楼层

多次检查也会给单片机带来负荷,对功耗不利
Bblythe 发表于 2022-10-1 17:29 | 显示全部楼层

如果在编程时加密锁定位被使能/锁定,就无法用普通编程器直接读取单片机内的程序
qbwww 发表于 2022-10-2 07:01 | 显示全部楼层
免除了组合陀螺仪与加速器时间轴之差的问题,减少了大量的封装空间
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 在线客服 返回列表 返回顶部