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:USI_B Tbuf参数冲突,在停止条件后立即发送启动条件

Guru**** 2539500 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/582676/msp430g2553-usci_b-tbuf-parameter-violation-sends-start-condition-immediately-after-stop-condition

部件号:MSP430G2553

这让我感到非常意外,我查看了数据表,用户指南,勘误表,不知道我做错了什么,也不知道如何处理。  

一些背景:  

此I2C实施使用轮询(请参阅SLAZ440H中的Issue USCI29)

不使用重复启动条件(参见SLAZ440H中的问题USCI35)

总线速度为100KHz,带有4.7K上拉电阻,取消了WFP 1.6 跳线。 我正在使用MSP430G2系列,版本1.5 的启动板。

此应用程序的目的是在INTB (连接到WFP 2.2)中断时,从MCP2.3018万上的寄存器INTCAPB读取信息。 P2中断设置一个软件标志,这将触发写入以设置寄存器地址,然后从寄存器INTCAPB中进行后续读取。

是的,我已经阅读 了MSP430TmMCU (SLAA734)上常见eUSCI和USCI串行通信问题的解决方案 以及器件的I2C示例代码。 我尝试了TI I2C实现,I2C中断导致调用TRAPINT,从而捕获程序计数器。

现在谈谈症状:

正如您从逻辑分析器输出中看到的那样,开始和停止条件在I2C规范范围内并得到确认。 在最近的写入事务结束之前,它们一直保持不变。 从属设备和逻辑分析仪都无法识别以下读取事务。

 在停止条件后立即设置断点似乎可以通过在停止和启动条件之间留下巨大的间隙来解决问题,但我无法解决该问题。 在调试时,我发现这是一个令人不快的代码:  

如果(状态和I2C_REG_SET){ //如果为以后的读取操作设置寄存器计数器
如果(状态和键盘读取){ //如果读取键盘的状态
// MCP2.3018万的地址将已加载
如果(UCB0TXBUF == INTCAPB){ //如果发送的最后一个字节是INTCAPB
//控制字节已成功发送
//现在可以发送停止条件,等待4.7us,然后作为接收器发送启动条件
状态&=~I2C_REG_SET; //重置I2C_REG_SET位,计数器已成功发送
UCB0CTL1 || UCTXSTP; //发送停止条件
While (UCB0CTL1和UCTXSTP); //确保停止条件已完成,然后再继续
__DELAY周期(Tbuf); //延迟4.7us (1/SMCLK * 75)
UCB0CTL1 &=~UCTR; //成为接收器
UCB0CTL1 || UCTXSTT; //发送开始条件
} 否则{ //否则:
UCB0TXBUF = INTCAPB; //发送INTCAPB作为注册号字节
I2C_I = INTCAPB; //更新寄存器迭代器的主副本
__DELAY周期(Tbuf); //延迟4.7us (1/SMCLK * 75)
}
}
} 


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

    感谢您提供详细信息,我很高兴您能找到MSP430TmMCU (SAA734)应用报告中常见eUSCI和USCI串行通信问题的解决方案。 查看MCP2.3018万数据表后,您似乎违反了启动条件设置时间。 您之前也注意到了这一点。 根据本文档,开始条件设置时间至少需要为4.7 Us,而您正在观察0.48 Us。

    我的第一个想法是您没有实施足够长的延迟(__delay_cycles (Tbuf);)。 要测试此函数延迟时间是否足够长,是否可以将其放置在单独的位置(如主环路),并在调用GPIO之前和之后切换GPIO。 然后测量切换之间的时间?

    此外,您能否提供I2C初始化代码和MCLK/SMCLK初始化?

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

    我的第一个想法是,延迟时间不够长,但即使将延迟乘以10也完全没有效果。 我使用__delay_cycles (Tbuf);在代码的其余部分中,它工作正常,只有在原始POST中运行代码时才会出现问题。

    #定义Tbuf 75 // I2C SPEC 1.1 (4.6875us)指定的正确总线空闲时间(以CPU周期为单位) 

    //时钟系统配置代码:
    DCOCTL = CALDCO_16MHz; //将DCO寄存器设置为预先校准的16MHz速度,通过WFP 1.4 SMCLK输出
    BCSCTL1 = CALC1_16MHz,通过逻辑分析器验证为16MHz; //设置RESL位 
    BCSCTL3 = LFXT1S_2;            //将ACLK设置为VLOCLK
    //初始化USI_B0到飞利浦1.1 规范I2C主模式。 PIN已分配给SCL,SDA
    UCB0CTL0 = UCMST | UCMODE_3 | UCSYNC; // 7位寻址,单主
    UCB0CTL1 |= UCSSEL_2 | UCTR | UCSWRST;//发送器模式,来自SMCLK
    UCB0BR1 =0; //将高波特率寄存器设置为0
    UCB0BR0 = I2C_CLOCK_DIV; // 100KHz总线频率,(16MHz/160)
    UCB0STAT = 0; //重置状态更改标志
    IFG2 =0; //重置所有发送和接收标志,包括USI_A
    UCB0I2CSA = MCP2.3018万_opcode; //将从属地址初始化为MCP2.3018万的基本地址
    UCB0I2CIE = 0; //禁用所有I2C相关中断(参见SLAZ440H中的问题USCI29)
    IE2 = 0; //禁用USI_A和USI_B TX和RX中断(参见SLAZ440H中的问题USCSI29)
    UCB0CTL1 &=~UCSWRST; //重置UCSWRST,启动I2C通信
    UCB0CTL1 || UCTXSTT; //启动条件 


    这里有相同的代码和逻辑输出,但放大后,您可以看到启动和停止之间的延迟第一次运行良好,但第二次,17后的小突起应该是停止和启动条件。

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

    正如我在上一篇文章中所说的,这里的Tbuf长度绝对不是问题,这是我检查的第一件事。 我将尝试使用TA0中断从LPM1唤醒设备,以验证在我看来这不是时间问题

    我的猜测是:

    1.编译器正在尝试通过组合来“优化”我的代码

    UCB0CTL1 || UCTXSTP; 

     和

    UCB0CTL1 || UCTXSTT; 

    进入:  

    UCB0CTL1 || UCTXSTT + UCTXSTP; 

    2. USI_B模块存在未发现的错误。

    我打赌这是一个编译器问题,因为它只出现在那个特定的块中,发生了当时的100 %。 用TimerA中断替换__delay_cycles()后,我会报告。

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

    我将在早上更近的时间了解这一点,但在此期间,您是否可以关闭优化并再次运行代码? 这将让您知道您的第一个猜测是否属实。 根据您的优化水平,我认为这种情况肯定会发生。 同样,我犹豫是否认为这是USI_B模块中的一个错误。 这里有许多工作部件可能会影响这种情况,例如时钟源,电源,代码结构等。我也可以尝试在早上的最后重现此问题。 一旦我和你处于同一个阶段,它将使调试速度快得多。

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

    我当前的优化设置是:--opt_level=0 --opt_for speed=1。 我不太确定如何更改它。

    我不能想象电源或时钟源有问题,因为我使用启动板作为电源和工厂校准的时钟值。 我已经通过WFP 1.4 用我的逻辑分析器检查了SMCLK的速度和一致性。

    希望这是我的代码结构。 同时,我要说

    UCB0CTL1 || UCTXSTT; 

     在TA0_A0 ISR中,防止编译器合并这两个指令。

    今天晚些时候,如果我有更多时间,我将发布完整的代码,包括头文件。

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

    您好,Stephen:

    在CCS中,您可以通过右键单击项目并选择“属性”来更改优化级别。 然后按照Build --> MSP430编译器-->优化,您将看到优化设置。

    从这里,您可以使用下拉菜单关闭优化。

    我认为您已经制定了一条良好的前进道路。 让我了解最新进展。

    此致,  

    Caleb Overbay

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

    我已更新优化级别,现在已关闭。 我还实施了TA0CCR0中断,以代替__DELAY周期()函数。

    现在我遇到了一个完全不同的问题,CPUOFF位仍然设置,即使ISR从LPm1重置SR。 以下是它被卡住的地方:

    下面是main.c:

    #include <MSP430-h>
    #include "MCP2.3018万.h"
    #include "12_key_board.h"
    /*
    连接图:
    
    MSP430| Vcc Vcc |MCP2.3018万
    || | |
    | 4.7K 4.7K |
    || | |
    SDA|--|---- +----------- SDA |SCL|---------------
    |SCL 2.2
    |INTB
    
    */*
    程序流:
    *首先,看门狗计时器被保持,时钟被配置,引脚被初始化,USI_B (I2C模式)被初
    始化*初始化后,立即发送I2C总线上的启动条件(UCB0CTL1 |= UCTXSTT;)
    * I2C设备初始化环路将运行。 在主循环可以运行
    * MCP2.3018万初始化循环之前:将一个字节加载到缓冲区中,重复此操作直到发送了23个字节,如果收到nack,则重新开始初始化。
    * 23字节序列决定MCP2.3018万的初始状态。
    *初始化后,设备进入LPM3,当INTB中断时,它触发写入MCP的寄存器计数器,写入'17',寄存INTCAPB
    *成功发送控制字节后,MSP成为接收器,并开始从MCP读取1字节。
    *如果接收到的字节与列表中的字节匹配,则安全PIN迭代器将递增,4个增量后,迭代器将溢出到下一个最大位
    ,*	SUC。 此时,系统解锁,警报(稍后将连接到GPIOA.2)关闭。
    */
    
    #define ACLK_FREQ 1.48万 //此特定芯片上的VLO范围为14.8KHz到10kHz,
    //#define ACLK_FREQ 3.2768万 //稍后从Xin和XOUT上的12.5pf晶体中获取
    #define SMCLK_FREQ 1600万 // 16MHz SMCLK
    #define I2C_CLock_FREQ 10万 // 100KHz SCL
    #define I2C_CLock_DIV SMCLK_FREQ/I2C_CLock_FREQ //将时钟缩放为(16MHz SMCLK)/(100KHz SCL)
    #define Tbuf 75 // I2C SPEC 1.1 (4.7us)
    
    #define键盘指定的正确总线空闲时间(以CPU周期为单位) 15. //键盘引脚位于INTCAPB的下4位
    #define I2C_ON BIT0 //如果设置,MSP430将无法关闭CPU,因为I2C依赖于轮询
    #define键盘读取 BIT1. //如果设置,则设备正在从MCP2.3018万的INTCAPB寄存器
    #define I2C_REG_SET读取 位2 //如果设置,MSP430仅为以后的读取
    #define MCP2.3018万_init BIT4传输从寄存器迭代器 //如果设置,则MCP2.3018万已初始化为正确的#define
    SEC0状态 位5 //这是安全销迭代器
    #define SEC1的第一位 BIT6. //这是安全PIN迭代器
    #define SEC的第二位 位5|BIT6. //这是安全PIN迭代器
    #define SUC BIT7. //如果设置,则系统处于解锁和撤防
    
    的无符号int状态; //状态字
    unsigned char i2c_i; // i2c从寄存器计数
    器unsigned char nackd; //主中继器被nack'd
    unsigned char tick数次的计数; // tick
    const unsigned char PIN[4]={three,nine,five,two};//用于安全代码
    
    int main(void)
    的4位PIN {//
    监视器配置:
    WDTCTL = WDTPW + WDTHOLD; //停止WDT
    
    //时钟系统配置代码:
    DCOCTL = CALDCO_16MHz; //将DCO寄存器设置为预分频16MHz速度
    BCSCTL1 = CALC1_16MHz; //设置RESL位
    BCSCTL3 = LFXT1S_2; //将ACLK设置为VLOCLK,当晶体焊接在上时,更新到以下代码
    
    //初始化变量:
    状态=0; //所有状态位重置
    i2c_i =0; //从寄存器迭代器从0开始
    
    // PIN配置代码:
    P1OUT = BIT3; //引脚1.3 被上拉(SW2)
    P1DIR = BIT0 | BIT4; //引脚1.0 和1.4 是输出(ACLK和SMCLK)
    P1REN = BIT3; //启用了WFP 1.3 上拉电阻(SW2)
    P1IE = BIT3; // WFP 1.3 interrupt enabled (SW2)
    P1IES = BIT3; // WFP 1.3 高到低触发中断(按下SW2时)
    P1IFG =0; //初始化P1标志为0;
    P1SEL = BIT0 | BIT4 | BIT6 | BIT7; // WFP 1.0 输出ACLK WFP输出1.4 输出SMCLK WFP 1.6 和WFP 1.7 被传送到USI_B0
    P1SEL2 = BIT6 | BIT7; // WFP 1.6 和WFP 1.7 连接到USI_B0
    //初始化端口2
    P2DIR = BIT0 | BIT1; // WFP 2.0 -1是TA1输出,WFP 2.2 是INTB,来自MCP2.3018万所有其它引脚都是输入
    P2REN = 255和~Ω(BIT0|BIT1); //除启用了WFP 2.1 上拉电阻
    器外的所有引脚P2OUT = 255和~Ω(BIT0|BIT1); //除WFP 2.1 外的所有引脚都为HIGH
    P2SEL = BIT0|BIT1; //为TA1模块输出
    P2IE = BIIT2选择了WFP 2.1 ; //启用在WFP 2.2 上的中断(INTB自MCP2.3018万)
    P2IES = BIIT2; //高到低转换中断WFP 2.2 (常高)
    P2IFG = 0; //仅在
    /*情况下将中断标志设置为0以下代码用于节省20引脚封装的电源*/
    P3DIR =0; //所有端口3引脚初始化为输入
    P3REN =255; //所有端口3上拉/下拉电阻器已启用
    P3OUT = 255; //所有端口3引脚都被上拉
    
    // TimerA0:I2C定时的间隔计时器
    TA0CTL = tassel_2 | MC_0| TCLR; // SMCLK SOURCE,STOPPED,CLEAR TAR
    TA0CCR0 = Tbuf-13; // Tbuf -13个周期,以考虑ISR开销和ISR内容
    TA0CCTL0 =0; //禁用中断,清除中断标志
    //初始化TimerA1,WFP 2.0 和WFP 2.1 已被分配给IT
    TA1CTL = tassel_1 | MC_1 | TCLR; //获取ACLK时钟,向上模式CLEAR TAR
    TA1CCR0 = ACLK_FREQ; //设置为1s间隔,(ACLK * 4000)
    //TA1CCTL0 = CCIE | OUTMOD_0; //启用中断并将TA1CCR0设置为输出到WFP 2.0 (如果选中)
    TA1CCR1 = ACLK_FREQ>>>1; //设置为0.5秒间隔,ACLKx2000
    TA1CCTL1的速度= OUTMOD_3; //将TA1CCR1设置为设置/重置WFP 2.1
    
    //将USI_B0初始化为飞利浦1.1 规范I2C主模式。 PIN已分配给SCL,SDA
    UCB0CTL0 = UCMST | UCMODE_3 | UCSYNC; // 7位寻址,单主
    UCB0CTL1 |= UCSSEL_2 | UCTR | UCSWRST;//发送器模式,来自SMCLK
    UCB0BR1 =0; //将高波特率寄存器设置为0
    UCB0BR0 = I2C_CLOCK_DIV; // 100KHz总线频率,(16MHz/160)
    UCB0STAT = 0; //重置状态更改标志
    IFG2 =0; //重置所有发送和接收标志,包括USI_A
    UCB0I2CSA = MCP2.3018万_opcode; //将从属地址初始化为MCP2.3018万的基本地址
    UCB0I2CIE = 0; //禁用所有I2C相关中断(参见SLAZ440H中的问题USCI29)
    IE2 = 0; //禁用USI_A和USI_B TX和RX中断(参见SLAZ440H中的问题USCSI29)
    UCB0CTL1 &=~UCSWRST; //重置UCSWRST,启动I2C通信
    UCB0CTL1 || UCTXSTT; //开始条件
    
    __bis_sr_register (GIE); //在
    
    以下情况下启用全局中断:(~status & MCP2.3018万_INIT){ //当MCP2.3018万未初始化时
    如果(UCB0STAT和UCNACKIFG){ //如果MCP2.3018万未确认,则必须重新启动整个初始化
    UCB0CTL1 || UCTXSTP; //发送停止条件
    I2C_I = 0; //重置从属寄存器计数器
    NACKd++; //增量未确认计数器
    同时(UCB0CTL1和UCTXSTP); //等待停止条件完成
    如果(NACKd < 30){ //如果它没有尝试30次
    TA0CTL = MC_1; //开始时间A0
    TA0CCTL0 |= CCIE; //启用TA0CCR0中断
    __bis_sr_register (LPM1 + GIE); //输入LPM1并设置GIE位(ISR发送启动条件)
    } 否则{								//在30次尝试失败后,确认是无望的
    __bis_sr_register (LPM4_bits); //进入深度睡眠
    }
    UCB0STAT &=~UCNACKIFG; //清除nack标志
    IFG2 &=~UCB0TXIFG; //重置TX IFG (有关详细信息,请参见USCI25)
    } 否则,如果(IFG2和UCB0TXIFG){ //如果需要加载TXBUF或发送停止条件(前提是由于上述代码而没有nack)
    IFG2 = 0; //清除所有USCI标志
    UCB0TXBUF = MCP2.3018万_INIT_DATA[i2c_I];//加载适当字节的缓冲区,从0开始
    I2C_I++; //递增迭代器
    如果(i2c_i > OLATB+1){ //如果从属寄存器迭代器已滚动(发送超过(1个控制)+(21个数据)字节)
    UCB0CTL1 || UCTXSTP; //发送停止条件
    同时(UCB0CTL1和UCTXSTP); //等待停止条件完成
    I2C_I = 0; //将指针置于主注册迭代器上
    状态|| MCP2.3018万_INIT; //已成功写入所有字节,MCP2.3018万现已初始化为正确状态
    }
    }否则,如果(UCB0STAT & UCALIFG){ //如果仲裁以某种方式丢失(仅主总线上的主)
    TA1CCTL0 = OUTMOD_4; 		//将TimerA1设置为在2.0 ~0.5Hz时切换为WFP,以指示致命错误
    __bis_sr_register (LPM4_bits); //进入深度睡眠,不中断
    }
    }
    同时(1){//
    此I2C实现使用轮询(参见SLAZ440H中的问题USCI29)
    //不使用重复启动条件(参见SLAZ440H中的问题USCI35)
    //维修nack时手动重置TXIFG (有关详细信息,请参阅问题USCI25)
    如果(UCB0STAT和UCNACKIFG){ //如果收到了一个nack
    IFG2 &=~UCB0TXIFG; //重置TX标志(参见USCI25)
    I2C_I = 0; //重置地址迭代器
    UCB0CTL1 || UCTXSTP; //发送停止条件
    While (UCB0CTL1和UCTXSTP); //等待停止条件完成
    TA0CTL |= MC_1; //开始时间A0
    TA0CCTL0 |= CCIE; //启用TA0CCR0中断(发送启动条件)
    __bis_sr_register (LPM1 + GIE); //输入LPM1并设置GEI位,直到TA0A0中断
    NACKd++; //递增NACKd
    UCB0STAT &=~UCNACKIFG; //重置nack标志
    } 否则,如果(IFG2和UCB0TXIFG){ //如果是时候加载TXBUF或发送停止条件了
    如果(状态和I2C_REG_SET){ //如果为以后的读取操作设置寄存器计数器
    如果(状态和键盘读取){ //如果读取键盘的状态
    // MCP2.3018万的地址将已加载
    如果(UCB0TXBUF == INTCAPB){ //如果发送的最后一个字节是INTCAPB
    //控制字节已成功发送
    //现在可以发送停止条件,等待4.7us,然后将启动条件作为接收器发送
    状态&=~I2C_REG_SET; //重置I2C_REG_SET位,计数器已成功发送
    UCB0CTL1 || UCTXSTP; //发送停止条件
    While (UCB0CTL1和UCTXSTP); //确保停止条件已完成,然后再继续
    TA0CTL |= MC_1; //开始时间A0
    TA0CCTL0 |= CCIE; //启用TA0CCR0中断
    UCB0CTL1 &=~UCTR; //成为接收器
    __bis_sr_register(LPM1 + GIE);//输入设置了GIE位的LPM1 (ISR发送启动条件)
    } 否则{ //否则:
    UCB0TXBUF = INTCAPB; //发送INTCAPB作为注册号字节
    I2C_I = INTCAPB; //更新寄存器迭代器的主副本
    }
    }
    }
    IFG2 &=~(UCB0TXIFG); //清除TX标志
    } 否则,如果(IFG2和UCB0RXIFG){ //如果收到一个字节
    如果((STATUS & KEYBUILD_READ)&&(UCB0I2CSA == MCP2.3018万_opcode))//如果读取键盘的状态和从地址为MCP2.3018万
    UCB0CTL1 || UCTXSTP; //发送停止条件
    //更高版本评估UCB0RXBUF的4位
    UCB0RXBUF &=键盘; //删除UCB0RXBUF的较低字节
    如果(UCB0RXBUF & PIN[(status & SEC)>>5]){//如果RXBUF与当前安全PIN匹配
    状态+= SEC0; //通过SEC0递增状态字
    如果(状态和SUC){ //如果解锁
    状态&=~SEC; //重置安全PIN迭代器
    //更高版本将在此处关闭报警
    }
    }否则,如果(status & SUC){ 	//如果在系统解锁时按下某个键
    如果(UCB0RXBUF == STAR){ //如果按星号
    //更高版本允许更改密码
    }
    }
    状态&=~(键盘读取|I2C_ON|I2C_REG_SET);//重置键盘读取,I2C_ON和I2C_REG_SET
    IFG2 &=~UCB0RXIFG; //清除RX标志
    }
    }否则,如果(UCB0STAT & UCALIFG){ //如果仲裁失败(这不是正常的,选择MSP430是唯一的主中继器)
    TA1CCTL0 = CCIE | OUTMOD_4; //将TimerA1设置为将2.0 ~0.5Hz的WFP切换为出现致命错误
    __bis_sr_register (LPM4_bits); //进入深度睡眠,不中断
    } 否则,如果((status & KEYBAL_READ)&&(~status & I2C_ON)){//如果是读取键盘的时间,并且没有其他I2C操作发生
    UCB0I2CSA = MCP2.3018万_opcode; //将从地址设置为MCP2.3018万
    UCB0CTL1 |= UCTR; //设置UCTR位
    TA0CTL |= MC_1; //开始时间A0
    TA0CCTL0 |= CCIE; //启用TA0CCR0中断
    __bis_sr_register (LPM1 + GIE); //输入LPM1并设置GIE位(ISR发送启动条件)
    状态|= I2C_ON|I2C_REG_SET; //设置I2C_ON和I2C_REG_SET
    } 否则,如果(~status & I2C_ON){ //如果设备未通过I2C通信
    //关闭USI_B和CPU,以节省电源
    __bis_sr_register (LPM3); //输入LPM3
    }
    }//结束主循环
    }//结束主循环()
    
    #pragma vector= TRAPINT_Vector
    __interrupt TRAPINT_ISR(void)
    {__no_operation()
    ;
    }
    
    #if defined(__TI_Compiler_version__)|| defined(__IAR_systems_icc__)
    #IMMA vector=TIMER0_A0_TIMER0_Isr_PER0=#void
    
    _TI_TI_TIME_PER0(_A)
    
    
    
    #endif
    {
    TA0CCR0 =0; //重置中断标志,禁用中断
    TA0CTL |= MC_0 + TALCL; //停止计时器和重置TAR
    UCB0CTL1 || UCTXSTT; //发送启动条件
    __BIC_SR_REGISTER_ON_EXIT (LPM1_BIT); //退出LPM1,继续程序
    }
    
    #if defined(__TI_Compiler_version__)|| defined(__IAR_systems_icc__)
    #pragma vector=Timer1_A0_vector
    __interrupt Timer1_A0_ISR (void)
    #Elif defined(__GNUC__)
    void __attribute__((vector_Timer__) Timer_or_1)
    
    
    #endif
    {
    tick++; // increment tick
    }//											返回睡眠
    
    #if defined(__TI_Compiler_version__)|| defined(__IAR_systems_icc__)
    #pragma vector=Port1_vector
    __interrupt Port_1(void)
    #Elif defined(__GNUC__)
    void __attribute__((void(Port1_vector))#interrupt 1(vector))
    
    不支持错误#elle_1!
    #endif
    {
    P1OUT ^= BIT0; //切换WFP 1.0
    P1IFG =0; //重置P1 IFG
    } //返回睡眠
    
    #if defined(__TI_Compiler_version__)|| defined(__IAR_systems_icc__)
    #pragma vector=port2_vector
    __interrupt void Port_2 (void)
    #Elif defined(__GNUC__)
    void __attribute__((interrupt (port2_vector)) Port_2 (vector)#void error_use)
    #elle!
    
    #endif
    {
    //仅启用了WFP 2.2 (INTB)中断,因此不需要检查设置了哪个标志
    状态|=键盘读取; //告诉主回路它需要读取键盘
    P2IFG = 0; //重置端口2中断标志
    __BIC_SR_REGISTER_ON_EXIT (LPM3_bits);//唤醒并返回程序
    }
    

    MCP2.3018万.h:

    /*
    * MCP2.3018万_driver.h
    *
    创建时间:2017年2月22日
    *作者:Stephen
    */
    
    #ifndef MCP2.3018万_H_
    #define MCP2.3018万_H_
    #define IODIRA 0// 1 for input,0 for output
    #define IODIBB 1// 1 for input,0 for output
    #define IPOLA 2 // input polarity (如果已设置), GPIO.x将反映输入引脚的相反逻辑状态
    #define IPOLB 3 //输入极性,如果设置,GPIO.x将反映输入引脚
    #define GPINTENA 4 //更改启用时中断的相反逻辑状态, 如果SET GPIO.x在状态更改
    时触发相应中断#define GPINTENB 5 //更改时中断启用,如果SET GPIO.x在状态更改
    时触发相应中断#define DEFVALA 6 //如果对应值与引脚
    //电平相反, 将触发中断,取决于GPINTENA和INTCONA
    #define DEFVAALB 7 //如果对应的值与引脚
    //级别相反,将触发中断,取决于GPINTENB和INTCONB
    #define INTCONA 8 //更改时中断控制寄存器,0=相对于先前值的引脚值, 1=与DEFVALA比较
    #define INTCONB 9 //更改时中断控制寄存器,0=引脚值与先前值比较,1=与DEFVAAL比较
    #define IOCONA 10// IOCON配置寄存器的排列方式,SEQ模式
    #define IOCONB 11// IOCON配置寄存器的排列方式, SEQ模式
    #define GPPUA 12// GPIO上拉,启用和禁用上拉电阻
    器#define GPPUB 13// GPIO上拉,启用和禁用上拉电阻
    器#define INTFA 14// intTF中断标志,如果设置,则表示端口A中导致中断的对应引脚
    #define INTFB 15// intf中断标志, 如果SET指示端口B中导致中断
    #define INTCAPA 16// Interrupt capted值的对应引脚,则捕获中断#define
    INTCAPB 17// Interrupt capted值时端口A引脚的状态, 捕获中断时端口B引脚的状态
    #define GPIOA 18//反映端口A中对应引脚的逻辑状态
    #define GPIOB 19//反映端口B中对应引脚
    的逻辑状态#define OLATA 20//输出闩锁(设置时), 将设置为输出配置的端口A引脚
    #define OLATB 21//输出闩锁,设置时,将设置为输出配置的端口B引脚
    
    #define MCP2.3018万_opcode 64>1//(由于USI_B在地址中不包括R/~W位,所以向右移动)
    
    const char MCP2.3018万_init_data[23]={0,//第一字节 这是通过I2C
    0发送的寄存器地址字节,// IODIRA:端口A上的引脚设置为输出
    255,// IODI-B:端口B上的引脚设置为输入
    0,// IPOLA:如果端口A中断,状态将反映实际状态
    0,// IPOLB: 如果端口B中断,状态将反映实际状态
    0,// GPINTENA:端口A
    255的中断已禁用,// GPINTENB:端口B
    0的中断已启用,// DEFVALA:中断比较值0,端口A中断已禁用,//
    DEFVAb: 中断比较值0,位从0变化中断发生
    0,// INTCONA:中断控制值为0。 端口A中断已禁用
    31,// INTCONB:将较低的5位设置为对照DEFVAB
    1,// IOCON:将INTCC设置为1,读取INTCAP将清除关联中断
    1,// IOCON:将INTCC设置为1,读取INTCAP将清除关联中断
    0,// GPPUA: 端口A
    255的内部上拉电阻被禁用,// GPPUB:端口B
    0的内部上拉电阻被启用,// INTFA:设置为0,端口A中断被禁用,仍然
    为0,// INTFB:端口B中断标志被清除,用于初始化
    0,// INTCAPA: 是0,因为端口A
    0的中断被禁用,// INTCAPB:是只读的,因此此字节没有影响
    0,// GPIOA:设置为全部低,点亮LED指示成功初始化
    0,// GPIOB: 设置为全部低,这些引脚是输入
    0,// OLATA:设置为全部低,亮起LED指示成功初始化
    0};// OLATB:设置为全部低,这些引脚是输入
    
    
    #endif /* MCP2.3018万_H_*/ 

    最后当然是最不重要的,12_key_board.h:  

    #定义无 0#
    定义零 1
    #定义一个 2
    #定义两个 3
    #定义三个 4
    #定义四个 5
    #定义5 6
    #定义六个 7
    #定义7 8
    #定义8 9
    #定义9 10
    #定义星号 11
    #定义井号 12
    
    //读数为0表示当前没有按钮被按下
    //任何其他读数表示按钮被按下。
    一次只能按下一个按钮//。
    
    #define ASCII_DECIMAL 48 //当按下十进制时,将48 +十进制值发送到地址125,以便逻辑分析器查看
    #define ascii_star 42
    #define ascii_Pound 35.
    

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

    拆下后

    UCB0CTL1 || UCTXSTT; 

     从TA0_A0 ISR中,我发现程序卡在上

    UCB0CTL1 || UCTXSTT 

    ,而不是  

    状态|= I2C_ON|I2C_REG_SET; 

    我仍然不知道为什么CPUOFF位设置不应该设置。

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

    您好,Caleb,感谢您对优化调整的帮助,我回到了我的__delay_cycles (Tbuf);方法和关闭优化解决了它。

    稍后我将需要进行另一个项目来修补TA0_A0 ISR问题。

    现在我只需要弄清楚如何在MCP有时间完成INTCAPB内容的发送之前发送nack和stop位。 这应该相当容易。

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

    我使用您发布的代码将其加载到MSP430G2553上,然后使用另一个MSP430G2553模拟MCP2.3018万。 我可以正确地完成MCP2018初始化,然后将主机的WFP 2.2 拉低,使其从从属设备读取。 发生这种情况时,我看到发送的地址,发送的INTCAPB代码,然后是停止条件。 之后,您的状态机似乎不同步,并且不会生成重复启动。 该代码在主while循环中循环,且状态= 0x13 (MCP2.3018万_init +键盘读取+ I2C_ON)。

    我看到在您的TA0 ISR内,您设置了TA0CCR0 =0,但从不在代码中的其他位置重置它。 这似乎是导致您的某些问题的原因。 请看一下,并告诉我它会带您去哪里。

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

    我看到,在您的TA0 ISR内,您设置了TA0CCR0 =0,但从不在代码中的其他位置重置它。 这似乎是导致您的某些问题的原因。 请看一下,并告诉我它会带您去哪里。
    [/引述]

    现在我在世界上是怎么弄乱的呢? 我的意思是将TA0CCTL0设置为0,而不是CCR0寄存器。 再次感谢,Caleb。

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

    您好,Stephen:

    很高兴听到事情再次工作。 我看到您正在使用轮询方法来解决一些针对USCI模块的勘误表,但您可能对下面的代码感兴趣。 这是一种基于中断的方法,可以正确处理所有勘误表,并且很可能比轮询方法更容易调试。 只是想将其作为FYI展示给您。

    #include <MSP430.h>
    #include <stdint.h>/*
    
    从属地址*/
    #define Slave_Addr 0x28
    
    /* I2C通信状态*/
    #define Send_Reg 1
    #define RX_Data 2
    #define TX_Data 3
    #define Idle 0/*
    
    I2C写入和读取函数*/
    INT8_I2C_Write_nt (uint8_dev_date_reg 8
    uINT8_t reg_addr,uint8_t *reg_data,uint8_t cnt);
    
    /*全局变量*/
    uint8_t I2C_ReG_Index = 0;
    uint8_t *I2C_ReG_Data;
    uint8_t
    
    
    
    Write TXtCtr = 0;uint8_Comm ByteCtr = 0;uint_0; uint_ut_ree_8_upt缓冲
    区
    
    
    
    
    WDTCTL = WDTPW | WDTHOLD;//秒表计时器
    
    /*初始化时钟系统*/
    BCSCTL1=CALC1_8MHZ;
    DCOCTL=CALDCO_8MHZ;
    BCSCTL2|=divs_2; //SMCLK分配器= 4;
    
    /*初始化I2C引脚*/
    P1SEL|=BIT6+BIT7;
    P1SEL2|=BIT6+BIT7; // WFP 1.6 = SCL (I2C);WFP;1.7 = SDA (I2C)
    
    /*为I2C通信初始化USI_B */
    UCB0CTL1 |= UCSWRST; //启用软件重置
    UCB0CTL1 |=UCSSEL_3 + UCTR; //选择SMCLK,发射器
    UCB0CTL0 |=UCMODE_3 + UCMST + UCSYNC; //设置I2C模式主模式
    UCB0BR0=20; //来自SMCLK的clk分频器,100kHz
    UCB0CTL1 &=~UCSWRST; //清除软件重置,恢复操作
    
    __DELAY周期(700万); //等待从属设备设置
    
    /*写入从属设备的示例*/
    write_buffer_[0]= 0x80;
    write_buffer_[1]= 0x0C;
    I2C_Write_Reg (Slave_Addr,0x3F,&Write_buffer[0],1);//将1字节写入从属寄存器0x3F
    I2C_Write_Reg (Slave_Addr,0x3D,&Write_buffer[1],1);//将1个字节写入从属寄存器0x3D
    
    
    /*从从属设备读取的示例*/
    I2C_READ_Reg (Slave_Addr,0x20,READ_BUFFER,1); //从寄存器0x20读取1个字节
    I2C_READ_Reg (Slave_Addr,0x20,READ_BUFFER,8); //从寄存器0x20读取8个字节
    
    __bis_sr_register (CPUOFF + GIE); //输入LPM0 w/中断
    }/*
    
    
    
    输入:
    
    dev_addr -从属I2C地址
    
    REG_addr -要读取的第一个寄存器的地址
    
    *REG_DATA -指向接收到的数据的存储位置
    
    *cnt -要读取的字节数
    
    */
    INT8_t I2C_READ_REG(uint8_t dev_addr, uint8_t reg_addr, uint8_t *reg_data, uint8_t cnt)
    {
    
    INT8_t状态= 0;//0 =无错误
    
    /*初始化从属地址*/
    UCB0I2CSA = dev_addr;
    
    /*初始化状态机*/
    Com_State =发送注册;
    Rx = 1; //信号这是一个读取操作
    I2C_ReG_Index =注册地址;
    I2C_ReG_Data = REG_DATA;
    RXByteCtr = cnt;
    
    /*开始I2C通信*/
    __disable_interrupt ();
    同时(UCB0CTL1和UCTXSTP); //确保停止条件已发送
    IE2 &=~UCB0RXIE; //禁用RX中断
    IE2 |= UCB0TXIE; //启用TX中断
    UCB0CTL1 || UCTR + UCTXSTT; // I2C TX,启动条件
    __bis_sr_register (CPUOFF + GIE); //输入带中断的LPM0
    
    返回状态;
    
    }/*
    
    输入:
    
    dev_addr -从属I2C地址
    
    REG_addr -要写入的寄存器的地址
    
    *REG_DATA -指向要写入数据的位置
    
    *cnt -要写入的字节数
    
    */
    INT8_t I2C_Write_Reg (uint8_t dev_addr,uint8_t reg_addr,uint8_t *reg_data,uint8_t cnt)
    {
    
    INT8_t状态=0;
    
    /*初始化从属地址*/
    UCB0I2CSA = dev_addr;
    
    /*初始化状态机*/
    Com_State =发送注册;
    Rx = 0; //信号这是一个写入操作
    I2C_ReG_Index =注册地址;
    I2C_ReG_Data = REG_DATA;
    TXByteCtr = cnt;
    
    /*开始I2C通信*/
    __disable_interrupt ();
    同时(UCB0CTL1和UCTXSTP); //确保停止条件已发送
    IFG2 &=~(UCB0TXIFG + UCB0RXIFG);
    IE2 &=~UCB0RXIE; //禁用RX中断
    IE2 |= UCB0TXIE; //启用TX中断
    UCB0CTL1 || UCTR + UCTXSTT; // I2C TX,启动条件
    __bis_sr_register (CPUOFF + GIE); //输入带中断的LPM0
    
    返回状态;
    }/*
    
    开始/停止/ nack ISR */
    #pragma vector = USCIAB0RX_vector
    __interrupt void USCIAB0RX_ISR(void)
    {
    IF ((UCB0STAT和UCNACKIFG))
    {//Nack received
    
    /*根据通信状态处理nack */
    开关(通信状态)
    {
    案例发送_注册:
    中断;
    
    案例TX_数据:
    IFG2 &=~UCB0TXIFG;//清除TXIFG USCI25变通办法
    中断;
    
    案例RX_Data:
    中断;
    
    默认:
    __no_operation();
    中断;
    }
    }
    }/*
    
    RX和TX ISR */
    #pragma载体= USCIAB0TX_vector
    __interrupt void USCIAB0TX_ISR(void){
    
    静态uint8_t临时;
    IF (IFG2和UCB0RXIFG)
    {//RX中断
    
    //必须先阅读RXBUF,才能使用USCI30解决方法
    TEMP = UCB0RXBUF;
    
    IF (RXByteCtr)
    {//接收字节
    *I2C_ReG_Data++=临时;
    RXByteCtr --;
    }
    
    IF (RXByteCtr == 1)
    {//完成接收
    UCB0CTL1 || UCTXSTP;
    }
    否则,如果(RXByteCtr == 0)
    {
    IE2 &=~UCB0RXIE;
    Com_State =空闲;
    __BIC_SR_REGISTER_ON_EXIT (CPUOFF); //退出LPM0
    }
    }
    否则,如果(IFG2和UCB0TXIFG)
    {//TX中断
    
    /*根据通信状态处理TXIFG */
    开关(通信状态)
    {
    Case Send_Reg://将寄存器索引传输到从属设备
    UCB0TXBUF = I2C_REG_Index;//发送数据字节
    IF (RX)
    Com_State = RX_Data; //下一个状态是接收数据
    否则
    Com_State = TX_Data; //下一个状态是传输数据
    中断;
    
    Case RX_Data://切换到接收器
    IE2 &=~UCB0TXIE; //禁用TX中断
    IE2 |= UCB0RXIE; //启用RX中断
    UCB0CTL1 &=~UCTR; //切换到接收器
    IF (RXByteCtr == 1)
    {
    UCB0CTL1 || UCTXSTT; // I2C启动条件
    期间(UCB0CTL1和UCTXSTT); //开始条件已发送?
    UCB0CTL1 || UCTXSTP; //发送停止条件
    }
    否则
    {
    UCB0CTL1 || UCTXSTT; //发送重复开始
    }
    中断;
    
    案例TX_Data://将字节传输到从属设备
    IF (TXByteCtr)
    {//发送字节
    UCB0TXBUF =* I2C_ReG_Data++;
    TXByteCtr --;
    }
    否则
    {//已完成传输数据
    UCB0CTL1 || UCTXSTP; //发送停止条件
    Com_State =空闲;
    IE2 &=~UCB0TXIE; //禁用TX中断
    __BIC_SR_REGISTER_ON_EXIT (CPUOFF); //退出LPM0
    }
    中断;
    
    默认:
    __no_operation();
    中断;
    }
    }
    用于
    
    USCI29的}/*陷阱ISR变通办法*/
    #pragma vector= TRAPINT_vector
    __interrupt void TRAPINT_ISR(void){
    
    __no_operation();//添加断点
    }
    
    

    此致,

    Caleb Overbay

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    感谢向我展示这一点,当我第一次阅读和测试TI I2C示例时,我曾计划类似的事情。

    我决定反对它是因为:从勘误表来看,如果出现USCI29中描述的故障情况,将调用TRAPINT_ISR,而不是预期的USCIAB_RX或USCIAB_TX。 由于应用程序将依赖USCI ISR中的指令进行处理,因此它不仅会停止应用程序,还会停止I2C总线上的其他设备。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好,Stephen:

    我理解您的顾虑,但据我所知,当代码退出陷阱ISR时,执行恢复为正常的应用程序代码。 这意味着中断请求(TX或RX)将在退出陷阱ISR后得到处理。

    此致,
    Caleb Overbay