stm32读取维特陀螺仪jy61p角度

如何用串口读取维特陀螺仪jy61p的数据?

一、摘要

经常做小车的朋友一定知道,采用mpu6050的DMP姿态解算Yaw轴的零点漂移非常严重,为此有两种解决方法,一种是写一个强大的滤波算法(如卡尔曼滤波),另一种是直接换一个更diao的陀螺仪。本人采用第二种方法,使用维特智能科技的陀螺仪jy61p,效果很好,就是有点小贵。该陀螺仪采用串口通信,也不会像IIC那样经常发癫。由于官方给的例程功能太过强大,移植比较麻烦,所以我查阅资料写了个易移植的代码。采用串口接收数据包的方法读取陀螺仪数据,主要有两件事:串口接收数据包和数据类型的转换。

二、c语言数据类型

以下是C语言的数据类型,陀螺仪的原始数据为16进制并且拆成高字节和低字节,也就是uint8_t,我们需要把他转化成int16_t或uint16_t才能合并,正常使用进行计算。具体操作在后面讲,这里需要先了解一下c语言数据类型的转换应该避的一些坑。

在这里插入图片描述

1、stdint关键字的含义

打开stdint.h可以看到如下定义:

    /* exact-width signed integer types */
typedef   signed          char int8_t;
typedef   signed short     int int16_t;
typedef   signed           int int32_t;
typedef   signed       __INT64 int64_t;

    /* exact-width unsigned integer types */
typedef unsigned          char uint8_t;
typedef unsigned short     int uint16_t;
typedef unsigned           int uint32_t;
typedef unsigned       __INT64 uint64_t;

可以看出stdint关键字基本都是(u)intx_t的形式,x为位数,这个数是怎么来的呢?比如说uint8_t,用二进制表示八位数,每位只能是0或1,进行排列组合共有28种情况,正好就是256,所以最多表示256个数,如果有符号(即int8_t)那就需要首位表示符号,剩余7位表示数的大小,27也就是256除以2就是128,所以可以表示范围-128~127。

2、数据范围是一个首尾相接的环形

比如说short类型(int16_t)表示的范围是-32768~+32767,但是当计数到32767后再加一结果是-32768

如图:在这里插入图片描述

可以在c语言环境下运行如下代码:

#include<stdio.h>
#include<stdint.h>

int main(void)
{  
	int16_t a=32768;
	printf("a=%d\n",a);

	return 0;
}

可以看到运行结果是-32768:在这里插入图片描述

usigned short类型(uint16_t)表示的范围是0~65535,当计数到65535后再加一后会变成0

如图:在这里插入图片描述

#include<stdio.h>
#include<stdint.h>

int main(void)
{  
	uint16_t a=65536;
	printf("a=%d\n",a);
	
	return 0;
}

结果为0:在这里插入图片描述

3、程序员计算器介绍

打开电脑计算器,切换到程序员模式:

在这里插入图片描述

HEX: 十六进制 Hexadecimal
DEC :十进制 Decimal
OCT :八进制 Octal
BIN :二进制 Binary

MC(Memory Clear):清除存储器中的数值。
MR(Memory Read):将存于存储器中的数显示在计算器的显示框上。
MS(Memory Storage):将显示框的数值存于存储器中。如果存储器中有数值将会显示M标志。
M+:将显示框的数与存储器中的数相加并进行存储。

BIT(位): 是计算机内部数据储存的最小单位
BYTE(字节): 八个比特 (bit) 称为一个字节,是计算机中数据处理的最基本的单位
WORD(字): 两个字节称为一个字, 即16位
DWORD:(双字) 两个字称为一个双字,两个Word,为32位 D为double
QWORD(四字): 两个双字称为一个四字,四个Word,为64位 Q为 quadra

4、数据类型强制转换

将int16_t强制转换为uint16_t,运行如下代码:

#include<stdio.h>
#include<stdint.h>

int main(void)
{  
	int16_t a=-50;
	printf("a=%d\n",a);
	
	uint16_t b;
	b=(uint16_t)a;
	
	printf("b=%d\n",b);
	
	return 0;
}

运行结果:在这里插入图片描述

可以看到负数-50转换为正数变为65486,这两个数是什么关系呢?既然涉及到正负数转换,就该想到原码反码补码。

  • 原码表示方法:最高位为符号位,1 表示负数,0 表示正数。其余比特位表示数值。
  • 反码表示方法:正数的反码是其本身,负数的反码为在原码的基础上,符号位不变,其余位取反。
  • 补码表示方法:正数的补码就是其本身,负数的补码为在原码的基础上,符号位不变,其余位取反,再+1(即在反码的基础上+1)
  • 位数:整数的二进制比特位数,可以输入整数的值的范围为 [-2n-1, 2n-1 - 1] , 其中 n 为比特位数。

简单总结:

原码反码补码
正数本身本身
负数符号位不变,其余取反反码+1

把-50输到原码反码补码计算器中计算出补码:

原码/反码/补码 计算器 - 锤子在线工具 (toolhelper.cn)

结果如图:在这里插入图片描述

把补码复制到程序员计算器进行进制转换

结果如图:在这里插入图片描述

发现结果就是65486,可以看出,从有符号位强制转换为无符号位就是取补码。

取补码有什么用呢?请运行如下代码:每次将a的值替换为注释中的值,可以得到b注释中对应的值

#include<stdio.h>
#include<stdint.h>

int main(void)
{  
	int16_t a=-32768;//1,10000,20000,30000,32767,-32768,-30000,-20000,-10000,-1
	printf("a=%d\n",a);
	
	uint16_t b;
	b=(uint16_t)a;//1,10000,20000,30000,32767,32768,35536,45536,55536,65535
	
	printf("b=%d\n",b);
	
	return 0;
}

得到上面的值后,可能仍然看不出什么规律来,但是画到之前的图中就一目了然了,

可以看到,取补码后并没有改变原数据的顺序关系,仍然是首尾相接的环形,这里在代码部分会用到。在这里插入图片描述

三、WIT私有协议

1.寻找数据包

要解析数据包,就要知道数据的基本格式与协议,这里我们可以去官方文档里看

WIT私有协议 (yuque.com)

因为我们只需要读角度,所以直接看他的读格式

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

可以看出,每一个轴的数据都被拆成了低八位和高八位,我们使用时要进行强制转换为short(int16_t)类型,数据包包头是0x55,第二个数据表示数据内容,我们需要角度,就是0x53,后面八个为数据,最后一个是校验和的低八位。

再看一下角度输出:

在这里插入图片描述

这就是我们需要的数据:

在这里插入图片描述

我们需要在陀螺仪输出的数据中找到0x55,0x53为包头的数据包,然后取接下来的八位为三轴角度,再取一位为校验位。

我们可以在上位机中查看原始数据试着找一下我们需要的数据包,将陀螺仪通过usb转ttl连接到电脑:

在这里插入图片描述

打开串口调试助手,十六进制显示数据,如图可以看到角度输出的数据包:

在这里插入图片描述

也可在官方上位机查看原始数据:

在这里插入图片描述

2.解读数据包

找到数据包后我们可以尝试验证一下数据是否正确,可以参考视频教程维特智能角度传感器数据解算方法JY61/JY901 - 西瓜视频 (ixigua.com)

首先我们把陀螺仪偏至一定角度保持不动,这里以30度为例:

在这里插入图片描述

根据数据包协议我们可以知道以0x55,0x53开头的数据包后第5、6位数据为z轴角度数据,查看数据包可以看到z轴低八位和高八位分别为0xAB,0x15:

在这里插入图片描述

通过计算器转换成十进制,为5547:在这里插入图片描述

通过计算公式可以算出角度为30.47度,结果正确:

在这里插入图片描述

在这里插入图片描述

3.解读数据包的坑

前面我们尝试解读了数据包,接下来说一下此处的坑,我们把陀螺仪旋转到负的角度,以-30度为例:

在这里插入图片描述

查看原始数据低八位高八位分别为0x73,0xEA:在这里插入图片描述

转换成十进制为60019:在这里插入图片描述

代入公式计算角度结果为329.7,并不是想要的结果:在这里插入图片描述

发现结果并不是-30度,为什么呢?这是因为把原始数据的符号位当做了普通数据,int16_t是带符号位的,表示的范围是-32768-32767,而uint16_t没有符号位,表示的范围是0-65535

通过计算器进行强制类型转换由32位变为16位得到转换后的数-5517:
在这里插入图片描述

代入公式计算角度得到-30.3度,结果正确:在这里插入图片描述

计算-5517的补码原码/反码/补码 计算器 - 锤子在线工具 (toolhelper.cn),转换成无符号数,发现结果恰好为60019:在这里插入图片描述

由上述步骤可以发现,对于0xEA73,如果考虑符号位表示的数是-5517,不考虑符号位表示的是60019,而它恰好是-5517的补码,对应计算得出的角度分别为330度和-30度。

由### 4、数据类型强制转换可知,补码并没有改变数据的顺序关系,如果考虑符号位,计算得到的角度范围就是-180-180,如果不考虑符号位,则计算得到的角度范围为0-360度,如何在程序中设置是否考虑符号位呢?其实可以通过数据的强制转换来实现,因为输出的数据一共16位(低八位高八位合并),那么我们可以通过设置强制转换为int16_t和uint16_t来确定是否考虑符号,当强制转换为int16_t时,会考虑符号位,表示数据范围为-32767-32768,当数据超过32767后会转变成对应的负数,对应角度-180-180,当强制转换成uint16_t时,不考虑符号位,表示的数据范围恰好是0-65535,对应角度0-360.

在这里插入图片描述

四、代码解析与实操

1、陀螺仪上位机配置

将陀螺仪通过usb转ttl连接至电脑,打开官方上位机,点击配置

在这里插入图片描述

如果是jy901,可以把算法切换到六轴,不使用磁场,这样可以返回相对角度,功能与jy61一样,如果采用九轴算法,返回的是绝对角度,勾选欧拉角的输出,波特率的设置要与单片机端配置一致,设置完成后左下角会显示配置成功,完成后退出。

在这里插入图片描述

2、stm32串口初始化

这里使用串口2

	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure; 
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//TX
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);    
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//RX
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	 
	USART_InitStructure.USART_BaudRate = bound;//波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//停止位
	USART_InitStructure.USART_Parity = USART_Parity_No ;//校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收发模式
	USART_Init(USART2, &USART_InitStructure); 
	
	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启中断
	USART_Cmd(USART2, ENABLE);//打开串口
	
	NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;//中断通道
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//抢占优先级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//响应优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能通道
	NVIC_Init(&NVIC_InitStructure);

3、接收数据包进行数据处理

在串口接收中断服务函数里进行数据包处理

void USART2_IRQHandler(void)
{
	uint8_t RxData;
	if (USART_GetITStatus(USART2, USART_IT_RXNE) == SET)
	{
		RxData = USART_ReceiveData(USART2);	/*读取接收到的数据*/
		
		jy61p_ReceiveData(RxData);	/*调用数据包处理函数*/
		
		USART_ClearITPendingBit(USART2, USART_IT_RXNE);
	}
}

4、OLED显示

在主函数中通过OLED显示角度。

5、效果展示

180度版:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

360度版:

在这里插入图片描述
在这里插入图片描述

五、源码链接

[stm32读取维特陀螺仪jy60,jy61,jy901] (https://www.bilibili.com/video/BV1KGHoemEF4/?share_source=copy_web&vd_source=d912cf4b424f2f4f9f337ac63872359a)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值