STM32HAL库硬件IIC从机中断收发实现

前言

想说的话:这一篇博客是自己作为笔记用的,仍然有一些问题没有解决,是按照我自己的需求写的。因为CubeMX自带的库函数烂的一批,然后我就自己根据手册写了,所以有很多是寄存器操作,不过应该还是有一定的参考意义。
尚存bug:1:没有加入超时机制
2:发送完成时,stopf位不能被置位,导致无法退出发送状态(尝试控制发送字节解决,嘻嘻我的协议是固定字节的)

数据手册

我们中断里面写的处理函数,基本就是按照这里的流程来的。

1从机发送流程

STM32HAL库硬件IIC从机中断收发实现_第1张图片

2从机接收流程

STM32HAL库硬件IIC从机中断收发实现_第2张图片

3IIC中断表

这也是比较重要的一张表,中断之后,必须清空标志位后才能进行通讯。
STM32HAL库硬件IIC从机中断收发实现_第3张图片
原来数据手册内还有发送接收的时序图,但其实就是流程图的时序描写,本质上是同一个事物,这里就不粘了 ,有兴趣的朋友可以去参考下。

初始化

根据数据手册,我做出如下设计:每当收到主机发来的地址时,就触发中断,然后在中断里面判断读写,接着进入读写流程(参照上面流程图)
从机硬件初始化:

/* I2C3 init function */
static void MX_I2C3_Init(void)
{

  hi2c3.Instance = I2C3;
  hi2c3.Init.Timing = 0x10909CEC;
  hi2c3.Init.OwnAddress1 = 0x60;//从机地址,注意和主机对应
  hi2c3.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c3.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c3.Init.OwnAddress2 = 0;
  hi2c3.Init.OwnAddress2Masks = I2C_OA2_NOMASK;
  hi2c3.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c3.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c3) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**Configure Analogue filter 
    */
  if (HAL_I2CEx_ConfigAnalogFilter(&hi2c3, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

    /**Configure Digital filter 
    */
  if (HAL_I2CEx_ConfigDigitalFilter(&hi2c3, 0) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }
//I2C_Enable_IRQ(hi2c3,I2C_XFER_RX_IT|I2C_XFER_TX_IT);
//	 if (HAL_I2C_EnableListen_IT(&hi2c3) != HAL_OK)
//  {
//   _Error_Handler(__FILE__, __LINE__);
//  }
	I2C3->CR1|=0x08;//使能addr中断
	//I2C3->CR1|=0x20000;
}
 /* USER CODE BEGIN I2C3_MspInit 0 */

  /* USER CODE END I2C3_MspInit 0 */
      __HAL_RCC_I2C3_CLK_ENABLE();
    /**I2C3 GPIO Configuration    
    PA7     ------> I2C3_SCL
    PB4 (NJTRST)     ------> I2C3_SDA 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_7;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
    GPIO_InitStruct.Pull = GPIO_PULLUP;//特别注意这里的上拉电阻,可以测试下,主机和从机应该都要能置0,1,一般主机提供会比较好
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    GPIO_InitStruct.Alternate = GPIO_AF4_I2C3;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_4;
    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_I2C3;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* Peripheral clock enable */

    /* I2C3 interrupt Init */
    HAL_NVIC_SetPriority(I2C3_EV_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(I2C3_EV_IRQn);
    HAL_NVIC_SetPriority(I2C3_ER_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(I2C3_ER_IRQn);
  /* USER CODE BEGIN I2C3_MspInit 1 */

初始化完成后,寄存器如下所示(stm32l431系列)
STM32HAL库硬件IIC从机中断收发实现_第4张图片

中断处理函数

void I2C3_EV_IRQHandler(void)
{
  /* USER CODE BEGIN I2C3_EV_IRQn 0 */

  /* USER CODE END I2C3_EV_IRQn 0 */
	loop1:
  	HAL_I2C_EV_IRQHandler(&hi2c3);
  /* USER CODE BEGIN I2C3_EV_IRQn 1 */
	if((((I2C3->ISR)&0x08)>>3)==1)//判断是addr触发的中断
	{
		I2C3->ISR|=0x01;//TXE=1
		I2C3->ICR|=0x08;//清除addr
	}

//读写处理
		{
			
			if((((I2C3->ISR)&0x10000)>>16)==1)//dir
			{
				int i=0;
				int j=0;
				while(((((I2C3->ISR)&0x32)>>5)==0))//detect stop
				{
					if(((((I2C3->ISR)&0x10000)>>16)==0)||((((I2C3->ISR)&0x08)>>3)==1))//addr or read
				goto loop1;			
				if(((((I2C3->ISR)&0x02)>>1)==1))TXIS
				{
					if(I2C3->RXDR==0x00)
					I2C3->TXDR=ppp1[i];
					if(I2C3->RXDR==0x12)
					{
						I2C3->TXDR=ppp2[i];
						
					}
					
					//[i]=I2C3->RXDR;
					i++;
			
				}
						if(i==21)
					{
					//21个字节 退出	
						ppp2[0]++;
						return;
					}
			
				}
				
				//x=HAL_I2C_Slave_Receive(&hi2c3,ppp,2,5);
				I2C3->ICR=(I2C3->ICR)|0x32;//clear stop

			else//read
			{
				int i=0;
				while(((((I2C3->ISR)&0x32)>>5)==0))//detect stop
				{
					if(((((I2C3->ISR)&0x10000)>>16)==1)||((((I2C3->ISR)&0x08)>>3)==1))
						goto loop1;					
					if(((((I2C3->ISR)&0x04)>>2)==1))//RXNE
					{
						ppp[i]=I2C3->RXDR;
						i++;
					}
					}
				//x=HAL_I2C_Slave_Receive(&hi2c3,ppp,2,5);
				I2C3->ICR=(I2C3->ICR)|0x32;
			}
	
		}

//	I2C3->CR1|=0x08;

//  /* USER CODE END I2C3_EV_IRQn 1 */
}

寄存器说明

ISR:
|bit23…17|ADDCODE ----|主机地址----------|
|bit16…|DIR------------------|0读/1写------------|在addr=1时更新
|bit15…|BUSY---------------| ---------------------|起始信号=1,检测到stop=0
|bit5…|STOPF---------------|----------------------|检测到stop
|bit3…|ADDR----------------|----------------------|匹配到地址
|bit2…|RXNE----------------|----------------------|RXDR不为空
|bit1…|TXIS------------------|-------------------- -|发送标志
|bit0…|TXE------------------|-----------------------|TXDR为空

你可能感兴趣的:(STM32笔记)