Совет по кодированию c18 / ошибка фигурных скобок / помощь по объявлению функции

У меня почти НЕТ опыта кодирования, так что извините за грубый стиль и многословные комментарии. Я пытаюсь сделать выборку с 4 датчиков (1 каждые 15 минут). Я думал, что было бы более эффективно использовать функции delayи data_writeкак отдельные функции для вызова, но это не очень хорошо работает. Я постоянно получаю следующую ошибку:

Ошибка [1302] объявления функций в старом стиле не поддерживаются

в конце data_writeфункции независимо от того, где и как я ставлю фигурные скобки (вложенные, та же строка, исключение и т. д.), delayфункция не дает ошибки, будь то до или после функции data_write.

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

======================================

    #include <stdio.h>
    #include <stdlib.h>
    #include <p18f452.h>
    #include <delays.h>
    #include <adc.h>

    int result;                         // used in ADC result handling
    int i;                              // used in delay loop/function
    int data_adr=0x64;                  // used in data_write function. initial=d100

    // assuming 4MHz oscillator => 8fosc.   Tinst= (4)*Tosc = (4)*(250ns) = 1us
    // all 4 sensors should read every minute so each will begin sequentially,
    // after 15sec delay from previous ADC conversion completes.

    void delay (void);                 // delay function prototype declaration
    void data_write (int, int);             // data-write function prototype declaration

    main()
    {
    // I think I need a while (1) loop here to repeat the loop forever???

    // sensor 1 configured to port AN0
        OpenADC(ADC_FOSC_8 & ADC_RIGHT_JUST & ADC_5ANA_0REF, ADC_CH0 & ADC_INT_OFF);
                            //configures ADC for port AN0 = sensor 1 input
            delay();                    // call the delay function
            ConvertADC();               // initiate conversion of sensor1 @ AN0
            while(BusyADC());           // waiting to complete conversion
            result=ReadADC();           // read the result of sensor1 @ AN0
            data_write();               // call data_write function
        CloseADC();


    // sensor 2 configured to port AN1
        OpenADC(ADC_FOSC_8 & ADC_RIGHT_JUST & ADC_5ANA_0REF, ADC_CH1 & ADC_INT_OFF);
                            //configures ADC for port AN1 = sensor 2 input
           delay();
           ConvertADC();
           while(BusyADC());
           result=ReadADC();
           data_write ();
        CloseADC();

    // sensor 3 configured to port AN2
        OpenADC(ADC_FOSC_8 & ADC_RIGHT_JUST & ADC_5ANA_0REF, ADC_CH2 & ADC_INT_OFF);
                            //configures ADC for port AN2 = sensor 3 input
           delay();
           ConvertADC();
           while(BusyADC());
           result=ReadADC();
           data_write ();
        CloseADC();

    // sensor 4 configured to port AN3
        OpenADC(ADC_FOSC_8 & ADC_RIGHT_JUST & ADC_5ANA_0REF, ADC_CH3 & ADC_INT_OFF);
                            //configures ADC for port AN3 = sensor 4 input
           delay();
           ConvertADC();
           while(BusyADC());
           result=ReadADC();
           data_write ();
        CloseADC();

        return (result);
    }

    // Delay function sequence
    void delay (void)
    {                                       // 15second delay routine
                                    // 15sec/Tinst= 15sec/1us
                                    // = 15*10^6 Tinst = 10K * 1500
                                    // Delay10KTCYx(1)= 0.01sec
                                    // = (10K)*(250)*(6)
        i=6;
        while(i>0) {
           Delay10KTCYx(250);      // 2.5sec delay
            i=i--;                  // run 6 times for total 15sec delay loop
        }
        return;
    }

    // data write sequence
    void data_write (data_adr, result) {
         _asm
         movlw  data_adr        // starting data memory address = data_adr
         movwf  EEADR,A
         movlw  result              // gets data stored in "result" variable
         movwf  EEDATA,A            // places data into data memory holder
         bcf    EECON1,EEPGD,A      // points to data memory
         bcf    EECON1,CFGS,A       // access data eeprom
         bsf    EECON1,WREN,A       // enable write to data EEPROM
         bcf    INTCON,IE,A         // disable interrupt
         movlw  0x55                // start flash erase sequence
         movwf  EECON2,A
         movlw  0xAA
         movwf  EECON2,A            // end flash erase sequence
         bsf    EECONN1,WR,A        // enable bit to start the write operation
         bsf    INTCON,GIE,A        // re-enable interrupt
         bcf    EECON1,WREN         // restores the write command to =disabled
         _endasm

         data_adr = data_adr+2;
         if (data_adr >= 0xC6)      // if address >= d'198
             data_adr = 0x64;       // resets starting point to d'100

        return; }

Ответы (3)

Все остальные ответы имеют хорошие стороны и указывают на другие проблемы, но конкретная причина, по которой вы получаете сообщение об ошибке, old style function declarations not supportedзаключается в том, что в объявлении вашей data_writeфункции отсутствуют типы. Его нужно изменить с

void data_write (data_adr, result)

к

void data_write (int data_adr, int result)
У меня есть еще один вопрос об определенной части этого кода, собственно о функции data_write (со сборкой). Я предполагаю, что мне следует задать его как новый вопрос, а не продолжать публиковать аналогичные блоки кода?

Во-первых, избавьтесь от возврата в основной функции. Куда вы собираетесь возвращать данные? Там нет операционной системы, и возврат бессмысленен, поэтому это может быть источником некоторых проблем.

Как именно вы собираетесь выводить данные? Похоже, вы пытаетесь записать данные в память, но что вы собираетесь делать после этого, вынимать чип и физически читать EEPROM с помощью программатора?

Далее, да, вам нужно while (1), чтобы правильно зацикливаться вокруг функции. Вы можете получить какой-то цикл даже без while. Если я правильно помню, флэш-память PIC18 по умолчанию заполнена NOP. Он будет продолжать выполнять инструкции до тех пор, пока не будет достигнут конец адресного пространства, после чего он должен (опять же, если я правильно помню) выполнить цикл и вернуться к первой инструкции. Вы не должны полагаться на эту функцию и вместо этого должны обернуть содержимое main с помощью while (1) или эквивалентного.

Далее сами ошибки: Ну, в руководстве по компилятору написано, что это вообще не связано с фигурными скобками. Это связано со стилем объявления функции. На самом деле вам нужно написать тип переменной и имя при объявлении функции. Вы создали переменные с тем же именем, что и глобальные переменные. Когда ваш код работает, он не будет использовать глобальные переменные. Вместо этого он будет использовать локальные переменные с таким именем, которое будет маскировать глобальные переменные.

Также вы плохо вызываете функции. Вы должны фактически перечислить аргументы, когда вы вызываете функции!

Далее, в C18 прототип для main должен быть void main (недействительным), что хорошо сочетается с правилом возврата, о котором я упоминал ранее.

Вы также, кажется, неправильно называете регистрационные имена. Попробуйте прочитать в руководстве пользователя, как C18 вызывает каждый регистр в PIC и как обращаться к каждому отдельному биту регистра. Например, вы должны использовать INTCON1bits.GIEдля доступа к общему биту разрешения прерывания в регистре управления прерыванием один.

Еще я заметил, что вы используете int для счетчика циклов. Не делайте этого, если можете этого избежать. Старайтесь использовать символы как можно чаще, так как они являются родным типом данных MCU. Целые числа будут обрабатываться дольше, что приведет к более медленным, чем ожидалось, циклам.

Также вы упомянули функции и эффективность. Имейте в виду, что C18 не может встраивать функции, поэтому, если вам когда-либо понадобится эффективно вызывать функцию, вам придется заменить ее макросом.

AndrejaKo, Спасибо за ответ. Я думал, что, поскольку основной функции нужно было передать «результат» функции data_write, я должен был объявить это таким образом. Если я пропущу возврат, будет ли функция data_write по-прежнему иметь доступ к переменной «результат»? Предполагается, что данные просто регистрируются. Мой план состоял в том, чтобы получить через ICSP или аналогичный. Эта часть не очень важна для меня. Поскольку ошибка компилятора останавливается на закрывающей фигурной скобке и указывает, что это проблема форматирования K&R, я так и подумал. Я думаю, что понимаю проблему с глобальными переменными. Я переименую.
извините за мое форматирование здесь тоже. Я тоже не привык.
Кроме того, формат адресации этих битов прямо из моего учебника (микроконтроллеры Huang-Pic). Я понимаю вашу точку зрения и делал это раньше с битами порта, поэтому я тоже могу это изменить, без проблем. Я просто пытался быть ловким и вызывать функции, а не вырезать/вставлять один и тот же код внутри main. Спасибо за отзыв. :-Д
@Mark Ну, мне кажется, вам нужно немного изучить C, прежде чем пытаться программировать микроконтроллеры на C. Взгляните, например, на этот учебник. По сути, return используется для предоставления результатов функции функции, которая ее вызвала.
Спасибо AdrejaKo. Я ценю ваше терпение. На самом деле я сейчас хожу на занятия, но инструктор не приводит много примеров и, кажется, предполагает, что мы все программисты. Однако этот курс не требует опыта программирования. Прошу прощения за элементарные вопросы.

Как указывает Андрея, вы неправильно используете оператор return.
Кроме того, теперь фактическое сообщение об ошибке было отредактировано, из него становится ясно, что ошибка, связанная с вашим, data_writeсвязана с тем, что вы не объявляете типы аргументов, как утверждает Джим в своем ответе. Вы можете увидеть примеры того, как они должны быть объявлены в коде ниже.

Оператор returnиспользуется для передачи вызывающей стороне результата определенного типа, продиктованного определением функции.

Например, эта функция возвращает целое число:

int add(int a, int b)
{
    int c;
    c = a + b;
    return c;
}

Чтобы использовать вышеизложенное, вы делаете что-то вроде:

int result;
result = add(5, 6); // result = 11

Но эта функция не принимает никаких аргументов и ничего не возвращает (обратите внимание на voidтип возврата/аргумента):

void do_something(void)
{
    // do something here...
    //
}

Существует множество применений функции без возврата/аргументов — например, настройка периферийного устройства, инициализация памяти и т. д.

Другой способ получить информацию из функции — использовать указатель, переданный в качестве аргумента:

void add(int a, int b, int* p_result)
{
    int temp;
    temp = a + b;
    *p_result = temp;
}

Чтобы использовать вышеизложенное, мы передаем адрес переменной результата в качестве третьего аргумента (оператора &):

int result = 0;
int a = 6;
int b = 5;
add(a, b, &result); // result will equal 11 on function return

Итак, надеюсь, вы видите, что нет смысла иметь returnоператор для функции, объявленной как void, (если вы не хотите вернуться раньше как часть некоторой логики принятия решения - аналогично операторам continueи break, которых у вас нет в ваших функциях выше) Если вы хотите что-то вернуть, объявите тип в начале определения функции. Как предлагает Андрея, я бы немного почитал об основных функциях и указателях C.

Спасибо, Оли, это очень полезно. Вы правы, я запутался в главном. Я хотел поставить что-то вроде int main(), думая, что возврат передаст «результат» из основного в функцию «записи данных». Мне нужно многому научиться.