【问题标题】:MSP430 I2C read multiple bytes communication problemMSP430 I2C读取多字节通信问题
【发布时间】:2020-11-04 10:06:36
【问题描述】:

我正在尝试使用 MSP430F249 的温度传感器 (PCT2075)

为了获得温度,我从这个传感器获得了 2 个字节。

我从这个链接写了一个代码。

https://e2e.ti.com/support/microcontrollers/msp430/f/166/t/589712?MSP430FR5969-Read-multiple-bytes-of-data-i2c-with-repeated-start-and-without-interrupts

我正在使用 MSP430F249。所以我修改了这个链接的代码。

但是,我只得到了两个相同的值。我认为是 MSByte。

有没有办法从传感器获取 2 个字节。

我的代码在这里

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

}

【问题讨论】:

    标签: c i2c msp430


    【解决方案1】:

    有两个问题...

    链接到的代码假定端口只需要为每个输出值读取一个字节。

    但是,根据您显示的传感器文档,对于数组中的每个 输出 值,我们需要读取 两个 字节(一个用于 MSB,一个用于LSB)。

    而且,我们需要将这两个字节值合并为一个 16 位值。请注意,arr 现在是 uint16_t,而不是 uint8_t。而且,l 现在是 [16 位] samples 的数量(相对于 bytes 的数量)。所以,this的调用者可能需要做相应的调整。

    此外,请注意我们必须“忽略”lsb 的低 5 位。我们通过将 16 位值右移 5 位来做到这一点(例如val16 &gt;&gt;= 5)。我认为这是正确的方法。或者,可能只是val16 &amp;= ~0x1F [不太可能]。您可能需要进行一些实验。

    这是重构后的代码。

    请注意,这假设数据以“大端”顺序到达 [根据我的最佳猜测]。如果它实际上是小端,请颠倒 msb =lsb = 语句。

    此外,可能需要调整“STOP”条件代码的位置。我不得不猜测它应该放在 LSB 读取还是 MSB 读取之上。

    我选择了 LSB——最后一个字节,因为它最接近链接的通用 i2c 读取的完成方式。 (即)i2c 不知道或不关心相关设备的 MSB/LSB 多路复用。它希望在最后一个 byte [not 16 位 sample] 之前停止。

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

    【讨论】:

    • 感谢您帮助我。它运行良好。我意识到如何从 I2C 获取多个字节。
    最近更新 更多