文章目录
如何用串口读取维特陀螺仪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.寻找数据包
要解析数据包,就要知道数据的基本格式与协议,这里我们可以去官方文档里看
因为我们只需要读角度,所以直接看他的读格式
可以看出,每一个轴的数据都被拆成了低八位和高八位,我们使用时要进行强制转换为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)