Я Нох.
Я пытаюсь управлять микроконтроллером с помощью кода 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»)
Я понятия не имею, почему основная функция повторяется без какой-либо функции цикла.
Я хочу, чтобы этот код запускал поток команд основной функции только один раз.
Вы случайно не знаете, почему это происходит и как решить эту проблему? 😥
Спасибо!
Искренне нет
Что вы ожидаете, когда main() завершится на микроконтроллере? Возможно, то, что вызывает main(), вызывает его в цикле. Если вы хотите, чтобы ваш код просто останавливался, поместите бесконечный цикл в конце main().
Сделайте правильный отступ в коде перед публикацией. Мы, которые отвечают на ваши вопросы, должны прочитать ваш код. Поэтому вы должны сделать его максимально читабельным.
Большинство программ для микроконтроллера имеют некоторый код инициализации на языке ассемблера, который выполняет некоторую базовую настройку микроконтроллера, копирует раздел данных из флэш-памяти в ОЗУ, обнуляет .bss, а затем переходит к main().
Как правило, main() никогда не возвращается. Он будет состоять из бесконечного цикла, выполняющего любые задачи, для которых предназначено программное обеспечение, до тех пор, пока не будет отключено питание.
Так что возврат вашего кода не очень типичен. Что должен делать MCU, если main() вернется? Ему больше нечего запускать. Некоторые варианты для этого могут быть:
Похоже, в вашем случае происходит либо 2, либо 3.
Если вы хотите, чтобы ваш код просто останавливался после того, как он сделал свое дело, добавьте пустой бесконечный цикл в конце main():
for (;;)
;
Благодарю за ваш ответ. Я пытался использовать возврат; и бесконечный цикл каждый раз, но проблема все еще возникает. Думаю, мне следует найти функцию, вызывающую main(). Это может быть вызов main() в цикле.
Вы не хотите возвращаться из main(). Вам просто нужен бесконечный цикл.
Если бесконечный цикл в конце main() не останавливает повторение main(), то, возможно, включен сторожевой таймер, который вызывает сброс.
@kkrambo Да, согласен. Неясно, пробовал ли Но бесконечный цикл самостоятельно и возвращал его самостоятельно. Или (сбивчиво) вернуться; затем бесконечный цикл.
Кажется, вам не хватает отступа.