模式I2C
#ifndef I2C_H
#define I2C_H
#include "air32f10x.h"
void IIC_Init(void);
uint8_t IIC_Write(uint8_t addr, uint8_t* buffer, uint16_t size);
uint8_t IIC_Read(uint8_t addr, uint8_t* buffer, uint16_t size);
uint8_t IIC_WriteRead(uint8_t addr, uint8_t* writeBuffer, uint16_t writeSize, uint8_t* readBuffer, uint16_t readSize);
#endif // I2C_H
PS:
1. I2C的每个周期是SCL_L, Delay, SCL_H, Delay
2. I2C的写位发生在SCL_L后,Delay前
3. I2C的读位发生在Delay后,SCL_H前
4. SCL_H, 第二个Delay, SCL_L可以构成一个KeepState状态
#include "i2c.h"
#define SCL_H GPIOB->BSRR = GPIO_Pin_14
#define SCL_L GPIOB->BRR = GPIO_Pin_14
#define SDA_H GPIOB->BSRR = GPIO_Pin_15
#define SDA_L GPIOB->BRR = GPIO_Pin_15
#define SDA_IN _SetPinMode(GPIOB, GPIO_Pin_15, GPIO_Mode_IPU)
#define SDA_OUT _SetPinMode(GPIOB, GPIO_Pin_15, GPIO_Mode_Out_PP)
#define GET_SDA ((GPIOB->IDR & GPIO_Pin_15) != 0)
static void _SetPinMode(GPIO_TypeDef* GPIOx, uint16_t Pin, GPIOMode_TypeDef Mode) {
GPIO_InitTypeDef Config;
Config.GPIO_Pin = Pin;
Config.GPIO_Mode = Mode;
Config.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOx, &Config);//初始化GPIO
}
void IIC_Init(void) {
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//PORT时钟使能
GPIO_SetBits(GPIOB, GPIO_Pin_14 | GPIO_Pin_15);
GPIO_InitTypeDef Config;
Config.GPIO_Pin = GPIO_Pin_14 | GPIO_Pin_15;
Config.GPIO_Mode = GPIO_Mode_Out_PP; //复用推挽输出
Config.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &Config);//初始化GPIO
}
static void IIC_Delay(void) {
for (uint8_t i = 0; i < 41; i++) __NOP();
}
static void IIC_KeepState(void) {
SCL_H;
IIC_Delay(); // 保持状态
SCL_L;
}
static void IIC_Start(void) {
SDA_L;
IIC_Delay();
SCL_L;
IIC_Delay(); // 等待对方识别到开始信号
}
static void IIC_Stop(void) {
SDA_L;
SCL_H;
IIC_Delay();
SDA_H;
IIC_Delay();
}
static void IIC_WriteByte(uint8_t ch) {
for (uint8_t mask = 0x80; mask; mask >>= 1) {
if (ch & mask) {
SDA_H;
} else {
SDA_L;
}
IIC_Delay(); // 等待对方识别SCL_L
IIC_KeepState();
}
}
static uint8_t IIC_WaitAck(void) {
IIC_Delay(); // 等待对方设置SDA
SDA_IN; // 如果对方不拉低,这个上拉输入就会拉高
uint8_t ch = GET_SDA;
IIC_KeepState();
SDA_OUT;
return ch;
}
static uint8_t IIC_ReadByte(void) {
SDA_IN;
uint8_t ch = 0;
for (uint8_t i = 0; i < 8; i++) {
IIC_Delay(); // 等待对方设置
ch <<= 1;
if (GET_SDA) {
ch++;
}
IIC_KeepState();
}
return ch;
}
static void IIC_Ack(uint8_t ack) {
SDA_OUT;
if (ack) {
SDA_H;
} else {
SDA_L;
}
IIC_Delay(); // 等待对方识别SCL_L
IIC_KeepState();
}
static uint8_t IIC_Write4(uint8_t addr, uint8_t* buffer, uint16_t size, uint8_t stop) {
IIC_Start();
IIC_WriteByte(addr & 0xFE);
if (IIC_WaitAck()) {
IIC_Stop();
return 0;
}
for (uint16_t i = 0; i < size; i++) {
IIC_WriteByte(buffer[i]);
if (IIC_WaitAck()) {
IIC_Stop();
return 0;
}
}
if (stop) {
IIC_Stop();
}
return 1;
}
uint8_t IIC_Write(uint8_t addr, uint8_t* buffer, uint16_t size) {
return IIC_Write4(addr, buffer, size, 1);
}
uint8_t IIC_Read(uint8_t addr, uint8_t* buffer, uint16_t size) {
IIC_Start();
IIC_WriteByte(addr | 0x01);
if (IIC_WaitAck()) {
IIC_Stop();
return 0;
}
for (uint16_t i = 0; i < size; i++) {
buffer[i] = IIC_ReadByte();
IIC_Ack(i+1 != size);
}
IIC_Stop();
return 1;
}
uint8_t IIC_WriteRead(uint8_t addr, uint8_t* writeBuffer, uint16_t writeSize, uint8_t* readBuffer, uint16_t readSize) {
if (IIC_Write4(addr, writeBuffer, writeSize, 0) == 0) {
return 0;
}
return IIC_Read(addr, readBuffer, readSize);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具