天天看點

【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)

           

繼續閱讀