int main зацикливается без видимой причины? (программирование PIC, XC16, MPLAB) dsPIC33EP

Работа над программой для dcPIC33 (очевидно, написанной на c) с использованием компилятора XC16 и MPLABX v2.10 IDE. Я реализовал некоторые функции, одной из которых является отправка строк текста на UART, чтобы я мог видеть последовательный вывод с помощью последовательного терминала. Моя проблема находится в этой строке.

UART_Write_Text("Starting ADXL345 test...fdsbjugbbjkdsf");

Который, когда вы смотрите на приведенный ниже код, должен запускаться только один раз, однако он всегда повторяется в терминале, как если бы int main зацикливался, хотя у main есть цикл while внизу, чтобы он не заканчивался, я просто не вижу как ему удается так зацикливаться.

    /* 
 * File:   main2.c
 * Author: nedu
 *
 * Created on 14 July 2014, 15:57
 */
#include <xc.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

#if __XC16_VERSION < 1011
#warning "Please upgrade to XC16 v1.11 or newer."
#endif

#pragma config ICS = PGD3           // ICD Communication Channel Select bits (Communicate on PGEC3 and PGED3)
#pragma config JTAGEN = OFF         // JTAG Enable bit (JTAG is disabled)

// FPOR
#pragma config ALTI2C1 = OFF        // Alternate I2C1 pins (I2C1 mapped to SDA1/SCL1 pins)
#pragma config ALTI2C2 = OFF        // Alternate I2C2 pins (I2C2 mapped to SDA2/SCL2 pins)
#pragma config WDTWIN = WIN25       // Watchdog Window Select bits (WDT Window is 25% of WDT period)

// FWDT
#pragma config WDTPOST = PS32768    // Watchdog Timer Postscaler bits (1:32,768)
#pragma config WDTPRE = PR128       // Watchdog Timer Prescaler bit (1:128)
#pragma config PLLKEN = ON          // PLL Lock Enable bit (Clock switch to PLL source will wait until the PLL lock signal is valid.)
#pragma config WINDIS = OFF         // Watchdog Timer Window Enable bit (Watchdog Timer in Non-Window mode)
#pragma config FWDTEN = OFF         // Watchdog Timer Enable bit (Watchdog timer enabled/disabled by user software)

// FOSC
#pragma config POSCMD = NONE          // Primary Oscillator Mode Select bits (XT Crystal Oscillator Mode)
#pragma config OSCIOFNC = OFF       // OSC2 Pin Function bit (OSC2 is clock output)
#pragma config IOL1WAY = OFF        // Peripheral pin select configuration (Allow multiple reconfigurations)
#pragma config FCKSM = CSECMD       // Clock Switching Mode bits (Clock switching is enabled,Fail-safe Clock Monitor is disabled)

// FOSCSEL
#pragma config FNOSC = FRC          // Oscillator Source Selection (Internal Fast RC (FRC))
#pragma config IESO = OFF           // Two-speed Oscillator Start-up Enable bit (Start up with user-selected oscillator source)

// FGS
#pragma config GWRP = OFF           // General Segment Write-Protect bit (General Segment may be written)
#pragma config GCP = OFF            // General Segment Code-Protect bit (General Segment Code protect is Disabled)

#define FP 40000000
#define BAUDRATE 9600
#define BRGVAL ((FP/BAUDRATE)/16)-1
#define DELAY_105uS asm volatile ("REPEAT, #4201"); Nop(); // 105uS delay

unsigned int i;
char *temp[40];

#include "spi.h"
#include "ADXL345.h"

void delay_ms(long ms){
    unsigned long x = 0;
    for(x = 0; x <= ((FP/24000))*ms; x++)
        Nop();
}
void __attribute__((__interrupt__)) _U1TXInterrupt(void)
{
    IFS0bits.U1TXIF = 0; // Clear TX Interrupt flag
}

void UART_Write(char data)
{
    while(!U1STAbits.TRMT);
    U1TXREG = data;
}

void UART_Write_Text(char *text)
{
    int i;
    UART_Write('\n');
    UART_Write('\r');
    for(i=0;text[i]!='\0';i++)
        UART_Write(text[i]);
}

void InitClock(){
    PLLFBD=63; // M=65
    CLKDIVbits.PLLPOST=0; // N2=2
    CLKDIVbits.PLLPRE=1; // N1=3
    // Initiate Clock Switch to FRC oscillator with PLL (NOSC=0b001)
    __builtin_write_OSCCONH(0x01);
    __builtin_write_OSCCONL(OSCCON | 0x01);
    // Wait for Clock switch to occur
    while (OSCCONbits.COSC!= 0b001);
    // Wait for PLL to lock
    while (OSCCONbits.LOCK!= 1);
}

void InitUart(){
    U1MODEbits.STSEL = 0; // 1-Stop bit
    U1MODEbits.PDSEL = 0; // No Parity, 8-Data bits
    U1MODEbits.ABAUD = 0; // Auto-Baud disabled
    U1MODEbits.BRGH = 0; // Standard-Speed mode
    U1BRG = BRGVAL; // Baud Rate setting for 9600
    U1STAbits.UTXISEL0 = 0; // Interrupt after one TX character is transmitted
    U1STAbits.UTXISEL1 = 0;
    IEC0bits.U1TXIE = 1; // Enable UART TX interrupt
    RPOR4bits.RP43R = 1;    //RP43/RB11 as U1TX
    RPINR18bits.U1RXR = 42; //RP42/RB10 as U1RX
    U1MODEbits.UARTEN = 1; // Enable UART
    U1STAbits.UTXEN = 1; // Enable UART TX
    /* Wait at least 105 microseconds (1/9600) before sending first char */
    DELAY_105uS
}

int main(void)
{
    InitClock();
    InitUart();

    spi_init();
    UART_Write_Text("Starting ADXL345 test...fdsbjugbbjkdsf");
    enable_adxl345();
    int id = adxl345_devID();
    sprintf(temp, "Device ID is: 0x%02x", id);
    UART_Write_Text(temp);
    UART_Write_Text("Done");


    /*
    //Go into standby mode to configure the device.
    setPowerControl(0x00);

    //Full resolution, +/-16g, 4mg/LSB.
    setDataFormatControl(0x0B);

    //3.2kHz data rate.
    setDataRate(ADXL345_3200HZ);

    //Measurement mode.
    setPowerControl(0x08);
    */
    int* readings[3] = {0,0,0};
    getOutput(readings);
    int inter = 7;

    while(1)
    {
        delay_ms(1000);
        /*UART_Write_Text("Starting ADXL345 test...");*/
        sprintf(temp, "%i, %i, %i", inter, (int) readings[1], (int) readings[2]);
        UART_Write_Text("WORK");
    }
    return 0;
}

Вывод терминала получен

Я просто не могу понять это, надеюсь, кто-то может указать мне правильное направление?

ОБНОВЛЕНИЕ: удалось исправить мою проблему, причиной сбоя программы был цикл for в функции UART_Write_Text() (тот, что закомментирован ниже).

void UART_Write(char data)
{
    while(!U1STAbits.TRMT);
    U1TXREG = data;
}

void UART_Write_Text(char *text)
{
    int i;
    UART_Write('\n');
    UART_Write('\r');

    for(i=0;i<25;i++)
        UART_Write(text[i]);
    /*
    for(i=0;text[i]!='\0';i++)
        UART_Write(text[i]);
    */
}

Условие цикла for text[I]!='\0', я использовал '\0', чтобы остановить цикл в конце char[], однако я предполагал, что '\0' означает char, который = NULL, когда чтобы условие действительно выполнялось, на самом деле должно было быть = '\ 0'.

Хотя ни одному ответу не удалось уловить это, я хотел бы поблагодарить всех, кто потратил свое время, чтобы попытаться помочь мне в этом, и я проголосовал за вас всех, поскольку все ваши ответы помогли мне понять C в целом, так как у меня есть возможность чтобы пометить вопрос как отвеченный, я собираюсь отметить ответ «gmch», поскольку его объяснение разницы между массивом переменных и массивом указателей на указанные переменные, на мой взгляд, является звездным :).


person Sam    schedule 17.07.2014    source источник
comment
Вероятно, он запускается только один раз — программа перезапускается, когда происходит сбой, потому что она перезагружается.   -  person Billy Pilgrim    schedule 17.07.2014
comment
Я думаю, вы правы, я считаю, что проблема связана с UART_Write_Text (char * text); функция, которую я просто не могу понять..   -  person Sam    schedule 17.07.2014
comment
#define DELAY_105uS asm volatile ("REPEAT, #4201"); Nop(); // 105uS delay не гарантируется корректная работа; вы не можете предположить, что компилятор создаст инструкцию NOP сразу после инструкции REPEAT, поэтому правильный подход — поместить NOP внутри asm()   -  person Jason S    schedule 04.06.2015


Ответы (3)


int* readings[3] = {0,0,0}; - это массив указателей на целые числа... возможно, поэтому вы (int)readings[1] останавливаете нытье компилятора.

Я не вижу getOutput(), поэтому не вижу, что он будет делать с getOutput(readings), но если ему нужен массив указателей на int, то вы даете ему три нулевых указателя, что может быть плохо.

Как отмечалось в другом месте, char *temp[40] также является массивом указателей на char, а не массивом из 40 символов.


C серьезно сбивает с толку, когда речь идет о массивах и указателях, не в последнюю очередь потому, что имя массива неявно является указателем на первый элемент массива, и (наоборот) указатель можно использовать, как если бы он был массивом. А «строки» только добавляют путаницы. Итак, в...

int readings[3] = { 11, 22, 33 } ;
int* p ;

у нас есть массив из трех целых чисел с именем readings, инициализированный, как показано, и указатель на целое число `p' без значения. Сейчас:

readings[2] += 1 ;

добавляет 1 к readings[2], получая 23. И мы можем:

p = readings ;

Итак, теперь p указывает на readings[0] -- потому что имя массива автоматически работает как указатель на начало массива. Мы могли бы также написать:

p = &readings[0] ;

что, как вы могли бы утверждать, более ясно... и согласуется с:

p = &readings[1] ;

Интересно, вы можете написать:

p[1] += 1 ;

("cos указатели и массивы -- в основном -- взаимозаменяемы"), что установит readings[2] в `33'.

На самом деле все нижеследующее относится к readings[2]:

*(p+1) 
p[1]
readings[2]
*(readings+2)

Становится лучше... когда вы (очевидно) передаете массив функции, вы фактически передаете указатель на первый элемент массива. Таким образом, ваша функция может быть:

static void foo(int* z) .....
static void foo(int a[]) .....

и эффект тот же. Вы можете назвать это:

foo(readings) ;
foo(p) ;

и в самой функции a[2] *(a+2) z[2] *(z+2) практически взаимозаменяемы.

Как правило, я думаю об определении:

символ бар[22] ;

как создание указателя char* (псевдо) с именем bar, который неявно указывает на первый элемент массива из 22 символов. Если я также создам:

char* pc = bar ; 

затем создается (реальный) указатель, также инициализированный для указания на первый элемент массива из 22 символов. Разница между bar и pc невелика: (1) вы не можете присвоить bar -- фактически const; (2) sizeof(bar) указывает размер массива, а sizeof(pc) указывает размер указателя.

person Community    schedule 17.07.2014

В вашем коде есть неопределенное поведение, что приведет к странным вещам. происходит (чаще всего вылетает).

Проблема заключается в вашем определении переменной temp и в том, как вы ее используете. Вы используете его как строку в вызове sprintf, но он определяется как массив строк.

person Some programmer dude    schedule 17.07.2014
comment
Это массив или символы, из которых состоит строка? или я должен идти об этом по-другому? так как я должен использовать массив символов при записи в UART. - person Sam; 17.07.2014
comment
@ sp10acnFIFO Еще раз посмотрите на объявление temp, это массив (из-за [40]) указателей (из-за *) на char. Другими словами, у вас есть массив из 40 указателей на char. Если вам нужна простая строка, которая может содержать до 39 символов (помните, что разделитель строки также должен быть там), просто введите char temp[40] (обратите внимание на отсутствие звездочки). - person Some programmer dude; 17.07.2014
comment
Я попытался удалить *, чтобы просто проанализировать char [], однако я все еще смущен тем, что зацикливание текста показано, поскольку эта конкретная строка не записывает char [] в UART. возможно, это как-то связано с функцией UART_Write_Text, принимающей аргументы (char * text)? - person Sam; 17.07.2014
comment
@ sp10acnFIFO После изменения он все еще зацикливается? Если это не так, то это просто из-за неопределенного поведения, заставляющего программу вести себя неопределенным образом. - person Some programmer dude; 17.07.2014
comment
Он все еще зацикливается, я попытался закомментировать весь код в основном коде, кроме InitClock(); ИнитУарт(); spi_init(); UART_Write_Text(Запуск теста ADXL345...fdsbjugbbjkdsf); Неподвижные петли - person Sam; 17.07.2014
comment
Как заявил @Billy Pilgrim, может ли это быть функция UART_Write_Text, вызывающая сбой программы и, таким образом, перезагрузка, чтобы она выглядела зацикленной? - person Sam; 17.07.2014

В качестве общей рекомендации: разбейте программу на части, разделите все на 2 или исключите функцию за функцией (вызовы). Вероятно, начните с простого цикла usngined long i = 0; while (1) { printf("%x ",i); i++; }, чтобы убедиться, что сторожевой таймер pragma применяется. Затем исключить другие. В противном случае вы можете только анализировать код и документы.

person Ruslan Gerasimov    schedule 18.07.2014