Микроконтролери и електроника
http://mcu-bg.com/mcu_site/

Разделяне на подпрограмите в .с фаилове.
http://mcu-bg.com/mcu_site/viewtopic.php?f=3&t=7576
Страница 1 от 2

Автор:  edi [ Съб Фев 20, 2010 6:15 pm ]
Заглавие:  Разделяне на подпрограмите в .с фаилове.

Здавейте.
До момента всеки път като съм писал софтуер за PIC18/С18 съм хакал всички функции и дифиниции в един фаил например main.c.
Но когато подпрограмите, функциите и т.н. станаха много, вече е неудобно да скролвам, а и искам да си ги отделя като отделни фаилове, така че да ги ползвам като готови функции.
Пероблема е следния.
definitions.h
Код:
#include <p18f452.h>
#include <delays.h>
#include <adc.h>
#include <stdlib.h>

#pragma udata access my_access
extern volatile near struct {
   unsigned inmenu2:1;
   unsigned rpgbp:1;
} flags;
#pragma udata


#define LCDRS    LATEbits.LATE0
#define LCDE    LATEbits.LATE1
#define LCDRW    LATEbits.LATE2   
#define PWMR   LATCbits.LATC0   //RED PWM
#define tmrval   105   //Задава периода на всеки подпериод на ШИМ
//=============Prototipi===============
void gene(void);
unsigned char checkbf(void);
void lcdcmd(unsigned char cmd);
void initlcd(void);
void lcdchar(unsigned char datachar);
void printlcdt(const rom char *buffer);
void printlcd(char *buffer);
void loadvals(void);
void chartbs(void);
unsigned char rpgdir(void);
unsigned char rpgbut(void);
void high_isr_h(void);   //handling high iterrupt
void low_isr_h(void);   //handling low interrupts
//================Използвани глобални променливи=============================================
extern volatile unsigned char oldrpg,rpgbuf,newrpg,mpos;
extern volatile unsigned char rpgdirv;


А това е кода на rpg.c .
Код:
#include "definitions.h"
#include <p18f452.h>

unsigned char rpgdir(void)
{   newrpg=PORTB&0x03;
   if(newrpg==oldrpg)
   {return 0;}
   oldrpg=newrpg;
   STATUSbits.C=0;
   _asm    
      movlb    rpgbuf
      rlcf    rpgbuf,1,1
      bcf      STATUS,0,0
      rlcf   rpgbuf,1,1
    _endasm
   rpgbuf|=newrpg;
   
   if(rpgbuf==0x4b)
   {rpgbuf=0x00;return 2;}
   if(rpgbuf==0x87)
   {rpgbuf=0x00;return 1;}
   return 0;
}

unsigned char rpgbut(void)
{
   if(PORTBbits.RB2==0)
   {flags.rpgbp=1;return 0;}
   if(PORTBbits.RB2==1 && flags.rpgbp==1)
   {flags.rpgbp=0;return 1;}
}


Идеята ми е всички глобални променливи заедно с прототипите на функците да са в "definition.h", но постоянно ми дава грешка "Error - could not find definition of symbol 'newrpg' in file './rpg.o'."

Насочете ме или направо ми кажете къде греша!

Автор:  Реконструктор [ Съб Фев 20, 2010 7:38 pm ]
Заглавие: 

Еми къде е дефинирано newrpg?

Автор:  edi [ Съб Фев 20, 2010 7:46 pm ]
Заглавие: 

Реконструктор написа:
Еми къде е дефинирано newrpg?


В "definition.h".

Автор:  head_up [ Съб Фев 20, 2010 7:54 pm ]
Заглавие: 

ммм, не е. значи ако декларираш една променлива някъде ок, да кажем unsigned char x и искаш да я използваш някъде другаде (в различен файл от този в който е декларирана) я добавяш 1:1 с декларацията, но добавяш extern. става extern unsigned char x, което указва на компилатора, че тя *вече* е декларирана някъде и той трябва да я намери извън текущият файл, но това с extern само по себе си НЕ декларира променливата. разбираш?

Автор:  edi [ Съб Фев 20, 2010 9:29 pm ]
Заглавие: 

head_up написа:
ммм, не е. значи ако декларираш една променлива някъде ок, да кажем unsigned char x и искаш да я използваш някъде другаде (в различен файл от този в който е декларирана) я добавяш 1:1 с декларацията, но добавяш extern. става extern unsigned char x, което указва на компилатора, че тя *вече* е декларирана някъде и той трябва да я намери извън текущият файл, но това с extern само по себе си НЕ декларира променливата. разбираш?

Дам разбрах и тръгна като ги дефинирах в main.c(без extern), но това исках да избегна :), т.е. мислих, че има начин след като се дефинира на едно място без да се дефинират на ново да се ползват т.к. са глобални, ама явно няма начин :).

Друго..."definition.h" вече изглежда така :
Код:

#pragma udata access my_access
volatile near struct {
   unsigned inmenu2:1;
   unsigned rpgbp:1;
} flags;
#pragma udata

volatile unsigned char oldrpg,rpgbuf,newrpg,mpos;

rpg.c
Код:
extern volatile unsigned char oldrpg,rpgbuf,newrpg;
extern volatile near struct {
   unsigned inmenu2:1;
   unsigned rpgbp:1;
} flags;

Но дава грешка "Error - symbol 'flags' has multiple definitions." А тази структура не е дефинирана никъде освен в "definition.h" .Когато е дефинирана в "main.c" проблеми няма.Има ли начин да я оставя в .h фаила?

Автор:  darkshy [ Съб Фев 20, 2010 10:49 pm ]
Заглавие: 

ами според мен трябва да имаш само unsigned char oldrpg,rpgbuf,newrpg,mpos; в definitions.h
не ти трябва extern май! :)

Автор:  tolstolob [ Съб Фев 20, 2010 10:56 pm ]
Заглавие: 

Как трябва e:

Код:
"Example.h":

extern volatile unsigned char newrpg;


Код:
"Example.c":

#include <Example.h>

volatile unsigned char newrpg;


Всичко, което трябва да се вижда навън - декларирано в хедъра като extern.
Останалото - в .с файла и без extern.

Автор:  edi [ Съб Фев 20, 2010 11:03 pm ]
Заглавие: 

tolstolob написа:
Как трябва e:

Код:
"Example.h":

extern volatile unsigned char newrpg;


Код:
"Example.c":

#include <Example.h>

volatile unsigned char newrpg;


Всичко, което трябва да се вижда навън - декларирано в хедъра като extern.
Останалото - в .с файла и без extern.


Сега ще пробвам това последното :).

Автор:  Gogo [ Нед Фев 21, 2010 1:23 am ]
Заглавие: 

Както ти е в първия пост, разкарай това "extern" от декларацийте и работата ще стане! :-)
Сега, ако имаш друг *.с файл (test.c) в който ще ползваш някоя променлива, декларирана в definitions.h, ще стане така:

Код:
test.c

#include <p18f452.h>
unsigned char test(void) ;
extern volatile unsigned char mpos;

unsigned char test(void)
{
   if(mpos==0x30) return 0xff;
}

Автор:  Реконструктор [ Нед Фев 21, 2010 9:25 am ]
Заглавие: 

edi написа:
Но дава грешка "Error - symbol 'flags' has multiple definitions." А тази структура не е дефинирана никъде освен в "definition.h" .Когато е дефинирана в "main.c" проблеми няма.Има ли начин да я оставя в .h фаила?


extern е за валидност на декларации, обявени в други object, lib, so или каквито се сетиш още байнъри файлове.
По принцип никога не се декларира променлива в хедър файл, защото в един момент почти сигурно е, че ще се получи двойна дефиниция.

Автор:  edi [ Нед Фев 21, 2010 10:26 am ]
Заглавие: 

Реконструктор написа:
extern е за валидност на декларации, обявени в други object, lib, so или каквито се сетиш още байнъри файлове.
По принцип никога не се декларира променлива в хедър файл, защото в един момент почти сигурно е, че ще се получи двойна дефиниция.


Ясно разбрах каква е логиката :).

Автор:  MidNighT_SpiRiT [ Нед Фев 21, 2010 1:49 pm ]
Заглавие: 

В хедърния файл е добре да слагаш хедърът, чрез който се избягва зацикляне на препроцесора от вмъкването на файла едновременно от няколко места. Нали се сещаш:
Код:
#ifndef _DEFINITION_H
#define _DEFINITION_H
.....
#endif

Освен това както каза реконструктора никога не се слагат декларации на променливи в хедърен файл.

Автор:  miro_atc [ Нед Фев 21, 2010 3:23 pm ]
Заглавие: 

MidNighT_SpiRiT написа:
Освен това както каза реконструктора никога не се слагат декларации на променливи в хедърен файл.


Много хора бъркат термините и така вместо да помогнат объркват още повече начинаещите...

Значи термините са "декларация" и "дефиниция".

Чрез дефиниция реално се създава дадена променлива или се кодира функция. Естествено е, че дефиницията е еднократна щото веднъж се създава дадения обект. При повторна дефиниция, компилатора ще се опита да създаде втори обект, стига да не е в същата област на валидност, щото в една област не може да има два обекта с едно и също име.
Пример за дефиниции:
Код:

char test;

char foo(void)
{
return  test++;
}



Чрез декларация се обявява даден обект и част от неговите атрибути като тип и т.н., без самият обект да се създава. С други думи декларацията е анонс на дефиниция, която е направена на друго място. Пример за декларации:
Код:

extern char test;

char foo(void);



Много често се бъркат термините (включително и на английски) и вместо дефиниция се използва декларация... Понякога хората ги бъркат неумишлено, но много често и поради незнание или неразбиране. Причината е, че за С-компилатора декларацията е по-важна от дефиницията. В смисъл за да се използва даден обект то той задължително трябва да бъде деклариран, но не е задължително да бъде дефиниран. Примерно може да си използвате променлива, която реално не съществува (не е дефинирана). Компилаторът ще ви го позволи и проблемът ще се появи чак на ниво линкер. Тук е другия проблем, че хората не правят разлика между компилатор и линкер, но това е друга тема ;-)

Както и да е... Накратко - дефиниция се прави веднъж, обикновено в .ц файл. Примерно ако си правиш библиотека за работа с PWM, то pwm.c ще съдържа дефинициите на всички променливи и функции. За да могат тия неща да се ползват от други места, ще трябва на всяко място да се декларират преди ползването. Би било неудобно на 100 места да декларираш едно и също нещо, затова се правят h-файлове и в тях се слагат съответните декларации. Примерно в pwm.h ще се сложат всички декларации на обектите от pwm.c който ще се ползват. Така ако искаш някъде да ползваш pwm просто вмъкваш #include "pwm.h" и това ти дава всички нужни декларации.

Още веднъж - дефиницията се прави веднъж, а декларацията толкова пъти, колкото е необходимо. Но с използване на хедър файлове се спестява многократното писане на едни и същи декларации.

Иначе в хедър файл може да се вкарват и дефиниции. Но това ще създава нов обект навсякъде където се вмъкне хедъра. Понякога това е целта. Примерно inline функциите се дефинират в h файлове, тъй като много компилатори изискват inline функциите да са статични.

Автор:  MidNighT_SpiRiT [ Пон Фев 22, 2010 9:02 pm ]
Заглавие: 

Прав си miro_atc, извинявам се за грешката!

Автор:  edi [ Сря Фев 24, 2010 8:00 pm ]
Заглавие: 

Благодаря ти miro_atc за изчерпателния отговор :).
Друг въпрос, не много по темата.
Как мога да присвоя стойност на една 16битова променлива, като стойността и се образува от две 8 битови например :
Код:
unsigned int temp;
unsigned char varh,varl;
temp=varh:varl;

Нещо такова ми трябва.
Спомням си, че го четах това из C18 User Guide, но немога да го намеря :(.

Страница 1 от 2 Часовете са според зоната UTC + 2 часа [ DST ]
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group
http://www.phpbb.com/