/** ****************************************************************************** * @文件 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; }