#ifndef __IIC_H__
#define __IIC_H__
#include "stm32mp1xx_gpio.h"
#include "stm32mp1xx_rcc.h"
//SDA 数据线为PF15
//SCL 时钟线为PF14
//配置PF15为输出模式
#define SET_SDA_OUT do{GPIOF->MODER &=(~(0x3<<30));\
GPIOF->MODER |=(0x1<<30);}while(0)
//配置PF15为输入模式
#define SET_SDA_IN do{GPIOF->MODER &=(~(0x3<<30));}while(0)
//读取PF15输入寄存器的值
#define I2C_SDA_READ GPIOF->IDR & (0x1<<15)
//PF14输出高电平、低电平
#define I2C_SCL_H do{GPIOF->BSRR |= (0x1<<14);}while(0)
#define I2C_SCL_L do{GPIOF->BRR |= (0x1<<14);}while(0)
//PF15输入高电平、低电平
#define I2C_SDA_H do{GPIOF->BSRR |= (0x1<<15);}while(0)
#define I2C_SDA_L do{GPIOF->BRR |= (0x1<<15);}while(0)
void delay_us(void);
//模拟I2C
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);
#endif
#include "iic.h"
//微妙级的延时
void delay_us(void){
unsigned int i=2000;
while(i--);
}
//模拟I2C
//I2C初始化
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));
//将SCL和SDA输出高电平
I2C_SCL_H;
I2C_SDA_H;
}
//发送起始信号
void i2c_start(void){
//设置SDA为输出模式
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();
delay_us();
//修改数据线为低电平
I2C_SDA_L;
delay_us();
//拉高时钟线
I2C_SCL_H;
delay_us();
//拉高数据线
I2C_SDA_H;
}
//发送数据
void i2c_write_byte(unsigned char dat){
unsigned int i;
//PF14配置为输出模式
SET_SDA_OUT;
for(i=0;i<8;i++){
//拉低时钟线
I2C_SCL_L;
delay_us();
//修改数据线的值
if(dat&(0x1<<7)){
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 char data;
for(unsigned int i=0;i<8;i++){
//从机需要向寄存器写入数据
//所有需要拉低时钟线
I2C_SCL_L;
delay_us(); //延时
delay_us(); //等待从机写入数据
//拉高时钟线读取数据
I2C_SCL_H;
delay_us(); //延时
data<<=1;
if(I2C_SDA_READ){
data|=0x1;
}
else data|=0x0;
}
if(!ack){
i2c_nack();
}
else{
i2c_ack();
}
//返回读取的数值
return data;
}
//等带从机ack
unsigned char i2c_wait_ack(void){
//拉低时钟线,修改SDA电平
I2C_SCL_L;
delay_us();
I2C_SDA_H; //释放给从机
delay_us();
//SDA配置为输入模式
SET_SDA_IN;
delay_us();
delay_us();
//拉高时钟线读取从机ack
I2C_SCL_H;
delay_us();
if(I2C_SDA_READ){
return 1;
}
I2C_SCL_L;
return 0;
}
//ack应答
void i2c_ack(void){
//配置为输出模式
SET_SDA_OUT;
//拉低时钟线
I2C_SCL_L;
delay_us();
//拉低数据线
I2C_SDA_L;
delay_us();
//拉高时钟线
I2C_SCL_H;
delay_us();
delay_us();
//拉低时钟线?
I2C_SCL_L;
}
//非ack应答
void i2c_nack(void){
//配置为输出模式
SET_SDA_OUT;
//拉低时钟线
I2C_SCL_L;
delay_us();
//拉高数据线
I2C_SDA_H;
delay_us();
//拉高时钟线
I2C_SCL_H;
delay_us();
delay_us();
//拉低时钟线?
I2C_SCL_L;
}