STM32H750XB_RT-THREAD/I2C—AP3216C(光照三合一)/4.AP3216C全功能例程_(模拟I2C)/User/i2c/bsp_i2c.c
2025-07-21 14:34:29 +08:00

489 lines
11 KiB
C
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/**
******************************************************************************
* @file bsp_i2c.c
* @author fire
* @version V1.0
* @date 2019-xx-xx
* @brief I2C 配置文件
******************************************************************************
* @attention
*
* 实验平台:野火 STM32 H750 开发板
* 论坛 :http://www.firebbs.cn
* 淘宝 :http://firestm32.taobao.com
*
******************************************************************************
*/
#include "./i2c/bsp_i2c.h"
#include "./usart/bsp_debug_usart.h"
/**
* @brief I2C I/O配置
* @param 无
* @retval 无
*/
static void I2C_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*使能引脚时钟*/
AP3216C_I2C_SCL_GPIO_CLK_ENABLE();
AP3216C_I2C_SDA_GPIO_CLK_ENABLE();
/*配置SCL引脚 */
GPIO_InitStructure.Pin = AP3216C_I2C_SCL_PIN;
GPIO_InitStructure.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
GPIO_InitStructure.Pull = GPIO_NOPULL;
HAL_GPIO_Init(AP3216C_I2C_SCL_GPIO_PORT, &GPIO_InitStructure);
/*配置SDA引脚 */
GPIO_InitStructure.Pin = AP3216C_I2C_SDA_PIN;
HAL_GPIO_Init(AP3216C_I2C_SCL_GPIO_PORT, &GPIO_InitStructure);
}
/**
* @brief I2C 外设(GT91xx)初始化
* @param 无
* @retval 无
*/
void I2C_Init(void)
{
I2C_GPIO_Config();
}
/*
*********************************************************************************************************
* 函 数 名: i2c_Delay
* 功能说明: I2C总线位延迟最快400KHz
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
static void i2c_Delay(void)
{
uint16_t i;
/* 
下面的时间是通过逻辑分析仪测试得到的。
工作条件CPU主频216MHz MDK编译环境1级优化
循环次数为200时SCL频率 = 100KHz
循环次数为30时SCL频率 = 400KHz
*/
for (i = 0; i < 200; i++);
}
/*
*********************************************************************************************************
* 函 数 名: i2c_Start
* 功能说明: CPU发起I2C总线启动信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_Start(void)
{
/* 当SCL高电平时SDA出现一个下跳沿表示I2C总线启动信号 */
I2C_SDA_1();
I2C_SCL_1();
i2c_Delay();
I2C_SDA_0();
i2c_Delay();
I2C_SCL_0();
i2c_Delay();
}
/*
*********************************************************************************************************
* 函 数 名: i2c_Start
* 功能说明: CPU发起I2C总线停止信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_Stop(void)
{
/* 当SCL高电平时SDA出现一个上跳沿表示I2C总线停止信号 */
I2C_SDA_0();
I2C_SCL_1();
i2c_Delay();
I2C_SDA_1();
}
/*
*********************************************************************************************************
* 函 数 名: i2c_SendByte
* 功能说明: CPU向I2C总线设备发送8bit数据
* 形 参_ucByte 等待发送的字节
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_SendByte(uint8_t _ucByte)
{
uint8_t i;
/* 先发送字节的高位bit7 */
for (i = 0; i < 8; i++)
{
if (_ucByte & 0x80)
{
I2C_SDA_1();
}
else
{
I2C_SDA_0();
}
i2c_Delay();
I2C_SCL_1();
i2c_Delay();
I2C_SCL_0();
if (i == 7)
{
I2C_SDA_1(); // 释放总线
}
_ucByte <<= 1; /* 左移一个bit */
i2c_Delay();
}
}
/*
*********************************************************************************************************
* 函 数 名: i2c_ReadByte
* 功能说明: CPU从I2C总线设备读取8bit数据
* 形 参:无
* 返 回 值: 读到的数据
*********************************************************************************************************
*/
uint8_t i2c_ReadByte(void)
{
uint8_t i;
uint8_t value;
/* 读到第1个bit为数据的bit7 */
value = 0;
for (i = 0; i < 8; i++)
{
value <<= 1;
I2C_SCL_1();
i2c_Delay();
if (I2C_SDA_READ())
{
value++;
}
I2C_SCL_0();
i2c_Delay();
}
return value;
}
/*
*********************************************************************************************************
* 函 数 名: i2c_WaitAck
* 功能说明: CPU产生一个时钟并读取器件的ACK应答信号
* 形 参:无
* 返 回 值: 返回0表示正确应答1表示无器件响应
*********************************************************************************************************
*/
uint8_t i2c_WaitAck(void)
{
uint8_t re;
I2C_SDA_1(); /* CPU释放SDA总线 */
i2c_Delay();
I2C_SCL_1(); /* CPU驱动SCL = 1, 此时器件会返回ACK应答 */
i2c_Delay();
if (I2C_SDA_READ()) /* CPU读取SDA口线状态 */
{
re = 1;
}
else
{
re = 0;
}
I2C_SCL_0();
i2c_Delay();
return re;
}
/*
*********************************************************************************************************
* 函 数 名: i2c_Ack
* 功能说明: CPU产生一个ACK信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_Ack(void)
{
I2C_SDA_0(); /* CPU驱动SDA = 0 */
i2c_Delay();
I2C_SCL_1(); /* CPU产生1个时钟 */
i2c_Delay();
I2C_SCL_0();
i2c_Delay();
I2C_SDA_1(); /* CPU释放SDA总线 */
}
/*
*********************************************************************************************************
* 函 数 名: i2c_NAck
* 功能说明: CPU产生1个NACK信号
* 形 参:无
* 返 回 值: 无
*********************************************************************************************************
*/
void i2c_NAck(void)
{
I2C_SDA_1(); /* CPU驱动SDA = 1 */
i2c_Delay();
I2C_SCL_1(); /* CPU产生1个时钟 */
i2c_Delay();
I2C_SCL_0();
i2c_Delay();
}
#define I2C_DIR_WR 0 /* 写控制bit */
#define I2C_DIR_RD 1 /* 读控制bit */
/**
* @brief 使用IIC读取数据
* @param
* @arg ClientAddr:从设备地址
* @arg pBuffer:存放由从机读取的数据的缓冲区指针
* @arg NumByteToRead:读取的数据长度
* @retval 无
*/
uint32_t I2C_ReadBytes(uint8_t ClientAddr,uint8_t* pBuffer, uint16_t NumByteToRead)
{
/* 第1步发起I2C总线启动信号 */
i2c_Start();
/* 第2步发起控制字节高7bit是地址bit0是读写控制位0表示写1表示读 */
i2c_SendByte(ClientAddr | I2C_DIR_RD); /* 此处是读指令 */
/* 第3步等待ACK */
if (i2c_WaitAck() != 0)
{
goto cmd_fail; /* 器件无应答 */
}
while(NumByteToRead)
{
if(NumByteToRead == 1)
{
i2c_NAck(); /* 最后1个字节读完后CPU产生NACK信号(驱动SDA = 1) */
/* 发送I2C总线停止信号 */
i2c_Stop();
}
*pBuffer = i2c_ReadByte();
/* 读指针自增 */
pBuffer++;
/*计数器自减 */
NumByteToRead--;
i2c_Ack(); /* 中间字节读完后CPU产生ACK信号(驱动SDA = 0) */
}
/* 发送I2C总线停止信号 */
i2c_Stop();
return 0; /* 执行成功 */
cmd_fail: /* 命令执行失败后切记发送停止信号避免影响I2C总线上其他设备 */
/* 发送I2C总线停止信号 */
i2c_Stop();
return 1;
}
/**
* @brief 使用IIC写入数据
* @param
* @arg ClientAddr:从设备地址
* @arg pBuffer:缓冲区指针
* @arg NumByteToWrite:写的字节数
* @retval 无
*/
uint32_t I2C_WriteBytes(uint8_t ClientAddr,uint8_t* pBuffer, uint8_t NumByteToWrite)
{
uint16_t m;
/* 第0步发停止信号启动内部写操作 */
i2c_Stop();
/* 通过检查器件应答的方式,判断内部写操作是否完成, 一般小于 10ms
CLK频率为200KHz时查询次数为30次左右
*/
for (m = 0; m < 1000; m++)
{
/* 第1步发起I2C总线启动信号 */
i2c_Start();
/* 第2步发起控制字节高7bit是地址bit0是读写控制位0表示写1表示读 */
i2c_SendByte(ClientAddr | I2C_DIR_WR); /* 此处是写指令 */
/* 第3步发送一个时钟判断器件是否正确应答 */
if (i2c_WaitAck() == 0)
{
break;
}
}
if (m == 1000)
{
goto cmd_fail; /* EEPROM器件写超时 */
}
while(NumByteToWrite--)
{
/* 第4步开始写入数据 */
i2c_SendByte(*pBuffer);
/* 第5步检查ACK */
if (i2c_WaitAck() != 0)
{
goto cmd_fail; /* 器件无应答 */
}
pBuffer++; /* 地址增1 */
}
/* 命令执行成功发送I2C总线停止信号 */
i2c_Stop();
return 0;
cmd_fail: /* 命令执行失败后切记发送停止信号避免影响I2C总线上其他设备 */
/* 发送I2C总线停止信号 */
i2c_Stop();
return 1;
}
/**
* @brief 写数据到AP3216C寄存器
* @param reg_add:寄存器地址
* @param reg_data:要写入的数据
* @retval
*/
uint32_t Sensor_write(uint8_t reg_add,uint8_t reg_dat)
{
/* 第0步发停止信号启动内部写操作 */
i2c_Stop();
/* 第1步发起I2C总线启动信号 */
i2c_Start();
/* 第2步发起控制字节高7bit是地址bit0是读写控制位0表示写1表示读 */
i2c_SendByte(AP3216C_ADDR | I2C_DIR_WR); /* 此处是写指令 */
/* 第3步发送一个时钟判断器件是否正确应答 */
if (i2c_WaitAck() != 0)
{
goto cmd_fail; /* EEPROM器件写超时 */
}
/* 第4步开始写入寄存器地址 */
i2c_SendByte(reg_add);
/* 第5步检查ACK */
if (i2c_WaitAck() != 0)
{
goto cmd_fail; /* 器件无应答 */
}
/* 第5步开始写入数据 */
i2c_SendByte(reg_dat);
/* 第5步检查ACK */
if (i2c_WaitAck() != 0)
{
goto cmd_fail; /* 器件无应答 */
}
/* 命令执行成功发送I2C总线停止信号 */
i2c_Stop();
return 0;
cmd_fail: /* 命令执行失败后切记发送停止信号避免影响I2C总线上其他设备 */
/* 发送I2C总线停止信号 */
i2c_Stop();
return 1;
}
/**
* @brief 写数据到AP3216C寄存器
* @param reg_add:寄存器地址
* @param reg_data:要写入的数据
* @retval
*/
uint32_t Sensor_Read(uint8_t reg_add,unsigned char* Read,uint8_t num)
{
/* 第0步发停止信号启动内部写操作 */
i2c_Stop();
/* 第1步发起I2C总线启动信号 */
i2c_Start();
/* 第2步发起控制字节高7bit是地址bit0是读写控制位0表示写1表示读 */
i2c_SendByte(AP3216C_ADDR | I2C_DIR_WR); /* 此处是写指令 */
/* 第3步发送一个时钟判断器件是否正确应答 */
if (i2c_WaitAck() != 0)
{
goto cmd_fail; /* EEPROM器件写超时 */
}
/* 第4步开始写入寄存器地址 */
i2c_SendByte(reg_add);
/* 第5步检查ACK */
if (i2c_WaitAck() != 0)
{
goto cmd_fail; /* 器件无应答 */
}
/* 发送I2C总线停止信号 */
i2c_Stop();
/* 第6步发起I2C总线启动信号 */
i2c_Start();
/* 第7步发起控制字节高7bit是地址bit0是读写控制位0表示写1表示读 */
i2c_SendByte(AP3216C_ADDR | I2C_DIR_RD); /* 此处是读指令 */
/* 第8步检查ACK */
if (i2c_WaitAck() != 0)
{
goto cmd_fail; /* 器件无应答 */
}
while(num)
{
*Read = i2c_ReadByte();
/* 读指针自增 */
Read++;
if(num == 1)
{
i2c_NAck(); /* 最后1个字节读完后CPU产生NACK信号(驱动SDA = 1) */
}
else
{
i2c_Ack(); /* 中间字节读完后CPU产生ACK信号(驱动SDA = 0) */
}
/*计数器自减 */
num--;
}
/* 发送I2C总线停止信号 */
i2c_Stop();
return 0; /* 执行成功 */
cmd_fail: /* 命令执行失败后切记发送停止信号避免影响I2C总线上其他设备 */
/* 发送I2C总线停止信号 */
i2c_Stop();
return 1;
}
/*********************************************END OF FILE**********************/