C语言中主函数命令重复问题

evrscar2  于 2022-12-03  发布在  其他
关注(0)|答案(1)|浏览(223)

我叫卢
我正在尝试用C代码控制微控制器。我使用的是我从GitHub获得的代码。(这里是链接https://github.com/jwr/msp430_usi_i2c
我遇到了main函数不停止的问题。尽管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;
}

This is code run result gotten by using Beagle(communication data recorder), and I believe you can see command flow is repeating (from 'Write 00' to 'Read EE')
我不知道为什么主函数重复没有任何循环函数。
我希望这段代码只运行main函数的命令流一次。
您是否知道为什么会发生这种情况以及如何解决此问题?😥
谢谢你,谢谢你
此致Noh

mnemlml8

mnemlml81#

微控制器的大多数程序都有一些汇编语言初始化代码,用于执行MCU的一些基本配置,将数据段从闪存复制到RAM,将.bss置零,然后跳转到main()。
通常情况下,main()函数永远不会返回,它会构成一个无限循环,永远执行软件应该执行的任务,直到电源被切断。
所以你的代码返回不是很典型。如果main()返回,MCU要做什么?它没有其他要运行的东西。它的一些选项可能是:
1.自旋无所作为
1.再次调用main()(在循环中)
1.重置MCU,这将有效地重新启动代码
听起来,在你的情况下,要么发生2,要么发生3。
如果你想让你的代码在完成它的工作后就停止,在main()的末尾添加一个空的无限循环:

for (;;)
    ;

相关问题