标准I2c是从高位到低位发送
//IO 口模拟起始信号
//产生起始信号
void I2C_Start(void)
{
I2C_SDA_OUT(); //对于有准双向的IO口,可以不设置SDA的输入输出模式。比如51单片机。
I2C_SDA_H;
I2C_SCL_H;
delay_us(5);
I2C_SDA_L;
delay_us(6);
I2C_SCL_L;
}
/*防止冲突的写法
bool I2C_Start(void)
{
SDA_H;I2C_delay();
SCL_H;I2C_delay();
if((SDA_read)==0)
{
return 0;
}
else
{
SDA_L;I2C_delay();
if(SDA_read)
{
return 0;
}
else
{
SDA_L;
I2C_delay();
return 1;
}
}
}
*/
//IO 口模拟结束信号
//产生停止信号
void I2C_Stop(void)
{
I2C_SDA_OUT(); I2C_SCL_L;
I2C_SDA_L;
I2C_SCL_H;
delay_us(6);
I2C_SDA_H;
delay_us(6);
I2C_SCL_L;
}
//主机产生应答信号 ACK
void I2C_Ack(void)
{
I2C_SCL_L;
I2C_SDA_OUT();
I2C_SDA_L;
delay_us(2);
I2C_SCL_H;
delay_us(5);
I2C_SCL_L;
}
//主机不产生应答信号 NACK
void I2C_NAck(void)
{
I2C_SCL_L;
I2C_SDA_OUT();
I2C_SDA_H;
delay_us(2);
I2C_SCL_H;
delay_us(5);
I2C_SCL_L;
}
6. IO 口模拟发送一个字节数据
//从scl拉低开始延时2us,写入数据到sda,再延时2us拉高scl
//I2C 发送一个字节
void I2C_Send_Byte(u8 txd)
{
u8 i=0;
I2C_SDA_OUT();
I2C_SCL_L;//拉低时钟开始数据传输
delay_us(2);
for(i=0;i<8;i++)
{
if((txd&0x80)>0) //0x80 1000 0000
I2C_SDA_H;
else
I2C_SDA_L;
delay_us(2); //等待数据稳定
txd<<=1;
I2C_SCL_H;
delay_us(4); //发送数据
I2C_SCL_L;
delay_us(2);
}
}
//等待从机应答信号
//从scl拉低开始延时4us,给从机写入数据的时间,然后开始读入数据
//返回值:1 接收应答失败
// 0 接收应答成功
u8 I2C_Wait_Ack(void)
{
u8 tempTime=0;
I2C_SCL_L; //释放总线
I2C_SDA_H; //释放总线
I2C_SDA_IN();
delay_us(4);
I2C_SCL_H;
//delay_us(1);
while(GPIO_ReadInputDataBit(GPIO_I2C,I2C_SDA)){
tempTime++;
if(tempTime>250){
I2C_Stop();
return 1;
}
}
I2C_SCL_L;
return 0;
}
7. IO 口模拟接收一个字节数据
//I2C 读取一个字节
//从scl拉低开始延时4us,给从机写入数据的时间,然后开始读入数据
u8 I2C_Read_Byte(u8 ack)
{
u8 i=0,receive=0;
I2C_SDA_H; //准双向需要这一句,释放总线
I2C_SDA_IN();
for(i=0;i<8;i++){
I2C_SCL_L;
delay_us(4);
I2C_SCL_H;
if(GPIO_ReadInputDataBit(GPIO_I2C,I2C_SDA))
receive++;
receive<<=1;
delay_us(1);
}
if(ack==0){
I2C_NAck();
}else{
I2C_Ack();
}
return receive;
}
17、模拟IIC编程
(1)、开引脚的时钟:RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
(2)、宏定义:
#define I2C_SCL GPIO_Pin_6
#define I2C_SDA GPIO_Pin_7
#define GPIO_I2C GPIOB
#define I2C_SCL_H GPIO_SetBits(GPIO_I2C, I2C_SCL) //把PB6置高
#define I2C_SCL_L GPIO_ResetBits(GPIO_I2C, I2C_SCL) //把PB6置低
#define I2C_SDA_H GPIO_ResetBits(GPIO_I2C, I2C_SDA) //把PB7置高
#define I2C_SDA_L GPIO_ResetBits(GPIO_I2C, I2C_SDA) //把PB7置低
(3)、配置函数
void I2C_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=I2C_SCL | I2C_SDA;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //推挽输出模式
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
(4)、SDA有输出方向和输入方向,配置SDA的这两个模式:
void I2C_OUT(void) //SDA是输出方向
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=I2C_SDA;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //推挽输出模式
GPIO_Init(GPIOB,&GPIO_InitStructure);
I2C_SCL_H;
I2C_SDA_H; //把两条线都变成高电平
}
void I2C_IN(void) //SDA是输入方向
{
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Pin=I2C_SDA;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_IPU; //输入上拉模式
GPIO_Init(GPIOB,&GPIO_InitStructure);
}
原文:https://blog.csdn.net/shaguahaha/article/details/70766665
1. 起始信号
定义:SCL线为高电平期间,SDA线由高电平向低电平的变化。
void iic_start(void)
{
SDA = 1;
SCL = 1;
delay_us(1);
SDA = 0;
delay_us(1);
SCL = 0;
}
2. 终止信号
定义:SCL线为高电平期间,SDA线由低电平向高电平的变化。
void iic_stop(void)
{
SDA = 0;
SCL = 1;
delay_us(1);
SDA = 1;
delay_us(1);
SCL = 0;
}
3. 写数据信号
I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高低电平状态才允许变化。
bit iic_send_byte(unsigned char byte)
{
unsigned char i;
for(i = 0; i < 8; i++)
{
SDA = byte & 0x80;
SCL = 1;
delay_us(1);
SCL = 0;
byte <<= 1;
}
SCL = 1;
SDA = 1;
delay_us(1);
if(0 == SDA)
{
ack = 1;
}
else
{
ack = 0;
}
SCL = 0;
return ack;
}
4. 读数据信号
I2C总线进行数据传送时,时钟信号为高电平期间,数据线上的数据必须保持稳定,只有在时钟线上的信号为低电平期间,数据线上的高低电平状态才允许变化。
unsigned char iic_rcv_byte(void)
{
unsigned char i;
unsigned char temp = 0;
unsigned char a;
SDA = 1;
for(i = 0; i < 8; i++)
{
SCL = 0;
delay_us(1);
SCL = 1;
if(SDA)
{
a = 0x01;
}
else
{
a = 0;
}
temp |= (a << (7 - i));
delay_us(1);
}
SCL = 0;
return temp;
}
5. 应答信号
I2C总线协议规定,每传送一个字节数据,都要有一个应答信号以确定数据传送是否被对方接收。应答信号由接收设备产生,在SCL为高电平期间,接收设备将SDA拉低为低电平,表示数据传输正确。
void iic_ack(void)
{
SDA = 0;
SCL = 1;
delay_us(1);
SCL = 0;
}
6. 非应答信号
void iic_noack(void)
{
SDA = 1;
SCL = 1;
delay_us(1);
SCL = 0;
}
原文:https://blog.csdn.net/zhengqijun_/article/details/52217101