使用 MSP430FR5969 MCU 从 TMP117 传感器读取温度值
Reading temperature values from TMP117 sensor using MSP430FR5969 MCU
我正在尝试通过 I2C 协议从 TMP117 传感器 [1] connected to an MSP430FR5969 MCU [2] 读取温度值。传感器结果寄存器中的数据为二进制补码格式,数据宽度为16位,分辨率为0.0078125℃。我使用 Code Composer Studio 对 MCU 进行编程,并附上了以下代码:
#include <msp430.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#define SLAVE_ADDR 0x48
#define CONVERSION_READY 0x10
#define TMP117_TEMP_REG 0x00
#define TMP117_CONFIG_REG 0x01
#define TMP117_RESOLUTION 0.0078125f
#define CMD_TYPE_0_SLAVE 0
#define CMD_TYPE_1_SLAVE 1
#define CMD_TYPE_2_SLAVE 2
#define CMD_TYPE_0_MASTER 3
#define CMD_TYPE_1_MASTER 4
#define CMD_TYPE_2_MASTER 5
#define TYPE_0_LENGTH 1
#define TYPE_1_LENGTH 2
#define TYPE_2_LENGTH 6
#define MAX_BUFFER_SIZE 20
char temperature[] = "Temperature is: ";
char dot[] = ".";
char celcuis[] = " degree Celcius\r\n";
int i;
char text[] = " I am an MSP430FR5969\r\n";
char rx_char[5];
volatile int rx_val = 0;
void clockSetup();
void gpioSetup();
void uartSetup();
void i2cSetup();
void ser_output(char *str);
uint8_t MasterType1 [TYPE_1_LENGTH] = {0x02, 0x20};
uint8_t SlaveType1 [TYPE_1_LENGTH] = {0};
typedef enum I2C_ModeEnum{
IDLE_MODE,
NACK_MODE,
TX_REG_ADDRESS_MODE,
RX_REG_ADDRESS_MODE,
TX_DATA_MODE,
RX_DATA_MODE,
SWITCH_TO_RX_MODE,
SWITHC_TO_TX_MODE,
TIMEOUT_MODE
} I2C_Mode;
I2C_Mode MasterMode = IDLE_MODE;
/* The Register Address/Command to use*/
uint8_t TransmitRegAddr = 0;
uint8_t ReceiveBuffer[MAX_BUFFER_SIZE] = {0};
uint8_t RXByteCtr = 0;
uint8_t ReceiveIndex = 0;
uint8_t TransmitBuffer[MAX_BUFFER_SIZE] = {0};
uint8_t TXByteCtr = 0;
uint8_t TransmitIndex = 0;
I2C_Mode I2C_Master_WriteReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t count);
I2C_Mode I2C_Master_ReadReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t count);
void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count);
I2C_Mode I2C_Master_ReadReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t count)
{
MasterMode = TX_REG_ADDRESS_MODE;
TransmitRegAddr = reg_addr;
RXByteCtr = count;
TXByteCtr = 0;
ReceiveIndex = 0;
TransmitIndex = 0;
UCB0I2CSA = dev_addr;
UCB0IFG &= ~(UCTXIFG + UCRXIFG);
UCB0IE &= ~UCRXIE;
UCB0IE |= UCTXIE;
UCB0CTLW0 |= UCTR + UCTXSTT;
__bis_SR_register(LPM0_bits + GIE);
return MasterMode;
}
I2C_Mode I2C_Master_WriteReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t count)
{
MasterMode = TX_REG_ADDRESS_MODE;
TransmitRegAddr = reg_addr;
CopyArray(reg_data, TransmitBuffer, count);
TXByteCtr = count;
RXByteCtr = 0;
ReceiveIndex = 0;
TransmitIndex = 0;
UCB0I2CSA = dev_addr;
UCB0IFG &= ~(UCTXIFG + UCRXIFG);
UCB0IE &= ~UCRXIE;
UCB0IE |= UCTXIE;
UCB0CTLW0 |= UCTR + UCTXSTT;
__bis_SR_register(LPM0_bits + GIE);
return MasterMode;
}
void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count)
{
uint8_t copyIndex = 0;
for (copyIndex = 0; copyIndex < count; copyIndex++)
{
dest[copyIndex] = source[copyIndex];
}
}
void main(void)
{
WDTCTL = WDTPW | WDTHOLD;
clockSetup();
gpioSetup();
uartSetup();
i2cSetup();
__bis_SR_register(GIE);
while (1)
{
_delay_cycles(500000);
I2C_Master_ReadReg(SLAVE_ADDR, 0x00, TYPE_1_LENGTH);
CopyArray(ReceiveBuffer, SlaveType1, TYPE_1_LENGTH);
if(ReceiveBuffer[1] & CONVERSION_READY)
{
I2C_Master_ReadReg(SLAVE_ADDR, 0x00, TYPE_1_LENGTH);
CopyArray(ReceiveBuffer, SlaveType1, TYPE_1_LENGTH);
_no_operation();
}
ltoa(rx_val, rx_char, 10);
ser_output(temperature);
ser_output(rx_char);
ser_output(dot);
ser_output(celcuis);
}
}
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCI_B0_ISR (void)
#else
#error Compiler not supported!
#endif
{
//Must read from UCB0RXBUF
//// uint8_t rx_val = 0;
switch(__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG))
{
case USCI_NONE: break; // Vector 0: No interrupts
case USCI_I2C_UCALIFG: break; // Vector 2: ALIFG
case USCI_I2C_UCNACKIFG: // Vector 4: NACKIFG
break;
case USCI_I2C_UCSTTIFG: break; // Vector 6: STTIFG
case USCI_I2C_UCSTPIFG: break; // Vector 8: STPIFG
case USCI_I2C_UCRXIFG3: break; // Vector 10: RXIFG3
case USCI_I2C_UCTXIFG3: break; // Vector 12: TXIFG3
case USCI_I2C_UCRXIFG2: break; // Vector 14: RXIFG2
case USCI_I2C_UCTXIFG2: break; // Vector 16: TXIFG2
case USCI_I2C_UCRXIFG1: break; // Vector 18: RXIFG1
case USCI_I2C_UCTXIFG1: break; // Vector 20: TXIFG1
case USCI_I2C_UCRXIFG0: // Vector 22: RXIFG0
rx_val = UCB0RXBUF;
if (RXByteCtr)
{
ReceiveBuffer[ReceiveIndex++] = rx_val;
RXByteCtr--;
}
if (RXByteCtr == 1)
{
UCB0CTLW0 |= UCTXSTP;
}
else if (RXByteCtr == 0)
{
UCB0IE &= ~UCRXIE;
MasterMode = IDLE_MODE;
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
break;
case USCI_I2C_UCTXIFG0: // Vector 24: TXIFG0
switch (MasterMode)
{
case TX_REG_ADDRESS_MODE:
UCB0TXBUF = TransmitRegAddr;
if (RXByteCtr)
MasterMode = SWITCH_TO_RX_MODE; // Need to start receiving now
else
MasterMode = TX_DATA_MODE; // Continue to transmision with the data in Transmit Buffer
break;
case SWITCH_TO_RX_MODE:
UCB0IE |= UCRXIE; // Enable RX interrupt
UCB0IE &= ~UCTXIE; // Disable TX interrupt
UCB0CTLW0 &= ~UCTR; // Switch to receiver
MasterMode = RX_DATA_MODE; // State state is to receive data
UCB0CTLW0 |= UCTXSTT; // Send repeated start
if (RXByteCtr == 1)
{
//Must send stop since this is the N-1 byte
while((UCB0CTLW0 & UCTXSTT));
UCB0CTLW0 |= UCTXSTP; // Send stop condition
}
break;
case TX_DATA_MODE:
if (TXByteCtr)
{
UCB0TXBUF = TransmitBuffer[TransmitIndex++];
TXByteCtr--;
}
else
{
//Done with transmission
UCB0CTLW0 |= UCTXSTP; // Send stop condition
MasterMode = IDLE_MODE;
UCB0IE &= ~UCTXIE; // disable TX interrupt
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
break;
default:
__no_operation();
break;
}
break;
default: break;
}
}
void ser_output(char *str)
{
while(*str !=0)
{
while(!(UCA0IFG&UCTXIFG));
UCA0TXBUF = *str++;
}
}
void gpioSetup()
{
P1OUT &= ~BIT0; // Clear P1.0 output latch
P1DIR |= BIT0; // For LED
P1SEL1 |= BIT6 | BIT7; // I2C pins
P2SEL1 |= BIT0 | BIT1; // USCI_A0 UART operation
P2SEL0 &= ~(BIT0 | BIT1);
PM5CTL0 &= ~LOCKLPM5;
}
void clockSetup()
{
FRCTL0 = FRCTLPW | NWAITS_1;
CSCTL0_H = CSKEY >> 8;
CSCTL1 = DCORSEL | DCOFSEL_0;
CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;
CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1;
CSCTL0_H = 0;
}
void uartSetup()
{
UCA0CTL1 |= UCSWRST;
UCA0CTL1 |= UCSSEL_2;
UCA0BR0 = 6;
UCA0BR1 = 0;
UCA0MCTLW = 0xAA;
UCA0MCTLW |= UCOS16 | UCBRF_1;
UCA0CTL1 &= ~UCSWRST;
UCA0IE |= UCRXIE;
}
void i2cSetup()
{
UCB0CTLW0 |= UCSWRST;
UCB0CTLW0 |= UCMODE_3 | UCMST | UCSSEL__SMCLK | UCSYNC;
UCB0CTLW1 |= UCSSEL_2;
UCB0BRW = 10;
UCB0I2CSA = 0x0048;
UCB0CTLW0 &= ~UCSWRST;
UCB0IE |= UCRXIE | UCNACKIE | UCBCNTIE;
}
我得到以下数据:
Temperature values in ReceviedBuffer, and transmitted value to PuTTY terminal
(i) 我的第一个问题是为什么我在终端上得到 RecevieBuffer1 值和 RecevieBuffer[0].
的缺失值
(ii) 我的第二个问题是如何将 16 位原始数据转换为摄氏度值。
非常感谢
要从您的字节缓冲区中获取 16 位值,您需要将每个字节转换为 16 位值,将第二个字节移动 8 位,然后将两者相加。在一行中它看起来像这样:
int16_t value = int16_t(buffer[0]) | int16_t(buffer[1]) << 8;
根据您读取的 0x0aaf 值,我猜您使用的温度传感器可能会输出以摄氏度*100 为单位的值,以使其保持整数并仍然具有 100 度精度。因此,要获得以摄氏度为单位的值,您必须转换为浮点数或双精度数并除以 100.0。所以0x0aaf是2735,意思是27.35摄氏度。
我正在尝试通过 I2C 协议从 TMP117 传感器 [1] connected to an MSP430FR5969 MCU [2] 读取温度值。传感器结果寄存器中的数据为二进制补码格式,数据宽度为16位,分辨率为0.0078125℃。我使用 Code Composer Studio 对 MCU 进行编程,并附上了以下代码:
#include <msp430.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#define SLAVE_ADDR 0x48
#define CONVERSION_READY 0x10
#define TMP117_TEMP_REG 0x00
#define TMP117_CONFIG_REG 0x01
#define TMP117_RESOLUTION 0.0078125f
#define CMD_TYPE_0_SLAVE 0
#define CMD_TYPE_1_SLAVE 1
#define CMD_TYPE_2_SLAVE 2
#define CMD_TYPE_0_MASTER 3
#define CMD_TYPE_1_MASTER 4
#define CMD_TYPE_2_MASTER 5
#define TYPE_0_LENGTH 1
#define TYPE_1_LENGTH 2
#define TYPE_2_LENGTH 6
#define MAX_BUFFER_SIZE 20
char temperature[] = "Temperature is: ";
char dot[] = ".";
char celcuis[] = " degree Celcius\r\n";
int i;
char text[] = " I am an MSP430FR5969\r\n";
char rx_char[5];
volatile int rx_val = 0;
void clockSetup();
void gpioSetup();
void uartSetup();
void i2cSetup();
void ser_output(char *str);
uint8_t MasterType1 [TYPE_1_LENGTH] = {0x02, 0x20};
uint8_t SlaveType1 [TYPE_1_LENGTH] = {0};
typedef enum I2C_ModeEnum{
IDLE_MODE,
NACK_MODE,
TX_REG_ADDRESS_MODE,
RX_REG_ADDRESS_MODE,
TX_DATA_MODE,
RX_DATA_MODE,
SWITCH_TO_RX_MODE,
SWITHC_TO_TX_MODE,
TIMEOUT_MODE
} I2C_Mode;
I2C_Mode MasterMode = IDLE_MODE;
/* The Register Address/Command to use*/
uint8_t TransmitRegAddr = 0;
uint8_t ReceiveBuffer[MAX_BUFFER_SIZE] = {0};
uint8_t RXByteCtr = 0;
uint8_t ReceiveIndex = 0;
uint8_t TransmitBuffer[MAX_BUFFER_SIZE] = {0};
uint8_t TXByteCtr = 0;
uint8_t TransmitIndex = 0;
I2C_Mode I2C_Master_WriteReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t count);
I2C_Mode I2C_Master_ReadReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t count);
void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count);
I2C_Mode I2C_Master_ReadReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t count)
{
MasterMode = TX_REG_ADDRESS_MODE;
TransmitRegAddr = reg_addr;
RXByteCtr = count;
TXByteCtr = 0;
ReceiveIndex = 0;
TransmitIndex = 0;
UCB0I2CSA = dev_addr;
UCB0IFG &= ~(UCTXIFG + UCRXIFG);
UCB0IE &= ~UCRXIE;
UCB0IE |= UCTXIE;
UCB0CTLW0 |= UCTR + UCTXSTT;
__bis_SR_register(LPM0_bits + GIE);
return MasterMode;
}
I2C_Mode I2C_Master_WriteReg(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t count)
{
MasterMode = TX_REG_ADDRESS_MODE;
TransmitRegAddr = reg_addr;
CopyArray(reg_data, TransmitBuffer, count);
TXByteCtr = count;
RXByteCtr = 0;
ReceiveIndex = 0;
TransmitIndex = 0;
UCB0I2CSA = dev_addr;
UCB0IFG &= ~(UCTXIFG + UCRXIFG);
UCB0IE &= ~UCRXIE;
UCB0IE |= UCTXIE;
UCB0CTLW0 |= UCTR + UCTXSTT;
__bis_SR_register(LPM0_bits + GIE);
return MasterMode;
}
void CopyArray(uint8_t *source, uint8_t *dest, uint8_t count)
{
uint8_t copyIndex = 0;
for (copyIndex = 0; copyIndex < count; copyIndex++)
{
dest[copyIndex] = source[copyIndex];
}
}
void main(void)
{
WDTCTL = WDTPW | WDTHOLD;
clockSetup();
gpioSetup();
uartSetup();
i2cSetup();
__bis_SR_register(GIE);
while (1)
{
_delay_cycles(500000);
I2C_Master_ReadReg(SLAVE_ADDR, 0x00, TYPE_1_LENGTH);
CopyArray(ReceiveBuffer, SlaveType1, TYPE_1_LENGTH);
if(ReceiveBuffer[1] & CONVERSION_READY)
{
I2C_Master_ReadReg(SLAVE_ADDR, 0x00, TYPE_1_LENGTH);
CopyArray(ReceiveBuffer, SlaveType1, TYPE_1_LENGTH);
_no_operation();
}
ltoa(rx_val, rx_char, 10);
ser_output(temperature);
ser_output(rx_char);
ser_output(dot);
ser_output(celcuis);
}
}
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = USCI_B0_VECTOR
__interrupt void USCI_B0_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCI_B0_ISR (void)
#else
#error Compiler not supported!
#endif
{
//Must read from UCB0RXBUF
//// uint8_t rx_val = 0;
switch(__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG))
{
case USCI_NONE: break; // Vector 0: No interrupts
case USCI_I2C_UCALIFG: break; // Vector 2: ALIFG
case USCI_I2C_UCNACKIFG: // Vector 4: NACKIFG
break;
case USCI_I2C_UCSTTIFG: break; // Vector 6: STTIFG
case USCI_I2C_UCSTPIFG: break; // Vector 8: STPIFG
case USCI_I2C_UCRXIFG3: break; // Vector 10: RXIFG3
case USCI_I2C_UCTXIFG3: break; // Vector 12: TXIFG3
case USCI_I2C_UCRXIFG2: break; // Vector 14: RXIFG2
case USCI_I2C_UCTXIFG2: break; // Vector 16: TXIFG2
case USCI_I2C_UCRXIFG1: break; // Vector 18: RXIFG1
case USCI_I2C_UCTXIFG1: break; // Vector 20: TXIFG1
case USCI_I2C_UCRXIFG0: // Vector 22: RXIFG0
rx_val = UCB0RXBUF;
if (RXByteCtr)
{
ReceiveBuffer[ReceiveIndex++] = rx_val;
RXByteCtr--;
}
if (RXByteCtr == 1)
{
UCB0CTLW0 |= UCTXSTP;
}
else if (RXByteCtr == 0)
{
UCB0IE &= ~UCRXIE;
MasterMode = IDLE_MODE;
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
break;
case USCI_I2C_UCTXIFG0: // Vector 24: TXIFG0
switch (MasterMode)
{
case TX_REG_ADDRESS_MODE:
UCB0TXBUF = TransmitRegAddr;
if (RXByteCtr)
MasterMode = SWITCH_TO_RX_MODE; // Need to start receiving now
else
MasterMode = TX_DATA_MODE; // Continue to transmision with the data in Transmit Buffer
break;
case SWITCH_TO_RX_MODE:
UCB0IE |= UCRXIE; // Enable RX interrupt
UCB0IE &= ~UCTXIE; // Disable TX interrupt
UCB0CTLW0 &= ~UCTR; // Switch to receiver
MasterMode = RX_DATA_MODE; // State state is to receive data
UCB0CTLW0 |= UCTXSTT; // Send repeated start
if (RXByteCtr == 1)
{
//Must send stop since this is the N-1 byte
while((UCB0CTLW0 & UCTXSTT));
UCB0CTLW0 |= UCTXSTP; // Send stop condition
}
break;
case TX_DATA_MODE:
if (TXByteCtr)
{
UCB0TXBUF = TransmitBuffer[TransmitIndex++];
TXByteCtr--;
}
else
{
//Done with transmission
UCB0CTLW0 |= UCTXSTP; // Send stop condition
MasterMode = IDLE_MODE;
UCB0IE &= ~UCTXIE; // disable TX interrupt
__bic_SR_register_on_exit(CPUOFF); // Exit LPM0
}
break;
default:
__no_operation();
break;
}
break;
default: break;
}
}
void ser_output(char *str)
{
while(*str !=0)
{
while(!(UCA0IFG&UCTXIFG));
UCA0TXBUF = *str++;
}
}
void gpioSetup()
{
P1OUT &= ~BIT0; // Clear P1.0 output latch
P1DIR |= BIT0; // For LED
P1SEL1 |= BIT6 | BIT7; // I2C pins
P2SEL1 |= BIT0 | BIT1; // USCI_A0 UART operation
P2SEL0 &= ~(BIT0 | BIT1);
PM5CTL0 &= ~LOCKLPM5;
}
void clockSetup()
{
FRCTL0 = FRCTLPW | NWAITS_1;
CSCTL0_H = CSKEY >> 8;
CSCTL1 = DCORSEL | DCOFSEL_0;
CSCTL2 = SELA__VLOCLK | SELS__DCOCLK | SELM__DCOCLK;
CSCTL3 = DIVA__1 | DIVS__1 | DIVM__1;
CSCTL0_H = 0;
}
void uartSetup()
{
UCA0CTL1 |= UCSWRST;
UCA0CTL1 |= UCSSEL_2;
UCA0BR0 = 6;
UCA0BR1 = 0;
UCA0MCTLW = 0xAA;
UCA0MCTLW |= UCOS16 | UCBRF_1;
UCA0CTL1 &= ~UCSWRST;
UCA0IE |= UCRXIE;
}
void i2cSetup()
{
UCB0CTLW0 |= UCSWRST;
UCB0CTLW0 |= UCMODE_3 | UCMST | UCSSEL__SMCLK | UCSYNC;
UCB0CTLW1 |= UCSSEL_2;
UCB0BRW = 10;
UCB0I2CSA = 0x0048;
UCB0CTLW0 &= ~UCSWRST;
UCB0IE |= UCRXIE | UCNACKIE | UCBCNTIE;
}
我得到以下数据:
Temperature values in ReceviedBuffer, and transmitted value to PuTTY terminal
(i) 我的第一个问题是为什么我在终端上得到 RecevieBuffer1 值和 RecevieBuffer[0].
的缺失值(ii) 我的第二个问题是如何将 16 位原始数据转换为摄氏度值。
非常感谢
要从您的字节缓冲区中获取 16 位值,您需要将每个字节转换为 16 位值,将第二个字节移动 8 位,然后将两者相加。在一行中它看起来像这样:
int16_t value = int16_t(buffer[0]) | int16_t(buffer[1]) << 8;
根据您读取的 0x0aaf 值,我猜您使用的温度传感器可能会输出以摄氏度*100 为单位的值,以使其保持整数并仍然具有 100 度精度。因此,要获得以摄氏度为单位的值,您必须转换为浮点数或双精度数并除以 100.0。所以0x0aaf是2735,意思是27.35摄氏度。