stm32主从机硬件IIC实现

前言:

        IIC作为一个基础的通信协议,活跃于各种设备之间。I2C作为两线通信协议,相较于spi来说所需引脚更少,我们可以使用硬件I2C在设备与设备之间通信,但在硬件I2c被其他功能所占据引脚时,也可以使用软件拉高拉低来模拟,32位单片机中我们常用的方式是软件模拟,但实际上软件模拟的I2C速度有时又达不到我们需求,软件的有点在于可以灵活使用各个引脚,硬件的优点在于能够更快的相应。硬件I2C网传存在一些小bug,但作者常常使用硬件I2C也并没有遇到什么bug,只能说具体问题具体看待了,当正遇到了的情况下,再去该软件模拟也可以的。毕竟硬件相对简单,便利。参考文章一般思路先介绍一下IIC后附加代码分析硬件I2C

一、IIC介绍

(一)、简介      
          I2C 是一种短距离总线通信协议,物理实现上,I2C 总线由两根信号线( SDA 与 SCL)和一个地线组成,两根信号线为双向发送的。它可以提供多主模式功能,支持标准(100KHZ)和快速模式(400KHZ),它可以用于多种用途,包括 CRC 生成和验证、SMBus(系统管理总线)以及 PMBus(电源管理总线)。 根据器件的不同,可利用 DMA 功能来减轻 CPU 的工作量。(作者暂时还没有使用过DMA在IIC中,后续有机会会进行补充)。
(二)、IIC特征
        1、支持多设备通信,多主模式功能:同一接口既可用作主模式也可用作从模式。
        2、IIC主模式特征:时钟生成,起始位和停止位生成
        3、IIC从模式特征: 可编程 I 2 C 地址检测,双寻址模式,可对 2 个从地址应答,停止位检测
        4、7 /10 位寻址以及广播呼叫的生成和检测
        5、总线需要接上拉电阻到电源,I2C 总线空闲状态下,输出为高阻态,所有设备空闲时,都输出高阻态,上拉电阻把总线拉成高电平。
(三)、补充关于IIC的上拉电阻
        
          1、  I2C总线采用 开漏输出(Open-Drain) 或 开集电极输出(Open-Collector) 的设计:
  • SDA(数据线)和SCL(时钟线)在空闲时处于高电平状态。

  • 当设备需要发送数据时,会拉低SDA或SCL。

  • 由于开漏输出无法主动拉高信号,因此需要通过外部上拉电阻将总线拉高到逻辑高电平。

如果没有上拉电阻,总线将无法正常工作,因为信号无法回到高电平状态

        2、上拉电阻的选择
  • 总线电容(Bus Capacitance)

    • 总线上的电容包括导线电容、设备引脚电容等。

    • 电容越大,信号的上升时间越长,通信速度越慢。

  • 通信速度(Clock Speed)

    • 标准模式(100 kHz)和快速模式(400 kHz)对上升时间的要求不同。

    • 高速模式(3.4 MHz)需要更小的上拉电阻。

  • 电源电压(VDD)

    • 电源电压越高,上拉电阻可以适当增大。

常用阻值范围:
  • 标准模式(100 kHz):通常使用 4.7 kΩ 到 10 kΩ 的上拉电阻。

  • 快速模式(400 kHz):通常使用 2.2 kΩ 到 4.7 kΩ 的上拉电阻。

  • 高速模式(3.4 MHz):通常使用 1 kΩ 到 2.2 kΩ 的上拉电阻。

计算公式:

上拉电阻的阻值可以通过以下公式估算:

Rmax=trise0.8473×CbusRmax​=0.8473×Cbus​trise​​

其中:

  • trisetrise​ 是信号的上升时间(由I2C规范决定)。

  • CbusCbus​ 是总线的电容值

3、上拉电阻布局
  • 每个总线都需要上拉电阻

    • SDA和SCL线都需要单独的上拉电阻。

  • 避免多个上拉电阻

    • 如果总线上有多个设备,不要为每个设备单独加上拉电阻,否则会导致总阻值过小,影响通信。

  • 靠近主设备放置

    • 上拉电阻应尽量靠近主设备(Master)放置,以减少信号反射和干扰。

4、电源匹配问题
  • 上拉电阻的电源电压(VDD)需要与I2C设备的逻辑电平匹配。

  • 例如,如果I2C设备的工作电压是3.3V,上拉电阻也应连接到3.3V电源。

5、常见问题
问题1:上拉电阻过小
  • 现象:总线电流过大,可能导致设备损坏或电源不稳定。

  • 解决方法:增大上拉电阻。

问题2:上拉电阻过大
  • 现象:信号上升时间过长,导致通信错误或速度下降。

  • 解决方法:减小上拉电阻。

问题3:没有上拉电阻
  • 现象:总线无法拉高,通信完全失败。

  • 解决方法:添加合适的上拉电阻。

注:补充部分来源与deepseek介绍。

二、硬件IIC连接

1、引脚选择

        本次实验所使用的是芯片是stm32f411ceu6的PB9,PB10 I2C2。手册显示

2、原理图

由于板子并未有上拉电阻,所以自己手动焊接了两个2.2K的上拉电阻

三、软件编程

(一)、I 2C 主机:
1、I2C主模式初始化:
I2C_HandleTypeDef gI2c2;//I2C句柄
/*****************************************************************************
 函 数 名  : AudioI2cInit
 功能描述  : IIC初始化,速度400000外部添加2.2K的上拉电阻外部实现上拉
 输入参数  : void
 返 回 值  : void
 作  者    : Bright
 创建日期 : 20240624
*****************************************************************************/
void MasterI2cInit(void)
{
	gI2c2.Instance=I2C2;
	gI2c2.Init.ClockSpeed=400000;						/*快速模式400,标准模式100KHZ*/
	gI2c2.Init.DutyCycle = I2C_DUTYCYCLE_16_9;              /*占空比:1/2 */ 
	gI2c2.Init.OwnAddress1=0;							/*主机不需要配置地址*/
	gI2c2.Init.AddressingMode=I2C_ADDRESSINGMODE_7BIT;	/*7位地址模式*/
	gI2c2.Init.DualAddressMode=I2C_DUALADDRESS_DISABLE;/*禁用双地址模式*/
	gI2c2.Init.OwnAddress2=0;							/*地址2未使用*/
	gI2c2.Init.GeneralCallMode=I2C_GENERALCALL_DISABLE;/*禁用广播呼叫*/
	gI2c2.Init.NoStretchMode=I2C_NOSTRETCH_DISABLE;	   /*始终拉伸*/
	gI2c2.Mode=HAL_I2C_MODE_MASTER;					   /*配置为主模式*/
	if(HAL_I2C_Init(&gI2c2)!=HAL_OK)
	{
		 
	};
}
/*****************************************************************************
 函 数 名  : HAL_I2C_MspInit
 功能描述  : IIC引脚初始胡初始化
 输入参数  : void
 返 回 值  : void
 作  者    : Bright
 创建日期 : 20240624
*****************************************************************************/
void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	if(hi2c->Instance==I2C1)
	{
		
	}
	if(hi2c->Instance==I2C2)
	{
		__HAL_RCC_GPIOB_CLK_ENABLE();
		__HAL_RCC_I2C2_CLK_ENABLE();
		GPIO_InitStruct.Pin = IIC_SCL_GPIO_PIN;
		GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;//GPIO_MODE_AF_OD;
		GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
		GPIO_InitStruct.Alternate = GPIO_AF4_I2C2;
		HAL_GPIO_Init(IIC_SCL_GPIO_PORT,&GPIO_InitStruct);
		
		//I2C_SDA config
		GPIO_InitStruct.Pin = IIC_SDA_GPIO_PIN;
		GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;//GPIO_MODE_AF_OD;
		GPIO_InitStruct.Pull = GPIO_PULLUP;//GPIO_NOPULL;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
		GPIO_InitStruct.Alternate = GPIO_AF9_I2C2;
		HAL_GPIO_Init(IIC_SDA_GPIO_PORT,&GPIO_InitStruct);

	}
}
2、I2C读写数据
/*****************************************************************************
 函 数 名  : I2C_Write
 功能描述  : 向从机写入数据
 输入参数  : void
 返 回 值  : void
 作  者    : Bright
 创建日期 : 20240624
*****************************************************************************/
void I2C_Write(uint8_t reg_address, uint8_t data)
{
    uint8_t buffer[2];
    buffer[0] = reg_address;  // 寄存器地址
    buffer[1] = data;         // 要写入的数据
    // 发送数据到从机
    HAL_I2C_Master_Transmit(&gI2c2, I2C_DEVICE_ADDR << 1, buffer, 2, 1000);
}
/*****************************************************************************
 函 数 名  : I2C_Read
 功能描述  : 从从机读取数据
 输入参数  : void
 返 回 值  : void
 作  者    : Bright
 创建日期 : 20240624
*****************************************************************************/
uint8_t I2C_Read(uint8_t reg_address)
{
    uint8_t data = 0; 
    // 先发送寄存器地址
    HAL_I2C_Master_Transmit(&gI2c2, I2C_DEVICE_ADDR << 1, &reg_address, 1, 1000);
    // 然后读取数据
    HAL_I2C_Master_Receive(&gI2c2,(I2C_DEVICE_ADDR << 1)|0x01, &data, 1, 1000);

    return data;
}
3、I2C.h文件
#ifndef __I2C_H_
#define __I2C_H_
#include "sys/sys.h"


#define I2C_DEVICE_ADDR					0x50					
#define I2C_WRITE_ADDR					(I2C_DEVICE_ADDR<<1)
#define I2C_READ_ADDR					(I2C_WRITE_ADDR|0x01)
#define IIC_SCL_GPIO_PORT               GPIOB
#define IIC_SCL_GPIO_PIN                GPIO_PIN_10
#define IIC_SCL_GPIO_CLK_ENABLE()       do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)   /* PB口时钟使能 */

#define IIC_SDA_GPIO_PORT               GPIOB
#define IIC_SDA_GPIO_PIN                GPIO_PIN_9
#define IIC_SDA_GPIO_CLK_ENABLE()       do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)   /* PB口时钟使能 */







/******************************************************************************************/

/* IO操作 */
#define IIC_SCL(x)        do{ x ? \
                              HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_SET) : \
                              HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_RESET); \
                          }while(0)       /* SCL */

#define IIC_SDA(x)        do{ x ? \
                              HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_SET) : \
                              HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_RESET); \
                          }while(0)       /* SDA */

#define IIC_READ_SDA     HAL_GPIO_ReadPin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN) /* 读取SDA */

extern void MasterI2cInit(void);
extern void I2C_Write(uint8_t reg_address, uint8_t data);
extern uint8_t I2C_Read(uint8_t reg_address);
#endif
(二)、从模式代码
1、从模式初始化
#include "config.h"
I2C_HandleTypeDef gI2c2;//I2C句柄
uint8_t ram[256];             // 模拟I2C从机数据寄存器(主机读写的数据都放在这块内存)
uint8_t offset;                      // 从机寄存器当前偏移地址
static uint8_t first_byte_state = 1; // 是否收到第1个字节,也就是偏移地址(0:已收到,1:没有收到)
/*****************************************************************************
 函 数 名  : I2c2SlaveInit
 功能描述  : IIC初始化,速度400000外部添加2.2K的上拉电阻外部实现上拉
 输入参数  : void
 返 回 值  : void
 作  者    : Bright
 创建日期 : 20240624
*****************************************************************************/
void SlaveI2cInit(void)
{
	gI2c2.Instance=I2C2;
	gI2c2.Init.ClockSpeed=400000;						/*快速模式400,标准模式100KHZ*/
	gI2c2.Init.DutyCycle = I2C_DUTYCYCLE_16_9;          /*占空比:1/2 */ 
	gI2c2.Init.OwnAddress1=I2C_DEVICE_ADDR;				/*主机不需要配置地址*/
	gI2c2.Init.AddressingMode=I2C_ADDRESSINGMODE_7BIT;	/*7位地址模式*/
	gI2c2.Init.DualAddressMode=I2C_DUALADDRESS_DISABLE; /*禁用双地址模式*/
	gI2c2.Init.OwnAddress2=0;							/*从机地址2未使用*/
	gI2c2.Init.GeneralCallMode=I2C_GENERALCALL_DISABLE; /*禁用广播呼叫*/
	gI2c2.Init.NoStretchMode=I2C_NOSTRETCH_DISABLE;	    /*时钟拉伸*/
	gI2c2.Mode=HAL_I2C_MODE_SLAVE;					    /*配置为从模式*/
	HAL_I2C_Init(&gI2c2);
	
	HAL_I2C_EnableListen_IT(&gI2c2);       // 使能I2C1的侦听中断  
}
/*****************************************************************************
 函 数 名  : HAL_I2C_MspInit
 功能描述  : IIC初始化,会自动调用
 输入参数  : void
 返 回 值  : void
 作  者    :  Bright
 创建日期 : 20240624
*****************************************************************************/
void HAL_I2C_MspInit(I2C_HandleTypeDef* hi2c)
{
	GPIO_InitTypeDef GPIO_InitStruct;
	if(hi2c->Instance==I2C1)
	{
		//I2c1
	}else if(hi2c->Instance == I2C2)
	{
		__HAL_RCC_GPIOB_CLK_ENABLE();
		__HAL_RCC_I2C2_CLK_ENABLE();
		GPIO_InitStruct.Pin = IIC_SCL_GPIO_PIN;
		GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;//GPIO_MODE_AF_OD;
		GPIO_InitStruct.Pull = GPIO_NOPULL;//GPIO_NOPULL;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
		GPIO_InitStruct.Alternate = GPIO_AF4_I2C2;
		HAL_GPIO_Init(IIC_SCL_GPIO_PORT,&GPIO_InitStruct);
		
		//I2C_SDA config
		GPIO_InitStruct.Pin = IIC_SDA_GPIO_PIN;
		GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;//GPIO_MODE_AF_OD;
		GPIO_InitStruct.Pull = GPIO_NOPULL;//GPIO_NOPULL;
		GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
		GPIO_InitStruct.Alternate = GPIO_AF9_I2C2;
		HAL_GPIO_Init(IIC_SDA_GPIO_PORT,&GPIO_InitStruct);
		
		HAL_NVIC_SetPriority(I2C2_EV_IRQn,1,1);  // 事件中断(必须有)
		HAL_NVIC_EnableIRQ(I2C2_EV_IRQn);
	}
	
}
/*****************************************************************************
 函 数 名  : I2C2_EV_IRQHandler
 功能描述  :I2C 事件中断服务函数
 输入参数  : void
 返 回 值  : void
 作  者    :  Bright
 创建日期 : 20240624
*****************************************************************************/
void I2C2_EV_IRQHandler(void)
{
	HAL_I2C_EV_IRQHandler(&gI2c2);
}
/*****************************************************************************
 函 数 名  : HAL_I2C_ListenCpltCallback
 功能描述  :从函数回调函数,用于监听主发送的数据
 输入参数  : i2c句柄
 返 回 值  : void
 作  者    :  Bright
 创建日期 : 20240624
*****************************************************************************/
void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c)
{
	if(hi2c->Instance == I2C2)
	{
		first_byte_state = 1;
		offset = 0;	//偏移位
		HAL_I2C_EnableListen_IT(hi2c); // slave is ready again
		// 完成一次通信,清除状态
	}
}
/*****************************************************************************
 函 数 名  : HAL_I2C_AddrCallback
 功能描述  :从设备地址回调函数,地址匹配上以后会进入该函数
 输入参数  : void
 返 回 值  : void
 作  者    :  Bright
 创建日期 : 20240624
*****************************************************************************/
void HAL_I2C_AddrCallback(I2C_HandleTypeDef *hi2c, uint8_t TransferDirection, uint16_t AddrMatchCode)
{
	if(hi2c->Instance == I2C2)
	{
		if(TransferDirection == I2C_DIRECTION_TRANSMIT) 
		{	// 主机发送,从机接收
			if(first_byte_state) 
			{// 准备接收第1个字节数据
				HAL_I2C_Slave_Seq_Receive_IT(hi2c, &offset, 1, I2C_NEXT_FRAME);  // 每次第1个数据均为偏移地址
			} 
		} 
		else 
		{	// 主机接收,从机发送
			HAL_I2C_Slave_Seq_Transmit_IT(hi2c, &ram[offset], 1, I2C_NEXT_FRAME);  // 打开中断并把ram[]里面对应的数据发送给主机
		}
	}
}
/*****************************************************************************
 函 数 名  : HAL_I2C_AddrCallback
 功能描述  :I2C数据接收回调函数(在I2C完成一次接收时会关闭中断并调用该函数,因此在处理完成后需要手动重新打开中断)
 输入参数  : hi2c 句柄
 返 回 值  : void
 作  者    :  Bright
 创建日期 : 20240624
*****************************************************************************/
void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
	if(hi2c->Instance == I2C2)
	{
		if(first_byte_state) 
		{
			first_byte_state = 0;// 收到的第1个字节数据(偏移地址)
		} 
		else 
		{	
			// 收到的第N个字节数据
			offset++;  // 每收到一个数据,偏移+1
		}
		// 打开I2C中断接收,下一个收到的数据将存放到ram[offset]
		HAL_I2C_Slave_Seq_Receive_IT(hi2c, &ram[offset], sizeof(ram), I2C_NEXT_FRAME);  // 接收数据存到ram[]里面对应的位置
	}
	
}
/*****************************************************************************
 函 数 名  : HAL_I2C_AddrCallback
 功能描述  :I2C数据发送回调函数(在I2C完成一次发送后会关闭中断并调用该函数,因此在处理完成后需要手动重新打开中断)
 输入参数  : hi2c 句柄
 返 回 值  : void
 作  者    :  Bright
 创建日期 : 20240624
*****************************************************************************/
void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
	if(hi2c->Instance == I2C2)
	{
		offset++;  // 每发送一个数据,偏移+1
		HAL_I2C_Slave_Seq_Transmit_IT(hi2c, &ram[offset], sizeof(ram), I2C_NEXT_FRAME);  // 打开中断并把ram[]里面对应的数据发送给主机
	}
}

2、I2c.h文件
#ifndef __I2C_H_
#define __I2C_H_
#include "sys/sys.h"
extern uint8_t ram[256]; 

#define I2C_DEVICE_ADDR						0xA0

#define IIC_SCL_GPIO_PORT               GPIOB
#define IIC_SCL_GPIO_PIN                GPIO_PIN_10
#define IIC_SCL_GPIO_CLK_ENABLE()       do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)   /* PB口时钟使能 */

#define IIC_SDA_GPIO_PORT               GPIOB
#define IIC_SDA_GPIO_PIN                GPIO_PIN_9
#define IIC_SDA_GPIO_CLK_ENABLE()       do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0)   /* PB口时钟使能 */

/******************************************************************************************/

/* IO操作 */
#define IIC_SCL(x)        do{ x ? \
                              HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_SET) : \
                              HAL_GPIO_WritePin(IIC_SCL_GPIO_PORT, IIC_SCL_GPIO_PIN, GPIO_PIN_RESET); \
                          }while(0)       /* SCL */

#define IIC_SDA(x)        do{ x ? \
                              HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_SET) : \
                              HAL_GPIO_WritePin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN, GPIO_PIN_RESET); \
                          }while(0)       /* SDA */

#define IIC_READ_SDA     HAL_GPIO_ReadPin(IIC_SDA_GPIO_PORT, IIC_SDA_GPIO_PIN) /* 读取SDA */

extern void SlaveI2cInit(void);
/*************************************IIC RAM[256]内存说明*****************************************************/

					  

/******************************************************************************************/
#endif



						  

四、主从模式测试

1、主测试代码:
#include "config.h"
u8 readData=0;
int main(void)
{
	DemoSystemInit();
	printf("%d\r\n",HAL_RCC_GetSysClockFreq());
	printf("Mcu pow On \r\n");
	uint8_t writeData=0XAA;
	uint8_t writeData2=0XBB;
	
	I2C_Write(0X00,writeData);
	readData=I2C_Read(0X02);//电池温度ram[2]

	while(1)
	{
		if(readData == 0XAA)
		{
			LED_ON();
			
		}else if(readData == 0XBB)
		{
			 LED_ON();
			DelayMs(1000);
			 LED_OFF();
			DelayMs(1000);
		}
		else
		{
			LED_OFF(); 
		}
	}
}




2、从测试代码
#include "config.h"
extern uint8_t ram[256]; 

int main(void)
{
	DemoSystemInit();
	while(1)
	{
		if(ram[0] == 0xAA)
		{
			LED_ON();
		}else if(ram[0] == 0xBB)
		{
			LED_ON();
			DelayMs(500);
			 LED_OFF();
			DelayMs(500);
		}else
		{
			LED_OFF(); 
		}
	}
	
}




3、实际效果

五、结尾

        总体上硬件i2c操作便是如此,可以作为少量快速相应的通信方式, 之前是想将其与I2S一起实现,但I2S的数据量需要的相应数据过快,I2C不适合。后续还会更新一下软件i2c实现主从机模式,作为学习I2c的对比总结。

补充一下M0芯片的使用,其实大同小异,都是在中断函数中去修改的。

#include "config.h"
void DataBufInit(void);
uint8_t dataBuf[DATA_BUF_SIZE] = {0};
uint8_t offset = 0;                 // 从机寄存器当前偏移地址
static uint8_t first_byte_state = 1; // 是否收到第1个字节,也就是偏移地址(0:已收到,1:没有收到)
BOOL first_byte_flag=FALSE;

/*****************************************************************************
 函 数 名  : I2C_Init
 功能描述  : I2C初始化函数400KHZ,2.2K上拉电阻,实际传输速度
 输入参数  : void
 返 回 值  : void
 作  者    : Bright
 创建日期 : 20241108
*****************************************************************************/
void I2C_Init(void)
{
    I2C_Config_T i2cConfig;

    /* ACK when current byte being received  */
    i2cConfig.ack = I2C_ACK_CURRENT;
    /* Set Address  */
    i2cConfig.addr = SLAVE_ADDR;
    /* 7-bit address */
    i2cConfig.addrMode = I2C_ADDR_7_BIT;
    /* duty cycle = 2 */
    i2cConfig.dutyCycle = I2C_DUTYCYCLE_2;
    /* Input clock frequency is 48MHZ */
    i2cConfig.inputClkFreqMhz = 48;
    /* Enable buffer and event interrupt */
    i2cConfig.interrupt = I2C_INT_BUFFER | I2C_INT_EVENT |I2C_INT_ERROR;
    /* Output clock frequency is 100KHZ */
    i2cConfig.outputClkFreqHz = 100000;
    I2C_Config(&i2cConfig);

    NVIC_EnableIRQRequest(IIC_IRQn, PRIORITY_I2C);

    /* Enable I2C */
    I2C_Enable();
}
/*****************************************************************************
 函 数 名  : I2C_Isr
 功能描述  : I2C中断处理函数
 输入参数  : void
 返 回 值  : void
 作  者    : Bright
 创建日期 : 20241108
*****************************************************************************/
void I2C_Isr(void)
{
     if(I2C_ReadStatusFlag(I2C_FLAG_ADDR) == SET)   //判断地址是否正确
    {
        /* Clear ADDR flag by reading STS3 register */  
        (void)I2C->STS3;
        first_byte_state=0;    //第一位清0
    }
     if(((I2C_ReadStatusFlag(I2C_FLAG_RXBNE)) == SET)&&(I2C_ReadStatusFlag(I2C_FLAG_RWMF) == RESET))//接收模式
     {
        if(!first_byte_state)//第一次接收,寄存器地址
        {
            offset=(uint8_t)I2C->DATA;//
            first_byte_state++;
        }else
        {
            if(offset < DATA_BUF_SIZE)
            {
                dataBuf[offset] = (uint8_t)I2C->DATA;
            }
        }
     }
    if(I2C_ReadStatusFlag(I2C_FLAG_ACKERR) == SET)//错误应答标志位
    {
        I2C_ClearStatusFlag(I2C_FLAG_ACKERR);
    }
    /* STS1_TXBEF = 1 and STS3_RWMF = 1 */
    if((I2C_ReadStatusFlag(I2C_FLAG_TXBE) == SET) && (I2C_ReadStatusFlag(I2C_FLAG_RWMF) == SET))//发送缓冲器为空标志,发送模式
    {
        I2C_TxData(dataBuf[offset]);    //读取写入的数据
//      I2C_TxData(0x98);    //固定放回0x98
    }
    /* Stop condition is detected */
    if(I2C_ReadStatusFlag(I2C_FLAG_STOP) == SET)
    {
        I2C->CTRL2 = I2C->CTRL2;
    }
}
/*****************************************************************************
 函 数 名  : DataBufInit
 功能描述  : 接收数据初始化,全部清零
 输入参数  : void
 返 回 值  : void
 作  者    : Bright
 创建日期 : 20241108
*****************************************************************************/
void DataBufInit(void)
{
    uint8_t i;
    
    for(i = 0; i < DATA_BUF_SIZE; i++)
    {
        dataBuf[i] = 0;
    }
}

后续添加的是AMP32F003CU6使用i2c做从机读写返回数据

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值