繁体   English   中英

C中Main函数的命令重复问题

[英]Main function's command repetition problem in C

我是诺

我正在尝试使用 C 代码控制微控制器。 我正在使用从 GitHub 获得的代码。(这是链接https://github.com/jwr/msp430_usi_i2c

我遇到了main function不停的问题。 即使在 main 中没有循环命令,命令流也会一次又一次地重复。

我写的命令流程如下。

写00→写AF→写00→写05→写45→写40→写03→写B0→读EE

您可以看到命令流从头到尾重复。

请参考下面的代码和通信结果。

#include <msp430.h>
#include <stdint.h>
#include "usi_i2c.h"

#include <stdio.h>
#include <stdlib.h>

// Internal state
static uint16_t const *i2c_sequence;
static uint16_t i2c_sequence_length;
static uint8_t *i2c_receive_buffer;
static uint16_t i2c_wakeup_sr_bits;
i2c_state_type i2c_state = I2C_IDLE;

static uint8_t status;

static inline void i2c_prepare_stop();
static inline void i2c_prepare_data_xmit_recv();

void i2c_send_sequence(uint16_t const * sequence,
                       uint16_t sequence_length,
                       uint8_t *received_data,
                       uint16_t wakeup_sr_bits) {
  while(i2c_state != I2C_IDLE); // we can't start another sequence until the current one is done
  while((status==0xEE)|(status==0xEF)) P1OUT |= 0x01;
    P1OUT &= ~0x01;
  i2c_sequence = sequence;
  i2c_sequence_length = sequence_length;
  i2c_receive_buffer = received_data;
  i2c_wakeup_sr_bits = wakeup_sr_bits;
  i2c_state = I2C_START;
  USICTL1 |= USIIFG; // actually start communication
}

static inline void i2c_prepare_stop() {
  USICTL0 |= USIOE; // SDA = output
  USISRL = 0x00;
  USICNT |= 0x01; // Bit counter= 1, SCL high, SDA low
  i2c_state = I2C_STOP;
}

static inline void i2c_prepare_data_xmit_recv() {
  if(i2c_sequence_length == 0) {
    i2c_prepare_stop(); // nothing more to do, prepare to send STOP
  } else {
  if(*i2c_sequence == I2C_RESTART) {
    USICTL0 |= USIOE; // SDA = output
    USISRL = 0xff; // prepare and send a dummy bit, so that SDA is high
    USICNT = (USICNT & 0xE0) | 1;
    i2c_state = I2C_START;
  }
  else if(*i2c_sequence == I2C_READ) {
    USICTL0 &= ~USIOE; // SDA = input
    USICNT = (USICNT & 0xE0) | 8; // Bit counter = 8, RX data
    i2c_state = I2C_RECEIVED_DATA; // next state: Test data and ACK/NACK
  } else { // a write
    (*i2c_sequence >> 8) == 0
    USICTL0 |= USIOE; // SDA = output
    USISRL = (char)(*i2c_sequence); // Load data byte
    USICNT = (USICNT & 0xE0) | 8; // Bit counter = 8, start TX
    i2c_state = I2C_PREPARE_ACKNACK; // next state: prepare to receive data ACK/NACK
  }
  i2c_sequence++;
  i2c_sequence_length--;
  }
}

#ifdef __GNUC__
__attribute__((interrupt(USI_VECTOR)))
#else
#pragma vector = USI_VECTOR
__interrupt
#endif
void USI_TXRX(void)
{
switch(__even_in_range(i2c_state,12)) {
case I2C_IDLE:
break;

case I2C_START: // generate start condition
  USISRL = 0x00;
  USICTL0 |= (USIGE|USIOE);
  USICTL0 &= ~USIGE;
  i2c_prepare_data_xmit_recv();
  break;

case I2C_PREPARE_ACKNACK: // prepare to receive ACK/NACK
  USICTL0 &= ~USIOE; // SDA = input
  USICNT |= 0x01; // Bit counter=1, receive (N)Ack bit into USISRL
  i2c_state = I2C_HANDLE_RXTX; // Go to next state: check ACK/NACK and 
  continue xmitting/receiving if necessary
  break;

case I2C_HANDLE_RXTX: // Process Address Ack/Nack & handle data TX
  if((USISRL & BIT0) != 0) { // did we get a NACK?
  i2c_prepare_stop();
  } else {
  i2c_prepare_data_xmit_recv();
  }
  break;

case I2C_RECEIVED_DATA: // received data, send ACK/NACK
  *i2c_receive_buffer = USISRL;
  i2c_receive_buffer++;
  USICTL0 |= USIOE; // SDA = output
  if(i2c_sequence_length > 0) {
    // If this is not the last byte
    USISRL = 0x00; // ACK
    i2c_state = I2C_HANDLE_RXTX; // Go to next state: data/rcv again
  } else { // last byte: send NACK
    USISRL = 0xff; // NACK
    i2c_state = I2C_PREPARE_STOP; // stop condition is next
  }
  USICNT |= 0x01; // Bit counter = 1, send ACK/NACK bit
  break;

case I2C_PREPARE_STOP: // prepare stop condition
  i2c_prepare_stop(); // prepare stop, go to state 14 next
  break;

case I2C_STOP: // Generate Stop Condition
  USISRL = 0x0FF; // USISRL = 1 to release SDA
  USICTL0 |= USIGE; // Transparent latch enabled
  USICTL0 &= ~(USIGE|USIOE); // Latch/SDA output disabled
  i2c_state = I2C_IDLE; // Reset state machine for next xmt
  if(i2c_wakeup_sr_bits) {
    _bic_SR_register_on_exit(i2c_wakeup_sr_bits); // exit active if prompted to
  }
  break;
  }
  USICTL1 &= ~USIIFG; // Clear pending flag
}

void main(){
  i2c_init(USIDIV_5, USISSEL_2);

  uint16_t PUP[] = {0xEA, 0x00};
  uint16_t PDWN[] = {0xEA, 0x20};

  uint16_t CVOL_PowerUp[] = {0xEA, 0xAF, 0x00};
  uint16_t AMODE_PowerUp[] = {0xEA, 0x05, 0x45};
  uint16_t AMODE_PowerDown[] = {0xEA, 0x05, 0x41};

  uint16_t RDSTAT_Command[] = {0xEA, 0xB0};
  uint16_t RDSTAT_Read[] = {0xEB, I2C_READ};

  uint16_t START[] = {0xEA, 0x51};

  uint16_t PLAY[] = {0xEA, 0x40, 0x03};
  uint16_t STOP[] = {0xEA, 0x61};

  i2c_send_sequence(PUP, 2, &status, LPM0_bits); // 00

  i2c_send_sequence(CVOL_PowerUp, 3, &status, LPM0_bits); // AF 00
  i2c_send_sequence(AMODE_PowerUp, 3, &status, LPM0_bits); // 05 45
  i2c_send_sequence(PLAY, 3, &status, LPM0_bits); // 40 03

  i2c_send_sequence(RDSTAT_Command, 2, &status, LPM0_bits); // B0
  i2c_send_sequence(RDSTAT_Read, 2, &status, LPM0_bits);
}

void i2c_init(uint16_t usi_clock_divider, uint16_t usi_clock_source) {
  _disable_interrupts();
  USICTL0 = USIPE6|USIPE7|USIMST|USISWRST; // Port & USI mode setup
  USICTL1 = USII2C|USIIE; // Enable I2C mode & USI interrupt
  USICKCTL = usi_clock_divider | usi_clock_source | USICKPL;
  USICNT |= USIIFGCC; // Disable automatic clear control
  USICTL0 &= ~USISWRST; // Enable USI
  USICTL1 &= ~USIIFG; // Clear pending flag
  _enable_interrupts();

  P1OUT = 0xC0; // P1.6 & P1.7 Pullups, others to 0
  P1REN |= 0xC0; // P1.6 & P1.7 Pullups
  P1DIR = 0xFF; // Unused pins as outputs
  P2OUT = 0;
  P2DIR = 0xFF;
}

这是使用 Beagle(通信数据记录器)得到的代码运行结果,我相信你可以看到命令流在重复(从'Write 00'到'Read EE')

我不知道为什么主 function 没有任何循环 function 重复。

我希望这段代码只运行一次主函数的命令流。

您碰巧知道为什么会发生这种情况以及如何解决这个问题吗?

谢谢!

真诚的能

大多数微控制器程序都有一些汇编语言初始化代码,这些代码对 MCU 进行一些基本配置,将数据部分从 flash 复制到 RAM,将 the.bss 清零,然后跳转到 main()。

通常,main() 永远不会返回。 它将由一个无限循环组成,永远执行软件打算执行的任何任务,直到电源被移除。

所以你的代码返回不是很典型。 如果 main() 返回,MCU 打算做什么? 它没有其他可运行的。 它的一些选择可能是:

  1. 旋转什么都不做
  2. 再次调用 main()(在循环中)
  3. 重置 MCU,这会有效地重新启动您的代码

在您的情况下,这听起来像是 2 或 3 正在发生。

如果你想让你的代码在完成它的事情后就停止,在 main() 的末尾添加一个空的无限循环:

for (;;)
    ;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM