2025-09-24 09:50:50 +00:00
|
|
|
|
/*************************************************
|
|
|
|
|
Copyright (c) 2025, 成都赛联科技有限责任公司
|
|
|
|
|
All rights reserved.
|
|
|
|
|
@file drv_i2c.C
|
|
|
|
|
@brief drv_i2c驱动程序
|
|
|
|
|
|
|
|
|
|
@details
|
|
|
|
|
@note
|
|
|
|
|
@author dufresne
|
|
|
|
|
@date 2025/09/24
|
|
|
|
|
|
|
|
|
|
@version v1.0 2025/09/24 初始版本
|
|
|
|
|
*************************************************/
|
|
|
|
|
|
|
|
|
|
#include "drv_i2c.h"
|
2025-09-26 10:17:39 +00:00
|
|
|
|
|
2025-09-24 09:50:50 +00:00
|
|
|
|
|
|
|
|
|
void i2c_init(void)
|
|
|
|
|
{
|
|
|
|
|
i2c_gpio_config();
|
2025-09-26 10:17:39 +00:00
|
|
|
|
|
|
|
|
|
#ifdef HARDWARE_I2C
|
2025-09-24 09:50:50 +00:00
|
|
|
|
i2c_config();
|
2025-09-26 10:17:39 +00:00
|
|
|
|
#endif
|
2025-09-24 09:50:50 +00:00
|
|
|
|
}
|
2025-09-26 10:17:39 +00:00
|
|
|
|
|
2025-09-24 09:50:50 +00:00
|
|
|
|
/*
|
2025-09-26 10:17:39 +00:00
|
|
|
|
@ brief 初始化i2c的GPIO引脚
|
2025-09-24 09:50:50 +00:00
|
|
|
|
@ param
|
|
|
|
|
@ return
|
|
|
|
|
@ note 2025-09-15
|
|
|
|
|
*/
|
|
|
|
|
void i2c_gpio_config(void)
|
|
|
|
|
{
|
|
|
|
|
// 配置引脚时钟
|
|
|
|
|
rcu_periph_clock_enable(RCU_GPIOB);
|
|
|
|
|
|
2025-09-26 10:17:39 +00:00
|
|
|
|
#ifdef HARDWARE_I2C
|
2025-09-24 09:50:50 +00:00
|
|
|
|
gpio_af_set(GPIOB, GPIO_AF_4, I2C_SCL_PIN | I2C_SDA_PIN);
|
|
|
|
|
/* 初始化GPIO复用功能模式 */
|
|
|
|
|
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, I2C_SCL_PIN | I2C_SDA_PIN);
|
|
|
|
|
gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, I2C_SCL_PIN | I2C_SDA_PIN);
|
2025-09-26 10:17:39 +00:00
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
#ifdef SOFTWARE_I2C
|
|
|
|
|
// 设置引脚为输出模式:PB6
|
|
|
|
|
gpio_mode_set(GPIOB, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, I2C_SCL_PIN | I2C_SDA_PIN);
|
|
|
|
|
gpio_output_options_set(GPIOB, GPIO_OTYPE_PP, GPIO_OSPEED_50MHZ, I2C_SCL_PIN | I2C_SDA_PIN);
|
|
|
|
|
I2C_SCL_HIGH;
|
|
|
|
|
I2C_SDA_HIGH;
|
|
|
|
|
#endif
|
2025-09-24 09:50:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2025-09-26 10:17:39 +00:00
|
|
|
|
#ifdef HARDWARE_I2C
|
2025-09-24 09:50:50 +00:00
|
|
|
|
void i2c_config(void)
|
|
|
|
|
{
|
|
|
|
|
// 启用 I2C 外设的时钟
|
|
|
|
|
rcu_periph_clock_enable(RCU_I2C0);
|
2025-09-25 10:05:11 +00:00
|
|
|
|
|
|
|
|
|
i2c_deinit(I2C_PERIPH);
|
|
|
|
|
|
2025-09-24 09:50:50 +00:00
|
|
|
|
// 配置 I2C 的时钟参数:
|
|
|
|
|
// I2C_PERIPH:这里使用的I2C1
|
|
|
|
|
// I2C_SPEED:通信速率(单位为 Hz,常用为 100000 或 400000),这里使用100000
|
|
|
|
|
i2c_clock_config(I2C_PERIPH, I2C_SPEED, I2C_DTCY_2);
|
|
|
|
|
|
|
|
|
|
// 配置 I2C 工作模式和地址:
|
|
|
|
|
// I2C_ADDFORMAT_7BITS:使用 7 位地址模式
|
2025-09-29 09:41:58 +00:00
|
|
|
|
i2c_mode_addr_config(I2C_PERIPH, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x00);//作为从机时的地址,随意设置即可
|
2025-09-25 10:05:11 +00:00
|
|
|
|
|
2025-09-24 09:50:50 +00:00
|
|
|
|
// 使能 ACK 应答功能,确保在接收数据后自动发送 ACK
|
|
|
|
|
i2c_ack_config(I2C_PERIPH, I2C_ACK_ENABLE);
|
2025-09-25 10:05:11 +00:00
|
|
|
|
|
|
|
|
|
// 启用 I2C 外设
|
|
|
|
|
i2c_enable(I2C_PERIPH);
|
|
|
|
|
|
2025-09-24 09:50:50 +00:00
|
|
|
|
}
|
|
|
|
|
|
2025-09-25 10:05:11 +00:00
|
|
|
|
|
|
|
|
|
|
2025-09-26 10:17:39 +00:00
|
|
|
|
void i2c_write(uint8_t *buff, int len, uint8_t device_address)
|
2025-09-24 09:50:50 +00:00
|
|
|
|
{
|
2025-09-25 10:05:11 +00:00
|
|
|
|
/* 等待总线空闲 */
|
|
|
|
|
while(i2c_flag_get(I2C_PERIPH, I2C_FLAG_I2CBSY));
|
|
|
|
|
/* 发送起始条件 */
|
|
|
|
|
i2c_start_on_bus(I2C_PERIPH);
|
|
|
|
|
/* 等待起始条件已发送标志 */
|
|
|
|
|
while(!i2c_flag_get(I2C_PERIPH, I2C_FLAG_SBSEND));
|
|
|
|
|
/* 发送从机地址(写模式) */
|
2025-09-26 10:17:39 +00:00
|
|
|
|
i2c_master_addressing(I2C_PERIPH, device_address << 1, I2C_TRANSMITTER);
|
2025-09-25 10:05:11 +00:00
|
|
|
|
/* 等待地址已发送标志 */
|
|
|
|
|
while(!i2c_flag_get(I2C_PERIPH, I2C_FLAG_ADDSEND));
|
|
|
|
|
/* 清除地址发送标志 */
|
|
|
|
|
i2c_flag_clear(I2C_PERIPH, I2C_FLAG_ADDSEND);
|
|
|
|
|
|
|
|
|
|
for(int i = 0; i < len; i++)
|
|
|
|
|
{
|
|
|
|
|
/* 等待发送数据缓冲区为空 */
|
|
|
|
|
while(!i2c_flag_get(I2C_PERIPH, I2C_FLAG_TBE));
|
|
|
|
|
/* 发送一个字节数据 */
|
|
|
|
|
i2c_data_transmit(I2C_PERIPH, buff[i]);
|
|
|
|
|
}
|
|
|
|
|
/* 等待数据传输完成 */
|
|
|
|
|
while(!i2c_flag_get(I2C_PERIPH, I2C_FLAG_TBE));
|
|
|
|
|
/* 发送停止条件 */
|
|
|
|
|
i2c_stop_on_bus(I2C_PERIPH);
|
|
|
|
|
/* 等待停止条件发送完成 */
|
|
|
|
|
while(I2C_CTL0(I2C_PERIPH) & I2C_CTL0_STOP); // 检查STPDET位或类似标志
|
|
|
|
|
}
|
|
|
|
|
|
2025-09-29 09:41:58 +00:00
|
|
|
|
|
2025-09-25 10:05:11 +00:00
|
|
|
|
//接收1字节数据
|
2025-09-26 10:17:39 +00:00
|
|
|
|
void i2c_read(uint8_t *buff, uint16_t len, uint8_t device_address)
|
2025-09-25 10:05:11 +00:00
|
|
|
|
{
|
|
|
|
|
/* 等待I2C总线空闲 */
|
|
|
|
|
while(i2c_flag_get(I2C_PERIPH, I2C_FLAG_I2CBSY));
|
2025-09-29 09:41:58 +00:00
|
|
|
|
|
2025-09-25 10:05:11 +00:00
|
|
|
|
/* 向I2C总线发送启动信号 */
|
|
|
|
|
i2c_start_on_bus(I2C_PERIPH);
|
|
|
|
|
/* 等待,直到设置SBSEND位 */
|
|
|
|
|
while(!i2c_flag_get(I2C_PERIPH, I2C_FLAG_SBSEND));//设置主机发送启动条件
|
|
|
|
|
|
|
|
|
|
/* 将从机地址发送到I2C总线 */
|
2025-09-26 10:17:39 +00:00
|
|
|
|
i2c_master_addressing(I2C_PERIPH, device_address << 1, I2C_RECEIVER);//设置主机接收
|
2025-09-25 10:05:11 +00:00
|
|
|
|
/* 等待地址位被设置 */
|
|
|
|
|
while(!i2c_flag_get(I2C_PERIPH, I2C_FLAG_ADDSEND));
|
|
|
|
|
/* 清除地址位 */
|
|
|
|
|
i2c_flag_clear(I2C_PERIPH, I2C_FLAG_ADDSEND);
|
|
|
|
|
/* 使能ACK(多个字节接收时需要应答) */
|
|
|
|
|
i2c_ack_config(I2C_PERIPH, I2C_ACK_ENABLE);
|
|
|
|
|
|
|
|
|
|
/* 5. 接收数据 */
|
|
|
|
|
if(len > 1)
|
|
|
|
|
{
|
|
|
|
|
/* 使能ACK(多个字节接收时需要应答) */
|
|
|
|
|
i2c_ack_config(I2C_PERIPH, I2C_ACK_ENABLE);
|
|
|
|
|
|
|
|
|
|
for(int i = 0; i < len; i++)
|
|
|
|
|
{
|
|
|
|
|
if(i == (len - 1))
|
|
|
|
|
{
|
|
|
|
|
/* 最后一个字节前禁用ACK */
|
|
|
|
|
i2c_ack_config(I2C_PERIPH, I2C_ACK_DISABLE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 等待RBNE标志(接收缓冲区非空) */
|
|
|
|
|
while(!i2c_flag_get(I2C_PERIPH, I2C_FLAG_RBNE));
|
|
|
|
|
|
|
|
|
|
/* 读取数据 */
|
|
|
|
|
buff[i] = i2c_data_receive(I2C_PERIPH);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
/* 单字节接收:直接禁用ACK */
|
|
|
|
|
i2c_ack_config(I2C_PERIPH, I2C_ACK_DISABLE);
|
|
|
|
|
|
|
|
|
|
/* 等待RBNE标志 */
|
|
|
|
|
while(!i2c_flag_get(I2C_PERIPH, I2C_FLAG_RBNE));
|
|
|
|
|
|
|
|
|
|
/* 读取数据 */
|
|
|
|
|
buff[0] = i2c_data_receive(I2C_PERIPH);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* 发送停止信号 */
|
|
|
|
|
i2c_stop_on_bus(I2C_PERIPH);
|
|
|
|
|
/* 等待停止信号完成 */
|
|
|
|
|
while(I2C_CTL0(I2C_PERIPH) & I2C_CTL0_STOP);
|
2025-09-24 09:50:50 +00:00
|
|
|
|
}
|
2025-09-26 10:17:39 +00:00
|
|
|
|
|
|
|
|
|
#endif
|