/**
 ******************************************************************************
 * @文件     iic.c
 * @作者     阜阳师范大学物电学院
 * @版本     V0.1
 * @日期     2025-03-27
 * @简介     软件 IIC 驱动程序
 ******************************************************************************
 **/

#include "iic.h"


/**
  * @brief  IIC初始化函数
  * @note   初始化IIC通信所需的GPIO引脚，配置为开漏输出模式
  * @retval 无
  */
void iic_init()
{
    GPIO_InitTypeDef gpio_init_struct;
    
    IIC_SCL_GPIO_CLK_ENABLE();
    IIC_SDA_GPIO_CLK_ENABLE();
    
    gpio_init_struct.Pin = IIC_SCL_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;
    gpio_init_struct.Pull = GPIO_PULLUP;
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(IIC_SCL_GPIO_PORT,&gpio_init_struct);
    
    gpio_init_struct.Pin = IIC_SDA_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_OD;
    HAL_GPIO_Init(IIC_SDA_GPIO_PORT,&gpio_init_struct);
    
    IIC_SDA(1);
    IIC_SCL(1);
}

/**
  * @brief  IIC总线延时函数
  * @note   提供固定2微秒的延时，满足IIC通信时序要求
  * @retval 无
  */
static void iic_delay(void)
{
    delay_us(2);
}

/**
  * @brief  产生IIC起始信号
  * @note   起始信号时序：SCL高电平时，SDA由高变低
  * @retval 无
  */
void iic_start(void)
{
    IIC_SCL(1);
    IIC_SDA(1);
    iic_delay();
    IIC_SDA(0);
    iic_delay();
    IIC_SCL(0);
    iic_delay();
}

/**
  * @brief  向IIC总线发送一个字节数据
  * @param  data：待发送的8位数据
  * @retval 无
  */
void iic_send_byte(uint8_t data)
{
    uint8_t t;
    for(t = 0;t<8;t++)
    {
        IIC_SDA((data&0x80)>>7);
        iic_delay();
        IIC_SCL(1);
        iic_delay();  
        IIC_SCL(0);
        data<<=1;
    }
    IIC_SDA(1);
}

/**
  * @brief  产生IIC停止信号
  * @note   停止信号时序：SCL高电平时，SDA由低变高
  * @retval 无
  */
void iic_stop(void)
{
    IIC_SDA(0);
    iic_delay();
    IIC_SCL(1);
    iic_delay();
    IIC_SDA(1);
    iic_delay();
}

/**
  * @brief  等待IIC从机应答信号
  * @note   从机应答信号为SDA低电平，超时自动释放总线
  * @retval 1：未接收到应答，0：接收到应答
  */
uint8_t iic_wait_ack(void)//返回1：失败，0：成功
{
    IIC_SDA(1);
    iic_delay();
    IIC_SCL(1);
    iic_delay();
    if(IIC_READ_SDA)
    {
        iic_stop();
        return 1;
    }
    IIC_SCL(0);
    iic_delay();
    
    return 0;
}

/**
  * @brief  主机发送应答信号
  * @note   应答信号时序：SCL高电平时，SDA保持低电平
  * @retval 无
  */
void iic_ack(void)
{
    IIC_SCL(0);
    iic_delay();
    IIC_SDA(0);     
    iic_delay();
    IIC_SCL(1);
    iic_delay();
}

/**
  * @brief  主机发送非应答信号
  * @note   非应答信号时序：SCL高电平时，SDA保持高电平
  * @retval 无
  */
void iic_nack(void)
{
    IIC_SCL(0);     /* 产生一个时钟 */
    iic_delay();
    IIC_SDA(1);
    iic_delay();
    IIC_SCL(1);     /* 主机释放SDA线 */
    iic_delay();
}

/**
  * @brief  从IIC总线读取一个字节数据
  * @param  ack：应答控制，0=发送非应答，1=发送应答
  * @retval 读取到的8位数据
  */
uint8_t iic_read_byte(uint8_t ack)
{
    uint8_t i,receive = 0;
    
    for(i=0;i<8;i++)
    {
        receive<<=1;
        IIC_SCL(1);
        iic_delay();
        if(IIC_READ_SDA) receive++;
        IIC_SCL(0);
        iic_delay();
    }
    if(!ack) iic_nack();
    else iic_ack();
    
    return receive;
}
