②,编写产生I2C起始信号函数,产生I2C停止信号函数,等待ACK应答信号函数,产生ACK应答信号函数,不产生ACK应答信号函数。
举例如下(基于STM32系列,IO口模拟产生i2c信号):
i2c初始化程序如下:
void IIC_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);//GPIO时钟使能 //GPIOB8,B9初始化设置 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//输出模式 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//内部上拉 GPIO_Init(GPIOB, &GPIO_InitStructure); IIC_SCL=1; IIC_SDA=1; }i2c起始程序如下: void IIC_Start(void) { SDA_OUT(); //sda线输出 IIC_SDA=1; IIC_SCL=1; delay_us(4); IIC_SDA=0;//当CLK高电平时,SDA从高电平到低电平表示起始状态 delay_us(4); IIC_SCL=0;//拉低i2c总线,准备发射或接受数据 }i2c停止程序如下:
void IIC_Stop(void) { SDA_OUT();//sda线设置为输出 IIC_SCL=0; IIC_SDA=0;//当CLK高电平时,SDA从低电平到高电平表示停止状态 delay_us(4); IIC_SCL=1; IIC_SDA=1;//发送i2c总线结束信号 delay_us(4); }i2c等待应答程序: u8 IIC_Wait_Ack(void) { u8 ucErrTime=0; SDA_IN(); //SDA设置为输入 IIC_SDA=1;delay_us(1); IIC_SCL=1;delay_us(1); while(READ_SDA) { ucErrTime++; if(ucErrTime>250) { IIC_Stop(); return 1; } } IIC_SCL=0;//时钟信号线拉低 return 0; } i2c产生ACK应答函数: void IIC_Ack(void) { IIC_SCL=0; SDA_OUT(); IIC_SDA=0; delay_us(2); IIC_SCL=1; delay_us(2); IIC_SCL=0; }i2c不产生ACK应答函数: void IIC_NAck(void) { IIC_SCL=0; SDA_OUT(); IIC_SDA=1; delay_us(2); IIC_SCL=1; delay_us(2); IIC_SCL=0; } 7,I2C写数据流程 ①,设置SDA为输出,当SCL线为高电平时,SDA 线从高电平向低电平切换,产生I2C启动信号 ②,设置SDA为输出,把写命令放入i2c-buffer ③,设置SDA为输入,等待ACK信号 ④,设置SDA为输出,把从机地址放入i2c-buffer ⑤,设置SDA为输入,等待ACK信号 ⑥,设置SDA为输出,把待发送的8位数据放入i2c-buffer ⑦,设置SDA为输入,等待ACK信号 ⑧,若传输完成,则当SCL线为高电平时,SDA 线由低电平向高电平切换,产生I2C停止信号,若传输未完成,重复4,5步。写字节程序如下(只是写一节字节的流程):
void IIC_Send_Byte(u8 txd) { u8 t; SDA_OUT(); IIC_SCL=0;//拉低时钟开始传输数据 for(t=0;t<8;t++) { IIC_SDA=(txd&0x80)>>7; txd<<=1; delay_us(2); IIC_SCL=1; delay_us(2); IIC_SCL=0; delay_us(2); } } 8,I2C读数据流程 ①,设置SDA为输出,当SCL线为高电平时,SDA 线从高电平向低电平切换,产生I2C启动信号 ②,设置SDA为输出,把写命令放入i2c-buffer ③,设置SDA为输入,等待ACK信号 ④,设置SDA为输出,把从机地址放入i2c-buffer ⑤,设置SDA为输入,等待ACK信号 ⑥,设置SDA为输出,当SCL线为高电平时,SDA 线从高电平向低电平切换,产生I2C启动信号 ⑦,设置SDA为输出,把读命令放入i2c-buffer ⑧,设置SDA为输入,等待ACK信号 ⑨,设置SDA为输入,把i2c-buffer数据放入内存 ⑩,设置SDA为输出,根据情况决定是否产生ACK信号?,若传输完成,则当SCL线为高电平时,SDA 线由低电平向高电平切换,产生I2C停止信号,若传输未完成,重复9,10步。
读字节程序如下(只是读一节字节的流程):
u8 IIC_Read_Byte(unsigned char ack) { unsigned char i,receive=0; SDA_IN();//SDA设置为输入 for(i=0;i<8;i++ ) { IIC_SCL=0; delay_us(2); IIC_SCL=1; receive<<=1; if(READ_SDA)receive++; delay_us(1); } if (!ack) IIC_NAck();//发送NAck函数 else IIC_Ack(); //发送ACK函数 return receive; }