代码工程
https://download.csdn.net/download/weixin_52849254/87886797
模拟I2C读写的实现
mpu6050_iic.c
/** **************************************************************************************************** * @file mpu6050_iic.c * @version V1.0 * @date 2022-06-21 * **************************************************************************************************** */ #include "mpu6050_iic.h" #include "main.h" /** * @brief IIC接口延时函数,用于控制IIC读写速度 * @param 无 * @retval 无 */ static inline void mpu6050_iic_delay(void) { delay_us(2); } /** * @brief 产生IIC起始信号 * @param 无 * @retval 无 */ void mpu6050_iic_start(void) { MPU6050_IIC_SDA(1); MPU6050_IIC_SCL(1); mpu6050_iic_delay(); MPU6050_IIC_SDA(0); mpu6050_iic_delay(); MPU6050_IIC_SCL(0); mpu6050_iic_delay(); } /** * @brief 产生IIC停止信号 * @param 无 * @retval 无 */ void mpu6050_iic_stop(void) { MPU6050_IIC_SDA(0); mpu6050_iic_delay(); MPU6050_IIC_SCL(1); mpu6050_iic_delay(); MPU6050_IIC_SDA(1); mpu6050_iic_delay(); } /** * @brief 等待IIC应答信号 * @param 无 * @retval 0: 应答信号接收成功 * 1: 应答信号接收失败 */ uint8_t mpu6050_iic_wait_ack(void) { uint8_t waittime = 0; uint8_t rack = 0; MPU6050_IIC_SDA(1); mpu6050_iic_delay(); MPU6050_IIC_SCL(1); mpu6050_iic_delay(); while (MPU6050_IIC_READ_SDA()) { waittime++; if (waittime > 250) { mpu6050_iic_stop(); rack = 1; break; } } MPU6050_IIC_SCL(0); mpu6050_iic_delay(); return rack; } /** * @brief 产生ACK应答信号 * @param 无 * @retval 无 */ void mpu6050_iic_ack(void) { MPU6050_IIC_SDA(0); mpu6050_iic_delay(); MPU6050_IIC_SCL(1); mpu6050_iic_delay(); MPU6050_IIC_SCL(0); mpu6050_iic_delay(); MPU6050_IIC_SDA(1); mpu6050_iic_delay(); } /** * @brief 不产生ACK应答信号 * @param 无 * @retval 无 */ void mpu6050_iic_nack(void) { MPU6050_IIC_SDA(1); mpu6050_iic_delay(); MPU6050_IIC_SCL(1); mpu6050_iic_delay(); MPU6050_IIC_SCL(0); mpu6050_iic_delay(); } /** * @brief IIC发送一个字节 * @param dat: 要发送的数据 * @retval 无 */ void mpu6050_iic_send_byte(uint8_t dat) { uint8_t t; for (t=0; t<8; t++) { MPU6050_IIC_SDA((dat & 0x80) >> 7); mpu6050_iic_delay(); MPU6050_IIC_SCL(1); mpu6050_iic_delay(); MPU6050_IIC_SCL(0); dat <<= 1; } MPU6050_IIC_SDA(1); } /** * @brief IIC接收一个字节 * @param ack: ack=1时,发送ack; ack=0时,发送nack * @retval 接收到的数据 */ uint8_t mpu6050_iic_read_byte(uint8_t ack) { uint8_t i; uint8_t dat = 0; for (i = 0; i < 8; i++ ) { dat <<= 1; MPU6050_IIC_SCL(1); mpu6050_iic_delay(); if (MPU6050_IIC_READ_SDA()) { dat++; } MPU6050_IIC_SCL(0); mpu6050_iic_delay(); } if (ack == 0) { mpu6050_iic_nack(); } else { mpu6050_iic_ack(); } return dat; } /** * @brief 初始化IIC接口 * @param 无 * @retval 无 */ void mpu6050_iic_init(void) { GPIO_InitTypeDef gpio_init_struct = {0}; /* 使能SCL、SDA引脚GPIO的时钟 */ MPU6050_IIC_SCL_GPIO_CLK_ENABLE(); MPU6050_IIC_SDA_GPIO_CLK_ENABLE(); /* 初始化SCL引脚 */ gpio_init_struct.Pin = MPU6050_IIC_SCL_GPIO_PIN; /* SCL引脚 */ gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出 */ gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */ gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */ HAL_GPIO_Init(MPU6050_IIC_SCL_GPIO_PORT, &gpio_init_struct); /* 初始化SDA引脚 */ gpio_init_struct.Pin = MPU6050_IIC_SDA_GPIO_PIN; /* SDA引脚 */ gpio_init_struct.Mode = GPIO_MODE_OUTPUT_OD; /* 开漏输出 */ HAL_GPIO_Init(MPU6050_IIC_SDA_GPIO_PORT, &gpio_init_struct); mpu6050_iic_stop(); }
mpu6050_iic.h
#ifndef __MPU6050_IIC_H #define __MPU6050_IIC_H #include "main.h" /* 引脚定义 */ #define MPU6050_IIC_SCL_GPIO_PORT GPIOB #define MPU6050_IIC_SCL_GPIO_PIN GPIO_PIN_8 #define MPU6050_IIC_SCL_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) #define MPU6050_IIC_SDA_GPIO_PORT GPIOB #define MPU6050_IIC_SDA_GPIO_PIN GPIO_PIN_9 #define MPU6050_IIC_SDA_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) /* IO操作 */ #define MPU6050_IIC_SCL(x) do{ x ? \ HAL_GPIO_WritePin(MPU6050_IIC_SCL_GPIO_PORT, MPU6050_IIC_SCL_GPIO_PIN, GPIO_PIN_SET) : \ HAL_GPIO_WritePin(MPU6050_IIC_SCL_GPIO_PORT, MPU6050_IIC_SCL_GPIO_PIN, GPIO_PIN_RESET); \ }while(0) #define MPU6050_IIC_SDA(x) do{ x ? \ HAL_GPIO_WritePin(MPU6050_IIC_SDA_GPIO_PORT, MPU6050_IIC_SDA_GPIO_PIN, GPIO_PIN_SET) : \ HAL_GPIO_WritePin(MPU6050_IIC_SDA_GPIO_PORT, MPU6050_IIC_SDA_GPIO_PIN, GPIO_PIN_RESET); \ }while(0) #define MPU6050_IIC_READ_SDA() HAL_GPIO_ReadPin(MPU6050_IIC_SDA_GPIO_PORT, MPU6050_IIC_SDA_GPIO_PIN) /* 操作函数 */ void mpu6050_iic_start(void); /* 产生IIC起始信号 */ void mpu6050_iic_stop(void); /* 产生IIC停止信号 */ uint8_t mpu6050_iic_wait_ack(void); /* 等待IIC应答信号 */ void mpu6050_iic_ack(void); /* 产生ACK应答信号 */ void mpu6050_iic_nack(void); /* 不产生ACK应答信号 */ void mpu6050_iic_send_byte(uint8_t dat); /* IIC发送一个字节 */ uint8_t mpu6050_iic_read_byte(uint8_t ack); /* IIC接收一个字节 */ void mpu6050_iic_init(void); /* 初始化IIC接口 */ #endif
代码分析
这段代码是用于驱动MPU6050模块的IIC接口的代码。主要功能包括产生起始信号、停止信号、等待应答信号、产生应答信号、发送字节和接收字节等操作。
具体代码功能如下:
mpu6050_iic_delay():用于控制IIC读写速度的延时函数。
mpu6050_iic_start():产生IIC起始信号。
mpu6050_iic_stop():产生IIC停止信号。
mpu6050_iic_wait_ack():等待IIC应答信号,返回值表示应答信号是否接收成功。
mpu6050_iic_ack():产生ACK应答信号。
mpu6050_iic_nack():不产生ACK应答信号。
mpu6050_iic_send_byte():发送一个字节。
mpu6050_iic_read_byte():接收一个字节,参数ack表示是否发送ACK应答信号。
mpu6050_iic_init():初始化IIC接口,配置SCL和SDA引脚的GPIO模式、上拉和输出类型。
这些函数一起完成了对MPU6050模块的IIC接口进行初始化和操作的功能。这些函数可以根据具体的硬件配置和需求进行修改和适应。