最近在捣鼓stm32f0的IIC从机,之前一直使用的是IIC主机,IIC主机主要用的是IO口模拟的,实现起来没什么问题。但是转到IIC从机后,发现通信读取数据过程中偶尔会出现串码的现象,大概一小时会出现两三次。以下是IIC从机的部分代码: /*-- defined -----------------------------------------------------------------*/ #define SLAVE_ADDR 0x16 #define POLYNOME 0x07 #define I2C_REC_BYTES 64 #define I2C_TX_BYTES 64 /*-- private variables -------------------------------------------------------*/ static I2C_HandleTypeDef hi2c1; static u8_t slaveTxBuff[I2C_TX_BYTES] = {0}; static u8_t slaveRxBuff[I2C_REC_BYTES] = {0}; static u8_t rsoc; static u16_t battVolt; static s16_t current; static u16_t Temper; static u16_t cellVolt[3]; /*-- functions ---------------------------------------------------------------*/ static void tx_match(u8_t cmd); /**@brief * @brief IIC初始化 * @param * @return */ void hal_iic_init(void) { u32_t tmpisr = 0; /* Peripheral clock enable */ __HAL_RCC_I2C1_CLK_ENABLE(); hi2c1.Instance = I2C1; hi2c1.Init.Timing = 0x2000090E; hi2c1.Init.OwnAddress1 = SLAVE_ADDR; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.OwnAddress2Masks = I2C_OA2_NOMASK; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_ENABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) { } /* Configure Analogue filter */ if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK) { } /* Configure Digital filter */ if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK) { } /* I2C1 interrupt Init */ HAL_NVIC_SetPriority(I2C1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(I2C1_IRQn); /** I2C_IT_ADDRI: Address match interrupt. I2C_IT_STOPI: STOP detection interrupt. I2C_IT_NACKI: NACK received interrupt. I2C_IT_ERRI: Errors interrupt. I2C_IT_TCI: TC interrupt. I2C_XFER_RX_IT: REC interrupt. */ tmpisr |= I2C_IT_ADDRI | I2C_IT_STOPI | I2C_IT_NACKI | I2C_IT_ERRI | I2C_IT_RXI | I2C_IT_TXI; __HAL_I2C_ENABLE_IT(&hi2c1, tmpisr); } /**@brief * @brief * @param * @return */ void i2c_err_irq_handler(I2C_HandleTypeDef *hi2c, u32_t isrFlag) { if((isrFlag & I2C_FLAG_ARLO) == I2C_FLAG_ARLO) { /* ARLO Err */ __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ARLO); } if((isrFlag & I2C_FLAG_BERR) == I2C_FLAG_BERR) { /* BERR Err */ __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_BERR); } if((isrFlag & I2C_FLAG_OVR) == I2C_FLAG_OVR) { /* OVR Err */ __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_OVR); } } /**@brief * @brief * @param * @return */ void i2c_evt_irq_handler(I2C_HandleTypeDef *hi2c, u32_t isrFlag) { static u8_t txCounter = 0; static u8_t rxCounter = 0; u32_t transferDir = 0; if(hi2c->Instance == hi2c1.Instance) { if((isrFlag & I2C_FLAG_ADDR) == I2C_FLAG_ADDR) { /* EV1 */ transferDir = isrFlag & I2C_ISR_DIR; /* 判断方向 */ if(transferDir) { /* 方向为从机发送 */ I2C1->ISR |= I2C_ISR_TXE; I2C1->TXDR = slaveTxBuff[0]; txCounter = 1; } else { /* 方向为从机接收 */ rxCounter = 0; } __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_ADDR); } else if((isrFlag & I2C_FLAG_TXIS) == I2C_FLAG_TXIS) { /* EV3 */ I2C1->TXDR = slaveTxBuff[txCounter++]; } else if((isrFlag & I2C_FLAG_RXNE) == I2C_FLAG_RXNE) { /* EV2 */ if(rxCounter < I2C_REC_BYTES) { slaveRxBuff[rxCounter] = hi2c->Instance->RXDR; /* 进行命令匹配 */ if(rxCounter == 0) { tx_match(slaveRxBuff[0]); } rxCounter++; } } else if((isrFlag & I2C_FLAG_STOPF) == I2C_FLAG_STOPF) { /* EV4 */ hi2c->Instance->ISR |= I2C_ISR_TXE; hi2c->Instance->ISR |= I2C_ISR_TXIS; txCounter = 0; rxCounter = 0; __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_STOPF); } else if((isrFlag & I2C_FLAG_AF) == I2C_FLAG_AF) { /* EV3_2 */ __HAL_I2C_CLEAR_FLAG(hi2c, I2C_FLAG_AF); } } } /** * @brief This function handles I2C1 global interrupt. * @param * @param * @return */ void I2C1_IRQHandler(void) { u32_t isrFlag = 0; isrFlag = hi2c1.Instance->ISR; if (isrFlag & (I2C_FLAG_BERR | I2C_FLAG_ARLO | I2C_FLAG_OVR)) { /* 异常处理 */ //HAL_I2C_ER_IRQHandler(&hi2c1); i2c_err_irq_handler(&hi2c1, isrFlag); } else { /* 事件处理 */ //HAL_I2C_EV_IRQHandler(&hi2c1); i2c_evt_irq_handler(&hi2c1, isrFlag); } } /** @function * @brief IIC从机匹配发送数据,发现如果使用switch-case出错率会更高,不知为何。 * @param * @return */ static void tx_match(u8_t cmd) { u8_t counter = 0; if(cmd == 0x08) { slaveTxBuff[counter++] = Temper&0x00ff; slaveTxBuff[counter++] = (Temper&0xff00)>>8; Temper++; } else if(cmd == 0x09) { slaveTxBuff[counter++] = battVolt&0x00ff; slaveTxBuff[counter++] = (battVolt&0xff00)>>8; battVolt++; } else if(cmd == 0x0A) { slaveTxBuff[counter++] = current&0x00ff; slaveTxBuff[counter++] = (current&0xff00)>>8; } else if(cmd == 0x0D) { slaveTxBuff[counter++] = rsoc&0x00ff; slaveTxBuff[counter++] = (rsoc&0xff00)>>8; } else if(cmd == 0x3F) { slaveTxBuff[counter++] = cellVolt[0]&0x00ff; slaveTxBuff[counter++] = (cellVolt[0]&0xff00)>>8; } else if(cmd == 0x3E) { slaveTxBuff[counter++] = cellVolt[1]&0x00ff; slaveTxBuff[counter++] = (cellVolt[1]&0xff00)>>8; } else if(cmd == 0x3D) { slaveTxBuff[counter++] = cellVolt[2]&0x00ff; slaveTxBuff[counter++] = (cellVolt[2]&0xff00)>>8; } slaveTxBuff[counter] = CRC8(slaveTxBuff, counter, POLYNOME); } 可能是因为本人对IIC从机原理理解得不够深,折腾了两天还是没什么进展,望由此经验的朋友多多指教,谢谢! |
我把IIC从机中断优先级调整为最高级,经过几个小时的测试,数据一次都没有出错过,暂时认定为是其他中断影响了IIC从机中断的发送。 |