STM32作为I2C从机中断接收和从模式中断应答数据总结

之前在项目中用到了STM32F103的i2c功能,大致功能是两个单片机进行i2c通信,而且通信模式是主问从答模式。这里我研究了一下STM32F103硬件i2c作为从机中断接收主设备请求,然后从设备在主设备发送读信号时中断发送回应的功能。

在网上找了很多资料,都说STM32F103的i2c硬件有瑕疵,具体有啥瑕疵我也不太清楚,只是大部分例程都是用IO模拟I2C。我这里使用的是硬件i2c,由于手上有两块单片机:一个是STM32F103VET6,另一个是STM32L151C8T6。开始还是比较头疼的,因为两个芯片不一样,工程就差别很大,后面我找以前的工程给这两个片子做了一套工程,比较复杂,STM32F103的还上了FreeRTOS,STM32L151的就是用的在cubeMAX上配置的工程,后面还找了个单片机的shell例程移植到这两款单片机上,实现shell测试。

 

1,STM32F103从中断接收和应答


#include "ipmi.h"
#include "cyclebuffer.h"
#include "FreeRTOS.h"
#include "task.h"
#include "fifo.h"
#include "i2c_gpio.h"
#include <stdio.h>
#include <string.h>

#define I2C_SLAVE_ADDRESS7 	0x30
#define ClockSpeed 			50000

__IO uint8_t ipmi_RX_buf[256]={0};
tFifo ipmi_fifo;


uint8_t I2C2_Buffer_Tx[64]={0};
uint8_t Tx_Idx,Rx_Idx,rx_addr_match=0,slave_receive_data=0;
uint8_t i2cResponse[16]="hello world! 5";
/*Exported types ------------------------------------------------------------*/

EventStatus i2c_event= NOEVENT;

void ipmi_i2c_configure(void)
{
	I2C_InitTypeDef I2C_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	GPIO_InitTypeDef GPIO_InitStructure;

	//I2C2 gpio congfig
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11; //SCL SDA
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
	GPIO_Init(GPIOB, &GPIO_InitStructure);
	
	/* Enable I2C2 clock */
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
	/* Enable GPIOB clock */
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
	
	/* Configure and enable I2Cx event interrupt -------------------------------*/
	NVIC_InitStructure.NVIC_IRQChannel = I2C2_EV_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_Init(&NVIC_InitStructure);

	/* Configure and enable I2C1 error interrupt -------------------------------*/
	NVIC_InitStructure.NVIC_IRQChannel = I2C2_ER_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;
	NVIC_Init(&NVIC_InitStructure);

	/* I2C1 configuration ------------------------------------------------------*/
	I2C_DeInit(I2C2);
	I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;//模式
	I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
	I2C_InitStructure.I2C_OwnAddress1 = I2C_SLAVE_ADDRESS7;//作为从机的地址
	I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
	I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;//
	I2C_InitStructure.I2C_ClockSpeed = ClockSpeed;
	I2C_Init(I2C2, &I2C_InitStructure);	

	/* Enable I2C1 event and buffer interrupts */
	I2C_ITConfig(I2C2, I2C_IT_EVT | I2C_IT_BUF, ENABLE);
	/* Enable I2C1 Error interrupts */
	I2C_ITConfig(I2C2, I2C_IT_ERR, ENABLE);
}


void ipmi_rx_fifo_init(void)
{
	FifoInit(&ipmi_fifo,(uint8_t *)ipmi_RX_buf,sizeof(ipmi_RX_buf));
	FifoFlush(&ipmi_fifo);
}

//时间终端处理函数
void I2C2_EV_IRQHandler(void)     
{ 
	uint8_t ch = 0,tempcnt=0;
	//获取中断事件
	switch (I2C_GetLastEvent(I2C2))
	{ 
		/* Slave Transmitter ---------------------------------------------------*/ 
		case I2C_EVENT_SLAVE_BYTE_TRANSMITTED: 
			/* 这个和下面那个都是从发生模式下发送数据的 */ 
			I2C_SendData(I2C2, i2cResponse[Tx_Idx]);
			Tx_Idx = 0;
			break; 

		case I2C_EVENT_SLAVE_BYTE_TRANSMITTING:             /* EV3 */  
			/* Transmit I2C1 data */
			I2C_SendData(I2C2, i2cResponse[Tx_Idx++]);
			break; 
		
		/* Slave Receiver ------------------------------------------------------*/ 
		case I2C_EVENT_SLAVE_RECEIVER_ADDRESS_MATCHED:     /* EV1 */ 
			rx_addr_match = 1;
			break; 

		case I2C_EVENT_SLAVE_BYTE_RECEIVED:                /* EV2 */ 
			/* Store I2C2 received data */ 
			slave_receive_data= 1;
			ch = I2C_ReceiveData(I2C2);
			if(false==IsFifoFull(&ipmi_fifo))
			{
				FifoPush(&ipmi_fifo,ch);
			}
			break; 

		case I2C_EVENT_SLAVE_STOP_DETECTED:                /* EV4 */
			/* Clear I2C2 STOPF flag */ 
			I2C_Cmd(I2C2, ENABLE); 
			Rx_Idx=0; 
			i2c_event = EVENT_OPCOD_NOTYET_READ; 
			break; 

		default: 
			break;    

	} 

} 
 
void I2C2_ER_IRQHandler(void) 
{ 
	/* Check on I2C1 AF flag and clear it */ 
	if (I2C_GetITStatus(I2C2, I2C_IT_AF)) 
	{ 
		I2C_ClearITPendingBit(I2C2, I2C_IT_AF); 
		Tx_Idx = 0; 

		i2c_event = EVENT_OPCOD_NOTYET_READ; 
	} 

	/* Check on I2C1 AF flag and clear it */ 

	if (I2C_GetITStatus(I2C2, I2C_IT_BERR))  
	{ 
		I2C_ClearITPendingBit(I2C2, I2C_IT_BERR);
	}

}

/*
*********************************************************************************************************
*	函 数 名: ipmi_WriteBytes
*	功能说明: 向串行EEPROM指定地址写入若干数据,采用页写操作提高写入效率
*	形    参:_usAddress : 起始地址
*			 _usSize : 数据长度,单位为字节
*			 _pWriteBuf : 存放读到的数据的缓冲区指针
*	返 回 值: 0 表示失败,1表示成功
*********************************************************************************************************
*/
uint8_t ipmi_WriteBytes(uint8_t *_pWriteBuf, uint16_t _usAddress, uint8_t ipmi_slave_addr, uint16_t _usSize)
{
	uint16_t i,m;
	uint16_t usAddr;
	
	/* 
		写串行EEPROM不像读操作可以连续读取很多字节,每次写操作只能在同一个page。
		对于24xx02,page size = 8
		简单的处理方法为:按字节写操作模式,没写1个字节,都发送地址
		为了提高连续写的效率: 本函数采用page wirte操作。
	*/

	usAddr = _usAddress;	
	for (i = 0; i < _usSize; i++)
	{
		/* 当发送第1个字节或是页面首地址时,需要重新发起启动信号和地址 */
		if ((i == 0) || (usAddr & (8 - 1)) == 0)
		{
			/* 第0步:发停止信号,启动内部写操作 */
			i2c_Stop();
			
			/* 通过检查器件应答的方式,判断内部写操作是否完成, 一般小于 10ms 			
				CLK频率为200KHz时,查询次数为30次左右
			*/
			for (m = 0; m < 100; m++)
			{				
				/* 第1步:发起I2C总线启动信号 */
				i2c_Start();
				
				/* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
				i2c_SendByte(ipmi_slave_addr | I2C_WR);	/* 此处是写指令 */
				
				/* 第3步:发送一个时钟,判断器件是否正确应答 */
				if (i2c_WaitAck() == 0)
				{
					break;
				}
			}
			if (m  == 1000)
			{
				goto cmd_fail;	/* EEPROM器件写超时 */
			}
		
			/* 第4步:发送字节地址,24C02只有256字节,因此1个字节就够了,如果是24C04以上,那么此处需要连发多个地址 */
			i2c_SendByte((uint8_t)usAddr);
			
			/* 第5步:发送ACK */
			if (i2c_WaitAck() != 0)
			{
				goto cmd_fail;	/* EEPROM器件无应答 */
			}
		}
	
		/* 第6步:开始写入数据 */
		i2c_SendByte(_pWriteBuf[i]);
	
		/* 第7步:发送ACK */
		if (i2c_WaitAck() != 0)
		{
			goto cmd_fail;	/* EEPROM器件无应答 */
		}

		usAddr++;	/* 地址增1 */		
	}
	
	/* 命令执行成功,发送I2C总线停止信号 */
	i2c_Stop();
	return 1;

cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
	/* 发送I2C总线停止信号 */
	i2c_Stop();
	return 0;
}


unsigned short IpmbCmdMatchTimeout(unsigned char *str,unsigned short TimeOut)
{
	unsigned short cnt=0;
	unsigned char flag=0,temp,strbuf[96];
	char *ptr=NULL;

	memset(strbuf,0,sizeof(strbuf));

	while((TimeOut!=0))
	{
		while(!IsFifoEmpty(&ipmi_fifo))
		{
			TimeOut = 10;
			temp = FifoPop(&ipmi_fifo);
			strbuf[cnt++] = temp;
			printf("0x%02x ",temp);
			ptr=strstr((char *)&strbuf[1],(char *)str);
			if(ptr)
			{
				flag = 1;
				continue ;
			}
		}
		TimeOut--;
		vTaskDelay(10);
	}
	
	if(flag)
	{
		printf("找到了%s\r\n",str);
		return cnt;
	}
	printf("没找到%s\r\n",str);
	return 0;
}



从中断接收和处理,主要在与I2C2_EV_IRQHandler和I2C2_ER_IRQHandler这两个中断函数,之前一直不知道的是,STM32F103的I2C从中断模式如何返回数据给主机,知道大神提点后,知道了,在主设备问从设备的时候(主设备发送读信号)从设备可以在中断处理中发送数据给主机,但是这种模式依然是从设备,回复数据是被动的,必须主设备发送读信号。

 

2,STM32L151做主设备发送i2c数据帧和请求数据应答

由于STM32L151使用的是cubeMAX建的工程,使用的是hal库,代码就规范很多,也直接调用hal的I2C库函数进行i2c数据发送和读取:

/**
  ******************************************************************************
  * File Name          : I2C.c
  * Description        : This file provides code for the configuration
  *                      of the I2C instances.
  ******************************************************************************
  ** This notice applies to any and all portions of this file
  * that are not between comment pairs USER CODE BEGIN and
  * USER CODE END. Other portions of this file, whether 
  * inserted by the user or by software development tools
  * are owned by their respective copyright owners.
  *
  * COPYRIGHT(c) 2019 STMicroelectronics
  *
  * Redistribution and use in source and binary forms, with or without modification,
  * are permitted provided that the following conditions are met:
  *   1. Redistributions of source code must retain the above copyright notice,
  *      this list of conditions and the following disclaimer.
  *   2. Redistributions in binary form must reproduce the above copyright notice,
  *      this list of conditions and the following disclaimer in the documentation
  *      and/or other materials provided with the distribution.
  *   3. Neither the name of STMicroelectronics nor the names of its contributors
  *      may be used to endorse or promote products derived from this software
  *      without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  *
  ******************************************************************************
  */

/* Includes ------------------------------------------------------------------*/
#include "i2c.h"

#include "gpio.h"

/* USER CODE BEGIN 0 */
#include "command_line.h"
#include "queue.h"
/* USER CODE END 0 */

I2C_HandleTypeDef hi2c1;
I2C_HandleTypeDef hi2c2;

/* I2C1 init function */
void MX_I2C1_Init(void)
{

  hi2c1.Instance = I2C1;
  hi2c1.Init.ClockSpeed = 100000;
  hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c1.Init.OwnAddress1 = 0x34;
  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(__FILE__, __LINE__);
  }

}
/* I2C2 init function */
void MX_I2C2_Init(void)
{

  hi2c2.Instance = I2C2;
  hi2c2.Init.ClockSpeed = 100000;
  hi2c2.Init.DutyCycle = I2C_DUTYCYCLE_2;
  hi2c2.Init.OwnAddress1 = 106;
  hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
  hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
  hi2c2.Init.OwnAddress2 = 0;
  hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
  hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
  if (HAL_I2C_Init(&hi2c2) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
  }

}

void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct;
  if(i2cHandle->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspInit 0 */

  /* USER CODE END I2C1_MspInit 0 */
  
    /**I2C1 GPIO Configuration    
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
    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);

    /* I2C1 clock enable */
    __HAL_RCC_I2C1_CLK_ENABLE();
  /* USER CODE BEGIN I2C1_MspInit 1 */

  /* USER CODE END I2C1_MspInit 1 */
  }
  else if(i2cHandle->Instance==I2C2)
  {
  /* USER CODE BEGIN I2C2_MspInit 0 */

  /* USER CODE END I2C2_MspInit 0 */
  
    /**I2C2 GPIO Configuration    
    PB10     ------> I2C2_SCL
    PB11     ------> I2C2_SDA 
    */
    GPIO_InitStruct.Pin = GPIO_PIN_10|GPIO_PIN_11;
    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_I2C2;
    HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

    /* I2C2 clock enable */
    __HAL_RCC_I2C2_CLK_ENABLE();
  /* USER CODE BEGIN I2C2_MspInit 1 */

  /* USER CODE END I2C2_MspInit 1 */
  }
}

void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle)
{

  if(i2cHandle->Instance==I2C1)
  {
  /* USER CODE BEGIN I2C1_MspDeInit 0 */

  /* USER CODE END I2C1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_I2C1_CLK_DISABLE();
  
    /**I2C1 GPIO Configuration    
    PB6     ------> I2C1_SCL
    PB7     ------> I2C1_SDA 
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_6|GPIO_PIN_7);

  /* USER CODE BEGIN I2C1_MspDeInit 1 */

  /* USER CODE END I2C1_MspDeInit 1 */
  }
  else if(i2cHandle->Instance==I2C2)
  {
  /* USER CODE BEGIN I2C2_MspDeInit 0 */

  /* USER CODE END I2C2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_I2C2_CLK_DISABLE();
  
    /**I2C2 GPIO Configuration    
    PB10     ------> I2C2_SCL
    PB11     ------> I2C2_SDA 
    */
    HAL_GPIO_DeInit(GPIOB, GPIO_PIN_10|GPIO_PIN_11);

  /* USER CODE BEGIN I2C2_MspDeInit 1 */

  /* USER CODE END I2C2_MspDeInit 1 */
  }
} 

/* USER CODE BEGIN 1 */
//IPMI数据帧转化16进制
unsigned short str2HEX(unsigned char *src,unsigned char *des)
{
   	unsigned short i=0,j=1;
	unsigned char byte = 0;
	unsigned char *ptr = src;
	while(*ptr!='\0')
	{
		if(*ptr == ' ')
		{
			des[i++] = byte;
			byte = 0;
			j = 1;
			ptr++;//
		}
		else
		{
				if(*ptr >= 'a' && *ptr <= 'f')
					byte += (*ptr - '0'-39)*(16%(16+j)+16/(16+j));
				else if(*ptr >= 'A' && *ptr <= 'F')
					byte += (*ptr - '0'-7)*(16%(16+j)+16/(16+j));
			    else if((*ptr >='0') && (*ptr <= '9'))
					byte += (*ptr - '0')*(16%(16+j)+16/(16+j));
				if(j--<=0) j = 1;
				ptr++;
		}
 
 
		if(*ptr == '\0')//the last byte
		{
			des[i++] = byte;
		}
	}
	/*
	j = i;
	for(i=0;i<j;i++)
	{
		//printf("0x%02x ",des[i]);
	*/
	return i;
}

/**
 * @brief  I2C command line
 * @param  null
 * @retval null
 */
uint8_t CLI_IPMI(void *para, uint8_t len)
{
    uint8_t *pTemp,err;
		int cnt = 0,i = 0;
		uint8_t tempbuf[256]={0};
		uint8_t ipmimsg[256] = {0};
    pTemp = (uint8_t *)para;

    if ((0 < len) && (NULL != pTemp)) 
		{
        pTemp++; /* skip a blank space */
        if ('w' == *pTemp) 
				{
					++pTemp; /* skip a blank space */
					printf("\nipmi cmd:%s\r\n",++pTemp);
					while(*pTemp)
					{
						tempbuf[cnt++] = *pTemp;
						pTemp++; 
					}
					cnt = str2HEX(tempbuf,ipmimsg);
					printf("ipmi cmd data size [%d]\r\n",cnt-1);
					if(HAL_I2C_IsDeviceReady(&hi2c1,ipmimsg[0],3,50)==HAL_OK)
					{
						err = HAL_I2C_Mem_Write(&hi2c1,ipmimsg[0], 0, I2C_MEMADD_SIZE_8BIT ,&ipmimsg[1], cnt-1,200);
						if(!err)
						{
							NL1();
							DBG("ipmi write done\r\n");
						}
						else
						{
								printf("write i2c data err\r\n");      
								return False;
						}
					}
					else
					{
						DBG("i2c slave device not exits\r\n");
						return False;
					}
        } 
				else if ('r' == *pTemp) 
				{
						++pTemp; /* skip a blank space */
						printf("ipmi cmd:%s\r\n",++pTemp);
						while(*pTemp)
						{
							tempbuf[cnt++] = *pTemp;
							pTemp++;
						}
						cnt = str2HEX(tempbuf,ipmimsg);
						
						if(cnt>2)
						{
							printf("too more parameters\r\n");
							return False;
						}
						
						if(ipmimsg[1]>127)
						{
							printf("read len out of range,please modify len to read and try again!\r\n");
							return False;
						}
						
						if(HAL_I2C_IsDeviceReady(&hi2c1,ipmimsg[0],3,50)==HAL_OK)						
						{
							memset(tempbuf,0,sizeof(tempbuf));
							err = HAL_I2C_Mem_Read(&hi2c1,ipmimsg[0], 0, I2C_MEMADD_SIZE_8BIT, tempbuf, ipmimsg[1], 200);
							if(!err)
							{
								printf("read i2c data:");
								for(i=0;i<ipmimsg[1];i++)
								printf("0x%02x ",tempbuf[i]);
								printf("\r\n");
								NL1();
								DBG("i2c read done\r\n");
							}
							else
							{
								printf("read i2c data err\r\n");      
								return False;
							}
						}
						else
						{
							DBG("i2c slave device not exits\r\n");
							            
							return False;
						}
        } 
				else 
				{
            /* para. wrong */
            return False;
        }
    }

    return True;
}
/* USER CODE END 1 */

/**
  * @}
  */

/**
  * @}
  */

/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/

不知道hal的库封装是怎样实现的,但是i2c发送读取只能调用HAL_I2C_Mem_Write和HAL_I2C_Mem_Read这两个函数才能正常发送和读取数据,但是想深入研究HAL库的同学,可以好好看看它的封装函数。

 

 

 

 

 

 

 

 

  • 9
    点赞
  • 107
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 8
    评论
stm8si2c程序,调试通过 INTERRUPT_HANDLER(I2C_IRQHandler, 19) { /* In order to detect unexpected events during development, it is recommended to set a breakpoint on the following instruction. */ struct SCB_T *system=&system_process; unsigned char i,i2c_sr1,i2c_sr2,i2c_event,i2c__status=0,temp,sr1_analysis_int_resource[8],sr2_analysis_int_resource[8]; char i2c_interrupt_type=0,p;//在一次I2中断中,I2C中断中的中断标志位个数; disableInterrupts();//关总中断 i2c_sr1=I2C->SR1; p=I2C->SR3; i2c_sr2=I2C->SR2; //temp=I2C->SR3; //analysis interrupt resource in i2c->sr1 register sr1_analysis_int_resource[0]=i2c_sr1&I2C_SR1_SB; sr1_analysis_int_resource[1]=i2c_sr1&I2C_SR1_ADDR; sr1_analysis_int_resource[2]=i2c_sr1&I2C_SR1_BTF; sr1_analysis_int_resource[3]=i2c_sr1&I2C_SR1_ADD10; sr1_analysis_int_resource[4]=i2c_sr1&I2C_SR1_STOPF; // sr1_i2c__state[5]=i2c_state&((u8)I2C_SR1_BIT6); sr1_analysis_int_resource[6]=i2c_sr1&I2C_SR1_RXNE; sr1_analysis_int_resource[7]=i2c_sr1&I2C_SR1_TXE; //analysis interrupt resource in i2c->sr2 register sr2_analysis_int_resource[0]=i2c_sr2&I2C_SR2_BERR; sr2_analysis_int_resource[1]=i2c_sr2&I2C_SR2_ARLO; sr2_analysis_int_resource[2]=i2c_sr2&I2C_SR2_AF; sr2_analysis_int_resource[3]=i2c_sr2&I2C_SR2_OVR; sr2_analysis_int_resource[5]=i2c_sr2&I2C_SR2_WUFH; if(sr1_analysis_int_resource[0]==I2C_SR1_SB) {i2c__status=0x01;i2c_interrupt_type++;} if(sr1_analysis_int_resource[1]==I2C_SR1_ADDR) {i2c__status=0x02;i2c_interrupt_type++;} if(sr1_analysis_int_resource[2]==I2C_SR1_BTF) {i2c__status=0x03;i2c_interrupt_type++;} if(sr1_analysis_int_resource[3]==I2C_SR1_ADD10) {i2c__status=0x04;i2c_interrupt_type++;} if(sr1_analysis_int_resource[4]==I2C_SR1_STOPF) {i2c__status=0x05;i2c_interrupt_type++;} if(sr1_analysis_int_resource[6]==I2C_SR1_RXNE) {i2c__status=0x06;i2c_interrupt_type++;} if(sr1_analysis_int_resource[7]==I2C_SR1_TXE) {i2c__status=0x07;i2c_interrupt_type++;} if(sr2_analysis_int_resource[0]==I2C_SR2_BERR) {i2c__status=0x08;i2c_interrupt_type++;} if(sr2_analysis_int_resource[1]==I2C_SR2_ARLO) {i2c__status=0x09;i2c_interrupt_type++;} if(sr2_analysis_int_resource[2]==I2C_SR2_AF) {i2c__status=0x0a;i2c_interrupt_type++;} if(sr2_analysis_int_resource[3]==I2C_SR2_OVR) {i2c__status=0x0b;i2c_interrupt_type++;} if(sr2_analysis_int_resource[5]==I2C_SR2_WUFH) {i2c__status=0x0c;i2c_interrupt_type++;} if(i2c_interrupt_type>=2) /*there are more than one interrupt resource in the time*/ { if(i2c_interrupt_type==2) { if((sr1_analysis_int_resource[1]==I2C_SR1_ADDR)&&(sr1_analysis_int_resource[7]==I2C_SR1_TXE)) { I2C->DR=system->i2c.send_frame.data[system->i2c.send_frame.proc]; system->i2c.send_frame.proc++; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x62; } else if((sr1_analysis_int_resource[7]==I2C_SR1_TXE)&&(sr1_analysis_int_resource[2]==I2C_SR1_BTF)) { system->i2c.send_frame.terminate=0; //set I2C transfer terminate bit; system->i2c.send_frame.mod=0; system->i2c.send_frame.write=0; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x64; } else if((sr1_analysis_int_resource[7]==I2C_SR1_TXE)&&(sr2_analysis_int_resource[2]==I2C_SR2_AF)) { I2C->CR2|=I2C_CR2_STOP; I2C->SR2&=(~I2C_SR2_AF);//clear AF bit; system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x64; } else { system->i2c.error=1; I2C_ITConfig(I2C_IT_EVT, DISABLE); system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x37; } } else { system->i2c.error=1; I2C_ITConfig(I2C_IT_EVT, DISABLE); system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x37; } } else { switch(i2c__status) { case I2C_SR1_SB_proc: //如果是发送模式 if(system->i2c.send_frame.mod==1)//说明本次中断之前是从模式,说明这是在从模式下发的起始位; { //EV5 p=I2C->SR1; I2C->DR=system->i2c.send_frame.add__L; //自动清除I2C_SR1_SB标志 system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x38; } else { if(system->i2c.rev_frame.mod==1) //说明本次中断之间是主模式,这次发的是重复起始位; { //EV6如果是接收模式 p=I2C->SR1; I2C->DR=system->i2c.rev_frame.add__L;//自动清除I2C_SR1_SB标志; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x51; } else { system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x36; } } break; case I2C_SR1_ADDR_proc: p=I2C->SR1; temp=I2C->SR3;//软件读取SR1寄存器后,对SR3寄存器的读操作将清除该位 temp&=(u8)I2C_SR3_TRA; I2C->CR2|=(u8)I2C_CR2_ACK;// 使能应答I2C->CR2&=(u8)(~I2C_CR2_POS);//设置接受到当字节应答 //如果是发送模式 if(system->i2c.send_frame.mod==1) { if(temp==(u8)I2C_SR3_TRA) {; } else { system->i2c.error=1; } } else { if(system->i2c.rev_frame.mod==1) { if(temp==0)//machine at a master-receive mod { system->i2c.rev_frame.proc=0; } else { system->i2c.error=1; } } else { system->i2c.error=1; } } system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x52; break; case I2C_SR1_RXNE_proc: if(system->i2c.rev_frame.proci2c.rev_frame.num-3)) { system->i2c.rev_frame.data[system->i2c.rev_frame.proc]=I2C->DR; system->i2c.rev_frame.proc++; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x57; } else if(system->i2c.rev_frame.proc==(u8)(system->i2c.rev_frame.num-2)) { system->i2c.rev_frame.data[system->i2c.rev_frame.proc]=I2C->DR; system->i2c.rev_frame.proc++; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x58; I2C->CR2&=(u8)(~I2C_CR2_ACK);//不返回应答 I2C->CR2|=I2C_CR2_STOP; //发停止位结束这次数据接收; } else if(system->i2c.rev_frame.proc>=(u8)(system->i2c.rev_frame.num-1)) { system->i2c.rev_frame.data[system->i2c.rev_frame.proc]=I2C->DR; system->i2c.rev_frame.proc++; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x59; system->i2c.rev_frame.terminate=0; //set I2C transfer terminate bit; system->i2c.rev_frame.mod=0; system->i2c.rev_frame.read=0; } else { system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0xfb; } break; case I2C_SR1_TXE_proc: if(system->i2c.send_frame.proci2c.send_frame.num-1)) { I2C->DR=system->i2c.send_frame.data[system->i2c.send_frame.proc]; system->i2c.send_frame.proc++; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x61; } else if(system->i2c.send_frame.proc=(u8)(system->i2c.send_frame.num)) { I2C->CR2|=I2C_CR2_STOP; // 发停止位结束 这次数据接收I2C_ITConfig(I2C_IT_BUF, DISABLE); system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x60; } else { system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0xfc; } break; case I2C_SR2_AF_proc: I2C->CR2|=I2C_CR2_STOP; I2C->SR2&=(~I2C_SR2_AF);//clear AF bit; system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0x63; break; default: system->i2c.error=1; system->i2c.debug.reserve[system->i2c.int_debug_count].type=0xfd; break; } } system->i2c.int_debug_count++; enableInterrupts();//开总中断 }
以下是一个简单的示例代码,用于在STM32F103上使用硬件I2C作为从机模式: 首先,需要包含相关的头文件: ```c #include "stm32f10x.h" #include "stm32f10x_i2c.h" #include "stm32f10x_gpio.h" #include "stm32f10x_rcc.h" ``` 然后,需要定义一些宏,用于配置I2C参数: ```c #define I2C_SLAVE_ADDRESS 0x50 // 从机地址 #define I2C_GPIO_PORT GPIOB // I2C引脚所在的GPIO端口 #define I2C_SCL_PIN GPIO_Pin_6 // I2C时钟引脚 #define I2C_SDA_PIN GPIO_Pin_7 // I2C数据引脚 #define I2C_RCC_GPIO RCC_APB2Periph_GPIOB // I2C引脚所在的GPIO端口时钟 #define I2C_RCC RCC_APB1Periph_I2C1 // I2C外设时钟 #define I2C_SPEED 100000 // I2C时钟速度 #define I2C_OWN_ADDRESS 0x00 // 本机地址 #define I2C_ACKNOWLEDGE I2C_Ack_Enable // I2C应答方式 ``` 然后,需要定义一些全局变量: ```c I2C_InitTypeDef I2C_InitStructure; // I2C初始化结构体 GPIO_InitTypeDef GPIO_InitStructure; // GPIO初始化结构体 uint8_t i2c_buffer[10]; // I2C数据缓存区 ``` 接下来,需要编写初始化函数: ```c void I2C_Init(void) { // 使能I2C外设时钟 RCC_APB1PeriphClockCmd(I2C_RCC, ENABLE); // 使能I2C引脚所在的GPIO端口时钟 RCC_APB2PeriphClockCmd(I2C_RCC_GPIO, ENABLE); // 配置I2C引脚 GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN | I2C_SDA_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(I2C_GPIO_PORT, &GPIO_InitStructure); // 配置I2C外设 I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; I2C_InitStructure.I2C_OwnAddress1 = I2C_OWN_ADDRESS; I2C_InitStructure.I2C_Ack = I2C_ACKNOWLEDGE; I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; I2C_InitStructure.I2C_ClockSpeed = I2C_SPEED; I2C_Init(I2C1, &I2C_InitStructure); // 使能I2C外设 I2C_Cmd(I2C1, ENABLE); } ``` 然后,需要编写一个函数来处理I2C从机接收数据中断: ```c void I2C1_EV_IRQHandler(void) { if (I2C_GetITStatus(I2C1, I2C_IT_EVT) == SET) { if (I2C_GetFlagStatus(I2C1, I2C_FLAG_ADDR) == SET) { // 清除ADDR标志位 (void)I2C1->SR2; // 使能接收数据中断 I2C_ITConfig(I2C1, I2C_IT_BUF, ENABLE); } else if (I2C_GetFlagStatus(I2C1, I2C_FLAG_RXNE) == SET) { // 从I2C数据寄存器中读取数据 uint8_t data = I2C_ReceiveData(I2C1); // 将接收到的数据存储到缓存区中 i2c_buffer[0] = data; // 清除RXNE标志位 I2C_ClearFlag(I2C1, I2C_FLAG_RXNE); } else if (I2C_GetFlagStatus(I2C1, I2C_FLAG_STOPF) == SET) { // 清除STOPF标志位 I2C_ClearFlag(I2C1, I2C_FLAG_STOPF); // 禁用接收数据中断 I2C_ITConfig(I2C1, I2C_IT_BUF, DISABLE); } else { // do nothing } // 清除EVT标志位 I2C_ClearITPendingBit(I2C1, I2C_IT_EVT); } } ``` 最后,需要在主函数中初始化I2C,并启动中断: ```c int main(void) { // 初始化I2C I2C_Init(); // 使能I2C从机接收数据中断 NVIC_EnableIRQ(I2C1_EV_IRQn); while (1) { // do something } } ``` 以上是一个简单的示例代码,用于在STM32F103上使用硬件I2C作为从机模式。由于具体的应用场景不同,实际代码可能需要进行一些修改。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

yzxjd1314

多谢鼓励,探索前行

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

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

打赏作者

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

抵扣说明:

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

余额充值