void MyI2C_W_SCL(uint8_t BitValue);
void MyI2C_W_SDA(uint8_t BitValue);
uint8_t MyI2C_R_SDA(void);
void MyI2C_Start(void);
void MyI2C_Stop(void);
void MyI2C_SendByte(uint8_t Byte);
void MyI2C_SendBuffer(uint8_t *Buffer, uint32_t len);
void MyI2C_RecvBuffer(uint8_t I2C_Slave_Addr, uint8_t AR_Addr, uint8_t *Buffer, uint32_t len);
uint8_t MyI2C_ReceiveByte(void);
void MyI2C_SendAck(uint8_t AckBit);
uint8_t MyI2C_ReceiveAck(void);
// 需要替换的函数
GPIO_WriteBit(); // 引脚电平写入函数
GPIO_ReadInputDataBit(); // 读引脚电平函数
Delay_us(10); // 延迟函数
/**
* [url=home.php?mod=space&uid=247401]@brief[/url] 拉高拉低SCL
* @param {uint8_t} BitValue 0/1
* [url=home.php?mod=space&uid=266161]@return[/url] {*}
*/
void MyI2C_W_SCL(uint8_t BitValue)
{
GPIO_WriteBit(GPIOB, GPIO_Pin_10, (BitAction)BitValue);
Delay_us(10);
}
/**
* @brief : 拉高拉低SDA
* @param {uint8_t} BitValue 0/1
* @return {*}
*/
void MyI2C_W_SDA(uint8_t BitValue)
{
GPIO_WriteBit(GPIOB, GPIO_Pin_11, (BitAction)BitValue);
Delay_us(10);
}
/**
* @brief : 读SDA电平
* @return {*}
*/
uint8_t MyI2C_R_SDA(void)
{
uint8_t BitValue;
BitValue = GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_11);
Delay_us(10);
return BitValue;
}
void MyI2C_Init(void)
{
/*使能外设时钟*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/*结构体配置IIC引脚*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB, GPIO_Pin_10 | GPIO_Pin_11); // 拉高引脚电平
}
/********************************************************************************************************************************************
修改上面的函数就行下面的都是封装好的
IIC通讯原则 发送起始信号 发送一个字节 接收应答标志 发送下一个字节 接收应答标志 发送停止标志
*******************************************************************************************************************************************/
/**
* @brief 发送开始标志
* @return {*}
*/
void MyI2C_Start(void)
{
MyI2C_W_SDA(1);
MyI2C_W_SCL(1);
MyI2C_W_SDA(0);
MyI2C_W_SCL(0);
}
/**
* @brief 发送停止标志
* @return {*}
*/
void MyI2C_Stop(void)
{
/*SCL高电平期间SDA由低变高*/
MyI2C_W_SDA(0);
MyI2C_W_SCL(1);
MyI2C_W_SDA(1);
}
/**
* @brief 起始位后SCL为低 可以放数据在SDA上,随后拉高SCL从机读取主机发送的数据,主机在拉低SCL进入下一位的发送
* @param {uint8_t} Byte
* @return {*}
*/
void MyI2C_SendByte(uint8_t Byte)
{
uint8_t i;
for (i = 0; i < 8; i++)
{
MyI2C_W_SDA(Byte & (0x80 >> i));
MyI2C_W_SCL(1);
MyI2C_W_SCL(0);
}
}
/**
* @brief 发送buffer
* @param {uint8_t} Byte
* @return {*}
*/
void MyI2C_SendBuffer(uint8_t *Buffer, uint32_t len)
{
MyI2C_Start();
for (int i = 0; i < len; i++)
{
MyI2C_SendByte(Buffer[i]);
MyI2C_ReceiveAck();
}
MyI2C_Stop();
}
/**
* @brief : 接收指定从机寄存器地址的buffer
* @param {uint8_t} I2C_Slave_Addr 从机地址
* @param {uint8_t} AR_Addr 寄存器地址
* @param {uint8_t} *Buffer 数据
* @param {uint32_t} len 数据长度
* @return {*}
*/
void MyI2C_RecvBuffer(uint8_t I2C_Slave_Addr, uint8_t AR_Addr, uint8_t *Buffer, uint32_t len)
{
MyI2C_Start();
MyI2C_SendByte(I2C_Slave_Addr);
MyI2C_ReceiveAck();
MyI2C_SendByte(AR_Addr);
MyI2C_ReceiveAck();
MyI2C_Start();
MyI2C_SendByte(I2C_Slave_Addr | 0x01);
MyI2C_ReceiveAck();
for (int i = 0; i < len; i++)
{
Buffer[i] = MyI2C_ReceiveByte();
if (i == len - 1)
{
MyI2C_SendAck(1);
}
else
{
MyI2C_SendAck(0);
}
}
MyI2C_Stop();
}
/**
* @brief 主机先拉高SDA是释放总线的意思,SCL此时为低 ,从机可以 放数据在SDA上,随后主机拉高SCL读取SDA的值在拉低SCL进入下一个周期
* @param {uint8_t} Byte
* @return {*}
*/
uint8_t MyI2C_ReceiveByte(void)
{
uint8_t i, Byte = 0x00;
MyI2C_W_SDA(1);
for (i = 0; i < 8; i++)
{
MyI2C_W_SCL(1);
if (MyI2C_R_SDA() == 1)
{
Byte |= (0x80 >> i);
}
MyI2C_W_SCL(0);
}
return Byte;
}
/**
* @brief 发送应答位
* @param {uint8_t} Byte 0应带继续接收,1不应答
* @return {*}
*/
void MyI2C_SendAck(uint8_t AckBit)
{
MyI2C_W_SDA(AckBit);
MyI2C_W_SCL(1);
MyI2C_W_SCL(0);
}
/**
* @brief 发送应答位
* @param {uint8_t} Byte 0应带继续接收,1不应答
* @return {*}
*/
uint8_t MyI2C_ReceiveAck(void)
{
uint8_t AckBit;
MyI2C_W_SDA(1);
MyI2C_W_SCL(1);
AckBit = MyI2C_R_SDA();
MyI2C_W_SCL(0);
return AckBit;
}
|