[STM32F0]

基于HAL库做的I2C从机通信?从机发的第一个字节错误

[复制链接]
1344|14
手机看帖
扫描二维码
随时随地手机跟帖
hzocce|  楼主 | 2020-4-23 21:12 | 显示全部楼层 |阅读模式
本帖最后由 hzocce 于 2020-5-4 07:14 编辑

一直不晓得I2C中断是拿来做什么的。

因为基本I2C都是主机是使用,不是使用E2PROM 就是一些传感器,直接配置他们,读取他们的数值便可。

后面想到I2C中断应该是作为从机的时候使用,因为不知道主机啥时候发信息过来,所以需要用到I2C的中断接收。
可是怎么使用他们的I2C中断接收?
在中断服务函数放些什么内容?

使用特权

评论回复
hzocce|  楼主 | 2020-4-25 14:51 | 显示全部楼层
?
调不通。

使用特权

评论回复
hzocce|  楼主 | 2020-4-26 10:39 | 显示全部楼层
有人测试过么?

使用特权

评论回复
香水城| | 2020-4-26 11:14 | 显示全部楼层
你可以到www.st.com/stm32 搜索下载STM32CubeF0固件包,里面有例程你可以试试学习、调试。
\Repository\STM32Cube_FW_F0_V1.11.0\Projects\STM32F030R8-Nucleo\Examples\I2C

使用特权

评论回复
hzocce|  楼主 | 2020-4-26 17:23 | 显示全部楼层
下载了,没有看懂,我也将范例下载到板子上面了,然后用USB-I2C工具去访问那个I2C地址,发现仍然没有应答。

范例上面也需要按键触发主机发送命令的,我也用了,仍然没有见到主机发送I2C命令。

所以才没有办法,主机用CUBEMX 生产初始化代码,仍然没有应答。

就是发现在CUBEMX里面设置好的地址,比如里面是0x07,实际在代码上面就是0x0e了。
0111 变成了1110 变左移了1位。。

其他尝试了好几天无果。

使用特权

评论回复
hzocce|  楼主 | 2020-4-26 17:23 | 显示全部楼层
香水城 发表于 2020-4-26 11:14
你可以到www.st.com/stm32 搜索下载STM32CubeF0固件包,里面有例程你可以试试学习、调试。
\Repository\STM ...

测试过了,不通的。

使用特权

评论回复
hzocce|  楼主 | 2020-4-27 11:24 | 显示全部楼层
这样配置,有误?
用USB-I2C工具去测试,无论如何更改配置,MCU都无法产生ACK信号
SMBusCfg.png

使用特权

评论回复
hzocce|  楼主 | 2020-4-29 09:35 | 显示全部楼层
本帖最后由 hzocce 于 2020-4-29 10:12 编辑

// 中断如下。

void I2C1_IRQHandler(void)
{
  /* USER CODE BEGIN I2C1_IRQn 0 */
Flag=1;
  /* USER CODE END I2C1_IRQn 0 */
  if (hi2c1.Instance->ISR & (I2C_FLAG_BERR | I2C_FLAG_ARLO | I2C_FLAG_OVR)) {
    HAL_I2C_ER_IRQHandler(&hi2c1);
  } else {
    HAL_I2C_EV_IRQHandler(&hi2c1);
  }
  /* USER CODE BEGIN I2C1_IRQn 1 */

  /* USER CODE END I2C1_IRQn 1 */
}



//I2C初始化
void MX_I2C1_Init(void)
{

  hi2c1.Instance = I2C1;
  hi2c1.Init.Timing = 0x2000090E;
  hi2c1.Init.OwnAddress1 = 16;
  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_DISABLE;
  if (HAL_I2C_Init(&hi2c1) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Analogue filter
  */
  if (HAL_I2CEx_ConfigAnalogFilter(&hi2c1, I2C_ANALOGFILTER_ENABLE) != HAL_OK)
  {
    Error_Handler();
  }
  /** Configure Digital filter
  */
  if (HAL_I2CEx_ConfigDigitalFilter(&hi2c1, 0) != HAL_OK)
  {
    Error_Handler();
  }

}

空闲的时候SCL,SDA都为高电平。

发现只要用ox10的地址去写,SDA线还好,正常的电平为高。
SCL就一直是低的,只要把板子掉电才可以恢复为高。

怎么解呢?

应该是地址是匹配到了,但是为什么SCL一直为低了,说明了什么问题
如何进行下一步??

初始化的地址是0x10,这个地址去操作,SCL 就别拉低了。
但是如果用0x10之外的地址去操作, 总线正常的。怎么回事?

使用特权

评论回复
hzocce|  楼主 | 2020-4-29 18:00 | 显示全部楼层
主机发写命令后,是有进到中断的,测试LED灯已经点亮,就是SCL线一直为低,无法恢复,怎么处理?
I2C中断.png

使用特权

评论回复
kingkits| | 2020-4-29 19:14 | 显示全部楼层
I2C的中断服务应该至少有2个

使用特权

评论回复
hzocce|  楼主 | 2020-4-30 09:50 | 显示全部楼层
kingkits 发表于 2020-4-29 19:14
I2C的中断服务应该至少有2个

啥意思?不懂,能说明白一点么?

使用特权

评论回复
kingkits| | 2020-5-1 21:07 | 显示全部楼层
本帖最后由 kingkits 于 2020-5-1 21:08 编辑

I2c有个状态中断,依据不同的状态,其操作不一样

使用特权

评论回复
kingkits| | 2020-5-1 21:17 | 显示全部楼层
void  I2C1_ER_IRQHandler(void){
        if (I2C_GetFlagStatus(I2C1, I2C_FLAG_AF))        {
                I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF, DISABLE);
                 I2C_ClearFlag(I2C1, I2C_FLAG_AF);
                 Message.status = I2C_STATUS_ERR;
        }
        if (I2C_GetFlagStatus(I2C1, I2C_FLAG_BERR))        {
                I2C_ClearFlag(I2C1, I2C_FLAG_BERR);
        }
        if (I2C_GetFlagStatus(I2C1, I2C_FLAG_OVR))        {
                I2C_ClearFlag(I2C1, I2C_FLAG_OVR);
        }
        if (I2C_GetFlagStatus(I2C1, I2C_FLAG_ARLO))
        {
                I2C_ClearFlag(I2C1, I2C_FLAG_ARLO);
        }
}
   
void I2C1_EV_IRQHandler(){
        uint16_t SR1;
        uint16_t SR2;
         SR1 = I2C1->SR1;
         // Start bit event
        if (SR1 & I2C_SR1_SB)        {
                if (Message.status == I2C_STATUS_START)                {
                        I2C_Send7bitAddress(I2C1, Message.slaveAddress << 1, I2C_Direction_Transmitter);//2
                        Message.status = I2C_STATUS_ADDRESS;
                }
                else if (Message.status == I2C_STATUS_START_R)                {
                        I2C_AcknowledgeConfig(I2C1, ENABLE);//5 转为读数据
                        I2C_Send7bitAddress(I2C1, Message.slaveAddress << 1, I2C_Direction_Receiver);
                        Message.status = I2C_STATUS_REDATA;
                }
        }
        else if (SR1 & I2C_SR1_ADDR)//地址传输完成        {
                SR2 = I2C1->SR2;
                 if (Message.status == I2C_STATUS_ADDRESS)//发送寄存器地址
                {
                        I2C_SendData(I2C1, Message.regAddress);//4 发送地址
                }
                if (Message.Length == 1)//只接受一个字节
                {
                        if (Message.status == I2C_STATUS_REDATA)
                        {
                                I2C_AcknowledgeConfig(I2C1, DISABLE);
                        }
                }
                 I2C_ITConfig(I2C1, I2C_IT_BUF, ENABLE);
            }
        else if (SR1 & I2C_SR1_BTF)        {                //4 上次传输完成
                 if (SR1&I2C_SR1_TXE)//发送完成
                {
                        if (Message.direction == i2cRead)//读数据
                        {
                                if (Message.status == I2C_STATUS_ADDRESS)//寄存器发送完
                                {
                                        I2C1->CR1 = (I2C_CR1_START | I2C_CR1_PE);//
                                        Message.status = I2C_STATUS_START_R;//启动读数据
                                }
                        }
                        else//写数据
                        {
                                I2C_SendData(I2C1, Message.buffer[Message.Index++]);
                                if (Message.Index == Message.Length)
                                {
                                        I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF, DISABLE);//关闭中断
                                        I2C1->CR1 = (I2C_CR1_STOP | I2C_CR1_PE);//后续测试是否添加
                                        Message.status = I2C_STATUS_FINSIH;
                                }
                        }
                }
        }
        if (SR1 & I2C_SR1_RXNE)
         {
                 Message.buffer[Message.Index++] = I2C_ReceiveData(I2C1);
                 if (Message.Index == Message.Length - 1)
                {
                        I2C_AcknowledgeConfig(I2C1, DISABLE);//末尾数据禁止应答
                }
                 if (Message.Index == Message.Length)
                {
                        I2C1->CR1 = (I2C_CR1_STOP | I2C_CR1_PE);//后续测试是否添加
                        I2C_ITConfig(I2C1, I2C_IT_EVT | I2C_IT_BUF, DISABLE);//接受结束
                        Message.status = I2C_STATUS_FINSIH
;                }
        }
        else if (SR1 & I2C_SR1_TXE)
        {
         }
}

仅供参考,网上有很多

使用特权

评论回复
hzocce|  楼主 | 2020-5-2 07:17 | 显示全部楼层
kingkits 发表于 2020-5-1 21:17
void  I2C1_ER_IRQHandler(void){
        if (I2C_GetFlagStatus(I2C1, I2C_FLAG_AF))        {
          ...

好,非常感谢这位兄弟的指导。

基于库不一样,很多时候都编译不了,一大推的错误,如何去看,接收的时候要关注哪些寄存器?

使用特权

评论回复
hzocce|  楼主 | 2020-5-3 20:47 | 显示全部楼层
本帖最后由 hzocce 于 2020-5-4 07:13 编辑

奇怪的,为什么用STM32作为I2C从机的时候,第一次发出的数据第一个字节总是是固定用0xFF(第二次被读访问后,则用的是上一次的最后一个数据),第二个发出的字节就是预先的第一个字节;第三个字节就是预想发送的第二个个字节(数据由逻辑分析仪得出);
是为什么?
0xff 0x11 0x22。。。。。
正确的应该是 0x11 0x22 0x33。。。。。
之后便是:0x33 0x11 0x22

是不是在哪个地方需要清理一下? 怎么清理??


请大师帮忙分析下,谢谢!

uint8_t User_RXBuffer[3]={0};//用于I2C从机被访问写时收数据
uint8_t User_TXBuffer[]={0x11,0x22,0x33};//用于I2C从机被访问读时候发出固定数

//以下是中断服务内容


if(__HAL_I2C_GET_FLAG(&hi2c1,I2C_ISR_ADDR)==SET)
{
  if(I2C1->ISR&I2C_ISR_DIR)
  {
   Tx_count=0;
   I2C1->ISR|=I2C_ISR_TXE;
   I2C1->ICR|=I2C_ICR_ADDRCF;
  }
  else
  {
   Rx_count=0;
   I2C1->ISR|=I2C_ISR_TXE;
   I2C1->ICR|=I2C_ICR_ADDRCF;
  }
}
else if(__HAL_I2C_GET_FLAG(&hi2c1,I2C_ISR_RXNE)==SET)
{
  User_RXBuffer[Rx_count++]=I2C1->RXDR;
}
else if(__HAL_I2C_GET_FLAG(&hi2c1,I2C_ISR_TXIS)==SET)
{
  I2C1->TXDR=User_TXBuffer[Tx_count++];
}
else if(__HAL_I2C_GET_FLAG(&hi2c1,I2C_ISR_STOPF)==SET)
{
  I2C1->ICR|=I2C_ICR_STOPCF;
  Rx_count=0;
  Tx_count=0;
}
else if(__HAL_I2C_GET_FLAG(&hi2c1,I2C_ISR_NACKF)==SET)
{
  I2C1->ICR|=I2C_ICR_NACKCF;
}
else if(__HAL_I2C_GET_FLAG(&hi2c1,I2C_ISR_ARLO)==SET)
{
  I2C1->ICR|=I2C_ICR_ARLOCF;
}
else if(__HAL_I2C_GET_FLAG(&hi2c1,I2C_ISR_BERR)==SET)
{
  I2C1->ICR|=I2C_ICR_BERRCF;
}
else if(__HAL_I2C_GET_FLAG(&hi2c1,I2C_ISR_OVR)==SET)
{
  I2C1->ICR|=I2C_ICR_OVRCF;

}

描述.png
IIC从机发送第一个字节错误.png

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

127

主题

561

帖子

4

粉丝