/************************************************* 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" void i2c_init(void) { i2c_gpio_config(); #ifdef HARDWARE_I2C i2c_config(); #endif } /* @ brief 初始化i2c的GPIO引脚 @ param @ return @ note 2025-09-15 */ void i2c_gpio_config(void) { // 配置引脚时钟 rcu_periph_clock_enable(RCU_GPIOB); #ifdef HARDWARE_I2C 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); #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 } #ifdef HARDWARE_I2C void i2c_config(void) { // 启用 I2C 外设的时钟 rcu_periph_clock_enable(RCU_I2C0); i2c_deinit(I2C_PERIPH); // 配置 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 位地址模式 i2c_mode_addr_config(I2C_PERIPH, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x00);//作为从机时的地址,随意设置即可 // 使能 ACK 应答功能,确保在接收数据后自动发送 ACK i2c_ack_config(I2C_PERIPH, I2C_ACK_ENABLE); // 启用 I2C 外设 i2c_enable(I2C_PERIPH); } void i2c_write(uint8_t *buff, int len, uint8_t device_address) { /* 等待总线空闲 */ while(i2c_flag_get(I2C_PERIPH, I2C_FLAG_I2CBSY)); /* 发送起始条件 */ i2c_start_on_bus(I2C_PERIPH); /* 等待起始条件已发送标志 */ while(!i2c_flag_get(I2C_PERIPH, I2C_FLAG_SBSEND)); /* 发送从机地址(写模式) */ i2c_master_addressing(I2C_PERIPH, device_address << 1, I2C_TRANSMITTER); /* 等待地址已发送标志 */ 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位或类似标志 } //接收1字节数据 void i2c_read(uint8_t *buff, uint16_t len, uint8_t device_address) { /* 等待I2C总线空闲 */ while(i2c_flag_get(I2C_PERIPH, I2C_FLAG_I2CBSY)); /* 向I2C总线发送启动信号 */ i2c_start_on_bus(I2C_PERIPH); /* 等待,直到设置SBSEND位 */ while(!i2c_flag_get(I2C_PERIPH, I2C_FLAG_SBSEND));//设置主机发送启动条件 /* 将从机地址发送到I2C总线 */ i2c_master_addressing(I2C_PERIPH, device_address << 1, I2C_RECEIVER);//设置主机接收 /* 等待地址位被设置 */ 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); } #endif