GD32F407之硬件IIC(从机模式)

本文介绍了GD32F407微控制器在硬件IIC模式下作为从机的配置和操作,包括从机接收和发送模式的软件流程、官方源码的解析与改进,以及中断函数的设置。强调了在整合接收和发送数据时要注意的标志位差异,并提供了接收和发送数据的处理函数示例。
摘要由CSDN通过智能技术生成

承接上一篇GD32F407硬件IIC主机模式,下面这一片介绍GD32F407硬件IIC从机模式,用MCU来做从机模式百度上有用的资源比较少,都是STM32里面的源码,千篇一律,有点水帖的感觉。

网上百度用GPIO模拟方式来做从机好像没有找到资料,也咨询了GD32F407的FE没有做过GPIO模拟从机,所以就用硬件方式来,官方源码这一次终于不是while结构了,而且官方还是IIC0做主机,IIC1从机的方式,真的太给力了。

1、从机接收模式下的软件流程

2、代码,官方源码从机发送模式

/*!
    \brief      handle I2C1 event interrupt request
    \param[in]  none
    \param[out] none
    \retval     none
*/
void I2C1_EventIRQ_Handler(void)
{
    if(i2c_flag_get(I2C1, I2C_ADDSEND)){
        /* clear the ADDSEND bit */
        i2c_flag_clear(I2C1, I2C_STAT0_ADDSEND);
    }else if((i2c_flag_get(I2C1, I2C_TBE))&&(!i2c_flag_get(I2C1, I2C_AERR))){
        /* send a data byte */
        i2c_transmit_data(I2C1, *i2c_txbuffer++);
    }
}

是不是感觉太少了,有点怀疑可行性啊,单独测试官方源码可以使用,但是拿到项目就不能用了,修改如下,加了一个清除ADDSEND bit后的标志,让它必须清除ADDSEND后才能下一步

void Si2c_Send_Data(uint32_t i2c_periph,BYTE Channel)
{
    /* wait until ADDSEND bit is set */
   if(i2c_flag_get(i2c_periph, I2C_ADDSEND)){
        ADDSEND_FLAG=1;
        /* clear ADDSEND bit */
        i2c_flag_clear(i2c_periph, I2C_ADDSEND);
    }       
    if(ADDSEND_FLAG){
        if(i2c_flag_get(i2c_periph, I2C_RBNE)){
            /*  reception data register  */
            SReceAddrBuffer[Channel] = i2c_receive_data(i2c_periph);
        }   
    }
}

也是很简单的

3、从机发送模式下的软件流程

4、从机发送模式代码,官方源码

*!
    \brief      handle I2C1 event interrupt request
    \param[in]  none
    \param[out] none
    \retval     none
*/
void I2C1_EventIRQ_Handler(void)
{
    if(i2c_flag_get(I2C1, I2C_ADDSEND)){
        /* clear the ADDSEND bit */
        i2c_flag_clear(I2C1, I2C_STAT0_ADDSEND);
    }else if(i2c_flag_get(I2C1, I2C_RBNE)){
        /* if reception data register is not empty ,I2C1 will read a data from I2C_DATA */
        *i2c_rxbuffer++ = i2c_receive_data(I2C1);
    }else if(i2c_flag_get(I2C1, I2C_STPDET)){
        Status = SUCCESS;
        /* clear the STPDET bit */
        i2c_enable(I2C1);
        /* disable I2C1 interrupt */
        i2c_interrupt_disable(I2C1, I2C_CTL1_ERRIE | I2C_CTL1_BUFIE | I2C_CTL1_EVIE);
    }
}

也是很简单,直接测试没有问题,

将发送和接收数据整合在一起,整合一定要注意接收和发送的标志位不同,

oid Si2c_Transfer_Data(uint32_t i2c_periph,BYTE Channel)
{
    /* wait until ADDSEND bit is set */
    if(i2c_flag_get(i2c_periph, I2C_ADDSEND)){
        ADDSEND_FLAG=1;
        /* clear ADDSEND bit */
        i2c_flag_clear(i2c_periph, I2C_ADDSEND);
    }
    if(ADDSEND_FLAG){
        if(i2c_flag_get(i2c_periph, I2C_RBNE) && (SRFalg ==0)){
            /*  Receive register  addr*/
            SReceAddrBuffer[Channel] = i2c_receive_data(i2c_periph);
            SRFalg = 1;
        }
        if(SReceAddrBuffer[Channel] != 0XFF){
            if(i2c_flag_get(i2c_periph, I2C_TBE)){
                /* Send a word data */
                MatchAdd_SendData(i2c_periph,SReceAddrBuffer[Channel]);
                ADDSEND_FLAG=0;
                SRFalg = 0;
            }

            if((SRFalg==1) && i2c_flag_get(i2c_periph, I2C_RBNE)){
                /*Receive a byte data */
                SReceDataBuffer[Channel] = i2c_receive_data(i2c_periph);
                MatchAdd_ReceData(SReceAddrBuffer[Channel],SReceDataBuffer[Channel]);
            }

            if(i2c_flag_get(i2c_periph, I2C_STPDET)){
                /* Receive mode clear the STPDET bit */
                ic20Flag = 2;
                SRFalg = 0;
                ADDSEND_FLAG=0;
                i2c_enable(i2c_periph);
                i2c_interrupt_disable(i2c_periph, I2C_CTL1_ERRIE | I2C_CTL1_BUFIE | I2C_CTL1_EVIE);
            }
            if(ic20Flag == 2){
                i2c_interrupt_enable(i2c_periph, I2C_CTL1_ERRIE | I2C_CTL1_BUFIE | I2C_CTL1_EVIE);
                ic20Flag = 0;
            }
        }
    }
}

注意:首先我们知道,,一般的IIC从设备都是有很多寄存器地址的,所以我们主机肯定也会发一个寄存器地址过来,官方源码里面是没有做处理的就当做(0x00),所以在整合的代码里面我有两次接收数据一个是寄存器地址放到地址数组和一个是数据放到了数据数组中。

5、接收发送处理函数

接收一个WORD数据

void MatchAdd_ReceData(BYTE Cmd,BYTE Data)
{ 
    if (Cmd == 0x02)
    {   /* Currently system power state. */
        PwrState.byte = Data;
    } 
    else if (Cmd == 0xB3)
    {   /* button event state */
        ButtState.byte = Data;
    }
    else if (Cmd == 0xB4)
    {   /* button event number */
        SCINumber = Data;
    }
        
    else if (Cmd == 0xB5)
    {  
        HeartBeatEnable = Data;
    } 
    else if (Cmd == 0xB6)
    {  
        HeartBeatTimer = Data;
    }
    else if (Cmd == 0xB7)
    {  
        HeartBeatFlag = Data;
    }
}

发送一个WORD数据

void MatchAdd_SendData(uint32_t i2c_periph ,BYTE Cmd)
{
    WORD rval = 0;
    WORD *pntr;
    if (Cmd == 0x02)
    {   /* Currently system power state. */
        rval = (WORD) PwrState.byte;
    } 
    else if (Cmd == 0xB3)
    {   /* button event state */
        rval = (WORD) ButtState.byte;
    }
    else if (Cmd == 0xB4)
    {   /* button sci event number */
        rval = (WORD) SCINumber;
    }

    i2c_transmit_worddata(i2c_periph,rval);
}

注意:接受和发送的寄存器其实是同一个地址,通俗说就是从机有一个0x00--0xFF的地址的寄存器来让主机读写

官方里面没有发送一个Word数据函数,修改如下

void i2c_transmit_worddata(uint32_t i2c_periph, uint16_t Data)
{
    /* send a data byte */
    I2C_DATA(i2c_periph) = Data;
    I2C_DATA(i2c_periph) = Data>>8;
}

6、中断函数

void I2C0_EV_IRQHandler(void)
{
    //DEBUG(0XAA);
    Si2c_Transfer_Data(I2C0,0);
}

到此GD32F407硬件IIC就结束了,其实硬件模式的从机还是比主机简单很多,主要是文档非常详细。

 

评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值