一.調試過程
執行兩句代碼
I2C_MAX30102_Single_Write(MAX30102_CONFIG_MODE,0X40); //複位
I2C_MAX30102_Single_Write(MAX30102_CONFIG_MODE,0X03); //開啟SPO2模式
整體效果圖:
高電平寬度為12微秒
低電平寬度為86微秒
其中的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總線,準備發送或接收資料
}
是以先不管其他部分的時序正确與否,首先這個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;
}
差別點在于 推挽輸出 與上拉
現在主循環測試兩個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);
}
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不影響,都可産生信号
将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))
大機率是這邊的位帶操作代碼的位址出現問題,導緻無法控制寄存器
對代碼的GPIO控制修改後,成功産生起始信号
與設計的相符合
具體修改的代碼如下,注釋的為原有代碼,替換為新的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)