1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
|
#define BUFF_SIZE (8U)
#define SLAVE_ADDRESS (0x5C)
#define CLK_DELAY (16U) /* SCL 半周期延时 */
#define ACK_DELAY (6U) /* 采样 ACK 前的建立延时 */
#define USER_DELAY (5U) /* 地址匹配后的额外延时 */
#define REQ_WRITE (0U)
#define REQ_READ (1U)
#define RET_ACK (0U)
#define RET_NACK (1U)
uint8_t g_tx_buffer[BUFF_SIZE] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08};
uint8_t g_rx_buffer[BUFF_SIZE];
/* 起始条件:SCL 高时,SDA 由高变低 */
void bsp_i2c_generate_start(void)
{
std_gpio_set_pin(I2C_PIN_PORT, (SCL_PIN | SDA_PIN)); /* SDA/SCL 先高 */
std_gpio_set_pin_mode(I2C_PIN_PORT, SDA_PIN, GPIO_MODE_OUTPUT);
i2c_delay_time(CLK_DELAY);
std_gpio_reset_pin(I2C_PIN_PORT, SDA_PIN); /* SDA 拉低 = 起始 */
i2c_delay_time(CLK_DELAY);
std_gpio_reset_pin(I2C_PIN_PORT, SCL_PIN); /* 拉低 SCL,准备传数据 */
}
/* 停止条件:SCL 高时,SDA 由低变高 */
void bsp_i2c_generate_stop(void)
{
std_gpio_reset_pin(I2C_PIN_PORT, (SCL_PIN | SDA_PIN)); /* SDA/SCL 先低 */
std_gpio_set_pin_mode(I2C_PIN_PORT, SDA_PIN, GPIO_MODE_OUTPUT);
i2c_delay_time(CLK_DELAY);
std_gpio_set_pin(I2C_PIN_PORT, SCL_PIN); /* SCL 拉高 */
i2c_delay_time(CLK_DELAY);
std_gpio_set_pin(I2C_PIN_PORT, SDA_PIN); /* SDA 拉高 = 停止 */
}
/* 发送 1 字节(高位先),返回从机 ACK 状态 */
uint32_t bsp_i2c_master_send_byte(uint8_t send_data)
{
uint32_t bit_cnt = 0, ack_type = 0;
/* 设置 SDA 初始电平并切输出 */
if (send_data & 0x80) std_gpio_set_pin(I2C_PIN_PORT, SDA_PIN);
else std_gpio_reset_pin(I2C_PIN_PORT, SDA_PIN);
std_gpio_set_pin_mode(I2C_PIN_PORT, SDA_PIN, GPIO_MODE_OUTPUT);
for (bit_cnt = 0; bit_cnt < 8; bit_cnt++) /* 逐位发送 */
{
if ((send_data << bit_cnt) & 0x80) std_gpio_set_pin(I2C_PIN_PORT, SDA_PIN);
else std_gpio_reset_pin(I2C_PIN_PORT, SDA_PIN);
i2c_delay_time(CLK_DELAY);
std_gpio_set_pin(I2C_PIN_PORT, SCL_PIN); /* SCL 高,从机采样 */
i2c_delay_time(CLK_DELAY);
std_gpio_reset_pin(I2C_PIN_PORT, SCL_PIN); /* SCL 低,准备下一位 */
}
/* 第 9 个时钟读 ACK:SDA 设为输入,主机释放 */
std_gpio_set_pin_mode(I2C_PIN_PORT, SDA_PIN, GPIO_MODE_INPUT);
i2c_delay_time(CLK_DELAY);
std_gpio_set_pin(I2C_PIN_PORT, SCL_PIN);
i2c_delay_time(ACK_DELAY);
ack_type = std_gpio_get_input_pin(I2C_PIN_PORT, SDA_PIN) ? RET_NACK : RET_ACK;
std_gpio_reset_pin(I2C_PIN_PORT, SCL_PIN);
i2c_delay_time(CLK_DELAY);
return ack_type;
}
/* 接收 1 字节(高位先) */
uint8_t bsp_i2c_master_receive_byte(void)
{
uint32_t bit_cnt = 0;
uint8_t receive_data = 0;
std_gpio_set_pin_mode(I2C_PIN_PORT, SDA_PIN, GPIO_MODE_INPUT); /* 主机释放 SDA */
for (bit_cnt = 0; bit_cnt < 8; bit_cnt++)
{
std_gpio_reset_pin(I2C_PIN_PORT, SCL_PIN);
i2c_delay_time(CLK_DELAY);
std_gpio_set_pin(I2C_PIN_PORT, SCL_PIN); /* SCL 高,从机驱动 SDA */
i2c_delay_time(CLK_DELAY);
receive_data <<= 1;
if (std_gpio_get_input_pin(I2C_PIN_PORT, SDA_PIN) == true)
receive_data += 1;
}
std_gpio_reset_pin(I2C_PIN_PORT, SCL_PIN);
i2c_delay_time(CLK_DELAY);
return receive_data;
}
/* 主机完整发送流程 */
void bsp_i2c_master_send(void)
{
uint32_t ack_type, index;
bsp_i2c_generate_start();
ack_type = bsp_i2c_master_send_byte(SLAVE_ADDRESS | REQ_WRITE); /* 地址 + 写 */
if (ack_type != RET_ACK) error_process(); /* 无 ACK 则异常处理 */
i2c_delay_time(USER_DELAY);
for (index = 0; index < BUFF_SIZE; index++)
{
ack_type = bsp_i2c_master_send_byte(g_tx_buffer[index]);
if (ack_type != RET_ACK) error_process();
}
bsp_i2c_generate_stop();
}
/* 主机完整接收流程(倒数第 2 字节回 ACK,最后 1 字节回 NACK) */
void bsp_i2c_master_receive(void)
{
uint32_t ack_type, index;
bsp_i2c_generate_start();
ack_type = bsp_i2c_master_send_byte(SLAVE_ADDRESS | REQ_READ); /* 地址 + 读 */
if (ack_type != RET_ACK) error_process();
i2c_delay_time(USER_DELAY);
for (index = 0; index < BUFF_SIZE - 1; index++)
{
g_rx_buffer[index] = bsp_i2c_master_receive_byte();
bsp_i2c_generate_ack(RET_ACK); /* 主机回 ACK,告诉从机继续发 */
}
g_rx_buffer[index] = bsp_i2c_master_receive_byte();
bsp_i2c_generate_ack(RET_NACK); /* 最后一字节回 NACK,结束 */
bsp_i2c_generate_stop();
}
|