реклама на сайте
подробности

 
 
> Как правильно создать многофайловый проект, Ошибка при линковке
alux
сообщение May 6 2007, 14:07
Сообщение #1


Знающий
****

Группа: Свой
Сообщений: 589
Регистрация: 24-04-05
Пользователь №: 4 447



Привет всем.
Создаю проект на IAR v.4.12A, состоящий из многих С-файлов. Проблема возникает при линковке в один файл. Если быть точнее, то при попытке вызова battery_charge(); из main возникает ошибка Error[e46]: Undefined external "FAST_charge" referred in bc ( IAR projects\pribor\Release\Obj\bc.r90 ). В main подключены хидеры всех используемых модулей, в том числе и bc.h :

///// main.c ////////
#include "bc.h"
...........
void main (void)
{
battery_charge();
}

//// bc.c /////
#include "bc.h"

void battery_charge(void)
{
FAST_charge();
}

///// bc.h ////////
extern void FAST_charge(void);
extern void TRICKLE_charge(void);
extern void battery_charge(void);

//// NiMh.c ////////
#include "NiMH.h"
void FAST_charge (void)
{
}


//// NiMh.h //////
void FAST_charge(void);

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

Сообщение отредактировал alux - May 6 2007, 14:40
Go to the top of the page
 
+Quote Post
 
Start new topic
Ответов
SasaVitebsk
сообщение Dec 9 2007, 19:06
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Простите, решил сюда добавить, чтобы темы не плодить.
Не так давно пишу на Си. За этот период сильно изменил свои подходы. Теперь проект разбиваю на файлы, которые логически закончены. Это даёт возможность многократного использования с минимальными изменениями. Но вот столкнулся с некоторыми проблемами в таком подходе. В принципе я о них уже читал в разных темах и общие указания слышал/запомнил.

Сама проблема возникает когда п/п из другого файла используется в прерывании, которое в main описывается. Как выходить из неё - вроде понятно. 1) Вообще убрать вызовы п/п. 2) перенести п/п в файл, где пишется прерывание.

Собственно меня интересует более общая тема. Как всётаки сделать так, чтобы и овцы целы и волки сыты. То есть вопросы следующие.

1) Правильным ли является подход с выделением логически законченного блока в отдельный файл со своим хедером. И если "нет" или "не совсем", то хотелось бы услышать как поступают проффессионалы.
2) Как использовать такие "почти библиотеки", чтобы уменьшить накладные рассходы и при этом сохранить красоту написания проги.
3) Является ли выигрышным в этом смысле вариант с С++ и созданием классов/объектов.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 9 2007, 21:56
Сообщение #3


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(SasaVitebsk @ Dec 9 2007, 21:06) *
п/п из другого файла используется в прерывании, которое в main описывается.
Это как? Обычно обработчик прерывания описываю не в main, а в том же файле, что и остальные п/п соответстующего модуля. А зачем обработчик уносить в тот же файл, где и main? Или это архитектера вроде pic, когда одно прервание на все случаи? Плюсы помогут, ибо в них можно в заголовочном файле описать обработчик как inline.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
alexander55
сообщение Dec 11 2007, 06:17
Сообщение #4


Бывалый
*****

Группа: Свой
Сообщений: 1 584
Регистрация: 7-08-07
Пользователь №: 29 615



Цитата(Сергей Борщ @ Dec 10 2007, 00:56) *
А зачем обработчик уносить в тот же файл, где и main?

Это дело вкуса.
Я вижу это так.
Если железно ясно, что
- используется прерывание
- и это универсальное решение,
то прерывание имеет смысл иметь в модуле, где осуществляется реализация.
Если :
- хочется иметь main как диспетчер, в котором видна вся логика функционирования
- main небольшой по размеру
- возможны изменения (без прерывания или с прерыванием),
то лучше обработчик прерывания в main.
В дальнейшем, когда все устаканится или размер main станет неприличным по размеру, можно его перенести. biggrin.gif
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 11 2007, 09:51
Сообщение #5


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(alexander55 @ Dec 11 2007, 08:17) *
Если :
- хочется иметь main как диспетчер, в котором видна вся логика функционирования
Если это ARM, то в main достаточно заносить адреса обработчиков (объявленных как extern) в нужные регистры контроллера прерываний. Тела самих обработчиков в main() не нужны. Если это проц без контроллера, то у него скорее всего вектора жестко распределены за периферией, и выбор вектора просто однозначен - в main нечего диспетчерить. Если хочется иметь выбор из нескольких одинаковых периферийных модулей (UART, например), то можно попробовать так:
Код
в Hardware.h указываем
#define RS232_MODULE   USART1
#define RS485_MODULE   USART0

в RS232.c:
#pragma RS232_MODULE##_UDRE_vect
interrupt void RS232_transmit_handler()
{

} //опять main.c не у дел
Наконец, если используются плюсы и обработчик - метод класса, то код этого метода с атрибутом inline размещается в заголовочном файле, а в main.cpp пишется "обертка":
Код
__irq void RS232_Handler()
{
      RS232.Handler();
}
или
#pragma USART1_UDRE_vect
interrupt void RS232_transmit_handler()
{
      RS232.Handler();
}
при этом обработчик делается private, а функция-обертка объявляется другом класса. Но при желании эти обертки уносятся в файл соответствующего модуля и можно снова применить первый вариант.
Цитата(alexander55 @ Dec 11 2007, 08:17) *
В дальнейшем, когда все устаканится или размер main станет неприличным по размеру, можно его перенести.
Мне кажется, что всякие методики проектирования создают именно для того, чтобы по возможности исключить такую непроизводительную работу. Хотя, конечно, идеала не существует и процесс был и будет итеративным. Но количество итераций можно попытаться уменьшить.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
alexander55
сообщение Dec 11 2007, 10:29
Сообщение #6


Бывалый
*****

Группа: Свой
Сообщений: 1 584
Регистрация: 7-08-07
Пользователь №: 29 615



Цитата(Сергей Борщ @ Dec 11 2007, 12:51) *
Наконец, если используются плюсы и обработчик - метод класса, то код этого метода с атрибутом inline размещается в заголовочном файле, а в main.cpp пишется "обертка":
Код
__irq void RS232_Handler()
{
      RS232.Handler();
}
или
#pragma USART1_UDRE_vect
interrupt void RS232_transmit_handler()
{
      RS232.Handler();
}

Я это и имел ввиду.

Цитата(Сергей Борщ @ Dec 11 2007, 12:51) *
в main нечего диспетчерить.

Это не совсем диспетчеризация и даже может совсем не диспетчерезация.
Приятно сразу понять логику работы всей системы глядя на один модуль.
Детали находятся за рамками и если требуются, то понятно, где это можно посмотреть (глядя на модуль).
Второй смысл - это скажем так "просмотр синхронизации потоков и распределенных приложений".
Во выдал. biggrin.gif
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 11 2007, 13:07
Сообщение #7


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(alexander55 @ Dec 11 2007, 12:29) *
Приятно сразу понять логику работы всей системы глядя на один модуль.
У меня в main.c обычно находятся собственно main() и __low_level_init(). Глядя на main() можно попытаться понять логику работы всей системы, правда есть одно исключение smile.gif :
Код
int main()
{
    OS::Run();
}
Цитата(alexander55 @ Dec 11 2007, 12:29) *
Детали находятся за рамками и если требуются, то понятно, где это можно посмотреть (глядя на модуль).
Так RS232_transmit_handler() - это и есть детали. А логика описывается getchar(), putchar() и hasinput(). Мне так кажется...
Цитата(SasaVitebsk @ Dec 11 2007, 12:58) *
Прерывание - метки времени. То есть там целый набор. smile.gif в том числе вызовы опроса клавиатуры.
В таком случае наименьшие накладные, наверное, можно получить если "набор" описать в заголовочных файлах как static inline функции.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
alexander55
сообщение Dec 11 2007, 13:39
Сообщение #8


Бывалый
*****

Группа: Свой
Сообщений: 1 584
Регистрация: 7-08-07
Пользователь №: 29 615



Цитата(Сергей Борщ @ Dec 11 2007, 16:07) *
У меня в main.c обычно находятся собственно main() и __low_level_init(). Глядя на main() можно попытаться понять логику работы всей системы, правда есть одно исключение smile.gif :
Код
int main()
{
    OS::Run();
}

Это логичный и устоявшийся модуль. biggrin.gif

Цитата(Сергей Борщ @ Dec 11 2007, 16:07) *
Так RS232_transmit_handler() - это и есть детали. А логика описывается getchar(), putchar() и hasinput(). Мне так кажется...

В данном случае так.

Цитата(Сергей Борщ @ Dec 11 2007, 16:07) *
В таком случае наименьшие накладные, наверное, можно получить если "набор" описать в заголовочных файлах как static inline функции.

Или включить максимальную оптимизацию по требуемому параметру.
Go to the top of the page
 
+Quote Post

Сообщений в этой теме
- alux   Как правильно создать многофайловый проект   May 6 2007, 14:07
- - jorikdima   хидеры то подключены, а в опциях проекта пути к ни...   May 6 2007, 14:20
|- - alux   Цитата(jorikdima @ May 6 2007, 17:20) хид...   May 6 2007, 14:46
||- - rezident   Цитата(alux @ May 6 2007, 20:46) Все файл...   May 6 2007, 18:25
|- - andrej2005   Цитата(jorikdima @ May 6 2007, 18:20) хид...   Apr 20 2008, 10:34
- - zltigo   Цитата(alux @ May 6 2007, 17:07) void bat...   May 6 2007, 14:24
|- - singlskv   Цитата(SasaVitebsk @ Dec 9 2007, 22:06) С...   Dec 9 2007, 20:22
|- - Сергей Борщ   Цитата(alexander55 @ Dec 11 2007, 15:39) ...   Dec 11 2007, 15:20
- - Непомнящий Евгений   Просветите плиз - что такое "п/п"?   Dec 10 2007, 06:26
|- - Николай Z   Цитата(Непомнящий Евгений @ Dec 10 2007, 09...   Dec 10 2007, 07:21
- - Непомнящий Евгений   Что такое подпрограмма - я в курсе Просто не сооб...   Dec 10 2007, 07:34
- - SasaVitebsk   Я, собственно так и работаю. И думал так все. В с...   Dec 11 2007, 10:58
- - Panych   Подниму тему, чтоб не плодить... Объявляю внешнюю ...   Apr 7 2008, 13:32
|- - gotty   Цитата(Panych @ Apr 7 2008, 16:32) Подним...   Apr 7 2008, 13:45
|- - alux   Цитата(gotty @ Apr 7 2008, 16:45) И ещё с...   Apr 8 2008, 12:04
- - Panych   gotty спасибо, сделал функцию внешней, IAR ругнулс...   Apr 7 2008, 14:15
|- - MrYuran   Цитата(Panych @ Apr 7 2008, 17:15) gotty ...   Apr 8 2008, 12:11
- - ivainc1789   Тема о многостраничных файлах, задам и свой махонь...   Apr 9 2008, 15:09
|- - Непомнящий Евгений   Цитата(ivainc1789 @ Apr 9 2008, 19:09) Те...   Apr 9 2008, 15:51
|- - rezident   Цитата(ivainc1789 @ Apr 9 2008, 21:09) Те...   Apr 9 2008, 21:55
- - sKWO   Добрый день! Многофайловый проект, чёрт по.......   Apr 13 2008, 10:55
- - alux   Цитата(sKWO @ Apr 13 2008, 13:55) файл dr...   Apr 13 2008, 14:08
|- - sKWO   Цитата(alux @ Apr 13 2008, 17:08) У вас в...   Apr 13 2008, 18:14
- - Непомнящий Евгений   Цитата(sKWO @ Apr 13 2008, 14:55) Кодtype...   Apr 14 2008, 04:44
- - alux   Цитата(Непомнящий Евгений @ Apr 14 2008, 07...   Apr 14 2008, 06:33


Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 21st July 2025 - 07:41
Рейтинг@Mail.ru


Страница сгенерированна за 0.01459 секунд с 7
ELECTRONIX ©2004-2016