简体   繁体   English

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

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

I'm Noh.我是诺

I'm trying to control Microcontroller with C code.我正在尝试使用 C 代码控制微控制器。 And I'm using a code I got from GitHub. (Here's the link https://github.com/jwr/msp430_usi_i2c )我正在使用从 GitHub 获得的代码。(这是链接https://github.com/jwr/msp430_usi_i2c

I encountered the problem that main function doesn't stop.我遇到了main function不停的问题。 Even though there's no loop command in main, command flow repeats again and again.即使在 main 中没有循环命令,命令流也会一次又一次地重复。

I write command flow like below.我写的命令流程如下。

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

And you can see the command flow repeats from beginning to end.您可以看到命令流从头到尾重复。

Please refer to below code and the communication result.请参考下面的代码和通信结果。

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

I have no idea why main function repeats without any loop function.我不知道为什么主 function 没有任何循环 function 重复。

I want this code run main function's command flow only once.我希望这段代码只运行一次主函数的命令流。

Do you happen to know why this happens and how to resolve this problem?您碰巧知道为什么会发生这种情况以及如何解决这个问题吗?

Thank you!谢谢!

Sincerely Noh真诚的能

Most programs for a microcontroller have some assembly language initialisation code that does some basic configuration of the MCU, copies the data section from flash to RAM, zeros the.bss, then jumps to main().大多数微控制器程序都有一些汇编语言初始化代码,这些代码对 MCU 进行一些基本配置,将数据部分从 flash 复制到 RAM,将 the.bss 清零,然后跳转到 main()。

Typically, main() would never return.通常,main() 永远不会返回。 It would consist of an infinite loop, doing whatever tasks the software is meant to do, forever, until power is removed.它将由一个无限循环组成,永远执行软件打算执行的任何任务,直到电源被移除。

So your code returning is not very typical.所以你的代码返回不是很典型。 What is the MCU meant to do if main() returns?如果 main() 返回,MCU 打算做什么? It has nothing else to run.它没有其他可运行的。 Some options for it might be to:它的一些选择可能是:

  1. Spin doing nothing旋转什么都不做
  2. Call main() again (in a loop)再次调用 main()(在循环中)
  3. Reset the MCU, which effectively restarts your code重置 MCU,这会有效地重新启动您的代码

It sounds like, in your case, either 2 or 3 is happening.在您的情况下,这听起来像是 2 或 3 正在发生。

If you want your code to just stop after it has done its thing, add an empty infinite loop at the end of main():如果你想让你的代码在完成它的事情后就停止,在 main() 的末尾添加一个空的无限循环:

for (;;)
    ;

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

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