本帖最后由 vrxiaochouyu 于 2018-9-11 15:18 编辑 现象: 1,有时有应答,有时没有应答。(具体情况是,开机第一次显示未应答,然后报超时错误。第二次直接卡死,如图所示。等了15分钟之后报了遇忙错误。第三次,就真的卡死了。SLC一直为低,程序一点反应都没有) 2,有应答时,写入时时钟不见了。把主设备复位之后,SCL还是低的。为什么会把SCL拉低呢? i2c即当主又当从。 做主的时候是给E2写数据,已经实现了,没出问题,可以排除硬件问题。 做从的时候是从芯片(另外一个芯片,该设备没有从模式)接收数据。难道是主从需要切换设置(轮巡代码里有设置模式啊)?还是因为STM32自身I2C BUG所致(从网上找了修改HAL_I2C_MspInit函数BUG的代码,然并卵)? (更新)已从下面这篇文章解决卡死问题(并未根除,还偶尔卡死,但是概率低了很多)。但是还是没有应答。 解决STM32 I2C接口死锁在BUSY状态的方法讨论 然后波形是这样(PS:超时改为1,如果超时为100,依然是卡死) 如果超时改为0,会是这样。这个后边的两个脉冲是怎么来的,难道是强制结束? 我又使了地址全为0,还是一样。 (更新)已解决地址问题,原因是I2C信号太快了。读的信号是从第二个脉冲才开始的,所以永远都是错的。但还是有卡死问题。经常SCL就莫名的拉低了。貌似是和最开始差不多。最后截止的时候不应该给应答信号。但是应该如何解决呢? “6,当Master速度过快Slave端来不及处理时,Slave设备可以拉低SCL不放(SCL=0将发生“线与”)以阻止Master发送更多的数据。此时Master将视情况减慢或结束数据传送。”难道和这个有关? (更新)已解决,但是很崩溃。STM32一直在发应答。不发停止。如果size小于主机发的数量,就会卡死。只有遇到主机发停止,才会停止。自己不会停止。收不到停止就一直等啊等,就卡死了。 static void MX_I2C2_Init(void) { hi2c2.Instance = I2C2; hi2c2.Init.ClockSpeed = 100000; hi2c2.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c2.Init.OwnAddress1 = 0xa0;//地址是A0 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__); } } temp=UserRxBufferFS[i+1];//USB接收指令 HAL_UART_Transmit(&huart2,(uint8_t *)&temp,1,1000);//UART发送指令 if( HAL_I2C_Slave_Receive(&hi2c2, i2cdata, 10, 100)== HAL_OK); //i2c接收数据 while( CDC_Transmit_FS(i2cdata,10) != USBD_OK );//USB返回数据 我自己又写了一个模拟的I2C从设备。有时报地址错误(a0变为4B),有时地址对了,但是没有给应答信号(报09错误,即没有收到第10个SLC)。求大神指正。int I2C_slave() { GPIO_InitTypeDef GPIO_InitStruct; uint32_t i,j=0; uint8_t data, temp,stop; //I2C_SDA_1; //释放SDA //SDA设为输入 GPIO_InitStruct.Pin = GPIO_PIN_5|GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); i=0; while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7)==1) { i++; if (i >=0xffff) {i=0;return 3;};};//start for ( i=0; i<8; i++ ) { while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==1) { i++;if (i >=0xffff) {i=0;return 4;}; }; while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==0) {i++;if (i >=0xffff) {i=0;return 5;};}; temp= HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7); data=data<<1; data=data|temp; } if( data!=0xa0) {if (data==0)return 15; else { return data;//ID } }; GPIO_InitStruct.Pin = GPIO_PIN_7; //SDA设为输出 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==1) { i++;if (i >=0xffff) {i=0;return 6;}; }; I2C_SDA_0;//ack while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==0) {i++;if (i >=0xffff) {i=0;return 7;};}; while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==1) { i++;if (i >=0xffff) {i=0;return 8;}; }; GPIO_InitStruct.Pin =GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; // GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); while(1) { while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==0) {i++;if (i >=0xffff) {i=0;return 9;};}; temp= HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7); if (temp==0) { while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==1) {i++;if (i >=0xffff) {i=0;return 10;};}; stop= HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7); if (stop==1){return 0;}//stop } data=data<<1; data=data|temp; for ( i=0; i<7; i++ ) { while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==0) {i++;if (i >=0xffff) {i=0;return 11;};}; temp= HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_7); data=data<<1; data=data|temp; while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==1) { i++;if (i >=0xffff) {i=0;return 12;}; }; } i2cdata[j] =data; j++; if(j>63)return 2;//over GPIO_InitStruct.Pin = GPIO_PIN_7; //SDA设为输出 GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); I2C_SDA_0; //ack while(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==0) {i++;if (i >=0xffff) {i=0;return 13;};}; while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5)==1) { i++;if (i >=0xffff) {i=0;return 14;}; }; GPIO_InitStruct.Pin =GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; // GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } } |
评分
查看全部评分
评分
查看全部评分
问题有歧义,稍作了更改。问题应该是,时钟后来怎么没了。写地址的时候还在,为什么写数据的时候就没了。
问题的重点不在于谁发的时钟,而在于时钟怎么自己没了。SCL被强制拉低了。程序卡死了。
SCL被强制拉低,有可能是从机。。。因为从机的scl的IO口配置必须是高阻态输入,也就是说,不能拉低。。。否则主机也没法输出高电平!!!
那么是代码哪里的问题,如何解决呢?用的是CUBE生成的代码呢
那应该是从设备的应答信号失败,主设备接收不到应答信号,自然没有读操作,时钟消失。
评分
查看全部评分
我一般不用ST的硬I2C。。。也没搞过I2C从机模式!!!如果是用Cube生成的代码,应该说配置是没问题的。。。
评分
查看全部评分
但是从逻辑分析仪上看,已经给了应答信号了