kehuadong

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

 

posted on 2023-02-26 17:02  kehuadong  阅读(25)  评论(0编辑  收藏  举报

导航