Reputation: 27
When I make I2C or UART library I need to include floating point in order to put the right bits into the registers that controlthe bit-rate or baud rate in these peripherals by using a formulas like the following one that is responsible of putting the right bits into UBBR register which controls the baud rate :`
#define F_CPU 1000000UL
#define BAUD_RATE 9600
#define FACTOR_8_16 16
/*calculate UBBR value */
uint16_t UBBR_value = lrint(( F_CPU / (FACTOR_8_16 * (float)BAUD_RATE) ) - 1);
//Put the upper part of the UBBR value here (bits 8 to 11)
UBRRH = (uint8)(UBBR_value >> 8);
//Put the remaining part of the UBBR value here
UBRRL = (uint8)UBBR_value;
The UBBR becomes 6 but when I remove the (float)type casting the UBBR becomes 5 which generates a different baud rate that's why I need to use floating point in order to get the accurate number, is this a bad approach as I should totally avoid using floating number as it adds massive blocks of code into program code,should I change it and use another way or is it ok? I can use some other ways but they will be more limited(because some way I can use is to limit the baud rate to certain values that are standardised , I won't be able to put any baud rate freely)
actually in the question I am talking generally -not just in the UART case- that if I faced I problem that the best solution to it is by including some floating point arithmetic should I avoid it and use another approach that might be not as good as the floating point approach but still gives the right answer , or is it okay to use it?
Upvotes: 0
Views: 370
Reputation: 27
I used fixed point arithmetic advice from one of the comments.. so I used one bit as precision and the rest of the of the register for the integer part- used only one bit precision because I wanted only to know if the precision part is > 0.5 so I round up to the next integer number (5.5-->6), otherwise( if precision <.5) I don't
#define FP_F_CPU (F_CPU<<1) //FP for fixed point
#define FP_FACTOR_8_16 (8<<1)
/*****enter the baud rate****/
#define BAUD_RATE 9600
#define FP_BAUD_RATE ((uint32)BAUD_RATE<<1)
#define MULTIPLY_FIXED_POINT(A , B ,scale_bits) (( (A) * (B) ) >> scale_bits)
#define DIVIDE_FIXED_POINT(A ,B ,scale_bits)( ((A) << scale_bits) / (B) )
/*calculate UBBR value */
uint16 UBBR_value = DIVIDE_FIXED_POINT( (uint32)FP_F_CPU, MULTIPLY_FIXED_POINT((uint32)FP_FACTOR_8_16, (uint32)FP_BAUD_RATE,1) ,1 ) - (1 << 1);
if((UBBR_value & 1) ) //if the percent is 0.5
UBBR_value = (UBBR_value >> 1) +1; //remove the extra fraction bit and round up
else
UBBR_value >>= 1; // else just remove the extra fraction bit
Upvotes: 0
Reputation: 50892
You don't need floating point here at all.
(FACTOR_8_16 * BAUD_RATE) = 76000
F_CPU / (FACTOR_8_16 * BAUD_RATE) ) =
1000000 / 76000 = 13.1578 which will be rounded
o 13 by integer arithmetic
So you can just write this:
/*calculate UBBR value */
uint16_t UBBR_value = F_CPU / (FACTOR_8_16 * BAUD_RATE) - 1;
//Put the upper part of the UBBR value here (bits 8 to 11)
UBRRH = (uint8)(UBBR_value >> 8);
//Put the remaining part of the UBBR value here
UBRRL = (uint8)UBBR_value;
Upvotes: 2