stm32F103 模拟i2c从机代码
时间: 2023-07-09 08:17:46 浏览: 69
以下是 STM32F103 上使用 GPIO 模拟 I2C 从机的代码示例,供您参考:
```c
#include "stm32f10x.h"
// I2C GPIO 端口定义
#define I2C_SCL_PIN GPIO_Pin_6
#define I2C_SDA_PIN GPIO_Pin_7
#define I2C_GPIO_PORT GPIOB
// I2C 状态定义
#define I2C_STA_IDLE 0
#define I2C_STA_START 1
#define I2C_STA_ADDR_R 2
#define I2C_STA_ADDR_W 3
#define I2C_STA_DATA_R 4
#define I2C_STA_DATA_W 5
#define I2C_STA_STOP 6
// I2C 从机状态定义
typedef struct
{
uint8_t State; // 当前状态
uint8_t Addr; // 从机地址
uint8_t Reg; // 寄存器地址
uint8_t Data; // 数据
} I2C_SwSlaveTypeDef;
I2C_SwSlaveTypeDef SwSlaveI2C;
// 设置 SCL 和 SDA 方向
#define SET_SCL_DIR(DIR) GPIO_WriteBit(I2C_GPIO_PORT, I2C_SCL_PIN, (DIR) ? Bit_SET : Bit_RESET)
#define SET_SDA_DIR(DIR) GPIO_WriteBit(I2C_GPIO_PORT, I2C_SDA_PIN, (DIR) ? Bit_SET : Bit_RESET)
// 读取 SDA 状态
#define READ_SDA_STATE() GPIO_ReadInputDataBit(I2C_GPIO_PORT, I2C_SDA_PIN)
// 延时一段时间(单位:微秒)
void DelayUs(uint32_t us)
{
uint32_t i;
for (i = 0; i < us * 8; i++) {} // 根据 CPU 主频调整
}
// 初始化 I2C 从机
void I2C_SwSlaveInit(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
// 使能 I2C GPIO 端口时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
// 配置 I2C GPIO 端口为推挽输出
GPIO_InitStruct.GPIO_Pin = I2C_SCL_PIN | I2C_SDA_PIN;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(I2C_GPIO_PORT, &GPIO_InitStruct);
// 初始化 I2C 从机状态
SwSlaveI2C.State = I2C_STA_IDLE;
SwSlaveI2C.Addr = 0;
SwSlaveI2C.Reg = 0;
SwSlaveI2C.Data = 0;
}
// 处理 I2C 从机中断
void I2C_SwSlaveHandler(void)
{
uint8_t i;
// 处理 I2C 从机状态
switch (SwSlaveI2C.State)
{
// 空闲状态
case I2C_STA_IDLE:
// 等待 I2C 主机发起起始信号
if (READ_SDA_STATE() == RESET)
{
DelayUs(5);
if (READ_SDA_STATE() == RESET)
{
SET_SCL_DIR(1);
SwSlaveI2C.State = I2C_STA_START;
}
}
break;
// 起始状态
case I2C_STA_START:
// SCL 保持高电平,SDA 下降沿表示起始信号
SET_SDA_DIR(0);
DelayUs(5);
SET_SCL_DIR(0);
SwSlaveI2C.State = I2C_STA_ADDR_R;
break;
// 读取从机地址状态
case I2C_STA_ADDR_R:
// 读取从机地址,并根据 R/W 位设置状态
for (i = 0; i < 8; i++)
{
SET_SCL_DIR(1);
DelayUs(5);
SwSlaveI2C.Addr <<= 1;
SwSlaveI2C.Addr |= READ_SDA_STATE();
SET_SCL_DIR(0);
DelayUs(5);
}
if (SwSlaveI2C.Addr & 0x01)
{
SwSlaveI2C.State = I2C_STA_DATA_R;
}
else
{
SwSlaveI2C.State = I2C_STA_DATA_W;
}
break;
// 读取数据状态
case I2C_STA_DATA_R:
// 读取数据,并