STM32—I2C的基本时序,MU6050的ID读取

2024-09-05 11:44

本文主要是介绍STM32—I2C的基本时序,MU6050的ID读取,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

前言

一、I2C基本时序的书写

二、I2C基本时序的代码

1.引脚的初始化

2.起始时序

3.停止时序

4.发送一个字节

5.接收一个字节

6.发送一个应答

7.接收一个应答

三.MU6050的应答

1.先验证下应答功能:

2.读取ID

总结



前言

环境:

芯片:STM32F103C8T6

Keil:V5.24.2.0

模块:MU6050模块


一、I2C基本时序的书写

上章对I2C时序进行了简单的讲解.

这章对代码进行书写.

二、I2C基本时序的代码

1.引脚的初始化

引脚的宏定义

#define GPIO_PORT    GPIOA
#define SCK_GPIO_PIN        GPIO_Pin_10
#define SDA_GPIO_PIN        GPIO_Pin_9

大家根据自己的连接需要,更改上面的宏就行.

void MyI2C_Init(void)//初始化函数
{/*将SCL和SDA引脚初始化为开漏模式*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Pin = SCK_GPIO_PIN | SDA_GPIO_PIN;GPIO_Init(GPIO_PORT, &GPIO_InitStructure);//需要拉高电平GPIO_SetBits(GPIO_PORT,SCK_GPIO_PIN | SDA_GPIO_PIN);
}

2.起始时序

参考上章的内容,起始时序代码如下:

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

1,保证SDA和SCL均在高电平

2.先拉低SDA线

3再拉低SCL线

具体书写的代码:补齐了上面的书写代码,参数0就是输出0.

延时10us是怕更高速度的MCU超过了I2C的频率而设置的.

void MyI2C_W_SCL(uint8_t BitValue)//SCL书写
{GPIO_WriteBit(GPIO_PORT,SCK_GPIO_PIN,(BitAction)BitValue);Delay_us(10);
}
void MyI2C_W_SDA(uint8_t BitValue)//SDA书写
{GPIO_WriteBit(GPIO_PORT,SDA_GPIO_PIN,(BitAction)BitValue);Delay_us(10);
}

3.停止时序

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

参考上章内容,时序是:在SCL高电平时拉高SDA

为什么第一句是将SDA拉低呢?因为在读取时可能会因为从机的拉高而不是低电平.所以这里进行一个防呆处理.

4.发送一个字节

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

 时序说明:

发送一个字节,就是发送一个bit

重复8次

5.接收一个字节

uint8_t MyI2C_ReceiveByte(void)
{uint8_t i,Byte=0x00;//定义变量MyI2C_W_SDA(1);//交出SDA控制权for(i = 0;i<8;i++){	MyI2C_W_SCL(1);//拉高开始读取数据if(MyI2C_R_SDA() == 1){Byte |= (0x80 >> i);}//是1则或上。是0则跳过。MyI2C_W_SCL(0);//拉低允许从机放入数据}return Byte;
}

详情如注释

6.发送一个应答

void MyI2C_SendAck(uint8_t AckBit)
{MyI2C_W_SDA(AckBit);//写入0或1MyI2C_W_SCL(1);MyI2C_W_SCL(0);//拉高拉低结束一个字节的发送
}

7.接收一个应答

uint8_t MyI2C_ReceiveAck(void)
{uint8_t AckBit;MyI2C_W_SDA(1);	//交出SDA控制权MyI2C_W_SCL(1);//拉高SCL开始读取数据AckBit = MyI2C_R_SDA();//读取数据MyI2C_W_SCL(0);//接收结束return AckBit;
}

以上就是I2C的基本时序.

最后看下.h文件

#ifndef  __MYI2C_H__
#define  __MYI2C_H__void MyI2C_W_SCL(uint8_t BitValue);
void MyI2C_W_SDA(uint8_t BitValue);
uint8_t MyI2C_R_SDA(void);
void MyI2C_Init(void);
void MyI2C_Start(void);
void MyI2C_Stop(void);
void MyI2C_SendByte(uint8_t Byte);
uint8_t MyI2C_ReceiveByte(void);
void MyI2C_SendAck(uint8_t AckBit);
uint8_t MyI2C_ReceiveAck(void);#endif

后面我们就可以调用基本时序,来进行通讯了.

三.MU6050的应答

现在我们来验证下基本时序的功能正常与否

1.先验证下应答功能:

int main(void)
{HardWare_Init();//初始化Delay_ms(10);MyI2C_Start();MyI2C_SendByte(0xD0);//110 1000,需要左移一位uint8_t Ack = MyI2C_ReceiveAck();MyI2C_Stop();OLED_ShowHexNum(70, 28, Ack, 4, OLED_6X8);//显示应答OLED_Update();//显示函数while (1){}
}

此时如果地址正确,则显示0000,如何验证呢?只需要更改下地址,将0xD0更换下再次烧录,则显示0001.说明设备没有应答.

2.读取ID

要写一个读取函数

uint8_t MU6050_RegRead(uint8_t RegAddress)
{uint8_t Data;MyI2C_Start();MyI2C_SendByte(MU6050_ADDRESS);//选择设备地址MyI2C_ReceiveAck();MyI2C_SendByte(RegAddress);//选择寄存器地址MyI2C_ReceiveAck();/*------下面转入正式读程序-------------*/MyI2C_Start();MyI2C_SendByte(MU6050_ADDRESS | 0x01);//选择设备地址,或上1,表示接下来是从机控制信号MyI2C_ReceiveAck();Data = MyI2C_ReceiveByte();MyI2C_SendAck(1);//不继续读则给1,如果还想继续则给0;MyI2C_Stop();return Data;
}

注意:为什么代码有部分重复了

因为我们需要先选择好设备寄存器的地址后才能进行数据的读取操作

而设备寄存器又是在我们操作完后自动+ 1操作的.所以我们先指定到地址,后面再进行读写,数据不会出错.

验证:

int main(void)
{HardWare_Init();Delay_ms(10);MyI2C_Start();MyI2C_SendByte(0x3D);uint8_t Ack = MyI2C_ReceiveAck();MyI2C_Stop();OLED_ShowHexNum(70, 28, Ack, 4, OLED_6X8);//显示应答OLED_Update();//显示函数uint8_t ID = MU6050_RegRead(0x0f);//0x0F地址参数不正确,需要去查阅下正确的地址OLED_ShowHexNum(70, 28, ID, 4, OLED_6X8);OLED_Update();while (1){}
}

然后会显示正确的ID号,大家根据手册去验证下读取的是否正确.


总结

通过读取ID号验证了I2C的时序,功能.是否发现I2C也没有想想的那么难了呢?

这篇关于STM32—I2C的基本时序,MU6050的ID读取的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1138872

相关文章

基本知识点

1、c++的输入加上ios::sync_with_stdio(false);  等价于 c的输入,读取速度会加快(但是在字符串的题里面和容易出现问题) 2、lower_bound()和upper_bound() iterator lower_bound( const key_type &key ): 返回一个迭代器,指向键值>= key的第一个元素。 iterator upper_bou

【IPV6从入门到起飞】5-1 IPV6+Home Assistant(搭建基本环境)

【IPV6从入门到起飞】5-1 IPV6+Home Assistant #搭建基本环境 1 背景2 docker下载 hass3 创建容器4 浏览器访问 hass5 手机APP远程访问hass6 更多玩法 1 背景 既然电脑可以IPV6入站,手机流量可以访问IPV6网络的服务,为什么不在电脑搭建Home Assistant(hass),来控制你的设备呢?@智能家居 @万物互联

【STM32】SPI通信-软件与硬件读写SPI

SPI通信-软件与硬件读写SPI 软件SPI一、SPI通信协议1、SPI通信2、硬件电路3、移位示意图4、SPI时序基本单元(1)开始通信和结束通信(2)模式0---用的最多(3)模式1(4)模式2(5)模式3 5、SPI时序(1)写使能(2)指定地址写(3)指定地址读 二、W25Q64模块介绍1、W25Q64简介2、硬件电路3、W25Q64框图4、Flash操作注意事项软件SPI读写W2

C 语言的基本数据类型

C 语言的基本数据类型 注:本文面向 C 语言初学者,如果你是熟手,那就不用看了。 有人问我,char、short、int、long、float、double 等这些关键字到底是什么意思,如果说他们是数据类型的话,那么为啥有这么多数据类型呢? 如果写了一句: int a; 那么执行的时候在内存中会有什么变化呢? 橡皮泥大家都玩过吧,一般你买橡皮泥的时候,店家会赠送一些模板。 上

matlab读取NC文件(含group)

matlab读取NC文件(含group): NC文件数据结构: 代码: % 打开 NetCDF 文件filename = 'your_file.nc'; % 替换为你的文件名% 使用 netcdf.open 函数打开文件ncid = netcdf.open(filename, 'NC_NOWRITE');% 查看文件中的组% 假设我们想读取名为 "group1" 的组groupName

STM32(十一):ADC数模转换器实验

AD单通道: 1.RCC开启GPIO和ADC时钟。配置ADCCLK分频器。 2.配置GPIO,把GPIO配置成模拟输入的模式。 3.配置多路开关,把左面通道接入到右面规则组列表里。 4.配置ADC转换器, 包括AD转换器和AD数据寄存器。单次转换,连续转换;扫描、非扫描;有几个通道,触发源是什么,数据对齐是左对齐还是右对齐。 5.ADC_CMD 开启ADC。 void RCC_AD

STM32内部闪存FLASH(内部ROM)、IAP

1 FLASH简介  1 利用程序存储器的剩余空间来保存掉电不丢失的用户数据 2 通过在程序中编程(IAP)实现程序的自我更新 (OTA) 3在线编程(ICP把整个程序都更新掉) 1 系统的Bootloader写死了,只能用串口下载到指定的位置,启动方式也不方便需要配置BOOT引脚触发启动  4 IAP(自己写的Bootloader,实现程序升级) 1 比如蓝牙转串口,

FreeRTOS-基本介绍和移植STM32

FreeRTOS-基本介绍和STM32移植 一、裸机开发和操作系统开发介绍二、任务调度和任务状态介绍2.1 任务调度2.1.1 抢占式调度2.1.2 时间片调度 2.2 任务状态 三、FreeRTOS源码和移植STM323.1 FreeRTOS源码3.2 FreeRTOS移植STM323.2.1 代码移植3.2.2 时钟中断配置 一、裸机开发和操作系统开发介绍 裸机:前后台系

寻迹模块TCRT5000的应用原理和功能实现(基于STM32)

目录 概述 1 认识TCRT5000 1.1 模块介绍 1.2 电气特性 2 系统应用 2.1 系统架构 2.2 STM32Cube创建工程 3 功能实现 3.1 代码实现 3.2 源代码文件 4 功能测试 4.1 检测黑线状态 4.2 未检测黑线状态 概述 本文主要介绍TCRT5000模块的使用原理,包括该模块的硬件实现方式,电路实现原理,还使用STM32类

Java 多线程的基本方式

Java 多线程的基本方式 基础实现两种方式: 通过实现Callable 接口方式(可得到返回值):