问题
I'm trying to set up the USART module in an XMEGA micro controller and stumble over an error I can not find. For clarity I give you the complete code. So nothing in this header file is missing. (F_CPU
is defined in the main file)
#ifndef USART_H_
#define USART_H_
#include <avr/io.h>
#define USART_BAUDRATE 4800
#define USART_BSCALE -3
#if USART_BSCALE < 0
#define USART_BSEL F_CPU / (pow(2,USART_BSCALE) * 16 * USART_BAUDRATE) - 1
#define USART_BAUD_REAL F_CPU / (pow(2,USART_BSCALE) * 16 * (USART_BSEL + 1))
#else
#define USART_BSEL (1 / (pow(2,USART_BSCALE))) * (F_CPU / (16 * USART_BAUDRATE) - 1)
#define USART_BAUD_REAL F_CPU / (16 * ((pow(2,USART_BSCALE) * USART_BSEL) + 1))
#endif
#define USART_BAUD_ERROR USART_BAUD_REAL * 1000 / USART_BAUDRATE
#if USART_BAUD_ERROR<990 || USART_BAUD_ERROR>1010 /* <-- ERROR IS IN THIS LINE! */
#error Baud rate error too high!
#endif
#endif /* USART_H_ */
The compiler ends with the error
missing binary operator before token "("
in the marked line. There have been brackets before, but I removed them, tried different bracket combinations but the compiler still does see them there. What is wrong here?
回答1:
The #if
pre-processor directive is evaluated during the pre-processing stages. The function pow
is evaluated in run-time. Therefore you can't use it inside pre-processor tokens (macros) that are passed to #if
. You'll want to compute all these values at compile-time.
Hint: "2 times n" is the same as 1 << n
(bit-wise left shift).
In addition, there are some other serious issues:
You have tagged this AVR so you probably shouldn't use floating point numbers. They will not only make your program incredibly slow and open up for all kinds of bug possibilities, there is nothing gained from using them.
If you are lucky, you would get warnings for "missing floating point library" or similar. If you are unlucky, the program will link and blow away all your execution speed and memory.
It might be wise to check if your target system even has a FPU before considering using floating point.
- You need to write macros proper, with parenthesis surrounding the macro expression. Just like your second
USART_BSEL
which is properly written. Otherwise if your macro is used in an expression, you can get very subtle and very severe bugs related to operator precedence. Every half-decent C book addresses this very issue in the pre-processor chapter.
回答2:
If you want preprocessor to evaluate an expression, it has to be constant. pow()
is a runtime function, it can't be evaluated by the preprocessor at compile time.
Use parentheses around macro bodies, otherwise you'll run into problems.
Watch the type of the number constants. The operations are evaluated according to the types. 1/ANY_NUMBER
gives 0
, because the division is performed in signed int.
#define USART_BAUDRATE 4800U
#define USART_BSCALE (-3)
#if USART_BSCALE < 0
#define USART_BSEL (F_CPU*(1UL<<(-USART_BSCALE)) / (16U*USART_BAUDRATE) - 1U)
#define USART_BAUD_REAL (F_CPU*(1UL<<(-USART_BSCALE)) / (16U*(USART_BSEL+1U)) )
#else
#define USART_BSEL (F_CPU / ((1UL<<USART_BSCALE)*(16U*USART_BAUDRATE-1U)) )
#define USART_BAUD_REAL (F_CPU / (16U*((1UL<<USART_BSCALE)*USART_BSEL+1U) )
#endif
#define USART_BAUD_ERROR ( USART_BAUD_REAL * 1000U / USART_BAUDRATE )
Suggestion: you can achieve better accuracy for divisions with the rounding trick:
#define USART_BSEL_DIVISOR ((1UL<<USART_BSCALE)*(16U*USART_BAUDRATE-1U))
#define USART_BSEL ( (F_CPU+USART_BSEL_DIVISOR/2) / USART_BSEL_DIVISOR )
来源:https://stackoverflow.com/questions/37814166/preprocessor-missing-binary-operator-before-token