这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界» 论坛首页» 活动中心» 板卡试用» N32A455硬件I2C调试

共2条 1/1 1 跳转至

N32A455硬件I2C调试

菜鸟
2024-03-30 15:18:16 被打赏40分(兑奖) 打赏

【前言】

i2c的通迅可以用IO来摸拟也可以使用硬件来实现,但是软件的I2C很难实现精准的发送波特率,我在调试MAX30100时,如果遇到软件I2C难以匹配到100KHz或者400KHz的速率,导到与传感器不能正常的通迅。经过认真的阅读官方文档,实现了硬件I2C的收发。在此分享如下。

【硬件】

1、国民技术N32A455车规级开发板。

2、MAX30100传感器。

【软件环境】

1、MDK5.39

2、N32A455 SDK

【I2C通道的选择】

根据开发板的原理图,I2C1接到了板载的EEROM上,并且给出了上拉电阻,因为选择PB8、PB9。

image.png

根据用户手册,I2C使用PB8、PB9需要对GPIO进行复用。

image.png

【I2C实始化】

1、先重定义一下I2C的IO,方便阅读:

#define I2C1_SCL_PIN GPIO_PIN_8

#define I2C1_SDA_PIN GPIO_PIN_9

#define GPIOx GPIOB

2、初始化函数如下:

void my_I2C_Init(void)

{

/** GPIO configuration and clock enable */

GPIO_InitType GPIO_InitStructure; //声明GPIO结构体

I2C_InitType I2C_InitStructure; //声明I2C结构体

/** enable peripheral clk*/

I2C1_peripheral_clk_en(); //使能i2c时钟

I2C_DeInit(I2C1); //重置I2C1


I2C1_scl_clk_en(); //打开SCL 的GPIO时钟

I2C1_sda_clk_en(); //打开SDA的GPIO时钟

RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_AFIO, ENABLE); //使能APB2时钟

GPIO_ConfigPinRemap(GPIO_RMP_I2C1, ENABLE); //复用i2c端口


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 为 400K */

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

}

2、向MAX00指定的地址发送一个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;

}

3、从MAX30100读取指定寄存器一个byte。

/**

* @ 功能:从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;

}



高工
2024-03-30 17:20:44 打赏
2楼

一般I2C的通信速率并不严格。

偏差实现没有啥问题

333Kbps也是可以的


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册]