天天看点

【MAX30100心率检测传感器】写入与读取数据调试

一.调试过程

执行两句代码

I2C_MAX30102_Single_Write(MAX30102_CONFIG_MODE,0X40); //复位

I2C_MAX30102_Single_Write(MAX30102_CONFIG_MODE,0X03); //开启SPO2模式

整体效果图:

【MAX30100心率检测传感器】写入与读取数据调试

高电平宽度为12微秒

【MAX30100心率检测传感器】写入与读取数据调试

低电平宽度为86微秒

【MAX30100心率检测传感器】写入与读取数据调试

其中的I2C_MAX30102_Single_Write函数代码:

/*---------------------------------------------------------------------------
* 函数:I2C_MAX30102_Single_Write(uint8_t Register_Address,uint8_t Word_Data)    
* 描述:把单个数据写入到相应的寄存器中
* 参数:Register_Address 寄存器地址 
		Word_Data 写入字节
* 返回:1:写入成功; 0:写入失败
*---------------------------------------------------------------------------*/
static uint8_t I2C_MAX30102_Single_Write(uint8_t Register_Address,uint8_t Word_Data)                      
{
	/* 采用串行EEPROM随即读取指令序列,连续读取若干字节 */

	/* 第1步:发起I2C总线启动信号 */
	I2C_MAX30102_Start();

	/* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
	I2C_MAX30102_SendByte( MAX30102_WR_address | I2C_WR);	/* 此处是写指令 */

	/* 第3步:发送ACK */
	if (I2C_MAX30102_WaitAck() != 0)
	{
		goto cmd_fail;	/* EEPROM器件无应答 */
	}

	/* 第4步:发送字节地址 */
	I2C_MAX30102_SendByte(Register_Address);
	if (I2C_MAX30102_WaitAck() != 0)
	{
		goto cmd_fail;	/* EEPROM器件无应答 */
	}
	
	/* 第5步:开始写入数据 */
	I2C_MAX30102_SendByte(Word_Data);

	/* 第6步:发送ACK */
	if (I2C_MAX30102_WaitAck() != 0)
	{
		goto cmd_fail;	/* EEPROM器件无应答 */
	}

	/* 发送I2C总线停止信号 */
	I2C_MAX30102_Stop();
	return 1;	/* 执行成功 */

cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
	/* 发送I2C总线停止信号 */
	I2C_MAX30102_Stop();
	return 0;
}
           

其中的I2C_MAX30102_Start()函数:

/*---------------------------------------------------------------------------
* 函数:I2C_MAX30102_Start(void) 
* 描述:IIC主机发出开始条件
* 参数:无
* 返回:无
*---------------------------------------------------------------------------*/
static void  I2C_MAX30102_Start(void)                        
{
	I2C_MAX30102_Sda_Mode(GPIO_Mode_OUT);     //sda线输出
	
	MAX30102_SDA_OUT=1;	                    //SDA置为高电平	  
	MAX30102_SCL=1;                         //SCL置为高电平
	delay_us(5);
	
 	MAX30102_SDA_OUT=0;                      
	delay_us(5);
	MAX30102_SCL=0;//钳住I2C总线,准备发送或接收数据 
}
           
【MAX30100心率检测传感器】写入与读取数据调试

所以先不管其他部分的时序正确与否,首先这个I2C_MAX30102_Start的起始信号就与程序设计中的不符合,尤其是SCL的时钟线信号,实际测试时一直处于低电平状态。

I2C_MAX30102_Sda_Mode函数:

/*---------------------------------------------------------------------------
* 函数:I2C_MAX30102_Sda_Mode(GPIOMode_TypeDef mode)
* 描述:IIC主机改变SDA的IO状态
* 参数:GPIO_Mode_IN		GPIO_Mode_OUT
* 返回:无
*---------------------------------------------------------------------------*/
static void I2C_MAX30102_Sda_Mode(GPIOMode_TypeDef mode)
{
	GPIO_InitTypeDef  	GPIO_InitStructure;
	
	GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9;				//第9号引脚
	GPIO_InitStructure.GPIO_Mode  = mode;					//输入/输出模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;			//推挽输出,增强驱动能力,引脚的输出电流更大
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;		//引脚的速度最大为100MHz
	GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;			//没有使用内部上拉电阻
	GPIO_Init(GPIOB, &GPIO_InitStructure);	
}
           

首先推测是GPIO引脚配置的问题,所以两个IIC信号不对。

mpu6050也是采用IIC,引脚初始化如下:

void I2C_GPIO_Config(void)
{
  GPIO_InitTypeDef  GPIO_InitStructure; 
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;
  GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
  GPIO_Init(GPIOB, &GPIO_InitStructure);
}
           

max30100引脚初始化如下:

/*---------------------------------------------------------------------------
* 函数:I2C_MAX30102_Config(void)
* 描述:MAX30102引脚初始化
* 参数:无
* 返回:无
*---------------------------------------------------------------------------*/
void I2C_MAX30102_Config(void)                               
{
	//Delay_Init();//初始化SysTick时钟延时
	
	GPIO_InitTypeDef  GPIO_InitStruct;
	
	//打开GPIOE组时钟 
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);		
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	
	GPIO_InitStruct.GPIO_Pin	= GPIO_Pin_8|GPIO_Pin_9;		
	GPIO_InitStruct.GPIO_Mode	= GPIO_Mode_OUT;				//输出模式
	GPIO_InitStruct.GPIO_OType	= GPIO_OType_PP;				//推挽输出
	GPIO_InitStruct.GPIO_PuPd	= GPIO_PuPd_UP;					//上拉
	GPIO_InitStruct.GPIO_Speed	= GPIO_Speed_50MHz;				//速度
	
	GPIO_Init(GPIOB, &GPIO_InitStruct);	
	
	GPIO_InitStruct.GPIO_Pin	= GPIO_Pin_7;					//引脚 7
	GPIO_InitStruct.GPIO_Mode	= GPIO_Mode_IN;					//输入模式
	GPIO_InitStruct.GPIO_PuPd	= GPIO_PuPd_UP;					//上拉
	GPIO_InitStruct.GPIO_Speed	= GPIO_Speed_50MHz;				//速度
	
	GPIO_Init(GPIOE, &GPIO_InitStruct);	
	
	PEout(7) = 1;
	
	//空闲状态
	MAX30102_SCL = 1;
	MAX30102_SDA_OUT = 1;
}
           

区别点在于 推挽输出 与上拉

【MAX30100心率检测传感器】写入与读取数据调试

现在主循环测试两个GPIO引脚的设置是否正确

while(1)
{
    	GPIO_SetBits(GPIOB,GPIO_Pin_1);
		GPIO_SetBits(GPIOB,GPIO_Pin_2);
		delay_ms(15);
		
		GPIO_ResetBits(GPIOB,GPIO_Pin_1);
		GPIO_ResetBits(GPIOB,GPIO_Pin_2);
		delay_ms(15);
}
           
【MAX30100心率检测传感器】写入与读取数据调试

GPIO8和GPIO9也可正常使用

while(1)
{
   	GPIO_SetBits(GPIOB,GPIO_Pin_8);
   	GPIO_SetBits(GPIOB,GPIO_Pin_9);
   	delay_ms(20);
   	
   	GPIO_ResetBits(GPIOB,GPIO_Pin_8);
   	GPIO_ResetBits(GPIOB,GPIO_Pin_9);
   	delay_ms(10);
}
           

引脚配置如下:

/*---------------------------------------------------------------------------
* 函数:I2C_MAX30102_Config(void)
* 描述:MAX30102引脚初始化
* 参数:无
* 返回:无
*---------------------------------------------------------------------------*/
void I2C_MAX30102_Config(void)                               
{
	//Delay_Init();//初始化SysTick时钟延时
	
	GPIO_InitTypeDef  GPIO_InitStruct;
	
	//打开GPIOE组时钟 
	//RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);		
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
	
	GPIO_InitStruct.GPIO_Pin	= GPIO_Pin_8|GPIO_Pin_9;		
	GPIO_InitStruct.GPIO_Mode	= GPIO_Mode_OUT;				//输出模式
	GPIO_InitStruct.GPIO_OType	= GPIO_OType_PP;				
	GPIO_InitStruct.GPIO_PuPd	= GPIO_PuPd_NOPULL;					
	GPIO_InitStruct.GPIO_Speed	= GPIO_Speed_50MHz;				//速度
	
	GPIO_Init(GPIOB, &GPIO_InitStruct);	
	
//	GPIO_InitStruct.GPIO_Pin	= GPIO_Pin_7;					//引脚 7
//	GPIO_InitStruct.GPIO_Mode	= GPIO_Mode_IN;					//输入模式
//	GPIO_InitStruct.GPIO_PuPd	= GPIO_PuPd_UP;					//上拉
//	GPIO_InitStruct.GPIO_Speed	= GPIO_Speed_50MHz;				//速度
//	
//	GPIO_Init(GPIOE, &GPIO_InitStruct);	
//	
//	PEout(7) = 1;
	
	//空闲状态
//	MAX30102_SCL = 1;
//	MAX30102_SDA_OUT = 1;
}
           

其中的GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;一定要是GPIO_OType_PP,如果使用GPIO_OType_OD,无法产生信号。

其中的GPIO_PuPd_UP或者GPIO_PuPd_NOPULL不影响,都可产生信号

【MAX30100心率检测传感器】写入与读取数据调试

将GPIO_SetBits(GPIOB,GPIO_Pin_8);修改为MAX30102_SCL = 1;

无法产生高电平信号,所以程序中的问题主要在于此。

#define MAX30102_SCL  		PBout(8)

#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出 
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入 

#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2)) 
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr)) 
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum)) 
           

大概率是这边的位带操作代码的地址出现问题,导致无法控制寄存器

【MAX30100心率检测传感器】写入与读取数据调试

对代码的GPIO控制修改后,成功产生起始信号

【MAX30100心率检测传感器】写入与读取数据调试

与设计的相符合

【MAX30100心率检测传感器】写入与读取数据调试

具体修改的代码如下,注释的为原有代码,替换为新的GPIO控制方式:

/*---------------------------------------------------------------------------
* 函数:I2C_MAX30102_Start(void) 
* 描述:IIC主机发出开始条件
* 参数:无
* 返回:无
*---------------------------------------------------------------------------*/
void  I2C_MAX30102_Start(void)                        
{
	I2C_MAX30102_Sda_Mode(GPIO_Mode_OUT);     //sda线输出
	
	//MAX30102_SDA_OUT=1;
  MAX30102_SDA_H;	
	//MAX30102_SCL=1;
	MAX30102_SCL_H;
	delay_us(5);
	
 	//MAX30102_SDA_OUT=0;
	MAX30102_SDA_L;	
	delay_us(5);
	//MAX30102_SCL=0;//钳住I2C总线,准备发送或接收数据 
	MAX30102_SCL_L;
}
           

将PBOUT的方式修改为set和reset的方式,具体代码如下:

---------------------------------------------------------------------------*/	 
#define MAX30102_SCL  		PBout(8)
#define MAX30102_SDA_IN		PBin(9)
#define MAX30102_SDA_OUT	PBout(9)

#define MAX30102_SCL_H    GPIO_SetBits(GPIOB,GPIO_Pin_8)
#define MAX30102_SCL_L    GPIO_ResetBits(GPIOB,GPIO_Pin_8)
#define MAX30102_SDA_H    GPIO_SetBits(GPIOB,GPIO_Pin_9)
#define MAX30102_SDA_L    GPIO_ResetBits(GPIOB,GPIO_Pin_9)

#define MAX30102_SDA_READ    GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_9)

           

继续阅读