由于个人应用到3轴传感器,所以买了直接买了一个9轴的,用于学习STM32Core平台串口2连接维特智能串口Normal协议,然后通过串口1直接打印数据,接收传感器数据和与传感器进行通信;需要看产品文档的可以直接官网搜索文档,咱直接接线上代码开始测试。
官方产品网址
在查看这个例程前请阅读相关传感器说明书,了解传感器所使用的协议,以及传感器的基本功能
点击查看BWT901BCL姿态传感器
实物图图下
硬件操作流程
传感器---------usert2------------->stm32-------------usart1-------------------->上位机(显示效果)
官方的接线图
首先准备维特智能标准传感器,这里以JY901S为例、STM32Core开发板和一个串口三合一模块。接线方式如下图
我的接线图
下面我用自己的开发板接的如下如 ,(九轴姿态传感器(BWT901CL,2.0 蓝牙版—HC-02)
设计采用的芯片是STM32F103ZET6,采用的传感器是BWT901CL姿态传感器,自主进行电路设计,通过串口传输,完成BWT901CL姿态传感器原始数据的读取与显示,以及依靠其内部的DMP模块对原始传感器数据进行滤波、融合处理,得到解算后的姿态角,再通过串口通信的方式,将数据输出到电脑上位机上。
下面直接上示例代码,(可下载官方的代码参考移植,上面有官网地址)-
#include "system.h"
#include "SysTick.h"
#include "led.h"
#include "usart.h" //串口1
#include "uart.h" //串口2
#include "bool.h"
#include "jy901.h" //官方数据模型**JY61** 模式一样的//jy61
//struct SAcc stcAcc;
//struct SGyro stcGyro;
//struct SAngle stcAngle;//jy901 https://wit-motion.yuque.com/docs/share/68d5aebd-703a-473a-836a-9bef2e5c0b4a?#%20%E3%80%8AWIT%E7%A7%81%E6%9C%89%E5%8D%8F%E8%AE%AE%E3%80%8B
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 ACCCALSW[5] = {0XFF,0XAA,0X01,0X01,0X00};//进入加速度校准模式
char SAVACALSW[5]= {0XFF,0XAA,0X00,0X00,0X00};//保存当前配置//用串口2给JY模块发送指令
void sendcmd(char cmd[])
{char i;for(i=0;i<5;i++)UART2_Put_Char(cmd[i]);
}//CopeSerialData为串口2中断调用函数,串口每收到一个数据,调用一次这个函数。
void CopeSerial2Data(unsigned char ucData)
{static unsigned char ucRxBuffer[250];static unsigned char ucRxCnt = 0; LED2=!LED2;//LED_REVERSE(); //接收到数据,LED灯闪烁一下ucRxBuffer[ucRxCnt++]=ucData; //将收到的数据存入缓冲区中if (ucRxBuffer[0]!=0x55) //数据头不对,则重新开始寻找0x55数据头{ucRxCnt=0;return;}if (ucRxCnt<11) {return;}//数据不满11个,则返回else{switch(ucRxBuffer[1])//判断数据是哪种数据,然后将其拷贝到对应的结构体中,有些数据包需要通过上位机打开对应的输出后,才能接收到这个数据包的数据{
// //memcpy为编译器自带的内存拷贝函数,需引用"string.h",将接收缓冲区的字符拷贝到数据结构体里面,从而实现数据的解析。
// case 0x51: memcpy(&stcAcc,&ucRxBuffer[2],8);break;
// case 0x52: memcpy(&stcGyro,&ucRxBuffer[2],8);break;
// case 0x53: memcpy(&stcAngle,&ucRxBuffer[2],8);break;case 0x50: memcpy(&stcTime,&ucRxBuffer[2],8);break;//memcpy为编译器自带的内存拷贝函数,需引用"string.h",将接收缓冲区的字符拷贝到数据结构体里面,从而实现数据的解析。case 0x51: memcpy(&stcAcc,&ucRxBuffer[2],8);break;case 0x52: memcpy(&stcGyro,&ucRxBuffer[2],8);break;case 0x53: memcpy(&stcAngle,&ucRxBuffer[2],8);break;case 0x54: memcpy(&stcMag,&ucRxBuffer[2],8);break;case 0x55: memcpy(&stcDStatus,&ucRxBuffer[2],8);break;case 0x56: memcpy(&stcPress,&ucRxBuffer[2],8);break;case 0x57: memcpy(&stcLonLat,&ucRxBuffer[2],8);break;case 0x58: memcpy(&stcGPSV,&ucRxBuffer[2],8);break;case 0x59: memcpy(&stcQ,&ucRxBuffer[2],8);break;//0x50 时间//0x51 加速度//0x52 角速度//0x53 角度//0x54 磁场//0x55 端口状态//0x56 气压高度//0x57 经纬度//0x58 地速//0x59 四元数//0x5A GPS定位精度//0x5F 读取}ucRxCnt=0;//清空缓存区}
}void CopeSerial1Data(unsigned char ucData)
{ UART2_Put_Char(ucData);//转发串口1收到的数据给串口2(JY模块)
}/*******************************************************************************
* 函 数 名 : main
* 函数功能 : 主函数
* 输 入 : 无
* 输 出 : 无
*******************************************************************************/int main()
{u8 i=0;SysTick_Init(72);Initial_UART1(9600);//串口初始化为9600Initial_UART2(9600);//接JY-901模块的串口 LED_Init();delay_ms(1000);delay_ms(1000);//等等JY-91初始化完成while(1){delay_ms(1000);i++;if(i%20==0){LED1=!LED1;}if(i>20){i = 0;printf("正在进行加速度校准\r\n");sendcmd(ACCCALSW);delay_ms(100);//等待模块内部自动校准好,模块内部会自动计算需要一定的时间sendcmd(SAVACALSW);delay_ms(100);//保存当前配置printf("加速度校准完成\r\n");}//输出时间printf("Time:20%d-%d-%d %d:%d:%.3f\r\n",stcTime.ucYear,stcTime.ucMonth,stcTime.ucDay,stcTime.ucHour,stcTime.ucMinute,(float)stcTime.ucSecond+(float)stcTime.usMiliSecond/1000);delay_ms(10);//输出加速度//串口接受到的数据已经拷贝到对应的结构体的变量中了,根据说明书的协议,以加速度为例 stcAcc.a[0]/32768*16就是X轴的加速度,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);delay_ms(10);//输出角速度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);delay_ms(10);//输出角度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);delay_ms(10);//输出磁场printf("Mag:%d %d %d\r\n",stcMag.h[0],stcMag.h[1],stcMag.h[2]); delay_ms(10);//输出气压、高度printf("Pressure:%ld Height%.2f\r\n",stcPress.lPressure,(float)stcPress.lAltitude/100);delay_ms(10);//输出端口状态printf("DStatus:%d %d %d %d\r\n",stcDStatus.sDStatus[0],stcDStatus.sDStatus[1],stcDStatus.sDStatus[2],stcDStatus.sDStatus[3]);delay_ms(10);//输出经纬度printf("Longitude:%ldDeg%.5fm Lattitude:%ldDeg%.5fm\r\n",stcLonLat.lLon/10000000,(double)(stcLonLat.lLon % 10000000)/1e5,stcLonLat.lLat/10000000,(double)(stcLonLat.lLat % 10000000)/1e5);delay_ms(10);//输出地速printf("GPSHeight:%.1fm GPSYaw:%.1fDeg GPSV:%.3fkm/h\r\n",(float)stcGPSV.sGPSHeight/10,(float)stcGPSV.sGPSYaw/10,(float)stcGPSV.lGPSVelocity/1000);delay_ms(10);//输出四元素printf("Four elements:%.5f %.5f %.5f %.5f\r\n\r\n",(float)stcQ.q[0]/32768,(float)stcQ.q[1]/32768,(float)stcQ.q[2]/32768,(float)stcQ.q[3]/32768);delay_ms(10);//等待传输完成}//主循环}
串口文件参考
#include <stdio.h>
#include "system.h" //#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_rcc.h"
#include "misc.h"static unsigned char TxBuffer[256];
static unsigned char TxCounter=0;
static unsigned char count=0;
extern void CopeSerial1Data(unsigned char ucData);void Initial_UART1(unsigned long baudrate)
{GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_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);NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;NVIC_InitStructure.NVIC_IRQChannelSubPriority = 7;NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;NVIC_Init(&NVIC_InitStructure);
}void UART1_Put_Char(unsigned char DataToSend)
{TxBuffer[count++] = DataToSend; USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
}void UART1_Put_String(unsigned char *Str)
{while(*Str){if(*Str=='\r')UART1_Put_Char(0x0d);else if(*Str=='\n')UART1_Put_Char(0x0a);else UART1_Put_Char(*Str);Str++;}
}//重定义fputc函数
int fputc(int ch, FILE *f)
{ while((USART1->SR&0X40)==0);//循环发送,直到发送完毕 USART1->DR = (u8) ch; return ch;
}void USART1_IRQHandler(void)
{if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET){ USART_SendData(USART1, TxBuffer[TxCounter++]); if(TxCounter == count) {USART_ITConfig(USART1, USART_IT_TXE, DISABLE);// 全部发送完成}USART_ClearITPendingBit(USART1, USART_IT_TXE); }else if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){CopeSerial1Data((unsigned char)USART1->DR);//处理数据USART_ClearITPendingBit(USART1, USART_IT_RXNE);}USART_ClearITPendingBit(USART1,USART_IT_ORE);}
JY901 官方参数直接下载拿过来用
#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
测试效果如下 (测试的效果)测试过程,注意细节,接线和程序,都会导致没有效果,