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

您所在的位置:网站首页 i2c主模式和从模式怎么决定 STM32作为I2C从机中断接收和从模式中断应答数据总结

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

2024-07-10 17:22| 来源: 网络整理| 查看: 265

之前在项目中用到了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 #include #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 = 'A' && *ptr ='0') && (*ptr


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3