#include "iic.h"
extern void printf(const char* fmt, ...);
void delay_us(void)
{
unsigned int i = 2000;
while(i--);
}
void i2c_init(void)
{
// 使能GPIOF端口的时钟
RCC->MP_AHB4ENSETR |= (0x1 << 5);
// 设置PF14,PF15引脚为通用的输出功能
GPIOF->MODER &= (~(0xF << 28));
GPIOF->MODER |= (0x5 << 28);
// 设置PF14, PF15引脚为推挽输出
GPIOF->OTYPER &= (~(0x3 << 14));
// 设置PF14, PF15引脚为高速输出
GPIOF->OSPEEDR |= (0xF << 28);
// 设置PF14, PF15引脚的禁止上拉和下拉
GPIOF->PUPDR &= (~(0xF << 28));
// 空闲状态SDA和SCL拉高
I2C_SCL_H;
I2C_SDA_H;
}
void i2c_start(void)
{
//在默认状态下改为输出模式
SET_SDA_OUT;
//首先在时钟线拉高时,再将数据线拉高,确保是在高电平状态下
I2C_SCL_H;
I2C_SDA_H;
//加个延时函数确保处于高电平状态,转换成功
delay_us();
//确定的高电平状态下,拉低数据线进行发送开始信号
I2C_SDA_L;//开始信号
delay_us();//延时过后的此时钟,已经下拉处于写状态
I2C_SCL_L;//拉低时钟线,确保处于写状态,
//并且总线被主机占用状态
}
void i2c_stop(void)
{
//确保SDA为输出模式
SET_SDA_OUT;
I2C_SCL_L;//时钟拉低,确保处于低电平状态
//并且可以将一些数据该发送的发送走
delay_us();
I2C_SDA_L;//数据线先拉低,确保处于低电平状态
delay_us();
//开始终止模式
I2C_SCL_H;//拉高时钟线
delay_us();
I2C_SDA_H;//拉高数据线
delay_us();
}
void i2c_write_byte(unsigned char dat)
{
//先设置为输出模式写入信号发送
SET_SDA_OUT;
unsigned int i;
for(i=0;i<8;i++){
I2C_SCL_L;//拉低时钟线占用切换写模式
delay_us();
if(dat&0x80)
{
I2C_SDA_H;
}//写入高位数据
else
{
I2C_SDA_L;
}
delay_us();
I2C_SCL_H;//时钟线拉高,禁止写入,等待下一个轮回
delay_us();
delay_us();
dat<<=1;//移位
}
}
unsigned char i2c_read_byte(unsigned char ack)
{
//设置为输入模式
SET_SDA_IN;
unsigned int i;
unsigned char dat;//返回读取的数据
for(i=0;i<8;i++)
{
I2C_SCL_L;//时钟线拉低
delay_us();//保证写数据完整
//这里试试只写一个延时函数
I2C_SCL_H;//时钟线拉高
delay_us();
dat<<=1;//先移位后每一个数据,都左移1位先
if(I2C_SDA_READ)//读取分机的数据位
{
dat|=1;//补上之前的左移后的1
}
else
{
dat|=0;//这里加不加都行
}
delay_us();//延时一下得到结果
}
if(!ack)
i2c_ack();//因为主机作为发送器接收的ACK应答包
else
i2c_nack();
return dat;//返回一个数据dat给主机
}
unsigned char i2c_wait_ack(void)
{
I2C_SCL_L;//拉低时钟线为了输入数据
I2C_SDA_H;//释放总线
delay_us();
SET_SDA_IN;//变换总线方向
I2C_SCL_H;
delay_us();
if(I2C_SDA_READ)
return 1;//非应答信号
I2C_SCL_L;
return 0;//应答信号
}
void i2c_ack(void)
{
SET_SDA_OUT;//确保总线输出模式
I2C_SCL_L;//时钟线拉低为写输出
delay_us();//
I2C_SDA_L;//数据线先拉低 应答信号
delay_us();
I2C_SCL_H;//时钟线拉高,读取数据
delay_us();
I2C_SCL_L;//时钟线拉低,总线处于占用状态
}
void i2c_nack(void)
{
SET_SDA_OUT;//确保总线输出模式
I2C_SCL_L;//拉低时钟为了写数据
delay_us();
I2C_SDA_H;//拉高写数据1非应答包
delay_us();
I2C_SCL_H;//时钟线拉高,读取数据
delay_us();
delay_us();
I2C_SCL_L;//时钟线拉低,总线处于占用状态
}
#define SET_SDA_OUT do{GPIOF->MODER &= (~(0x3 << 30)); \
GPIOF->MODER |= (0x1 << 30);}while(0)
#define SET_SDA_IN do{GPIOF->MODER &= (~(0x3 << 30));}while(0)
#define I2C_SCL_H do{GPIOF->BSRR |= (0x1 << 14);}while(0)
#define I2C_SCL_L do{GPIOF->BRR |= (0x1 << 14);}while(0)
#define I2C_SDA_H do{GPIOF->BSRR |= (0x1 << 15);}while(0)
#define I2C_SDA_L do{GPIOF->BRR |= (0x1 << 15);}while(0)
#define I2C_SDA_READ (GPIOF->IDR & (0x1 << 15))
void delay_us(void);
void i2c_init(void);
void i2c_start(void);
void i2c_stop(void);
void i2c_write_byte(unsigned char dat);
unsigned char i2c_read_byte(unsigned char ack);
unsigned char i2c_wait_ack(void);
void i2c_ack(void);
void i2c_nack(void);