注册 登录
电子工程世界-论坛 返回首页 EEWORLD首页 频道 EE大学堂 下载中心 Datasheet 专题
lugl4313820的个人空间 https://home.eeworld.com.cn/space-uid-1269709.html [收藏] [复制] [分享] [RSS]
日志

【国民技术车规MCU N32A455开发板】4、硬件I2C驱动血氧传感器MAX30100

已有 210 次阅读2024-4-1 12:02

【目的】

熟悉N32A455的硬件i2c

【实现的步骤】

1、新建i2c.c/i2c.h。添加n32g455a.h的头文件的引用。

2、i2c的GPIO的选择,我这里先用PB8、PB9为SCL、SDA的引脚 ,查看数据手册后,使用IO复用到i2c。具体的实初始化代码如下:

void my_I2C_Init(void)
{
    /** GPIO configuration and clock enable */
    GPIO_InitType GPIO_InitStructure;
    I2C_InitType I2C_InitStructure;
    /** enable peripheral clk*/
    I2C1_peripheral_clk_en();
    I2C_DeInit(I2C1);

    I2C1_scl_clk_en();
    I2C1_sda_clk_en();


    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_AFIO, ENABLE);
    GPIO_ConfigPinRemap(GPIO_RMP_I2C1, ENABLE);

    GPIO_InitStructure.Pin        = I2C1_SCL_PIN | I2C1_SDA_PIN;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;
    GPIO_InitPeripheral(GPIOx, &GPIO_InitStructure);

    /** I2C periphral configuration */
    I2C_DeInit(I2C1);
    I2C_InitStructure.BusMode     = I2C_BUSMODE_I2C;
    I2C_InitStructure.FmDutyCycle = I2C_FMDUTYCYCLE_2;
    I2C_InitStructure.OwnAddr1    = 0xff;
    I2C_InitStructure.AckEnable   = I2C_ACKEN;
    I2C_InitStructure.AddrMode    = I2C_ADDR_MODE_7BIT;
    I2C_InitStructure.ClkSpeed    = I2C_Speed;
    I2C_Init(I2C1, &I2C_InitStructure);

} 

3、库函数n32a455_i2c.c中实现了i2c的数据写入,发送状态的功能函数,但是在实际的操作中,还需要重新发送命令以及接收数据的功能函数,我这里结合max30100来实现对寄存器的命令,读一个byte以及读多个数据的功能函数。

具体的代码见注释

/**
 * @ 功能:向MAX30100指定地址写入命令.
 * @param 需要写入的地址.
 * @param 需要写入的值 .
 * 返回值  0为正常.
 */
uint8_t max30100_Bus_Write(uint8_t Register_Address, uint8_t Word_Data)
{
	  sMAX30100Timeout = sEE_LONG_TIMEOUT; //重置超时时间
    while (I2C_GetFlag(I2C1, I2C_FLAG_BUSY)) //等待i2c1的总线为空闲
    {
        if ((sMAX30100Timeout--) == 0)
            sEE_TIMEOUT_UserCallback();
    }
    /* 向总线发送起始信号 */
    I2C_GenerateStart(I2C1, ENABLE);
    /** 等待总线的回复 */
    sMAX30100Timeout = sEE_LONG_TIMEOUT;
		while (!I2C_CheckEvent(I2C1, I2C_EVT_MASTER_MODE_FLAG))
    {
        if ((sMAX30100Timeout--) == 0)
            sEE_TIMEOUT_UserCallback();
    }
    /** 写入从机地址 */
    I2C_SendAddr7bit(I2C1, 0xAE, I2C_DIRECTION_SEND);
    /** 等待从机反回ACK */
		sMAX30100Timeout = sEE_LONG_TIMEOUT;
    while (!I2C_CheckEvent(I2C1, I2C_EVT_MASTER_TXMODE_FLAG))
    {
        if ((sMAX30100Timeout--) == 0)
            sEE_TIMEOUT_UserCallback();
    }
		    /** 向MAX30100发送需要写入的寄存器地址 */
    I2C_SendData(I2C1, Register_Address);
    /**等待发送完成标志 */
    sMAX30100Timeout = sEE_LONG_TIMEOUT;
    while (!I2C_CheckEvent(I2C1, I2C_EVT_MASTER_DATA_SENDED))
    {
        if ((sMAX30100Timeout--) == 0)
            sEE_TIMEOUT_UserCallback();
    }
		/** 向总线写入数据 */
			I2C_SendData(I2C1, Word_Data);
			/** 等待发送结束的标志位 */
			sMAX30100Timeout = sEE_LONG_TIMEOUT;
			while (!I2C_CheckEvent(I2C1, I2C_EVT_MASTER_DATA_SENDED))
			{
					if ((sMAX30100Timeout--) == 0)
							sEE_TIMEOUT_UserCallback();
			}
		    /**发送STOP信号 */
    I2C_GenerateStop(I2C1, ENABLE);	
		return 0;
}


/**
 * @ 功能:从MAX30100指定地址读取一个byte.
 * @param 需要写入的地址.
 * @param 需要写入的值 .
 * 返回值  0为正常.
 */
uint8_t max30100_Bus_Read(uint8_t Register_Address)
{
		uint8_t  data;
	//等待i2c1的总线为空闲
	  sMAX30100Timeout = sEE_LONG_TIMEOUT;
    while (I2C_GetFlag(I2C1, I2C_FLAG_BUSY))
    {
        if ((sMAX30100Timeout--) == 0)
            sEE_TIMEOUT_UserCallback();
    }
		//清除ACK标志位,并使能返回ACK
    I2C_ConfigNackLocation(I2C1, I2C_NACK_POS_CURRENT);  // clear ACKPOS
    I2C_ConfigAck(I2C1, ENABLE);
    /* 向总线发送起始信号 */
    I2C_GenerateStart(I2C1, ENABLE);

   /** 等待总线的回复 */
    sMAX30100Timeout = sEE_LONG_TIMEOUT;
    while (!I2C_CheckEvent(I2C1, I2C_EVT_MASTER_MODE_FLAG))
    {
        if ((sMAX30100Timeout--) == 0)
            sEE_TIMEOUT_UserCallback();
    }
		
	   /** 写入从机地址 即MAX30100的地址*/
    I2C_SendAddr7bit(I2C1, 0xAE, I2C_DIRECTION_SEND);
    /**等待发送完成标志 */
    sMAX30100Timeout = sEE_LONG_TIMEOUT;
    while (!I2C_CheckEvent(I2C1, I2C_EVT_MASTER_TXMODE_FLAG))
    {
        if ((sMAX30100Timeout--) == 0)
            sEE_TIMEOUT_UserCallback();
    }
    /** Clear EV6 by setting again the PE bit */
    I2C_Enable(I2C1, ENABLE);	
		 /** 向MAX30100发送需要读取的寄存器地址 */
    I2C_SendData(I2C1, Register_Address);
    /** 等待发送结束标志 */
    sMAX30100Timeout = sEE_LONG_TIMEOUT;
    while (!I2C_CheckEvent(I2C1, I2C_EVT_MASTER_DATA_SENDED))
    {
        if ((sMAX30100Timeout--) == 0)
            sEE_TIMEOUT_UserCallback();
    }
		/** 产生起始信号 */
    I2C_GenerateStart(I2C1, ENABLE);
    /** Test on EV5 and clear it */
    sMAX30100Timeout = sEE_LONG_TIMEOUT;
    while (!I2C_CheckEvent(I2C1, I2C_EVT_MASTER_MODE_FLAG))
    {
        if ((sMAX30100Timeout--) == 0)
            sEE_TIMEOUT_UserCallback();
    }
    /** 发送以读的方式发送从机地址 */
    I2C_SendAddr7bit(I2C1, 0xAE, I2C_DIRECTION_RECV);
    sMAX30100Timeout = sEE_LONG_TIMEOUT;
    while (!I2C_GetFlag(I2C1, I2C_FLAG_ADDRF))
    {
        if ((sMAX30100Timeout--) == 0)
            sEE_TIMEOUT_UserCallback();
    }		
		/** 不需要等待ACK */
		I2C_ConfigAck(I2C1, DISABLE);
		(void)(I2C1->STS1); /// clear ADDR
		(void)(I2C1->STS2);
		/* 发送结束信号 */
		I2C_GenerateStop(I2C1, ENABLE);
		//读取数据
		data = I2C_RecvData(I2C1);
	return data;
}

void max30100_FIFO_Read(uint8_t Register_Address,uint16_t  Word_Data[][2],uint8_t count)
{
	uint8_t i=0;
	uint8_t no = count*4;
	uint8_t pBuffer[no];
	sMAX30100Timeout = sEE_LONG_TIMEOUT;
	while (I2C_GetFlag(I2C1, I2C_FLAG_BUSY))
	{
			if ((sMAX30100Timeout--) == 0)
					sEE_TIMEOUT_UserCallback();
	}
	I2C_ConfigNackLocation(I2C1, I2C_NACK_POS_CURRENT);  // clear ACKPOS
	I2C_ConfigAck(I2C1, ENABLE);
	/** Send START condition */
	I2C_GenerateStart(I2C1, ENABLE);

	/** Test on EV5 and clear it */
	sMAX30100Timeout = sEE_LONG_TIMEOUT;
	while (!I2C_CheckEvent(I2C1, I2C_EVT_MASTER_MODE_FLAG))
	{
			if ((sMAX30100Timeout--) == 0)
					sEE_TIMEOUT_UserCallback();
	}
	
		/** Send EEPROM address for write */
	I2C_SendAddr7bit(I2C1, 0xAE, I2C_DIRECTION_SEND);
	/** Test on EV6 and clear it */
	sMAX30100Timeout = sEE_LONG_TIMEOUT;
	while (!I2C_CheckEvent(I2C1, I2C_EVT_MASTER_TXMODE_FLAG))
	{
			if ((sMAX30100Timeout--) == 0)
					sEE_TIMEOUT_UserCallback();
	}
	/** Clear EV6 by setting again the PE bit */
	I2C_Enable(I2C1, ENABLE);	
	/** Send the EEPROM's internal address to write to */
	I2C_SendData(I2C1, Register_Address);
	/** Test on EV8 and clear it */
	sMAX30100Timeout = sEE_LONG_TIMEOUT;
	while (!I2C_CheckEvent(I2C1, I2C_EVT_MASTER_DATA_SENDED))
	{
			if ((sMAX30100Timeout--) == 0)
					sEE_TIMEOUT_UserCallback();
	}
			/** Send STRAT condition a second time */
	I2C_GenerateStart(I2C1, ENABLE);
	/** Test on EV5 and clear it */
	sMAX30100Timeout = sEE_LONG_TIMEOUT;
	while (!I2C_CheckEvent(I2C1, I2C_EVT_MASTER_MODE_FLAG))
	{
			if ((sMAX30100Timeout--) == 0)
					sEE_TIMEOUT_UserCallback();
	}
	/** Send EEPROM address for read */
	I2C_SendAddr7bit(I2C1, 0xAE, I2C_DIRECTION_RECV);
	sMAX30100Timeout = sEE_LONG_TIMEOUT;
	while (!I2C_GetFlag(I2C1, I2C_FLAG_ADDRF))
	{
			if ((sMAX30100Timeout--) == 0)
					sEE_TIMEOUT_UserCallback();
	}	
	    /** While there is data to be read */
    if (no == 1)
    {
        /** Disable Acknowledgement */
        I2C_ConfigAck(I2C1, DISABLE);
        (void)(I2C1->STS1); /// clear ADDR
        (void)(I2C1->STS2);
        I2C_GenerateStop(I2C1, ENABLE);
    }
    else if (no == 2)
    {
        I2C_ConfigNackLocation(I2C1, I2C_NACK_POS_NEXT);  // set ACKPOS
        (void)(I2C1->STS1);
        (void)(I2C1->STS2);
        I2C_ConfigAck(I2C1, DISABLE);
    }
    else
    {
        I2C_ConfigAck(I2C1, ENABLE);
        (void)(I2C1->STS1);
        (void)(I2C1->STS2);
    }
		
	   while (no)
    {
        if (no <= 3)
        {
            /** One byte */
            if (no == 1)
            {
                /** Wait until RXNE flag is set */
                sMAX30100Timeout = sEE_LONG_TIMEOUT;
                while (!I2C_GetFlag(I2C1, I2C_FLAG_RXDATNE))
                {
                    if ((sMAX30100Timeout--) == 0)
                        sEE_TIMEOUT_UserCallback();
                }
                /** Read data from DAT */
                /** Read a byte from the EEPROM */
                pBuffer[i] = I2C_RecvData(I2C1);
                /** Point to the next location where the byte read will be saved */
                i++;
                /** Decrement the read bytes counter */
                no--;
            }
            /** Two bytes */
            else if (no == 2)
            {
                /** Wait until BTF flag is set */
                sMAX30100Timeout = sEE_LONG_TIMEOUT;
                while (!I2C_GetFlag(I2C1, I2C_FLAG_BYTEF))
                {
                    if ((sMAX30100Timeout--) == 0)
                        sEE_TIMEOUT_UserCallback();
                }
                /** Send STOP Condition */
                I2C_GenerateStop(I2C1, ENABLE);

                /** Read data from DAT */
                pBuffer[i] = I2C_RecvData(I2C1);
                /** Point to the next location where the byte read will be saved */
                i++;
                /** Decrement the read bytes counter */
                no--;
                /** Read data from DAT */
                pBuffer[i] = I2C_RecvData(I2C1);
                /** Point to the next location where the byte read will be saved */
                i++;
                /** Decrement the read bytes counter */
                no--;
            }
            /** 3 Last bytes */
            else
            {
                sMAX30100Timeout = sEE_LONG_TIMEOUT;
                while (!I2C_GetFlag(I2C1, I2C_FLAG_BYTEF))
                {
                    if ((sMAX30100Timeout--) == 0)
                        sEE_TIMEOUT_UserCallback();
                }
                /** Disable Acknowledgement */
                I2C_ConfigAck(I2C1, DISABLE);
                /** Read data from DAT */
                pBuffer[i] = I2C_RecvData(I2C1);
                /** Point to the next location where the byte read will be saved */
                i++;
                /** Decrement the read bytes counter */
                no--;

                /** Wait until BTF flag is set */
                sMAX30100Timeout = sEE_LONG_TIMEOUT;
                while (!I2C_GetFlag(I2C1, I2C_FLAG_BYTEF))
                {
                    if ((sMAX30100Timeout--) == 0)
                        sEE_TIMEOUT_UserCallback();
                }
                /** Send STOP Condition */
                I2C_GenerateStop(I2C1, ENABLE);

                /** Read data from DAT */
                pBuffer[i] = I2C_RecvData(I2C1);
                /** Point to the next location where the byte read will be saved */
                i++;
                /** Decrement the read bytes counter */
                no--;

                /** Read data from DAT */
                pBuffer[i] = I2C_RecvData(I2C1);
                /** Point to the next location where the byte read will be saved */
                i++;
                /** Decrement the read bytes counter */
                no--;
            }
        }
        else
        {
            /** Test on EV7 and clear it */
            sMAX30100Timeout = sEE_LONG_TIMEOUT;
            while (!I2C_CheckEvent(I2C1, I2C_EVT_MASTER_DATA_RECVD_FLAG))
            {
                if ((sMAX30100Timeout--) == 0)
                    sEE_TIMEOUT_UserCallback();
            }
            /** Read a byte from the EEPROM */
            pBuffer[i] = I2C_RecvData(I2C1);
            /** Point to the next location where the byte read will be saved */
            i++;
            /** Decrement the read bytes counter */
            no--;
            if (I2C_GetFlag(I2C1, I2C_FLAG_BYTEF))
            {
                /** Read a byte from the EEPROM */
                pBuffer[i] = I2C_RecvData(I2C1);
                /** Point to the next location where the byte read will be saved */
                i++;
                /** Decrement the read bytes counter */
                no--;
            }
        }
    }
		//组装数据
		for(i=0;i<count;i++)
		{
			Word_Data[i][0] = (pBuffer[i*2]<<8) | pBuffer[i*2+1];
			Word_Data[i][1] = (pBuffer[i*2+2]<<8) | pBuffer[i*2+3];
		}
}
/**
 * @brief  Timeout callback used by the I2C EEPROM driver.
 */
u8 sEE_TIMEOUT_UserCallback(void)
{
    printf("error!!!\r\n");
    /* Block communication and all processes */
    while (1)
    {
    }
}

把i2c的添加到工程中,在前面的LCD的代码中添回max30100的功能函数。最后通过fft来对传感器的数据进行处理,最后生成血氧、心率数据,显示到LCD屏中。

实现在的效果如下:

附工程:

N32A455血氧传感器

 

本文来自论坛,点击查看完整帖子内容。

评论 (0 个评论)

facelist doodle 涂鸦板

您需要登录后才可以评论 登录 | 注册

热门文章