Проблема повторения команд основной функции в C

Я Нох.

Я пытаюсь управлять микроконтроллером с помощью кода C. И я использую код, полученный с GitHub. (Вот ссылка https://github.com/jwr/msp430_usi_i2c)

Я столкнулся с проблемой, что основная функция не останавливается. Несмотря на то, что в 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 (регистратор данных связи), и я думаю, вы можете видеть, что поток команд повторяется (от «Запись 00» до «Чтение EE»)

Я понятия не имею, почему основная функция повторяется без какой-либо функции цикла.

Я хочу, чтобы этот код запускал поток команд основной функции только один раз.

Вы случайно не знаете, почему это происходит и как решить эту проблему? 😥

Спасибо!

Искренне нет

Кажется, вам не хватает отступа.

William Pursell 19.11.2022 13:39

Что вы ожидаете, когда main() завершится на микроконтроллере? Возможно, то, что вызывает main(), вызывает его в цикле. Если вы хотите, чтобы ваш код просто останавливался, поместите бесконечный цикл в конце main().

pmacfarlane 19.11.2022 14:41

Сделайте правильный отступ в коде перед публикацией. Мы, которые отвечают на ваши вопросы, должны прочитать ваш код. Поэтому вы должны сделать его максимально читабельным.

klutt 19.11.2022 18:14
[JS за 1 час] - 9. Асинхронный
[JS за 1 час] - 9. Асинхронный
JavaScript является однопоточным, то есть он может обрабатывать только одну задачу за раз. Для обработки длительных задач, таких как сетевые запросы,...
Топ-10 компаний-разработчиков PHP
Топ-10 компаний-разработчиков PHP
Если вы ищете надежных разработчиков PHP рядом с вами, вот список лучших компаний по разработке PHP.
Скраппинг поиска Apple App Store с помощью Python
Скраппинг поиска Apple App Store с помощью Python
📌Примечание: В этой статье я покажу вам, как скрапировать поиск Apple App Store и получить точно такой же результат, как на Apple iMac, потому что...
Редкие достижения на Github ✨
Редкие достижения на Github ✨
Редкая коллекция доступна в профиле на GitHub ✨
Подъем в javascript
Подъем в javascript
Hoisting - это поведение в JavaScript, при котором переменные и объявления функций автоматически "перемещаются" в верхнюю часть соответствующих...
Улучшение генерации файлов Angular
Улучшение генерации файлов Angular
Angular - это фреймворк. Вы можете создать практически любое приложение без использования сторонних библиотек.
1
3
62
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Большинство программ для микроконтроллера имеют некоторый код инициализации на языке ассемблера, который выполняет некоторую базовую настройку микроконтроллера, копирует раздел данных из флэш-памяти в ОЗУ, обнуляет .bss, а затем переходит к main().

Как правило, main() никогда не возвращается. Он будет состоять из бесконечного цикла, выполняющего любые задачи, для которых предназначено программное обеспечение, до тех пор, пока не будет отключено питание.

Так что возврат вашего кода не очень типичен. Что должен делать MCU, если main() вернется? Ему больше нечего запускать. Некоторые варианты для этого могут быть:

  1. Вращение ничего не делая
  2. Снова вызовите main() (в цикле)
  3. Сбросьте MCU, который эффективно перезапустит ваш код

Похоже, в вашем случае происходит либо 2, либо 3.

Если вы хотите, чтобы ваш код просто останавливался после того, как он сделал свое дело, добавьте пустой бесконечный цикл в конце main():

for (;;)
    ;

Благодарю за ваш ответ. Я пытался использовать возврат; и бесконечный цикл каждый раз, но проблема все еще возникает. Думаю, мне следует найти функцию, вызывающую main(). Это может быть вызов main() в цикле.

Noh-Ahyun 21.11.2022 03:37

Вы не хотите возвращаться из main(). Вам просто нужен бесконечный цикл.

pmacfarlane 21.11.2022 12:12

Если бесконечный цикл в конце main() не останавливает повторение main(), то, возможно, включен сторожевой таймер, который вызывает сброс.

kkrambo 21.11.2022 21:16

@kkrambo Да, согласен. Неясно, пробовал ли Но бесконечный цикл самостоятельно и возвращал его самостоятельно. Или (сбивчиво) вернуться; затем бесконечный цикл.

pmacfarlane 21.11.2022 23:06

Другие вопросы по теме