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.

[参考译文] MSP430F5438A:无法通过 I2C 从 Adafruit MPRLS 压力传感器读取数据

Guru**** 2540720 points


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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/899705/msp430f5438a-can-not-read-data-from-the-adafruit-mprls-pressure-sensor-via-i2c

器件型号:MSP430F5438A

大家好、我已经在 MSP4305438A 中尝试了 I2C 的基本通信。

我使用的晶体为29.5MHz。

我的目标是达到 Adafruit MPRLS 压力传感器并获取压力数据。

在上一篇文章中、我最终可以将数据发送到传感器。 我使用示波器检查信号、它可以完美地显示 SCL/SDA。

我检查 了传感器的文档、它说如果我想读取数据、步骤是:(不确定我是否误解了这一点)

发送0x30、0xAA、0x00、0x00

2.发送0x31并从从从器件读取1个字节

3.发送0x31并从从从器件读取4个字节

如下图所示(此传感器的地址为0x18):

现在、我想首先读取状态字节以检查 I2CRead 函数是否正常工作。

但是、如果我尝试从传感器读取数据。 它在 I2CRead 函数中停止、无法读取任何内容。

最糟糕的是:调用 I2CRead 函数后、无法再通过 I2C 发送数据。

如果我想让我的器件再次工作、我必须将其复位(和调试器)并删除 I2CRead 函数。

以下是我的代码:

//写入命令
U8 TXData;
U8 TXByteCtr;

//读取数据
U8 RXData;
U8 * PRxData; //指向 RX 数据
U8 RXByteCtr 的指针;
volatile U8 RxBuffer[128]; //分配128字节的 RAM


int main (void)
{
int i;
// LED 控制
P3DIR |=(BIT2|BIT3|BIT6);
P3OUT |=(BIT3|BIT6);
P3REN |=(BIT2|BIT3|BIT6);
init_clock
();_EINT);
I2CInit();
while (1)
{
I2CWrite (0x30);
I2CWrite (0xAA);
I2CWrite (0x00);
I2CWrite (0x00);
I2CWrite (0x31);
U8测试= I2CRead ();
}
/

*********
函数:init_clock
用途:初始系统时钟
参数:无
返回值:无
/
void init_clock (void)
{
unsigned int i;
WDTCTL = WDTPW + WDTHOLD;//停止看门狗计时器
P5SEL |= 0x0C;//端口选择 XT2
UCSCTL6 &=~XT2OFF;//即使未使用
也可以
启用 XT2 #ifdef crystal_295 CLR6 |= 0xT2OFF

;//如果未使用则启用 // FLLref = REFO
UCSCTL4 |= SELA_XT2CLK;//从 XT2-16M
UCSCTL4中选择源|= IVA_5 + SELM_5;// SMCLK=MCLK=XT2-16M
_NOP ();
#ifdef CRYS_OSCTL295 |
= DIVA_5 + SEL_;// XFFT2+
D_+ DCODx


~+ DFFD_+ Dx + DFFDx + Dx + T2M_+ T2M_+ DFFT2M_+ DFFDx + T2M_+ DFFDCO+ Dx + DFFDx + Dx + T2M_+ DFFT2M_+ DFFDCO+ Dx + DFFDx + Dx + DFFT2M_+ D
~ //清除
(i=0;i<0xFFFF;i++)的故障标志;// OSC 稳定的延迟
} while (SFRIFG1&OFIFG);//测试振荡器故障标志
}

void I2CInit()
{
P3SEL |= BIT7; //将 I2C 引脚分配给 USCI_B0
P5SEL |= BIT4;
UCB1CTL1 |= UCSWRST; //启用 SW 复位
UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C 主设备,同步模式
UCB1CTL1 = UCSSEL_SMCLK + UCSWRST; //使用 SMCLK、保持软件复位
UCB1BR0 = 12; // fSCL = SMCLK/12 =~100kHz
UCB1BR1 = 0;
UCB1I2CSA = 0x18; //从器件地址为048h
UCB1CTL1 &=~UCSWRST; //清除 SW 复位,恢复操作
UCB1IE |= UCTXIE;

}//-----------


// USCIAB0_ISR 的结构使其可用于通过
预加载带有字节计数的 TXByteCtr 来发送任何//字节数。
///----------------------------------

#pragma vector = USCI_B1_Vector
__INTERRUPT void USCI_B1_ISR (void)

{
switch (_even_in_range (UCB1IV、12))
{
case 0:break; //向量0:无中断
情况2:中断; //向量2:ALIFG
情况4:中断; //向量4:NACKIFG
情况6:中断; //向量6:STTIFG
情况8:中断; //向量8:STPIFG
情况10: //向量10:RXIFG
RXData = UCB1RXBUF; //获取 RX 数据
_BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//退出活动 CPU
中断;
情况12: //向量12:TXIFG
IF (TXByteCtr) //检查 TX 字节计数器
{
UCB1TXBUF = TXData; //加载 TX 缓冲区
TXByteCtr --; //减量 TX 字节计数
器}
其他
{
UCB1CTL1 |= UCTXSTP; // I2C 停止条件
UCB1IFG &=~UCTXIFG; //清除 USCI_B0 TX int 标志
_BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//退出 LPM0
}
中断;
默认值:中断;
}



/*********
函数:I2CWrite
Purpose:Write 1 byte via I2C
parameter:unsigned char
return value:none
/
void I2CWrite (U8 cmd)
{
TXByteCtr = 1; //加载 TX 字节计数器
TXData = cmd;
UCB1IE &=~UCRXIE; //启用 TX 中断
UCB1IE |= UCTXIE; //启用 TX 中断

while (UCB1CTL1 & UCTXSTP); //确保发送了停止条件
UCB1CTL1 |= UCTR + UCTXSTT; // I2C TX、启动条件


_bis_SR_register (LPM0_bits + GIE); //输入带中断的 LPM0
__no_operation(); //保持在 LPM0中直到所有数据
//是 TX
//增加数据字节
}

/*********
函数:I2CRead
用途:通过 I2C
参数写入1个字节:无符号字符
返回值:无
/
U8 I2CRead ()
{
UCB1IE &=~UCTXIE; //启用 TX 中断
UCB1IE |= UCRXIE; //启用 TX 中断
while (UCB1CTL1 & UCTXSTP); //确保发送了停止条件
UCB1CTL1 |= UCTXSTT; // I2C 启动条件
while (UCB1CTL1 & UCTXSTT); //起始条件是否已发送?
UCB1CTL1 |= UCTXSTP; // I2C 停止条件

_bis_SR_register (LPM0_bits + GIE); //输入 LPM0,启用中断
__no_operation(); //用于调试器

返回 RXData
;} 

我不确定我的代码发生了什么情况。

是否有人可以帮助我解决此问题?

非常感谢您的参与。

Michelle

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

    I2C_Write 设置 UCTR、但 I2C_Read 不清除它。 (它会卡住、因为这会使它成为主发送器、而主发送器永远不会看到 RXIFG。)

    在设置 STT 之前的一段时间内、将此值添加到 I2C_Read 中:

    > UCB1CTL1 &=~UCTR;   //主接收器

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

    嘿、Michelle、

    您是否在  http://dev.ti.com/tirex/explore/node?node=ALHXCIM3yLjgI9OmNVYxDA__IOGqZri__LATEST 上查看了我们的 I2C 标准主设备示例 

    我会尝试运行该示例。  您应该能够开箱即用、以查看 I2C 是否正在运行。  甚至可以在 "示例命令"#define 部分中加载从器件地址和一些寄存器地址、以便从传感器获取一些响应。  然后您可以从此处进行比较。   

    谢谢、

    JD

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

    尊敬的 Bruce McKenney:

    非常感谢您的帮助。 添加  UCB1CTL1 &=~UCTR 后、我可以成功读取数据。

    但是、我尝试像这样重写我的代码、但它有一些问题...

    #include 
    
    /*精确宽度有符号整数类型*/
    typedef signed char int8_t;
    typedef int8_t S8;
    typedef S8 Rets8;
    typedef signed short int int16_t;
    typedef int16_t S16;
    typedef int16 Rets16;
    typedef signed int int32_t;
    tyf int8_t
    
    ;tynttyf int8_t;ttyf int8_t int8;turt int8
    
    
    typedef U8 RetU8;
    typedef unsigned short int uint16_t;
    typedef uint16_t U16;
    typedef U16 RetU16;
    typedef unsigned int uint32_t;
    typedef uint32_t U32;
    typedef U32
    
    
    ;#define port (port)(P# unsigned int uint32_t);tydefine 3 ^
    
    (#define DDR_port)<#define 3 (#define #define 3)#define 3 (#define TRY_TRU3)<#define 3 (define 3)#define 3 (#define (0x18)//<最常见的 I2C 地址
    #define MPRLS_STATUS_PUSTONGLE (0x40)//<状态 SPI 受电位
    #define MPRLS_STATUS_BUSY (0x20)//<状态忙位
    #define MPRLS_STATUS_FAILED (0x04)//<完整性故障的状态位
    #define MPRLS_STATUS_MATHSAT (0x01)//<数学饱和
    
    #define PSI_max 25
    #define PSI_MIN 0
    
    
    #define CRYSTICAL_295
    #ifdef CRYSTICL_295
    #define AccessTimer (29500000 / 2000)
    #endif
    
    //写入命令
    U8 TXData;
    U8 TXByteCtr;
    
    //读取数据
    U8 RXData;
    U8 * PRxData; //指向 RX 数据
    U8 RXByteCtr 的指针;
    volatile U8 RxBuffer[128]; //分配128字节的 RAM
    U8测试;
    U8数据[4];
    U32 ret;
    float psi;
    
    void init_clock (void);
    void I2CInit();
    void I2CWrite (U8 cmd);
    U8 I2CRead ();
    
    U16 Timer0Cnt = 0;
    void Init_Timer0 (void);
    void Delayms (U16延迟);
    
    int main (void)
    {
    int i;
    // LED Control
    P3DIR |=(BIT2|BIT6|BIT3|BIT6|BIT3|BIT0|BIT3
    )
    
    
    ;BIT|BIT|BIT|BIT3|BIT|BIT|BIT3|BIT|BIT|BIT|BIT|3 (BIT|BIT|BIT|BIT|BIT|BIT|BIT|BIT|3)
    _EINT();
    I2CInit();
    
    while (1)
    {
    I2CWrite (0x30);
    I2CWrite (0xAA);
    I2CWrite (0x00);
    I2CWrite (0x00);
    Delayms(10);
    
    I2CWrite (0x31);
    TEST = I2CRead ();
    
    I2CWrite (0x31);
    DATA[0]= I2CRead ();
    DATA[1]= I2CRead ();
    DATA[2]= I2CRead ();
    data[3]= I2CRead ();
    
    Delayms (100);
    }
    
    
    
    /*********
    函数:init_clock
    用途:初始系统时钟
    参数:无
    返回值:无
    /
    void init_clock (void)
    {
    unsigned int i;
    WDTCTL = WDTPW + WDTHOLD;//停止看门狗计时器
    P5SEL |= 0x0C;//端口选择 XT2
    UCSCTL6 &=~XT2OFF;//即使未使用
    #ifdef crystal_295、也能使能端 XT2
    UCSCTL6 |= 0xC000;//即使未使用
    也能使能端 XT2 #endif
    UCSCTL3 |= SELREF_2;// FLLref = REFO
    UCSCTL4 |= SELA_XT2CLK;//从 XT2-16M 中选择源
    UCSCTL4 |= SELS_5 + SELM_5;// SMCLK=MCLK=XT2-16M
    _NOP();
    #ifdef crystal_295
    UCSCTL5 |= DIVM__2 + DIVS__32+ DIVA__2;//晶体-> 29.5MHz
    #endif
    操作
    {
    UCSCTL7 &=~(XT2OFFG + XT1LFOFFG + DCOFFG);//清除 XT2、XT1、DCO 故障标志
    SFRIFG1 &=~OFIFG;//清除故障标志
    for (i=0;i<0xFFFF;i++);// OSC 稳定的延迟
    } while (SFRIFG1&OFIFG);//测试振荡器故障标志
    }
    
    void I2CInit()
    {
    P3SEL |= BIT7; //将 I2C 引脚分配给 USCI_B0
    P5SEL |= BIT4;
    UCB1CTL1 |= UCSWRST; //启用 SW 复位
    UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C 主设备,同步模式
    UCB1CTL1 = UCSSEL_SMCLK + UCSWRST; //使用 SMCLK、保持软件复位
    UCB1BR0 = 12; // fSCL = SMCLK/12 =~100kHz
    UCB1BR1 = 0;
    UCB1I2CSA = 0x18; //从器件地址为048h
    UCB1CTL1 &=~UCSWRST; //清除 SW 复位,恢复操作
    UCB1IE |= UCTXIE;
    
    }//-----------
    
    
    // USCIAB0_ISR 的结构使其可用于通过
    预加载带有字节计数的 TXByteCtr 来发送任何//字节数。
    ///----------------------------------
    
    #pragma vector = USCI_B1_Vector
    __INTERRUPT void USCI_B1_ISR (void)
    
    {
    switch (_even_in_range (UCB1IV、12))
    {
    case 0:break; //向量0:无中断
    情况2:中断; //向量2:ALIFG
    情况4:中断; //向量4:NACKIFG
    情况6:中断; //向量6:STTIFG
    情况8:中断; //向量8:STPIFG
    情况10: //向量10:RXIFG
    RXData = UCB1RXBUF; //获取 RX 数据
    _BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//退出活动 CPU
    中断;
    情况12: //向量12:TXIFG
    IF (TXByteCtr) //检查 TX 字节计数器
    {
    UCB1TXBUF = TXData; //加载 TX 缓冲区
    TXByteCtr --; //减量 TX 字节计数
    器}
    其他
    {
    UCB1CTL1 |= UCTXSTP; // I2C 停止条件
    UCB1IFG &=~UCTXIFG; //清除 USCI_B0 TX int 标志
    _BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//退出 LPM0
    }
    中断;
    默认值:中断;
    }
    
    
    
    /*********
    函数:I2CWrite
    Purpose:Write 1 byte via I2C
    parameter:unsigned char
    return value:none
    /
    void I2CWrite (U8 cmd)
    {
    TXByteCtr = 1; //加载 TX 字节计数器
    TXData = cmd;
    UCB1IE &=~UCRXIE; //启用 TX 中断
    UCB1IE |= UCTXIE; //启用 TX 中断
    
    while (UCB1CTL1 & UCTXSTP); //确保发送了停止条件
    UCB1CTL1 |= UCTR + UCTXSTT; // I2C TX、启动条件
    
    
    _bis_SR_register (LPM0_bits + GIE); //输入带中断的 LPM0
    __no_operation(); //保持在 LPM0中直到所有数据
    //是 TX
    //增加数据字节
    }
    
    /*********
    函数:I2CRead
    用途:通过 I2C
    参数写入1个字节:无符号字符
    返回值:无
    /
    U8 I2CRead ()
    {
    UCB1IE &=~UCTXIE; //启用 TX 中断
    UCB1IE |= UCRXIE; //启用 TX 中断
    while (UCB1CTL1 & UCTXSTP); //确保发送了停止条件
    UCB1CTL1 &=~UCTR; //主接收器
    UCB1CTL1 |= UCTXSTT; // I2C 启动条件
    while (UCB1CTL1 & UCTXSTT); //起始条件是否已发送?
    UCB1CTL1 |= UCTXSTP; // I2C 停止条件
    
    _bis_SR_register (LPM0_bits + GIE); //输入 LPM0,启用中断
    __no_operation(); //用于调试器
    
    返回 RXData;
    }
    
    void Init_Timer0 (void)
    {
    TA0CTL = 0 //
    |(1 << 2)//
    |(1 << 8);//
    TA0CCR0 =访问计时器;//
    TA0CCTL0 = 0 //
    |(1 << 4);//
    TA0CTL |=(1 << 4);//
    }
    
    #pragma vector=TIMER0_A0_VECTOR
    __INTERRUPT void Timer0_A0 (void)
    {
    TA0CCR0 =访问定时器;//复位定时器 A 计数器
    if (Timer0Cnt!= 0)
    {
    Timer0Cnt--;
    }
    }
    
    /*********
    功能:延迟
    用途:延迟功能, 1ms 基本
    参数:无
    返回值:无
    /
    空延迟(U16延迟)
    {
    Timer0Cnt =延迟;
    while (Timer0Cnt!= 0);
    }
    

    在这种情况    下、变量 test 将始终为0x60、数组数据将始终为0x60、0x40、0x40、0x40、0x40、不会改变。

    我不确定我是否误解了数据表上的内容。  

    提前感谢您。

    Michelle

    [引用用户="Bruce McKenney47378"]

    I2C_Write 设置 UCTR、但 I2C_Read 不清除它。 (它会卡住、因为这会使它成为主发送器、而主发送器永远不会看到 RXIFG。)

    在设置 STT 之前的一段时间内、将此值添加到 I2C_Read 中:

    > UCB1CTL1 &=~UCTR;   //主接收器

    [/报价]

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

    您的 I2C_Read 和 I2C_WRITE 函数仅支持1字节(不包括 SLA)事务(即每个调用都会创建一个新事务)。 根据 MPR 数据表表表表15、MPR 传感器需要3字节写入事务和4字节读取事务。

    60-60-60-40-40-40序列是读取状态寄存器[参考表14] 5次[如表15步骤2]的结果。 前两个指示繁忙、其余仅"通电"。 由于没有事务读取其他3个字节[表15步骤3]、因此您不会获取数据。

    我建议您仔细阅读上面提到的 JD 示例、看看它是如何进行多字节事务的。

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

    尊敬的 JD:

    感谢您的建议。  

    是的、我之前看过这个示例、但我不确定 I2C_Master_WriteReg 和 I2C_Master_ReadReg 中的参数 reg_addr

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

    我想确认:在我的例子中、reg_addr 0x30用于写入、0x31用于读取?  

    Michelle

    [引用用户="JD Crutchfield"]

    嘿、Michelle、

    您是否在  http://dev.ti.com/tirex/explore/node?node=ALHXCIM3yLjgI9OmNVYxDA__IOGqZri__LATEST 上查看了我们的 I2C 标准主设备示例 

    我会尝试运行该示例。  您应该能够开箱即用、以查看 I2C 是否正在运行。  甚至可以在 "示例命令"#define 部分中加载从器件地址和一些寄存器地址、以便从传感器获取一些响应。  然后您可以从此处进行比较。   

    谢谢、

    JD

    [/报价]

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

    尊敬的 Bruce McKenney:

    感谢您的建议。

    我将引用 msp430x54xA_USCI_i2c_standard_master.c 来表示多个字节的写入/读取和发布结果。

    非常感谢!

    Michelle

    [引用用户="Bruce McKenney47378"]

    您的 I2C_Read 和 I2C_WRITE 函数仅支持1字节(不包括 SLA)事务(即每个调用都会创建一个新事务)。 根据 MPR 数据表表表表15、MPR 传感器需要3字节写入事务和4字节读取事务。

    60-60-60-40-40-40序列是读取状态寄存器[参考表14] 5次[如表15步骤2]的结果。 前两个指示繁忙、其余仅"通电"。 由于没有事务读取其他3个字节[表15步骤3]、因此您不会获取数据。

    我建议您仔细阅读上面提到的 JD 示例、看看它是如何进行多字节事务的。

    [/报价]

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

    再次查看 i2c_standard_master、它似乎遵循大多数 I2C 器件使用的"寄存器"模型、而 MPR 不是这样。 您可以更好地将 msp430x54xA_uscib0_i2c_08.c 和_10.c 组合在一起、这样可以执行简单的读取和写入操作。 您的 I2C 器件地址(I2CSA)为0x18。

    http://dev.ti.com/tirex/explore/node?node=AJVzsnQtq6Z.R.GWKeoUfg__IOGqZri__LATEST

    http://dev.ti.com/tirex/explore/node?node=AEr-n1WlVkjcSFJzHJwUOQ__IOGqZri__LATEST

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

    尊敬的 Bruce McKenney:

    感谢您的建议。 我已经尝试将您提到的两个示例代码组合在一起。 但是、与之前的帖子一样、它始终可以读取状态数据0x40的1个字节...

    以下是我的最新代码和调试过程的屏幕截图:

    #include 
    
    /*精确宽度有符号整数类型*/
    typedef signed char int8_t;
    typedef int8_t S8;
    typedef S8 Rets8;
    typedef signed short int int16_t;
    typedef int16_t S16;
    typedef int16 Rets16;
    typedef signed int int32_t;
    tyf int8_t
    
    ;tynttyf int8_t;ttyf int8_t int8;turt int8
    
    
    typedef U8 RetU8;
    typedef unsigned short int uint16_t;
    typedef uint16_t U16;
    typedef U16 RetU16;
    typedef unsigned int uint32_t;
    typedef uint32_t U32;
    typedef U32
    
    
    ;#define port (port)(P# unsigned int uint32_t);tydefine 3 ^
    
    (#define DDR_port)<#define 3 (#define #define 3)#define 3 (#define TRY_TRU3)<#define 3 (define 3)#define 3 (#define (0x18)//<最常见的 I2C 地址
    #define MPRLS_STATUS_PUSTONGLE (0x40)//<状态 SPI 受电位
    #define MPRLS_STATUS_BUSY (0x20)//<状态忙位
    #define MPRLS_STATUS_FAILED (0x04)//<完整性故障的状态位
    #define MPRLS_STATUS_MATHSAT (0x01)//<数学饱和
    
    #define PSI_max 25
    #define PSI_MIN 0
    
    
    #define CRYSTICAL_295
    #ifdef CRYSTICAL_295
    #define AccessTimer (29500000 / 2000)
    #endif
    
    //用于写入命令
    U8 * PTxData; //指向 TX 数据
    U8 TXByteCtr 的指针;
    
    const unsigned char TxData[]= //要发送
    的数据表{
    0x30、
    0xAA、
    0x00、
    0x00
    };
    
    const unsigned char TxData2[]= //要发送
    的数据表{
    0x31}
    ;
    
    
    //要读取数据
    U8 RXData;
    U8 * PRxData; //指向 RX 数据
    U8 RXByteCtr 的指针;
    volatile U8 RxBuffer[128]; //分配128字节的 RAM
    U8测试;
    U8数据[4];
    U32 ret;
    float psi;
    
    void init_clock (void);
    void I2CInit();
    void I2CWrite (void);
    void I2CWrite2 (void);
    void I2CRead (U8 cnt);
    
    U16 Timer0Cnt = 0;
    void Init_Timer0 (void);
    void Delayms (U16 delay);
    
    int main (
    
    
    
    
    OUT){int i;// LED Control P3|BIT6|BITRF|3 (BITE|BITE|BITE|BITE|BITE|3
    
    
    );(BITE|BITE|BITE|BITE|BITE|BITE|BITE|BITE|3)
    _EINT();
    I2CInit();
    
    while (1)
    {
    I2CWrite();
    Delayms(10);
    I2CWrite2();
    I2CRead (1);
    TEST = RxBuffer[0];
    I2CWrite2();
    I2CRead (4);
    Delayms (10);
    }
    
    
    
    /*********
    函数:init_clock
    用途:初始系统时钟
    参数:无
    返回值:无
    /
    void init_clock (void)
    {
    unsigned int i;
    WDTCTL = WDTPW + WDTHOLD;//停止看门狗计时器
    P5SEL |= 0x0C;//端口选择 XT2
    UCSCTL6 &=~XT2OFF;//即使未使用
    #ifdef crystal_295、也能使能端 XT2
    UCSCTL6 |= 0xC000;//即使未使用
    也能使能端 XT2 #endif
    UCSCTL3 |= SELREF_2;// FLLref = REFO
    UCSCTL4 |= SELA_XT2CLK;//从 XT2-16M 中选择源
    UCSCTL4 |= SELS_5 + SELM_5;// SMCLK=MCLK=XT2-16M
    _NOP();
    #ifdef crystal_295
    UCSCTL5 |= DIVM__2 + DIVS__32+ DIVA__2;//晶体-> 29.5MHz
    #endif
    操作
    {
    UCSCTL7 &=~(XT2OFFG + XT1LFOFFG + DCOFFG);//清除 XT2、XT1、DCO 故障标志
    SFRIFG1 &=~OFIFG;//清除故障标志
    for (i=0;i<0xFFFF;i++);// OSC 稳定的延迟
    } while (SFRIFG1&OFIFG);//测试振荡器故障标志
    }
    
    void I2CInit()
    {
    P3SEL |= BIT7; //将 I2C 引脚分配给 USCI_B0
    P5SEL |= BIT4;
    UCB1CTL1 |= UCSWRST; //启用 SW 复位
    UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C 主设备,同步模式
    UCB1CTL1 = UCSSEL_SMCLK + UCSWRST; //使用 SMCLK、保持软件复位
    UCB1BR0 = 12; // fSCL = SMCLK/12 =~100kHz
    UCB1BR1 = 0;
    UCB1I2CSA = 0x18; //从器件地址为048h
    UCB1CTL1 &=~UCSWRST; //清除 SW 复位,恢复操作
    UCB1IE |= UCTXIE;
    
    }//-----------
    
    
    // USCIAB0_ISR 的结构使其可用于通过
    预加载带有字节计数的 TXByteCtr 来发送任何//字节数。
    ///----------------------------------
    
    #pragma vector = USCI_B1_Vector
    __INTERRUPT void USCI_B1_ISR (void)
    
    {
    switch (_even_in_range (UCB1IV、12))
    {
    case 0:break; //向量0:无中断
    情况2:中断; //向量2:ALIFG
    情况4:中断; //向量4:NACKIFG
    情况6:中断; //向量6:STTIFG
    情况8:中断; //向量8:STPIFG
    情况10: //向量10:RXIFG
    RXByteCtr---; //递减 RX 字节计数器
    IF (RXByteCtr)
    {
    * PRxData++= UCB1RXBUF; //将 RX 数据移动到地址 PRxData
    IF (RXByteCtr = 1) //只剩下一个字节?
    UCB1CTL1 |= UCTXSTP; //生成 I2C 停止条件
    }
    其他
    {
    * PRxData = UCB1RXBUF; //将最终 RX 数据移动到 PRxData
    __BIC_SR_REGISTER_ON_EXIT (LPM0_Bits);//退出活动 CPU
    }
    中断;
    案例12: //向量12:TXIFG
    IF (TXByteCtr) //检查 TX 字节计数器
    {
    UCB1TXBUF =* PTxData++; //加载 TX 缓冲区
    TXByteCtr --; //减量 TX 字节计数
    器}
    其他
    {
    UCB1CTL1 |= UCTXSTP; // I2C 停止条件
    UCB1IFG &=~UCTXIFG; //清除 USCI_B0 TX int 标志
    _BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//退出 LPM0
    }
    默认值:break;
    }
    
    
    
    /*********
    函数:I2CWrite
    Purpose:Write 1 byte via I2C
    parameter:unsigned char
    return value:none
    /
    void I2CWrite (void)
    {
    Delayms(50岁); //事务之间需要延迟
    PTxData =(U8 *) TxData; // TX 数组起始地址
    //在此处放置断点以查看每个断点
    //发送操作。
    TXByteCtr = TxData 的大小; //加载 TX 字节计数器
    UCB1IE &=~UCRXIE; //启用 TX 中断
    UCB1IE |= UCTXIE; //启用 TX 中断
    
    UCB1CTL1 |= UCTR + UCTXSTT; // I2C TX、启动条件
    
    _bis_SR_register (LPM0_bits + GIE); //输入 LPM0,启用中断
    __no_operation(); //保持在 LPM0中直到所有数据
    //是 TX
    while (UCB1CTL1 & UCTXSTP); //确保已发送停止条件
    }
    
    /*********
    函数:I2CWrite
    Purpose:Write 1 byte via I2C
    parameter:unsigned char
    return value:none
    /void
    I2CWrite2(void){
    
    Delayms(50岁); //事务之间需要延迟
    
    PTxData =(U8 *) TxData2; // TX 数组起始地址
    //在此处放置断点以查看每个断点
    //发送操作。
    TXByteCtr = TxData2的大小; //加载 TX 字节计数器
    UCB1IE &=~UCRXIE; //启用 TX 中断
    UCB1IE |= UCTXIE; //启用 TX 中断
    
    UCB1CTL1 |= UCTR + UCTXSTT; // I2C TX、启动条件
    
    _bis_SR_register (LPM0_bits + GIE); //输入 LPM0,启用中断
    __no_operation(); //保持在 LPM0中直到所有数据
    //是 TX
    while (UCB1CTL1 & UCTXSTP); //确保已发送停止条件
    }
    
    /*********
    函数:I2CRead
    用途:通过 I2C
    参数写入1个字节:无符号字符
    返回值:无
    /
    void I2CRead (U8 cnt)
    {
    
    PRxData =(U8 *) RxBuffer;// RX 缓冲区开始
    RXByteCtr = cnt; //加载 RX 字节计数器
    UCB1IE &=~UCTXIE; //启用 TX 中断
    UCB1IE |= UCRXIE; //启用 TX 中断
    while (UCB1CTL1 & UCTXSTP); //确保发送了停止条件
    UCB1CTL1 &=~UCTR; //主接收器
    UCB1CTL1 |= UCTXSTT; // I2C 启动条件
    
    _bis_SR_register (LPM0_bits + GIE); //输入 LPM0,启用中断
    //保持在 LPM0中直到所有数据
    //是 RX
    __no_operation(); //设置断点>>此处<<和
    }
    
    void Init_Timer0 (void)
    {
    TA0CTL = 0 //
    |(1 << 2)//
    |(1 << 8);//
    TA0CCR0 =访问计时器;//
    TA0CCTL0 = 0 //
    |(1 << 4);//
    TA0CTL |=(1 << 4);//
    }
    
    #pragma vector=TIMER0_A0_VECTOR
    __INTERRUPT void Timer0_A0 (void)
    {
    TA0CCR0 =访问定时器;//复位定时器 A 计数器
    if (Timer0Cnt!= 0)
    {
    Timer0Cnt--;
    }
    }
    
    /*********
    功能:延迟
    用途:延迟功能, 1ms 基本
    参数:无
    返回值:无
    /
    空延迟(U16延迟)
    {
    Timer0Cnt =延迟;
    while (Timer0Cnt!= 0);
    }
    

    我为 I2CWrite 编写两个函数、以轻松实现不同的命令写入过程。 I2CRead 从传感器读取多个字节。

    I2CWrite -向 MPRLS 传感器发送0x30、0xAA、0x00、0x00

    -I2CWrite2 - 向 MPRLS 传感器发送0x31

    -I2CRead -可以传递从 MPRLS 传感器读取 cnt 字节的参数。 所有读取数据都将存储在 RxBuffer 中

    设置一些断点后,我注意到,即使我尝试通过调用 I2CRead ()来读取4个字节,也只能读取第一个字节:

    调用 I2CRead (1)从传感器读取一个字节状态后、变量 test 将从 RxBuffer[0]获取值并设置为0x40。 我认为这意味着传感器工作正常。

    再次发送0x31后、该过程将进入  I2CRead (4)获取4字节数据。 但是、只更新了 RxBuffer[0]、并且我再次只得到0x40。

    您对哪一部分出错有什么想法吗?

    非常感谢您的帮助。

    Michelle

    [引用用户="Bruce McKenney47378"]

    再次查看 i2c_standard_master、它似乎遵循大多数 I2C 器件使用的"寄存器"模型、而 MPR 不是这样。 您可以更好地将 msp430x54xA_uscib0_i2c_08.c 和_10.c 组合在一起、这样可以执行简单的读取和写入操作。 您的 I2C 器件地址(I2CSA)为0x18。

    http://dev.ti.com/tirex/explore/node?node=AJVzsnQtq6Z.R.GWKeoUfg__IOGqZri__LATEST

    http://dev.ti.com/tirex/explore/node?node=AEr-n1WlVkjcSFJzHJwUOQ__IOGqZri__LATEST

    [/报价]

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    >constunsigned charTxData[] =              // Table of data to transmit
    >{
    >  0x30,
    >  0xAA,

    您不应在此处发送0x30。 这是 I2C 单元将为您发送的 I2C 地址字节(基于 I2CSA=0x18)。 您应该发送3个字节0xAA、0x00、0x00。 我认为发送0x30的效果是 MPR 将其视为其"命令"(而不是0xAA)、因此从不启动测量、因此您得到的是0x00s

    因此、I2C 单元将自动发送0x31进行读取、因此根本没有理由调用 I2CWrite2()(它甚至可能会混淆 MPR)。

    我认为 MPR 用户想象的模型重复读取1字节(状态)、直到0x20 (忙)位变为0、然后读取4字节。 我怀疑您只能重复读取4个字节(状态+数据)、直到 BUSY 变为0、然后使用刚刚读取的数据。

    根据检查、代码看起来不错。 我无法尝试、因为我没有您的设备

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

    尊敬的 Bruce McKenney:

    感谢您的建议和帮助! 我尝试仅向传感器发送0xAA、0x00、0x00、并读取4个字节的数据、它起作用了!

    调试过程的最新屏幕截图如下所示。

    读取4个字节后、RxBuffer 中的数据发生变化。 我认为结果是正确的。 (我将通过将值转换为 PSI 单位来验证它。)

    以下是我访问 MPRLS 传感器的最新代码、它运行良好:

    #include 
    
    /*精确宽度有符号整数类型*/
    typedef signed char int8_t;
    typedef int8_t S8;
    typedef S8 Rets8;
    typedef signed short int int16_t;
    typedef int16_t S16;
    typedef int16 Rets16;
    typedef signed int int32_t;
    tyf int8_t
    
    ;tynttyf int8_t;ttyf int8_t int8;turt int8
    
    
    typedef U8 RetU8;
    typedef unsigned short int uint16_t;
    typedef uint16_t U16;
    typedef U16 RetU16;
    typedef unsigned int uint32_t;
    typedef uint32_t U32;
    typedef U32
    
    
    ;#define port (port)(P# unsigned int uint32_t);tydefine 3 ^
    
    (#define DDR_port)<#define 3 (#define #define 3)#define 3 (#define TRY_TRU3)<#define 3 (define 3)#define 3 (#define (0x18)//<最常见的 I2C 地址
    #define MPRLS_STATUS_PUSTONGLE (0x40)//<状态 SPI 受电位
    #define MPRLS_STATUS_BUSY (0x20)//<状态忙位
    #define MPRLS_STATUS_FAILED (0x04)//<完整性故障的状态位
    #define MPRLS_STATUS_MATHSAT (0x01)//<数学饱和
    
    #define PSI_max 25
    #define PSI_MIN 0
    
    
    #define CRYSTICAL_295
    #ifdef CRYSTICAL_295
    #define AccessTimer (29500000 / 2000)
    #endif
    
    //用于写入命令
    U8 * PTxData; //指向 TX 数据
    U8 TXByteCtr 的指针;
    
    const unsigned char TxData[]= //要发送
    的数据表{
    0xAA、
    0x00、
    0x00
    };
    
    //要读取数据
    U8 RXData;
    U8 * PRxData; //指向 RX 数据
    U8 RXByteCtr 的指针;
    volatile U8 RxBuffer[128]; //分配128字节的 RAM
    U8测试;
    U8数据[4];
    U32 ret;
    float psi;
    
    void init_clock (void);
    void I2CInit();
    void I2CWrite (void);
    void I2CRead (U8 cnt);
    
    U16 Timer0Cnt = 0;
    void Init_Timer0 (void);
    void Delayms (U16延迟);
    
    
    
    int main (void)
    {
    int i;
    // LED Control
    P3DIR |=(BIT2|BIT2|BIT3|BIT|BIT3|BIT|BIT3|BIT|BIT|BIT3|BIT|BIT|BIT3|BIT|BIT|BIT|BIT|BIT3|BIT|BIT|BIT|BIT|BIT|BIT3
    )
    
    
    
    _EINT();
    I2CInit();
    
    while (1)
    {
    I2CWrite();
    Delayms(10);
    I2CRead (4);
    TEST = RxBuffer[0];
    //将3个字节的数据组合在一起
    RET = RxBuffer[1];
    RET <<= 8;
    RET |= RxBuffer[2];
    RET <<= 8;
    RET |= RxBuffer[3];
    //psi =(RET - 0x19999A)*(PSI_max - PSI_min);
    //psi /=(浮点)(0xE66666 - 0x19999A);
    //psi += PSI_MIN;
    //将 PSI 转换为 HPA
    //psi *= 68.947572932;
    Delayms (10);
    }
    
    
    
    /*********
    函数:init_clock
    用途:初始系统时钟
    参数:无
    返回值:无
    /
    void init_clock (void)
    {
    unsigned int i;
    WDTCTL = WDTPW + WDTHOLD;//停止看门狗计时器
    P5SEL |= 0x0C;//端口选择 XT2
    UCSCTL6 &=~XT2OFF;//即使未使用
    #ifdef crystal_295、也能使能端 XT2
    UCSCTL6 |= 0xC000;//即使未使用
    也能使能端 XT2 #endif
    UCSCTL3 |= SELREF_2;// FLLref = REFO
    UCSCTL4 |= SELA_XT2CLK;//从 XT2-16M 中选择源
    UCSCTL4 |= SELS_5 + SELM_5;// SMCLK=MCLK=XT2-16M
    _NOP();
    #ifdef crystal_295
    UCSCTL5 |= DIVM__2 + DIVS__32+ DIVA__2;//晶体-> 29.5MHz
    #endif
    操作
    {
    UCSCTL7 &=~(XT2OFFG + XT1LFOFFG + DCOFFG);//清除 XT2、XT1、DCO 故障标志
    SFRIFG1 &=~OFIFG;//清除故障标志
    for (i=0;i<0xFFFF;i++);// OSC 稳定的延迟
    } while (SFRIFG1&OFIFG);//测试振荡器故障标志
    }
    
    void I2CInit()
    {
    P3SEL |= BIT7; //将 I2C 引脚分配给 USCI_B0
    P5SEL |= BIT4;
    UCB1CTL1 |= UCSWRST; //启用 SW 复位
    UCB1CTL0 = UCMST + UCMODE_3 + UCSYNC; // I2C 主设备,同步模式
    UCB1CTL1 = UCSSEL_SMCLK + UCSWRST; //使用 SMCLK、保持软件复位
    UCB1BR0 = 12; // fSCL = SMCLK/12 =~100kHz
    UCB1BR1 = 0;
    UCB1I2CSA = 0x18; //从器件地址为048h
    UCB1CTL1 &=~UCSWRST; //清除 SW 复位,恢复操作
    UCB1IE |= UCTXIE;
    
    }//-----------
    
    
    // USCIAB0_ISR 的结构使其可用于通过
    预加载带有字节计数的 TXByteCtr 来发送任何//字节数。
    ///----------------------------------
    
    #pragma vector = USCI_B1_Vector
    __INTERRUPT void USCI_B1_ISR (void)
    
    {
    switch (_even_in_range (UCB1IV、12))
    {
    case 0:break; //向量0:无中断
    情况2:中断; //向量2:ALIFG
    情况4:中断; //向量4:NACKIFG
    情况6:中断; //向量6:STTIFG
    情况8:中断; //向量8:STPIFG
    情况10: //向量10:RXIFG
    RXByteCtr---; //递减 RX 字节计数器
    IF (RXByteCtr)
    {
    * PRxData++= UCB1RXBUF; //将 RX 数据移动到地址 PRxData
    IF (RXByteCtr = 1) //只剩下一个字节?
    UCB1CTL1 |= UCTXSTP; //生成 I2C 停止条件
    }
    其他
    {
    * PRxData = UCB1RXBUF; //将最终 RX 数据移动到 PRxData
    __BIC_SR_REGISTER_ON_EXIT (LPM0_Bits);//退出活动 CPU
    }
    中断;
    案例12: //向量12:TXIFG
    IF (TXByteCtr) //检查 TX 字节计数器
    {
    UCB1TXBUF =* PTxData++; //加载 TX 缓冲区
    TXByteCtr --; //减量 TX 字节计数
    器}
    其他
    {
    UCB1CTL1 |= UCTXSTP; // I2C 停止条件
    UCB1IFG &=~UCTXIFG; //清除 USCI_B0 TX int 标志
    _BIC_SR_REGISTER_ON_EXIT (LPM0_BITS);//退出 LPM0
    }
    默认值:break;
    }
    
    
    
    /*********
    函数:I2CWrite
    Purpose:Write 1 byte via I2C
    parameter:unsigned char
    return value:none
    /
    void I2CWrite (void)
    {
    Delayms(50岁); //事务之间需要延迟
    PTxData =(U8 *) TxData; // TX 数组起始地址
    //在此处放置断点以查看每个断点
    //发送操作。
    TXByteCtr = TxData 的大小; //加载 TX 字节计数器
    UCB1IE &=~UCRXIE; //启用 TX 中断
    UCB1IE |= UCTXIE; //启用 TX 中断
    
    UCB1CTL1 |= UCTR + UCTXSTT; // I2C TX、启动条件
    
    _bis_SR_register (LPM0_bits + GIE); //输入 LPM0,启用中断
    __no_operation(); //保持在 LPM0中直到所有数据
    //是 TX
    while (UCB1CTL1 & UCTXSTP); //确保已发送停止条件
    }
    
    /*********
    函数:I2CRead
    用途:通过 I2C
    参数写入1个字节:无符号字符
    返回值:无
    /
    void I2CRead (U8 cnt)
    {
    
    PRxData =(U8 *) RxBuffer;// RX 缓冲区开始
    RXByteCtr = cnt; //加载 RX 字节计数器
    UCB1IE &=~UCTXIE; //启用 TX 中断
    UCB1IE |= UCRXIE; //启用 TX 中断
    while (UCB1CTL1 & UCTXSTP); //确保发送了停止条件
    UCB1CTL1 &=~UCTR; //主接收器
    UCB1CTL1 |= UCTXSTT; // I2C 启动条件
    
    _bis_SR_register (LPM0_bits + GIE); //输入 LPM0,启用中断
    //保持在 LPM0中直到所有数据
    //是 RX
    __no_operation(); //设置断点>>此处<<和
    }
    
    void Init_Timer0 (void)
    {
    TA0CTL = 0 //
    |(1 << 2)//
    |(1 << 8);//
    TA0CCR0 =访问计时器;//
    TA0CCTL0 = 0 //
    |(1 << 4);//
    TA0CTL |=(1 << 4);//
    }
    
    #pragma vector=TIMER0_A0_VECTOR
    __INTERRUPT void Timer0_A0 (void)
    {
    TA0CCR0 =访问定时器;//复位定时器 A 计数器
    if (Timer0Cnt!= 0)
    {
    Timer0Cnt--;
    }
    }
    
    /*********
    功能:延迟
    用途:延迟功能, 1ms 基本
    参数:无
    返回值:无
    /
    空延迟(U16延迟)
    {
    Timer0Cnt =延迟;
    while (Timer0Cnt!= 0);
    }
    

    非常感谢您的帮助、让我了解如何使用 MSP430 I2C 访问传感器。

    Michelle

    [引用用户="Bruce McKenney47378"]

    >constunsigned charTxData[] =              // Table of data to transmit
    >{
    >  0x30,
    >  0xAA,

    您不应在此处发送0x30。 这是 I2C 单元将为您发送的 I2C 地址字节(基于 I2CSA=0x18)。 您应该发送3个字节0xAA、0x00、0x00。 我认为发送0x30的效果是 MPR 将其视为其"命令"(而不是0xAA)、因此从不启动测量、因此您得到的是0x00s

    因此、I2C 单元将自动发送0x31进行读取、因此根本没有理由调用 I2CWrite2()(它甚至可能会混淆 MPR)。

    我认为 MPR 用户想象的模型重复读取1字节(状态)、直到0x20 (忙)位变为0、然后读取4字节。 我怀疑您只能重复读取4个字节(状态+数据)、直到 BUSY 变为0、然后使用刚刚读取的数据。

    根据检查、代码看起来不错。 我无法尝试、因为我没有您的设备

    [/报价]