- 学习目标
- 学习内容
- define SCL_RCU RCU_GPIOB
- define SCL_PORT GPIOB
- define SCL_PIN GPIO_PIN_6
- define SCL_AF GPIO_AF_4
- define SDA_RCU RCU_GPIOB
- define SDA_PORT GPIOB
- define SDA_PIN GPIO_PIN_7
- define SDA_AF GPIO_AF_4
- define SCL(BIT) gpio_bit_write(SCL_PORT, SCL_PIN, BIT?SET:RESET)
- define SDA(BIT) gpio_bit_write(SDA_PORT, SDA_PIN, BIT?SET:RESET)
- define SDA_STATE() gpio_input_bit_get(SDA_PORT, SDA_PIN)
- define SDA_IN() gpio_mode_set(SDA_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, SDA_PIN)
- define SDA_OUT() gpio_mode_set(SDA_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SDA_PIN)
- 硬件I2C-GD32F4系列
学习目标
- 理解I2C通讯原理
- 理解I2C通讯过程中的信号
- 理解软件I2C实现过程
-
学习内容
I2C通讯规则
I2C总线包括两根信号线:SDA(串行数据线)和SCL(串行时钟线)。这两根信号线共用一个总线,因此在总线上可以连接多个设备。在I2C总线上,每个设备都有一个唯一的地址,用于标识设备。
SCL线是时钟线,用于控制数据传输的速度和时序;SDA线是数据线,用于传输实际的数据.I2C写操作
流程如下:
开始。
- 发送设备地址,等待从设备响应
- 发送寄存器地址,等待从设备响应
- 发送一个字节,等待从设备响应。这个操作是循环执行,直到没有数据。
- 停止。
I2C读流程
流程如下:
- 开始。
- 发送设备地址(写地址),等待从设备响应
- 发送寄存器地址,等待从设备响应。
- 开始
- 发送设备地址(读地址),等待从设备响应
- 接收一个字节,发送响应给从设备。这个操作是循环执行,直到没有数据。当是最后一个数据时,发送空响应。
- 停止。
通讯信号
开始
static void start() {
SDA_OUT();
SDA(1);
delay_1us(5);
SCL(1);
delay_1us(5);
SDA(0);
delay_1us(5);
SCL(0);
delay_1us(5);
}
结束
static void stop() {
SDA_OUT();
SCL(0);
SDA(0);
SCL(1);
delay_1us(5);
SDA(1);
delay_1us(5);
}
发送数据
bit发送
数据有效性:
- SCL上升沿到下降沿这个阶段,SDA电平的高低,表示数据bit的1和0
如果SDA电平在这个阶段发生变化,则无效,参考start和stop信号。
Byte发送
基于数据有效性,将byte按bit位变化为高低电平,发送出去。
static void send(uint8_t data) {
uint8_t i;
SDA_OUT();
for(i = 0; i < 8; i++) {
if(data & 0x80) {
SDA(1);
} else {
SDA(0);
}
SCL(1);
delay_1us(5);
SCL(0);
delay_1us(5);
data <<= 1;
}
}
等待响应
wait ack:_Ack_nowledge character。表示等待响应,每发送一个数据,需要确认对方是否收到,就需要等待对方响应。
static uint8_t wait_ack() {
int8_t retry = 10;
SCL(0);
SDA(1);
SDA_IN();
delay_1us(5);
SCL(1);
delay_1us(5);
while(SDA_STATE() == 1 && retry > 0) {
retry --;
delay_1us(5);
}
if(retry <= 0) {
stop();
return 1;
} else {
SCL(0);
SDA_OUT();
}
return 0;
}
接收数据
bit接收
Byte接收
static uint8_t recv() {
uint8_t i, data;
SDA_IN();
data = 0;
for(i = 0; i < 8; i++) {
SCL(0);
delay_1us(5);
SCL(1);
delay_1us(5);
data <<= 1;
data |= SDA_STATE();
delay_1us(5);
}
SCL(0);
return data;
}
发送响应
static void send_ack() {
SDA_OUT();
SCL(0);
SDA(0);
delay_1us(5);
SDA(0);
SCL(1);
delay_1us(5);
SCL(0);
SDA(1);
}
static void send_nack() {
SDA_OUT();
SCL(0);
SDA(0);
delay_1us(5);
SDA(1);
SCL(1);
delay_1us(5);
SCL(0);
SDA(1);
}
软件I2C
开发流程
- 引脚初始化
- 引脚功能定义
- 实现读操作
-
GD32F4软件I2C初始化
void SoftI2C_init() {
// 时钟配置
rcu_periph_clock_enable(SCL_RCU);
// 设置输出模式
gpio_mode_set(SCL_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SCL_PIN);
gpio_output_options_set(SCL_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, SCL_PIN);
// 时钟配置
rcu_periph_clock_enable(SDA_RCU);
// 设置输出模式
gpio_mode_set(SDA_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SDA_PIN);
gpio_output_options_set(SDA_PORT, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, SDA_PIN);
}
- I2C引脚高低电平
GD32F4软件I2C引脚功能
```cdefine SCL_RCU RCU_GPIOB
define SCL_PORT GPIOB
define SCL_PIN GPIO_PIN_6
define SCL_AF GPIO_AF_4
define SDA_RCU RCU_GPIOB
define SDA_PORT GPIOB
define SDA_PIN GPIO_PIN_7
define SDA_AF GPIO_AF_4
/** io */
define SCL(BIT) gpio_bit_write(SCL_PORT, SCL_PIN, BIT?SET:RESET)
define SDA(BIT) gpio_bit_write(SDA_PORT, SDA_PIN, BIT?SET:RESET)
define SDA_STATE() gpio_input_bit_get(SDA_PORT, SDA_PIN)
define SDA_IN() gpio_mode_set(SDA_PORT, GPIO_MODE_INPUT, GPIO_PUPD_NONE, SDA_PIN)
define SDA_OUT() gpio_mode_set(SDA_PORT, GPIO_MODE_OUTPUT, GPIO_PUPD_NONE, SDA_PIN)
- IO引脚定义
- 引脚输出模式高低电平输出:SCL高和低,SDA高和低
- SDA模式配置:SDA输出模式,SDA输入模式
- SDA输入模式状态读取。
<a name="tWatG"></a>
#### 写操作
![031.png](https://cdn.nlark.com/yuque/0/2023/png/27903758/1692842768446-3c8ee866-5cbf-4ef6-820e-3fc85b744592.png#averageHue=%23140a04&clientId=uff3818e1-2c0e-4&from=ui&height=425&id=u42a0aaa4&originHeight=760&originWidth=442&originalType=binary&ratio=1&rotation=0&showTitle=false&size=194479&status=done&style=none&taskId=u6e0b107f-f9ad-4c5b-99e3-7e152dffed5&title=&width=247)
```c
uint8_t SoftI2C_write(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len) {
start();
send(addr << 1); //发送设备写地址
if(wait_ack()) return 1; //等待响应
send(reg); //发送寄存器地址
if(wait_ack()) return 2; //等待响应
do {
send(*data++);
if(wait_ack()) return 3;
} while(--len);
stop();
return 0;
}
读操作
uint8_t SoftI2C_read(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len) {
start();
send(addr << 1); //发送设备写地址
if(wait_ack()) return 1; //等待响应
send(reg); //发送寄存器地址
if(wait_ack()) return 2; //等待响应
start();
send((addr << 1) | 0x01); //发送设备读地址
if(wait_ack()) return 3; //等待响应
do {
*data = recv();
data++;
if(len != 1) send_ack(); // 发送 NACK
} while(--len);
send_nack(); // 发送 NACK
stop();
return 0;
}
硬件I2C-GD32F4系列
初始化操作
uint32_t i2cx_scl_port_rcu = RCU_GPIOB;
uint32_t i2cx_scl_port = GPIOB;
uint32_t i2cx_scl_pin = GPIO_PIN_6;
uint32_t i2cx_scl_af = GPIO_AF_4;
uint32_t i2cx_sda_port_rcu = RCU_GPIOB;
uint32_t i2cx_sda_port = GPIOB;
uint32_t i2cx_sda_pin = GPIO_PIN_7;
uint32_t i2cx_sda_af = GPIO_AF_4;
uint32_t i2cx = I2C0;
uint32_t i2cx_rcu = RCU_I2C0;
uint32_t i2cx_speed = 400000;
/****************** GPIO config **********************/
// 时钟配置
rcu_periph_clock_enable(i2cx_scl_port_rcu);
// 设置复用功能
gpio_af_set(i2cx_scl_port, i2cx_scl_af, i2cx_scl_pin);
// 设置输出模式
gpio_mode_set(i2cx_scl_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_scl_pin);
gpio_output_options_set(i2cx_scl_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_scl_pin);
// 时钟配置
rcu_periph_clock_enable(i2cx_sda_port_rcu);
// 设置复用功能
gpio_af_set(i2cx_sda_port, i2cx_sda_af, i2cx_sda_pin);
// 设置输出模式
gpio_mode_set(i2cx_sda_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_sda_pin);
gpio_output_options_set(i2cx_sda_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_sda_pin);
/****************** I2C config **********************/
i2c_deinit(i2cx);
// 时钟配置
rcu_periph_clock_enable(i2cx_rcu);
// I2C速率配置
i2c_clock_config(i2cx, i2cx_speed, I2C_DTCY_2);
// 使能i2c
i2c_mode_addr_config(i2cx, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x00);
i2c_enable(i2cx);
// i2c ack enable
i2c_ack_config(i2cx, I2C_ACK_ENABLE);
- 哪个I2C
- SCL是哪个引脚
- SDA是哪个引脚
- 速度是多快
写操作流程
开始
```c /* start */ // 等待I2C闲置 if(I2C_waitn(i2cx, I2C_FLAG_I2CBSY)) return 1;
// start i2c_start_on_bus(i2cx);
// 等待I2C主设备成功发送起始信号 if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 2;
<a name="WtaJX"></a>
##### 发送设备地址
```c
/************* device address **************/
// 发送设备地址
i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);
// 等待地址发送完成
if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 3;
i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);
发送寄存器地址
/************ register address ************/
// 寄存器地址
// 等待发送数据缓冲区为空
if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 4;
// 发送数据
i2c_data_transmit(i2cx, reg);
// 等待数据发送完成
if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 5;
数据发送
/***************** data ******************/
// 发送数据
uint32_t i;
for(i = 0; i < data_len; i++) {
uint32_t d = data[i];
// 等待发送数据缓冲区为空
if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 6;
// 发送数据
i2c_data_transmit(i2cx, d);
// 等待数据发送完成
if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 7;
}
停止
/***************** stop ********************/
// stop
i2c_stop_on_bus(i2cx);
if(I2C_waitn(i2cx, I2C_CTL0(I2C0)&I2C_CTL0_STOP)) return 8;
读操作流程
开始
/************* start ***********************/
// 等待I2C空闲
if(I2C_waitn(i2cx, I2C_FLAG_I2CBSY)) return 1;
// 发送启动信号
i2c_start_on_bus(i2cx);
if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 2;
发送设备地址(写)
/************* device address **************/
// 发送从设备地址
i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);
if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 3;
i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);
发送寄存器地址
/********** register address **************/
// 等待发送缓冲区
if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 4;
// 发送寄存器地址
i2c_data_transmit(i2cx, reg);
// 等待发送数据完成
if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 5;
if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 6;
开始
/************* start ***********************/
// 发送再启动信号
i2c_start_on_bus(i2cx);
if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 7;
发送设备地址(读)
/************* device address **************/
// 发送从设备地址
i2c_master_addressing(i2cx, address, I2C_RECEIVER);
if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 8;
i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);
//ack
i2c_ack_config(i2cx, I2C_ACK_ENABLE);
i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);
if(I2C_wait(i2cx, (I2C_CTL0(i2cx) & I2C_CTL0_ACKEN))) return 23;
数据读取
/************* data **************/
//ack
i2c_ack_config(i2cx, I2C_ACK_ENABLE);
i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);
if(I2C_wait(i2cx, (I2C_CTL0(i2cx) & I2C_CTL0_ACKEN))) return 11;
// 读取数据
uint8_t i;
for (i = 0; i < len; i++) {
if(i != len - 1) {
// 等待接收缓冲区
if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 9;
}
// 等待ACK数据发送完成
// 等待接收缓冲区
if(I2C_wait(i2cx, I2C_FLAG_RBNE)) return 10;
data[i] = i2c_data_receive(i2cx);
if (i == len - 1) {
// 在读取最后一个字节之前,禁用ACK,并发送停止信号
// 配置自动NACK
i2c_ack_config(i2cx, I2C_ACK_DISABLE);
}
}
结束
/***************** stop ********************/
i2c_stop_on_bus(i2cx);
if(I2C_waitn(i2cx, I2C_CTL0(I2C0) & I2C_CTL0_STOP)) return 11;
GD32F4寄存器
流程 | 功能 | 标记 | 描述 |
---|---|---|---|
START | I2C_FLAG_I2CBSY |
busy标记。I2C是否占用,没有占用才可以使用。 | |
I2C_FLAG_SBSEND |
起始信号发送状态标记。START成功或失败。 | ||
数据 | 设备地址 | I2C_FLAG_ADDSEND |
地址发送状态标记。成功或失败。 |
发送 | I2C_FLAG_TBE |
发送数据寄存器是否为空的标记。为空才可以继续发送。 | |
I2C_FLAG_BTC |
发送数据寄存器中数据是否发送完成。 | ||
接收 | I2C_FLAG_RBNE |
接收缓冲区寄存器是否为空的标记。为空才可以继续接收。 | |
STOP | I2C_CTL0_STOP |
停止标记位。 |
完整代码
#ifndef __I2C0_H__
#define __I2C0_H__
#include "systick.h"
#include "gd32f4xx.h"
void I2C0_init();
uint8_t I2C0_read(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len);
uint8_t I2C0_write(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len);
uint8_t I2C0_write2(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t offset, uint32_t len);
void I2C0_deinit();
#endif
#include "I2C0.h"
void I2C0_init() {
uint32_t i2cx_scl_port_rcu = RCU_GPIOB;
uint32_t i2cx_scl_port = GPIOB;
uint32_t i2cx_scl_pin = GPIO_PIN_6;
uint32_t i2cx_scl_af = GPIO_AF_4;
uint32_t i2cx_sda_port_rcu = RCU_GPIOB;
uint32_t i2cx_sda_port = GPIOB;
uint32_t i2cx_sda_pin = GPIO_PIN_7;
uint32_t i2cx_sda_af = GPIO_AF_4;
uint32_t i2cx = I2C0;
uint32_t i2cx_rcu = RCU_I2C0;
uint32_t i2cx_speed = 400000;
/****************** GPIO config **********************/
// 时钟配置
rcu_periph_clock_enable(i2cx_scl_port_rcu);
// 设置复用功能
gpio_af_set(i2cx_scl_port, i2cx_scl_af, i2cx_scl_pin);
// 设置输出模式
gpio_mode_set(i2cx_scl_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_scl_pin);
gpio_output_options_set(i2cx_scl_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_scl_pin);
// 时钟配置
rcu_periph_clock_enable(i2cx_sda_port_rcu);
// 设置复用功能
gpio_af_set(i2cx_sda_port, i2cx_sda_af, i2cx_sda_pin);
// 设置输出模式
gpio_mode_set(i2cx_sda_port, GPIO_MODE_AF, GPIO_PUPD_NONE, i2cx_sda_pin);
gpio_output_options_set(i2cx_sda_port, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, i2cx_sda_pin);
/****************** I2C config **********************/
i2c_deinit(i2cx);
// 时钟配置
rcu_periph_clock_enable(i2cx_rcu);
// I2C速率配置
i2c_clock_config(i2cx, i2cx_speed, I2C_DTCY_2);
// 使能i2c
i2c_mode_addr_config(i2cx, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, 0x00);
i2c_enable(i2cx);
// i2c ack enable
i2c_ack_config(i2cx, I2C_ACK_ENABLE);
//i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);
}
static uint8_t I2C_wait(uint32_t i2cx, uint32_t flag) {
uint16_t TIMEOUT = 50000;
uint16_t cnt = 0;
while(!i2c_flag_get(i2cx, flag)) {
cnt++;
if(cnt > TIMEOUT) return 1;
}
return 0;
}
static uint8_t I2C_waitn(uint32_t i2cx, uint32_t flag) {
uint16_t TIMEOUT = 50000;
uint16_t cnt = 0;
while(i2c_flag_get(i2cx, flag)) {
cnt++;
if(cnt > TIMEOUT) return 1;
}
return 0;
}
uint8_t I2C0_write(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t data_len) {
uint32_t i2cx = I2C0;
uint8_t address = addr << 1;
/************* start ***********************/
// 等待I2C闲置
if(I2C_waitn(i2cx, I2C_FLAG_I2CBSY)) return 1;
// start
i2c_start_on_bus(i2cx);
// 等待I2C主设备成功发送起始信号
if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 2;
/************* device address **************/
// 发送设备地址
i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);
// 等待地址发送完成
if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 3;
i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);
/************ register address ************/
// 寄存器地址
// 等待发送数据缓冲区为空
if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 4;
// 发送数据
i2c_data_transmit(i2cx, reg);
// 等待数据发送完成
if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 5;
/***************** data ******************/
// 发送数据
uint32_t i;
for(i = 0; i < data_len; i++) {
uint32_t d = data[i];
// 等待发送数据缓冲区为空
if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 6;
// 发送数据
i2c_data_transmit(i2cx, d);
// 等待数据发送完成
if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 7;
}
/***************** stop ********************/
// stop
i2c_stop_on_bus(i2cx);
if(I2C_waitn(i2cx, I2C_CTL0(I2C0)&I2C_CTL0_STOP)) return 8;
return 0;
}
uint8_t I2C0_write2(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t offset, uint32_t len) {
uint32_t i2cx = I2C0;
uint8_t address = addr << 1;
/************* start ***********************/
// 等待I2C闲置
if(I2C_waitn(i2cx, I2C_FLAG_I2CBSY)) return 1;
// start
i2c_start_on_bus(i2cx);
// 等待I2C主设备成功发送起始信号
if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 2;
/************* device address **************/
// 发送设备地址
i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);
// 等待地址发送完成
if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 3;
i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);
/************ register address ************/
// 寄存器地址
// 等待发送数据缓冲区为空
if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 4;
// 发送数据
i2c_data_transmit(i2cx, reg);
// 等待数据发送完成
if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 5;
/***************** data ******************/
// 发送数据
do {
// 等待发送数据缓冲区为空
if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 6;
// 发送数据
i2c_data_transmit(i2cx, *data);
data += offset;
// 等待数据发送完成
if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 7;
} while(--len);
/***************** stop ********************/
// stop
i2c_stop_on_bus(i2cx);
if(I2C_waitn(i2cx, I2C_CTL0(I2C0)&I2C_CTL0_STOP)) return 8;
return 0;
}
void I2C0_deinit() {
}
uint8_t I2C0_read(uint8_t addr, uint8_t reg, uint8_t* data, uint32_t len) {
uint32_t i2cx = I2C0;
uint8_t address = addr << 1;
/************* start ***********************/
// 等待I2C空闲
if(I2C_waitn(i2cx, I2C_FLAG_I2CBSY)) return 1;
// 发送启动信号
i2c_start_on_bus(i2cx);
if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 2;
/************* device address **************/
// 发送从设备地址
i2c_master_addressing(i2cx, address, I2C_TRANSMITTER);
// //ack
// i2c_ack_config(i2cx, I2C_ACK_ENABLE);
// i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);
// if(I2C_wait(i2cx, (I2C_CTL0(i2cx) & I2C_CTL0_ACKEN))) return 11;
// // i2c_ack_config(i2cx, I2C_ACK_DISABLE);
if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 3;
i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);
/********** register address **************/
// 等待发送缓冲区
if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 4;
// 发送寄存器地址
i2c_data_transmit(i2cx, reg);
// 等待发送数据完成
if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 5;
if(I2C_wait(i2cx, I2C_FLAG_TBE)) return 6;
/************* start ***********************/
// 发送再启动信号
i2c_start_on_bus(i2cx);
if(I2C_wait(i2cx, I2C_FLAG_SBSEND)) return 7;
/************* device address **************/
// 发送从设备地址
i2c_master_addressing(i2cx, address, I2C_RECEIVER);
if(I2C_wait(i2cx, I2C_FLAG_ADDSEND)) return 8;
i2c_flag_clear(i2cx, I2C_FLAG_ADDSEND);
/************* data **************/
//ack
i2c_ack_config(i2cx, I2C_ACK_ENABLE);
i2c_ackpos_config(i2cx, I2C_ACKPOS_CURRENT);
if(I2C_wait(i2cx, (I2C_CTL0(i2cx) & I2C_CTL0_ACKEN))) return 23;
// 读取数据
uint8_t i;
for (i = 0; i < len; i++) {
if(i != len - 1) {
// 等待ACK发送完成
if(I2C_wait(i2cx, I2C_FLAG_BTC)) return 9;
}
// 等待ACK数据发送完成
// 等待接收缓冲区
if(I2C_wait(i2cx, I2C_FLAG_RBNE)) return 10;
data[i] = i2c_data_receive(i2cx);
if (i == len - 1) {
// 在读取最后一个字节之前,禁用ACK,并发送停止信号
// 配置自动NACK
//i2c_ackpos_config(i2cx, I2C_ACKPOS_NEXT);
//if(I2C_wait(i2cx, (I2C_CTL0(i2cx) & I2C_CTL0_ACKEN))) return 9;
i2c_ack_config(i2cx, I2C_ACK_DISABLE);
}
}
/***************** stop ********************/
i2c_stop_on_bus(i2cx);
if(I2C_waitn(i2cx, I2C_CTL0(I2C0) & I2C_CTL0_STOP)) return 11;
return 0;
}