stm32学习-软件I2C读取MPU6050

news/2024/10/3 4:59:55

接线

SDAPB11
SCLPB10

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);
}
uint8_t MyI2C_R_SDA(void)//读
{uint8_t BitValue;BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);Delay_us(10);return BitValue;
}

I2C初始化

第一步:把SCL和SDA都初始化为开漏输出模式

方法:

1.打开RCC时钟

void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
作用:外设时钟控制(根据外设连接的总线选择要开启的时钟)

2.配置GPIO,将PB10和PB11配置为开漏输出模式

void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
作用:用结构体的参数初始化GPIO。

用法:先定义一个结构体变量,再给变量赋值,最后调用这个函数即可(这个函数就会自动读取结构体的值,然后自动把外设的各个参数配置好)。     

第二步:把SCL和SDA配置为高电平

void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)

作用:用于将指定引脚设置为高电平

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);
}

I2C起始条件

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

配置方法:先拉高SDA,再拉高SCL,然后拉低SDA,最后拉低SCL。

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

 I2C终止条件

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

配置方法:先拉低SDA,再释放SCL,再释放SDA.

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

 I2C发送字节

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

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

小tips:利用按位与的方式取出数据的某一位或某几位

 I2C接收字节

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

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;
}

 I2C发送应答

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

void MyI2C_SendAck(uint8_t AckBit)
{MyI2C_W_SDA(AckBit);MyI2C_W_SCL(1);MyI2C_W_SCL(0);
}

 I2C接收应答

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

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;
}

MPU6050

MPU6050写指令

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();
}

MPU6050读指令

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);MyI2C_Stop();return Data;
}

MPU6050初始化

void MPU6050_Init(void)
{MyI2C_Init();MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);MPU6050_WriteReg(MPU6050_CONFIG, 0x06);MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18);
}

MPU6050得到ID号

uint8_t MPU6050_GetID(void)
{return MPU6050_ReadReg(MPU6050_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;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;
}

例题 

读取MPU6050六个轴的数据

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "OLED.h"
#include "MPU6050.h"uint8_t ID;
int16_t AX, AY, AZ, GX, GY, GZ;int main(void)
{OLED_Init();MPU6050_Init();OLED_ShowString(1, 1, "ID:");ID = MPU6050_GetID();OLED_ShowHexNum(1, 4, ID, 2);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);}
}

有什么不懂的可以私信我哦


https://dhexx.cn/news/show-5395759.html

相关文章

计算机人请记住,这些网站专治不想学,没动力

刷题是计算机专业学生学习过程中一个非常重要的环节&#xff0c;通过刷题&#xff0c;学生可以巩固基础知识&#xff0c;提高解题能力&#xff0c;增强编程能力&#xff0c;准备面试和考试以及增强自信心。因此建议计算机专业的学生要多做题&#xff0c;勤刷题&#xff0c;提高…

PostgreSQL和Oracle的数据类型对比:时间类型 #PG培训

在数据库管理系统中&#xff0c;时间数据类型是非常关键的一部分。时间数据类型的选择和使用直接影响到数据存储、查询效率和应用程序的设计。本文将对比PostgreSQL和Oracle在时间类型方面的实现和特性。 #PG考试#postgresql培训#postgresql考试#postgresql认证 日期和时间类型…

示例:WPF中TreeView自定义TreeNode泛型绑定对象来实现级联勾选

一、目的&#xff1a;在绑定TreeView的功能中经常会遇到需要在树节点前增加勾选CheckBox框&#xff0c;勾选本节点的同时也要同步显示父节点和子节点状态 二、实现 三、环境 VS2022 四、示例 定义如下节点类 public partial class TreeNodeBase<T> : SelectBindable<…

特斯拉、路特斯、中国一汽、毕博、博世等企业将出席中国汽车供应链降碳和可持续国际峰会

由ECV International 举办的2024中国汽车供应链脱碳与可持续国际峰会将于2024年9月23-24日在上海召开。 在本次峰会上&#xff0c;来自全球各地的行业领袖、政策制定者、研究人员和利益相关者将齐聚一堂&#xff0c;商讨对于减少碳排放和促进整个汽车供应链可持续实践至关重要…

蓝卓为中小制造企业注入数字化转型活力

随着劳动力成本上升,原材料价格上涨,企业生产成本逐年增加&#xff0c;市场竞争越来越激烈&#xff0c;传统的中小制造企业面临着巨大的压力。 通过数字化转型应对环境的变化已成为行业共识&#xff0c;在数字化的进程中&#xff0c;中小企业首要考虑生存问题&#xff0c;不能…

btrace:binder_transaction+eBPF+Golang实现通用的Android APP动态行为追踪工具

一、简介&#xff1a; 在进行Android恶意APP检测时&#xff0c;需要进行自动化的行为分析&#xff0c;一般至少包括行为采集和行为分析两个模块。其中&#xff0c;行为分析有基于规则、基于机器学习、基于深度学习甚至基于大模型的方案&#xff0c;各有各的优缺点&#xff0c;不…

记一次java.lang.ClassCastException的java类型转换异常解决方案

一、问题描述 在系统中应用了spring的Cacheable注解功能&#xff0c;首次请求方法没问题&#xff0c;但在二次加载中&#xff0c;会抛出类转换异常&#xff0c;根本原因是&#xff1a;同一个类的加载类不同&#xff0c;既&#xff1a;applicationClassLoader 和 RestartClassL…

【ubuntu】用户添加root权限

添加root用户添加新用户并赋予权限 文件只读&#xff0c;无法更改 rootubuntu-server:/home/ubuntu# vi /etc/sudoers rootubuntu-server:/home/ubuntu# vi /etc/sudoers rootubuntu-server:/home/ubuntu# chmod -R 777 /etc/sudoers rootubuntu-server:/home/ubuntu# vi /et…

服务器部署开源大模型完整教程 Ollama+Gemma+open-webui

现在开源的大模型其实挺多的&#xff0c;今天搭建Gemma这个谷歌开源的大模型&#xff0c;但是你想搭建别的只要你看完你都会了。 介绍 Ollama&#xff1a;一款可以让你在本地快速搭建大模型的工具 官网&#xff1a;https://ollama.com/ github&#xff1a;https://github.c…

Netty中的Reactor模型实现

Netty版本&#xff1a;4.1.17 Reactor模型是Doug Lea在《Scalable IO in Java》提出的&#xff0c;主要是针对NIO的。 其中的主从Reactor模式在Netty中的配置如下&#xff1a; EventLoopGroup bossGroup new NioEventLoopGroup(1); EventLoopGroup workerGroup new NioEv…