本程序主要用于使用可编程芯片自身的IO管脚,模拟I2C通信的协议,实现I2C总线数据的传输.
/** ****************************************************************************** * @file Virtual_I2C.C * @author Ryan Zhao * @version V1.0.0 * @date 2017-04-20 * @brief 软件I/O模拟I2C总线通讯. ****************************************************************************** * @attention Null * ****************************************************************************** */ /** * @brief I2C引脚初始化. * @param None. * @retval None. */ void I2C_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );//使能GPIOB时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_SetBits(GPIOB,GPIO_Pin_6|GPIO_Pin_7); //PB6,PB7 输出高 } /** * @brief 产生I2C开始信号. * @param None. * @retval None. */ void I2C_Start(void) { SDA_OUT(); //SDA引脚设置为输出模式 I2C_SDA_H; //SDA引脚设置为高电平 I2C_SCL_H; //SCL引脚设置为高电平 Delay(); //软件延时 I2C_SDA_L; Delay(); //软件延时 I2C_SCL_L; //准备发送或接收数据 } /** * @brief 产生I2C停止信号. * @param None. * @retval None. */ void I2C_Stop(void) { SDA_OUT();//SDA引脚设置为输出模式 I2C_SCL_l; I2C_SDA_l; Delay(); //软件延时 I2C_SCL_H; I2C_SDA_H; Delay(); } /** * @brief 等待ACK信号. * @param None. * @retval 1:接收应答成功; 0:接收应答失败; */ unsigned char I2C_Wait_Ack(void) { unsigned char ucErrTime=0; SDA_IN(); //SDA引脚设置为输入模式 I2C_SDA_H; Delay(); I2C_SCL_H; Delay(); while(READ_SDA)//读取SDA引脚电平状态 { ucErrTime++; if(ucErrTime>250) { I2C_Stop(); return 0; //接收应答失败 } } I2C_SCL_L; return 1; //接收应答成功 } /** * @brief 产生ACK信号. * @param None. * @retval None. */ void I2C_Ack(void) { I2C_SCL_L; SDA_OUT(); //SDA引脚设置为输出模式 I2C_SDA_L; Delay(); I2C_SCL_H; Delay(); I2C_SCL_L; } /** * @brief 不产生ACK信号. * @param None. * @retval None. */ void I2C_NAck(void) { I2C_SCL_L; SDA_OUT(); I2C_SDA_H; Delay(); I2C_SCL_H; Delay(); I2C_SCL_L; } /** * @brief I2C发送一个字节. * @param None. * @retval None. */ void I2C_Send_Byte(unsigned char txd) { unsigned char i; SDA_OUT(); I2C_SCL_L; for(i=0;i<8;i++) { if((txd&0x80)>>7) { I2C_SDA_H; } else { I2C_SDA_L; } txd = txd<<1; Delay(); I2C_SCL_H; Delay(); I2C_SCL_L; Delay(); } } /** * @brief I2C读取一个字节. * @param None. * @retval 读取到的数据 */ unsigned char I2C_Read_Byte(unsigned char ack) { unsigned char i,receive=0; SDA_IN();//SDA设置为输入 for(i=0;i<8;i++ ) { I2C_SCL=0; Delay(); I2C_SCL=1; receive<<=1; if(READ_SDA) { receive++; } Delay(); } if (!ack) { I2C_NAck();//发送nACK } else { I2C_Ack(); //发送ACK } return receive; }