当前位置: 首页 > wzjs >正文

广州网站seo优化排名做外贸什么网站比较好做

广州网站seo优化排名,做外贸什么网站比较好做,重庆市工程建设信息网2021,公司企业发展建议写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做! 本文写于:2025.04.10 STM32开发板学习——第33节: [10-3] 软件I2C读写MPU6050 前言开发板说明引用解答…

写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做!

本文写于:2025.04.10

STM32开发板学习——第33节: [10-3] 软件I2C读写MPU6050

  • 前言
  • 开发板说明
  • 引用
  • 解答和科普
  • 一、硬件接线
  • 二、软件实现
  • 问题
  • 总结

前言

   本次笔记是用来记录我的学习过程,同时把我需要的困难和思考记下来,有助于我的学习,同时也作为一种习惯,可以督促我学习,是一个激励自己的过程,让我们开始32单片机的学习之路。
   欢迎大家给我提意见,能给我的嵌入式之旅提供方向和路线,现在作为小白,我就先学习32单片机了,就跟着B站上的江协科技开始学习了.
   在这里会记录下江协科技32单片机开发板的配套视频教程所作的实验和学习笔记内容,因为我之前有一个开发板,我大概率会用我的板子模仿着来做.让我们一起加油!
   另外为了增强我的学习效果:每次笔记把我不知道或者问题在后面提出来,再下一篇开头作为解答!

开发板说明

   本人采用的是慧净的开发板,因为这个板子是我N年前就买的板子,索性就拿来用了。另外我也购买了江科大的学习套间。
   原理图如下
1、开发板原理图
在这里插入图片描述
2、STM32F103C6和51对比
在这里插入图片描述
3、STM32F103C6核心板
在这里插入图片描述

视频中的都用这个开发板来实现,如果有资源就利用起来。另外也计划实现江协科技的套件。

下图是实物图
在这里插入图片描述

引用

【STM32入门教程-2023版 细致讲解 中文字幕】
还参考了下图中的书籍:
STM32库开发实战指南:基于STM32F103(第2版)
在这里插入图片描述
数据手册
在这里插入图片描述

解答和科普

一、硬件接线

第一部分:完成软件I2C协议的时序;
第二部分:基于I2C协议读写寄存器,来操控MPU6050;

在这里,VCC和GND分别接到电源正负极进行供电,然后SCL,这里我引到了STM32的PB1O号引脚,SDA接在了PB11引脚,由于这个代码实用的是软件I2C,就是用普通的GPIO口,手动翻转电平实现的协议,它并不需要STM32内部的外设资源支持,所以这个端口可以任意指定。然后配置并操作SCL和SDA对应的端口就行了。
根据I2C协议的硬件规定,SCL和SDA都应该外挂一个上拉电阻,但是这里并没有外挂上拉电阻,因为上一节讲过了,这个模块内部自带了上拉电阻。AD0因为模块内置下拉电阻,悬空的时候是接地,最后INT,中断信号输出脚,暂时不用,可以不接;

在这里插入图片描述

二、软件实现

代码框架:这个框架和之前51单片机的I2C是一样的,这里首先建立I2C通信层的.C和.H模块,在通信层里,写好I2C底层的GPIO初始化,和6个时序基本单元,也就是起始、终止,发送一个字节,接收一个字节,发送应答和接受应答,写好I2C通信协议之后,再建立MPU6050模块的.C和.H模块,在这一层,我们讲基于I2C通信的模块,来实现指定地址读、指定地址写,再实现写寄存器对芯片进行配置,读寄存器得到传感器数据,最后在main.c里,调用MPU6050的模块,初始化,拿到数据,显示数据,这就是程序的整体框架结构。

I2C初始化:当前接线SCL(PB10),SDA(PB11)
第一个任务,把SCL和SDA都初始化为开漏输出模式;
虽然开漏输出,名字带了个输出,但这并不代表只能输出,开漏输出模式仍然可以输入,输入时,先输出1,再直接读取输入数据寄存器就行了,这个过程,讲I2C硬件规定时介绍过。
第二个任务,把SCL和SDA置高电平;
调用SetBits,把GPIO的Pin_10和Pin_11,都置高电平,这样I2C初始化就完成了。

void MyI2C_Init(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef   GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;GPIO_InitStructure.GPIO_Pin=GPIO_Pin_10| GPIO_Pin_11;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStructure);GPIO_SetBits(GPIOB,GPIO_Pin_10|GPIO_Pin_11);
}

调用MyI2C_Init()函数,PB10和PB11两个端口,就被初始化为开漏输出模式,然后释放总线,SCL和SDA处于高电平,此时I2C总线处于空闲模式,然后接下来,就根据波形,来完成I2C的6个时序基本单元。

起始单元:
在这里插入图片描述
我们首先把SCL和SDA都确保释放,然后先拉低SDA,再拉低SCL,这样就能产生起始条件了,那在这里,可以不断地调用SetBits 和ResetBits来手动翻转高低电平,但是这样做的话,会在后面的程序中,出现非常多的地方,来制定这个GPIO的端口号,一方面这样做语义不是很明显,另一方面如果我们之后需要换一个端口,那就需要改动非常多的地方,所以这时,我们就需要在上面做个定义,把这个端口号统一替换一个名字,这样无论是语义还是端口的修改,都会非常方便,那给端口号换一个名字呢,有很多方法都能实现功能,在51单片机中,我们一般用Sbit来定义端口的名称,但是Sbit并不是标准C语言的语法,STM32也不支持这样做,那这里,一种简单的替换方法就是宏定义,

#define SCL_PORT  GPIOB
#define SCL_Pin   GPIO_Pin_10

之后如果想释放SCL,就GPIO_SetBits(SCL_PORT, SCL_Pin);
而且修改引脚的时候,直接在上面修改一下宏定义,下面所有引用宏定义的地方,都会自动更改,这时一种简单可行的方法。如果你觉得每次定义都要定义PORT和PIN,比较麻烦,还可以把这整个函数用宏定义进行替换,

/*引脚配置*/
#define OLED_W_SCL(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)(x))
#define OLED_W_SDA(x)		GPIO_WriteBit(GPIOB, GPIO_Pin_9, (BitAction)(x))

这里,直接用宏定义把GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)(x)),包括参数在内的整个函数,用宏定义替换了个名字,新的名字叫做OLED_W_SCL(x),之后再需要操作SCL的时候,就可以使用这个新名字,这样函数比较简短,语义比较明确,并且这里使用了带参数的宏定义,也就是有参宏,在宏定义后面加一个括号,里面写入形参,那在实际引用的时候,比如这里调用OLED_W_SCL(1);实参给1,那替换的时候,这里的实参1就对应这里的形参x,然后再进一步替换到函数里的x,经过有参宏替换之后,这句话就相当于,GPIO_WriteBit(GPIOB, GPIO_Pin_8, (BitAction)(1)),然后把x替换为1,这两句是一样的效果;
还有就这这种方法,在移植到其他库或者其他种类单片机时,不知道怎么修改,另外这种宏定义的方法,如何换到一个主频很高的单片机中,需要对软件时序进行延迟操作的时候,也不太方便进一步修改,所以综合上遇到的宏定义替换的缺点,在这里就直接再套个函数得了,这样即容易理解又方便加软件延迟,所以这里,直接定义函数,对操作端口的库函数进行封装。

void MyI2C_W_SCL (uint8_t BitValue)
{GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)BitValue );
}

这样套一个函数替换之后,我后面再调用这个W_SCL,参数给1或0,就可以释放或拉低SCL了,如果说你要把这个程序移植到别的单片机,就可以把这个函数里的操作,替换为其他单片机对应的操作,比如SCL是51单片机P10口,就可以把这句替换为P10=BitValue,这样就行了,

void MyI2C_W_SCL (uint8_t BitValue)
{P10= BitValue;
}

另外如果你主频比较快,这里也非常方便加一些延时,比如这里要求每次操作引脚后,都要延迟10us,那可以这样,先#include Delay.h

void MyI2C_W_SCL (uint8_t BitValue)
{GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)BitValue );Delay_us(10);
}

这样就能很方便地进行引脚延时操作了。
对于MPU6050来说,经过实测,对于STM32F1系列这里即使不加任何延时,这个引脚翻转速度,MPU6050也能跟的上,但是为了保险起见,我们还是延时10us吧,I2C可以慢一些,多慢都行,但是快的话,就是要看一下手册里对时序时间的要求;

void MyI2C_W_SCL (uint8_t BitValue)
{GPIO_WriteBit(GPIOB,GPIO_Pin_10,(BitAction)BitValue );Delay_us(10);
}void MyI2C_W_SDA (uint8_t BitValue)
{GPIO_WriteBit(GPIOB,GPIO_Pin_11,(BitAction)BitValue );Delay_us(10);
}

另外我们还要再来个读SDA的函数,因为在STM32库函数中,读和写不是同一个寄存器,

uint8_t MyI2C_R_SDA(void)
{uint8_t BitValue;BitValue=GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_11);Delay_us(10);return BitValue;
}

返回读到SDA线的电平。

有了这三个函数的封装,就实现了函数名称、端口号的替换、同时也很方便地修改时序的延时,当我们需要替换端口,或者把这个程序移植到别的单片机中时,就只需要对这前四个函数里的操作对应更改,后面的函数,我们都调用这里的封装的新名称进行操作,这样在移植到时候,后面的部分就不需要再进行修改了。
在这里插入图片描述
我们需要把SCL和SDA都释放,也就是都输出1,然后复制一下,先拉低SDA,再拉低SCL,这就是起始条件的执行逻辑,这里注意一下,在这前面,我们最好把释放SDA的放在前面,这样保险一点,如果起始条件之前SCL和SDA都是高电平了,那先释放哪一个都是一样的效果,但是在这里,我们这个Start还要兼容这里的重复起始条件SR,Sr最开始,SCL是低电平,SDA电平不敢确定,所以保险起见,我们趁SCL是低电平,先确保释放SDA,再释放SCL,这时SDA和SCL都是高电平,然后再拉低SDA,拉低SCL,这样这个Start就可以兼容起始条件和重复起始条件了,所以我们这个起始条件是这个逻辑。

void MyI2C_Start(void)
{	MyI2C_W_SDA(1);MyI2C_W_SCL(1);MyI2C_W_SDA(0);MyI2C_W_SDA(0);
}

接下来,是终止条件:
如果Stop开始时,SCL和SDA都已经是低电平了,那就先释放SCL,再释放SDA就行了,但是在这个时序单元开始时,SDA并不一定是低电平,所以为了确保之后释放SDA能产生上升沿,就要在时序单元开始时,先拉低SDA,然后再释放SCL、释放SDA,所以在程序里Stop的逻辑是:先拉低SDA,再释放SCL,再释放SDA,这就是终止条件;

void MyI2C_Stop(void)
{MyI2C_W_SDA(0);MyI2C_W_SCL(1);MyI2C_W_SDA(1);
}

终止条件后,SCL和SDA都回归到高电平。

发送一个字节:
发送一个字节时序开始时,SCL是低电平,实际上除了终止条件,SCL以高电平结束,所有的单元我们都会保证SCL以低电平结束,这样方便各个单元的拼接。
在这里插入图片描述
这里,SCL低电平,变换数据,高电平,保持数据稳定,由于是高位先行,所以变化数据的时候,按照先放高位,再放次高位,等等,最后最低位,这样的顺序,依次把一个字节的每一位放在SDA线上,每放完一位后,执行释放SCL,拉低SCL的操作,驱动时钟运转,那在程序中的操作就是,首先趁SCL低电平,先把Byte的最高位放在SDA线上,也就是这样写SDA, MyI2C_W_SDA(Byte&0x80);这是常见操作,用按位与的方式,取出数据的某一位或某几位,如果Byte的最高位为1,结果就是0x80,如果Byte的最高位为0,结果就是0x00,这就相当于把Byte的最高位取出来了,这个式子计算结果为0x 80或0x00,而不是1或0,考虑到调用的函数,具有非0即1的特性,所以即使传入0x80,也相当于传入1,不放心的话可以写 if(Byte &0x80==0),MyI2C_W_SDA(0); else { MyI2C_W_SDA(1)};这样最高位就放好了,我们再释放SCL,释放SCL后,从机就会立刻把我刚才放在SDA的数据读走,再拉低SCL,我们可以继续放下一位数据了,下一位是次高位,然后就是0x40,然后再驱动SCL,来一个时钟,所以这里写个for循环,循环8次;

void MyI2C_SendByte(uint8_t Byte){MyI2C_W_SDA(Byte&0x80);MyI2C_W_SCL(1);MyI2C_W_SCL(0);}void MyI2C_SendByte(uint8_t Byte){uint8_t i=0;for(i=0;i<8;i++){MyI2C_W_SDA(Byte&(0x80>>i));MyI2C_W_SCL(1);MyI2C_W_SCL(0);}}

接收一个字节:
在这里插入图片描述
SCL低电平,此时从机需要把数据放到SDA上,为了防止主机干扰从机写入数据,主机需要先释放SDA,释放SDA也相当于切换为输入模式,那在SCL低电平时,从机会把数据放到SDA,如果从机想发1,就释放SDA,如果从机想发0,就拉低SDA,然后主机释放SCL,在SCL高电平期间,读取SDA,再拉低SCL,低电平期间,从机就会把下一位数据放到SDA上,这样重复8次,主机就能读到一个字节了,可以发现:SCL低电平变化数据,高电平读取数据,实际上就是一种读写分离的设计,低电平时间定义为写的时间,高电平时间定义为读的时间。那在SCL高电平时间,如果你非要动SDA,来破坏游戏规则的话,那这个信号就是起始条件和终止条件,SCL高电平时,SDA下降沿为起始条件,SDA上升沿为终止条件,这个设计也保证了起始和终止的特异性,能够让我们在连续不断地波形中,快速定位起始和终止,因为起始和终止和数据传输的波形有本质区别,数据传输,SCL高电平不许动SDA,起始终止,SCL高电平必须动SDA.

接受一个自己,进来之后SCL是低电平,主机释放SDA,从机把数据放到SDA,这时主机释放SCL,SCL高电平,主机就能读取数据了,读取数据用uint8_t MyI2C_R_SDA(void)。

uint8_t MyI2C_ReceiveByte(void){uint8_t Byte=0x00;MyI2C_W_SDA(1);MyI2C_W_SCL(1); if(MyI2C_R_SDA()==1){Byte|=0x80;}MyI2C_W_SCL(0)}

写个for循环,

uint8_t MyI2C_ReceiveByte(void){uint8_t i,Byte=0x00;MyI2C_W_SDA(1);for(i=0;i<8;i++){MyI2C_W_SCL(1); if(MyI2C_R_SDA()==1){Byte|=(0x80>>i);}MyI2C_W_SCL(0);}return Byte;}

发送应答和接收应答:这里发送应答和接收应答,起始就是发送一个字节和接收一个自己的简化版,发送一个字节是发8位,发送应答就是发1位,接收一个字节是收8位,接受应答就是收1位,
在这里插入图片描述

uint8_t MyI2C_ReceiveAck(void){uint8_t AckBit;MyI2C_W_SDA(1);MyI2C_W_SCL(1); AckBit=MyI2C_R_SDA();MyI2C_W_SCL(0);return AckBit;}

为什么你SDA置后,再读取肯定是1呀。
第一, I2C的引脚都是开漏输出+弱上拉的配置,主机输出1,并不是强制SDA为高电平,而是释放SDA,
第二, 你要明白I2C是在进行通信,主机释放了SDA,从机又不是在外面看戏,从机如果在的话,它是有义务在此时把SDA再拉低的,所以这里,即使之前主机把SDA置1了,之后在读取SDA,读到的值也可能是0,读到0,代表从机给了应答。
还有就是主机每次循环读取SDA的时候,这个读取到的数据是从机控制的,也正是从机想要给我们发送的数据,所以这个时序叫做接收一个字节。
测试:

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"
#include "OLED.h"
#include "MyI2C.h"int main(void)
{OLED_Init();MyI2C_Init();MyI2C_Start();MyI2C_SendByte(0xD0);			//½Óµ½¸ßµçƽÔÙ²âÊÔuint8_t ACK=MyI2C_ReceiveAck();MyI2C_Stop();OLED_ShowNum(2,1,ACK,3);OLED_ShowString(1,1,"Hello STM32 MCU");while(1){}
}

接下来写MPU6050上的程序:
初始化:

void MPU6050_Init(void)
{MyI2C_Init();
}

字节写:

void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data)
{MyI2C_Start();MyI2C_SendByte(MPU6050_ADDRESS);MyI2C_ReceiveAck();MyI2C_SendByte(RegAddress);	//地址指针MyI2C_ReceiveAck();MyI2C_SendByte(Data);MyI2C_ReceiveAck();MyI2C_Stop();
}

字节读:

uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{uint8_t Data;MyI2C_Start();MyI2C_SendByte(MPU6050_ADDRESS);MyI2C_ReceiveAck();MyI2C_SendByte(RegAddress);	//µØÖ·Ö¸ÕëMyI2C_ReceiveAck();MyI2C_Start();MyI2C_SendByte(MPU6050_ADDRESS|0x01);MyI2C_ReceiveAck();Data=MyI2C_ReceiveByte();MyI2C_SendAck(1);	//Èç¹ûÏë¶Á¶à¸ö×Ö½Ú£¬¾ÍÒª¸øÓ¦´ð0MyI2C_Stop();return  Data;
}

测试

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"
#include "OLED.h"
#include "MPU6050.h"int main(void)
{OLED_Init();/*MyI2C_Init();MyI2C_Start();MyI2C_SendByte(0xD0);	//0xD2 //½Óµ½¸ßµçƽÔÙ²âÊÔuint8_t ACK=MyI2C_ReceiveAck();MyI2C_Stop();OLED_ShowNum(2,1,ACK,3);OLED_ShowString(1,1,"Hello STM32 MCU");
*/MPU6050_Init();uint8_t ID = MPU6050_ReadReg(0x75);OLED_ShowHexNum(1,1,ID,2);/*д¼Ä´æÆ÷£¬Ê×ÏȽӴ¥Ë¯Ãßģʽ*/MPU6050_WriteReg(0x6B,0x00);MPU6050_WriteReg(0x19,0xAA);uint8_t ID1 = MPU6050_ReadReg(0x75);OLED_ShowHexNum(1,5,ID1,2);while(1){}
}

到这里起始已经完成了对存储器的读和写和AT24C02是一样的,寄存器也是一种存储器,只不过普通的存储器只能读和写,里面的数据并没有赋予什么实际意义,但是寄存器就不一样了,寄存器的每一位数据,都对应了硬件电路的状态,寄存器和外设的硬件电路,是可以进行互动的,所以程序到这里,我们就可以通过寄存器来控制电路了。

#ifndef    __MPU6050_REG_H
#define    __MPU6050_REG_H#define	MPU6050_SMPLRT_DIV		0x19
#define	MPU6050_CONFIG			0x1A
#define	MPU6050_GYRO_CONFIG		0x1B
#define	MPU6050_ACCEL_CONFIG	0x1C#define	MPU6050_ACCEL_XOUT_H	0x3B
#define	MPU6050_ACCEL_XOUT_L	0x3C
#define	MPU6050_ACCEL_YOUT_H	0x3D
#define	MPU6050_ACCEL_YOUT_L	0x3E
#define	MPU6050_ACCEL_ZOUT_H	0x3F
#define	MPU6050_ACCEL_ZOUT_L	0x40
#define	MPU6050_TEMP_OUT_H		0x41
#define	MPU6050_TEMP_OUT_L		0x42
#define	MPU6050_GYRO_XOUT_H		0x43
#define	MPU6050_GYRO_XOUT_L		0x44
#define	MPU6050_GYRO_YOUT_H		0x45
#define	MPU6050_GYRO_YOUT_L		0x46
#define	MPU6050_GYRO_ZOUT_H		0x47
#define	MPU6050_GYRO_ZOUT_L		0x48#define	MPU6050_PWR_MGMT_1		0x6B
#define	MPU6050_PWR_MGMT_2		0x6C
#define	MPU6050_WHO_AM_I		0x75#endif
==写配置寄存器初始状态==
void MPU6050_Init(void)
{MyI2C_Init();MPU6050_WriteReg(MPU6050_PWR_MGMT_1,0x01);		//½â³ý˯Ãß £¬Ñ¡ÔñÍÓÂÝÒÇʱÖÓMPU6050_WriteReg(MPU6050_PWR_MGMT_2,0x00);		//6¸öÖá¾ù²»´ý»úMPU6050_WriteReg(MPU6050_SMPLRT_DIV,0x09);		//²ÉÑù·ÖƵΪ10MPU6050_WriteReg(MPU6050_CONFIG	,0x06);			//Â˲¨²ÎÊý¸ø×î´óMPU6050_WriteReg(MPU6050_GYRO_CONFIG,0x18);		//ÍÓÂÝÒÇ×î´óÁ¿³ÌMPU6050_WriteReg(MPU6050_ACCEL_CONFIG,0x18);	//¼ÓËٶȼÆ×î´óÁ¿³Ì
}

在这里插入图片描述
想获取数据的话,写一个获取数据的函数,根据任务需求,这个函数需要返回6个int16_t的数据,分别表示XYZ的加速度值和陀螺仪值,但是C语言中,函数的返回值只能有一个,所以这里就需要一些特殊的操作来实现返回6个值的任务,多函数返回值的方法有很多:
第一种,最简单的方法就是,在函数外面定义6个全局变量,子函数读到的数据直接写入到全局变量里,然后6个全局变量在主函数里进行共享,这样就相当于返回了6个值。
第二种,用指针,进行变量的地址传递,来实现多返回值。
第三种,用结构体,对多个变量进行打包,然后再统一进行传递,这种方法,就是STM32的库函数里,这里使用到的。

指针,这6个参数,均是int16_t的指针类型,之后我们会在主函数里定义变量,通过指针,把主函数变量的地址传递到子函数来,子函数中,通过传递过来的地址,操作主函数的变量,这样子函数结束之后,主函数变量的值,就是子函数想要返回的值,这就是使用指针,实现函数多返回值的设计。

void MPU6050_GetData(int16_t *AccX, int16_t *AccY,int16_t *AccZ,int16_t *GyroX, int16_t *GyroY,int16_t *GyroZ)
{uint8_t DataH,DataL;DataH=MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);DataL=MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);*AccX=(DataH<<8)|DataL;DataH=MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);DataL=MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);*AccY=(DataH<<8)|DataL;DataH=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);DataL=MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);*AccZ=(DataH<<8)|DataL;DataH=MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);DataL=MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);*GyroX=(DataH<<8)|DataL;DataH=MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);DataL=MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);*GyroY=(DataH<<8)|DataL;DataH=MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);DataL=MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);*GyroZ=(DataH<<8)|DataL;}

逻辑是分别读取6个轴数据寄存器的高位和低位,拼接成16位的数据,在通过指针变量返回,或者使用I2C读取多个字节的时序,从一个基地址开始,连续读取一片的寄存器,因为是连续的可以连续的读取。
int16_t AX,AY,AZ,GX,GY,GZ;之后,在主循环里,不断地读取数据,

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "LED.h"
#include "Key.h"
#include "OLED.h"
#include "MPU6050.h"int16_t AX,AY,AZ,GX,GY,GZ;int main(void)
{OLED_Init();MPU6050_Init();while(1){MPU6050_GetData(&AX,&AY,&AZ,&GX,&GY,&GZ);OLED_ShowSignedNum(2,1,AX,5);OLED_ShowSignedNum(3,1,AY,5);OLED_ShowSignedNum(4,1,AZ,5);OLED_ShowSignedNum(2,8,GX,5);OLED_ShowSignedNum(3,8,GY,5);OLED_ShowSignedNum(4,8,GZ,5);}
}

问题

总结

本节课主要是学了了低层I2C的写,对函数的GPIO进行了封装,调用函数即可完成写,然后写了I2C的六个模块,然后在I2C的基础上完成了MPU6050的写,选择模式,先唤醒,然后写入寄存器相应的值,最后读取多函数返回值,运用指针传递变量的值,最终显示在OLED上,完成了软件I2C读写MPU6050.

http://www.dtcms.com/wzjs/569281.html

相关文章:

  • 个人网页背景图片大全柳州做网站优化
  • 大学生网站建设课程总结在vs上用c 做登录网站
  • 建设简单网站的图纸app开发和网站开发
  • 深圳广东网站建设套餐flash网站大全
  • 网站建设使用的工具jsp网站建设美食
  • 北京住房和城乡建设部网站官网泰安房产信息网官网首页
  • 提供网站建设的各类服务网站过期查询
  • 网站访问对应二级域名wordpress 数据调用api接口
  • 网站建设投放广告密云网站建设
  • 贵阳专业做网站的公司织梦 去掉我的网站
  • 网站音乐播放代码资金盘网站建设
  • 南宁网站建设哪家合肥公司网站建设多少费用
  • 钟表网站开发背景文章自己做产品网站
  • 桂阳局网站建设方案医疗器械四大龙头企业
  • 直播网站建设开发黑龙江新闻法制频道
  • 北京南站地铁做网站在哪里申请
  • 山西运城给网站做系统的公司建网站优化
  • 腾讯云网站建设视频教程wordpress 蜘蛛统计
  • 高质量的网站内容建设wordpress怎么置顶文章
  • index.html网站怎么做网络平台 策划方案
  • 网站制作设计专业公司wordpress采集文章教程
  • 西宁做腋臭北大网站Ywordpress categories
  • 广州网站建设网络培训教育学校的网站建设方案
  • wordpress 网站备案上海网站制作软件
  • 东营wordpress网站建设wordpress 添加账号
  • 银川做网站最好的公司公众号网页源码
  • 网站导航栏动效怎么做的网站上线有什么线上活动可以做
  • 深圳福田住房和建设局网站网站建设方面的课程
  • 医院网站建设招标软装设计方案网站
  • 做网站的一个黑点符号三星网上商城官网app下载