I2C 主从模式切换 总结 IPMB

 

项目健康管理模块IPMB,针对协议要求对I2C总结上的节点设备,每一个可以作为主设备去访问从设备的信息。

 

作为发起者,上电启动后主节点为主模式,发起请求消息;从节点在接收到主节点发送的请求消息后,主节点转换为从模式,从节点转换为主模式。从节点发送消息到目的节点,完成通信过程。

 

此协议遵循SMBUS协议。

 

项目基于stm32 设计完成IPMB健康管理,关键点在于主从模式的切换,首先要挂接中断,当为主模式时,关接收中断;当为从模式时打开中断。代码实现如下所示:

I2C配置实现:

void I2C1_Configuration(void)
{
  I2C_InitTypeDef I2C_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    
    I2C_DeInit(I2C1);
    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStructure.I2C_OwnAddress1 = I2C1_Slave_Address;                           //�ӻ���ַ
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStructure.I2C_AcknowledgedAddress= I2C_AcknowledgedAddress_7bit;
    I2C_InitStructure.I2C_ClockSpeed = 100000;
    I2C_Init(I2C1, &I2C_InitStructure);

    
    NVIC_InitStructure.NVIC_IRQChannel                   = I2C1_EV_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    
    NVIC_InitStructure.NVIC_IRQChannel = I2C1_ER_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;                 //�����ȼ�
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
  NVIC_Init(&NVIC_InitStructure);

  I2C_ITConfig(I2C1, I2C_IT_BUF | I2C_IT_EVT |I2C_IT_ERR, ENABLE);   //ʹ���ж�
  I2C_Cmd(I2C1, ENABLE);                                             //ʹ��I2C
}

中断函数实现:

void I2C1_EV_IRQHandler(void)
{

  __IO uint32_t SR1Register =0;
  __IO uint32_t SR2Register =0;

  Recvmark = 1;

  SR1Register = I2C1->SR1;
  SR2Register = I2C1->SR2;
	
  /* I2C1�Ǵӻ�(MSL = 0) */
  if((SR2Register &0x0001) != 0x0001)
  {
    /* �����ѷ�����ַ(ADDR = 1: EV1) */
    if((SR1Register & 0x0002) == 0x0002)
    {
      /* �����־��׼���������� */
      SR1Register = 0;
      SR2Register = 0;
			
	  Rx_Idx_IIC1=0;
	  Tx_Idx_IIC1=0;
    }
		
    /* ��������(RXNE = 1: EV2) */
    if((SR1Register & 0x0040) == 0x0040)
    {
      Buffer_Rx_IIC1[Rx_Idx_IIC1++] = I2C1->DR;
      SR1Register = 0;
      SR2Register = 0;
    }
    /* ��⵽ֹͣ����(STOPF =1: EV4) */
    if(( SR1Register & 0x0010) == 0x0010)
    {
      I2C1->CR1 |= 0x0001;
      SR1Register = 0;
      SR2Register = 0;
      Flag_RcvOK_IIC1 = 1; 			
    }
		
	/* ��������(TxE = 1: EV3) */
    if((SR1Register & 0x0080) == 0x0080)
    {
	  I2C1->DR = Response_Message[Tx_Idx_IIC1++];	
      SR1Register = 0;
      SR2Register = 0;
    }
    /* ��⵽��Ӧ��(AF =1: EV3-2) */
    if(( SR1Register & 0x0400) == 0x0400)
    {
			I2C1->SR1 &= 0xFDFF;
      SR1Register = 0;
      SR2Register = 0;		
    }		
  }
	
}

 

开关中断操作:主发送之前关闭中断,从接收时打开中断。

I2C_ITConfig(I2C1, I2C_IT_BUF | I2C_IT_EVT |I2C_IT_ERR, ENABLE);  //使能中断

I2C_ITConfig(I2C1, I2C_IT_BUF | I2C_IT_EVT |I2C_IT_ERR, DISABLE); //关闭中断

一般设计中,对于总线主模式,数据发送为抢占总线的操作,主模式在执行完总线发送需求后自动切换为从模式。

I2C允许多主站模式,数据发送采用总线竞争发送。

作为一个AI语言模型,我无法提供某个特定开发板的IPMB代码,因为不同的开发板使用的代码也不同。但我可以向您介绍IPMB的一些基本知识和编程要点,以帮助您编写自己的IPMB代码。 IPMB(Intelligent Platform Management Bus)是一种用于管理电子设备的串行总线协议。它用于在计算机系统中连接管理控制器、传感器等设备。IPMB提供了一种基本的通信机制,允许管理系统监测设备并向其发送指令。IPMB协议支持两种消息类型:请求和响应。请求消息是管理员通过IPMB传输到设备的消息,响应消息是设备通过IPMB回复给管理员的消息。 在STM32上编写IPMB代码需要了解以下几个方面: 1. 硬件配置:需要根据具体的开发板配置GPIO口、串口等硬件资源,并实现发送和接收IPMB消息的逻辑。 2. IPMB协议:需要了解IPMB协议的基本结构、消息格式等。 3. 代码实现:需要实现IPMB协议的报文解析、报文发送等功能,并处理IPMB设备的响应消息。 以下是一份基本的IPMB简单代码,供您参考: ```c #include "stm32f10x.h" #define IPMB_ADDR 0x3C void IPMB_Init(void) { //在GPIO中配置IPMB数据线和时钟线 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_SetBits(GPIOB, GPIO_Pin_13); GPIO_SetBits(GPIOB, GPIO_Pin_7); } void IPMB_Send(uint8_t *buf, uint8_t len) { int i; GPIO_ResetBits(GPIOB, GPIO_Pin_7); for(i=0;i<len;i++) { while((USART_GetFlagStatus(USART1, USART_FLAG_TC)) != SET); USART_SendData(USART1, buf[i]); while((USART_GetFlagStatus(USART1, USART_FLAG_RXNE)) == RESET); USART_ReceiveData(USART1); } GPIO_SetBits(GPIOB, GPIO_Pin_7); } void IPMB_Receive(uint8_t *buf, uint8_t len) { uint8_t i; for(i=0;i<len;i++) { while((USART_GetFlagStatus(USART1, USART_FLAG_TC)) != SET); USART_SendData(USART1, 0xFF); while((USART_GetFlagStatus(USART1, USART_FLAG_RXNE)) == RESET); buf[i] = USART_ReceiveData(USART1); } } void IPMB_Message_Send(uint8_t slave, uint8_t *message, uint8_t length) { uint8_t buf[256]; buf[0] = IPMB_ADDR << 1; buf[1] = slave << 1; buf[2] = length+1; memcpy(&buf[3], message, length); IPMB_Send(buf, length+3); } void IPMB_Message_Receive(uint8_t *message) { uint8_t buf[256]; uint8_t length; IPMB_Receive(buf, 3); if((buf[0] >> 1) == IPMB_ADDR) { length = buf[2] -1; IPMB_Receive(&buf[3], length); memcpy(message, &buf[3], length); } } ``` 该代码使用STM32F10x芯片,并通过USART1作为IPMB数据端口与IPMB总线通讯。该代码实现了以下功能: 1. 初始化IPMB硬件配置,包括设置GPIO口等。 2. 实现了IPMB_Send函数和IPMB_Receive函数,分别用于发送和接收数据。 3. 实现了IPMB_Message_Send函数和IPMB_Message_Receive函数,分别用于发送和接收IPMB消息。其中,IPMB_Message_Send函数将指定地址的slave地址、消息长度和消息内容打包成IPMB消息格式,然后通过IPMB_Send函数发送出去。而IPMB_Message_Receive函数则接收IPMB消息,并解析出其中的数据。 当然这只是一个示例代码,如果要编写真正的IPMB代码,还需要根据具体的开发板和应用场景进行具体的代码实现。
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值