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

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,取反后加10000 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,结果如下:

是我们想要的结果,由于在代码中直接对补码全部取反了(包括符号位),所以在取出我们想要的数据之后,再在前面添加一个符号,就完成了。再来看以下结果:

和之前手推的结果一模一样。现在把这个函数代入到程序中去,打印出波形:

大功告成,从来没发现正弦波如此的好看!

总结

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

HT7036数据读取(补码原码转换)相关推荐

  1. 补码原码转换c语言代码,c/c++原码反码补码原理 以及进制转换

    1首先了解 低字节位 和高字节位 看图 2字节在内存的排列方式//int num = 010; //0开头代表 8禁止 //("%d",num); //所以打印的是8 int nu ...

  2. 补码原码反码溢出问题

    数据的机器层次表示 文章目录 数据的机器层次表示 2.1 补码+原码+反码 1. 原码表示法 2. 补码表示法 3. 反码表示法 4. 三种表示法比较 2.2 原码补码加减法运算 1. 补码加法 2. ...

  3. 补码原码反码简单理解

    补码原码反码简单理解 看到一句I2S的data是以补码形式来表现数据.再次查阅得出以下只管结论: ####1,首先直观举例机器里面是如何存放有符号数的:#### 1在机器里面表示为 0000 0001 ...

  4. 负数的补码和原码转换

    负数的补码和原码双向转换过程是相同的,都是逐位 求非 再加 1 . 同一个值的正负数是相反的值,所以要求非:     求非之后再加1则是因为中间的"零"占了一个数的位置:

  5. java反码补码原码作用_java原码补码反码关系解析

    本文为大家解析了java原码补码反码的关系,供大家参考,具体内容如下 原码:不管源数据是十进制还是十六进制,统统将数字转成二进制形式 反码:把原码的二进制统统反过来,0变成1,1变成0 补码:负数的反 ...

  6. 补码 原码 反码

    假设有一个 int 类型的数,值为5,那么,我们知道它在计算机中表示为: 00000000 00000000 00000000 00000101 5转换成二制是101,不过int类型的数占用4字节(3 ...

  7. 负数 补码 原码

    负数在计算机中是用补码的形式存储的,正数在计算机中是用原码的形式存储的. 正数求原码直接将十进制转二进制即可,负数的补码是在原码的基础上除符号位外其余位取反后+1. 但是用这种方式求负数补码用编程实现 ...

  8. 计算机原理原码反码,计算机原理 计算 —11011011补码( ) 原码( ) 反码( )11001010补码 原码 反码...

    -11011011补码( 100100101 ) 原码(111011011 ) 反码(100100100 ) 11001010补码 11001010 原码 11001010 反码 11001010 ( ...

  9. 从补码的来源剖析到为啥补码=原码按位取反+1

    1.引入问题 你已经困惑了很久,你明明知道 补码就是按位取反,然后加一,但是你想知道的,不是它怎么求滴,而是,它怎来滴.当然,对于阅读这篇文章的你,既然想要知道这个答案,一定是有一定编程基础的读者,肯 ...

最新文章

  1. Centos6.8防火墙配置
  2. lua 实现策划需要保留的小数位数
  3. Java——String类中的compareTo方法总结
  4. 算法系列15天速成——第三天 七大经典排序【下】
  5. Jupyter notebook中用python matplotlib ax3.plot_surface绘制的三维图(3D图)(三维函数)无法旋转解决办法(%matplotlib notebook)
  6. 给其他账户访问mysql的权限,将postgresql数据库的权限授予其他用户
  7. 分布式事物一致性设计思路
  8. js 操作Listbox js 获取Listbox选择的值的代码
  9. java笔试完一般多久给通知_恭喜浙江,喜提浙江中烟招聘通知,一、二批共计招录130人左右...
  10. CSS word-wrap强制换行截断长字符串
  11. 求矩形的最小值c语言,C语言复习---矩形法求定积分函数
  12. Go map 转 slice
  13. 比亚迪汉鸿蒙系统测评_深度:预判比亚迪汉EV电驱动系统技术状态
  14. mount: 未知的文件系统类型“vboxsf”_好程序员云计算学习路线教程大纲课件:Mount 挂载详解...
  15. 三菱四节传送带梯形图_PLC控制四节传送带设计
  16. 刘汝佳小白书-最长回文字串
  17. RAID-6技术详解
  18. oneDrive登陆界面空白 的解决办法
  19. vb访问服务器文件,VB6打开远程服务器文件
  20. Java多线程实现简易微信发红包

热门文章

  1. Android移植之dropbear
  2. GPS 入门 10 ——GPS快速定位之AGPS、EPO
  3. docker创建镜像并打包成tar
  4. Submit和execute的区别
  5. 高中英语教学论文的方向有哪些
  6. matlab chebyshev插值,Matlab之插值
  7. 计算机应用技术大专生可以考吗,计算机应用技术大专生毕业后两年考研都考什么...
  8. 科普!不同学历考生考研的要求和条件
  9. Hadoop生态系统图
  10. 联想微型计算机c200电脑烂了,联想C200一体电脑基本配置