基于STM32CubeMx 实现STM32 IIC Slave功能

懒,直接上代码

暂时只实现slave功能,后续有时间再增加master

H文件

typedef enum
{
	eMaster,
	eSlave,
}eIICMode;

typedef enum
{
	eCmd0,
	eCmd1,
	eCmd2,
	eCmd3,
	eCmd4,
	eCmd5,
	//...
}IIC_CMD;

typedef uint8_t (*I2C_Read)(void);
typedef uint8_t (*I2C_Write)(uint8_t data);

C文件


/*
本实验是基于stm32cubemx生成的HAL IIC库文件,
通过IIC中断和库文件实现IIC master和slave(重点)功能
*/

#include "stm32iic.h"

HAL_StatusTypeDef HAL_I2C_Slave_Start(I2C_HandleTypeDef *hi2c);
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/

/** @defgroup I2C_Private_Define I2C Private Define
  * @{
  */
#define TIMING_CLEAR_MASK   (0xF0FFFFFFU)  /*!< I2C TIMING clear register Mask */
#define I2C_TIMEOUT_ADDR    (10000U)       /*!< 10 s  */
#define I2C_TIMEOUT_BUSY    (25U)          /*!< 25 ms */
#define I2C_TIMEOUT_DIR     (25U)          /*!< 25 ms */
#define I2C_TIMEOUT_RXNE    (25U)          /*!< 25 ms */
#define I2C_TIMEOUT_STOPF   (25U)          /*!< 25 ms */
#define I2C_TIMEOUT_TC      (25U)          /*!< 25 ms */
#define I2C_TIMEOUT_TCR     (25U)          /*!< 25 ms */
#define I2C_TIMEOUT_TXIS    (25U)          /*!< 25 ms */
#define I2C_TIMEOUT_FLAG    (25U)          /*!< 25 ms */

#define MAX_NBYTE_SIZE      255U
#define SlaveAddr_SHIFT     7U
#define SlaveAddr_MSK       0x06U

/* Private define for @ref PreviousState usage */
#define I2C_STATE_MSK             ((uint32_t)((uint32_t)((uint32_t)HAL_I2C_STATE_BUSY_TX | (uint32_t)HAL_I2C_STATE_BUSY_RX) & (uint32_t)(~((uint32_t)HAL_I2C_STATE_READY)))) /*!< Mask State define, keep only RX and TX bits            */
#define I2C_STATE_NONE            ((uint32_t)(HAL_I2C_MODE_NONE))                                                        /*!< Default Value                                          */
#define I2C_STATE_MASTER_BUSY_TX  ((uint32_t)(((uint32_t)HAL_I2C_STATE_BUSY_TX & I2C_STATE_MSK) | (uint32_t)HAL_I2C_MODE_MASTER))            /*!< Master Busy TX, combinaison of State LSB and Mode enum */
#define I2C_STATE_MASTER_BUSY_RX  ((uint32_t)(((uint32_t)HAL_I2C_STATE_BUSY_RX & I2C_STATE_MSK) | (uint32_t)HAL_I2C_MODE_MASTER))            /*!< Master Busy RX, combinaison of State LSB and Mode enum */
#define I2C_STATE_SLAVE_BUSY_TX   ((uint32_t)(((uint32_t)HAL_I2C_STATE_BUSY_TX & I2C_STATE_MSK) | (uint32_t)HAL_I2C_MODE_SLAVE))             /*!< Slave Busy TX, combinaison of State LSB and Mode enum  */
#define I2C_STATE_SLAVE_BUSY_RX   ((uint32_t)(((uint32_t)HAL_I2C_STATE_BUSY_RX & I2C_STATE_MSK) | (uint32_t)HAL_I2C_MODE_SLAVE))             /*!< Slave Busy RX, combinaison of State LSB and Mode enum  */
#define I2C_STATE_MEM_BUSY_TX     ((uint32_t)(((uint32_t)HAL_I2C_STATE_BUSY_TX & I2C_STATE_MSK) | (uint32_t)HAL_I2C_MODE_MEM))               /*!< Memory Busy TX, combinaison of State LSB and Mode enum */
#define I2C_STATE_MEM_BUSY_RX     ((uint32_t)(((uint32_t)HAL_I2C_STATE_BUSY_RX & I2C_STATE_MSK) | (uint32_t)HAL_I2C_MODE_MEM))               /*!< Memory Busy RX, combinaison of State LSB and Mode enum */


/* Private define to centralize the enable/disable of Interrupts */
#define I2C_XFER_TX_IT          (uint16_t)(0x0001U)   /* Bit field can be combinated with @ref I2C_XFER_LISTEN_IT */
#define I2C_XFER_RX_IT          (uint16_t)(0x0002U)   /* Bit field can be combinated with @ref I2C_XFER_LISTEN_IT */
#define I2C_XFER_LISTEN_IT      (uint16_t)(0x8000U)   /* Bit field can be combinated with @ref I2C_XFER_TX_IT and @ref I2C_XFER_RX_IT */

#define I2C_XFER_ERROR_IT       (uint16_t)(0x0010U)   /* Bit definition to manage addition of global Error and NACK treatment */
#define I2C_XFER_CPLT_IT        (uint16_t)(0x0020U)   /* Bit definition to manage only STOP evenement */
#define I2C_XFER_RELOAD_IT      (uint16_t)(0x0040U)   /* Bit definition to manage only Reload of NBYTE */

/* Private define Sequential Transfer Options default/reset value */
#define I2C_NO_OPTION_FRAME     (0xFFFF0000U)

typedef struct _iic
{
	uint16_t RW;
	uint8_t Cmd;
	uint8_t isTrigCmd;
	uint8_t *ptr;
	uint8_t size;
	eIICMode mode;
	
}iic_struct_t;

iic_struct_t iictype = 
{
	.RW = 0,
	.Cmd = 0,
	.isTrigCmd = 0,
	.ptr = 0,
	.size = 0,
	.mode = eSlave,
};

uint8_t I2C_Slave_Read_Cmd0(void)
{
	return 0x11;
}

uint8_t I2C_Slave_Read_Cmd1(void)
{
	return 0xF2;
}

I2C_Read pI2CSlaveReadFunctionbuf[]=
{
	I2C_Slave_Read_Cmd0,
	I2C_Slave_Read_Cmd1,
};

uint8_t I2C_Slave_Write_Cmd0(uint8_t data)
{
	(void)data;
	return 0;
}

uint8_t I2C_Slave_Write_Cmd1(uint8_t data)
{
	(void)data;
	return 0;
}

I2C_Write pI2CSlaveWriteFunctionbuf[]=
{
	I2C_Slave_Write_Cmd0,
	I2C_Slave_Write_Cmd1,
};
/*
重写IIC从机中断,系统启动时,需设置从机Enable ERR, TC, STOP, NACK, TXI interrupt
*/
HAL_StatusTypeDef HAL_I2C_SlaveIT(struct __I2C_HandleTypeDef *hi2c)
{
  /* Process locked */
  __HAL_LOCK(hi2c);
	if (hi2c->Instance->ISR & I2C_FLAG_ADDR)
	{
		//trig slave address
		__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ADDR);
		iictype.RW = I2C_GET_DIR(hi2c);
		if ((iictype.RW == 1) && (iictype.isTrigCmd == 0))
		{
			while(1);
		}
	}
	else if (hi2c->Instance->ISR & I2C_FLAG_RXNE)
	{
		//rx is not empty
		if (iictype.RW == 0)//write
		{
		  if (iictype.isTrigCmd == 0)//cmd
		  {
			  iictype.Cmd = (uint8_t)hi2c->Instance->RXDR;
			  iictype.isTrigCmd = 1;
		  }
		  else
		  {
			  pI2CSlaveWriteFunctionbuf[iictype.Cmd]((uint8_t)hi2c->Instance->RXDR);
		  }
		}
		else
		{
		  //error
			while(1);
		}
	}
	else if (hi2c->Instance->ISR & I2C_FLAG_TXIS)
	{
		//set tx data
		if (iictype.isTrigCmd == 0)
		{
		  //error
			while(1);
		}
		else
		{
		  if (iictype.RW == 0)
		  {
			  //error
				while(1);
		  }
		  else
		  {
			  //tx
			  do
			  {
				hi2c->Instance->TXDR = pI2CSlaveReadFunctionbuf[iictype.Cmd]();
			  }while(hi2c->Instance->ISR & I2C_FLAG_TXIS);
		  }
		}
	}
	else if ((hi2c->Instance->ISR & I2C_FLAG_ARLO) || (hi2c->Instance->ISR & I2C_FLAG_STOPF)
			|| (hi2c->Instance->ISR & I2C_FLAG_BERR) || (hi2c->Instance->ISR & I2C_ISR_NACKF))
	{
		
		__HAL_I2C_CLEAR_FLAG(hi2c, I2C_ISR_NACKF);
		__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_BERR);
		__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ARLO);
		__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF);

		/* If a pending TXIS flag is set */
		/* Write a dummy data in TXDR to clear it */
		if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXIS) != RESET)
		{
			hi2c->Instance->TXDR = 0x00U;
		}

		/* Flush TX register if not empty */
		if (__HAL_I2C_GET_FLAG(hi2c, I2C_FLAG_TXE) == RESET)
		{
			__HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_TXE);
		}
		if (hi2c->Instance->ISR & 0xFFFE)
		{
			//has any error
			
			hi2c->Instance->CR1 &= 0xFFFFFFFE;//clear PE
			hi2c->Instance->CR1 |= 0x01;//set PE
		}
		//restart
		HAL_I2C_Slave_Start(hi2c);
		iictype.isTrigCmd = 0;
		iictype.Cmd = 0;
		iictype.RW = 0;
	}

  /* Process Unlocked */
  __HAL_UNLOCK(hi2c);

  return HAL_OK;
}

void HAL_I2C_MasterTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
}

void HAL_I2C_MasterRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
}

void HAL_I2C_SlaveTxCpltCallback(I2C_HandleTypeDef *hi2c)
{
}

void HAL_I2C_SlaveRxCpltCallback(I2C_HandleTypeDef *hi2c)
{
}


void HAL_I2C_ListenCpltCallback(I2C_HandleTypeDef *hi2c)
{
}

static void I2C_Enable_IRQ1(I2C_HandleTypeDef *hi2c, uint16_t InterruptRequest)
{
  uint32_t tmpisr = 0U;

  {
    if ((InterruptRequest & I2C_XFER_LISTEN_IT) == I2C_XFER_LISTEN_IT)
    {
      /* Enable ERR, STOP, NACK, and ADDR interrupts */
      tmpisr |= I2C_IT_ADDRI | I2C_IT_STOPI | I2C_IT_NACKI | I2C_IT_ERRI;
    }

    if ((InterruptRequest & I2C_XFER_TX_IT) == I2C_XFER_TX_IT)
    {
      /* Enable ERR, TC, STOP, NACK and RXI interrupts */
      tmpisr |= I2C_IT_ERRI | I2C_IT_TCI | I2C_IT_STOPI | I2C_IT_NACKI | I2C_IT_TXI;
    }

    if ((InterruptRequest & I2C_XFER_RX_IT) == I2C_XFER_RX_IT)
    {
      /* Enable ERR, TC, STOP, NACK and TXI interrupts */
      tmpisr |= I2C_IT_ERRI | I2C_IT_TCI | I2C_IT_STOPI | I2C_IT_NACKI | I2C_IT_RXI;
    }

    if (InterruptRequest == I2C_XFER_CPLT_IT)
    {
      /* Enable STOP interrupts */
      tmpisr |= I2C_IT_STOPI;
    }
  }

  /* Enable interrupts only at the end */
  /* to avoid the risk of I2C interrupt handle execution before */
  /* all interrupts requested done */
  __HAL_I2C_ENABLE_IT(hi2c, tmpisr);
}

HAL_StatusTypeDef HAL_I2C_Slave_Start(I2C_HandleTypeDef *hi2c)
{
  if (hi2c->State == HAL_I2C_STATE_READY)
  {
    /* Process Locked */
    __HAL_LOCK(hi2c);

    /* Enable Address Acknowledge */
    hi2c->Instance->CR2 &= ~I2C_CR2_NACK;

    /* Process Unlocked */
    __HAL_UNLOCK(hi2c);

    /* Note : The I2C interrupts must be enabled after unlocking current process
              to avoid the risk of I2C interrupt handle execution before current
              process unlock */

    /* Enable ERR, TC, STOP, NACK, RXI interrupt */
    /* possible to enable all of these */
    /* I2C_IT_ERRI | I2C_IT_TCI| I2C_IT_STOPI| I2C_IT_NACKI | I2C_IT_ADDRI | I2C_IT_RXI | I2C_IT_TXI */
    I2C_Enable_IRQ1(hi2c, I2C_XFER_TX_IT | I2C_XFER_RX_IT | I2C_XFER_LISTEN_IT | I2C_XFER_CPLT_IT);

    return HAL_OK;
  }
  else
  {
    return HAL_BUSY;
  }
}


使用方法

通过STM32CubeMx生成IIC,并将IIC中断打开,然后在main里面调用一次HAL_I2C_Slave_Start(hi2c);即可使能iic slave read/write功能

如何修改自己的read/write功能

read/write功能请查看pI2CSlaveReadFunctionbuf和pI2CSlaveWriteFunctionbuf这2个函数指针数组。每个数组对应一个cmd,cmd从0开始的。分别修改这2个函数指针数组里面的函数即可。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当然可以帮你配置STM32CubeMX的I2C,并提供相应的代码。以下是一步步的说明: 1. 打开STM32CubeMX并创建一个新的工程。 2. 选择你的目标STM32微控制器型号,并点击"Start Project"按钮。 3. 在"Pinout & Configuration"选项卡中,找到I2C外设,并将其使能。 4. 选择合适的引脚作为I2C的SDA和SCL,可以直接在图形界面上拖拽连接引脚。 5. 在"Configuration"选项卡中,配置I2C的工作模式、时钟速率等参数。根据你的需求进行配置。 6. 点击"Project"菜单,选择"Generate Code"生成代码。 生成的代码将会包含初始化I2C外设的函数。你可以在主程序中调用这些函数来使用I2C进行通信。以下是一个简单的I2C初始化和发送数据的示例代码: ```c #include "stm32f4xx_hal.h" I2C_HandleTypeDef hi2c1; void MX_I2C1_Init(void) { hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 400000; hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) { Error_Handler(); } } void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(i2cHandle->Instance==I2C1) { __HAL_RCC_GPIOB_CLK_ENABLE(); /**I2C1 GPIO Configuration PB8 ------> I2C1_SCL PB9 ------> I2C1_SDA */ GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; GPIO_InitStruct.Pull = GPIO_PULLUP; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; GPIO_InitStruct.Alternate = GPIO_AF4_I2C1; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); } } void I2C_WriteData(uint8_t slaveAddress, uint8_t regAddress, uint8_t* data, uint16_t size) { HAL_I2C_Master_Transmit(&hi2c1, slaveAddress, &regAddress, 1, HAL_MAX_DELAY); HAL_I2C_Master_Transmit(&hi2c1, slaveAddress, data, size, HAL_MAX_DELAY); } int main(void) { HAL_Init(); MX_I2C1_Init(); // 调用I2C_WriteData函数向从设备写入数据 uint8_t slaveAddress = 0x50; // 从设备地址 uint8_t regAddress = 0x00; // 寄存器地址 uint8_t data[4] = {0x01, 0x02, 0x03, 0x04}; // 待发送的数据 uint16_t dataSize = sizeof(data); I2C_WriteData(slaveAddress, regAddress, data, dataSize); while (1) { } } ``` 以上代码中,`MX_I2C1_Init()`函数用于初始化I2C1外设,`HAL_I2C_MspInit()`函数用于配置相关引脚的GPIO模式和复用功能。`I2C_WriteData()`函数用于向从设备写入数据,其中的`HAL_I2C_Master_Transmit()`函数用于发送数据。 请根据你的具体需求进行适当的修改和扩展。希望这能帮助到你!如果你还有其他问题,请继续提问。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值