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

 
 
> Как правильно создать многофайловый проект, Ошибка при линковке
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
3 страниц V   1 2 3 >  
Start new topic
Ответов (1 - 31)
jorikdima
сообщение May 6 2007, 14:20
Сообщение #2


тут может быть ваша реклама
*****

Группа: Свой
Сообщений: 1 164
Регистрация: 15-03-06
Из: Санкт-Петербург/CA
Пользователь №: 15 280



хидеры то подключены, а в опциях проекта пути к ним прописаны? (если они по поддиректориям распределены)
Go to the top of the page
 
+Quote Post
zltigo
сообщение May 6 2007, 14:24
Сообщение #3


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(alux @ May 6 2007, 17:07) *
void battery_charge(void)
{
FAST_charge();
}

Описка. Найдите разницу в одной букве:
Цитата
void FAST_carge (void)
{
}


И пожалуй не стоит писать в AVR->IAR, ибо сие ни к AVR ни к IAR отнрошения не имеет.

P.S.
И дублировать прототипы функций в headers это лишнее.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
alux
сообщение May 6 2007, 14:46
Сообщение #4


Знающий
****

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



Цитата(jorikdima @ May 6 2007, 17:20) *
хидеры то подключены, а в опциях проекта пути к ним прописаны? (если они по поддиректориям распределены)

Все файлы (*.с, *.h) лежат в одной рабочей папке.


Цитата(zltigo @ May 6 2007, 17:24) *
И дублировать прототипы функций в headers это лишнее.

Ошибся при наборе сообщения, уже исправил...
Go to the top of the page
 
+Quote Post
rezident
сообщение May 6 2007, 18:25
Сообщение #5


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(alux @ May 6 2007, 20:46) *
Все файлы (*.с, *.h) лежат в одной рабочей папке.

Дык мало положить их в одну папку, нужно их еще и в проект включить. См. пример на скриншоте.
P.S. кстати, не обязательно все файлы валить в одну кучу. Я для хидеров каждого проекта использую каталог _INC, а для Си-ных исходников каталог _LIB. А в самих файлах пишу относительные пути (на скриншоте выделено красным). Таким образом я могу весь проект легко перенести на другой диск или в другой каталог без потери связей между файлами и перенастройки проекта.
Эскизы прикрепленных изображений
Прикрепленное изображение
 
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Dec 9 2007, 19:06
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 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
singlskv
сообщение Dec 9 2007, 20:22
Сообщение #7


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(SasaVitebsk @ Dec 9 2007, 22:06) *
Сама проблема возникает когда п/п из другого файла используется в прерывании, которое в main описывается. Как выходить из неё - вроде понятно. 1) Вообще убрать вызовы п/п. 2) перенести п/п в файл, где пишется прерывание.
3) объявить п/п через extern в соответствующем хидере.
Цитата
1) Правильным ли является подход с выделением логически законченного блока в отдельный файл со своим хедером. И если "нет" или "не совсем"
Правильным, тока для разрешения всех противоречий нужно еще иметь "главный" хидер
в котором и объявляются основные настройки проекта и инклудятся все необходимые хидеры, ИМХО.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 9 2007, 21:56
Сообщение #8


Гуру
******

Группа: Модераторы
Сообщений: 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
Непомнящий Евген...
сообщение Dec 10 2007, 06:26
Сообщение #9


Знающий
****

Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153



Просветите плиз - что такое "п/п"?
Go to the top of the page
 
+Quote Post
Николай Z
сообщение Dec 10 2007, 07:21
Сообщение #10


Местный
***

Группа: Участник*
Сообщений: 418
Регистрация: 20-08-07
Пользователь №: 29 930



Цитата(Непомнящий Евгений @ Dec 10 2007, 09:26) *
Просветите плиз - что такое "п/п"?


Видимо подпрограмма.... Она же - функция...
Немного не С-шная терминология, но суть практически та же...
В Фортране к примеру - были функции, кторые возврвщали значение и void-функции, которые не возвращали значение или что почти то же самое обычно - возвращали пустое значение...

Еще в некоторых других языках использовалась такая терминология.

Сообщение отредактировал Николай Z - Dec 10 2007, 07:24
Go to the top of the page
 
+Quote Post
Непомнящий Евген...
сообщение Dec 10 2007, 07:34
Сообщение #11


Знающий
****

Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153



Что такое подпрограмма - я в курсе smile.gif Просто не сообразил, что п\п - это ее сокращение. Спасибо.

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

Ну например, чтобы не зависеть от конкретного прерывания. Тогда в модуле (а точнее в хидере) я пишу inline-функцию, а само прерывание делаю в основной программе, дергая из его обработчика эту функцию. Вместо inline-функции в С можно использовать макрос.
Go to the top of the page
 
+Quote Post
alexander55
сообщение Dec 11 2007, 06:17
Сообщение #12


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

Группа: Свой
Сообщений: 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
Сообщение #13


Гуру
******

Группа: Модераторы
Сообщений: 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
Сообщение #14


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

Группа: Свой
Сообщений: 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
SasaVitebsk
сообщение Dec 11 2007, 10:58
Сообщение #15


Гуру
******

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



Я, собственно так и работаю. И думал так все. smile.gif В смысле "main" главная или основная.

В main.h описываю основные переменные проекта. Например частоту проца и прочее. Этот хидер включаю во все хидера составных частей проекта (В данном последнем это Kls3x4.h, timerhw.h, lcd44780.h, wake.h). В каждом из составляющих хидеров определяются внутренние константы и объявления данного модуля и прототипы функций.

В самой main.c описывается вся программа опирающаяся на составные части. Прерывание описывается в main.c

Прерывание - метки времени. То есть там целый набор. smile.gif в том числе вызовы опроса клавиатуры. Вот и получается - засунуть её в Kls3x4.с некрасиво (там логически законченная библиотека) а при применении в main - есть накладные.


Собственно само по себе, естественно, это проблему не вызывает. Данное прерывание обрабатывается раз в 10мс и, честно говоря мне до лампочки что там весь контекст сохраняется. Я просто на будущее. Чтобы оценить кто как работает с оформлением и структурой программы. Ведь не маловажная причина перехода на Си - это читаемость программы её структурированность и возможность неоднократного применения модулей. По крайней мере я так рассматриваю. А опыта пока не хватает. Это я вижу хотябы по тому, что у меня от проекта к проекту пока меняются некоторые моменты оформления.

Думаю конечно скоро всё устаканится.

Спасибо за советы. beer.gif
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Dec 11 2007, 13:07
Сообщение #16


Гуру
******

Группа: Модераторы
Сообщений: 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
Сообщение #17


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

Группа: Свой
Сообщений: 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
Сергей Борщ
сообщение Dec 11 2007, 15:20
Сообщение #18


Гуру
******

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



Цитата(alexander55 @ Dec 11 2007, 15:39) *
Или включить максимальную оптимизацию по требуемому параметру.
Не поможет. Если части обработчика в виде функций раскиданы по разным модулям, а из обработчика видны как extern func(), то при любой оптимизации встраивания не будет, а компилятор будет сохранять/восстанавливать ненужные регистры. Если же все функции встраиваются - у компилятора широкое поле для оптимизаций


--------------------
На любой вопрос даю любой ответ
"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
Panych
сообщение Apr 7 2008, 13:32
Сообщение #19


Местный
***

Группа: Свой
Сообщений: 335
Регистрация: 17-06-04
Из: Москва
Пользователь №: 35



Подниму тему, чтоб не плодить...
Объявляю внешнюю функцию:
Код
extern void LCD_INIT ( void );

В main делаю вызов
Код
  LCD_INIT();

Не работает. Вставляю в main тело функции - все работает.
IAR не ругается и не предупреждает.
Файлы прикрепил. Помогите понять, плиз smile.gif
Прикрепленные файлы
Прикрепленный файл  AVR_Project.zip ( 1.39 килобайт ) Кол-во скачиваний: 40
 


--------------------
Всегда не хватает времени, чтобы выполнить работу как надо, но на то, чтобы ее переделать, время находится. (Закон Мескимена.)
Go to the top of the page
 
+Quote Post
msalov
сообщение Apr 7 2008, 13:45
Сообщение #20


Знающий
****

Группа: Свой
Сообщений: 526
Регистрация: 24-08-07
Из: Беларусь, Минск
Пользователь №: 30 045



Цитата(Panych @ Apr 7 2008, 16:32) *
Подниму тему, чтоб не плодить...
Объявляю внешнюю функцию:
Код
extern void LCD_INIT ( void );

В main делаю вызов
Код
  LCD_INIT();

Не работает. Вставляю в main тело функции - все работает.
IAR не ругается и не предупреждает.
В пятницу текст выводился, все вроде было именно так организовано - а в понедельник...
Файлы прикрепил. Помогите понять, плиз smile.gif

Судя по вашему проекту, функция LCD_INIT() у Вас не внешняя а очень даже локальная. Если уж решили разбивать проект на модули - доводите дело до конца, а не сводите все "модули" в один через #include.
С минимальной правкой того что есть, можно перенести прототип функции LCD_INIT() до тела самой функции.
Код
void LCD_INIT ( void );
void LCD_INIT ( void )
{
...
}

И ещё совет: все прототипы лучше описывать в заголовочных файлах.
Go to the top of the page
 
+Quote Post
Panych
сообщение Apr 7 2008, 14:15
Сообщение #21


Местный
***

Группа: Свой
Сообщений: 335
Регистрация: 17-06-04
Из: Москва
Пользователь №: 35



gotty
спасибо, сделал функцию внешней, IAR ругнулся на то, что в функции было объявлено
Код
extern void DELAYMKS ();
extern void DELAYMS ();

а не
Код
extern void DELAYMKS ( unsigned long mks );
extern void DELAYMS ( unsigned long ms );

исправил и все вроде заработало...


--------------------
Всегда не хватает времени, чтобы выполнить работу как надо, но на то, чтобы ее переделать, время находится. (Закон Мескимена.)
Go to the top of the page
 
+Quote Post
alux
сообщение Apr 8 2008, 12:04
Сообщение #22


Знающий
****

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



Цитата(gotty @ Apr 7 2008, 16:45) *
И ещё совет: все прототипы лучше описывать в заголовочных файлах.
... и чтобы исключить многократные включения заголовочных файлов в начале каждого хидера применять "заглушку" типа:
Код
#ifndef XXX_H
#define XXX_H

..................

#endif
Go to the top of the page
 
+Quote Post
MrYuran
сообщение Apr 8 2008, 12:11
Сообщение #23


Беспросветный оптимист
******

Группа: Свой
Сообщений: 4 640
Регистрация: 26-12-07
Из: Н.Новгород
Пользователь №: 33 646



Цитата(Panych @ Apr 7 2008, 17:15) *
gotty
спасибо, сделал функцию внешней, IAR ругнулся на то, что в функции было объявлено
Код
extern void DELAYMKS ();
extern void DELAYMS ();

очень правильно ругнулся, ибо () означает void, а вы туда переменные суёте...


--------------------
Программирование делится на системное и бессистемное. ©Моё :)
— а для кого-то БГ — это Bill Gilbert =)
Go to the top of the page
 
+Quote Post
ivainc1789
сообщение Apr 9 2008, 15:09
Сообщение #24


Профессионал
*****

Группа: Свой
Сообщений: 1 175
Регистрация: 5-01-05
Пользователь №: 1 807



Тема о многостраничных файлах, задам и свой махонький вопрос. А как описать внешние метки? Например, в main.c у меня описана метка Sleep. В другом файле модуля есть необходимость в безусловном переходе на Sleep типа goto Sleep. Сходу в документации не нашел как " ласково попросить" компилятор считать метку Sleep внешней? Конструкции типа extern label Sleep естественно не прокатывают...
Go to the top of the page
 
+Quote Post
Непомнящий Евген...
сообщение Apr 9 2008, 15:51
Сообщение #25


Знающий
****

Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153



Цитата(ivainc1789 @ Apr 9 2008, 19:09) *
Тема о многостраничных файлах, задам и свой махонький вопрос. А как описать внешние метки? ...

#include <setjmp.h>
Описание можно посмотреть например здесь http://www.freetype.org/david/reliable-c.html#annex-A

Но можно вопрос - а зачем вам это надо???
Go to the top of the page
 
+Quote Post
rezident
сообщение Apr 9 2008, 21:55
Сообщение #26


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(ivainc1789 @ Apr 9 2008, 21:09) *
Тема о многостраничных файлах, задам и свой махонький вопрос. А как описать внешние метки? Например, в main.c у меня описана метка Sleep. В другом файле модуля есть необходимость в безусловном переходе на Sleep типа goto Sleep. Сходу в документации не нашел как " ласково попросить" компилятор считать метку Sleep внешней? Конструкции типа extern label Sleep естественно не прокатывают...
bb-offtopic.gif Жесть! 07.gif Использование goto в программах на Си вообще считается моветоном, а чтобы еще и скакать по goto из одного файла в другой мне бы вообще в голову не пришло cranky.gif
Насколько я понимаю метка всегда привязана к оператору или функции, поэтому ее область видимости ограничена этой самой функцией или модулем. В самом стандарте ANSI C про goto говорится что
Цитата
6.8.6.1 The goto statement
Constraints
1 The identifier in a goto statement shall name a label located somewhere in the enclosing
function. A goto statement shall not jump from outside the scope of an identifier having
a variably modified type to inside the scope of that identifier.

Т.е. стандартными средствами Си "прыгнуть" по goto, допустим, внутрь другой функции нельзя. Тем более нельзя для функции, описанной в другом модуле.
Go to the top of the page
 
+Quote Post
sKWO
сообщение Apr 13 2008, 10:55
Сообщение #27


Местный
***

Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530



Добрый день!
Многофайловый проект, чёрт по.....
Подскажите, как обойти ошибку, извиняюсь что может быть повторяюсь.
Просто переопределения нигде не вижу, понимаю что чтото с включением файлов, пытался экстернить
но не помогло. Прикреплю проджект на всякий случай. Спросил на телесисах, но там молчок 05.gif
Error[e27]: Entry "EN" in module driver_lcd ( C:\Program Files\IAR Systems\test\testlsd\Debug\Obj\driver_lcd.r90 )
redefined in module main ( C:\Program Files\IAR Systems\test\testlsd\Debug\Obj\main.r90 )
ИАР версия 4.хх.
имею след код
файл bitdef.h
Код
#ifndef    BITDEF_H    
#define    BITDEF_H
#ifndef    BOOL_t  
#define    BOOL_t
typedef uint8_t bool_t;
#endif // BOOL_t
#ifndef    BitStr_t
#define    BitStr_t
typedef volatile uint8_t * port_t;
typedef struct{
  port_t Port;
  bool_t Bit;
}Port_Bit;
#endif // BitStr_t
#pragma inline=forced
void SETDDR(const Port_Bit * pb){
  *(pb->Port-1) |= 1 << pb->Bit;
}
#endif //BITDEF_H

файл driver_lcd.c
Код
#ifndef    driver_lcd_C  
#define    driver_lcd_C
#include "driver_lcd.h"
#include "delay.h"
// Команда на настройку выводов управления линиями управления ЖКИ на выход
void lcd_CMND_port_out(void)    {
                                        SETDDR(RW);\
                                        SETDDR(EN);\
                                        SETDDR(RS);\
                };
#endif //driver_lcd_C

файл driver_lcd.h
Код
#ifndef    driver_lcd_H
#define    driver_lcd_H
#include "bitdef.h"
// "E" Clock
Port_Bit dEN={&PORTB, 3};
const Port_Bit * EN = &dEN;
void lcd_CMND_port_out(void);
#endif //driver_lcd_H


Сообщение отредактировал sKWO - Apr 13 2008, 10:58
Прикрепленные файлы
Прикрепленный файл  testlsd.zip ( 25.62 килобайт ) Кол-во скачиваний: 25
 


--------------------
нельзя недооценивать предсказуемость глупости
Go to the top of the page
 
+Quote Post
alux
сообщение Apr 13 2008, 14:08
Сообщение #28


Знающий
****

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



Цитата(sKWO @ Apr 13 2008, 13:55) *
файл driver_lcd.h
Код
#ifndef    driver_lcd_H
#define    driver_lcd_H
#include "bitdef.h"
// "E" Clock
Port_Bit dEN={&PORTB, 3};   <<<<<<<<!!!!!!!!!!
const Port_Bit * EN = &dEN;   <<<<<<<<!!!!!!!!!!
#endif //driver_lcd_H

У вас в driver_lcd.h вынесено определение указателя EN. И это, естественно, является причиной переопределения. Нарушено правило одного определения. Перенесите определения в driver_lcd.с, а в driver_lcd.h объявите эти переменные с модификатором extern.

PS. Это же касается и других переменных.
И уберите обратные слеши в определении lcd_CMND_port_out. Они там ни к чему.

PS2. И
Код
#ifndef    driver_lcd_C  
#define    driver_lcd_C
...
... это лишнее.
Go to the top of the page
 
+Quote Post
sKWO
сообщение Apr 13 2008, 18:14
Сообщение #29


Местный
***

Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530



Цитата(alux @ Apr 13 2008, 17:08) *
У вас в driver_lcd.h вынесено определение указателя EN. И это, естественно, является причиной переопределения. Нарушено правило одного определения. Перенесите определения в driver_lcd.с, а в driver_lcd.h объявите эти переменные с модификатором extern.

Спасибо добрый чел, а то как-то грустно было вместо файла driver_lcd.h в мейне подключать файл driver_lcd.c. Так компилится без ошибок. Поэтому и было
Код
#ifndef    driver_lcd_C  
#define    driver_lcd_C

smile.gif smile.gif smile.gif smile.gif
Сам знаю что не правильно, а с меня пиво beer.gif , щас программы нету под рукой но думаю что вопрос будет закрыт


--------------------
нельзя недооценивать предсказуемость глупости
Go to the top of the page
 
+Quote Post
Непомнящий Евген...
сообщение Apr 14 2008, 04:44
Сообщение #30


Знающий
****

Группа: Свой
Сообщений: 771
Регистрация: 16-07-07
Из: Волгодонск
Пользователь №: 29 153



Цитата(sKWO @ Apr 13 2008, 14:55) *
Код
typedef uint8_t bool_t;
...
typedef struct{
  port_t Port;
  bool_t Bit;
}Port_Bit;
...
Port_Bit dEN={&PORTB, 3};


Странно как то - eсли вы объявили тип bool_t, то зачем туда запихивать 3????

И вообще, ИМХО, очень уж у вас сложный способ устанавливать биты в порту smile.gif
Может быть, конечно, ваш компилятор все это соптимизирует...

И еще вопросик - зачем вам такие конструкции:
Цитата
Код
#ifndef    BOOL_t  
#define    BOOL_t
typedef uint8_t bool_t;
#endif // BOOL_t

У вас bool_t что, в разных h-файлах объявляется? Объявляйте только в одном, и затем включайте везде, куда надо. Код сильно упростится...
Go to the top of the page
 
+Quote Post
alux
сообщение Apr 14 2008, 06:33
Сообщение #31


Знающий
****

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



Цитата(Непомнящий Евгений @ Apr 14 2008, 07:44) *
И вообще, ИМХО, очень уж у вас сложный способ устанавливать биты в порту smile.gif

Присоединяюсь.
Код
#ifndef    BOOL_t  
#define    BOOL_t
typedef uint8_t bool_t;
#endif // BOOL_t

Подключите stdbool.h, и пользуйтесь bool как полноценным типом.
Go to the top of the page
 
+Quote Post
andrej2005
сообщение Apr 20 2008, 10:34
Сообщение #32





Группа: Новичок
Сообщений: 14
Регистрация: 20-04-08
Пользователь №: 36 922



Цитата(jorikdima @ May 6 2007, 18:20) *
хидеры то подключены, а в опциях проекта пути к ним прописаны? (если они по поддиректориям распределены)


У меня была подобная проблема, только в MPLab для PIC. Думал рехнусь, и путь к линкеру был прописан в опциях проекта. Все решилось, когда взял в фигурные скобки етот путь.
Go to the top of the page
 
+Quote Post

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

 


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


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