简体   繁体   中英

MSP430 I2C read multiple bytes communication problem

I'm trying to use a temperature sensor(PCT2075) by MSP430F249

To get a temperature, I get a 2bytes from this sensor.

I wrote a code from this link.

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

I'm using MSP430F249. so I modified a code from this link.

在此处输入图像描述 Howerver, I got just two same value. I think that it is MSByte.

Is there any way to get 2bytes from sensor.

在此处输入图像描述

my code here

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

}

There are two issues...

The linked to code assumes that the port only needs to read one byte for each output value.

But, based on the sensor documentation you've shown, for each value output to the array, we need to read two bytes (one for MSB and one for LSB).

And, we need to merge those two byte values into one 16 bit value. Note that arr is now uint16_t instead of uint8_t . And, l is now the number of [16 bit] samples (vs. number of bytes ). So, the caller of this may need to be adjusted accordingly.

Further, note that we have to "ignore" the lower 5 bits of lsb . We do that by shifting the 16 bit value right by 5 bits (eg val16 >>= 5 ). I assume that's the correct way to do it. Or, it could be just val16 &= ~0x1F [less likely]. You may have to experiment a bit.

Here's the refactored code.

Note that this assumes the data arrives in "big endian" order [based on my best guess]. If it's actually little endian, reverse the msb = and lsb = statements.

Also, the placement of the "STOP" condition code may need to be adjusted. I had to guess as to whether it should be placed above the LSB read or MSB read.

I chose LSB--the last byte because that's closest to how the linked general i2c read is done. (ie) i2c doesn't know about or care about the MSB/LSB multiplexing of the device in question. It wants the STOP just before the last byte [ not the 16 bit 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);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM