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.

[参考译文] CCS/MSP430FR5994:使用I2C - nack或无用数据

Guru**** 2538950 points
Other Parts Discussed in Thread: MSP430FR5994

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

https://e2e.ti.com/support/microcontrollers/msp-low-power-microcontrollers-group/msp430/f/msp-low-power-microcontroller-forum/574478/ccs-msp430fr5994-using-i2c---nack-or-useless-data

部件号:MSP430FR5994

工具/软件:Code Composer Studio

大家好,

在过去的几周里,我一直在努力使用MSP430FR5994和VEML6070来获得基本的I2C工作。 我的代码如下。

#include <MSP430-h>
#include <stdio.h>

/*
启动I2C与UV传感器。
*/

int MSB;
int lsb;
int test;
long uv数据;
int main (void){
WDTCTL = WDTPW | WDTHOLD;	//停止看门狗计时器
	
//根据MCLK设备数据表的要求配置一个FRAM等待状态
//在配置时钟系统之前运行超过8MHz。
FRCTL0 = FRCTLPW | NWAITS_1;//更改naccess-x值以添加正确数量的等待(每个数据表1个)

//设置XT1,32.768 kHz外部晶体
PJSEL0 = BIT4 | BIT5; //用于XT1

//禁用GPIO开机默认高阻抗模式以激活
//以前配置的端口设置
PM5CTL0 &=~LOCKLPM2;

//时钟系统设置
CSCTL0_H = CSCKEY_H; //解锁CS寄存器
CSCTL1 = DCOFSEL_0; //将DCO设置为1MHz
// SET SMCLK = MCLK = DCO,ACLK = VLOCLK
CSCTL2 =拉美经济体系_ LFXTCLK | SELS__DCOCLK | SELM__DCOCLK;
//在将频率更改为之前,按器件勘误表将除法器设置为4
//防止过冲瞬态的超出规格操作
CSCTL3 = DIVA__4 | DIVs__4 | DIVM__4;//将所有相应的clk源除以4,以获得勘误表
CSCTL1 = DCOFsel_4 | DCORSEL; //将DCO设置为16MHz
//延迟~10us,让DCO结算。 60个周期= 20个周期缓冲+(10us /(1/4MHz))
__DELAY周期(60);
CSCTL3 = DIVA__32 | DIVs__1 | DIVM__1;//时钟分频器(除以最大时钟)
CSCTL4 &=~LFxTOFF;
做
{
CSCTL5 &=~LFxTOFFG; //清除XT1故障标志
SFRIFG1 &=~OFIFG;
} 同时(SFRIFG1和OFIFG); //测试振荡器故障标志
CSCTL0_H = 0; //锁定CS寄存器

//配置USCI_B1用于I2C模式,发射器
	UCB1CTLW0|= UCSWRST; //软件重置已启用
	UCB1CTLW0 |= UCMODE_3 | UCMST | UCSYNC | UCSSEL__SMCLK;// I2C模式,主模式,同步,UCTR =0, SMCLK
	UCB1CTLW1 |= UCASTP_2; //自动生成停止

//设置UCB1 (SDA和SCL函数,根据数据表)
	P5DIR &=~(BIT0 | BIT1);
	P5REN &=~(BIT0 | BIT1);
P5SEL1 &=~(BIT0 | BIT1);
P5SEL0 = BIT0 | BIT1;
											//达到UCB1TBCNT后
	UCB1BRW = UCBR9; //波特率= SMCLK /(0x0200h = 512十进制)
	UCB1TBCNT = 0x0001; //要接收的字节数(5)
	UCB1I2CSA = 0x18; //初始化地址
	UCB1CTLW0 &=~UCSWRST;
	UCB1IE |= UCNACKIE | UCTXIFG0 | UCRXIFG0;
	//UCB1CTLW0 |= UCTXSTT;
	//__bis_sr_register(LPM3_bits | GIE);

	//test = 10;UCT1CSB/UCS1CWS0
	

	
		
		
		;UCS1=~;UCS1CWS0;UCS1CWS0;UCS1= //停止更改寄存器
		UCB1IE |= UCNACKIE | UCTXIFG0 | UCRXIFG0;
		测试= 1;//获取MSB
		UCB1CTLW0 |= UCTXSTT;//开始命令
		__bis_sr_register(LPM3_bits | GIE);

		UCB1LWCT0 |= UCS1WSB,
		
		~读存器;UCS1WS= UCS1L1UCS1; //停止更改寄存器
		UCB1IE |= UCNACKIE | UCTXIFG0 | UCRXIFG0;
		测试=0;
		UCB1CTLW0 |= UCTXSTT;//开始命令
		__bis_sr_register(LPM3_bits | GIE);
		printf("%d\n", MSB);
		printf, sb"
		uv数据=(MSB <<8)| LSB;
		printf("%ld\n", uv数据);
		__delay_cycles(1600万);
	}
#if

defined(__TI_Compiler_version__)|| defined(___IAR_SYSTEMS _ICC__)
#Elima vector = EUvoid_B1_vector
__interid ISR_US_USE_ISR_




#endif
{
Switch(__偶 数_in_range(UCB1IV, USI_I2C_UCBIT9IFG))
{
案例USI_NONE: 中断; //矢量0:无中断
案例USI_I2C_UCALIFG:中断; //矢量2:ALIFG
案例USI_I2C_UCNACKIFG: //矢量4:NACKIFG
UCB1CTL1 || UCTXSTT; // I2C启动条件
中断;
案例USI_I2C_UCSTIFG:中断; //向量6:STTIFG
案例USI_I2C_UCSTPIFG:中断; //矢量8:STPIFG
案例USI_I2C_UCRXIFG3:中断; //矢量10:RXIFG3
案例USI_I2C_UCTXIFG3:中断; //矢量12:TXIFG3
案例USI_I2C_UCRXIFG2:中断; //矢量14:RXIFG2
案例USI_I2C_UCTXIFG2:中断; //矢量16:TXIFG2
案例USI_I2C_UCRXIFG1:中断; //矢量18:RXIFG1
案例USI_I2C_UCTXIFG1:中断; //矢量20:TXIFG1
案例USI_I2C_UCRXIFG0: //矢量22:RXIFG0
	如果(test==1){
		MSB = UCB1RXBUF;//获取MSB数据
	}
	否则,如果(Test==0){
		LSB = UCB1RXBUF;//获取LSB
	}
	__BIC_SR_REGISTER_ON_EXIT (LPM3_bits);
中断;
案例USI_I2C_UCTXIFG0: 	//矢量24:TXIFG0
	//UCB1TXBUF = 0xE;// 0.111万,最长集成时间和ACK OFF,关机
	__BIC_SR_REGISTER_ON_EXIT (LPM3_bits);
	中断;
案例USI_I2C_UCBCNTIFG: //矢量26:BCNTIFG
P1OUT ^= BIT0; //在WFP 1.0 上切换LED
中断;
案例USI_I2C_UCCLTOIFG:中断; //向量28:时钟低超时
案例USI_I2C_UCBIT9IFG:中断; //矢量30:第9位
默认值:break;
}
}

现在,忽略0x18地址。 根据VEML6070数据表,这是一个初始化时应读取的地址,但我尝试读取该地址会导致一个nack。

根据VEML6070的数据表,另外两个地址0x39和0x38是只读寄存器,并以MSB,LSB格式提供UV数据。  

MSP对此代码的响应如下:

Arduino轮询相同地址的响应如下:

发送0x38地址时,Arduino接收ACK,而MSP430接收nack。

以下是我对此的看法:

  • 为什么Arduino会定期暂停一个周期?
  • 我是否必须像Arduino一样以100kHz工作? 我目前的工作频率接近32kHz,因为我认为这会增加我的成功机会。
  • 我是否可以将MSP430FR5994的模式从标准模式更改为快速模式,反之亦然? 我在用户指南中没有看到任何有关更改模式的信息,因此我假定模式只是一个数字,无需更改代码。
  • MSP430FR5994和VEML6070均可在3.3V逻辑上运行。 考虑到这一点,Arduino使用5V逻辑应该没有什么区别,对吗?
  • 电压峰值是否是MSP绘图中的问题? 如果是,我该如何处理?
  • 我在MSP图中看不到停止设置;这是否是因为我有一个固定点?
  • 根据VEML6070的数据表,我认为我不需要初始化设备来访问数据寄存器。 您同意吗?
  • 我没有看到主模块(Arduino)向VEML6070发送ACK,而VEML6070的数据表显示应该发生这种情况。 这似乎不是问题。
  • 是否可以启用和禁用主接收器ACK?
  • 我的MSP I2C信号与Arduino信号相比是否有任何不好的地方?

我组的一位成员在将SPI与MSP430集成时遇到同样的问题。 我们正在使用VEML6070的分支,它似乎使用10k电阻,而不是VEML6070数据表中建议的2.2k电阻。 我尝试了电阻分压器来降低上拉电阻的值,但这似乎不起作用。

运行代码时,我已确保所有寄存器都尽可能使用正确的值。 我已全面检查了引脚配置,时钟速度和eUSI_B1配置。

我的测试设置如下图所示。

黄灯接地,蓝灯接地,蓝灯接地5.1 ,绿色灯接地,绿色灯接地,绿色灯接地,绿色灯接5.0 我知道这不是最好的设置,但长度完全相同的导线和相同的上拉电阻适用于Arduino。

作为参考,Arduino是SparkFun RedBoard。

基本上,我需要帮助从使用I2C的VEML6070获取ACK。 我尝试过很多,但似乎没有获得积极的结果。

非常感谢您的帮助!

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

    这三张照片似乎没有通过。

    按顺序:

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    暂停不是问题;主从由时钟信号同步。

    没有最低频率。 快速模式只是更高的频率(以及更严格的电气规格以确保信号通过)。

    您没有看到停止,因为您没有告诉MSP发送停止。 (由于您没有收到一个字节,因此不会发生自动停止。)

    在最后一个读取字节之后,主中继器发送nack。 (随后必须重新启动或停止。)

    您无需输入重置状态即可更改从属地址寄存器。

    我看不出奴隶为什么不回答。 可能是因为错过了上一站而混淆了。 您可以尝试将其电源连接到GPIO输出,以便能够重置它。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    您好,Clemens:

    感谢您的快速响应!

    我认为暂停可能是Arduino I2C库中的一些内容,它们是我可以看到的MSP430输出(不工作)和Arduino (工作)之间最显著的差异之一。 就像等待SCL循环。

    Arduino还在5V逻辑上运行。 除此之外... MSP发出的信号对我来说非常强烈,确实令人困惑。

    MSP通信范围图片是  我发送的第一件事。 我想知道,是否如您所提到的那样,使用GPIO为VEML6070供电,只能 在 完成所有配置后才可使其打开。 您认为,在我提供的代码中,最好在哪里打开传感器? 我认为VEML6070可能会在MSP配置/启动期间读取SCL和SDA中的一些变化作为信号。 但是,这会很奇怪,因为Arduino同样总是为传感器供电。

    再次感谢。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    VEML6070数据表(www.vishay.com/.../veml6070.pdf) 介绍了"建议在150毫秒内完成"的初始化(我猜是从开机开始)。
    如果未提供初始化,则可能是设备不再回复。

    另请注意,您正在玩火,而不是制造不稳定的MSB和LSB变量。

    此致,

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

    Peppe,

    是的,这是一个好的观点。 我已经考虑过这一点,但Arduino测试代码(github.com/.../Adafruit_VEML6070

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

    数据表有点模糊,但我还没有收到给Vishay的电子邮件的回复(~3天)。

    我将尝试使用GPIO将其打开,然后快速初始化。 但是,Arduino代码(位于GitHub地址)似乎从未遵循初始化过程,但可以正常工作。 我有点迷路了。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您错了,Adafruit驱动程序正在执行调用Adafruit_VEML6070::BEGIN的初始化(uv.begin的结果)。
    此致,
    第页
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    您好,

    我看到它正在执行0x06写入,但根据数据表,它不会显示在第一个地址0x18中。 如果是,您能否指出它访问警报寄存器的位置?

    我将尝试在开机后不久发送写入命令。
  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。

    初始化中不需要地址0x18,它与确认活动任务相关。

    如您所见,值0x06必须写入保存LSB读数的同一0x38寄存器。

    此致,

    第页

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

    您好,

    我想你可能已经回答了我原来的问题,很快就会将其标记为这样。

    但是,I2C仍不能始终如一地工作。

    当我尝试发送第一个通信时,总线几乎总是(并非总是)繁忙。 考虑到UV传感器和MSP430目前是总线上唯一的产品,这种情况很奇怪。

    我已经知道它可能是接地不当,所以我检查了这一点。 但它没有解决问题。

    有人知道为什么我的代码显示总线繁忙吗? 以下是巴士繁忙时该点周围的线路。

    //初始化函数
    void UX_I2C_INIT(void){//
    	I2C UV
    	P8DIR的电源|= BIT2;
    	P8OUT &=~Ω(BIT2);
    
    	//为I2C模式配置USSCI_B1,发射器
    	UCB1CTLW0|= UCSWRST; //软件重置已启用
    	UCB1CTLW0 |= UCMODE_3 | UCMST | UCSYNC | UCTR | UCSSEL__SMCLK;// I2C模式,主模式,同步,UCTR = 1, SMCLK
    	UCB1CTLW1 |= UCASTP_2; //手动生成停止
    
    	//设置UCB1 (SDA和SCL函数,根据数据表)
    	P5DIR &=~(BIT0 | BIT1);
    	P5REN &=~(BIT0 | BIT1);
    	P5SEL1 &=~(BIT0 | BIT1);
    	P5SEL0 = BIT0 | BIT1;
    	达到后的BITRW
    	= UCBU1CB1;UCBN/ //波特率= SMCLK /(0x0200h = 512十进制)
    	UCB1TBCNT = 0x0001; //要接收的字节数(5)
    	UCB1I2CSA = 0x38; //写初始化地址
    	UCB1CTLW0 &=~UCSWRST;
    	__DELAY_CYCLES (1万);
    
    	//禁用GPIO通电默认高阻抗模式以激活
    	//先前配置的端口设置
    	PM5CTL0 &=~LOCKLPM5;
    
    	//初始化
    	P8OUT |= BIT2;//打开电源UCB1CTL0;
    	UCT1ST= UCT1CTUF0
    	
    	;CB1ST0
    	UCB1TXBUF = 0x06;
    	UCB1IFG &=~UCTXIFG0;//
    	清除标记while ((UCB1IFG & UCSTPIIFG)== 0);
    	UCB1IFG &=~UCSTPIIFG;
    } 

    谢谢。

  • 请注意,本文内容源自机器翻译,可能存在语法或其它翻译错误,仅供参考。如需获取准确内容,请参阅链接中的英语原文或自行翻译。
    我发现我现在的问题是硬件--从SCL到地面的电阻是5-44k,而SDA和ACK的电阻是1.5M。 要么我找到短款,要么买另一款。

    谢谢,我验证了您的解决方案!