1144|5

6973

帖子

11

TA的资源

版主

楼主
 

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

【目的】

熟悉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];
		}
}
/**
 * [url=home.php?mod=space&uid=159083]@brief[/url] 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_MAX30100.zip (519.2 KB, 下载次数: 3)

N32A455血氧传感器

 

此帖出自汽车电子论坛

最新回复

这个项目可以落这到具体的工程中吗?有没有低功耗的项目,比如手表之类的?   详情 回复 发表于 2024-4-6 14:26

赞赏

1

查看全部赞赏

点赞(1) 关注(1)

回复
举报

6807

帖子

0

TA的资源

五彩晶圆(高级)

沙发
 

看到效果了

 

此帖出自汽车电子论坛
 
 

回复

419

帖子

0

TA的资源

纯净的硅(中级)

板凳
 
图文并茂,受益匪浅,收藏学习中。加油加油!!!
此帖出自汽车电子论坛

点评

感谢大佬的关注,我一直在努力中!  详情 回复 发表于 2024-4-2 20:01
 
 
 

回复

6973

帖子

11

TA的资源

版主

4
 
通途科技 发表于 2024-4-2 19:34 图文并茂,受益匪浅,收藏学习中。加油加油!!!

感谢大佬的关注,我一直在努力中!

此帖出自汽车电子论坛
 
 
 

回复

37

帖子

0

TA的资源

一粒金砂(中级)

5
 

这个项目可以落这到具体的工程中吗?有没有低功耗的项目,比如手表之类的?

此帖出自汽车电子论坛

点评

感谢大佬的关注,目前还没有这个计划,我是想做ADC的数据采集。国民技术有M0/M0+的芯片,那个更好的适配电池供电的环境。  详情 回复 发表于 2024-4-6 14:58
 
 
 

回复

6973

帖子

11

TA的资源

版主

6
 
Mcu_MMU 发表于 2024-4-6 14:26 这个项目可以落这到具体的工程中吗?有没有低功耗的项目,比如手表之类的?

感谢大佬的关注,目前还没有这个计划,我是想做ADC的数据采集。国民技术有M0/M0+的芯片,那个更好的适配电池供电的环境。

此帖出自汽车电子论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/8 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表