在嵌入式库中使用浮点数

时间:2017-05-11 07:16:51

标签: c embedded

当我制作I2C或UART库时,我需要包含浮点,以便将正确的位放入控制这些外设中的比特率或波特率的寄存器中,使用类似下面的公式来负责放置右边的位进入控制波特率的UBBR寄存器:`

#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;

UBBR变为6但是当我移除(浮动)类型时,UBBR变为5 这会产生不同的波特率,这就是为什么我需要使用浮点来获得准确的数字,这是一个糟糕的方法,因为我应该完全避免使用浮点数,因为它会在程序代码中添加大量代码块,我应该更改它并使用另一种方式或者它可以吗? 我可以使用其他一些方法,但它们会受到更多限制(因为我可以使用的一些方法是将波特率限制为标准化的某些值,我将无法自由地设置任何波特率)

实际上我正在谈论的问题 - 不仅仅是在UART案例中 - 如果我遇到问题我最好的解决办法就是通过包含一些浮点运算来避免它并使用另一种可能不是的方法和浮点方法一样好,但仍能给出正确的答案,还是可以使用它?

2 个答案:

答案 0 :(得分:2)

你根本不需要浮点数。

(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

所以你可以这样写:

/*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;

答案 1 :(得分:0)

我使用了其中一条注释中的定点算术建议..所以我使用了一位作为精度,而整数部分的寄存器的其余部分只使用了一位精度,因为我只想知道精度部分是> 0.5所以我向上舍入到下一个整数(5.5 - > 6),否则(如果精度< .5)我不

    #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