Arduino:更改无需编辑库即可定义[已解决,编译器中的错误,可用的解决方法] [英] Arduino: Change defines without edit library [solved, bug in compiler, workaround available]

查看:160
本文介绍了Arduino:更改无需编辑库即可定义[已解决,编译器中的错误,可用的解决方法]的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在下面查看我的答案

edit: See my answer below

我对Arduino平台还很陌生,现在使用AdaFruit的attiny85(Trinket)库创建一个USB HID项目.另请参阅我先前回答的有关此库选项的问题: 更改/覆盖Trinket(attiny85)USB标识名称,设备名称

I'm fairly new to the Arduino platform and creating now an USB HID project with the attiny85 (Trinket) library of AdaFruit. See also my previous answered question about the options of this library: Change/Override Trinket (attiny85) USB identification name, device name

我对C的一个罕见限制感到困惑(另请参阅上一个问题的链接的答案中的最新评论),即通过单独的编译来分离二进制文件的后期绑定.如果要更改USB设备的选项,则必须更改库本身,这对我来说有点奇怪,因为它是一个库.

I'm stumped on a rare C-related limitation (see also latest comment at answer in link above to previous question), the separated late binding of binaries by separated compiling. If you want to change options of the USB device, you have to change the library itself, kinda weird to me because it's a library.

例如,如果在加载库之前包含具有更改选项的头文件,则不会进行任何更改,因为该库是未知的,因为该库也必须包含该文件.

For example, if you include a header file with changed options before you loading the library, nothing is changed because it is unknown by the library because it must be included by this library either.

示例:这不起作用:

#include "myUSBOptions.h"
#include "TrinketHidCombo.h"

另一种方法:

因此,我需要为每个项目更改库本身,在本例中为usbconfig.h文件.对我来说,这听起来有点愚蠢,因为它是一个库,可以供其他项目使用. 也许这是Adafruit库中的一个设计错误,诸如供应商名称,设备名称等之类的东西在该库之外必须是可选的,并且当该库更新时,您的设置也可能被覆盖.而且...您需要为每个单独的项目再次编辑文件.

So I need to change the library itself for each project, in this case the usbconfig.h file. That's sounds a kind of stupid to me because it's a library and can be used by other projects. Maybe this is a design error in the Adafruit library, such things like vendorname, devicename etc must be optional OUTSIDE this library and also your settings can be overwritten when there is an update of the library. And... you need to edit the file again for each separated project.

因此,我想到了在usbconfig.h文件#include "user_usbconfig.h"中包含一个可选头文件的想法,该文件仅需更改即可.但这不是唯一的usbconfig.h文件,至少可以使用三个版本!在项目目录中创建一个user_usbconfig.h文件,编写一个用于使其自动化的批处理文件,并将其包含在项目目录中,以便在切换项目时只需单击即可更改选项.

So I came up with the idea to include an optional header file in the usbconfig.h file, #include "user_usbconfig.h" that requires only one change. But that's not the only usbconfig.h file, at least three versions are available! Create one user_usbconfig.h file in the project directory, Wrote a batch file for to automate it and include it in the project directory so you can change the options by simply clicking on it when switching project.

在usbconfig.h文件中添加了行:

.......

#include "cmdline_defs.h"

#ifndef __usbconfig_h_included__
#define __usbconfig_h_included__

#include "user_usbconfig.h" // <-- added this

.......

例如项目中包含的user_usbconfig.h

/* DEVICE SETTINGS */

/* Version number of the device: Minor number first, then major number. */
#define USB_CFG_DEVICE_VERSION  0x00, 0x01


/* VENDOR_NAME
 * These two values define the vendor name returned by the USB device. The name
 * must be given as a list of characters under single quotes. The characters
 * are interpreted as Unicode (UTF-16) entities.
 * If you don't want a vendor name string, undefine these macros.
 * ALWAYS define a vendor name containing your Internet domain name if you use
 * obdev's free shared VID/PID pair. See the file USB-IDs-for-free.txt for
 * details.
 */
#define USB_CFG_VENDOR_NAME     'm', 'y', 'C', 'o', 'm', 'p', 'a', 'n', 'y', 'n'
#define USB_CFG_VENDOR_NAME_LEN 10


/* DEVICE_NAME
 * Same as above for the device name. If you don't want a device name, undefine
 * the macros. See the file USB-IDs-for-free.txt before you assign a name if
 * you use a shared VID/PID.
 */
#define USB_CFG_DEVICE_NAME     'm', 'y', 'D', 'e', 'v', 'i', 'c', 'e'
#define USB_CFG_DEVICE_NAME_LEN 8


/* SERIAL_NUMBER
 * Same as above for the serial number. If you don't want a serial number,
 * undefine the macros.
 * It may be useful to provide the serial number through other means than at
 * compile time. See the section about descriptor properties below for how
 * to fine tune control over USB descriptors such as the string descriptor
 * for the serial number.
 */
/*#define USB_CFG_SERIAL_NUMBER   'N', 'o', 'n', 'e' */
/*#define USB_CFG_SERIAL_NUMBER_LEN   0 */

示例源代码myProject.ino,除了激活USB之外,什么也不做:

#include "TrinketHidCombo.h"

void setup()
{
  TrinketHidCombo.begin(); 
}

void loop() // Main program - main()
{
  // do nothing, check if USB needs anything done
  TrinketHidCombo.poll();  
}

我创建的批处理文件,添加到项目目录中:

@echo off
rem ********************************************************
rem * setTrinketUSBLibraryOptions.bat                      *
rem * ---------------------------------------------------- *
rem * Author       : Erwin Haantjes                        *
rem * Project      : Arduino Trinket USB                   * 
rem * Dev date     : 11-06-2016                            *
rem * Last changed : 11-06-2016                            *
rem * What it do   : 'Copy' (link) USB options project to  *
rem *                Trinket lib to make settings optional.* 
rem *                                                      *
rem ********************************************************


rem *** Config parts that can be modified if required
SET ARDUINO_LIB_DIR=F:\Program Files\Arduino\DigiSpark\Digispark-Arduino-1.0.4\libraries
SET USER_HEADER_FILE=user_usbconfig.h
SET ATU_HEADER_FILE=usbconfig.h
SET ATU_DIRNAME1=TrinketHidCombo
SET ATU_DIRNAME2=TrinketKeyboard
SET ATU_DIRNAME3=TrinketMouse

SET ATU_HEADER_FILE1=%ARDUINO_LIB_DIR%\%ATU_DIRNAME1%\%ATU_HEADER_FILE%
SET ATU_HEADER_FILE2=%ARDUINO_LIB_DIR%\%ATU_DIRNAME2%\%ATU_HEADER_FILE%
SET ATU_HEADER_FILE3=%ARDUINO_LIB_DIR%\%ATU_DIRNAME3%\%ATU_HEADER_FILE%
SET ATU_USER_HEADER_FILE1=%ARDUINO_LIB_DIR%\%ATU_DIRNAME1%\%USER_HEADER_FILE%
SET ATU_USER_HEADER_FILE2=%ARDUINO_LIB_DIR%\%ATU_DIRNAME2%\%USER_HEADER_FILE%
SET ATU_USER_HEADER_FILE3=%ARDUINO_LIB_DIR%\%ATU_DIRNAME3%\%USER_HEADER_FILE%

rem *** START
echo.
echo.
echo Set Thrinket USB Library options to match your project
echo ------------------------------------------------------
echo.
if "@%1"=="@/?" goto USAGE
if "@%1"=="@-?" goto USAGE
goto INTRO

:USAGE
SET USAGEMODE=true
echo Created by Erwin Haantjes 2016
echo.
echo USAGE:
echo %0 [/?,/C,-?,-C]
echo.
echo SWITCHES:
echo - ?   Shows this help
echo - C   Use copy command instead of symlink to hardcopy the "%USER_HEADER_FILE%" to it's targets
echo.

:INTRO
rem *** WARNING and NOTICE
echo WARNING:
echo - This batch changes/symlink options to be able to config the Trinket USB Library by project easily. Run this file once each time you work on a project to be sure you are using the right settings.
echo - If a physical %USER_HEADER_FILE% file exists in the library directory, it will be deleted!
echo.
echo NOTICE: 
echo - Each "%ATU_HEADER_FILE%" file in (parts/the) Trinket USB library must include the line: #include "%USER_HEADER_FILE%" at top of the file after #define __usbconfig_h_included__ .
echo - Once applying this 'patch', you can change USB settings in the "%USER_HEADER_FILE%" file in this directory on the fly without the need to run this batch again. Just compile it after a change and your changes will be 'visible'. 
echo.
echo.
echo Library directory is set to:
echo %ARDUINO_LIB_DIR%
echo.
echo. 
if "%USAGEMODE%"=="true" goto END
echo Do you want to continue? Press any key.
pause >NUL
echo.

rem *** Check destinations
if exist "%USER_HEADER_FILE%" goto NEXT1
goto ERROR_NO_USER_FILE
:NEXT1
if exist "%ATU_HEADER_FILE1%" goto NEXT2
goto ERROR_LIB_NOT_EXISTS
:NEXT2
if exist "%ATU_HEADER_FILE2%" goto NEXT3
goto ERROR_LIB_NOT_EXISTS
:NEXT3
if exist "%ATU_HEADER_FILE3%" goto NEXT4
goto ERROR_LIB_NOT_EXISTS
:NEXT4
goto APPLY

rem *** ERRORS
:ERROR_NO_USER_FILE
echo ERROR: Create a "%USER_HEADER_FILE%" in this directory first.
goto ABORTED
:ERROR_LIB_NOT_EXISTS
echo %ATU_HEADER_FILE1%
echo ERROR: Check the directory location match your Arduino IDE setup, see "ARDUINO_LIB_DIR" at top of this batch file. Check also if you have the Trinket USB Library currently installed.
goto ABORTED

:APPLY
echo All seems to be fine, applying patch (symlinks).....
echo Checking and removing target files....
if exist "%ATU_USER_HEADER_FILE1%" goto REMOVE1
goto APPLY_NEXT2
:REMOVE1
echo Remove symlink of "%ATU_USER_HEADER_FILE1%" ....
del "%ATU_USER_HEADER_FILE1%"

:APPLY_NEXT2
if exist "%ATU_USER_HEADER_FILE2%" goto REMOVE2
goto APPLY_NEXT3
:REMOVE2
echo Remove symlink of "%ATU_USER_HEADER_FILE2%" ....
del "%ATU_USER_HEADER_FILE2%"

:APPLY_NEXT3
if exist "%ATU_USER_HEADER_FILE3%" goto REMOVE3
goto APPLY_NEXT
:REMOVE3
echo Remove file/symlink of "%ATU_USER_HEADER_FILE3%" ....
del "%ATU_USER_HEADER_FILE3%"

:APPLY_NEXT
echo.
if "@%1"== "@/c" goto APPLY_COPY
if "@%1"== "@/C" goto APPLY_COPY
if "@%1"== "@-c" goto APPLY_COPY
if "@%1"== "@-C" goto APPLY_COPY
echo Applying symlinks....
mklink /H "%ATU_USER_HEADER_FILE1%" "%USER_HEADER_FILE%" 
mklink /H "%ATU_USER_HEADER_FILE2%" "%USER_HEADER_FILE%" 
mklink /H "%ATU_USER_HEADER_FILE3%" "%USER_HEADER_FILE%" 
goto SUCCESS

:APPLY_COPY
echo Copy file(s)....
copy "%USER_HEADER_FILE%" "%ATU_USER_HEADER_FILE1%"  
copy "%USER_HEADER_FILE%" "%ATU_USER_HEADER_FILE2%"  
copy "%USER_HEADER_FILE%" "%ATU_USER_HEADER_FILE3%"  
SET COPYMODE=true
goto SUCCESS

:ABORTED
echo Batch aborted due error.
goto END

:SUCCESS
echo.
echo SUCCESS!
echo NOTICE: 
echo - Patch succesfully applied when no error is visible on screen.
if "%COPYMODE%"=="true" echo - Because you specify the copymode switch, you have to take care of updates yourself. Run this batch file again when you have changed USB settings. 

:END
SET USAGEMODE=
SET COPYMODE=
echo.
echo Press any key to exit...
pause >NUL

:DIE
echo.

结论和问题:

尽管此方法可以正常工作,但我仍然不满意,想知道是否有一种更简单的方法而无需更改库的任何代码行.更加实时"的解决方案,因此您不必考虑这一点,从而避免出现错误和其他麻烦.

Although this method is working fine, I'm still not satisfied and wonder if there is an easier way to this without changing any line of code of the library. A more "on the fly" solution so you don't have to think about this to avoid errors and other headaches.

推荐答案

很长一段时间后,我发现Arduino编译器如何编译代码.这不是C/C ++问题,实际上这是Arduino编译器中的错误,即合并和编译顺序.同样,编译器会在编译之前添加一些特定的代码.

After a long time I discover how the Arduino compiler compiles the code. It is not a C/C++ issue, actually it is an error in the Arduino compiler, the combine and compile order. Also the compiler add some specific code before compiling.

解决方法:

使用exra项目h文件包含您的库/独立性.在包含之前定义将不起作用,因为在应用定义(在ino文件中)之前,编译方法包括h文件.使用定义时,例如要更改库,需要一个单独的h文件.例如,"myproject.inc.h"包含要使用的所有库.

Include your libraries/independencies with use of an exra project h-file. Defines before includes will not work because the compile method includes h-files before the defines (in your ino file) will be applied. When using defines, to change a library for example, requires a separated h-file. For example "myproject.inc.h" which includes all libraries you want to use.

现在将应用您在包含库之前指定的所有定义.

Now all defines you specify before including a library will be applied.

示例:

myproject.ino

#include "myproject.inc.h"

void setup()
{
  TrinketHidCombo.begin(); 
}

void loop() // Main program - main()
{
  // do nothing, check if USB needs anything done
  TrinketHidCombo.poll();  
}


myproject.inc.h

#define USB_CFG_VENDOR_NAME     'm', 'y', 'C', 'o', 'm', 'p', 'a', 'n', 'y', 'n'
#define USB_CFG_VENDOR_NAME_LEN 10

#include "TrinketHidCombo.h"

这篇关于Arduino:更改无需编辑库即可定义[已解决,编译器中的错误,可用的解决方法]的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆