I2C从传感器接收2个字节

13个职位/ 0新
最后一篇
詹菲尔德
离线
最后一次露面:4年7个月前
加入:2016-03-08 14:38
I2C从传感器接收2个字节

你好

我尝试与传感器进行通信。传感器数据表说我需要编写测量命令。它的值(12或14位)存储在其内存中。要获取此数据,我必须读出2个字节。但每当我尝试用“i2c eeprom读取数据(uint8*rd数据ptr、uint32地址、uint32大小)“我被困在”read_data_single()“ 在里面 ”WAIT_FOR_RECEIVED_BYTE ();“循环。似乎DA14580没有收到一些东西。

* rd_data_ptr.我有一个指向一个值变量的指针uint32_t mes_val.. 我使用了i2c_slave_address.在user_peripher_setup .h中配置。为尺寸我有2个字节。

我该怎么办才能收到两个字节?它如何存储?我需要存储在一个变量中的值,该变量大小为2bytes。发送“读取”命令后,传感器发送“most_significant_byte”_ack_“最终_significant_byte”_ack_(也许校验和)_nack_ stop_condition。

为了更好地描述它,我也尝试了i2c_eeprom_read_byte.获得第一个字节。但这也不起作用。BLE连接也丢失了,我无法重新连接。整个系统仅在“等待循环”中。我必须取消,重置和重新启动系统以再次获得蓝牙。我想通过BLE-命令触发测量,并将1写入特征值。在写入1到CHAR值,应触发测量的触发命令(1byte长度)。之后我想读出将存储在另一个特征中的值(2个字节)。
当一切正常时,我想使用通知来更新我手机上的传感器的新值。

谢谢!

1月

设备:
mt_dialog.
离线
最后一次露面:4个月2周前
职员
加入:2015-06-08 11:34
嗨Janfeld,

嗨Janfeld,

如果你被困在WAIT_FOR_RECEIVE_BYTE(),那么是的580没有从另一边收到任何东西。我不认为这是由于代码实现,但由于与580和传感器的连接,或传感器从不回复你发送的命令的某种原因。在这种情况下,逻辑分析仪捕获会有很大帮助。

关于BLE,I2C驱动程序轮询I2C接口以获得一些数据,因为没有数据返回驱动程序,因为M0卡在I2C轮询中,因此丢失了驱动程序。您必须捕获I2C总线,并查看580在总线上发送的内容,如果它是正确的(传感器获取他想要的命令),如果传感器的回复。

关于I2C驱动程序的阅读过程中,你可以使用read_data_single()函数设置传感器,你想读(传感器的一些内部地址)的地址和值2,这将迫使驾驶员设定的尺寸,以便从指定的地址读取数据,你声明发送两个时钟周期。然后,驱动程序将放置在指向函数中作为参数传递的指针中收到的数据。

谢谢mt_dialog.

詹菲尔德
离线
最后一次露面:4年7个月前
加入:2016-03-08 14:38
谢谢你的回答。我不知道

谢谢你的回答。我不知道't have any kind of information about the internal addresses of the sensor. With an arduino it works fine. I send the "Measurement CMD" to the sensor, wait for some milliseconds while it's measuring then i send the read request. after that i'll read two bytes of data. There's nothing with internal addresses of the sensor. I think it works this way:

μC:_____ S___ADDR + WR_BIT_____Meas_CMD_____ADDR + RD_BIT______ACK_____ACK____________NACK___P

传感器:确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认确认__________

这是传感器数据表中描述的。没有特定的指针地址可用。是否有其他方式接收值?也许是像“听”这样的功能?

我会尽快用示波器分析传输。但也许你知道我能做什么。

谢谢,

1月

mt_dialog.
离线
最后一次露面:4个月2周前
职员
加入:2015-06-08 11:34
嗨Janfeld,

嗨Janfeld,

为了执行两次读取,您似乎必须将该Meas_CMD作为read_data_single()中的地址参数发送,大小为2。为了让i2c传感器返回一些值,它需要知道要将哪些数据发送到emmit和哪个设备,或者通常要做什么,因此您必须向i2c总线提供您想要与之通信的设备的地址,并向传感器写入(i2c的写入命令)您想要的值(Meas_CMD)。因此,当您尝试使用read_data_single()函数访问总线时,I2C将自动提供从设备的地址,在I2C模块初始化期间(在I2C_init()中)和写入位,只要在从设备地址(Meas_CMD)之后执行I2C_发送_地址(Meas_CMD)然后I2C模块将提供从传感器获取两个字节的时钟。我希望我说得够清楚了。

谢谢mt_dialog.

詹菲尔德
离线
最后一次露面:4年7个月前
加入:2016-03-08 14:38
嗨,它仍然没有

嗨,还是不行。我尝试将MEAS_CMD作为地址参数发送。

我从传感器的数据表附上了方案。它显示了传感器使用的通信序列。到目前为止,我无法在I2C_EEPROM文件中看到可以提供这种通信流的可能性。

在尝试接收字节时,我仍然会卡住。

据我所知,我必须使用写功能发送测量命令。我没有存储器地址,只有传感器的I2C地址。测量(20-80µs之间的某个值)后,我可以发送读取命令(I2C_地址+读取位)。然后传感器开始发送数据。首先是最高有效字节。当收到数据时,DA14580必须提供ACK。然后发送第二个字节(LSB)(后面是DA14580的ACK)。最后发送校验和。

我是不是对它的工作原理有错误的认识,还是有什么我看不见的?

对于通信,两条通信线路上都必须有上拉。我使用了我在“ConfigurePin(……INPUT_PULLUP…)”上设置的内部上拉,这是错误的吗?我也尝试过外拉。(ConfigurePin(..输入…)).也没用。

谢谢,

1月

依恋:
mt_dialog.
离线
最后一次露面:4个月2周前
职员
加入:2015-06-08 11:34
嗨Janfeld,

嗨Janfeld,

正如我提到的,如果没有捕获,就没有容易的方法来调试这个,您将不得不检查总线上的信号,只是推测我们无法跟踪问题的原因。您必须检查在I2C总线上输出的是什么。I2C功能当执行一个读将执行写第一次(最后一点I2C奴隶地址设置为0),为了写设备的内部地址,或者一个命令在你的情况中,然后将读取命令(奴隶地址最后位设置为1)为了从传感器开始阅读,在写和读命令之间不发出延迟。您可以检查的是传感器I2C的配置,如果它对应于初始化时I2C模块的设置。但你必须捕捉到巴士才能解决这个问题。

谢谢mt_dialog.

詹菲尔德
离线
最后一次露面:4年7个月前
加入:2016-03-08 14:38
你好,我们又见面了,

你好,我们又见面了,

我用示波器检查了通信,发现发送I2C_命令不能正常工作。当我想写一个命令时,它发送ADDR+WR_位,然后命令向右移位一位。(大部分时间,不是所有时间……有时它会起作用)

例如:send_i2c_command(0xF3)将发送:addr + wr_bit和0x71作为命令。(1000'0000为7位ADDR。+ WR位0和0111'1001而不是1111'0011)。地址是正确的,有时它有效,传感器正在进行工作。但大多数时间它都不工作并发送错误的值。

当我尝试阅读某些东西时也一样。我想发送SEND_I2C_COMMAND (0 x0100).它发送:ADDR+WR_BIT(而不是RD_BIT)以及之后的一些随机值。有时它会发送ADDR+RD_BIT。(1000'0001)但大多数时候它不能正常工作。

我拥有的另一个问题是,是ACK自动设置或者我必须手动将其设置为Ack第一个字节,以便传感器可以发送第二个字节?

谢谢,

1月

mt_dialog.
离线
最后一次露面:4个月2周前
职员
加入:2015-06-08 11:34
嗨Janfeld,

嗨Janfeld,

关于send_i2c_command(),我不认为该命令必须与您所面临的内容进行任何操作,如果有时它有效,另外但我不认为它必须用您的连接做点什么。

当他自动获取收到的数据时,I2C控制器将生成ACK,您不必从代码中执行任何额外的事情。

谢谢mt_dialog.

文究
离线
最后一次露面:10个月前1年
加入:2016-07-12 07:10
你好

你好

我遇到的问题与在I2C总线上读取多字节数据时遇到的问题相同。我将I2C多读功能从“I2C_eeprom.c”中修改过来。该功能描述如下。

而问题是,当我试图从我的传感器(加速计MMA8652)读取192字节时,程序将停止在“WAIT_FOR_RECEIVED_BYTE();',其中已经读取的数据的索引总是66(dec)。

我从逻辑信号分析仪得到了通信图,看起来DA14580和加速度计之间的通信是正确的,信号持续了192字节的周期!当我消除代码“WAIT_FOR_RECEIVED_BYTE”时,整个时间段的时间是相同的。根据图表,甚至在I2C-STOP信号之前就有可用的数据。

因此,DA14580和加速计之间的“连接问题”似乎不是正确的原因。

希望你的帮助。

无效I2C_读取多字节(uint8_t regAddr,uint8_t data[],uint8_t size)
{
uint8_t索引;

WAIT_UNTIL_I2C_FIFO_IS_EMPTY ();

等待直到没有主活动();

//要读取的寄存器地址
SEND_I2C_COMMAND (regAddr);

对于(索引=0;索引{
正在等待,I2C FIFO已满()如果Tx FIFO已满,请等待
SEND_I2C_COMMAND (0 x0100);//设置读取次数
}

//数据阅读
对于(索引=0;索引{
WAIT_FOR_RECEIVED_BYTE ();
data[index] = (uint8_t)(uint8_t)(GetWord16(I2C_DATA_CMD_REG) & 0xFF);
}

}

并初始化I2C Contorler:

i2cInitParam\u t param;
param.periadrr = 0x1d;
参数。addressMode = I2C_7BIT_ADDR;
param.speedMode=I2C_FAST;

void I2C_Init(const i2cInitParam_t *param)
{
设置16(时钟/寄存器,I2C启用,1);//为I2C启用时钟
setword16(i2c_enable_reg,0x0);//禁用I2C控制器
setword16(i2c_con_reg,i2c_master_mode | i2c_slave_disable | i2c_restart_en);//从站被禁用
setBits16(i2c_con_reg,i2c_speed,param-> speedmode);//设置速度
SetBits16 (I2C_CON_REG I2C_10BITADDR_MASTER, param - > addressMode);//设置寻址模式
SetWord16(I2C_TAR_REG,param->periAdrr&0x3FF);//设置从设备地址
SetWord16(I2C_ENABLE_REG,0x1);//启用I2C控制器
而((getword16(i2c_status_reg)&0x20)!= 0);//等待I2C主FSM闲置
}

文究
离线
最后一次露面:10个月前1年
加入:2016-07-12 07:10
你好

你好

我遇到的问题与在I2C总线上读取多字节数据时遇到的问题相同。我将I2C多读功能从“I2C_eeprom.c”中修改过来。该功能描述如下。

而问题是,当我试图从我的传感器(加速计MMA8652)读取192字节时,程序将停止在“WAIT_FOR_RECEIVED_BYTE();',其中已经读取的数据的索引总是66(dec)。

我从逻辑信号分析仪得到了通信图,看起来DA14580和加速度计之间的通信是正确的,信号持续了192字节的周期!当我消除代码“WAIT_FOR_RECEIVED_BYTE”时,整个时间段的时间是相同的。根据图表,甚至在I2C-STOP信号之前就有可用的数据。

因此,DA14580和加速计之间的“连接问题”似乎不是正确的原因。

希望你的帮助。

无效I2C_读取多字节(uint8_t regAddr,uint8_t data[],uint8_t size)
{
uint8_t索引;

WAIT_UNTIL_I2C_FIFO_IS_EMPTY ();

等待直到没有主活动();

//要读取的寄存器地址
SEND_I2C_COMMAND (regAddr);

对于(索引=0;索引{
正在等待,I2C FIFO已满()如果Tx FIFO已满,请等待
SEND_I2C_COMMAND (0 x0100);//设置读取次数
}

//数据阅读
对于(索引=0;索引{
WAIT_FOR_RECEIVED_BYTE ();
data[index] = (uint8_t)(uint8_t)(GetWord16(I2C_DATA_CMD_REG) & 0xFF);
}

}

并初始化I2C Contorler:

i2cInitParam\u t param;
param.periadrr = 0x1d;
参数。addressMode = I2C_7BIT_ADDR;
param.speedMode=I2C_FAST;

void I2C_Init(const i2cInitParam_t *param)
{
设置16(时钟/寄存器,I2C启用,1);//为I2C启用时钟
setword16(i2c_enable_reg,0x0);//禁用I2C控制器
setword16(i2c_con_reg,i2c_master_mode | i2c_slave_disable | i2c_restart_en);//从站被禁用
setBits16(i2c_con_reg,i2c_speed,param-> speedmode);//设置速度
SetBits16 (I2C_CON_REG I2C_10BITADDR_MASTER, param - > addressMode);//设置寻址模式
SetWord16(I2C_TAR_REG,param->periAdrr&0x3FF);//设置从设备地址
SetWord16(I2C_ENABLE_REG,0x1);//启用I2C控制器
而((getword16(i2c_status_reg)&0x20)!= 0);//等待I2C主FSM闲置
}

詹菲尔德
离线
最后一次露面:4年7个月前
加入:2016-03-08 14:38
我有一个解决方案

我有一个适合我的解决方案,但我认为它可能不够安全,无法连续存储大量字节。但也许你可以试试。。

我通过删除WAIT_FOR_RECEIVED_BYTE ();然后尝试直接获取该值,并通过指针将其保存到数组中。

我的函数现在看起来像这样:


void i2c_cust_read_bytes(uint8_t * val_ptr)
{
val_ptr[0]=0x00;
val_ptr [1] = 0x00;

等待直到没有主活动();
SEND_I2C_COMMAND (0 x0100);
WAIT_WHILE_I2C_FIFO_IS_FULL ();

val_ptr [1] = getword16(i2c_data_cmd_reg);

SEND_I2C_COMMAND (0 x0100);
WAIT_WHILE_I2C_FIFO_IS_FULL ();

val_ptr[0]=GetWord16(I2C_DATA_CMD_REG)&0xFC;

}

这对我很有效。我得到数组第二个元素的第一个值的原因只是我想让它在那里。您可以选择要指向的元素。

我想是这样的:

一开始:没有大师级的活动。
然后发送“READ_CMD”。等待FIFO为空以接收新字节(在将地址+读取位和0x00写入I2C_DATA_CMD_REG时清除)。
然后保存到你想要的变量。再次发送一个READ_CMD,它将覆盖I2C_DATA_CMD_REG中保存的值,并对希望在一行中接收的每个字节重复此操作。

对于两个值,它可能会起作用,但我不知道是否有可能在没有错误或更改位的情况下保存并接收一行中超过一个或两个字节。

遗憾的是,我仍然不知道为什么等待收到的字节()对我不起作用。。

希望我能帮助你一点。

干杯

1月

mt_dialog.
离线
最后一次露面:4个月2周前
职员
加入:2015-06-08 11:34
你好

你好

您是否尝试过按原样使用I2C驱动程序(i2c_eeprom_read_data)。捕捉你的高度我看到没有停止条件从580年为了读取数据(FIFO满-32时钟周期emmited和32字节的数据已收到,所以proccessor应该开始阅读FIFO和把数据从I2C FIFO缓冲区),当FIFO是满的时候,你正在读取数据吗?WAIT_FOR_RECEIVED_BYTE检查I2C_RX_FLR_REG,这个寄存器包含有效的数据,已经接收到,并且位于FIFO中,如果在FIFO中没有数据,它将被卡在while中,因为它被指示读取。在你的代码中作为输入的大小的值是多少?如果您正在调用您提到的超过32的函数,那么您的FIFO是满的,并且FIFO中的数据被下一个传入的数据重写。如果你检查I2C_eeprom司机你会看到i2c_eeprom_read_data是阅读的数据使用read_data_single eepm在32的倍数()函数和当FIFO满32字节I2C模块将停止时钟读取32个字节的数据。

坦斯克山对话

Naracontrol.
离线
最后一次露面:3年7个月前
加入:2016-04-14 10:22
你好

你好
我也遇到了同样的问题&找到了解决办法。

您可以用此代码读取两个字节。
键是I2C_CON_REG的I2C_RESTART_EN位禁用。

void init_i2c(void)
{
设置16(时钟/寄存器,I2C启用,1);//为I2C启用时钟
setword16(i2c_enable_reg,0x0);//禁用I2C控制器

//这是关键的解决方案。
// SetWord16(I2C_CON_REG,I2C_MASTER_MODE | I2C_SLAVE_DISABLE | I2C_RESTART_EN);//从站被禁用
setword16(i2c_con_reg,i2c_master_mode | i2c_slave_disable);

设置16(I2C_CON_REG,I2C_速度,I2C_标准);//设置速度
设置16(I2C_CON_REG,I2C_10bit ADDR_MASTER,I2C_7BIT_ADDR);//设置寻址模式

// I2C设备地址设置。
SetWord16(I2C_TAR_REG,地址);//设置从设备地址

SetWord16(I2C_ENABLE_REG,0x1);//启用I2C控制器
而((getword16(i2c_status_reg)&0x20)!= 0);//等待I2C主FSM闲置
}

无符号短readshorti2c(无效)
{
无符号短V,V1,V2;

WAIT_WHILE_I2C_FIFO_IS_FULL ();//设置R/W位为1(读访问)
发送I2C命令(0x0100);//设置读取访问次数。所以打了两次电话
WAIT_WHILE_I2C_FIFO_IS_FULL ();
SEND_I2C_COMMAND (0 x0100);

WAIT_FOR_RECEIVED_BYTE ();//等待接收的数据
v1 = 0xff&getword16(i2c_data_cmd_reg);//获得收到的字节,MSB
WAIT_FOR_RECEIVED_BYTE ();//等待接收的数据
v2=(0xFF&GetWord16(I2C_DATA_CMD_REG));//获取接收字节,LSB

V = v1<<8 | v2;
ARCH_PRINTF(“\ r \ nv%04x:%04x =%04x(%d)”,v1,v2,v,v);
返回v;
}

谢谢你。