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.
工具与软件:
大家好!
我要将 MSP 与 MPU-6050和 CCS811气体传感器进行连接、想通过 UART 查看相关值。
为此、我编码了两个函数、一个将整数值转换为字符串、另一个使用 UART 模块打印;在 main 函数中、我这样做:
while (1) { acc_comm(); //int_to_string(xAccel, num); //uart_puts(num); //int_to_string(yAccel, num); //uart_puts(num); //int_to_string(zAccel, num); //uart_puts(num); gases_comm(); //int_to_string(co2Lvl, num); //uart_puts(num); //int_to_string(tvocLvl, num); //uart_puts(num); // do something with the data __delay_cycles(500000); }
当我取消注释函数调用时、通信失败。
我想知道导致此问题发生的原因。 我想 I2C 线路不能空闲、但没有这方面的确认;你们的任何帮助都会非常感谢。
为了便于参考、我将两个函数代码保留在此处:
void int_to_string(int num, unsigned char *str) { unsigned char i = 0, j = 0; char aux[5]; do { aux[i++] = num % 10 + '0'; num /= 10; } while(num > 0); while(i--) { str[j++] = aux[i]; } str[j] = '\0'; } void uart_puts(unsigned char *str) { while(*str) { while(!(IFG2 & UCA0TXIFG)); UCA0TXBUF = *str++; } UCA0TXBUF = '\n'; }
此外、I2C 和 UART 的配置代码与 TI 开发人员专区中的示例相同。
通信以何种方式失败? (暂停? NACK? 无效数据?) 您改编/采用了哪个 TI 示例? (我记得有几个。)
如何声明"num"(在 main 中)? 是否可能发生缓冲区溢出?
CCS811寄存器抽象有一点不常见;我想知道其中是否有某些临界情况。
您好!
应用这些函数时、似乎未进行通信。
下图显示了逻辑分析仪输出:
至于使用的示例、对于 UART、我只使用9600波特和1MHz 的配置、但不使用 ISR;对于 I2C、最好共享代码:
//********************************************************************************************* void i2cInit(void) { // set up I2C pins P1SEL |= BIT6 | BIT7; // Assign I2C pins to USCI_B0 P1SEL2|= BIT6 | BIT7; // Assign I2C pins to USCI_B0 // set up I2C module UCB0CTL1 |= UCSWRST; // Enable SW reset UCB0CTL0 = UCMST | UCMODE_3 | UCSYNC; // I2C Master, synchronous mode UCB0CTL1 = UCSSEL_2 | UCSWRST; // Use SMCLK, keep SW reset UCB0BR0 = 10; // fSCL = SMCLK/10 = ~100kHz UCB0BR1 = 0; UCB0CTL1 &= ~UCSWRST; // Clear SW reset, resume operation IE2 |= UCB0RXIE | UCB0TXIE; } //********************************************************************************************* void i2cWrite(unsigned char address) { IFG2 &= ~(UCB0TXIFG + UCB0RXIFG); // Clear pending interrupts UCB0I2CSA = address; // Load slave address IE2 |= UCB0TXIE; // Enable TX interrupt while(UCB0CTL1 & UCTXSTP); // Ensure stop condition sent UCB0CTL1 |= UCTR | UCTXSTT; // TX mode and START condition __bis_SR_register(CPUOFF | GIE); // sleep until UCB0TXIFG is set ... } //********************************************************************************************* void i2cRead(unsigned char address) { IFG2 &= ~(UCB0TXIFG + UCB0RXIFG); // Clear pending interrupts UCB0I2CSA = address; // Load slave address IE2 |= UCB0RXIE; // Enable RX interrupt while(UCB0CTL1 & UCTXSTP); // Ensure stop condition sent UCB0CTL1 &= ~UCTR; // RX mode UCB0CTL1 |= UCTXSTT; // Start Condition __bis_SR_register(CPUOFF | GIE); // sleep until UCB0RXIFG is set ... } /**********************************************************************************************/ // USCIAB0TX_ISR #pragma vector = USCIAB0TX_VECTOR __interrupt void USCIAB0TX_ISR(void) { if(UCB0CTL1 & UCTR) // TX mode (UCTR == 1) { if (TX_ByteCtr) // TRUE if more bytes remain { TX_ByteCtr--; // Decrement TX byte counter UCB0TXBUF = TX_Data[TX_ByteCtr]; // Load TX buffer } else // no more bytes to send { UCB0CTL1 |= UCTXSTP; // I2C stop condition IFG2 &= ~UCB0TXIFG; // Clear USCI_B0 TX int flag __bic_SR_register_on_exit(CPUOFF); // Exit LPM0 } } else // (UCTR == 0) // RX mode { RX_ByteCtr--; // Decrement RX byte counter if (RX_ByteCtr) // RxByteCtr != 0 { RX_Data[RX_ByteCtr] = UCB0RXBUF; // Get received byte if (RX_ByteCtr == 1) // Only one byte left? UCB0CTL1 |= UCTXSTP; // Generate I2C stop condition } else // RxByteCtr == 0 { RX_Data[RX_ByteCtr] = UCB0RXBUF; // Get final received byte IFG2 &= ~UCB0RXIFG; // Clear RX flag //int_to_str(RX_Data, num); //uart_puts(num); __bic_SR_register_on_exit(CPUOFF); // Exit LPM0 } } }
这些函数和 ISR 适用于这两个传感器、只需要切换地址。
数组 num 声明为无符号字符;关于 缓冲区溢出、这是一个好问题。
如果您在调试器中暂停、程序在哪里执行? 在第一个事务之后添加代码会导致第一个事务失败、这似乎很奇怪。
您好!
我使用 platformIO 进行开发、但我不能使用调试器、尽管按照提供的文档进行操作。
CCS Studio 在 Linux 上不适用于我的 MCU、我在这里的一些线程中确认这是由于微控制器淘汰造成的。
我再次执行代码以验证一次观察结果并猜测是什么? 它正在工作(无法解释)!
但是、分隔传感器读数的3对转换和打印相加的延迟为10毫秒。 这可能会导致通信失败?
如果没有调试器、这就很难实现。
我不熟悉 platformIO,但由于它指的是一个"框架",我想知道它是否会造成一些堆栈大小的成本。 G2553中相对较小的 SRAM 可使平衡堆栈大小变得棘手。
我在使用 CCS 12.6.0与 G2553配合使用时没有遇到问题、不过这是在 Windows 上使用的。 platformIO 还声称能够使用 Launchpad (板载调试接口)进行调试、但可能是"还不是全部使用"?
也就是说、如果您受困于(我们过去所调用的)"printf 调试"、我会先绕过"uart_puts ("Step 1\r\m")"等调用来看看您能实现多远。 uart_puts()具有同步的优点、只需要很少的栈。 TI 编译器将常量字符串放置在闪存中、因此不会影响 SRAM。
如何在 main 中声明"num"? 我知道它是"unsigned char num[ ];"。 的值 可能是一个线索。
是的,文档说,所以,但我不知道我是否有一些错误的步骤,但遵循参考和添加解决方案的错误记录在 foruns 是不够的。
我这样声明数组:
unsigned char num[] = {'0','0','0','0','0','\0'};
两个传感器都具有相关的数据、长度为16位、因此我认为一个包含5个位置的阵列就足够了。
现在、我正在研究一些数据的奇怪而错误的输出、 执行似乎是稳定的。
我将介绍一种使用 Windows 操作系统来使用 CCS 的方法、并研究可能的堆栈大小成本和缓冲区溢出。 您是否认为通信失败 可能是由内存问题引起的?
顺便说一下、感谢您到目前为止的帮助。
我没有您的设备、也没有您的开发工具(或您的整个源代码)、因此我只能做一些一般性的陈述:
1) 1)如果您在 I2C 上从未看到任何活动、则第一个猜测是您的程序未在运行(正在运行)。
2)堆栈或缓冲区溢出会产生不可预测的结果、其中一个可能未运行(在未初始化的存储器中旋转、反复非常快速地复位、卡在 LPM 中)。
3) G2553上的 SRAM 相当有限。
因此、我想知道程序认为它在做什么。 如果您有调试器、您可以暂停并查看。 否则,一组 UART_PUT()进度指示器会有所帮助。
您好! 很抱歉耽误你的时间。
尝试在 Windows 上下载 CCS 12.7、但仍然无法使用 MCU 的调试器。
现在我使用 MSP430FR2433更改了目标、不知道该线程是否仍然适合、或者我必须创建另一个线程。
我会将使用的代码迁移到新的 MCU、现在我只对 I2C 接口进行编码、以便与加速计进行通信、而且使用在 Linux 中安装的 CCS 调试器、并验证 UCBBUSY 是否在数据采集的第二次迭代中设置。
我已经输出了10k 个电阻器并检查了引脚配置、 如此处所述。
以下是 I2C 的配置:
/** * Configuration of I2C module */ void i2c_conf(void) { // I2C pins configuration P1SEL0 |= BIT2 | BIT3; // Disable the GPIO power-on default high-impedance mode to activate // previously configured port settings PM5CTL0 &= ~LOCKLPM5; // Configure USCI_B0 for I2C mode UCB0CTLW0 |= UCSWRST; // Software reset enabled UCB0CTLW0 |= UCMODE_3 | UCMST; // I2C mode, Master mode UCB0CTLW0 |= UCSSEL__SMCLK | UCSYNC; // Use SMCLK as clock source, sync UCB0CTLW1 |= UCASTP_2; // Automatic stop generated by // reaching data acquisition boundary UCB0BRW = 0x000A; // baudrate = SMCLK / 10 = 100 kHz UCB0CTL1 &= ~UCSWRST; // Disable SW reset UCB0IE |= UCTXIE | UCRXIE | UCBCNTIE; // Enable Tx, RX, and count interruptions }
这是 ISR;除了 UCB0TBCNT 接收 byteCtr 之外、写入和读取函数保持不变
/** * UCB0 ISR */ #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector = USCI_B0_VECTOR __interrupt void USCIB0_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCIB0_ISR (void) #else #error Compiler not supported! #endif { switch(__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG)) { case USCI_I2C_UCRXIFG0: RX_ByteCtr--; if(RX_ByteCtr) { RX_Data[RX_ByteCtr] = UCB0RXBUF; // Store RX'd byte } break; case USCI_I2C_UCTXIFG0: if(TX_ByteCtr) { TX_ByteCtr--; UCB0TXBUF = TX_Data[TX_ByteCtr]; // Load TX buffer } break; case USCI_I2C_UCBCNTIFG: __bic_SR_register_on_exit(CPUOFF); break; } }
1) 1)请记住、仅当 I2C 单元处于复位状态(UCSWRST=1)时才能更改 UCB0TBCNT。 我看不到您在 i2c_conf()中设置它。
2) 2)(a)在最后一个字节之后停止条件被(自动)发出之前、UCBCNTIFG 被置位、(b)停止需要一段时间、(c)在一个停止等待期间、eUSCI 对发出一个启动十分敏感。
这就是为什么您会在新操作的设置中经常看到这一点的原因:
> while (UCB0CTLW0 & UCTXSTP)/* empty*/; //等待之前的操作(停止)完成
我删除了 UCB0TBCNT 中断使能和处理。 现在在 UCB0CTLW0 |= UCTR | UCTXSTT 后置位 UCBBUSY 和 UCSCLLOW 时、我遇到了问题。 已尝试通过8位版本(UCB0CTL1)进行访问、但遇到了同样的问题。
是否围绕设置 UCB0TBCNT 复位 I2C (UCSWRST=1、然后=0)? 如果不是这样、可能是 UCB0TBCNT=0、我不是很确定 UCASTP=2对这一点做了什么(我还没有尝试过)。 请记住、复位 I2C 会设置 UCB0IE=0、因此必须将它们放回。
是否正在等待 UCTXSTP 清除后再开始新的操作(UCTXSTT)?
几周前、我为 FR2433编写了代码、以便与 MPU-6050通信[现在其他人拥有]、我不记得该器件有任何特别之处。 可能有助于您发布 I2C 读取/写入函数。
当然、这里是:
/** * Write function */ void i2c_wr(unsigned char addr) { UCB0CTL1 |= UCSWRST; UCB0I2CSA = addr; // Slave address UCB0TBCNT = TX_ByteCtr; UCB0CTL1 &= ~UCSWRST; UCB0IE |= UCTXIE | UCRXIE; // Enable Tx and RX interruptions while(UCB0CTL1 & UCTXSTP); // Ensure stop condition sent UCB0CTL1 |= UCTR; // Transmitter mode UCB0CTL1 |= UCTXSTT; // and send START condition __bis_SR_register(LPM0_bits|GIE); // Enter LPM0 w/ interrupt } /** * Read function */ void i2c_rd(unsigned char addr) { UCB0CTL1 |= UCSWRST; UCB0I2CSA = addr; // Slave address UCB0TBCNT = RX_ByteCtr; UCB0CTL1 &= ~UCSWRST; UCB0IE |= UCTXIE | UCRXIE; // Enable Tx and RX interruptions while(UCB0CTL1 & UCTXSTP); // Ensure stop condition sent UCB0CTL1 &= ~UCTR; // Receiver mode UCB0CTL1 |= UCTXSTT; // and send START condition __bis_SR_register(LPM0_bits|GIE); // Enter LPM0 w/ interrupt }
UCBBUSY 和 UCSCLLOW 仍被置位。 由于在调试器中 UCTXSTT 已清除、所以发送了 START (可能吗?)。
这看起来是合理的;我建议移动 UCTXSTP 检查、使其先于复位(UCSWRST)、因为复位可能会干扰(持续)停止。
回顾 ISR、这看起来是个1次关断:
case USCI_I2C_UCRXIFG0: RX_ByteCtr--; if(RX_ByteCtr) { RX_Data[RX_ByteCtr] = UCB0RXBUF; // Store RX'd byte } break;
例如、如果您以 RxByteCtr=1开始、那么它根本不会读取 UCB0RXBUF。 对 RXBUF 的读取会绑定到流量控制中、因此可能会挂起总线。 您可能应该在 if ()块内移动递减。
以下是更新后的函数和 ISR:
/** * Write function */ void i2c_wr(unsigned char addr) { while(UCB0CTL1 & UCTXSTP); // Ensure stop condition sent UCB0CTL1 |= UCSWRST; UCB0I2CSA = addr; // Slave address UCB0TBCNT = TX_ByteCtr; UCB0CTL1 &= ~UCSWRST; UCB0IE |= UCTXIE | UCRXIE | UCBCNTIE; // Enable Tx and RX interruptions UCB0CTL1 |= UCTR; // Transmitter mode UCB0CTL1 |= UCTXSTT; // and send START condition __bis_SR_register(LPM0_bits|GIE); // Enter LPM0 w/ interrupt } /** * Read function */ void i2c_rd(unsigned char addr) { while(UCB0CTL1 & UCTXSTP); // Ensure stop condition sent UCB0CTL1 |= UCSWRST; UCB0I2CSA = addr; // Slave address UCB0TBCNT = RX_ByteCtr; UCB0CTL1 &= ~UCSWRST; UCB0IE |= UCTXIE | UCRXIE | UCBCNTIE; // Enable Tx and RX interruptions UCB0CTL1 &= ~UCTR; // Receiver mode UCB0CTL1 |= UCTXSTT; // and send START condition __bis_SR_register(LPM0_bits|GIE); // Enter LPM0 w/ interrupt } /** * UCB0 ISR */ #if defined(__TI_COMPILER_VERSION__) || defined(__IAR_SYSTEMS_ICC__) #pragma vector = USCI_B0_VECTOR __interrupt void USCIB0_ISR(void) #elif defined(__GNUC__) void __attribute__ ((interrupt(USCI_B0_VECTOR))) USCIB0_ISR (void) #else #error Compiler not supported! #endif { switch(__even_in_range(UCB0IV, USCI_I2C_UCBIT9IFG)) { case USCI_I2C_UCRXIFG0: if (RX_ByteCtr--) { RX_Data[RX_ByteCtr] = UCB0RXBUF; // Get received byte } break; case USCI_I2C_UCTXIFG0: if (TX_ByteCtr--) // TRUE if more bytes remain { UCB0TXBUF = TX_Data[TX_ByteCtr]; // Load TX buffer } break; case USCI_I2C_UCBCNTIFG: __bic_SR_register_on_exit(CPUOFF); // Exit LPM0 break; } }
从而得出:
数据线保持高电平、但正在生成时钟。
再试一次、得到以下结果:
在第三次尝试中、我收到了 accel 值。
这太奇怪了...
顶部的配置看起来特别奇怪、因为没有启动/停止条件、但 SCL 看起来很合理。
是否复位 MPU-6050 (寄存器0x6B)? 如果是、您是否在等待器件启动? 数据表要求为30ms、但我记得我给它的时间大约为100ms。
我在传感器唤醒块中添加了一个延迟。 现在,它似乎工作正常,谢谢你先生。
现在、我将添加气体传感器寄存器和 UART。 我认为最好创建另一个线程。
我很高兴您启动了该工具。 我希望下一款器件会更简单。
CCS811唯一与众不同的地方在于、它具有多字节寄存器("邮箱")、这些寄存器不是寄存器空间中的连续字节、这意味着您不能在单个事务中读取多个寄存器(或许这不重要)。
您好!
我创建了另一个线程来处理这个主题,因为我认为它与最初的 问题不同。
单击 此处 访问。
再次感谢您到目前为止的帮助!