STM32F405 硬件I2C(SMBus)做从机与电脑通信,使用I2C中断收发

        首先I2C和SMBus是兼容的,亲测把初始化换成SMBus或者I2C都是可以通信的。

        这几天老师因为工控机上SMBus接口长得好看一点。。。。。。。所以非要我搞SMBus的通信。。。。。。。其实旁边就是UART接口,就是接线麻烦一点。

        反正他既然说了就搞呗,结果发现网上关于I2C用从机中断的资料巨少,就想着把代码po上来共享一下。

#include "IIC.h"
#include "delay.h"
#include "stm32f4xx_i2c.h"
#include "Exti.h"

//********接口定义*********************************************************//
//调用库函数将 
//程序代码如下:
//************************************************************************//

void IIC_Init(void)
{

    GPIO_InitTypeDef GPIO_InitStructure;                                              //GPIO 结构体定义
    I2C_InitTypeDef I2C_InitStructure;                                                //I2C 结构体定义
    NVIC_InitTypeDef NVIC_InitStructure;
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1,ENABLE);	                              //I2C 时钟使能
    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);
    //RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
    /* Configure and enable SI2CMASTER interrupt --------------------------------*/
    //RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, ENABLE);
    //RCC_APB1PeriphResetCmd(RCC_APB1Periph_I2C1, DISABLE);

    //*I2C1-模式 配置*//

    I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;                                        //选择I2C功能
    I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;                                       //I2C应答使能
    I2C_InitStructure.I2C_ClockSpeed = 400000;                                        //时钟速率,以 HZ 为单位的,最高为 400khz
    I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;                                //该参数只有在 I2C 工作在快速模式(时钟工作频率高于 100KHz)下才有意义
    I2C_InitStructure.I2C_OwnAddress1 =0x30;                                          //设置第一个设备自身地址
    I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;         //
    I2C_Init(I2C1, &I2C_InitStructure);                                               //初始化结构体配置

// IIC_SCL=1;
// IIC_SDA=1;


    /* 1 bit for pre-emption priority, 3 bits for subpriority */
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
    /* Configure and enable I2CMASTER interrupt --------------------------------*/
    NVIC_InitStructure.NVIC_IRQChannel = I2C1_EV_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority =0x01;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority =0x01;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    //*I2C1-IO 口配置*//
    //使能GPIOB时钟

    GPIO_PinAFConfig(GPIOB, GPIO_PinSource6, GPIO_AF_I2C1);
    GPIO_PinAFConfig(GPIOB, GPIO_PinSource7, GPIO_AF_I2C1);
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;                                   //复用功能的开漏输出
    GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;                          //使能B.6和B.7
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                                 //速度最高50MHz
    GPIO_Init(GPIOB, &GPIO_InitStructure);                                            //初始化结构体配置

    //I2C_ITConfig(I2C1,I2C_IT_EVT|I2C_IT_BUF|I2C_IT_ERR,ENABLE);
    I2C_ITConfig(I2C1,I2C_IT_EVT|I2C_IT_BUF,ENABLE);
    I2C_Cmd(I2C1, ENABLE);                        //使能 I2C1
}



//extern u32 BufferSize ;
//extern u8 I2C1_ADDRESS ;
//extern u8 I2C2_ADDRESS ;
extern vu8 I2C1_Buffer_Tx[];
extern vu8 I2C1_Buffer_Rx[];
vu32 Tx_Counter = 0;
vu32 Rx_Counter = 0;
vu32 USART_Counter=0;
#define size 100
//vu32 show_counter1 = 0;
//vu32 show_counter2 = 0;
vu8 I2C1_Buffer_Rx[size]= {0};

int I2C_Tx = KEY_LEN;

void I2C1_EV_IRQHandler(void)
{
    __IO uint16_t SR1Register =0;
    __IO uint16_t SR2Register =0;


    SR1Register = I2C1->SR1;
    SR2Register = I2C1->SR2;


    // 从机发送
    // 从模式(MSL = 0)
    if((SR2Register & 0x0005) == 0x0004)
    {

        // ADDR
        if((SR1Register & 0x0002) == 0x0002)
        {
            // 清除标志
            SR1Register = 0;
            SR2Register = 0;
            //Tx_Counter= 0;
        }


//TxE:DR为空
        if((SR1Register & 0x0080) == 0x0080)
        {
            SR1Register = 0;
            SR2Register = 0;
            I2C1->DR = I2C_Tx;
            //I2C_GenerateSTOP(I2C1, ENABLE);
        }

//STOPF
        if((SR1Register & 0x0010) == 0x0010)
        {
            I2C1->CR1 |= 0x0001;
            SR1Register = 0;
            SR2Register = 0;
            //   Tx_Counter= 5;
        }

//TIME_OUT
        if((SR1Register & 0x4000) == 0x4000)
        {
            I2C1->CR1 |= 0x0001;
            SR1Register = 0;
            SR2Register = 0;
        }
    }

    // 从机接收
    // 从模式(MSL = 0)
    else if((SR2Register &0x0005) == 0x0000)
    {

        // (ADDR = 1: EV1)
        if((SR1Register & 0x0002) == 0x0002)
        {

            SR1Register = 0;
            SR2Register = 0;
            Rx_Counter = 0;
            USART_Counter=0;
        }

        //  (RXNE = 1: EV2)
        if((SR1Register & 0x0040) == 0x0040)
        {
        	I2C_Tx = KEY_LEN;
            delay_ms(1);
            Rx_Counter++;
            if(Rx_Counter>=2)
            {
                I2C1_Buffer_Rx[Rx_Counter]=I2C1->DR;
                if(Rx_Counter>=3)
                {
                    I2C1_Buffer_Rx[USART_Counter]=I2C1_Buffer_Rx[Rx_Counter];
                    delay_ms(1);
                    USART_SendData( UART4, I2C1_Buffer_Rx[USART_Counter++] );
                }
            }
            SR1Register = 0;
            SR2Register = 0;
        }

        //  (STOPF =1: EV4)
        if(( SR1Register & 0x0010) == 0x0010)
        {
            I2C1->CR1 |= 0x0001;
            SR1Register = 0;
            SR2Register = 0;
//      Flag_RcvOK = 1;
        }
    }
}



        I2C_Tx就是我发送的数据,只发送这么一个字节的数据,发送多个数据的同学可以试着改一下程序。然后我是在电脑在给我发一个发送的时候把I2C_Tx赋值为初始值,这样我们就知道电脑已经读了这个数据了。

        完整的项目代码已经上传到我的CSDN上,这个工程是一个按键板的工程,有使用pwm做蜂鸣器,按键中断检测按键,和按键扫描。

        喜欢的话记得点赞哦~~~






你可能感兴趣的:(C++)