MSP430 I2C读取多字节通信问题
MSP430 I2C read multiple bytes communication problem
我正在尝试使用 MSP430F249 的温度传感器 (PCT2075)
为了获取温度,我从这个传感器获取了 2 个字节。
我从这个link写了一个代码。
我正在使用 MSP430F249。所以我修改了这个 link.
的代码
但是,我只有两个相同的值。我认为它是 MSByte。
有什么方法可以从传感器中获取 2bytes。
我的代码在这里
void i2c_read_multi(uint8_t slv_addr, uint8_t reg_addr, uint8_t l, uint8_t *arr)
{
uint8_t i;
while(UCB0STAT & UCBBUSY);
UCB0I2CSA = slv_addr; // set slave address
UCB0CTL1 |= UCTR | UCTXSTT; // transmitter mode and START condition.
while(UCB0CTL1 & UCTXSTT);
UCB0TXBUF = reg_addr;
while(!(UCB0CTL1 & UCTXSTT));
UCB0CTL1 &= ~UCTR; // receiver mode
UCB0CTL1 |= UCTXSTT; // START condition
while(UCB0CTL1 & UCTXSTT); // make sure start has been cleared
for (i = 0; i < l; i++) {
while(!(IFG2 & UCB0RXIFG));
if(i == l - 1){
UCB0CTL1 |= UCTXSTP; // STOP condition
}
arr[i] = UCB0RXBUF;
}
while(UCB0CTL1 & UCTXSTP);
}
有两个问题...
链接代码假定端口只需要为每个输出值读取一个字节。
但是,根据您显示的传感器文档,对于数组的每个值 output,我们需要读取 two字节(一个用于 MSB,一个用于 LSB)。
并且,我们需要将这两个字节值合并为一个 16 位值。请注意 arr
现在是 uint16_t
而不是 uint8_t
。而且,l
现在是 [16 位] 样本 的数量(对比 字节 的数量)。所以,this的调用者可能需要做相应的调整。
此外,请注意我们必须“忽略”lsb
的低 5 位。我们通过将 16 位值右移 5 位(例如 val16 >>= 5
)来做到这一点。我认为这是正确的方法。或者,它 可能 只是 val16 &= ~0x1F
[不太可能]。您可能需要进行一些试验。
这是重构后的代码。
请注意,这假设数据以“大端”顺序到达 [基于我的最佳猜测]。如果它实际上是小端,则反转 msb =
和 lsb =
语句。
此外,可能需要调整“STOP”条件代码的位置。我不得不猜测它应该放在 LSB 读取还是 MSB 读取之上。
我选择了 LSB——最后一个字节,因为它最接近链接的通用 i2c 读取的完成方式。 (即)i2c 不知道或不关心相关设备的 MSB/LSB 多路复用。它希望在最后一个 byte [not 16 位 sample].[=20 之前停止=]
void
i2c_read_multi(uint8_t slv_addr, uint8_t reg_addr, uint8_t l,
uint16_t *arr)
{
uint8_t i;
uint8_t msb;
uint8_t lsb;
uint16_t val16;
while (UCB0STAT & UCBBUSY);
// set slave address
UCB0I2CSA = slv_addr;
// transmitter mode and START condition.
UCB0CTL1 |= UCTR | UCTXSTT;
while (UCB0CTL1 & UCTXSTT);
UCB0TXBUF = reg_addr;
while (!(UCB0CTL1 & UCTXSTT));
// receiver mode
UCB0CTL1 &= ~UCTR;
// START condition
UCB0CTL1 |= UCTXSTT;
// make sure start has been cleared
while (UCB0CTL1 & UCTXSTT);
for (i = 0; i < l; i++) {
while (!(IFG2 & UCB0RXIFG));
msb = UCB0RXBUF;
while (!(IFG2 & UCB0RXIFG));
// STOP condition
if (i == l - 1) {
UCB0CTL1 |= UCTXSTP;
}
lsb = UCB0RXBUF;
val16 = msb;
val16 <<= 8;
val16 |= lsb;
// use only most 11 significant bits
// NOTE: this _may_ not be the correct way to scale the data
val16 >>= 5;
arr[i] = val16;
}
while (UCB0CTL1 & UCTXSTP);
}
我正在尝试使用 MSP430F249 的温度传感器 (PCT2075)
为了获取温度,我从这个传感器获取了 2 个字节。
我从这个link写了一个代码。
我正在使用 MSP430F249。所以我修改了这个 link.
的代码有什么方法可以从传感器中获取 2bytes。
我的代码在这里
void i2c_read_multi(uint8_t slv_addr, uint8_t reg_addr, uint8_t l, uint8_t *arr)
{
uint8_t i;
while(UCB0STAT & UCBBUSY);
UCB0I2CSA = slv_addr; // set slave address
UCB0CTL1 |= UCTR | UCTXSTT; // transmitter mode and START condition.
while(UCB0CTL1 & UCTXSTT);
UCB0TXBUF = reg_addr;
while(!(UCB0CTL1 & UCTXSTT));
UCB0CTL1 &= ~UCTR; // receiver mode
UCB0CTL1 |= UCTXSTT; // START condition
while(UCB0CTL1 & UCTXSTT); // make sure start has been cleared
for (i = 0; i < l; i++) {
while(!(IFG2 & UCB0RXIFG));
if(i == l - 1){
UCB0CTL1 |= UCTXSTP; // STOP condition
}
arr[i] = UCB0RXBUF;
}
while(UCB0CTL1 & UCTXSTP);
}
有两个问题...
链接代码假定端口只需要为每个输出值读取一个字节。
但是,根据您显示的传感器文档,对于数组的每个值 output,我们需要读取 two字节(一个用于 MSB,一个用于 LSB)。
并且,我们需要将这两个字节值合并为一个 16 位值。请注意 arr
现在是 uint16_t
而不是 uint8_t
。而且,l
现在是 [16 位] 样本 的数量(对比 字节 的数量)。所以,this的调用者可能需要做相应的调整。
此外,请注意我们必须“忽略”lsb
的低 5 位。我们通过将 16 位值右移 5 位(例如 val16 >>= 5
)来做到这一点。我认为这是正确的方法。或者,它 可能 只是 val16 &= ~0x1F
[不太可能]。您可能需要进行一些试验。
这是重构后的代码。
请注意,这假设数据以“大端”顺序到达 [基于我的最佳猜测]。如果它实际上是小端,则反转 msb =
和 lsb =
语句。
此外,可能需要调整“STOP”条件代码的位置。我不得不猜测它应该放在 LSB 读取还是 MSB 读取之上。
我选择了 LSB——最后一个字节,因为它最接近链接的通用 i2c 读取的完成方式。 (即)i2c 不知道或不关心相关设备的 MSB/LSB 多路复用。它希望在最后一个 byte [not 16 位 sample].[=20 之前停止=]
void
i2c_read_multi(uint8_t slv_addr, uint8_t reg_addr, uint8_t l,
uint16_t *arr)
{
uint8_t i;
uint8_t msb;
uint8_t lsb;
uint16_t val16;
while (UCB0STAT & UCBBUSY);
// set slave address
UCB0I2CSA = slv_addr;
// transmitter mode and START condition.
UCB0CTL1 |= UCTR | UCTXSTT;
while (UCB0CTL1 & UCTXSTT);
UCB0TXBUF = reg_addr;
while (!(UCB0CTL1 & UCTXSTT));
// receiver mode
UCB0CTL1 &= ~UCTR;
// START condition
UCB0CTL1 |= UCTXSTT;
// make sure start has been cleared
while (UCB0CTL1 & UCTXSTT);
for (i = 0; i < l; i++) {
while (!(IFG2 & UCB0RXIFG));
msb = UCB0RXBUF;
while (!(IFG2 & UCB0RXIFG));
// STOP condition
if (i == l - 1) {
UCB0CTL1 |= UCTXSTP;
}
lsb = UCB0RXBUF;
val16 = msb;
val16 <<= 8;
val16 |= lsb;
// use only most 11 significant bits
// NOTE: this _may_ not be the correct way to scale the data
val16 >>= 5;
arr[i] = val16;
}
while (UCB0CTL1 & UCTXSTP);
}