别着急,坐和放宽
在浮点兼容定点的应用时,分辨率的转换很让人头疼,所以有如下的宏方法。
对应关系类似 2--0.01--100 ,可以覆盖倍乘、倍除的数值关系。
/* 辅助宏 */
#define LIB_DEC_FACTOR_TOKEN(dp) LIB_DEC_FACTOR_##dp
#define LIB_DEC_FACTOR_0 1
#define LIB_DEC_FACTOR_1 10
#define LIB_DEC_FACTOR_2 100
#define LIB_DEC_FACTOR_3 1000
#define LIB_DEC_FACTOR_4 10000
#define LIB_DEC_FACTOR_5 100000
#define LIB_DEC_FACTOR_6 1000000
#define LIB_DEC_FACTOR_7 10000000
#define LIB_DEC_FACTOR_8 100000000
#define LIB_DEC_FACTOR_9 1000000000
#define LIB_DECIMAL_FACTOR(dp) LIB_DEC_FACTOR_TOKEN(dp)
#define LIB_DEC_STEP_TOKEN(dp) LIB_DEC_STEP_##dp
#define LIB_DEC_STEP_0 1.0f
#define LIB_DEC_STEP_1 1e-1f
#define LIB_DEC_STEP_2 1e-2f
#define LIB_DEC_STEP_3 1e-3f
#define LIB_DEC_STEP_4 1e-4f
#define LIB_DEC_STEP_5 1e-5f
#define LIB_DEC_STEP_6 1e-6f
#define LIB_DEC_STEP_7 1e-7f
#define LIB_DEC_STEP_8 1e-8f
#define LIB_DEC_STEP_9 1e-9f
#define LIB_DECIMAL_STEP(dp) LIB_DEC_STEP_TOKEN(dp)
/* 统一管理 */
#define RES_DEC_ACVoltage 2 /* 交流电压 */
#define RES_DEC_LoadACCurrent 2 /* 交流电流 */
#define RES_DEC_OutputACFreq 2 /* 交流频率 */
#define RES_DEC_PowerFactors 3 /* 功率因数 */
#define RES_DEC(name) (RES_DEC_##name) /* 小数位数 */
#define RES_FACTOR(name) (LIB_DECIMAL_FACTOR(RES_DEC_##name)) /* 倍数 */
#define RES_STEP(name) (LIB_DECIMAL_STEP(RES_DEC_##name)) /* 小数 */
使用类似如下
int a = RES_DEC(ACVoltage); // =2 获得小数位数
int b = RES_FACTOR(ACVoltage); // =100 获得对应倍数系数
int c = RES_STEP(ACVoltage); // =0.01 获得对应小数系数
哪怕具有倍数系数,在浮点转为定点数时依然面临四舍五入的小问题。可能可以结合以下函数进行。
#include <stdint.h>
#include <limits.h>
/**
* @brief 浮点值按十进制位缩放并四舍五入后转整型。
* @param value: 期望被转化的浮点值
* @param decimalPlaces: 缩放的小数位数(10^decimalPlaces)
* @retval 四舍五入后的缩放结果,超限时按int32范围饱和
*/
int32_t LIB_FloatToScaledInt(float value, uint8_t decimalPlaces)
{
double scale = 1.0;
for(uint8_t i = 0; i < decimalPlaces; i++)
{
scale *= 10.0;
}
double scaled = (double)value * scale;
if(scaled >= 0.0)
{
scaled += 0.5;
}
else
{
scaled -= 0.5;
}
if(scaled > (double)INT32_MAX)
{
return INT32_MAX;
}
if(scaled < (double)INT32_MIN)
{
return INT32_MIN;
}
return (int32_t)scaled;
}
一个应用示例
SelfACRunSetting[0].ACVoltage = 123.45678;
int a = LIB_FloatToScaledInt(SelfACRunSetting[0].ACVoltage, RES_DEC(ACVoltage); // = 12347