【目的】
熟悉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];
}
}
/**
* @brief 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屏中。
实现在的效果如下:
附工程: