软件IIC与硬件IIC的差异性解析:stm32软件IIC代码详解
目录
1.IIC总线概述
a.基本原理
总线结构
设备类型
b.通信协议
2.软件IIC和硬件1IC的区别:
2.1.实现方式
2.2. 性能
2.3. 可靠性
3. 硬件IIC和软件IIC代码示例
3.1 硬件IIC
1.首先打开外部高速晶振
2.IIC设置
3. 时钟源设置
3.2 软件IIC
1.IIC总线概述
a.基本原理
总线结构
IIC总线使用两条线进行通信
设备类型
IIC总线上可以连接多个设备,这些设备分为两种类型:
b.通信协议
2.软件IIC和硬件1IC的区别:
2.1.实现方式
软件IIC:通过控制GPIO来模拟IIC的SCL和SDA信号来产生IIC的时序
硬件IIC:MCU内部专用硬件模块(IIC外设)来时许的,软件只负责发出命令
2.2. 性能
软件IIC:速度通常比较慢,速度受限于CPU
硬件IIC:速度就比较快,在高频率下工作,不受CPU的限制
2.3. 可靠性
硬件IIC可靠性较高
软件IIC取决于CPU的运行速度,取决于程序员的代码设计
3. 硬件IIC和软件IIC代码示例
3.1 硬件IIC
硬件IIC我们可以使用STM32Cubemx生成代码,以下是使用STM32Cubemx步骤:
1.首先打开外部高速晶振
2.IIC设置
图中第3步保持默认即可
3. 时钟源设置
至此STM32Cubemx关于IIC的基础配置已经完成,点击右上角GENERATE CODE即可以生成代码,需要其余操作可以自行编写代码。
3.2 软件IIC
我们根据IIC的通信时序图即可以模拟出IIC。
.h文件
#ifndef IIC_H
#define IIC_H
#include "stm32f10x.h"
// IIC配置结构体
typedef struct {
uint32_t I2C_ClockSpeed; // IIC时钟速度
uint16_t I2C_Mode; // IIC模式(I2C_Mode_I2C)
uint16_t I2C_DutyCycle; // IIC占空比(I2C_DutyCycle_2)
uint16_t I2C_OwnAddress1; // IIC自身地址(不常用)
uint16_t I2C_Ack; // IIC应答使能(I2C_Ack_Enable 或 I2C_Ack_Disable)
uint16_t I2C_AcknowledgedAddress; // IIC地址位数(I2C_AcknowledgedAddress_7bit 或 I2C_AcknowledgedAddress_10bit)
} I2C_ConfigTypeDef;
// IIC初始化
void I2C_Init(I2C_TypeDef* I2Cx, I2C_ConfigTypeDef* I2C_Config);
// IIC启动条件
void I2C_Start(I2C_TypeDef* I2Cx);
// IIC停止条件
void I2C_Stop(I2C_TypeDef* I2Cx);
// IIC发送地址
void I2C_SendAddr(I2C_TypeDef* I2Cx, uint8_t Addr, uint8_t Dir);
// IIC发送字节
void I2C_WriteByte(I2C_TypeDef* I2Cx, uint8_t Data);
// IIC读取字节
uint8_t I2C_ReadByte(I2C_TypeDef* I2Cx, uint8_t Ack);
// IIC等待忙状态
void I2C_WaitForEvent(I2C_TypeDef* I2Cx, uint32_t Event, uint32_t Timeout);
#endif // IIC_H
.c文件
#include "iic.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_i2c.h"
// IIC初始化
void I2C_Init(I2C_TypeDef* I2Cx, I2C_ConfigTypeDef* I2C_Config) {
GPIO_InitTypeDef GPIO_InitStructure;
I2C_InitTypeDef I2C_InitStructure;
// 使能I2C和GPIO时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// 配置I2C引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; // PB6 (SCL), PB7 (SDA)
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; // 复用开漏输出
GPIO_Init(GPIOB, &GPIO_InitStructure);
// 配置I2C
I2C_InitStructure.I2C_ClockSpeed = I2C_Config->I2C_ClockSpeed;
I2C_InitStructure.I2C_Mode = I2C_Config->I2C_Mode;
I2C_InitStructure.I2C_DutyCycle = I2C_Config->I2C_DutyCycle;
I2C_InitStructure.I2C_OwnAddress1 = I2C_Config->I2C_OwnAddress1;
I2C_InitStructure.I2C_Ack = I2C_Config->I2C_Ack;
I2C_InitStructure.I2C_AcknowledgedAddress = I2C_Config->I2C_AcknowledgedAddress;
I2C_Init(I2Cx, &I2C_InitStructure);
// 使能I2C
I2C_Cmd(I2Cx, ENABLE);
}
// IIC启动条件
void I2C_Start(I2C_TypeDef* I2Cx) {
I2C_GenerateSTART(I2Cx, ENABLE);
I2C_WaitForEvent(I2Cx, I2C_EVENT_MASTER_MODE_SELECT, 10000);
}
// IIC停止条件
void I2C_Stop(I2C_TypeDef* I2Cx) {
I2C_GenerateSTOP(I2Cx, ENABLE);
}
// IIC发送地址
void I2C_SendAddr(I2C_TypeDef* I2Cx, uint8_t Addr, uint8_t Dir) {
uint8_t I2C_Address = (Addr << 1) | Dir;
I2C_Send7bitAddress(I2Cx, I2C_Address, I2C_Direction_Transmitter);
I2C_WaitForEvent(I2Cx, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED, 10000);
}
// IIC发送字节
void I2C_WriteByte(I2C_TypeDef* I2Cx, uint8_t Data) {
I2C_SendData(I2Cx, Data);
I2C_WaitForEvent(I2Cx, I2C_EVENT_MASTER_BYTE_TRANSMITTED, 10000);
}
// IIC读取字节
uint8_t I2C_ReadByte(I2C_TypeDef* I2Cx, uint8_t Ack) {
if (Ack == I2C_Ack_Enable) {
I2C_AcknowledgeConfig(I2Cx, ENABLE);
} else {
I2C_AcknowledgeConfig(I2Cx, DISABLE);
}
I2C_WaitForEvent(I2Cx, I2C_EVENT_MASTER_BYTE_RECEIVED, 10000);
return I2C_ReceiveData(I2Cx);
}
// IIC等待忙状态
void I2C_WaitForEvent(I2C_TypeDef* I2Cx, uint32_t Event, uint32_t Timeout) {
uint32_t tickstart = HAL_GetTick();
while (!I2C_CheckEvent(I2Cx, Event)) {
if ((HAL_GetTick() - tickstart) > Timeout) {
// 超时处理
return;
}
}
}
作者:Redemption