STM32 LL库 硬件IIC从机中断收发通信

1、IC内部硬件原理

I2C由一个独立的时钟源计时,它允许I2C从PCLK频率独立地操作。

主从机模式只需要配置I2C_SDA和I2C_SCL和打开I2C APB clock(i2c_pclk)时钟;

2、初始化

3、通讯波形

Acknowledge(ACK)能软件启用或禁用。I2C接口的地址可以通过软件选择。

例如:I2C_InitStruct.OwnAddress1 = 0xA8;//接收地址

I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;//ACK在当前收到的字节之后发送

IIC初始化部分:

void MX_I2C2_Init(void)
{
  LL_I2C_InitTypeDef I2C_InitStruct = {0};
  LL_GPIO_InitTypeDef GPIO_InitStruct = {0};

  LL_AHB2_GRP1_EnableClock(LL_AHB2_GRP1_PERIPH_GPIOB);
  /**I2C2 GPIO Configuration
  PB10   ------> I2C2_SCL
  PB11   ------> I2C2_SDA
  */
  GPIO_InitStruct.Pin = LL_GPIO_PIN_10|LL_GPIO_PIN_11;
  GPIO_InitStruct.Mode = LL_GPIO_MODE_ALTERNATE;
  GPIO_InitStruct.Speed = LL_GPIO_SPEED_FREQ_VERY_HIGH;
  GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_OPENDRAIN;
  GPIO_InitStruct.Pull = LL_GPIO_PULL_UP;
  GPIO_InitStruct.Alternate = LL_GPIO_AF_4;
  LL_GPIO_Init(GPIOB, &GPIO_InitStruct);

  /* Peripheral clock enable */
  LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_I2C2);

  /* I2C2 interrupt Init */
  NVIC_SetPriority(I2C2_EV_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
  NVIC_EnableIRQ(I2C2_EV_IRQn);
  NVIC_SetPriority(I2C2_ER_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
  NVIC_EnableIRQ(I2C2_ER_IRQn);

  /** I2C Initialization
  */
  LL_I2C_EnableAutoEndMode(I2C2);
  LL_I2C_DisableOwnAddress2(I2C2);
  LL_I2C_DisableGeneralCall(I2C2);
  LL_I2C_EnableClockStretching(I2C2);
  I2C_InitStruct.PeripheralMode = LL_I2C_MODE_I2C;//I2C主或者从机模式
  I2C_InitStruct.Timing = 0x00731012;       
  I2C_InitStruct.AnalogFilter = LL_I2C_ANALOGFILTER_ENABLE;  //模拟滤波器开启
  I2C_InitStruct.DigitalFilter = 0;//数字滤波器
  I2C_InitStruct.OwnAddress1 = 0xA8;//接收地址
  I2C_InitStruct.TypeAcknowledge = LL_I2C_ACK;//ACK在当前收到的字节之后发送
  I2C_InitStruct.OwnAddrSize = LL_I2C_OWNADDRESS1_7BIT;//7位地址
  LL_I2C_Init(I2C2, &I2C_InitStruct);

	LL_I2C_Enable(I2C2);//Enable I2C peripheral .
	uint32_t temp = I2C_IT_STOPI |
				    I2C_IT_ADDRI |
				    I2C_IT_RXI   |
				    I2C_IT_TXI;
    I2C2->CR1 |= temp;  //初始化IIC中断
}

IIC中断接收部分:

从机在接收和发送之前都要比配地址;

1、从机接收流程图

2、从机发送的流程图

/*IIC中断接收*/
void I2C2_EV_IRQHandler(void)
{
	static uint8_t  Instruct = 0;
	static uint8_t	Offset   = 0;//接收的数据个数
	static uint8_t	TxBuff_num   = 0;//发送的数据个数
	static uint8_t  MaxBytes = 0;
	static uint8_t  Addr_Bit=0;//因为接收和发送前都会I2C_ISR_ADDR,确保比配地址后接收和发送完成I2C_ISR_STOPF;

	static uint8_t *TxBuff;
	static uint8_t RxBuff[40] = { 0 };

	uint8_t  temp;
	uint32_t status;
	status = I2C2->ISR;//接收硬件自动发送过来的寄存器数据
	
//	DBG_printf("I2C2->ISR: %08X \n\r", status);
	if((status & I2C_ISR_ADDR)&&(!Addr_Bit))//判断是addr触发的中断 //0x00000008
	{
		I2C2->ISR|=I2C_ISR_TXE;//TXE=1
		I2C2->ICR|=I2C_ISR_ADDR;//0x08;//清除addr
		if(status & I2C_ISR_DIR)   //0x00010000  //Transfer direction (slave mode)
		{   // I2C2: slave enters transmitter mode.
			if(Flag_Wakeup == 0xAA) Flag_Wakeup = 0; 
		}
		else
		{   // I2C1: slave enters receiver mode.
			Instruct = 1;
		}
		Offset = 0;
		TxBuff_num=0;
//		DEBUG_I2C("I2C_ISR_ADDR =%d,%d,%08X \n\r", Instruct,Offset,status);
	}
	else if(status & I2C_ISR_RXNE)//从机接收内容
	{
		Addr_Bit=1;
		I2C1->ISR |= I2C_ISR_TXE;
		temp = LL_I2C_ReceiveData8(I2C2);
		if(Instruct)
			{   // Host Instruct
				switch(temp)
				{
					case 0x00:  // Get DevInfo
						TxBuff = (uint8_t *)&tpDevInfo;		// 24 bytes
						MaxBytes = sizeof(tpDevInfo);
						break;
					case 0x18:	// Get DevStatus//主机询问从机是否就绪
						Addr_Bit=0;  //
						TxBuff = (uint8_t *)&tpDevStatus;	// 8 bytes
						MaxBytes = sizeof(tpDevStatus);
						EventRelieved();
					break;
				default: break;
				}
				Instruct = 0;
			}
			if(Offset <= sizeof(MotorCtrlTab))
			{
				RxBuff[Offset] = temp;//保存接收的内容
//				DEBUG_I2C("I2C_ISR_RXNE =%x,%d,%08X \n\r", RxBuff[Offset],Offset,status);
    			  Offset++;
			}
	}
	else if(status & I2C_ISR_TXIS)//0x00000002//从机发送命令
	{
		I2C2->ISR |= I2C_ISR_TXE;//清除I2C_ISR_TXE标志
		if(Offset < MaxBytes)
		{    //发送需要的数据给主机
			LL_I2C_TransmitData8(I2C2, TxBuff[TxBuff_num++]);
		}
		else
		{
//			DEBUG_I2C("I2C_ISR_TXIS =ff,%d,%08X \n\r", TxBuff_num,status);
			LL_I2C_TransmitData8(I2C2, 0xff);
		}
	}
	else if(status & I2C_ISR_STOPF)//停止检测标志
	{
		Addr_Bit=0;
		I2C2->ICR|=I2C_ISR_STOPF;//清除I2C_ISR_STOPF标志
		DEBUG_I2C("STOPF =%x,%x,%d \n", RxBuff[0],RxBuff[1],Offset);
		if((status & 0x10000) == 0)
		{   // Instruction parsing from the Host
		    if(Offset == 2)//Offset接收的数据个数
		    {
		    	switch(RxBuff[0])//取出接收的内容进行判断
		    	{
		    		case 0x31:	// Set Heat pulse width
		    			break;
		    		case 0x32:  // Set Motor speed
		    			break;
		    		case 0x33:  // Set Motor direction
		    			break;
		    		default: return;
		    	}
		    }
		    else if(Offset == 3)
		    {
	
		    }
		    else if(Offset == (1 + sizeof(tpDevControl)))
		    {

		    }
		    else if(Offset == (1 + sizeof(MotorCtrlTab)))
		    {
	
		    }
		}
  }
	else
	{
		I2C2->ICR = 0x00003F38;//I2C_ClearITPendingBit(I2C2, 0x00003F38);
		DBG_printf("I2C2 Unknown event occurs!\n\r");
	}
  /* USER CODE END I2C2_EV_IRQn 1 */
}

  • 1
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汽车观察侠

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值