Изучаю STM32. Взял пример с сайта STM для STM322xG-EVAL, в котором шина USB используется как виртуальный COMport, и пытаюсь его немного переделать. Хочу, чтоб при нажатии кнопки на клавиатуре контроллер передавал компьютеру в ЦИКЛЕ массив из цифр 1-32, при повторном нажатии- чтоб останавливался. Возникла проблема: когда я пытаюсь организовать передачу из main вызывая функцию VCP_DataТx, то программа не компилируется - пишет либо "функция не определена" при простом вызове VCP_DataTx (), либо "недопустимо двойное определение" - на определение функции как "extern uint16_t VCP_DataTx ();". Функция VCP_DataTx () определена в исходной программе в модуле usbd_cdc_vcp.c . Как правильно поступить в данной ситуации?
подключить соотвествующий заголовочный файл (там где её прототип, должно называться usbd_cdc_vcp.h)?
Попробовал. Компиляция прошла с предупреждением: warning: #223-D: function "VCP_DataTx" declared implicitly. А линковщик выдал ошибку:
Error: L6218E: Undefined symbol VCP_DataTx (referred from app.o). Это можно обойти?
В файле usbd_cdc_vcp.c функция VCP_DataTx определена как static. Поэтому ее нельзя использовать в другом модуле, уберите static в объявлении и тогда можно будет подцепить ее в другом модуле.
Меня смущает определение "static". Наверно, при написании программы его ввели с определённой целью. Если я его уберу, то не появятся новые "косяки"?
Весьма странно. Нет ли на VCP_DataTx() модификатора static?
Надо бы проект выложит сюда.
__
упс, уже опередили.
косяки не появятся, static нужен для того, чтобы отрубать доступ к функции вне единицы трансляции.
Сергей Борщ
Jun 17 2013, 06:36
QUOTE (NikP @ Jun 17 2013, 09:28)

Меня смущает определение "static". Наверно, при написании программы его ввели с определённой целью. Если я его уберу, то не появятся новые "косяки"?
Исходников не видел, но ваши рассуждения кажутся мне очень и очень логичными. Отсюда следует вывод - для передачи данных из вашего, пользовательского кода предусмотрена другая функция. И вам надо ее найти.
Цитата(Сергей Борщ @ Jun 17 2013, 10:36)

Отсюда следует вывод - для передачи данных из вашего, пользовательского кода предусмотрена другая функция.
Не предусмотрена. Этот пример - банальный переходник USB-UART. Указанная функция вызывается из прерывания по RXNE и берет данные из UART, что бы передавать ей свои данные ее нужно слегка переписать.
Сергей Борщ
Jun 17 2013, 08:04
QUOTE (Flexz @ Jun 17 2013, 10:25)

Не предусмотрена.
...
чтобы передавать ей свои данные ее нужно слегка переписать.
Значит это
пример того, как не надо писать программы.
Иногда полезно обращаться к первоисточникам: почитал про то, как определяются функции, переопределил VCP_DataTx() как extern (вместо static) в модуле usbd_cdc_vcp.c , и всё прекрасно увиделось из модуля app.c ( из main). Может кому пригодится этот опыт.
Lagman
Jun 18 2013, 18:46
Что это за первоисточник такой? Если в объявлении функции отсутствует спецификатор класса памяти, то по умолчанию принимается класс extern. Вам написали, что надо сделать заголовочный файл в котором перечислить прототипы функций, которые вы хотите использовать не только в текущем исходном файле, и уже подключать это заголовочный файл к другим исходным файлам (это все с условием что нет static)
Заголовочный файл
Я далеко не специалист в программировании, и не особо настаиваю на правильности того, что написал. Может, это совсем неправильно с точки зрения программирования на Си. Просто на практике так сделал - и заработало, без сбоев и тормозов.
Сведения же я взял так : набрал в яндексе "static в си" и первая ссылка оказалась helloworld.ru›texts/comp/lang/c/c/h16.htm .
Там и прочитал следующее :
"Спецификатор класса памяти в объявлении переменной может быть auto, register, static или extern. Если класс памяти не указан, то он определяется по умолчанию из контекста объявления. " и далее
"При объявлении переменной на внутреннем уровне может быть использован любой из четырех спецификаторов класса памяти, а если он не указан, то подразумевается класс памяти auto. "
Цитата(NikP @ Jun 18 2013, 21:13)

переопределил VCP_DataTx() как extern (вместо static) в модуле usbd_cdc_vcp.c , и всё прекрасно увиделось из модуля app.c ( из main).
Если автор программы определил в модуле функцию как static, это значит, что он не предполагал, что этой функцией будут пользоваться снаружи модуля. Когда вы сделали ее extern, до нее стало можно добраться и снаружи, но намерения первоначального автора модуля при этом не изменились
Так что позвать вы ее (функцию) теперь можете, но последствия этого вызова целиком на вашей совести.
Яркий пример - вы вытащили наружу функцию, которая работает с регистрами какого то аппаратного модуля и вызывается только из прерываний. Вызов этой функции снаружи (не из прерывания) может нарушить работу этого самого модуля, если в процессе ее вызова произойдет прерывание, и обработчик снова позовет эту функцию.
Цитата(XVR @ Jun 19 2013, 12:38)

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