完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
1 介绍
大家从标题中来看呢,大家可能会有些困惑,MPU6050只输出加速度、陀螺仪。没有角度。这个也是我今天想和大家说的。最近我做了一个倾角项目。老板基于成本考虑希望我能用MPU6050去算出来角度。说实话自己没接触这个东西,去搞的时候才知道挺难的,很地方看不懂。然后我去看过了正电原子的MPU6050的解算。但是那个角度的结果和我想要精度有点差别。无意中呢在淘宝上搜到了一个维特智能的JY61模块。这个模块的内置的就是MPU6050模块。这个商家说它的静态角度的精度为0.05度、动态0.1度。这个精度是很符合我的需求。给大家看下这个模块 这个模块体积很小巧就15×15×2mm大小。串口通讯用单片机去获取数据很简单,相比起直接去获取MPU6050简单不知道多少倍了。下面和大家说说我是怎么去用STM32F103读取JY61陀螺仪、加速度、角度的数据。 2 开发准备 讲程序之前呢,和大家简单的说说一些硬件、软件准备和JY61怎么和STM32F103接线的。 2.1硬件、软件准备 硬件:JY61模块、USB-TTL、STM32F103开发板、杜邦线。STM32F103的开发板呢,我用的也是维特智能32开发板做测试用。给大家上个图: 软件 :https://pan.baidu.com/s/1SEWmixu4jtUL2HH_3Hcn2g 提取码:zryo 这个是我的写的一个 示例代码大家有兴趣的可以看下:https://pan.baidu.com/s/1sXnlT89FTTs5tONLiaPihw 2.2 接线方式 1、使用USB-TTL将STM32F103C8T6与电脑连接通信 2、JY61与STM32F103C8T6使用杜邦线连接。具体接线如下图所示: 具体接线方式如下: 3 程序讲解 3.1程序思路讲解 好了到大家最关心的地方了。在这里呢。我先和大家说下。我的整体思路是什么。以一个整体框架给大家做一个说明 从上面来看呢,一共就分为主要的两个部分。串口初始化和while主循环。 1 、串口初始化又分为串口1初始化、串口2初始化。其中串口2初始化又多了一个串口2中断服务函数,这个函数用来接收JY61的传过来的数据,然后放在数据缓存区。 2、while主循环包括数据解析和数据输出。数据解析负责把从串口2中断服务函数得到的数据进行数据的一个处理。然后从串口1把数据输出到PC端。 下面分别和大家说下中间的一些重要的函数。 3.2 main函数 程序的执行都是在这个函数里面进行的。它包括串口初始化和while主循环。其中这个Initial_UART1函数就是串口1初始化。Initial_UART2是串口2初始化. int main(void) { char str[100]; unsigned char len,i; USB_Config(); //配置USB-HID SysTick_init(72,10);//设置时钟频率 Initial_UART1(9600);//接PC的串口 Initial_UART2(9600);//接JY-901模块的串口 LED_ON(); delay_ms(1000);//等等JY-91初始化完成 while(1) { delay_ms(500); //输出时间 sprintf(str,"Time:20%d-%d-%d %d:%d:%.3frn",stcTime.ucYear,stcTime.ucMonth,stcTime.ucDay,stcTime.ucHour,stcTime.ucMinute,(float)stcTime.ucSecond+(float)stcTime.usMiliSecond/1000); UART1_Put_String(str); delay_ms(10); //输出加速度 sprintf(str,"Acc:%.3f %.3f %.3frn",(float)stcAcc.a[0]/32768*16,(float)stcAcc.a[1]/32768*16,(float)stcAcc.a[2]/32768*16); UART1_Put_String(str); delay_ms(10); //输出角速度 sprintf(str,"Gyro:%.3f %.3f %.3frn",(float)stcGyro.w[0]/32768*2000,(float)stcGyro.w[1]/32768*2000,(float)stcGyro.w[2]/32768*2000); UART1_Put_String(str); delay_ms(10); //输出角度 sprintf(str,"Angle:%.3f %.3f %.3frn",(float)stcAngle.Angle[0]/32768*180,(float)stcAngle.Angle[1]/32768*180,(float)stcAngle.Angle[2]/32768*180); UART1_Put_String(str); delay_ms(10); //输出磁场 sprintf(str,"Mag:%d %d %drn",stcMag.h[0],stcMag.h[1],stcMag.h[2]); UART1_Put_String(str); delay_ms(10); //输出气压、高度 sprintf(str,"Pressure:%ld Height%.2frn",stcPress.lPressure,(float)stcPress.lAltitude/100); UART1_Put_String(str); delay_ms(10); //输出端口状态 sprintf(str,"DStatus:%d %d %d %drn",stcDStatus.sDStatus[0],stcDStatus.sDStatus[1],stcDStatus.sDStatus[2],stcDStatus.sDStatus[3]); UART1_Put_String(str); delay_ms(10); //输出经纬度 sprintf(str,"Longitude:%ldDeg%.5fm Lattitude:%ldDeg%.5fmrn",stcLonLat.lLon/10000000,(double)(stcLonLat.lLon % 10000000)/1e5,stcLonLat.lLat/10000000,(double)(stcLonLat.lLat % 10000000)/1e5); UART1_Put_String(str); delay_ms(10); //输出地速 sprintf(str,"GPSHeight:%.1fm GPSYaw:%.1fDeg GPSV:%.3fkm/hrn",(float)stcGPSV.sGPSHeight/10,(float)stcGPSV.sGPSYaw/10,(float)stcGPSV.lGPSVelocity/1000); UART1_Put_String(str); delay_ms(10); //输出四元素 sprintf(str,"Four elements:%.5f %.5f %.5f %.5frnrn",(float)stcQ.q[0]/32768,(float)stcQ.q[1]/32768,(float)stcQ.q[2]/32768,(float)stcQ.q[3]/32768); UART1_Put_String(str); delay_ms(10);//等待传输完成 }//主循环 } 3.3 串口1初始化 串口1初始化就是对串口1进行使能。打开UART1_Put_String函数。通过这个函数把结果输出到PC端的。 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); } 3.4 串口2初始化 串口2初始化两个作用,第一打开串口2这个通道。第二就是打开串口2的中断服务函数。 void Initial_UART2(unsigned long baudrate) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2 | 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, DISABLE); USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); USART_ClearFlag(USART2,USART_FLAG_TC); USART_Cmd(USART2, ENABLE); NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; NVIC_InitStructure.NVIC_IRQChannelSubPriority = 8; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } 3.5 串口2中断服务函数 这个函数的功能就是不停的把JY61的数据放到数据缓存区,就是往这个CopeSerial2Data函数发数据。 void USART2_IRQHandler(void) { if(USART_GetITStatus(USART2, USART_IT_TXE) != RESET) { USART_SendData(USART2, TxBuffer[TxCounter++]); USART_ClearITPendingBit(USART2, USART_IT_TXE); if(TxCounter == count) USART_ITConfig(USART2, USART_IT_TXE, DISABLE); } else if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) { CopeSerial2Data((unsigned char)USART2->DR);//处理数据 USART_ClearITPendingBit(USART2, USART_IT_RXNE); } USART_ClearITPendingBit(USART2,USART_IT_ORE); } 3.6 数据缓存区 数据缓存区是从串口2中断服务函数过来的。把数据最终放在stcAcc、stcGyro、stcAngle这些结构体里等待数据解析来处理。 void CopeSerial2Data(unsigned char ucData) { static unsigned char ucRxBuffer[250]; static unsigned char ucRxCnt = 0; 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; } ucRxCnt=0;//清空缓存区 } } 3.7 数据解析 从数据缓存区过来的数据,根据商家的协议都是16进制的数据。因此,我还需要进一步的把数据进行处理把16进制的数据处理成10进制的数据方便阅读。怎么处理呢?还是根据商家的协议去处理的。我们就以角度为例。商家协议在下图: 从上图看呢。角度输出的格式呢应该是55 53 RollL RollH PitchL PitchH YawL YawH TL TH SUM。这个格式就是放在数据缓存区的格式。怎么把数据缓存区的16进制转换成10进制呢?这个还要根据商家给的公式(如下图所示)。 写成程序就是下面这样的。 (float)stcAngle.Angle[0]/32768*180,(float)stcAngle.Angle[1]/32768*180,(float)stcAngle.Angle[2]/32768*180) 3.8 数据输出 数据输出相比较前面的就比较简单了。它的原理就是把上面解析好的数据直接通过一个函数就发出来了。 sprintf(str,"Angle:%.3f %.3f %.3frn",(float)stcAngle.Angle[0]/32768*180,(float)stcAngle.Angle[1]/32768*180,(float)stcAngle.Angle[2]/32768*180); UART1_Put_String(str); delay_ms(10); 发送的函数就很简单了。就是一个UART1_Put_String打印函数。把解析的结果直接从串口1打印出来到PC端。 4输出结果显示 在电脑上正确连接好板子,首先打开串口调试助手,找到相应的端口,然后打开串口,注意这里波特率设置为9600,然后就可以观察到左边的窗口有数据输出了。如图所示: |
|
|
|
只有小组成员才能发言,加入小组>>
调试STM32H750的FMC总线读写PSRAM遇到的问题求解?
1602 浏览 1 评论
X-NUCLEO-IHM08M1板文档中输出电流为15Arms,15Arms是怎么得出来的呢?
1536 浏览 1 评论
967 浏览 2 评论
STM32F030F4 HSI时钟温度测试过不去是怎么回事?
680 浏览 2 评论
ST25R3916能否对ISO15693的标签芯片进行分区域写密码?
1579 浏览 2 评论
1860浏览 9评论
STM32仿真器是选择ST-LINK还是选择J-LINK?各有什么优势啊?
640浏览 4评论
STM32F0_TIM2输出pwm2后OLED变暗或者系统重启是怎么回事?
513浏览 3评论
526浏览 3评论
stm32cubemx生成mdk-arm v4项目文件无法打开是什么原因导致的?
500浏览 3评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-11-19 08:27 , Processed in 0.648359 second(s), Total 79, Slave 62 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号