IIC--主从机的中断收发

一,简介:

        I2C(IIC)属于两线式串行总线,由飞利浦公司开发用于微控制器(单片机)和外围设备 (从设备)进行通信的一种总线,属于一主多从(一个主设备 (主设备),

多个从设备 (从设备))的总线结构,总线上的每个设备都有一个特定的设备地址,以区分同一12C总线上的其他设备。


物理I2C接口有两根双向线,串行时钟线 (SCL)和串行数据线 (SDA)组成,可用于发送和接收数据,但是通信都是由主设备发起,从设备被动响应,实现数据的传输。

本节主要介绍IIC的主发,主收,从发,从收。由于基本收发例程均存在,所以本节全部采用中断的方式实现!

二,I2C主设备与从设备的一般通信过程:
主设备给从设备发送/写入数据
1.主设备发送起始(START) 信号
2.主设备发送设备地址到从设备
3.等待从设备响应(ACK)
4.主设备发送数据到从设备,一般发送的每个字节数据后会跟着等待接收来自从设备的响应(ACK)
5.数据发送完毕,主设备发送停止(STOP)信号终止传输

主设备从从设备接收/读取数据
1.设备发送起始 (START) 信号
2.主设备发送设备地址到从设备
3.等待从设备响应(ACK)
4.主设备接收来自从设备的数据,一般接收的每个字节数据后会跟着向从设备发送一个响应(ACK)
5.一般接收到最后一个数据后会发送一个无效响应(NACK),然后主设备发送停止(STOP)信号终止传输

 三,代码实现

1,主发从收

( IIC初始化基础配置参考我们IIC例程即可 )

    1.1主中断发:

            中断前主机需要先产生起始位:

I2C_GenerateSTART(I2C1, ENABLE);

              中断配置:

void iic_int()
{
    NVIC_InitTypeDef NVIC_InitStructure;
    /* 中断分组初始化 */
    NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;  //中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;   //抢占优先级
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  //子优先级
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init( &NVIC_InitStructure );
   
    I2C_ITConfig( I2C1, I2C_IT_BUF, ENABLE );   //使能中断
    I2C_ITConfig( I2C1, I2C_IT_EVT, ENABLE );   //使能中断

}

             中断服务函数:


void I2C1_EV_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void I2C1_EV_IRQHandler(void )
{
    if( I2C_GetITStatus( I2C1, I2C_IT_SB ) != RESET )//起始位发送标志位
      {
           I2C_Send7bitAddress( I2C1, 0x02, I2C_Direction_Transmitter );
          ((void)(I2C1->STAR1));
          ((void)(I2C1->STAR2));
      }
    if( I2C_GetITStatus( I2C1, I2C_IT_ADDR ) != RESET )//地址匹配
    {
        ((void)(I2C1->STAR1));
        ((void)(I2C1->STAR2));
    }
    if( I2C_GetITStatus( I2C1, I2C_IT_TXE ) != RESET )
      {
            if(master_send_len<6){
                I2C_SendData( I2C1, TxData[master_send_len] );
                master_send_len++;
            }
            else{
                I2C_GenerateSTOP(I2C1, ENABLE);//再次进入TX中断后产生停止位,结束通信
            }
        ((void)(I2C1->STAR1));
        ((void)(I2C1->STAR2));
      }
}

    1.2从中断收:

           中断配置:和上面主机相同。

          中断服务函数:

void I2C1_EV_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void I2C1_EV_IRQHandler(void )
{
    if( I2C_GetITStatus( I2C1, I2C_IT_ADDR ) != RESET )
    {
            printf( "ADDR\r\n" );
            ((void)(I2C1->STAR1));
            ((void)(I2C1->STAR2));
    }
    else if( I2C_GetITStatus( I2C1, I2C_IT_RXNE ) != RESET )
   {
           RxData[slave_recv_len] = I2C1->DATAR;
           slave_recv_len++;
           if (slave_recv_len==6) {
               slave_recv_len=0;
        }
           ((void)(I2C1->STAR1));
           ((void)(I2C1->STAR2));
   }
    else if( I2C_GetITStatus( I2C1, I2C_IT_STOPF ) != RESET )
   {
       slave_state = 0xff;
       I2C1->CTLR1 &= I2C1->CTLR1;
       ((void)(I2C1->STAR1));  //读SR1寄存器
   }
}

 

2,主收从发

    2.1主中断收:

         中断配置:和上面相同

         中断服务函数:

void I2C1_EV_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void I2C1_EV_IRQHandler(void )
{
    if( I2C_GetITStatus( I2C1, I2C_IT_SB ) != RESET )//起始位发送标志位
      {

          I2C_Send7bitAddress( I2C1, 0x02, I2C_Direction_Receiver );//置主机为接收状态
          ((void)(I2C1->STAR1));
          ((void)(I2C1->STAR2));
      }

    if( I2C_GetITStatus( I2C1, I2C_IT_ADDR ) != RESET )//地址匹配
    {
        ((void)(I2C1->STAR1));
        ((void)(I2C1->STAR2));
    }
     if( I2C_GetITStatus( I2C1, I2C_IT_BTF ) != RESET )
       {

           I2C_ReadRegister( I2C1, I2C_Register_STAR1);
           ((void)I2C1->DATAR);
       }
    if( I2C_GetITStatus( I2C1, I2C_IT_RXNE ) != RESET )
       {
               if(master_recv_len<6){
                   mastr_RxData[master_recv_len] = I2C1->DATAR;
                   master_recv_len++;
               }
               if (master_recv_len==5) {//发六个数据要在第五位时就要发停止位,也就是需要提前停止
                                  I2C_GenerateSTOP( I2C1, ENABLE );   //产生停止条件
                                  I2C_NACKPositionConfig(I2C1, I2C_NACKPosition_Next);
                                                  }
               if(master_recv_len==6){
                   master_sate=0xff;
            }
          ((void)(I2C1->STAR1));
          ((void)(I2C1->STAR2));
       }
}

 

    2.2从中断发:

          中断使能:和上面相同

         中断服务函数:

void I2C1_EV_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void I2C1_EV_IRQHandler(void )
{
    if( I2C_GetITStatus( I2C1, I2C_IT_ADDR ) != RESET )
    {
            ((void)(I2C1->STAR1));
            ((void)(I2C1->STAR2));
    }
    else if( I2C_GetITStatus( I2C1, I2C_IT_BTF ) != RESET )
       {
           I2C_ReadRegister( I2C1, I2C_Register_STAR1);
           ((void)I2C1->DATAR);
       }
   else if( I2C_GetITStatus( I2C1, I2C_IT_TXE ) != RESET )
     {            
                  I2C_SendData( I2C1, TxData[slave_send_len] );
                  slave_send_len++;
                  if (slave_send_len==7) {//会进七次中断,虽然收六个数据,但也是要再第七次再清零
                  slave_send_len=0;
                }
      ((void)(I2C1->STAR1));
      ((void)(I2C1->STAR2));
     }
   else if( I2C_GetITStatus( I2C1, I2C_IT_STOPF ) != RESET )
      {
          I2C1->CTLR1 &= I2C1->CTLR1;
          ((void)(I2C1->STAR1));  //读SR1寄存器
      }
}

如果移植测试不成功,可留言留下你的邮箱,将源码发你这边!

posted @ 2023-12-22 15:26  WCH_CH32  阅读(1491)  评论(0编辑  收藏  举报