HT7036数据读取(补码原码转换)

您所在的位置:网站首页 补码转化成原码怎么计算 HT7036数据读取(补码原码转换)

HT7036数据读取(补码原码转换)

2023-12-29 22:40| 来源: 网络整理| 查看: 265

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

HT7036数据读取(补码原码转换) 前言一、原码?补码?二、案发现场二、此地无坑,还是跳了下去三、补码转原码四、最初的起点总结

前言

虽然在单片机的数据处理中补码使用的场合很少,但是在使用一些外部模块的时候,由于模块产生的数据是补码类型的,这就不可避免的让脑袋不大灵光的我又跳进了一个深坑,此篇文章,以示警醒。

提示:以下是本篇文章正文内容,下面案例可供参考

一、原码?补码?

至于源码,反码,补码的转换,论坛上有很多的讲解,我就不重复造轮子了(其实我也不太懂,能解决实际问题就行)。关于原码反码补码之间的转换,可以参考以下文章: 篇幅很短,但通俗易懂 在这里插入图片描述 其中这句话很精髓。

二、案发现场

还原案发现场:两天前,某佩奇由于实验需要,玩起了HT7036,这是一款三相电能计量芯片,相比于HLW8032功能强大了不少,在佩奇苦苦的哀求下,实验室大佬佐助将HT7036芯片的初始化源码和用户参考手册发给了我,怀着感激的心,立刻研究起了芯片。 芯片的具体功能还没有细究,毕竟,先把时序写出来,随便读取一个寄存器的值,能看到希望才有动力进行下一步嘛。需要注意的是,HT7036的初始化程序使用的模拟SPI,其中读写数据时涉及到延时,在使用STM32F103RCT6作为主控芯片时,只需要将例程中的所有延时函数改成delay_us(1);即可,起初想过用__nop()来替代延时函数,如下图: 在这里插入图片描述 理解为等待5个系统时钟周期,想通过这样的方法来提高模拟SPI的传输速度(毕竟例程中也是这样的嘛),测试如下: 在这里插入图片描述 其中r_UaRms,r_UbRms,r_UcRms对应的寄存器地址如下: 在这里插入图片描述 通过读取寄存器的值,将读取到的数据打印到串口助手,测试结果如下图: 在这里插入图片描述 看到这里时,我激动到飞起,能读到ID寄存器的默认值,就是图中的0x7022e0,倒是仔细往下看时,发现读出来的电压有效值全部为零??是没有接三相电的原因??于是就借助了实验室的仪器,给其中一路采集通道加上了交流电,但还全部都是0!!!,这就不像话了,明明读出来的ID是对的,说明模拟SPI的读写时序是没有问题的,怎么会读出来的全部都是0呢???没办法,只能用示波器一点一点的找问题(此处无图),最后发现还是时序的问题,当把延时函数改为如下时: 在这里插入图片描述 它就成了,结果如下图所示: 在这里插入图片描述 通过改变交流电压,数值也在有规律的变化,这下前期工作也算差不多完成了,更大的坑还在后面等着我。

二、此地无坑,还是跳了下去

在这里插入图片描述 也许是由于受到例程的影响,我也理所当然的直接读取了对应的寄存器,将寄存器中的值读取了出来,按照道理来说,输入的波形是一个正弦波,那么无论采集的速度快慢,采集到的数据应该也是正弦波才对,但是,我还是不得不佩服我的脑回路(或者说佩服我的眼睛),代码如下,其中r_SampleUC就是上图中对应的0x34 在这里插入图片描述 测试结果如下: 在这里插入图片描述 这是正弦波???有点像梯形波对不对??也有点正弦波的味道??行了行了,别再欺骗自己了,开始也想过,产生这种情况的原因也推测过,可能是读取数据的方式不对,事已至此,就换个方法测量数据吧,HT7036中有一个寄存器,其介绍如下:在这里插入图片描述 在使用缓存数组之前,需要开启缓存命令,选择需要缓存数据的通道, 在这里插入图片描述 之后对数据进行缓。0xc1命令可以获得当前缓存了多少数据,代码如下图: 在这里插入图片描述 在这里选择了Uc的通道进行采集缓存,延时100毫秒才能采集完1024个数据(50毫秒能采集700个数据),缓存之后进行读取打印,结果如下: 在这里插入图片描述 这TM是什么妖魔鬼怪???方天画戟???由于数据转换的原因,16进制的数据转化为整形导致的??那我们就再来看看原原本本的16进制数据: 在这里插入图片描述 红色斜线为分界线数据从最大以下跳到最小,和波形图打印出的结果基本一样,也看不出来什么结果,还是回去老老实实看波形吧。其实仔细观察波形,会发现一个很有趣的事情,把上面的波形放大,仔细观察:

在这里插入图片描述 有没有一点正弦波的后半个周期的波形样子???这完完全全就是啊!!再回到之前那个方天画戟的波形仔细观察,将顶端和底端连结起来,新大陆!!!采集出来的就是正弦波!!但是由于一些原因数据发生了跳变,并且跳变的幅度很大。那这么说,之前采集的实时值是不是也是这样的波形??只不过速度太快了导致出来的是梯形波??回去仔细观察下 (发现CSDN不能上传视频,只能插入GIF,但是又特别麻烦,就用图片展示):在这里插入图片描述 实际将y轴拉长就会出现一个半波,这说明,采集的数据是正确的,可以开始下一步,再跳进一个更大的坑…

三、补码转原码

产生上述结果的原因,其实在用户手册中已经提及到了,而且提及到很多次,但我就是知道有坑还是往下跳,先上用户手册:在这里插入图片描述 结合着这句话就很清除的明白了,产生跳变的原因是什么了,由于单片机读回来的是补码数据,最高位位符号位,转换为源码需要除符号位取反再加1才能得到原码(此时的原码最高位是符号位,1为负,0为正),不懂得可以看开篇的链接或者查找相关的书籍。 话说,到这一步,应该能解决问题了吧,正数的补码转化为原码不用转,直接使用就可以。负数的补码在代码中实现就是全部取反 然后加1,再在前面加个符号,就是负数的原码其实这样也没有错,也是按照定义来的,但是后面还又一个坑,细心的人到这里就能采集到正弦波了,奈何我粗心大意,还要再写一个小结来解决这个问题。 以下补码转原码的代码只适用于当前的寄存器,代码如下:

int Complement_2_Original(u32 Comp_data) { int Orig_data; if(Comp_data & 0x40000) { Orig_data = (~Comp_data) + 1; Orig_data = -Orig_data; } else { Orig_data = Comp_data; } return Orig_data; } 四、最初的起点

仔细检查上面的代码,根据补码转原码的定义来的(还有溢出的情况没考虑,暂时还没完善),正常使用应该是没有问题的,那就把它带到程序中进行测试: 代码如下: 在这里插入图片描述 结果如下: 在这里插入图片描述 纳尼???怎么还是这种情况???逻辑上来说,应该是很标准的正弦波啊!!!又出问题了啊,没办法,开始排查错误,既然传回来的数据没有问题,那问题可能就出在转换函数上面(因为这方天画戟波也没怎么变化啊)。那我们就单独的验证这个函数,打开祖传的VC++6.0,将转换函数复制过去。 在这里插入图片描述 数据被原封不动的打印出来了。也就是说,在第18个bit位为1的时候,没有进入到if()语句,而是进入了else()语句,这问题就大了,祖传的VC++6.0出问题了??按位运算都不会了??如果这样想,这个问题就解决不了了。我们再进行下一步的测试,在语句块中加上打印语句,来判断是进入了哪个语句块: 在这里插入图片描述 是不是更加奇怪了,明明进入了if()语句,但是结果没变??那肯定是在转换的时候出问题了。先来手推一遍正确的结果:

1111 1111 0101 0100 1011 1000 //0xff54b8对应的二进制码 由于数据是18位的,即0~17bit,第19位为符号位,即18bit,高于18bit的位可以忽略 将上述补码除符号位其他位都按位取反,结果如下 0000 0100 1010 1011 0100 0111,高五位可以忽略,置1清0无所谓 (0000 0100 1010 1011 0100 0111)+1,取反后加1 0000 0100 1010 1011 0100 1000,这个就是原码,为负数

将上述二进制的原码转换为十进制,为 -43848,这和打印出来的0xff54b8对应的十进制 16733368 差了不知多少倍,知道了正确结果,开始在负数的补码转换原码语句块中一步一步调试。首先将取反后加1的结果以2进制打印出来。 在这里插入图片描述 怎么还是这么大的数字??先别着急,将上面的0xff00ab48转换为二进制

1111 1111 0000 0000 1010 1011 0100 1000 (0xff00ab48) 0000 0100 1010 1011 0100 1000 (0xff54b8除符号位取反+1,右对齐)

有没有发现有一点相似,不只是相似,是相同,也就是说,对补码取反后加1的结果是正确的,现在的问题就是,高8bit的1是怎么来的,通过函数的形参类型可以知道,函数传进来的是 unsigned int类型的,占用4个字节,虽然int类型得1也占用4个字节,但是,int类型有正负号,还是以0xff54b8为例:

当把形参传进去得时候,0xff54b8为 0000 0000 1111 1111 0101 0100 1011 1000 这是一个无符的int类型,占4个字节(32位),当进行取反操作(注意符号位)的时候,转换结果如下 1111 1111 0000 0100 1010 1011 0100 0111 然后加1 1111 1111 0000 0100 1010 1011 0100 1000 和上面的值特别大结果一模一样是不是

这样我们就知道高8bit的1是怎么来的了,下一步操作,就是取我们想要得数据了呀,直接与上0x3ffff,结果如下: 在这里插入图片描述 是我们想要的结果,由于在代码中直接对补码全部取反了(包括符号位),所以在取出我们想要的数据之后,再在前面添加一个符号,就完成了。再来看以下结果: 在这里插入图片描述 和之前手推的结果一模一样。现在把这个函数代入到程序中去,打印出波形: 在这里插入图片描述 大功告成,从来没发现正弦波如此的好看!

总结

改掉进去不该掉进去的坑算是一个都逃不过。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3