GD32 I2C主机发送和从机中断接收
layout: post
title: GD32 I2C主机发送和从机中断接收
description: GD32 I2C主机发送和从机中断接收
categories:
- GD32
tags: - GD32
I2C
GD32 I2C主机发送和从机中断接收
一、I2C初始化
此程序采用I2C0作为主机,I2C1作为从机,因此需要初始化I2C0和I2C1
/***************************************************
* 名称: i2c_init
* 描述: i2c初始化函数
* 参数: void
* 返回: void
***************************************************/
void i2c_init(void)
{
i2c_master_init(); // 主机初始化
i2c_slave_init(); // 从机初始化
i2c_nvic_init(); // i2c中断初始化
}
1.主机初始化
/***************************************************
* 名称: i2c_master_init
* 描述: 主机初始化
* 参数: void
* 返回: void
***************************************************/
void i2c_master_init(void)
{
// 主机初始化
rcu_periph_clock_enable(RCU_GPIOB); // 使能GPIOB时钟
rcu_periph_clock_enable(RCU_I2C0); // 使能I2C0时钟
gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_6); // 配置I2C0_SCL到PB6
gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_7); // 配置I2C0_SDA到PB7
// 配置I2C所用的IO口
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_6);
gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_6);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_7);
gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_7);
i2c_clock_config(I2C0, 100000, I2C_DTCY_2); // 配置I2C时钟
i2c_mode_addr_config(I2C0, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, I2C0_OWN_ADDRESS); // 配置I2C地址
i2c_enable(I2C0); // 使能I2C0
i2c_ack_config(I2C0, I2C_ACK_ENABLE);
}
2.从机初始化
/***************************************************
* 名称: i2c_slave_init
* 描述: 从机初始化
* 参数: void
* 返回: void
***************************************************/
void i2c_slave_init(void)
{
rcu_periph_clock_enable(RCU_GPIOB); // 使能GPIOB时钟
rcu_periph_clock_enable(RCU_I2C1); // 使能I2C0时钟
gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_10); // 配置I2C1_SCL到PB10
gpio_af_set(GPIOB, GPIO_AF_4, GPIO_PIN_11); // 配置I2C1_SDA到PB11
// 配置I2C所用的IO口
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_10);
gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_10);
gpio_mode_set(GPIOB, GPIO_MODE_AF, GPIO_PUPD_PULLUP, GPIO_PIN_11);
gpio_output_options_set(GPIOB, GPIO_OTYPE_OD, GPIO_OSPEED_50MHZ, GPIO_PIN_11);
i2c_clock_config(I2C1, 100000, I2C_DTCY_2); // 配置I2C时钟
i2c_mode_addr_config(I2C1, I2C_I2CMODE_ENABLE, I2C_ADDFORMAT_7BITS, I2C0_OWN_ADDRESS); // 配置I2C地址
i2c_enable(I2C1); // 使能I2C1
i2c_ack_config(I2C1, I2C_ACK_ENABLE);
}
3.中断配置
/***************************************************
* 名称: i2c_nvic_init
* 描述: i2c中断初始化
* 参数: void
* 返回: void
***************************************************/
void i2c_nvic_init(void)
{
// 中断优先级分组
nvic_priority_group_set(NVIC_PRIGROUP_PRE1_SUB3);
// 配置中断优先级
nvic_irq_enable(I2C0_EV_IRQn, 0, 3);
nvic_irq_enable(I2C1_EV_IRQn, 0, 4);
nvic_irq_enable(I2C0_ER_IRQn, 0, 2);
nvic_irq_enable(I2C1_ER_IRQn, 0, 1);
// 使能I2C0中断
i2c_interrupt_enable(I2C0, I2C_INT_ERR);
i2c_interrupt_enable(I2C0, I2C_INT_EV);
i2c_interrupt_enable(I2C0, I2C_INT_BUF);
// 使能I2C1中断
i2c_interrupt_enable(I2C1, I2C_INT_ERR);
i2c_interrupt_enable(I2C1, I2C_INT_EV);
i2c_interrupt_enable(I2C1, I2C_INT_BUF);
}
二、中断服务函数
1.I2C0事件中断
由于I2C0作为主机的发送端,因此需要
- 在检测到起始位中断后发送从地址
- 检测到从机回复了地址检测后清除相关标志位
- 检测到发送数据寄存器为空后发送数据
/***************************************************
* 名称: I2C0_EV_IRQHandler
* 描述: I2C0 事件中断
* 参数: void
* 返回: void
***************************************************/
void I2C0_EV_IRQHandler(void)
{
if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_SBSEND)) {
i2c_master_addressing(I2C0, I2C1_SLAVE_ADDRESS, I2C_TRANSMITTER); // 发送从机地址
}
else if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_ADDSEND)) {
i2c_interrupt_flag_clear(I2C0, I2C_INT_FLAG_ADDSEND); // 清ADDSEND标志位
}
else if (i2c_interrupt_flag_get(I2C0, I2C_INT_FLAG_TBE)) {
if (I2C_nBytes > 0) {
i2c_data_transmit(I2C0, *i2c_txbuffer++); // 发送数据
I2C_nBytes--;
}
else {
i2c_stop_on_bus(I2C0); // 发送停止位
i2c_interrupt_disable(I2C0, I2C_INT_ERR);
i2c_interrupt_disable(I2C0, I2C_INT_BUF);
i2c_interrupt_disable(I2C0, I2C_INT_EV);
}
}
}
2.I2C1事件中断
I2C1作为从机,负责接收主机I2C0发送的数据,因此需要
- 检测到主机发送了地址后进行回复
- 检测到数据寄存器为非空时记录数据
- 检测到主机STOP信号后给出接收完毕的信号
/***************************************************
* 名称: I2C1_EV_IRQHandler
* 描述: I2C1 事件中断
* 参数: void
* 返回: void
***************************************************/
void I2C1_EV_IRQHandler(void)
{
if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_ADDSEND)) {
i2c_interrupt_flag_clear(I2C1, I2C_INT_FLAG_ADDSEND); // 清除ADDSEND位
}
else if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_RBNE)) {
*i2c_rxbuffer++ = i2c_data_receive(I2C1);
// recv_buf[recv_buf_len++] = *(i2c_rxbuffer - 1); // 记录接收数据
}
else if (i2c_interrupt_flag_get(I2C1, I2C_INT_FLAG_STPDET)) {
i2c_recv_finish_flag = true;
i2c_enable(I2C1);
i2c_interrupt_disable(I2C1, I2C_INT_ERR);
i2c_interrupt_disable(I2C1, I2C_INT_BUF);
i2c_interrupt_disable(I2C1, I2C_INT_EV);
}
}
三、测试函数
/***************************************************
* 名称: i2c_test
* 描述: i2c接收测试
* 参数: void
* 返回: void
***************************************************/
void i2c_test(void)
{
uint8_t i = 0;
for (i = 0; i < 16; i++) {
i2c_transmitter[i] = test_num++; // 测试数据赋值
}
// 由于i2c_txbuffer和i2c_rxbuffer申请时为空指针,因此需要在这里指向地址
i2c_txbuffer = i2c_transmitter;
i2c_rxbuffer = i2c_buffer_receiver;
I2C_nBytes = 16;
// 中断使能
i2c_interrupt_enable(I2C0, I2C_INT_ERR);
i2c_interrupt_enable(I2C0, I2C_INT_EV);
i2c_interrupt_enable(I2C0, I2C_INT_BUF);
i2c_interrupt_enable(I2C1, I2C_INT_ERR);
i2c_interrupt_enable(I2C1, I2C_INT_EV);
i2c_interrupt_enable(I2C1, I2C_INT_BUF);
// 主机等待空闲
while (i2c_flag_get(I2C0, I2C_FLAG_I2CBSY)) {};
// 主机发送起始位
i2c_start_on_bus(I2C0);
while (I2C_nBytes > 0) {};
}
四、测试结果
1.连线
2.数据变化
本文是原创文章,采用 CC BY-NC-ND 4.0 协议,完整转载请注明来自 开心大佬
评论
匿名评论
隐私政策
你无需删除空行,直接评论以获取最佳展示效果