求教STM32硬件I2C EV5和EV6错误问题
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了求教STM32硬件I2C EV5和EV6错误问题相关的知识,希望对你有一定的参考价值。
EV5、EV6并不是错误。
EV5事件:
程序中是这样调用的
//检测 EV5 事件并清除标志
while(! I2C_CheckEvent(EEPROM_I2C,I2C_EVENT_MASTER_MODE_SELECT))
if ((I2CTimeout--) == 0) return I2C_TIMEOUT_UserCallback(1);
可以看到这里有一个宏I2C_EVENT_MASTER_MODE_SELECT,它定义在stm32f4xx_i2c.h头文件中(答主用的STM32F4单片机)
它的值为((uint32_t)0x00030001)。
这里还有一个函数I2C_CheckEvent();
这个函数将I2C的两个16位寄存器SR1和SR2合并成一个32位数据再与FLAG_MASK (这也是一个宏,在stm32f4xx_i2c.c中,它的值为((uint32_t)0x00FFFFFF)) 做按位与运算,得到SR1的低8位数据和SR2的全部16位数据,这个数据再与宏 I2C_EVENT_MASTER_MODE_SELECT 做按位与运算这个宏的值为((uint32_t)0x00030001) ,取出了SR1寄存器的位0、位1,SR2寄存器的位0 的值。
我们来看看 SR1寄存器的位0、位1,SR2寄存器的位0 表示的什么含义?
在STM32F4xx中文参考手册中查到:
SR1:
SR2:
可见,EV5事件是判断起始位有没有产生、判断是主模式还是从模式,地址有没有发送的? 判断完成,无异常接下来就开始发送从设备地址了。
EV6事件同理,如果不懂,说明还没有理解上面的EV5事件,继续看EV5。
参考技术A 这两个不是错误。当你配置I2C为主模式式,会有EV5时间产生。主模式配置为发送模式的时候会有EV6I2C_EVENT_MASTER_MODE_SELECT: EV5
I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED: EV6本回答被提问者和网友采纳
硬件实现IIC协议读取EEPROM
我TMD也是服了,反正我板子搞了半天也不成功我也不知道为什么,野火STM32-MINI,一直卡EV5,不管了 先代码沾上
串口相关代码:
bsp_usart.h
#ifndef __USART_H #define __USART_H #include "stm32f10x.h" #include <stdio.h> /** * 串口宏定义,不同的串口挂载的总线和IO不一样,移植时需要修改这几个宏 * 1-修改总线时钟的宏,uart1挂载到apb2总线,其他uart挂载到apb1总线 * 2-修改GPIO的宏 */ // 串口1-USART1 #define DEBUG_USARTx USART1 #define DEBUG_USART_CLK RCC_APB2Periph_USART1 #define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd #define DEBUG_USART_BAUDRATE 115200 // USART GPIO 引脚宏定义 #define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA) #define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd #define DEBUG_USART_TX_GPIO_PORT GPIOA #define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9 #define DEBUG_USART_RX_GPIO_PORT GPIOA #define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10 #define DEBUG_USART_IRQ USART1_IRQn #define DEBUG_USART_IRQHandler USART1_IRQHandler void USART_Config(void); #endif /* __USART_H */
bsp_usart.c
#include "./usart/bsp_usart.h" /** * @brief USART GPIO 配置,工作参数配置 * @param 无 * @retval 无 */ void USART_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; // 打开串口GPIO的时钟 DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE); // 打开串口外设的时钟 DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE); // 将USART Tx的GPIO配置为推挽复用模式 GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure); // 将USART Rx的GPIO配置为浮空输入模式 GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure); // 配置串口的工作参数 // 配置波特率 USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE; // 配置 针数据字长 USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 配置停止位 USART_InitStructure.USART_StopBits = USART_StopBits_1; // 配置校验位 USART_InitStructure.USART_Parity = USART_Parity_No ; // 配置硬件流控制 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 配置工作模式,收发一起 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 完成串口的初始化配置 USART_Init(DEBUG_USARTx, &USART_InitStructure); // 使能串口 USART_Cmd(DEBUG_USARTx, ENABLE); } ///重定向c库函数printf到串口,重定向后可使用printf函数 int fputc(int ch, FILE *f) { /* 发送一个字节数据到串口 */ USART_SendData(DEBUG_USARTx, (uint8_t) ch); /* 等待发送完毕 */ while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET); return (ch); } ///重定向c库函数scanf到串口,重写向后可使用scanf、getchar等函数 int fgetc(FILE *f) { /* 等待串口输入数据 */ while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET); return (int)USART_ReceiveData(DEBUG_USARTx); }
bsp_i2c_ee.h
#ifndef __I2C_EE_H #define __I2C_EE_H #include "stm32f10x.h" #include "bsp_usart.h" #define EEPROM_ADDR 0xA0 void I2C_EE_Config(void); void EEPROM_Byte_Write(uint8_t addr,uint8_t data); void EEPROM_Page_Write(uint8_t addr,uint8_t *data,uint8_t numByteToWrite); void EEPROM_Read(uint8_t addr,uint8_t *data,uint8_t numByteToRead); void EEPROM_WaitForWriteEnd(void); #endif /* __I2C_EE_H */
bsp_i2c_ee.c
#include "bsp_i2c_ee.h" void I2C_EE_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; I2C_InitTypeDef I2C_InitStructure; // 打开IIC GPIO的时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); // 打开IIC 外设的时钟 RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); // 将IIC SCL SDA的GPIO配置为推挽复用模式 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); // 配置IIC的工作参数 I2C_InitStructure.I2C_Ack = I2C_Ack_Enable ;//使能应答 I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit ;//使用7位地址模式 I2C_InitStructure.I2C_ClockSpeed = 400000; //配置SCL时钟频率 I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2 ; I2C_InitStructure.I2C_Mode = I2C_Mode_I2C ; I2C_InitStructure.I2C_OwnAddress1 = 0x5f; //这是STM32 IIC自身设备地址,只要是总线上唯一即可 I2C_Init(I2C1,&I2C_InitStructure); // 使能串口 I2C_Cmd (I2C1, ENABLE); } //向EEPROM写入一个字节 void EEPROM_Byte_Write(uint8_t addr,uint8_t data) { //产生起始信号 I2C_GenerateSTART(I2C1,ENABLE); while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT) == ERROR); //EV5事件被检测到,发送设备地址 I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Direction_Transmitter); while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ) == ERROR); //EV6事件被检测到,发送要操作的存储单元地址 I2C_SendData (I2C1,addr); while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTING ) == ERROR); //EV8事件被检测到,发送要存储的数据 I2C_SendData (I2C1,data); while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED ) == ERROR); //数据传输完成 I2C_GenerateSTOP(I2C1,ENABLE); } //向EEPROM写入多个字节(页写入),每次写入不能超过8个字节 void EEPROM_Page_Write(uint8_t addr,uint8_t *data,uint8_t numByteToWrite) { //产生起始信号 I2C_GenerateSTART(I2C1,ENABLE); while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT) == ERROR); //EV5事件被检测到,发送设备地址 I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Direction_Transmitter); while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ) == ERROR); //EV6事件被检测到,发送要操作的存储单元地址 I2C_SendData (I2C1,addr); while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTING ) == ERROR); while(numByteToWrite) { //EV8事件被检测到,发送要存储的数据 I2C_SendData (I2C1,*data); while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTED ) == ERROR); data++; numByteToWrite--; } //数据传输完成 I2C_GenerateSTOP(I2C1,ENABLE); } //从EEPROM读取数据 void EEPROM_Read(uint8_t addr,uint8_t *data,uint8_t numByteToRead) { //产生起始信号 I2C_GenerateSTART(I2C1,ENABLE); while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT) == ERROR); //EV5事件被检测到,发送设备地址 I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Direction_Transmitter); while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED ) == ERROR); //EV6事件被检测到,发送要操作的存储单元地址 I2C_SendData (I2C1,addr); while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_TRANSMITTING ) == ERROR); //第二次起始信号 //产生起始信号 I2C_GenerateSTART(I2C1,ENABLE); while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_MODE_SELECT) == ERROR); //EV5事件被检测到,发送设备地址 I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Direction_Receiver); while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED ) == ERROR); while(numByteToRead) { if(numByteToRead == 1) { //如果为最后一个字节 I2C_AcknowledgeConfig (I2C1,DISABLE); } //EV7事件被检测到 while(I2C_CheckEvent(I2C1,I2C_EVENT_MASTER_BYTE_RECEIVED ) == ERROR); //EV7事件被检测到,即数据寄存器有新的有效数据 *data = I2C_ReceiveData(I2C1); data++; numByteToRead--; } //数据传输完成 I2C_GenerateSTOP(I2C1,ENABLE); //重新配置ACK使能,以便下次通讯 I2C_AcknowledgeConfig (I2C1,ENABLE); } //等待EEPROM内部时序完成 void EEPROM_WaitForWriteEnd(void) { do { //产生起始信号 I2C_GenerateSTART(I2C1,ENABLE); while(I2C_GetFlagStatus (I2C1,I2C_FLAG_SB) == RESET); //EV5事件被检测到,发送设备地址 I2C_Send7bitAddress(I2C1,EEPROM_ADDR,I2C_Direction_Transmitter); } while(I2C_GetFlagStatus (I2C1,I2C_FLAG_ADDR) == RESET ); //EEPROM内部时序完成传输完成 I2C_GenerateSTOP(I2C1,ENABLE); }
main.c
#include "stm32f10x.h" #include "./usart/bsp_usart.h" #include "./i2c/bsp_i2c_ee.h" uint8_t readData[10]={0}; uint8_t writeData[8]={4,5,6,7,8,9,10,11}; /** * @brief 主函数 * @param 无 * @retval 无 */ int main(void) { uint8_t i=0; USART_Config(); printf("这是一个IIC通讯实验\\n"); I2C_EE_Config(); //向 EEPROM 11地址写入0x55, EEPROM_Byte_Write(11,0x55); EEPROM_WaitForWriteEnd(); //读出 EEPROM 11地址的内容,保存到readData中(数组的第一个址位) EEPROM_Read(11,readData,1); printf("%x",readData[0]); //addr%8 == 0 ,即为地址对齐 EEPROM_Page_Write(16,writeData,8); //等待写入操作完成 EEPROM_WaitForWriteEnd(); //读取数据 EEPROM_Read(16,readData,8); for(i=0;i<8;i++) { printf("%d ",readData[i]); } while(1); } /*********************************************END OF FILE**********************/
以上是关于求教STM32硬件I2C EV5和EV6错误问题的主要内容,如果未能解决你的问题,请参考以下文章