文章目录
0.相关基础知识介绍
欧拉角、旋转矩阵、四元数合辑
这个确实复杂,如果以后有机会接触到飞控,再好好看看。
0.1六轴、九轴传感器有什么区别?
加速度传感器(即加速计)、角速度传感器(即陀螺仪)、磁感应传感器(即电子罗盘)。这三类传感器测量的数据在空间坐标系中都可以被分解为X,Y,Z三个方向轴的力,因此也常常被称为3轴加速度计、3轴陀螺仪、3轴磁力计。
加速度传感器(即加速计) | 检测横向加速 |
---|---|
角速度传感器(即陀螺仪) | 检测角度旋转和平衡 |
磁感应传感器(即电子罗盘) | 获取磁场数据 |
气压传感器 | 获取海拔高度的数据 |
6轴 : 三轴(XYZ)加速度计 + 三轴(XYZ)陀螺仪(也叫角速度传感器)
9轴 : 6轴 + 三轴(XYZ)磁场传感器
1.JY901模块简介
以下内容来自JY901使用说明书V4.4,仅摘录了需要注意的内容。
1.1 产品概述
模块内部自带电压稳定电路, 工作电压 3.3v~5v, 引脚电平兼容 3.3V/5V 的嵌入式系统,连接方便。
模块内部集成了姿态解算器, 配合动态卡尔曼滤波算法, 能够在动态环境下准确输出模块的当前姿态, 姿态测量精度静态 0.05 度, 动态 0.1 度, 稳定性极高。
支持串口和 IIC 两种数字接口。 方便用户选择最佳的连接方式。 串口速率
2400bps~921600bps 可调, IIC 接口支持全速 400K 速率。(本博客采用串口通信)
1.2 性能参数
1、 电压: 3.3V~5V
2、 电流: <25mA
3、 测量维度: 加速度: 3 维; 角速度: 3 维; 磁场: 3 维;角度: 3 维, 气压:1 维(JY-901B);GPS: 3 维(接 GPS 模块)
4、 量程: 加速度:±2/4/8/16 g(可选) ; 角速度:±250/500/1000/2000 °/s(可选) ;角度 X,Z 轴±180°, Y 轴±90°。
5、 数据输出内容: 时间、 加速度、 角速度、 角度、 磁场、 端口状态、 气压(JY-901B) 、高度(JY-901B) 、 经纬度(需连接 GPS) 、 地速(需连接 GPS) 。
6、 数据接口: 串口(TTL 电平, 波特率支持 2400、 4800、 9600(默认) 、 19200、 38400、57600、 115200、 230400、 460800、 921600) , I2C(最大支持高速 IIC 速率 400K)
7.扩展口功能: 模拟输入(0~VCC) 、 数字输入、 数字输出、 PWM 输出(周期 1us-65535us,分辨率 1us)
1.3 实物图和接线
串口通信接线如下:
JY901 | 单片机 |
---|---|
VCC | 3.3V 或 5V |
RX | TX |
TX | RX |
GND | GND |
IIC通信接线如下:
JY901 | 单片机 |
---|---|
VCC | 3.3V 或 5V |
SCL | I2C 时钟线 |
SDA | I2C 数据线 |
GND | GND |
注意: 为了能在 IIC总线上面挂接多个模块, 模块的 IIC 总线是开漏输出的, MCU 在连接模块时需要将 IIC 总线通过一个 4.7K 的电阻上拉到 VCC。
注意: VCC 为 3.3V, 要另外接电源供电。 直接用模块上面的电源供电, 可能会产生压降, 使模块实际电压没有3.3~5V。
2.软件和使用说明书
上位机软件
提取码:nu3h
JY901使用说明书
提取码:apmd
3.串口通信JY901
3.1 cubemx工程配置
利用DMA空闲中断通信。
1.开启串口1并开启对应的中断
2.添加DMA通道
3.2代码编写
参考博客:
STM32 Cubemax(十) ——JY901陀螺仪数据的读取与简单数据处理
3.2.1 DMA空闲中断的开启
1.在usatr.c文件中添加DMA空闲中断
/* USER CODE BEGIN 0 */
extern User_USART JY901_data;//数据变量声明
/* USER CODE END 0 */
/* USER CODE BEGIN USART1_Init 2 */
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
HAL_UART_Receive_DMA(&huart1,JY901_data.RxBuffer,RXBUFFER_LEN);
/* USER CODE END USART1_Init 2 */
2.在stm32f4xxx_it.c文件中编写中断服务程序
/* USER CODE BEGIN PV */
extern User_USART JY901_data;
/* USER CODE END PV */
/**
* @brief This function handles USART1 global interrupt.
*/
void USART1_IRQHandler(void)
{
/* USER CODE BEGIN USART1_IRQn 0 */
uint32_t temp_flag = 0;
uint32_t temp;
temp_flag = __HAL_UART_GET_FLAG(&huart1,UART_FLAG_IDLE);
if((temp_flag!=RESET))
{
__HAL_UART_CLEAR_IDLEFLAG(&huart1);
temp = huart1.Instance->SR;
temp = huart1.Instance->DR;
HAL_UART_DMAStop(&huart1);
temp = hdma_usart1_rx.Instance->NDTR;
//F1的板子 temp = hdma_usart3_rx.Instance->CNDTR;
JY901_data.Rx_len = RXBUFFER_LEN-temp;
JY901_Process(); //按照自己需求改写这个函数
JY901_data.Rx_flag = 1;
}
HAL_UART_Receive_DMA(&huart1,JY901_data.RxBuffer,RXBUFFER_LEN);
/* USER CODE END USART1_IRQn 0 */
HAL_UART_IRQHandler(&huart1);
/* USER CODE BEGIN USART1_IRQn 1 */
/* USER CODE END USART1_IRQn 1 */
}
3.2.2 添加JY901.h
淘宝客服提供。
#ifndef __JY901_H
#define __JY901_H
#define SAVE 0x00
#define CALSW 0x01
#define RSW 0x02
#define RRATE 0x03
#define BAUD 0x04
#define AXOFFSET 0x05
#define AYOFFSET 0x06
#define AZOFFSET 0x07
#define GXOFFSET 0x08
#define GYOFFSET 0x09
#define GZOFFSET 0x0a
#define HXOFFSET 0x0b
#define HYOFFSET 0x0c
#define HZOFFSET 0x0d
#define D0MODE 0x0e
#define D1MODE 0x0f
#define D2MODE 0x10
#define D3MODE 0x11
#define D0PWMH 0x12
#define D1PWMH 0x13
#define D2PWMH 0x14
#define D3PWMH 0x15
#define D0PWMT 0x16
#define D1PWMT 0x17
#define D2PWMT 0x18
#define D3PWMT 0x19
#define IICADDR 0x1a
#define LEDOFF 0x1b
#define GPSBAUD 0x1c
#define YYMM 0x30
#define DDHH 0x31
#define MMSS 0x32
#define MS 0x33
#define AX 0x34
#define AY 0x35
#define AZ 0x36
#define GX 0x37
#define GY 0x38
#define GZ 0x39
#define HX 0x3a
#define HY 0x3b
#define HZ 0x3c
#define Roll 0x3d
#define Pitch 0x3e
#define Yaw 0x3f
#define TEMP 0x40
#define D0Status 0x41
#define D1Status 0x42
#define D2Status 0x43
#define D3Status 0x44
#define PressureL 0x45
#define PressureH 0x46
#define HeightL 0x47
#define HeightH 0x48
#define LonL 0x49
#define LonH 0x4a
#define LatL 0x4b
#define LatH 0x4c
#define GPSHeight 0x4d
#define GPSYAW 0x4e
#define GPSVL 0x4f
#define GPSVH 0x50
#define q0 0x51
#define q1 0x52
#define q2 0x53
#define q3 0x54
#define DIO_MODE_AIN 0
#define DIO_MODE_DIN 1
#define DIO_MODE_DOH 2
#define DIO_MODE_DOL 3
#define DIO_MODE_DOPWM 4
#define DIO_MODE_GPS 5
struct STime
{
unsigned char ucYear;
unsigned char ucMonth;
unsigned char ucDay;
unsigned char ucHour;
unsigned char ucMinute;
unsigned char ucSecond;
unsigned short usMiliSecond;
};
struct SAcc//加速度
{
short a[3];
short T;
};
struct SGyro//角速度
{
short w[3];
short T;
};
struct SAngle//角度
{
short Angle[3];
short T;
};
struct SMag//磁场输出
{
short h[3];
short T;
};
struct SDStatus//端口状态数据输出
{
short sDStatus[4];
};
struct SPress//气压高度
{
long lPressure;
long lAltitude;
};
struct SLonLat//经纬度
{
long lLon;
long lLat;
};
struct SGPSV
{
short sGPSHeight;
short sGPSYaw;
long lGPSVelocity;
};
struct SQ //四元数
{ short q[4];
};
#endif
3.2.3 重定义需要的结构体和JY901数据结构体
typedef struct
{
float angle[3];
}Angle;
typedef struct
{
float a[3];
}Acc;
typedef struct
{
float w[3];
}SGyro;
typedef struct//四元数
{ float q[4];
}SQ;
typedef struct//磁场输出
{
float h[3];
}SMag;
typedef struct//气压高度
{
float lPressure;
float lAltitude;
}SPress;
typedef struct//经纬度
{
float lLon;
float lLat;
}SLonLat;
typedef struct User_USART
{
uint8_t Rx_flag;
uint8_t Rx_len;
uint8_t frame_head; //帧头
uint8_t RxBuffer[RXBUFFER_LEN]; //接收缓冲
Angle angle; //角度
Acc acc; //加速度
SGyro w; //角速度
SMag h; //磁场
SPress lPressure; //气压
SPress lAltitude; //高度
SLonLat lLon; //经度
SLonLat lLat; //维度
SQ q; //四元数
}User_USART;
3.2.4 接收结构体初始化
void User_USART_Init(User_USART *Data)
{
for(uint16_t i=0; i < RXBUFFER_LEN; i++) Data->RxBuffer[i] = 0;
Data->frame_head = 0x55;
Data->Rx_flag = 0;
Data->Rx_len = 0;
}
3.2.5 数据解算
#define RXBUFFER_LEN 99 //接收9类数据,一共99位
User_USART JY901_data;
struct SAcc stcAcc;
struct SGyro stcGyro;
struct SAngle stcAngle;
struct SMag stcMag;
struct SPress stcPress;
struct SLonLat stcLonLat;
struct SQ stcQ;
void JY901_Process()
{
if(JY901_data.Rx_len < RXBUFFER_LEN) return; //如果位数不对
for(uint8_t i=0;i<9;i++)
{
if(JY901_data.RxBuffer[i*11]!= JY901_data.frame_head) return; //如果帧头不对
switch(JY901_data.RxBuffer[i*11+1])
{
case 0x51:
memcpy(&stcAcc,&JY901_data.RxBuffer[2 + i*11],8);
for(uint8_t j = 0; j < 3; j++)
JY901_data.acc.a[j] = (float)stcAcc.a[j]/32768*16;
break;
case 0x52:
memcpy(&stcGyro,&JY901_data.RxBuffer[2 + i*11],8);
for(uint8_t j = 0; j < 3; j++)
JY901_data.w.w[j] = (float)stcGyro.w[j]/32768*2000;
break;
case 0x53:
memcpy(&stcAngle,&JY901_data.RxBuffer[2 + i*11],8);
for(uint8_t j = 0; j < 3; j++)
JY901_data.angle.angle[j] = (float)stcAngle.Angle[j]/32768*180;
break;
case 0x54: //磁场解算
memcpy(&stcMag,&JY901_data.RxBuffer[2 + i*11],8);
for(uint8_t j = 0; j < 3; j++)
JY901_data.h.h[j] = (float)stcMag.h[j];
break;
case 0x55: //D0-D3端口状态
break;
case 0x56: //气压高度
memcpy(&stcPress,&JY901_data.RxBuffer[2 + i*11],8);
JY901_data.lPressure.lPressure = (float)stcPress.lPressure;
JY901_data.lPressure.lAltitude = (float)stcPress.lAltitude/100;
break;
case 0x57: //经纬度
memcpy(&stcLonLat.lLat,&JY901_data.RxBuffer[2 + i*11],8);
JY901_data.lLon.lLat = (float)stcLonLat.lLat/10000000+(double)(stcLonLat.lLat % 10000000)/1e5;
JY901_data.lLon.lLat = (float)stcLonLat.lLon/10000000+(double)(stcLonLat.lLon % 10000000)/1e5;
break;
case 0x58: //GPS
break;
case 0x59: //四元数
memcpy(&stcQ,&JY901_data.RxBuffer[2 + i*11],8);
for(uint8_t j = 0; j < 4; j++)
JY901_data.q.q[j] = (float)stcQ.q[j]/32768;
break;
}
}
}
3.3现象观测
打开上位机软件,勾选需要测试的数据。
可以看到JY901读取到的数据,作为参考量。
在debug模式,读取到的数据。
4.I2C通信JY901
JY901的I2C通信的排针没有焊,以后抽空更。
I2C通信也可参见该博客。
STM32 CubeMx(六)I2C同步串行通信与EEPROM 24C02的读写