初级会员
积分 59
金钱 59
注册时间 2020-10-16
在线时间 30 小时
20 金钱
本帖最后由 zly0516 于 2020-11-25 10:21 编辑
模拟例程,读取max30102的六组数据时,第一组没读到,后五组读到是0xff,代码如下,求各位大神帮帮忙,问题出在哪里?
#include "myiic.h"
#include "delay.h"
//初始化IIC
void IIC_Init(void)
{
//IO口配置
//PA9---> SCL,PA10 ---> SDA
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOA_CLK_ENABLE();
/*Configure GPIO pin : PtPin */
GPIO_InitStruct.Pin = IIC_SCL_PIN | IIC_SDA_PIN;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIO_PORT_IIC, &GPIO_InitStruct);
IIC_SCL_1;
IIC_SDA_1;
}
//产生IIC起始信号
void IIC_Start(void)
{
SDA_OUT(); //SDA线输出
IIC_SDA_1;
IIC_SCL_1;
delay_us(4);
IIC_SDA_0; //START:when CLK is high,DATA change form high to low
delay_us(4);
IIC_SCL_0 ; //钳住I2C总线,准备发送或接收数据
}
//产生IIC停止信号
void IIC_Stop(void)
{
SDA_OUT();//sda线输出
IIC_SCL_0;
IIC_SDA_0; //STOP:when CLK is high DATA change form low to high
delay_us(4);
IIC_SCL_1;
IIC_SDA_1; //发送I2C总线结束信号
delay_us(4);
}
//等待应答信号到来
//返回值:1,接收应答失败
// 0,接收应答成功
uint8_t IIC_Wait_Ack(void)
{
uint8_t ucErrTime = 0;
// SDA_read;
SDA_IN(); //SDA设置为输入
IIC_SDA_1;
delay_us(1);
IIC_SCL_1;
delay_us(1);
while(READ_SDA)
{
ucErrTime++;
if(ucErrTime > 250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL_0; //时钟输出0
return 0;
}
//产生ACK应答
void IIC_Ack(void)
{
IIC_SCL_0;
SDA_OUT();
IIC_SDA_0;
delay_us(2);
IIC_SCL_1;
delay_us(2);
IIC_SCL_1;
}
//不产生ACK应答
void IIC_NAck(void)
{
IIC_SCL_0;
SDA_OUT();
IIC_SDA_1;
delay_us(2);
IIC_SCL_1;
delay_us(2);
IIC_SCL_0;
}
//IIC发送一个字节
//返回从机有无应答
//1,有应答
//0,无应答
void IIC_Send_Byte(uint8_t txd)
{
uint8_t t;
SDA_OUT();
IIC_SCL_0; //拉低时钟开始数据传输
for(t = 0; t < 8; t++)
{ if((txd & 0x80) >> 7) IIC_SDA_1;
else IIC_SDA_0;
// IIC_SDA = (txd & 0x80) >> 7;
txd <<= 1;
delay_us(2); //对TEA5767这三个延时都是必须的
IIC_SCL_1;
delay_us(2);
IIC_SCL_0;
delay_us(2);
}
}
//读1个字节,ack=1时,发送ACK,ack=0,发送nACK
uint8_t IIC_Read_Byte(unsigned char ack)
{
unsigned char i, receive = 0;
SDA_IN();//SDA设置为输入
for(i = 0; i < 8; i++ )
{
IIC_SCL_0;
delay_us(2);
IIC_SCL_1;
receive <<= 1;
if(READ_SDA)receive++;
delay_us(1);
}
if (!ack)
IIC_NAck();//发送nACK
else
IIC_Ack(); //发送ACK
return receive;
}
void IIC_WriteBytes(uint8_t WriteAddr, uint8_t* data, uint8_t dataLength)
{
uint8_t i;
IIC_Start();
IIC_Send_Byte(WriteAddr); //发送写命令
IIC_Wait_Ack();
for(i = 0; i < dataLength; i++)
{
IIC_Send_Byte(data);
IIC_Wait_Ack();
}
IIC_Stop();//产生一个停止条件
// delay_ms(10);
HAL_Delay(10);
}
void IIC_ReadBytes(uint8_t deviceAddr, uint8_t writeAddr, uint8_t* data, uint8_t dataLength)
{
uint8_t i;
IIC_Start();
IIC_Send_Byte(deviceAddr); //发送写命令
IIC_Wait_Ack();
IIC_Send_Byte(writeAddr);
IIC_Wait_Ack();
IIC_Send_Byte(deviceAddr | 0X01); //进入接收模式
IIC_Wait_Ack();
for(i = 0; i < dataLength - 1; i++)
{
data = IIC_Read_Byte(1);
}
data[dataLength - 1] = IIC_Read_Byte(0);
IIC_Stop();//产生一个停止条件
// delay_ms(10);
HAL_Delay(10);
}
#ifndef __MYIIC_H
#define __MYIIC_H
#include "main.h"
#include "stm32l0xx_hal.h"
#include "stdint.h"
//#define SDA_IN() {GPIOA->MODER&=0XFFCFFFFF;GPIOA->PUPDR&=0XFFCFFFFF;GPIOA->PUPDR|=(uint32_t)1<<19;}
//#define SDA_OUT() {GPIOA->MODER&=0XFFCFFFFF;GPIOA->MODER|=(uint32_t)1<<19;GPIOA->OSPEEDR&=0XFFCFFFFF;GPIOA->OSPEEDR|=(uint32_t)2<<19;}
#define SDA_IN() {GPIO_InitTypeDef GPIO_InitStruct = {0};\
__HAL_RCC_GPIOA_CLK_ENABLE();\
GPIO_InitStruct.Pin = IIC_SDA_PIN;\
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;\
GPIO_InitStruct.Pull = GPIO_PULLUP;\
HAL_GPIO_Init(GPIO_PORT_IIC, &GPIO_InitStruct);}
#define SDA_OUT() {GPIO_InitTypeDef GPIO_InitStruct = {0};\
__HAL_RCC_GPIOA_CLK_ENABLE();\
GPIO_InitStruct.Pin = IIC_SDA_PIN;\
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;\
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;\
HAL_GPIO_Init(GPIO_PORT_IIC, &GPIO_InitStruct);}
//IO操作函数
#define GPIO_PORT_IIC GPIOA /* GPIO端口 */
#define IIC_SCL_PIN GPIO_PIN_9 /* 连接到SCL时钟线的GPIO */
#define IIC_SDA_PIN GPIO_PIN_10 /* 连接到SDA数据线的GPIO */
#define IIC_SCL_1 HAL_GPIO_WritePin(GPIO_PORT_IIC, IIC_SCL_PIN,GPIO_PIN_SET) /* SCL = 1 */
#define IIC_SCL_0 HAL_GPIO_WritePin(GPIO_PORT_IIC, IIC_SCL_PIN,GPIO_PIN_RESET) /* SCL = 0 */
#define IIC_SDA_1 HAL_GPIO_WritePin(GPIO_PORT_IIC, IIC_SDA_PIN,GPIO_PIN_SET) /* SDA = 1 */
#define IIC_SDA_0 HAL_GPIO_WritePin(GPIO_PORT_IIC, IIC_SDA_PIN,GPIO_PIN_RESET) /* SDA = 0 */
#define READ_SDA HAL_GPIO_ReadPin(GPIO_PORT_IIC , IIC_SDA_PIN)
//#define IIC_SCL PBout(9) //SCL
//#define IIC_SDA PBout(10) //SDA
//#define READ_SDA PBin(10) //输入SDA
//IIC所有操作函数
void IIC_Init(void); //初始化IIC的IO口
void IIC_Start(void); //发送IIC开始信号
void IIC_Stop(void); //发送IIC停止信号
void IIC_Send_Byte(uint8_t txd); //IIC发送一个字节
uint8_t IIC_Read_Byte(unsigned char ack);//IIC读取一个字节
uint8_t IIC_Wait_Ack(void); //IIC等待ACK信号
void IIC_Ack(void); //IIC发送ACK信号
void IIC_NAck(void); //IIC不发送ACK信号
void IIC_WriteBytes(uint8_t WriteAddr,uint8_t* data,uint8_t dataLength);
void IIC_ReadBytes(uint8_t deviceAddr, uint8_t writeAddr,uint8_t* data,uint8_t dataLength);
#include "max30102.h"
#include "myiic.h"
#include "delay.h"
u8 max30102_Bus_Write(u8 Register_Address, u8 Word_Data)
{
/* 采用串行EEPROM随即读取指令序列,连续读取若干字节 */
/* 第1步:发起I2C总线启动信号 */
IIC_Start();
/* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
IIC_Send_Byte(max30102_WR_address | I2C_WR); /* 此处是写指令 */
/* 第3步:发送ACK */
if (IIC_Wait_Ack() != 0)
{
goto cmd_fail; /* EEPROM器件无应答 */
}
/* 第4步:发送字节地址 */
IIC_Send_Byte(Register_Address);
if (IIC_Wait_Ack() != 0)
{
goto cmd_fail; /* EEPROM器件无应答 */
}
/* 第5步:开始写入数据 */
IIC_Send_Byte(Word_Data);
/* 第6步:发送ACK */
if (IIC_Wait_Ack() != 0)
{
goto cmd_fail; /* EEPROM器件无应答 */
}
/* 发送I2C总线停止信号 */
IIC_Stop();
return 1; /* 执行成功 */
cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
/* 发送I2C总线停止信号 */
IIC_Stop();
return 0;
}
u8 max30102_Bus_Read(u8 Register_Address)
{
u8 data;
/* 第1步:发起I2C总线启动信号 */
IIC_Start();
/* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
IIC_Send_Byte(max30102_WR_address | I2C_WR); /* 此处是写指令 */
/* 第3步:发送ACK */
if (IIC_Wait_Ack() != 0)
{
goto cmd_fail; /* EEPROM器件无应答 */
}
/* 第4步:发送字节地址, */
IIC_Send_Byte((uint8_t)Register_Address);
if (IIC_Wait_Ack() != 0)
{
goto cmd_fail; /* EEPROM器件无应答 */
}
/* 第6步:重新启动I2C总线。下面开始读取数据 */
IIC_Start();
/* 第7步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
IIC_Send_Byte(max30102_WR_address | I2C_RD); /* 此处是读指令 */
/* 第8步:发送ACK */
if (IIC_Wait_Ack() != 0)
{
goto cmd_fail; /* EEPROM器件无应答 */
}
/* 第9步:读取数据 */
{
data = IIC_Read_Byte(0); /* 读1个字节 */
IIC_NAck(); /* 最后1个字节读完后,CPU产生NACK信号(驱动SDA = 1) */
}
/* 发送I2C总线停止信号 */
IIC_Stop();
return data; /* 执行成功 返回data值 */
cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
/* 发送I2C总线停止信号 */
IIC_Stop();
return 0;
}
void max30102_FIFO_ReadBytes(u8 Register_Address,u8* Data)
{
max30102_Bus_Read(REG_INTR_STATUS_1);
max30102_Bus_Read(REG_INTR_STATUS_2);
/* 第1步:发起I2C总线启动信号 */
IIC_Start();
/* 第2步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
IIC_Send_Byte(max30102_WR_address | I2C_WR); /* 此处是写指令 */
/* 第3步:发送ACK */
if (IIC_Wait_Ack() != 0)
{
goto cmd_fail; /* EEPROM器件无应答 */
}
/* 第4步:发送字节地址, */
IIC_Send_Byte((uint8_t)Register_Address);
if (IIC_Wait_Ack() != 0)
{
goto cmd_fail; /* EEPROM器件无应答 */
}
/* 第6步:重新启动I2C总线。下面开始读取数据 */
IIC_Start();
/* 第7步:发起控制字节,高7bit是地址,bit0是读写控制位,0表示写,1表示读 */
IIC_Send_Byte(max30102_WR_address | I2C_RD); /* 此处是读指令 */
/* 第8步:发送ACK */
if (IIC_Wait_Ack() != 0)
{
goto cmd_fail; /* EEPROM器件无应答 */
}
/* 第9步:读取数据 */
Data[0] = IIC_Read_Byte(1);
Data[1] = IIC_Read_Byte(1);
Data[2] = IIC_Read_Byte(1);
Data[3] = IIC_Read_Byte(1);
Data[4] = IIC_Read_Byte(1);
Data[5] = IIC_Read_Byte(0);
/* 最后1个字节读完后,CPU产生NACK信号(驱动SDA = 1) */
/* 发送I2C总线停止信号 */
IIC_Stop();
cmd_fail: /* 命令执行失败后,切记发送停止信号,避免影响I2C总线上其他设备 */
/* 发送I2C总线停止信号 */
IIC_Stop();
}
//max30102初始化
void max30102_init(void)
{
IIC_Init();
max30102_reset();
max30102_Bus_Write(REG_INTR_ENABLE_1,0xc0); // INTR setting
max30102_Bus_Write(REG_INTR_ENABLE_2,0x00);
max30102_Bus_Write(REG_FIFO_WR_PTR,0x00); //FIFO_WR_PTR[4:0]
max30102_Bus_Write(REG_OVF_COUNTER,0x00); //OVF_COUNTER[4:0]
max30102_Bus_Write(REG_FIFO_RD_PTR,0x00); //FIFO_RD_PTR[4:0]
max30102_Bus_Write(REG_FIFO_CONFIG,0x0f); //sample avg = 1, fifo rollover=false, fifo almost full = 17
max30102_Bus_Write(REG_MODE_CONFIG,0x03); //0x02 for Red only, 0x03 for SpO2 mode 0x07 multimode LED
max30102_Bus_Write(REG_SPO2_CONFIG,0x27); // SPO2_ADC range = 4096nA, SPO2 sample rate (100 Hz), LED pulseWidth (400uS)
max30102_Bus_Write(REG_LED1_PA,0x24); //Choose value for ~ 7mA for LED1
max30102_Bus_Write(REG_LED2_PA,0x24); // Choose value for ~ 7mA for LED2
max30102_Bus_Write(REG_PILOT_PA,0x7f); // Choose value for ~ 25mA for Pilot LED
}
//max30102复位
void max30102_reset(void)
{
max30102_Bus_Write(REG_MODE_CONFIG,0x40);
max30102_Bus_Write(REG_MODE_CONFIG,0x40);
}
主函数的一部分:
for(i = 0; i < n_ir_buffer_length; i++)
{
while(MAX30102_INT == 1); //wait until the interrupt pin asserts
max30102_FIFO_ReadBytes(REG_FIFO_DATA, temp);
aun_red_buffer = (long)((long)((long)temp[0] & 0x03) << 16) | (long)temp[1] << 8 | (long)temp[2]; // Combine values to get the actual number
aun_ir_buffer = (long)((long)((long)temp[3] & 0x03) << 16) | (long)temp[4] << 8 | (long)temp[5]; // Combine values to get the actual number
if(un_min > aun_red_buffer)
un_min = aun_red_buffer; //update signal min
if(un_max < aun_red_buffer)
un_max = aun_red_buffer; //update signal max
}
max30102_FIFO_ReadBytes(REG_FIFO_DATA, temp);通过这个函数读取数据,但是数据不对。
前面命令都对,就是读取数据时,第一个没读到,后面全是0xff,单片机用的是stm31l0系列的,用hal改写的。
我来回答