This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

[参考译文] MSP430G2553:两个 MSP430g2553之间的 I2C 通信

Guru**** 1783340 points
Other Parts Discussed in Thread: MSP430G2553
请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/1423664/msp430g2553-i2c-communication-between-two-msp430g2553

器件型号:MSP430G2553

工具与软件:

我设置两个  MSP430g2553之间的 I2C 通信。 我的从器件  MSP430g2553处于传输模式。  从设备执行 ADC 过程、在该过程中、电位器连接到其中一个通道。 主器件处于接收模式、从从器件获取该数据并通过 UART 发送。 我所面临的问题是、当我在示波器上进行检查时、SCL 和 SDA 信号仍然为高电平。 我在此处包含了我的主代码和从代码。

MASTERCODE (码)...

#include <msp430.h>

unsigned char RXData[2];
unsigned int RXADCValue;    // Variable to store the reconstructed 10-bit ADC value

void configure_uart(void);     // Function to configure UART
void uart_print(char *str);    // Function to print a string over UART
void uart_print_number(unsigned char num);  // Function to print a number over UART

int main(void)
{
    WDTCTL = WDTPW + WDTHOLD;  // Stop WDT

    // ** UART Configuration **
    configure_uart();  // Initialize UART for serial communication

    P1OUT &= ~BIT0;    // P1.0 = 0 (Turn off LED)
    P1DIR |= BIT0;     // P1.0 set as output

    // ** I2C Configuration **
    P1SEL |= BIT6 + BIT7;        // Assign I2C pins to USCI_B0
    P1SEL2 |= BIT6 + BIT7;       // Assign I2C pins to USCI_B0
    UCB0CTL1 |= UCSWRST;         // Enable SW reset
    UCB0CTL0 = UCMST + UCMODE_3 + UCSYNC;  // I2C Master, synchronous mode
    UCB0CTL1 = UCSSEL_2 + UCSWRST;         // Use SMCLK, keep SW reset
    UCB0BR0 = 12;                // fSCL = SMCLK/12 = ~100kHz
    UCB0BR1 = 0;
    UCB0I2CSA = 0x048;           // Slave Address is 048h
    UCB0CTL1 &= ~UCSWRST;        // Clear SW reset, resume operation
    IE2 |= UCB0RXIE;             // Enable RX interrupt
//    RXCompare = 0;               // Used to check incoming data
//    UCB0CTL1 |= UCTXSTT;

    // Print initial message to UART
    uart_print("Starting I2C Master and UART Communication...\r\n");

    while (1)
    {
        while (UCB0CTL1 & UCTXSTP);             // Ensure stop condition got sent
        UCB0CTL1 &= ~UCTR;                      // Put it in recieve mode
        UCB0CTL1 |= UCTXSTT;                    // I2C start condition
        while (UCB0CTL1 & UCTXSTT);             // Wait for start condition to be sent
        //        UCB0CTL1 |= UCTXSTP;                    // I2C stop condition
        __bis_SR_register(CPUOFF + GIE);        // Enter LPM0 w/ interrupts

        RXADCValue = (RXData[0] << 2) | (RXData[1] >> 6);  // Combine high and low bytes

        // Print received data to UART
        uart_print("Received ADC Value: ");
        uart_print_number(RXADCValue);
        uart_print("\r\n");

//        if (RXData != RXCompare)                // Trap CPU if data is not as expected
//        {
//            P1OUT |= BIT0;                      // Turn on LED (P1.0) to indicate error
//            while (1);                          // Trap CPU
//        }
//
//        RXCompare++;                            // Increment correct RX value
    }
}

// Function to configure UART for 9600 baud rate at 1 MHz clock
void configure_uart(void)
{
    P1SEL |= BIT1 + BIT2;  // Set P1.1 = RXD, P1.2 = TXD
    P1SEL2 |= BIT1 + BIT2;
    UCA0CTL1 |= UCSWRST;   // Put state machine in reset
    UCA0CTL1 |= UCSSEL_2;  // SMCLK
    UCA0BR0 = 104;         // 1MHz 9600 (N = 1MHz/9600)
    UCA0BR1 = 0;
    UCA0MCTL = UCBRS0;     // Modulation UCBRSx = 1
    UCA0CTL1 &= ~UCSWRST;  // Initialize USCI state machine
    IE2 |= UCA0RXIE;       // Enable USCI_A0 RX interrupt
}

// Function to print a string over UART
void uart_print(char *str)
{
    while (*str != '\0')   // Loop until end of string
    {
        while (!(IFG2 & UCA0TXIFG));  // Wait until the TX buffer is ready
        UCA0TXBUF = *str++;           // Send each character
    }
}

// Function to print a number over UART as a string
void uart_print_number(unsigned char num)
{
    char buf[5];   // Buffer to hold ASCII string of the number (0-255)
    char *str = &buf[4];
    *str = '\0';
    do
    {
        *--str = (num % 10) + '0';  // Get the last digit and convert to ASCII
        num /= 10;                  // Remove the last digit
    } while (num);

    uart_print(str);  // Print the resulting number string
}

// USCI_B0 Data ISR
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCIAB0TX_VECTOR))) USCIAB0TX_ISR (void)
#else
#error Compiler not supported!
#endif
{
    static unsigned char rx_byte_count = 0;

        RXData[rx_byte_count++] = UCB0RXBUF;    // Read received byte into buffer

        if (rx_byte_count >= 2)                 // If two bytes have been received
        {
            rx_byte_count = 0;                  // Reset counter for next transmission
            __bic_SR_register_on_exit(CPUOFF);  // Exit LPM0 after two bytes are received
        }
}

从代码...

//
//******************************************************************************

#include <msp430.h>

unsigned char TXData[2] = {0,0};         // Variable to hold TX data (ADC value)
unsigned int adc_values[16];             // Buffer to hold 16 ADC samples (for the ADC reference code structure)
//unsigned int *adc_ptr = adc_values;      // Pointer to iterate through ADC buffer

void configure_adc(void);                // Function to configure ADC

int main(void)
{
    WDTCTL = WDTPW + WDTHOLD;            // Stop Watchdog

    // Configure LED on P1.0 for indication
    P1DIR |= BIT0;                       // Set P1.0 as output (LED)
    P1OUT &= ~BIT0;                      // Turn off LED initially

    // Configure I2C pins
    P1SEL |= BIT6 + BIT7;                // Assign I2C pins to USCI_B0
    P1SEL2 |= BIT6 + BIT7;

    // Configure I2C Slave
    UCB0CTL1 |= UCSWRST;                 // Enable SW reset
    UCB0CTL0 = UCMODE_3 + UCSYNC;        // I2C Slave, synchronous mode
    UCB0I2COA = 0x048;                    // Own Address is 048h
    UCB0CTL1 &= ~UCSWRST;                // Clear SW reset, resume operation
    UCB0I2CIE |= UCSTTIE;                // Enable Start condition interrupt
    IE2 |= UCB0TXIE;                     // Enable TX interrupt

    configure_adc();                     // Configure the ADC for reading


    // Infinite loop to keep the code running
    while (1)
    {
        __bis_SR_register(CPUOFF + GIE);   // Enter LPM0 with interrupts enabled
    }
}

// Function to configure ADC for multi-channel sampling as in the reference code
void configure_adc(void)
{

    ADC10CTL1 = INCH_5 + CONSEQ_2;           // A2 repeat CHANNEL CONVERSION
    ADC10CTL0 = SREF_0 + ADC10SHT_2 + MSC + ADC10ON + ADC10IE; // Sample and Hold Time + Multi-Sample Conversion + ADC on + Enable Interrupt
    ADC10AE0 = BIT5;                         // Enable analog input P1.5
    ADC10DTC1 = 1;                        // 16 conversions (reference code)
}

// ADC10 interrupt service routine to handle ADC conversion completion
#pragma vector = ADC10_VECTOR
__interrupt void ADC10_ISR(void)
{
    unsigned int adc_value = ADC10MEM;
    TXData[0] = (unsigned char)((adc_value >> 2) & 0xFF);   // Read the lower8 bits of ADC value
    TXData[1] = (unsigned char)((adc_value & 0x03) << 6);
    P1OUT ^= BIT0;                               // Toggle LED to indicate ADC conversion
    __bic_SR_register_on_exit(CPUOFF);           // Exit LPM0
}

// USCI_B0 Data ISR to transmit data to the I2C master
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = USCIAB0TX_VECTOR
__interrupt void USCIAB0TX_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCIAB0TX_VECTOR))) USCIAB0TX_ISR (void)
#else
#error Compiler not supported!
#endif
{
    static unsigned char byte_counter = 0;

        // Send the high byte first, followed by the low byte
        UCB0TXBUF = TXData[byte_counter++];      // Load TX buffer with the current byte to send to master

        if (byte_counter >= 2)                   // If both bytes have been sent
        {
            byte_counter = 0;                    // Reset counter for next transmission
        }

        __bic_SR_register_on_exit(CPUOFF);       // Exit LPM0
}

// USCI_B0 State ISR for handling start condition
#if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__)
#pragma vector = USCIAB0RX_VECTOR
__interrupt void USCIAB0RX_ISR(void)
#elif defined(__GNUC__)
void __attribute__ ((interrupt(USCIAB0RX_VECTOR))) USCIAB0RX_ISR (void)
#else
#error Compiler not supported!
#endif
{
    UCB0STAT &= ~UCSTTIFG;   // Clear start condition interrupt flag

    // Trigger ADC sampling when I2C start condition is detected
    ADC10CTL0 &= ~ENC;       // Disable ADC before starting new conversion
    while (ADC10CTL1 & ADC10BUSY);  // Wait if ADC is busy
    ADC10CTL0 |= ENC + ADC10SC;     // Enable and start ADC sampling
}

I ma 通过10k 上拉电阻器连接 SDA 和 SCL。 我有一个公共接地和电源。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您是否正在使用 Launchpad? 如果是、您是否从 J7 (P1.6/LED)上移除了跳线?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    是的、我正在使用 LaunchPad、并且在使用之前移除了跳线 J7。 我的代码是否正确、或者它们有一些问题。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我看不出你所做的事情有什么明显的错误,但这也在我的测试设备上失败了,所以这是我们都缺少的东西。 我还没有找到原因。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我看到了与您相同的症状(UCTXSTT 之后完全没有活动)。 经过大量实验、我尝试使用更强的上拉电阻(4.7K)、它立即开始工作。 我不知道为什么会这样。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您是否收到了正确的 ADC 值?

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我没有将 A5引脚连接到任何东西、因此我不知道 ADC 数据(在主器件处)是否合理。

    我确实注意到一些异常行为、我想一旦您超过了最初的症状、您就会修复(根据您的偏好)。

    首先、由于主控方从不发出停止命令(UCTXSTP)、它不断地读取 Rx 字节、并且几乎将所有字节都丢弃。 随后的启动(实际上是重复启动)会重新启动从器件、但同步可能会关闭。 我的建议:

    1) 1)在 ISR 中或从 LPM 返回后发出停止条件。 这并不完美、但它已经足够接近了。

    2)在从器件中、启动时复位 BYTE_COUNTER=0。 这将为下一个事务重新同步。

    第二、我不知道为什么(在从器件中)需要 CONSEQ=2并且 MSC=1。 这会产生大量数据、您只能使用很少的数据、并使从属设备不必要地忙碌。 你可能更喜欢 CONSEQ=0 (可能带有 I2C ISR 的完成联锁-这会很快)。  

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    我还将上拉电阻更改为4.7千欧、它现在可以正常工作。 但我在终端上接收的 ADC 数据是0。对于任何电压(使用电位器)。 我将执行你提出的建议。