在小华的RTC外设中,有个RTC补偿寄存器,可以对外部32768Hz晶振的频率进行修正,可以使RTC运行精度更高。
这里分享一下个人对这个补偿值计算的一些理解,经过实测补偿效果还是很准确的。 RTC补偿寄存器描述如下(L196系列参考手册): 其中CR部分就是补偿值,对晶振的补偿范围可达-274.6~212.6ppm的。补偿步进0.96ppm。 此寄存器描述中,说明此寄存器是带有5位小数的补码形式。 并给出了以下取值实例: 此示例中,涉及到一个操作是“取2的补码”,在此实例中,需要了解两个概念才能完成运算。 一:关于补码 在计算机存储中,为了存储有符号数,所以有了补码的概念,具体原理可以参考网络其他原理性文章,这里就不再重复引用了。 关于补码,可以只记住以下两句话 1、 正数的补码是正数本身。(0也是) 2、 负数的补码,是其对应正数的取反加一。 二:如何取小数的补码 整数取二进制时,可以使用辗转相除法,一直除2并取余数即可。 而小数值取二进制时,需要使用“乘二取整”的方式,例如例子中对0.6651904取2的补码,由于需要取5位二进制小数,如下步骤操作 0.6651904*2 =1.3303808 -------取1 0.3303808*2 = 0.6607616-------取0 0.6607616*2 = 1.3215232-------取1 0.3215232*2 = 0.6430464-------取0 0.6430464*2 = 1.2860928-------取1 因此例子中的0.6651904转换为五位二进制是0.10101B,寄存器需要四位整数,即0000.10101B,最终写入值就是0000.10101 + 0001.00000 = 0001.10101B。 对于负数,取二的补码就是正数的取反加一的值,0000.10101取反+1即1111.01011。 最终写入值为1111.01011+ 0001.00000 = 0000.01011B 以上就是手册中描述的计算方法。 三:简化算法 可以注意到,正数取二进制时,每一BIT表示的就是2的N次方,即从最低位开始,表示的1,2,4,8,16,32……的个数。 而小数部分,表示的是2的-N次方,即从小数最高位开始,分别表示1/2,1/4,1/8,1/16…. 我们寄存器的小数部分,只用到了5位小数,所以最低位表示的是1/32,即一个数字由多少个1/32组成。 因此在这种特定情况下,正数取2的补码,可以直接除1/32,也就是直接乘32,就是所要计算的2的补码。 例如例子中的0.6651904,不需要再一步步的乘二取整,直接乘32,得到21.2,其二进制数值就是10101B。 如果是负数,就直接取反加一即可。 在完整的计算步骤中,需要将ppm值进行* (2^15) / (10^6)处理再进行取补码的计算。 而我们之前已经把取补码的计算简化为*32。 所以此处可以合并计算为ppm值进行* (2^15) *32/ (10^6) 即 ppm*32768*32/1000000. 如果ppm为负数,就将结果进行取反+1即可。 因此,按照以上思路,将ppm转换为补偿寄存器的值可以按照以下代码进行转换 传入值为当前晶振的误差,单位为ppm。返回结果是可以直接写入寄存器的CR值。 uint32_tPpm_2_Compensation_Reg_standard(float ppm) { uint32_t Result = 0; ppm *= 32768*32; Result = ppm / 1000000; if(ppm > 0) //正数 { Result += 0x20; } else //负数,取反加1 { Result = ((~Result) + 1) + 0x20; } return Result&0x1ff; }
|