少女祈祷中...

几种通信协议

通信协议概览

ps:文本模式,会先通过映射表

HEX模式,输入什么就是什么

通信的目的:将一个设备的数据传送到另一个设备,扩展硬件系统

通信协议:制定通信的规则,通信双方按照协议规则进行数据收发

image.png

(1)引脚

TX(Transmit Exchange)数据发送脚

RX(Receive Exchange)数据接收脚

SCl(Serial Clock)时钟

SDA(Serial Data)数据

MOSL(Master Output Slave Input )主机输出数据脚

MISO(Master Input Slave Output)主机输入数据脚

CS片选,用于指定通信对象

CAN_H CAN_N指定差分数据脚

DP(Data Positive)DM(Data Minus)一对差分数据脚

(2)双工

全双工:双方能够同时进行双向通信。

单工:只能一个设备到另一个设备,不能反着来

(3)时钟

同步通信:双方在通信时时间完全同步,当接收方接收并处理完成后发送方才能再次进行下一步操作。

异步通信:不需要等待接收方处理完成,可以立即进行下一步操作。接收方可以在方便的时候处理收到的数据。收发两端中,发送端啥时候想发啥时候发,不需要等某一方的时钟信号来进行同步接受次序后再发。实现简单,但较长的通信内容可能会由于双方的时钟不统一而出现错位。因此,通过对一个二进制码元进行多次采样可以一定程度上发现甚至解决错位问题。常见采样次数为8和16。

(4)电平

单端电平:引脚的高低电平都是对于GND的电压差,因此传输双方必须共地。不连GND无法通信。

差分电平:靠着两个差分引脚的电压差进行信号传输。

5)设备

点对点通信:只有两个设备。

多设备通信:可以在总线上挂载多个设备。

串口通信

串口是一种应用十分广泛的通讯接口,串口成本低、容易使用、通信线路简单,可实现两个设备的互相通信

单片机的串口可以使单片机与单片机、单片机与电脑、单片机与各式各样的模块互相通信,极大地扩展了单片机的应用范围,增强了单片机系统的硬件实力。

UART通信

通用异步收发协议(Universal Asynchronous Receiver Transmitter,UART)

(1)分层思想

物理信号层,规定了硬件电路的设计规则、用户使用的接线方式、线路上传输信号与电平格式对应关系、波特率比特率、数据同步异步传输、收发模式等内容。

链路传输层,规定了地址(ID)、冲突检测与避免(仲裁)、误码校验、滤波器与掩码、该层的帧格式。

应用数据层是被传输的数据主体;链路层把应用层的数据拿来,加上相关的地址、校验等信息封装;物理层把链路层的数据拿来,编码成物理信号传输出去。

(2)硬件电路引脚

两个模块点对点通信

在两模块已供电的情况下,总共需要三根线即可

Rx,Receiver,接收端

Tx,Transmitter,发送端

GND,两模块需要共地,这样才可以区分出Rx和Tx两根线上电平的高低

TX与RX要交叉连接

当只需单向的数据传输时,可以只接一根通信线

当电平标准不一致时,需要加电平转换芯片

image.png

(3)信号与电平格式

很直观的信号传输格式,传输0/1码元

高电平代表1,低电平代表0

单片机中高电平是3.3V,低电平是0V

在通信和数据存储领域,二进制码元和有效信息码元是两个重要的概念。它们在确保数据传输的准确性和效率方面发挥着关键作用。

电平标准是数据1和数据0的表达方式,是传输线缆中人为规定的电压与数据的对应关系,串口常用的电平标准有如下三种:

TTL电平:+3.3V或+5V表示1,0V表示0

RS232电平:-3-15V表示1,+3+15V表示0

RS485电平:两线压差+2+6V表示1,-2-6V表示0(差分信号)

(4)串口参数

二进制码元是指在二进制系统中使用的符号,通常包括0和1两个数字。在计算机和其他数字系统中,所有的数据和指令都是通过这两个基本的二进制数字来表示的。二进制系统是信息处理的基础,因为它简化了数据的表示和处理过程。

有效信息码元是指在数据传输或存储过程中,实际携带有用信息的码元。这些码元不仅仅是用于表示数据,还包括了用于确保数据完整性和准确性的校验码、同步码等。有效信息码元是通信系统设计中的一个重要方面,因为它们直接影响到数据传输的效率和可靠性。有效信息码元是基于二进制码元构建的。在设计通信系统时,工程师会使用二进制码元来构建能够传输有效信息的码元。这些有效信息码元可能包括数据码元、控制码元和特殊码元等,它们共同确保了数据的正确传输和接收。

比特率,bit/s,bps

每秒钟传输的二进制码元的数量,越高意味着数据传输的越快。

在二进制调制下,一个码元就是一个bit,此时波特率=比特率(若是多进制则不同)

波特率,symbol/s

规定串口通信的速率,单位:码元/s,波特(Baud)。

每秒钟传输的有效信息码元的数量,描述信号的变化频率

UART通信中,比特率等于波特率,因为有效信息码元直接对应二进制的0/1码元十。

六进制字符编码中,如果一秒传输1000个字符,每个字符对应一种唯一的电平信号,那么波特率就是1000symbol/s;由于一个十六进制字符要用四位二进制编码表示,那么它的比特率就是4000bit/s。

ps:若波特率=1000dps,意思是1s发送1000位,每一位就是1ms

发送1ms发送一位,接收方每隔1ms接收一位。

(5)时序

起始位(1位):标志一个数据帧的开始,固定为低电平。空闲状态默认高电平。

数据位(8位):数据帧的有效载荷,1为高电平,0为低电平,低位先行。

example:发送0x0F ——>0000 1111 低位先行,需要从1开始发送1111 0000

校验位(1位):用于数据验证,根据数据位计算得来

使用奇偶校验

无校验 奇校验 偶校验

奇校验:包括校验位在内的9位数据会出现奇数个1(保证1为奇数个)。

偶校验:包括校验位在内的9位数据会出现偶数个1(保证1为偶数个)。

CRC校验(更好用)

停止位(1位):用于数据帧间隔,固定为高电平(为下一个起始位做准备),校验位在有效载荷后面,占一位。

(6)STM32内部的USART外设

USART是STM32内部集成的硬件外设,可根据数据寄存器的一个字节数据自动生成数据帧时序,从TX引脚发送出去,也可自动接收RX引脚的数据帧时序,拼接为一个字节数据,存放在数据寄存器里。

自带波特率发生器,最高达4.5Mbits/s

可配置数据位长度(8/9)、停止位长度(0.5/1/1.5/2)【决定了帧的间隔】

可选校验位(无校验/奇校验/偶校验)

支持同步模式、硬件流控制、DMA、智能卡、IrDA、LIN

STM32F103C8T6 USART资源: USART1、 USART2、 USART3

接收器控制:

TXE发送寄存器空,RXNE接受寄存器非空

判断发送状态和接受状态的必要标志位

波特率发生器:

分频器

image.png

image.png

数据帧

image.png

16倍帧侦测起始位

发送器和接收器的波特率由波特率寄存器BRR里的DIV确定

计算公式:波特率 = fPCLK2/1 / (16 * DIV)

如果要配置波特率为9600,那么BRR寄存器配置

USART的时钟为72M

9600=72/16*DIV,解得DIV

USB标准供电是5v

(8)链路传输

冲突检测与避免是计算机网络中用于解决多个设备在同一通信介质上发送数据时可能出现的冲突问题的重要技术。在计算机网络中,特别是在使用共享介质的局域网(LAN)中,冲突是不可避免的,因为多个设备可能会尝试在同一时间通过同一通信介质发送数据。

(9)仲裁

仲裁是计算机网络和分布式系统中用于解决资源竞争问题的一种机制。当多个设备或进程同时请求访问同一资源时,仲裁确保了对资源的访问是有序的,避免了冲突和死锁,保证了系统的稳定性和效率。

(11)阻塞/中断/DMA中断

阻塞式通信

发送:MCU一个字节一个字节送给外设,让外设一个一个发过去,MCU与此同时不能干别的,比较迟钝。

接收:傻等着,和EXTI那节一开始讲的那个只会吃饭睡觉打豆豆的大冤种一样,等东西来了之后我再一个字节一个字节接收 中断式通信。

需要在cubemx中配置这个:

image.png

MCU送一个字节给外设,外设发完一个之后告诉MCU,MCU这时候让它发下一个。

接收:学聪明了,对方给我发消息,我产生一个中断事件,然后MCU看到中断事件了再一个字节一个字节接收。

DMA中断通信

直接内存访问(Direct Memory Access,DMA),不产生数据,只是数据的搬运工。

发送:MCU把指定要发送的数据的起始地址与长度告诉DMA,DMA帮忙搬运给外设,发完了告诉MCU。

接收:MCU告诉DMA去把外设发给单片机的消息搬到指定位置。当然要告诉DMA接收方式,比如是等MCU通知(代码主动调用)搬运还是一直搬运(直接配置不让DMA停下来)等等。搬运完成会触发相应的中断事件。

UART总结(HAL)

阻塞式

(串口,收/发,字节长度,时间)

1
HAL_UART_Transmit(&huart1, TxData, 5, 1000);//发HAL_UART_Receive(&huart1, RxData, 5, 1000);//收

中断式(使能中断)

1
2
3
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){};
HAL_UART_Transmit_IT(&huart1, TxData, 5);
HAL_UART_Receive_IT(&huart1, RxData, 5);

空闲中断(使能中断)

1
2
3
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){};
HAL_UART_Transmit_IT(&huart1, TxData, 5);
HAL_UARTEx_ReceiveToIdle_IT(&huart1, RxData, 5);

DMA中断(配置DMA且使能中断)

1
2
3
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){};
HAL_UART_Transmit_DMA(&huart1, TxData, 5);
HAL_UART_Receive_DMA(&huart1, RxData, 5);

DMA空闲中断(配置DMA且使能中断)

1
2
3
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size){};
HAL_UART_Transmit_DMA(&huart1, TxData, 5);
HAL_UARTEx_ReceiveToIdle_DMA(&huart1, RxData, 5);

CAN通信

I2C通信

让两个模块实现通信,单片机读写外部寄存器

HEX数据包

第一个字节代表读写

0写数据包,1读数据包

第二个字节代表读写的地址

第三个字节代表写入的数据

异步时序

同步时序

SCL和SDA

硬件电路链接,输入输出端口配置

软件定义时序

(1)I2C

I2C(Inter IC Bus)是由Philips公司开发的一种通用数据总线

两根通信线:SCL(Serial Clock)、SDA(Serial Data)

同步,半双工

带数据应答

支持总线挂载多设备(一主多从、多主多从)

(2)硬件规定

所有I2C设备的SCL连在一起,SDA连在一起

设备的SCL和SDA均要配置成开漏输出模式

SCL和SDA各添加一个上拉电阻,阻值一般为4.7KΩ左右

(3)I2C时序基本单元

起始条件:SCL高电平期间,SDA从高电平切换到低电平

终止条件:SCL高电平期间,SDA从低电平切换到高电平

发送一个字节:SCL低电平期间,主机将数据位依次放到SDA线上(高位先行),然后释放SCL,从机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可发送一个字节

接收一个字节:SCL低电平期间,从机将数据位依次放到SDA线上(高位先行),然后释放SCL,主机将在SCL高电平期间读取数据位,所以SCL高电平期间SDA不允许有数据变化,依次循环上述过程8次,即可接收一个字节(主机在接收之前,需要释放SDA)

发送应答:主机在接收完一个字节之后,在下一个时钟发送一位数据,数据0表示应答,数据1表示非应答

接收应答:主机在发送完一个字节之后,在下一个时钟接收一位数据,判断从机是否应答,数据0表示应答,数据1表示非应答(主机在接收之前,需要释放SDA)

(4)MPU6050

是一个6轴姿态传感器,可以测量芯片自身X、Y、Z轴的加速度、角速度参数,通过数据融合,可进一步得到姿态角,常应用于平衡车、飞行器等需要检测自身姿态的场景

3轴加速度计(Accelerometer):测量X、Y、Z轴的加速度

3轴陀螺仪传感器(Gyroscope):测量X、Y、Z轴的角速度

代码逻辑

(1)起始条件

先将SCL和SDA都输出1

先拉低SDA,再拉低SCL;

先释放SDA,再释放SCL

循环上述

(2)终止条件

拉低SDA

释放SCL,释放SDA,同时回到高电平

(3)发送一个字节

低电平——变换数据

高电平——保持数据稳定

且高位先行

每放一位执行:释放SCL,拉低SCL

相与运算

全1为1,有0则0

SDA低电平变换数据,高电平读取数据。

(4)接受一个字节

主机释放SDA,从机释放SCL,把数据放上去

(5)发送应答和接受应答

发送/接收一个字节的简化版(1位)

(6)加速度和陀螺仪

分别读取6个轴数据寄存器的高位和低位,拼接成16位数据,再通过指针变量返回。

代码main.c里的

&AX,&AY,&AZ代表三个轴的加速度

&GX,&GY,&GZ代表三个轴的角速度

MyI2C.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
#include "stm32f10x.h"                  // Device header
#include "Delay.h"
//写SCL引脚电平
void MyI2C_W_SCL(uint8_t BitValue)
{
GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);
Delay_us(10
}
//写SDA引脚电平
void MyI2C_W_SDA(uint8_t BitValue)
{
GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue);
Delay_us(10);
}
//读SDA引脚电平
uint8_t MyI2C_R_SDA(void)
{
uint8_t BitValue;
BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
Delay_us(10);
return BitValue;//返回SDA电平
}

//I2C初始化
void MyI2C_Init(void)
{
/*开启时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/*GPIO初始化*/
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);
}

//I2C起始
void MyI2C_Start(void)
{
MyI2C_W_SDA(1); //释放SDA,确保SDA为高电平
MyI2C_W_SCL(1); //释放SCL,确保SCL为高电平
MyI2C_W_SDA(0); //在SCL高电平期间,拉低SDA,产生起始信号
MyI2C_W_SCL(0); //起始后把SCL也拉低,即为了占用总线,也为了方便总线时序的拼接
}

//I2C终止
void MyI2C_Stop(void)
{
MyI2C_W_SDA(0);//拉低SDA,确保SDA为低电平
MyI2C_W_SCL(1);//释放SCL,使SCL呈现高电平
MyI2C_W_SDA(1);//在SCL高电平期间,释放SDA,产生终止信号
}

//I2C发送一个字节
void MyI2C_SendByte(uint8_t Byte)
{
uint8_t i;
for (i = 0; i < 8; i ++)//循环8次,主机依次发送数据的每一位
{
MyI2C_W_SDA(Byte & (0x80 >> i));//使用掩码的方式取出Byte的指定一位数据并写入到SDA线
MyI2C_W_SCL(1); //释放SCL,从机在SCL高电平期间读取SDA
MyI2C_W_SCL(0); //拉低SCL,主机开始发送下一位数据
}
}

//I2C接收一个字节
uint8_t MyI2C_ReceiveByte(void)
{
uint8_t i, Byte = 0x00; //定义接收的数据,并赋初值0x00,此处必须赋初值0x00,后面会用到
MyI2C_W_SDA(1);//接收前,主机先确保释放SDA,避免干扰从机的数据发送
for (i = 0; i < 8; i ++)//循环8次,主机依次接收数据的每一位
{
MyI2C_W_SCL(1); //释放SCL,主机机在SCL高电平期间读取SDA
if (MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);}
//读取SDA数据,并存储到Byte变量
//当SDA为1时,置变量指定位为1,当SDA为0时,不做处理,指定位为默认的初值0
MyI2C_W_SCL(0); //拉低SCL,从机在SCL低电平期间写入SDA
}
return Byte;
//返回接收到的一个字节数据
}

//I2C发送应答位
void MyI2C_SendAck(uint8_t AckBit)
{
MyI2C_W_SDA(AckBit);//主机把应答位数据放到SDA线
MyI2C_W_SCL(1); //释放SCL,从机在SCL高电平期间,读取应答位
MyI2C_W_SCL(0); //拉低SCL,开始下一个时序模块
}

//I2C接收应答位
uint8_t MyI2C_ReceiveAck(void)
{
uint8_t AckBit; //定义应答位变量
MyI2C_W_SDA(1); //接收前,主机先确保释放SDA,避免干扰从机的数据发送
MyI2C_W_SCL(1); //释放SCL,主机机在SCL高电平期间读取SDA
AckBit = MyI2C_R_SDA(); //将应答位存储到变量里
MyI2C_W_SCL(0); //拉低SCL,开始下一个时序模块
return AckBit; //返回定义应答位变量
}

MPU6050.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include "stm32f10x.h"                  // Device header
#include "MyI2C.h"
#include "MPU6050_Reg.h"

#define MPU6050_ADDRESS 0xD0 //MPU6050的I2C从机地址

/**
* 函 数:MPU6050写寄存器
* 参 数:RegAddress 寄存器地址,范围:参考MPU6050手册的寄存器描述
* 参 数:Data 要写入寄存器的数据,范围:0x00~0xFF
* 返 回 值:无
*/
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
MyI2C_Start(); //I2C起始
MyI2C_SendByte(MPU6050_ADDRESS); //发送从机地址,读写位为0,表示即将写入
MyI2C_ReceiveAck(); //接收应答
MyI2C_SendByte(RegAddress); //发送寄存器地址
MyI2C_ReceiveAck(); //接收应答
MyI2C_SendByte(Data); //发送要写入寄存器的数据
MyI2C_ReceiveAck(); //接收应答
MyI2C_Stop(); //I2C终止
}

/**
* 函 数:MPU6050读寄存器
* 参 数:RegAddress 寄存器地址,范围:参考MPU6050手册的寄存器描述
* 返 回 值:读取寄存器的数据,范围:0x00~0xFF
*/
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
uint8_t Data;

MyI2C_Start(); //I2C起始
MyI2C_SendByte(MPU6050_ADDRESS); //发送从机地址,读写位为0,表示即将写入
MyI2C_ReceiveAck(); //接收应答
MyI2C_SendByte(RegAddress); //发送寄存器地址
MyI2C_ReceiveAck(); //接收应答

MyI2C_Start(); //I2C重复起始
MyI2C_SendByte(MPU6050_ADDRESS | 0x01); //发送从机地址,读写位为1,表示即将读取
MyI2C_ReceiveAck(); //接收应答
Data = MyI2C_ReceiveByte(); //接收指定寄存器的数据
MyI2C_SendAck(1); //发送应答,给从机非应答,终止从机的数据输出
MyI2C_Stop(); //I2C终止

return Data;
}

/**
* 函 数:MPU6050初始化
* 参 数:无
* 返 回 值:无
*/
void MPU6050_Init(void)
{
MyI2C_Init(); //先初始化底层的I2C

/*MPU6050寄存器初始化,需要对照MPU6050手册的寄存器描述配置,此处仅配置了部分重要的寄存器*/
MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01); //电源管理寄存器1,取消睡眠模式,选择时钟源为X轴陀螺仪
MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00); //电源管理寄存器2,保持默认值0,所有轴均不待机
MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09); //采样率分频寄存器,配置采样率
MPU6050_WriteReg(MPU6050_CONFIG, 0x06); //配置寄存器,配置DLPF
MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18); //陀螺仪配置寄存器,选择满量程为±2000°/s
MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18); //加速度计配置寄存器,选择满量程为±16g
}

/**
* 函 数:MPU6050获取ID号
* 参 数:无
* 返 回 值:MPU6050的ID号
*/
uint8_t MPU6050_GetID(void)
{
return MPU6050_ReadReg(MPU6050_WHO_AM_I); //返回WHO_AM_I寄存器的值
}

//MPU6050获取数据

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; //定义数据高8位和低8位的变量

DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H); //读取加速度计X轴的高8位数据
DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L); //读取加速度计X轴的低8位数据
*AccX = (DataH << 8) | DataL; //数据拼接,通过输出参数返回

DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H); //读取加速度计Y轴的高8位数据
DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L); //读取加速度计Y轴的低8位数据
*AccY = (DataH << 8) | DataL; //数据拼接,通过输出参数返回

DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H); //读取加速度计Z轴的高8位数据
DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L); //读取加速度计Z轴的低8位数据
*AccZ = (DataH << 8) | DataL; //数据拼接,通过输出参数返回

DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H); //读取陀螺仪X轴的高8位数据
DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L); //读取陀螺仪X轴的低8位数据
*GyroX = (DataH << 8) | DataL; //数据拼接,通过输出参数返回

DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H); //读取陀螺仪Y轴的高8位数据
DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L); //读取陀螺仪Y轴的低8位数据
*GyroY = (DataH << 8) | DataL; //数据拼接,通过输出参数返回

DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H); //读取陀螺仪Z轴的高8位数据
DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L); //读取陀螺仪Z轴的低8位数据
*GyroZ = (DataH << 8) | DataL; //数据拼接,通过输出参数返回
}

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "MPU6050.h"

uint8_t ID; //定义用于存放ID号的变量
int16_t AX, AY, AZ, GX, GY, GZ; //定义用于存放各个数据的变量

int main(void)
{
/*模块初始化*/
MPU6050_Init(); //MPU6050初始化

/*显示ID号*/
OLED_ShowString(1, 1, "ID:"); //显示静态字符串
ID = MPU6050_GetID(); //获取MPU6050的ID号
OLED_ShowHexNum(1, 4, ID, 2); //OLED显示ID号

while (1)
{
MPU6050_GetData(&AX, &AY, &AZ, &GX, &GY, &GZ);//获取MPU6050的数据
}
}

SPI通信

(Serial Peripheral Interface)

一主多从

四根通信线:SCK-串行时钟线(Serial Clock)、MOSI-主机输出从机输入(Master Output Slave Input)、MISO-主机输入从机输出(Master Input Slave Output)、SS-从机选择(Slave Select)

同步,全双工

连接W25Q64

CLK-SCK

DI-MOSI

DO-MISO