/*----------------------------------------------------
* 模块名: I2C.c
* 功能描述:I2C接口驱动,软件模拟I2C接口时序
*----------------------------------------------------*/
#include "I2C.h"
/*----------------------------------------------------
* 函数原型:void I2C_delay(void)
* 功 能:I2C延时
* 输 入:无
* 输 出:无
* 备 注:
*----------------------------------------------------*/
void I2C_delay(void)
{
uint8_t i=5;
while(i)
{
i--;
}
}
/*----------------------------------------------------
* 函数原型:void I2C_NoAck(void)
* 功 能:产生NoAck信号
* 输 入:无
* 输 出:无
* 备 注:第9个周期SCL为高,SDA为高
*----------------------------------------------------*/
void I2C_NoAck(void)
{
SCL_L;
I2C_delay();
SDA_H;
I2C_delay();
SCL_H;
I2C_delay();
SCL_L;
I2C_delay();
}
/*----------------------------------------------------
* 函数原型:void I2C_Initial()
* 功 能:I2C初始化
* 输 入:无
* 输 出:无
* 备 注:配置SCL和SDA引脚
*----------------------------------------------------*/
void I2C_Initial()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB , ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
/*----------------------------------------------------
* 函数原型:bool I2C_Start(void)
* 功 能:产生开始标志
* 输 入:无
* 输 出:bool:FALSE--总线忙,TRUE--启动成功
* 备 注:SCL为高,SDA下降沿
*----------------------------------------------------*/
bool I2C_Start(void)
{
SDA_H;
SCL_H;
I2C_delay();
if(!SDA_read)return FALSE; //SDA线为低电平则总线忙,退出
SDA_L;
I2C_delay();
if(SDA_read) return FALSE; //SDA线为高电平则总线出错,退出
SDA_L;
I2C_delay();
return TRUE;
}
/*----------------------------------------------------
* 函数原型:void I2C_Stop(void)
* 功 能:产生停止标志
* 输 入:无
* 输 出:无
* 备 注:SCL为高,SDA上升沿
*----------------------------------------------------*/
void I2C_Stop(void)
{
SCL_L;
I2C_delay();
SDA_L;
I2C_delay();
SCL_H;
I2C_delay();
SDA_H;
I2C_delay();
}
/*----------------------------------------------------
* 函数原型:void I2C_Ack(void)
* 功 能:产生ACK应答信号
* 输 入:无
* 输 出:无
* 备 注:第9个周期时,SCL为高,SDA为低
*----------------------------------------------------*/
void I2C_Ack(void)
{
SCL_L;
I2C_delay();
SDA_L;
I2C_delay();
SCL_H;
I2C_delay();
SCL_L;
I2C_delay();
}
/*----------------------------------------------------
* 函数原型:void I2C_SendByte(uint8_t SendByte)
* 功 能:发送一个字节
* 输 入:SendByte:待发送的数
* 输 出:无
* 备 注:数据从高位到低位
*----------------------------------------------------*/
void I2C_SendByte(uint8_t SendByte)
{
uint8_t i=8;
while(i--)
{
SCL_L;
I2C_delay();
if(SendByte&0x80)
SDA_H;
else
SDA_L;
SendByte<<=1;
I2C_delay();
SCL_H;
I2C_delay();
}
SCL_L;
}
/*----------------------------------------------------
* 函数原型:void I2C_SendAddress(uint8_t Address, uint8_t Direction)
* 功 能:发送器件地址与读写标志
* 输 入:Address:器件地址
* Direction:方向 0--写,1--读
* 输 出:无
* 备 注:将7位器件地址与1位读写标志组合,然后发送
*----------------------------------------------------*/
void I2C_SendAddress(uint8_t Address, uint8_t Direction)
{
uint8_t send_data;
send_data = Address << 1;
send_data |= (Direction & 0x01);
I2C_SendByte(send_data);
}
/*----------------------------------------------------
* 函数原型:bool I2C_ChkAck(void)
* 功 能:检测有无收到Ack确认
* 输 入:无
* 输 出:bool:1--ACK, 0--NoAck
* 备 注:
*----------------------------------------------------*/
bool I2C_ChkAck(void)
{
SCL_L;
I2C_delay();
SDA_H;
I2C_delay();
SCL_H;
I2C_delay();
if(SDA_read)
{
SCL_L;
return FALSE;
}
SCL_L;
return TRUE;
}
/*----------------------------------------------------
* 函数原型:bool I2C_ReadByte(uint8_t DevAddr,
uint8_t RegAddr, uint8_t* pRcvData)
* 功 能:从指定器件读取指定寄存器中的值
* 输 入:DevAddr:器件地址
* RegAddr:寄存器地址
* pRcvData:接收数据地址指针
* 输 出:bool:TRUE--读取成功, FALSE--读取失败
* 备 注:
*----------------------------------------------------*/
bool I2C_ReadByte(uint8_t DevAddr, uint8_t RegAddr, uint8_t* pRcvData)
{
if(!I2C_Start())
return FALSE; // 发送启动标志
I2C_SendAddress(DevAddr, DIR_WRITE); // 发送器件地址与写标志
if(!I2C_ChkAck())
return FALSE; // 等待应答信号
I2C_SendByte(RegAddr); // 发送寄存器地址
if(!I2C_ChkAck())
return FALSE; // 等待应答信号
if(!I2C_Start())
return FALSE; // 发送启动标志
I2C_SendAddress(DevAddr, DIR_READ); // 发送器件地址与读标志
if(!I2C_ChkAck())
return FALSE; // 等待应答信号
*pRcvData = I2C_ReceiveByte();
I2C_NoAck(); // 发送NoAck信号
I2C_Stop();
return TRUE;
}
/*----------------------------------------------------
* 函数原型:uint8_t I2C_ReceiveByte(void)
* 功 能:I2C接收一个字节
* 输 入:无
* 输 出:uint8_t:接收到的数据
* 备 注:数据从高位到地位依次接收
*----------------------------------------------------*/
uint8_t I2C_ReceiveByte(void)
{
uint8_t i=8;
uint8_t ReceiveByte = 0;
SDA_H;
while(i--)
{
ReceiveByte <<= 1;
SCL_L;
I2C_delay();
SCL_H;
I2C_delay();
if(SDA_read)
{
ReceiveByte |= 0x01;
}
}
SCL_L;
return ReceiveByte;
}
/*----------------------------------------------------
* 函数原型:bool I2C_ReadBuffer(uint8_t DevAddr, uint8_t RegAddr,
uint8_t* pBuffer, uint8_t NumByteToRead)
* 功 能:连续读取指定器件中的数据
* 输 入:DevAddr:器件地址
* RegAddr:寄存器地址
* pBuffer:接收的数组
* NumByteToRead:读取的字节数
* 输 出:bool:成功标志 TRUE--读取成功,FALSE--读取失败
* 备 注:
*----------------------------------------------------*/
bool I2C_ReadBuffer(uint8_t DevAddr, uint8_t RegAddr, uint8_t* pBuffer, uint8_t NumByteToRead)
{
if(!I2C_Start())
return FALSE;
I2C_SendAddress(DevAddr, DIR_WRITE); // 发送器件地址和写标志
if(!I2C_ChkAck()) // 等待确认应答
return FALSE;
I2C_SendByte(RegAddr); // 发送寄存器地址
if(!I2C_ChkAck()) // 等待确认应答
return FALSE;
if(!I2C_Start())
return FALSE;
I2C_SendAddress(DevAddr, DIR_READ); // 发送器件地址和写标志
if(!I2C_ChkAck()) // 等待确认应答
return FALSE;
while(NumByteToRead--)
{
*pBuffer++ = I2C_ReceiveByte(); // 接收数据
if(NumByteToRead > 0) // 最后一次发送NoAck
{
I2C_Ack(); // 发送Ack确认应答
}
}
I2C_NoAck(); // 发送NoAck信号
I2C_Stop();
return TRUE;
}
/*----------------------------------------------------
* 函数原型:bool I2C_WriteByte(uint8_t DevAddr, uint8_t RegAddr, uint8_t data)
* 功 能:单字节写入
* 输 入:DevAddr:地址
* RegAddr:寄存器地址
* data:待写数据
* 输 出:bool:成功标志 TRUE--写入成功,FALSE--写入失败
* 备 注:
*----------------------------------------------------*/
bool I2C_WriteByte(uint8_t DevAddr, uint8_t RegAddr, uint8_t data)
{
if(!I2C_Start()) return FALSE; // 发送起始标志
I2C_SendAddress(DevAddr, DIR_WRITE); // 发送器件地址和写标志
if(!I2C_ChkAck())return FALSE; // 等待确认信号
I2C_SendByte(RegAddr); // 发送寄存器地址
if(!I2C_ChkAck()) return FALSE; // 等待确认信号
I2C_SendByte(data); // 发送数据
if(!I2C_ChkAck()) return FALSE; // 等待确认信号
I2C_Stop(); // 发送停止标志
return TRUE;
}
/*----------------------------------------------------
* 函数原型:bool I2C_WriteBuffer(uint8_t DevAddr,
uint8_t RegAddr, uint8_t* pBuffer,
uint8_t NumByteToWrite)
* 功 能:连续字节写入
* 输 入:DevAddr:器件地址
* pBuffer:待写数据数组
* RegAddr:寄存器地址
* NumByteToWrite:写入字节数量
* 输 出:bool:成功标志 TRUE--写入成功,FALSE--写入失败
* 备 注:
*----------------------------------------------------*/
bool I2C_WriteBuffer(uint8_t DevAddr, uint8_t RegAddr, uint8_t* pBuffer, uint8_t NumByteToWrite)
{
if(!I2C_Start()) return FALSE;
I2C_SendAddress(DevAddr, DIR_WRITE); // 发送器件地址和写标志
if(!I2C_ChkAck()) return FALSE; // 等待确认应答
I2C_SendByte(RegAddr); // 发送寄存器地址
if(!I2C_ChkAck()) return FALSE; // 等待确认应答
while(NumByteToWrite > 0)
{
I2C_SendByte(*pBuffer); // 发送数据
I2C_ChkAck(); // 等待确认应答
pBuffer++;
NumByteToWrite--;
}
I2C_Stop();
return TRUE;
}
|