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

北京站如何做游戏网站

北京站,如何做游戏网站,网络舆情监控,网站建设官方商城注:2025年4月4日23:53已经修复本篇文章代码bug,bug已经修复,现在可以正常无误使用 前言 用是最好的学,学习了IIC协议的知识,那么我的要去使用他才更方便我们去理解,本篇文章会给出.c和.h的文件&#xff0c…

注:2025年4月4日23:53已经修复本篇文章代码bug,bug已经修复,现在可以正常无误使用

前言

用是最好的学,学习了IIC协议的知识,那么我的要去使用他才更方便我们去理解,本篇文章会给出.c和.h的文件,直接复制粘贴,直接修改引脚和主频,就可以直接使用这套代码区读MPU6050。

IIC和MPU6050这篇文章有点长,所以我分为上中下篇

上篇主要讲解IIC协议和基本使用,获取MPU6050的ID

中篇主要讲解MPU6050模块的使用

下篇主要是硬件IIC驱动MPU6050

IIC协议的简介

IIC协议的优点是两根信号线就可以对多个设备进行通信,缺点是通信速度慢,刚好跟SPI相反。

然后IIC有软件和硬件,软件的话直接用我这套代码就好了。

理解IIC协议的核心就是

SCL为高的时候,SDA会被读取或者使用,此时SDA不能改变

SCL为低的时候,SDA可以变化高低电平来准备下一次SCL为高的时候要用的电平

本篇文章是结合AI协作完成

IIC协议的基本框架 

IIC主要有起始,停止,发送一个字节,接受一个字节,应答信号,接下来我们逐一分析

IIC协议的基本框架完整的.c和.h文件在本小结后面会有,不想看分析的可以直接跳过

1.延时

IIC一般有个几微妙的延时,但是我们在使用HAL库的时候,只有毫秒级的延时,所以这个我们要自己编写

void delay_us(uint32_t us) {uint32_t i;for (i = 0; i < us * (SYSTEM_MAX); i++) {__asm("nop");}
}

其中SYSTEM_MAX是系统主频

2.定义引脚状态

// 定义 SCL 和 SDA 引脚
#define SOFT_IIC_SCL_PORT GPIOA  // 请根据实际情况修改
#define SOFT_IIC_SCL_PIN GPIO_PIN_4  // 请根据实际情况修改
#define SOFT_IIC_SDA_PORT GPIOA  // 请根据实际情况修改
#define SOFT_IIC_SDA_PIN GPIO_PIN_5  // 请根据实际情况修改

  头文件出加的定义,确定好哪个引脚,这样可以跳过cubemx的配置

// 设置 SCL 引脚电平,并添加延时
void IIC_SCL_(uint8_t state) {if (state)HAL_GPIO_WritePin(SOFT_IIC_SCL_PORT, SOFT_IIC_SCL_PIN, GPIO_PIN_SET);elseHAL_GPIO_WritePin(SOFT_IIC_SCL_PORT, SOFT_IIC_SCL_PIN, GPIO_PIN_RESET);delay_us(5);
}// 设置 SDA 引脚电平,并添加延时
void IIC_SDA_(uint8_t state) {if (state)HAL_GPIO_WritePin(SOFT_IIC_SDA_PORT, SOFT_IIC_SDA_PIN, GPIO_PIN_SET);elseHAL_GPIO_WritePin(SOFT_IIC_SDA_PORT, SOFT_IIC_SDA_PIN, GPIO_PIN_RESET);delay_us(5);
}// 读取 SDA 引脚电平
uint8_t IIC_SDA_Read(void) {return HAL_GPIO_ReadPin(SOFT_IIC_SDA_PORT, SOFT_IIC_SDA_PIN);
}

软件模拟高低电平,然后只有SDA需要读的操作

3.引脚初始化

// I2C 初始化
void IIC_Init(void) {GPIO_InitTypeDef GPIO_InitStruct = {0};// 使能 SCL 和 SDA 引脚所在端口的时钟__HAL_RCC_GPIOA_CLK_ENABLE();  // 请根据实际情况修改// 配置 SCL 引脚GPIO_InitStruct.Pin = SOFT_IIC_SCL_PIN;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(SOFT_IIC_SCL_PORT, &GPIO_InitStruct);// 配置 SDA 引脚GPIO_InitStruct.Pin = SOFT_IIC_SDA_PIN;HAL_GPIO_Init(SOFT_IIC_SDA_PORT, &GPIO_InitStruct);// 初始状态:SCL 和 SDA 都为高电平IIC_SCL_(1);IIC_SDA_(1);
}

IIC使用的是开漏输出

4.起始信号

// 发送起始信号
void IIC_Start(void) {IIC_SDA_(1);IIC_SCL_(1);IIC_SDA_(0);IIC_SCL_(0);
}

SDA先下降,SCL后下降

5.终止信号


// 发送停止信号
void IIC_Stop(void) {IIC_SCL_(0);IIC_SDA_(0);IIC_SCL_(1);IIC_SDA_(1);
}

SCL先升高,SDA后升高

6.发送一个字节

// 发送一个字节
void IIC_SendByte(uint8_t data) {uint8_t i;for (i = 0; i < 8; i++) {IIC_SDA_((data & 0x80) >> 7);data <<= 1;IIC_SCL_(1);IIC_SCL_(0);}
}

当SCL为高的时候,SDA会被读取,此时SDA不能改变

当SCL为低的时候,SDA才能变化

7.等待应答

// 等待应答信号
uint8_t IIC_WaitAck(void) {uint8_t ack;IIC_SDA_(1);IIC_SCL_(1);ack = IIC_SDA_Read();IIC_SCL_(0);return ack;
}

每当主机向从机发送完一个字节的数据,主机总是需要等待从机给出一个应答信号,以确认从机是否成功接收到了数据

8.接收一个字节

// 接收一个字节
uint8_t IIC_ReceiveByte(uint8_t ack) {uint8_t i, data = 0;IIC_SDA_(1);  // 释放 SDA 线for (i = 0; i < 8; i++) {IIC_SCL_(1);data <<= 1;if (IIC_SDA_Read())data |= 0x01;IIC_SCL_(0);}if (ack)IIC_SDA_(0);  // 发送应答elseIIC_SDA_(1);  // 发送非应答IIC_SCL_(1);IIC_SCL_(0);return data;
}

在读取完后发送一个应答信号,SDA为0是应答,1是非应答

MPU6050模块简介

在编写完IIC框架后,我们开始来使用IIC读取MPU6050的数据

MPU6050 是一款常见的 6轴惯性测量单元(IMU),集成了 三轴加速度计 和 三轴陀螺仪 于单一芯片,可同时测量物体在 X、Y、Z 三个方向的 加速度 和绕这三轴的 角速度 

一般我们就是用来当陀螺仪使用,主要是获取角度

MPU6050的读取过程

1.初始化引脚

// MPU6050 初始化函数
uint8_t MPU6050_Init(void) {IIC_Init();  // 初始化 I2C 总线return 0;
}

没有返回说明卡死了 

2.获取ID地址

       一般IIC模块都有多个地址,其中看某些特定引脚的电平

        MPU605默认是0x68,当AD0为低的时候

        如果AD0接高电平,那么地址就为0x69

        

// 定义 MPU6050 设备地址
#define MPU6050_ADDR_AD0_LOW 0x68  // AD0 引脚接地时的地址
#define MPU6050_ADDR_AD0_HIGH 0x69 // AD0 引脚接高电平时的地址// 定义 MPU6050 寄存器地址
#define MPU6050_WHO_AM_I_REG 0x75  // 设备 ID 寄存器地址

 .h处定义的

通信过程(详细讲解基本通信过程)

1.主机发出通信请求,让所有连接在这条总线上的模块做好通信准备

主机:所有人,听我叫编号

挂载在设备上的模块都做好倾听准备

让所有模块准备

  // 发送起始信号IIC_Start();

2.主机先发送将要通信的地址

主机:0x68这个编号是谁?在这里吗?

此时是询问挂载在这条总线上是否存在0x68这个地址对应的模块

第一位为0代表是写命令

    // 发送 MPU6050 写地址IIC_SendByte((MPU6050_ADDR_AD0_LOW << 1) | 0);

 3.主机等待挂载众设备的回应

主机:等待回应   

这时候有模块举手了

MPU6050把手高高举起

没有就说明这个编号的人不在这里,那么说明自己没有让这个加入或者找错编号了

    // 等待应答if (IIC_WaitAck()) {IIC_Stop();return 0xFF; // 错误返回}

4.主机发出读取寄存器的指令
主机:0x68是你是吧,现在请把你的身份证给我看看吧!

每个模块都有唯一ID,就是身份证

当上一条,3处有回应后,这时候的IIC通信只有主机和MPU6050模块,其他模块都不能插嘴

这时候把

    // 发送要读取的寄存器地址IIC_SendByte(MPU6050_WHO_AM_I_REG);

5.主机发出指令后,等待从机接收到指令的回应

主机等待MPU6050模块是否听到了问题

MPU6050回应了个OK

用来判断是否接收到了指令

    // 等待应答if (IIC_WaitAck()) {IIC_Stop();return 0xFF; // 错误返回}
6.主机切换成读模式

主机:刚才我问的你们只能做手势回答,我要换一下我的问答方式,接下来我问的你们可以说话回答了。那个,MPU6050,刚才你说你的地址是0X68,请把你的身份证拿出来给我们看看呗

主机切换成读模式,1代表读

      // 重新发送起始信号以进行读操作IIC_Start();// 发送 MPU6050 读地址IIC_SendByte((MPU6050_ADDR_AD0_LOW << 1) | 1);

7.主机等待从机回应

MPU6050此时给了个OK的手势

    // 等待应答if (IIC_WaitAck()) {IIC_Stop();return 0xFF; // 错误返回}

8.读取ID设备

这时候MPU6050把身份证拿出来给主机看,主机逐一读取

获取8位返回值

因为数据手册表明地址就是8位

所以读完后就可以获得我们想要的数据了

此时就可以结束通话了

 // 读取设备 IDdevice_id = IIC_ReceiveByte(0); // 最后一个字节不需要应答// 发送停止信号IIC_Stop();

单独完整获取ID的.c和.h代码

MPU6050.c

#include "MPU6050.h"// MPU6050 初始化函数
uint8_t MPU6050_Init(void) {IIC_Init();  // 初始化 I2C 总线return 0;
}// 获取 MPU6050 设备 ID
uint8_t MPU6050_GetDeviceID(void) {uint8_t device_id = 0;// 发送起始信号IIC_Start();// 发送 MPU6050 写地址IIC_SendByte((MPU6050_ADDR_AD0_LOW << 1) | 0);// 等待应答if (IIC_WaitAck()) {IIC_Stop();return 0xFF; // 错误返回}// 发送要读取的寄存器地址IIC_SendByte(MPU6050_WHO_AM_I_REG);// 等待应答if (IIC_WaitAck()) {IIC_Stop();return 0xFF; // 错误返回}// 重新发送起始信号以进行读操作IIC_Start();// 发送 MPU6050 读地址IIC_SendByte((MPU6050_ADDR_AD0_LOW << 1) | 1);// 等待应答if (IIC_WaitAck()) {IIC_Stop();return 0xFF; // 错误返回}// 读取设备 IDdevice_id = IIC_ReceiveByte(0); // 最后一个字节不需要应答// 发送停止信号IIC_Stop();return device_id;
}

MPU6050.H

#ifndef __MPU6050_H
#define __MPU6050_H#include "SOFT_IIC.h"// 定义 MPU6050 设备地址
#define MPU6050_ADDR_AD0_LOW 0x68  // AD0 引脚接地时的地址
#define MPU6050_ADDR_AD0_HIGH 0x69 // AD0 引脚接高电平时的地址// 定义 MPU6050 寄存器地址
#define MPU6050_WHO_AM_I_REG 0x75  // 设备 ID 寄存器地址// 函数声明
uint8_t MPU6050_Init(void);
uint8_t MPU6050_GetDeviceID(void);#endif

3.优化代码

根据上述的通信流程,我们可以根据框架,然后编写一个专门的代码,当传入地址,数据寄存器,和指令后,就可以返回我们需要的值


// 向 MPU6050 写入一个字节数据
void IIC_Write_REG(uint8_t addr, uint8_t reg, uint8_t data) {IIC_Start();IIC_SendByte((addr << 1) | 0);  // 发送写地址IIC_WaitAck();IIC_SendByte(reg);  // 发送寄存器地址IIC_WaitAck();IIC_SendByte(data);  // 发送数据IIC_WaitAck();IIC_Stop();
}uint8_t IIC_Read_REG(uint8_t Address,uint8_t regaddress) {uint8_t data;IIC_Start();  // 发送起始信号IIC_SendByte(Address<<1|0);  // 发送设备地址和写操作IIC_WaitAck();  // 等待 ACKIIC_SendByte(regaddress);  // 发送寄存器地址IIC_WaitAck();  // 等待 ACKIIC_Start();  // 发送起始信号IIC_SendByte(Address<<1|1);  // 发送设备地址和读操作IIC_WaitAck();  // 等待 ACKdata = IIC_ReceiveByte(0);  // 读取数据IIC_Stop();  // 发送停止信号return data;  // 返回读取的数据	
}

此时我们只需要对上述框架封装使用即可 

#define WHO_AM_I     0x75 	// IIC地址寄存器(默认数值0x68,只读) */// HAL库的读写只需要使用7位地址
#define MPU6050_ADDR_AD0_LOW 0x68	// AD0低电平时7位地址为0X68 iic写时许发送0XD0// 读取 MPU6050 的设备 ID
uint8_t MPU6050_GetDeviceID(void) {uint8_t data;data=IIC_Read_REG(MPU6050_ADDR_AD0_LOW, WHO_AM_I);  // 读取设备 ID 寄存器return data;  // 返回设备 ID	
}

使用这个代码框架后,我们就可以容易对多个设备获取值

此时的完整代码为

soft_iic.c

#include "SOFT_IIC.h"// 延时函数,单位:微秒
// 假设系统频率为 80MHz
void delay_us(uint32_t us) {uint32_t i;for (i = 0; i < us * SYSTEM_MAX ; i++) {__asm("nop");}
}// 设置 SCL 引脚电平,并添加延时
void IIC_SCL_(uint8_t state) {if (state)HAL_GPIO_WritePin(SOFT_IIC_SCL_PORT, SOFT_IIC_SCL_PIN, GPIO_PIN_SET);elseHAL_GPIO_WritePin(SOFT_IIC_SCL_PORT, SOFT_IIC_SCL_PIN, GPIO_PIN_RESET);delay_us(5);
}// 设置 SDA 引脚电平,并添加延时
void IIC_SDA_(uint8_t state) {if (state)HAL_GPIO_WritePin(SOFT_IIC_SDA_PORT, SOFT_IIC_SDA_PIN, GPIO_PIN_SET);elseHAL_GPIO_WritePin(SOFT_IIC_SDA_PORT, SOFT_IIC_SDA_PIN, GPIO_PIN_RESET);delay_us(5);
}// 读取 SDA 引脚电平
uint8_t IIC_SDA_Read(void) {return HAL_GPIO_ReadPin(SOFT_IIC_SDA_PORT, SOFT_IIC_SDA_PIN);
}// I2C 初始化
void IIC_Init(void) {GPIO_InitTypeDef GPIO_InitStruct = {0};// 使能 SCL 和 SDA 引脚所在端口的时钟__HAL_RCC_GPIOA_CLK_ENABLE();  // 请根据实际情况修改// 配置 SCL 引脚GPIO_InitStruct.Pin = SOFT_IIC_SCL_PIN;GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;GPIO_InitStruct.Pull = GPIO_PULLUP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;HAL_GPIO_Init(SOFT_IIC_SCL_PORT, &GPIO_InitStruct);// 配置 SDA 引脚GPIO_InitStruct.Pin = SOFT_IIC_SDA_PIN;HAL_GPIO_Init(SOFT_IIC_SDA_PORT, &GPIO_InitStruct);// 初始状态:SCL 和 SDA 都为高电平IIC_SCL_(1);IIC_SDA_(1);
}// 发送起始信号
void IIC_Start(void) {IIC_SDA_(1);IIC_SCL_(1);IIC_SDA_(0);IIC_SCL_(0);
}// 发送停止信号
void IIC_Stop(void) {IIC_SCL_(0);IIC_SDA_(0);IIC_SCL_(1);IIC_SDA_(1);
}// 发送一个字节
void IIC_SendByte(uint8_t data) {uint8_t i;for (i = 0; i < 8; i++) {IIC_SDA_((data & 0x80) >> 7);data <<= 1;IIC_SCL_(1);IIC_SCL_(0);}
}// 接收一个字节
uint8_t IIC_ReceiveByte(uint8_t ack) {uint8_t i, data = 0;IIC_SDA_(1);  // 释放 SDA 线for (i = 0; i < 8; i++) {IIC_SCL_(1);data <<= 1;if (IIC_SDA_Read())data |= 0x01;IIC_SCL_(0);}if (ack)IIC_SDA_(0);  // 发送应答elseIIC_SDA_(1);  // 发送非应答IIC_SCL_(1);IIC_SCL_(0);return data;
}// 等待应答信号
uint8_t IIC_WaitAck(void) {uint8_t ack;IIC_SDA_(1);IIC_SCL_(1);ack = IIC_SDA_Read();IIC_SCL_(0);return ack;
}// 向 MPU6050 写入一个字节数据
void IIC_Write_REG(uint8_t addr, uint8_t reg, uint8_t data) {IIC_Start();IIC_SendByte((addr << 1) | 0);  // 发送写地址IIC_WaitAck();IIC_SendByte(reg);  // 发送寄存器地址IIC_WaitAck();IIC_SendByte(data);  // 发送数据IIC_WaitAck();IIC_Stop();
}uint8_t IIC_Read_REG(uint8_t Address,uint8_t regaddress) {uint8_t data;IIC_Start();  // 发送起始信号IIC_SendByte(Address<<1|0);  // 发送设备地址和写操作IIC_WaitAck();  // 等待 ACKIIC_SendByte(regaddress);  // 发送寄存器地址IIC_WaitAck();  // 等待 ACKIIC_Start();  // 发送起始信号IIC_SendByte(Address<<1|1);  // 发送设备地址和读操作IIC_WaitAck();  // 等待 ACKdata = IIC_ReceiveByte(0);  // 读取数据IIC_Stop();  // 发送停止信号return data;  // 返回读取的数据	
}

soft_iic.h

#ifndef __SOFT_IIC_H
#define __SOFT_IIC_H#include "gpio.h"// 定义 SCL 和 SDA 引脚
#define SOFT_IIC_SCL_PORT GPIOA  // 请根据实际情况修改
#define SOFT_IIC_SCL_PIN GPIO_PIN_4  // 请根据实际情况修改
#define SOFT_IIC_SDA_PORT GPIOA  // 请根据实际情况修改
#define SOFT_IIC_SDA_PIN GPIO_PIN_5  // 请根据实际情况修改
#define SYSTEM_MAX 80
// 函数声明
void IIC_Init(void);
void IIC_Start(void);
void IIC_Stop(void);
void IIC_SendByte(uint8_t data);
uint8_t IIC_ReceiveByte(uint8_t ack);
uint8_t IIC_WaitAck(void);
void IIC_Ack(void);
void IIC_NAck(void);
void IIC_Write_REG(uint8_t Address,uint8_t regaddress, uint8_t data);
uint8_t IIC_Read_REG(uint8_t Address,uint8_t regaddress);
// 延时函数声明
void delay_us(uint32_t us);#endif

MPU6050.c

#include "MPU6050.h"
#include "math.h"
#include "SOFT_IIC.h"
#include <stdio.h>
// MPU6050 初始化函数
uint8_t MPU6050_Init(void) {IIC_Init();  // 初始化 I2C 总线HAL_Delay(100);  // 等待传感器稳定return 0;
}// 读取 MPU6050 的设备 ID
uint8_t MPU6050_GetDeviceID(void) {uint8_t data;data=IIC_Read_REG(MPU6050_ADDR_AD0_LOW, WHO_AM_I);  // 读取设备 ID 寄存器return data;  // 返回设备 ID	
}

MPU6050.H

#ifndef __MPU6050_H
#define __MPU6050_H#include "main.h"// HAL库的读写只需要使用7位地址
#define MPU6050_ADDR_AD0_LOW 0x68	// AD0低电平时7位地址为0X68 iic写时许发送0XD0
#define WHO_AM_I     0x75 	// IIC地址寄存器(默认数值0x68,只读) */// 函数声明
uint8_t MPU6050_Init(void);
uint8_t MPU6050_GetDeviceID(void);
#endif

 下篇我们开始讲解MPU6050寄存器,然后去获取角度和角加速度等数据


文章转载自:

http://1CoiT5IJ.pLgbh.cn
http://UjSZEQP2.pLgbh.cn
http://SQjVXqt8.pLgbh.cn
http://41I4Nvzk.pLgbh.cn
http://PXcaSwAn.pLgbh.cn
http://56f15Rlg.pLgbh.cn
http://XoV69S5H.pLgbh.cn
http://NPuxNit8.pLgbh.cn
http://F83TTm6m.pLgbh.cn
http://WaYQTaoy.pLgbh.cn
http://XSy7pTzk.pLgbh.cn
http://VJ6xA1co.pLgbh.cn
http://ejD42mLD.pLgbh.cn
http://lEsIpGaf.pLgbh.cn
http://wXT7O0Ns.pLgbh.cn
http://ywUYKMuY.pLgbh.cn
http://piaQfTXv.pLgbh.cn
http://IJwIiuNj.pLgbh.cn
http://uehUzu8f.pLgbh.cn
http://6ejzzAI5.pLgbh.cn
http://RzBYpQvY.pLgbh.cn
http://Z1tQ52hu.pLgbh.cn
http://iK2L7GRq.pLgbh.cn
http://R9Ln7taY.pLgbh.cn
http://RCbDKXqS.pLgbh.cn
http://4srGLWtz.pLgbh.cn
http://21QNroG3.pLgbh.cn
http://vzIiFLm4.pLgbh.cn
http://ok3WsRfP.pLgbh.cn
http://Tk4OF12q.pLgbh.cn
http://www.dtcms.com/wzjs/662071.html

相关文章:

  • 没有公司做网站可以吗北京网站建立公司
  • 门户网站开发费需入无形资产厦门建设网站制作
  • 洛阳建设企业网站娱乐视频直播网站建设
  • 制作公司网站在公账汇款时用途备注什么刚刚中国突然宣布
  • 商务网站建设的必备功能引擎搜索
  • 百度做任务的网站运营推广是什么工作
  • 洛阳建站优化教程深圳网站设计成功刻
  • seo网站推广电话品质好的客户管理系统
  • 功能型网站 设计大型网站开发公司
  • 网站制作广多元网站
  • 建设网站服务器wordpress更改自定义文章页面
  • 域名查询站长工具好的手表网站
  • 小网站代码百度交易平台
  • 网站dedecms模板怎么查看修改啊经典重庆新闻论坛
  • 商务网站建设中存在的问题asp sqlserver做网站
  • 留住用户网站dell公司网站设计特色
  • 山东汽车行业网站开发成都络迈品牌网站建设
  • 台州网站建设策划湖南搜索引擎推广多少钱
  • 深圳网站建设民治大道英文域名在哪个网站查询
  • 四川建设网站官网目前做网站需要什么cms
  • 网站编辑能在家做平面设计怎么网上接单
  • 国外 网站 设计wordpress主导航菜单
  • 网站有哪些推荐梅州免费建站
  • 网站关键词排名优化推广软件上海注册公司能落户上海吗
  • 注册网站域名需要什么资料医疗器械h5电子商务网站
  • 南阳专业做网站公司哪家好做网站用什么系统较好
  • 静态网站建设开发wordpress auto get rss
  • 行业网站 cms域名和网站的建设实训报告
  • 登录手机网站模板html推广软件app赚钱联盟
  • seo网站分析工具网址seo分析