Files

209 lines
4.0 KiB
C
Raw Permalink Normal View History

#include "SoftI2C.h"
void Dri_I2C_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 1. 时钟使能GPIOA
__HAL_RCC_GPIOA_CLK_ENABLE();
// 2. 设置引脚模式PA8(SDA), PA9(SCL)设置为通用开漏输出
GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; // 通用开漏输出
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; // 高速
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
// 发送起始信号
void Dri_I2C_Start(void)
{
// 拉高SCL、拉高SDA、延时
SCL_HIGH;
SDA_HIGH;
SCL_DELAY;
// 拉低SDA下降沿表示起始信号; 延时
SDA_LOW;
SCL_DELAY;
// 拉低SCL方便发送方修改SDA
SCL_LOW;
SCL_DELAY;
}
// 发送停止信号
void Dri_I2C_Stop(void)
{
// 在拉高SCL之前先拉低SDA (避免意外产生起始信号)
SDA_LOW;
// 拉高SCL并延时
SCL_HIGH;
SCL_DELAY;
// SCL高电平期间拉高SDA发起结束信号
SDA_HIGH;
SCL_DELAY;
}
// 发送一个字节的数据
void Dri_I2C_TransmitByte(uint8_t byte)
{
// 分8次逐bit发送先发高位
for (uint8_t i = 0; i < 8; i++)
{
// 判断当前 byte 的最高位
if (byte & 0x80)
{
SDA_HIGH;
}
else
{
SDA_LOW;
}
// 拉高时钟并延时,让接收方采样
SCL_HIGH;
SCL_DELAY;
// byte 左移1位
byte <<= 1;
// 拉低SCL好准备下一个要发的数据
SCL_LOW;
SCL_DELAY;
}
}
// 接收一个字节的数据
uint8_t Dri_I2C_ReceiveByte(void)
{
// 释放数据总线
SDA_HIGH;
// 定义变量,用于接收数据
uint8_t byte = 0;
// 分8次逐bit接收先收高位
for (uint8_t i = 0; i < 8; i++)
{
// 拉高SCL
SCL_HIGH;
// byte 左移1位空出最低位用于接收当前的bit
byte <<= 1;
// 读SDA, 如果SDA是高电平
if (SDA_READ)
{
byte |= 0x01;
}
// 延时
SCL_DELAY;
// 拉低SCL并延时让发送方准备数据
SCL_LOW;
SCL_DELAY;
}
// 返回
return byte;
}
// 发送一个ACK信号, 参数是0(ACK)或1(NACK)
void Dri_I2C_TransmitACK(uint8_t ack)
{
if (ack)
{
// 发送NACK
SDA_HIGH;
}
else
{
// 发送ACK
SDA_LOW;
}
// 拉高时钟并延时
SCL_HIGH;
SCL_DELAY;
// 高低时钟并延时
SCL_LOW;
SCL_DELAY;
}
// 接收一个ACK信号并返回
uint8_t Dri_I2C_ReceiveACK(void)
{
// 定义变量保存收到的ack信号
uint8_t ack = 0;
// 释放数据总线
SDA_HIGH;
// 拉高SCL
SCL_HIGH;
// 读取SDA
ack = SDA_READ ? 1 : 0;
// 延时
SCL_DELAY;
// 拉低SCL并延时
SCL_LOW;
SCL_DELAY;
return ack;
}
void Dri_I2C_WriteAddr(uint8_t slave_addr)
{
Dri_I2C_TransmitByte(slave_addr);
uint8_t ack = Dri_I2C_ReceiveACK();
if (ack)
{
debug_printf("I2C send slave address error");
return;
}
}
void Dri_I2C_WriteReg(uint8_t reg, uint8_t data)
{
Dri_I2C_TransmitByte(reg);
uint8_t ack = Dri_I2C_ReceiveACK();
if (ack)
{
debug_printf("I2C send register address error");
return;
}
Dri_I2C_TransmitByte(data);
ack = Dri_I2C_ReceiveACK();
if (ack)
{
debug_printf("I2C send register data error");
return;
}
}
uint8_t Dri_I2C_ReadReg(uint8_t slave_addr_read, uint8_t reg)
{
Dri_I2C_Start();
Dri_I2C_WriteAddr(slave_addr_read - 1);
Dri_I2C_TransmitByte(reg);
uint8_t ack = Dri_I2C_ReceiveACK();
if (ack)
{
debug_printf("I2C send register address error");
return 0;
}
Dri_I2C_Start();
Dri_I2C_WriteAddr(slave_addr_read);
uint8_t data = Dri_I2C_ReceiveByte();
Dri_I2C_TransmitACK(0);
Dri_I2C_Stop();
return data;
}