维特智能六轴姿态传感器JY61P_stm32f1xx驱动代码解析

目录

目录

硬件准备/上位机直连

 代码驱动

关于官方给出的示例

代码功能及其走位

1.怎样不依托代码验证传感器的某个功能是否有效或者能用?

2.写寄存器的方式

3.为什么不使用WIT私有协议中的关闭上电输出然后读寄存器的方式获得数据?

4.为什么是50个字节的数据?

5.关于休眠

代码

最终效果

遗留问题

2023-3-8更新(遗留问题解决)


主控stm32F103RCT6(原子的mini stm32)

模块:维特智能JY61P

串口通讯

主要是能力有限,其次是时间有限,实在是看不懂四元数那一套。。。干脆弄了个现成的

毕竟

维特智能六轴姿态传感器JY61P_stm32f1xx驱动代码解析_第1张图片

最后效果还是可以的

硬件准备/上位机直连

USB转TTL模块,某宝上五块左右一个,如下图接线

维特智能六轴姿态传感器JY61P_stm32f1xx驱动代码解析_第2张图片维特智能六轴姿态传感器JY61P_stm32f1xx驱动代码解析_第3张图片

 USB转TTL模块接在电脑上,在维特官网下载维特智能上位机,在产品快速上手中有设置上位机的步骤,到处点点就能连上,然后就有下面这张图

维特智能六轴姿态传感器JY61P_stm32f1xx驱动代码解析_第4张图片

 可以看看3D姿态拿来作PPT应该不错

以上这些有什么意义吗?看看买的传感器好不好使?

不,没啥意义,图个乐

维特智能六轴姿态传感器JY61P_stm32f1xx驱动代码解析_第5张图片

 代码驱动

关于官方给出的示例

我之前在维特官网上下载到一个JY901的示例工程实测可用,但是等我写到这时维特官网上有关32的示例工程都没了,不知道为什么。

维特智能六轴姿态传感器JY61P_stm32f1xx驱动代码解析_第6张图片

这是我之前在JY901里面下载的 

代码功能及其走位

原子的mini板上有三个可以自由发挥的按键,我想要实现按一下按键,刷新一遍数据,然后显示在XCOM上。

只需要加速度、角速度和角度这三个数据。

走位很简单,给按键设个外部中断唤醒JY61P,然后串口2接收50个字节的数据然后休眠JY61P,在while(1)里面置一个数据处理的标志,标志置1就休眠JY61P然后处理数据最后显示。

这里说一些调试了很久的问题:

1.怎样不依托代码验证传感器的某个功能是否有效或者能用?

用那个USB转TTL模块直连电脑与传感器进行通信,打开XCOM用里面的多条发送(16进制发送)。

维特智能六轴姿态传感器JY61P_stm32f1xx驱动代码解析_第7张图片

点后面的序号就能发送,这些指令都在维特智能官网WIT私有协议里有详细的列举

注意要先解锁再发送指令最后保存;JY61P是上电自动输出,上面的显示的原始数据看起来有点乱,但是仔细找找就能找到以55开头的数据包(一共11个字节一包),55后面跟的51(加速度)或者52(角速度)或者53(角度),下面这些都会说

重要的事情说三遍

调试过程与WIT私有协议(通信协议)有密切联系,协议不难你一定看得懂

调试过程与WIT私有协议(通信协议)有密切联系,协议不难你一定看得懂

调试过程与WIT私有协议(通信协议)有密切联系,协议不难你一定看得懂

2.写寄存器的方式

根据维特智能官网Modbus协议关于写寄存器的方法,普通六轴只需要发送指令即可设置成功

但是六轴增强(JY61P)、九轴等等需要解锁、设置、保存三步才能写成功。

下图截自操作视频、10.姿态传感器指令配置

维特智能六轴姿态传感器JY61P_stm32f1xx驱动代码解析_第8张图片

维特智能六轴姿态传感器JY61P_stm32f1xx驱动代码解析_第9张图片

3.为什么不使用WIT私有协议中的关闭上电输出然后读寄存器的方式获得数据?

试过了,JY61P没有关闭上电输出这一功能,但是有休眠功能。

4.为什么是50个字节的数据?

前面说过只需要加速度、角速度和角度这三个数据,说全了其实是三轴加速度、三轴角速度和三轴角度,WIT私有协议中关于读取寄存器返回值说的很清楚,一个数据包一共返回11个字节,四个寄存器的值。

维特智能六轴姿态传感器JY61P_stm32f1xx驱动代码解析_第10张图片

 如下图所示,假如读取三轴加速度,则返回X轴加速度、Y轴加速度、Z轴加速度、温度

维特智能六轴姿态传感器JY61P_stm32f1xx驱动代码解析_第11张图片

 一个数据包11个字节,三个数据包33个字节,处理数据一定要求是一个完整的数据包。JY61P是循环发送需要输出的数据的(需要输出什么可以自行设置)

下面讨论两种极限情况:

运气好没丢数据那串口2的接收中断收到的第一个字节就是0x55,那么接收到33个字节的时候(三个完整的数据包)已经足够了。

运气不好把第一个数据包的第一个字节0x55丢了那第一个包就用不了了,算上第一个不完整的数据包10个字节,还有三个数据包33个字节,一共43个字节才能有三个完整的包,所以50个字节够了。

5.关于休眠

前面说过了写寄存器要三步:解锁、设置、保存。但是WIT私有协议这里写的也很明白,任意串口数据可唤醒,所以想要JY61P休眠只需要解锁、设置这两步,第二步之后JY61P就会进入休眠,第三步保存会唤醒,

感兴趣的可以试试。

维特智能六轴姿态传感器JY61P_stm32f1xx驱动代码解析_第12张图片

代码

main.c

#include //需要使用memcpy函数
#include 
#include "usart.h"
#include "UART2.h"
#include "delay.h"
#include "JY901.h"
#include "key.h"

extern void led_init(void);//不知道为什么“#include "led.h"”报错重复定义,led调试用的
extern u8 rec_50_flag;//50个字节的标志
extern u8 rec_data_clc_flag;//处理数据的标志
extern u8 ucRxBuffer[250];
extern u8 ucRxCnt;	

struct STime		stcTime;
struct SAcc 		stcAcc;
struct SGyro 		stcGyro;
struct SAngle 	    stcAngle;
struct SMag 		stcMag;
struct SDStatus     stcDStatus;
struct SPress    	stcPress;
struct SLonLat  	stcLonLat;
struct SGPSV 		stcGPSV;
struct SQ           stcQ;

//因为用到的指令也不多,所以全部列出来了
char unlock[5] = {0xFF,0xAA,0x69,0x88,0xB5};//解锁
char ACCCALSW[5] = {0xFF,0xAA,0x01,0x01,0x00};//进入加速度校准模式
char HeadAngle_to_zero[5] = {0xFF,0xAA,0x01,0x04,0x00};// 航向角置零
char SAVACALSW[5]= {0xFF,0xAA,0x00,0x00,0x00};//保存当前配置
char read_acc[5] = {0xFF,0xAA,0x27,0x34,0x00};//读取三轴加速度
char read_gyro[5] = {0xFF,0xAA,0x27,0x37,0x00};//读取三轴角速度
char read_angle[5] = {0xFF,0xAA,0x27,0x3d,0x00};//读取三轴角度
char sleep[5] = {0xFF,0xAA,0x22,0x01,0x00};//休眠
char band_width[5] = {0xFF,0xAA,0x1F,0x02,0x00};//带宽98Hz
char six_axis[5] = {0xFF,0xAA,0x24,0x01,0x00};//六轴算法
char acc_gyro_angle[5] = {0xFF,0xAA,0x02,0x0E,0x00};//指定输出加速度角速度角度

//数据处理
void usart2_rec_data_handle(unsigned char *rec_data)
{
    //把一个完整的数据包copy到rec_buffer里
	static unsigned char rec_buffer[20];
	u8 i;
	for(i=0;i<=15;i++){
		
		rec_buffer[i] = *(rec_data+i);
	}
	
	switch(rec_buffer[1])//判断数据是哪种数据,然后将其拷贝到对应的结构体中,有些数据包需要通过上位机打开对应的输出后,才能接收到这个数据包的数据
	{
		
		case 0x50:	memcpy(&stcTime,&rec_buffer[2],8);break;//memcpy为编译器自带的内存拷贝函数,需引用"string.h",将接收缓冲区的字符拷贝到数据结构体里面,从而实现数据的解析。
		case 0x51:	memcpy(&stcAcc,&rec_buffer[2],8);break;
		case 0x52:	memcpy(&stcGyro,&rec_buffer[2],8);break;
		case 0x53:	memcpy(&stcAngle,&rec_buffer[2],8);break;
		case 0x54:	memcpy(&stcMag,&rec_buffer[2],8);break;
		case 0x55:	memcpy(&stcDStatus,&rec_buffer[2],8);break;
		case 0x56:	memcpy(&stcPress,&rec_buffer[2],8);break;
		case 0x57:	memcpy(&stcLonLat,&rec_buffer[2],8);break;
		case 0x58:	memcpy(&stcGPSV,&rec_buffer[2],8);break;
		case 0x59:	memcpy(&stcQ,&rec_buffer[2],8);break;
	}//这段数据处理的代码就是我之前在维特官网下载的JY901的数据处理部分的代码,但是很奇怪现在有关32的示例工程都没了

}

int main(void)
{  		
	u8 i = 0;
	u8 n = 0;
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 设置中断优先级分组2
	delay_init();
	Initial_UART1(9600);//接PC的串口
	Initial_UART2(9600);//接JY61P模块的串口	
	
	led_init();//调试用
	KEY_Init();
	
	delay_ms(1000);
	delay_ms(1000);//等等JY-91初始化完成
	
    //JY61P上电自动输出,为了稳定发送指令,每次都会把串口2的接收中断关了
	USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);//关闭串口接受中断
	sendcmd_usart2(unlock);//解锁
	delay_ms(10);
	sendcmd_usart2(ACCCALSW);//加速度校准
	delay_ms(10);
	sendcmd_usart2(band_width);//设置带宽98Hz
	delay_ms(10);
	sendcmd_usart2(six_axis);//设置为6轴算法
	delay_ms(10);
	sendcmd_usart2(acc_gyro_angle);//设置只输出加速度、角速度、角度
	delay_ms(10);
	sendcmd_usart2(SAVACALSW);//保存
	delay_ms(10);
	
	
	sendcmd_usart2(unlock);//解锁
	delay_ms(10);
	sendcmd_usart2(sleep);//休眠
	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断		
	printf("init_ok\r\n");

	
	while(1)
	{			
		if(rec_data_clc_flag == 1){
			//rec_data_clc_flag置1时说明已经收到完整的三个数据包,先关停通信再处理数据
			USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);//关闭串口接受中断
			sendcmd_usart2(unlock);//解锁
			delay_ms(10);
			sendcmd_usart2(sleep);//休眠
		    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断			
			for(i=0;i<=100;i++){
				if(ucRxBuffer[i] == 0x55){
					usart2_rec_data_handle(&ucRxBuffer[i]);
					n++;
				}
				else if(n == 3)//只处理3个0x55开头的数据包
					break;
			}
            //显示接收到的原始数据
			for(i=0;i<=ucRxCnt;i++){
				printf("%x--",ucRxBuffer[i]);
			}
			printf("\r\n");
            //相应标志清零
			rec_50_flag = 0;
			rec_data_clc_flag = 0;
			ucRxCnt = 0;			
			
			//显示角度
			printf("Angle:%.3f %.3f %.3f\r\n",(float)stcAngle.Angle[0]/32768*180,(float)stcAngle.Angle[1]/32768*180,(float)stcAngle.Angle[2]/32768*180);
			//显示加速度
			printf("Acc:%.3f %.3f %.3f\r\n",(float)stcAcc.a[0]/32768*16,(float)stcAcc.a[1]/32768*16,(float)stcAcc.a[2]/32768*16);
			//显示角速度
			printf("Gyro:%.3f %.3f %.3f\r\n",(float)stcGyro.w[0]/32768*2000,(float)stcGyro.w[1]/32768*2000,(float)stcGyro.w[2]/32768*2000);
		}
	}
	
}

usart.c

#include "sys.h"
#include "usart.h"	  
// 	 
//如果使用ucos,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_OS
#include "includes.h"					//ucos 使用	  
#endif

//
//加入以下代码,支持printf函数,而不需要选择use MicroLIB	  
#if 1
#pragma import(__use_no_semihosting)             
//标准库需要的支持函数                 
struct __FILE 
{ 
	int handle; 

}; 

FILE __stdout;       
//定义_sys_exit()以避免使用半主机模式    
void _sys_exit(int x) 
{ 
	x = x; 
} 
//重定义fputc函数 
int fputc(int ch, FILE *f)
{      
	while((USART1->SR&0X40)==0);//循环发送,直到发送完毕   
    USART1->DR = (u8) ch;      
	return ch;
}
#endif 

 
 
void Initial_UART1(unsigned long baudrate)
{
 	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);    

	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	  
	USART_InitStructure.USART_BaudRate = baudrate;
	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(USART1, &USART_InitStructure); 
	USART_ITConfig(USART1, USART_IT_TXE, DISABLE);  
	USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);        
	USART_ClearFlag(USART1,USART_FLAG_TC);
	USART_Cmd(USART1, ENABLE);

}

UART2.c   

#include 
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_rcc.h"
#include "misc.h"
#include "UART2.h"
#include "led.h"

extern char unlock[5];//解锁
extern char sleep[5];//休眠

void Initial_UART2(unsigned long baudrate)
{
 	GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure; 
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
	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;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	 
	USART_InitStructure.USART_BaudRate = baudrate;
	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_TXE, ENABLE);    
	USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);
	
		
	USART_Cmd(USART2, ENABLE);
	NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);
	
	USART_ClearFlag(USART2,USART_FLAG_TC);
    USART_Init(USART2, &USART_InitStructure); //初始化串口1
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断
    USART_Cmd(USART2, ENABLE);                    //使能串口1 
}

u8 Res;
u8 send_data_usart2;
void USART2_IRQHandler(void)
{

	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET){
		LED1=!LED1;//调试用
        //之前调试的时候发送的休眠指令没办法使JY61P休眠,就是用这个灯看出来的
		Res =USART_ReceiveData(USART2);
		CopeSerial2Data(Res);//处理数据
		USART_ClearITPendingBit(USART2, USART_IT_RXNE);
	}
	else if(USART_GetITStatus(USART2, USART_IT_TXE) != RESET){
		USART_ITConfig(USART2, USART_IT_TXE, DISABLE);
		USART_SendData(USART2,send_data_usart2);
		LED0=!LED0;//调试用
	}
}

//用串口2给JY模块发送指令,触发串口2的发送中断实现
void sendcmd_usart2(char cmd[])
{
	u8 i;
	for(i=0;i<5;i++){	
		send_data_usart2 = cmd[i];
		USART_ITConfig(USART2, USART_IT_TXE, ENABLE);
		while(USART_GetFlagStatus(USART2,USART_FLAG_TC)==RESET);
	}
}

u8 rec_50_flag = 0;
u8 rec_data_clc_flag = 0;
u8 ucRxBuffer[250];//这个其实没必要这么大
u8 ucRxCnt = 0;	

//CopeSerialData为串口2中断调用函数,串口每收到一个数据,调用一次这个函数。
void CopeSerial2Data(unsigned char ucData)
{
	
	rec_50_flag++;
	if(rec_50_flag == 50){
		rec_data_clc_flag = 1;
	}
	ucRxBuffer[ucRxCnt++]=ucData;	//将收到的数据存入缓冲区中
}

UART2.h

#ifndef __UART2_H
#define __UART2_H

void Initial_UART2(unsigned long baudrate);
void CopeSerial2Data(unsigned char ucData);

void sendcmd_usart2(char cmd[]);

#endif

//------------------End of File----------------------------

key.c

#include "key.h"
#include "delay.h"
#include "UART2.h"
#include "usart.h"
#include "led.h"
	 
 	    
void KEY_Init(void)
{
	
	GPIO_InitTypeDef GPIO_InitStructure;
	EXTI_InitTypeDef EXTI_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

  	RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//外部中断,需要使能AFIO时钟
 	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//PORTC时钟
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//PORTC时钟
	
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_5;//PC5
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
 	GPIO_Init(GPIOC, &GPIO_InitStructure);//初始化GPIOC5
 
	GPIO_InitStructure.GPIO_Pin  = GPIO_Pin_0;//PA0
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //设置成下拉输入
 	GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA0
	
  	GPIO_EXTILineConfig(GPIO_PortSourceGPIOC,GPIO_PinSource5);

  	EXTI_InitStructure.EXTI_Line=EXTI_Line5;
  	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
  	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发
  	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  	EXTI_Init(&EXTI_InitStructure);	 //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器	
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;		//使能按键所在的外部中断通道
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2, 
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;			//子优先级1
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;					//使能外部中断通道
  	NVIC_Init(&NVIC_InitStructure); 	
	
  	GPIO_EXTILineConfig(GPIO_PortSourceGPIOA,GPIO_PinSource0);

  	EXTI_InitStructure.EXTI_Line=EXTI_Line0;
  	EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;	
  	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;//下降沿触发
  	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  	EXTI_Init(&EXTI_InitStructure);	 //根据EXTI_InitStruct中指定的参数初始化外设EXTI寄存器	
	
	NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;		//使能按键所在的外部中断通道
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x02;	//抢占优先级2, 
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;			//子优先级1
  	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;					//使能外部中断通道
  	NVIC_Init(&NVIC_InitStructure);	
} //按键的中断抢占优先级高于串口2的中断


//KEY0的中断,用来唤醒JY61P,根据WIT私有协议任意串口数据都可以唤醒JY61P
 void EXTI9_5_IRQHandler(void)
{		
	delay_ms(10);   //消抖			 
	if(KEY0 == 0){
		
		LED0=!LED0;//调试用
		USART_SendData(USART2,0x55); 
	}
 	 EXTI_ClearITPendingBit(EXTI_Line5);    //清除LINE5上的中断标志位  
}

//第二个中断是为了调试设置的
//当时没办法让JY61P正常休眠,所以把这一部分单独设了个中断调试
//反复试验最后确定了每次发送指令时先关闭接收中断的做法,比较稳定
extern char unlock[5];//解锁
extern char sleep[5];

void EXTI0_IRQHandler(void){
	delay_ms(10);   //消抖	
	if(WK_UP==1){
		
		USART_ITConfig(USART2, USART_IT_RXNE, DISABLE);//关闭串口接受中断
		sendcmd_usart2(unlock);
		delay_ms(10);
		sendcmd_usart2(sleep);
		
		LED0=!LED0;

		USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启串口接受中断
	}
	EXTI_ClearITPendingBit(EXTI_Line0);    //清除LINE5上的中断标志位  
}


key.h

#ifndef __KEY_H
#define __KEY_H	 
#include "sys.h"


#define KEY0  GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_5)//读取按键0
#define WK_UP   GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)//读取按键2 

void KEY_Init(void);//IO初始化
				    
#endif

JY901.h   

这是我之前在维特官网上下载的关于32的示例工程里包含的和数据处理有关的头文件

定义了各种结构体方便数据处理用

现在没了,莫名其妙

#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

主要代码就这些

最终效果

按一次按键就显示原始数据(调试用)和处理后的数据,角度、加速度、角速度

维特智能六轴姿态传感器JY61P_stm32f1xx驱动代码解析_第13张图片

 有需要完整工程的留邮箱就行

遗留问题

不知道是否有大佬能帮帮忙,下面有三次显示,第一次是初始化后显示的,第二三次是我按了两次按键之后显示的,最后一次按按键时我已经明显改变了传感器的航向角(Z轴的角度),但是任然显示0.071,数值非常小,开始我以为是数据解析处理的有问题,于是我把原始数据显示出来了希望能看见原始数据是对的而我解析错了,但是以55开头,以53为第二位的数据包的原始数据的第7、第8位(根据WIT私有协议可知第七八位是Z轴的角度,红框)很明显是个很小的值,这说明原始数据有问题而非数据处理有问题,再一个就是以53为第二位的数据包里面有三轴角度,X轴和Y轴的角度不论是原始数据还是处理结果验证过都是正确变化的,唯独Z轴的原始数据不正确。

传感器验证过是好的,直连电脑不论用维特提供的上位机还是用XCOM显示,Z轴的原始数据都有而且按照手拿的姿态变化,但是用32读出来的原始数据就不对,这我也不会调了,串口通信丢数据有只丢特定数据包特定位的数据这种丢法吗?

维特智能六轴姿态传感器JY61P_stm32f1xx驱动代码解析_第14张图片

 这个bug还非常稳定

维特智能六轴姿态传感器JY61P_stm32f1xx驱动代码解析_第15张图片

 小白一个,有错还请指正。

完整工程,如果过期了评论告诉我。

链接:https://pan.baidu.com/s/1turX2sJgNxR_MIQ6fYzpNA?pwd=kwq5 
提取码:kwq5

维特智能六轴姿态传感器JY61P_stm32f1xx驱动代码解析_第16张图片

今日废话

人生如此,别多会少,不如莫遇。

从此音尘各悄然,春山如黛草如烟。

2023-3-8更新(遗留问题解决)

非常感谢@忙里偷闲QwQ的帮助。

我咨询了维特,最后验证了给出的结果是六轴产品休眠后唤醒会将Z轴置零。

技术给出的原因是6轴的产品只输出加速度、角速度、角度,6轴的Z轴角度是加速度和角速度积分得来的会产生累计误差,给出的角度是相对角度。九轴的不会,九轴的Z轴角度是磁场结算的,没有累计误差,但是遇到铁类物体时会受到磁场干扰。

开个玩笑我觉得还是钱的问题

维特智能六轴姿态传感器JY61P_stm32f1xx驱动代码解析_第17张图片

你可能感兴趣的:(stm32,单片机,嵌入式硬件)