JY61P陀螺仪使用串口接收数据
2024年电赛已经过去,相信有许多人选择了H题,选择了MPU6050走直线,灰度传感器巡线的方案,但是在移植mpu6050时卡住了,现在市面上有许多陀螺仪模块可以通过串口传输数据,像维特智能推出的JY61系列,JY91系列等都可以通过串口传输,模块自带姿态解算,通过数据包串口直接将角速度,加速度,角度的数据打包传输,只需要进行数据包解包即可。现在还有惯导,支持CAN通信,RS485通信,可以更快更
一、JY61P是什么?
JY61P是一个可以获取物体姿态(角速度,加速度,角度)的陀螺仪模块,它和常规的mpu6050陀螺仪一样,但是该模块的精度更加细,有两种传输方式,1种是I2C,还有1种是串口usart传输。很多人在移植mpu6050时苦不堪言,搞不懂I2C协议,不会移植。现在可以通过一种更简单的方式串口,获取数据。关于JY61P的更多资料请看网址:六轴姿态角度传感器模组
二、串口协议?
首先列出网址:WIT私有协议 · 深圳维特智能科技有限公司
官方的资料对一些小白不是很友好,对官方的协议做出详细解释,不管是JY6,JY91都可以用官方的WT61协议,一下图片来源于:WT61协议 · 深圳维特智能科技有限公司
首先看官方协议:

这几句话,首先明确1点数据包发的是十六机制数,每个数据拆分成了两个字节,将两个高低字节和一组成shortl类型的数据,但是这不是最终数据,真正的数据还有经过计算得出。

这是JY61P串口发送的数据包,帧头是0x55,在判断第一个数据帧头0x51后,后面就是加速度的数据内容,其他角速度,角度一样。


由上图可知数据包是先发送协议帧头0x55,在发送数据帧头0x53,这里是角度所以帧头是0x53,余下就是8个数据位,加上一个停止位。这样就清楚了,我只要将每两个数据整合成一个short类型数据,在根据公式(float)Data=(short)Data/32768*180,就可以了,这样问题的关键在于怎么将数据整合,在c语言的库中有 memcpy()这个函数可以选择将一个存储区的多少字节复制的另一个存储区中:C 库函数 – memcpy() | 菜鸟教程,这样我只需要将这8个数据位,即8个字节复制到我定义的short类型数组中就可以了,因为short类型占两个字节,所以会自动将前两个字节存放在第一个short类型的数组中,开始贴代码
/***********采集JY61P数据**************/
void Get_Jy61(uint16_t Data)
{
static u8 RX_Data[250];
static u8 len = 0;
RX_Data[len++]=Data; //将收到的数据存入缓冲区中
if (RX_Data[0]!=0x55) //数据头不对,则重新开始寻找0x55数据头
{
len=0;
return;
}
if (len<11) return;//数据不满11个,则返回
else
{
switch(RX_Data[1])//判断数据是哪种数据,然后将其拷贝到对应的结构体中,有些数据包需要通过上位机打开对应的输出后,才能接收到这个数据包的数据
{
case 0x51:
memcpy(&SAcc,&RX_Data[2],8);
for(uint8_t j = 0; j < 3; j++)
{
SAcc.Acc[j] = (float)SAcc.Acc_S[j]/32768*16;
}
break;
case 0x52:
memcpy(&SGyro,&RX_Data[2],8);
for(uint8_t j = 0; j < 3; j++)
{
SGyro.Gyro[j] = (float)SGyro.Gyro_S[j]/32768*2000;
}
break;
case 0x53:
memcpy(&SAngle,&RX_Data[2],8);
for(uint8_t j = 0; j < 3; j++)
{
SAngle.Angle[j] = (float)SAngle.Angle_S[j]/32768*180;
}
break;
}
len=0;//清空缓存区
}
}
这样通过串口中断函数将数据传入Get_Jy61(uint16_t Data)函数中,就可以完成数据的解包了,另外官方协议上表示串口是以char类型传输,可以将类型改成char,我用u8也可以。我写的是串口二
void JY61_Init(uint32_t bound)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD,ENABLE);
GPIO_PinAFConfig(GPIOD,GPIO_PinSource6,GPIO_AF_USART2);//IO口用作串口引脚要配置复用模式
GPIO_PinAFConfig(GPIOD,GPIO_PinSource5,GPIO_AF_USART2);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;//TX引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//IO口用作串口引脚要配置复用模式
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOD,&GPIO_InitStructure);
GPIO_StructInit(&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//RX引脚
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOD,&GPIO_InitStructure);
USART_InitTypeDef USART_InitStructure;//定义配置串口的结构体变量
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);//开启串口二的时钟
USART_DeInit(USART2);//清除TIM2的相关配置
USART_StructInit(&USART_InitStructure);
USART_InitStructure.USART_BaudRate = (uint32_t)(115200);//设置波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字节长度为8bit
USART_InitStructure.USART_StopBits = USART_StopBits_1;//1个停止位
USART_InitStructure.USART_Parity = USART_Parity_No ;//没有校验位
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//将串口配置为收发模式
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //不提供流控
USART_Init(USART2,&USART_InitStructure);//将相关参数初始化给串口二
NVIC_InitTypeDef NVIC_InitStructure;//中断控制结构体变量定义
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;//中断通道指定为USART2
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//主优先级为0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//次优先级为1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//确定使能
NVIC_Init(&NVIC_InitStructure);//初始化配置此中断通道
USART_ClearFlag(USART2,USART_FLAG_RXNE);//初始配置时清除接受置位
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//初始配置接受中断
USART_Cmd(USART2,ENABLE);//开启串口二
}
/******** 串口二 中断服务函数 ***********/
void USART2_IRQHandler(void)
{
if(USART_GetITStatus(USART2, USART_IT_RXNE) == SET)//判断是不是真的有中断发生
{
//USART_SendData(USART2,USART_ReceiveData(USART2));//又将数据发回去(用于验证)
//Get_Jy61(USART_ReceiveData(USART2));
uint16_t Data=(USART2->DR & (uint16_t)0x01FF);
Get_Jy61(Data);
}
USART_ClearITPendingBit(USART2, USART_IT_RXNE); //清除标志位
}
三、总结
JY61P的协议需要花心思了解,希望看完我这篇文章的朋友能有所收获,以上代码除了.h文件没有贴上去以外.c文件全部贴上去了,我这篇文章上的是基于STM32F4固件库的代码,本人还写了F4寄存器的代码,F1的标准库和寄存器的代码,都可用。需要的私信我就可以了
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)