首页 » 智能 » 巧用补码(若何转化器件的补码数据?)_补码_函数

巧用补码(若何转化器件的补码数据?)_补码_函数

神尊大人 2025-01-07 05:31:12 0

扫一扫用手机浏览

文章目录 [+]

假设一个 ADC 转换芯片的转化数据为补码形式,24 位精度。
最大电压值为 0x7fffff,最小电压值为 0x800000,转化为十进制如下表:

先思考大略的,理解一下什么是补码:

巧用补码(若何转化器件的补码数据?)_补码_函数 巧用补码(若何转化器件的补码数据?)_补码_函数 智能

看 +127 的二进制 0111 1111b,再加 1 为 1000 0000b,立时变成负数最小值 -128。
如果把 1000 0000b 算作无符号常数,那么这个数便是 +128。
在这个数的根本上加 1,便是 1000 0001b,算作无符号常数便是 129,但是算作有符号常数便是 -127,由于最高位为 1 ,那么一定是负数,不可能是 129。
通过剖析这些数据,自己也能创造规律。

巧用补码(若何转化器件的补码数据?)_补码_函数 巧用补码(若何转化器件的补码数据?)_补码_函数 智能
(图片来自网络侵删)

那么如何将补码转化为我们须要的数据呢?网上很多方法对负数求原码是采取补码取反 + 1 的形式进行转化,但是真的须要这么麻烦吗?

先来验证一样平常方法的准确性:

1000 0001b 取反为 0111 1110b 再加 1 便是 0111 1111b 十进制为 +127,转换精确。
由于已经判断过是负数(负数才须要转化,正数的补码便是原码)然后通过打印函数 printf 打印出来。

来看看作这些处理须要多少步:

1、首先判断正负数

2、如果是正数,不转化,如果是负数,取反后 + 1。

3、当你显示出来的时候就须要在显示前加负号才对。
这样才能显示精确。

但是你有没有创造,干嘛要这么麻烦,既然打算机存储是用补码形式,你吸收的数据也是补码形式,直接用不就行啦。
把它当成有符号的数据直策应用就行了,不管做什么语句处理也是该当是没问题的:

if(AD_Value > -125)

{

}

else if(AD_Value > 125)

{

}

当你吸收的 AD 转化数据直接放到有符号 AD_Value 变量里面,难道这些判断就会有问题,难道就必须要转化才能进行其他处理?这不是多此一举嘛?直接把它算作有符号变量利用就行了。

你可能会问,机器里面是知道这是补码,我想打印显示出来的时候总的进行转化吧?彷佛挺有道理。
那你直接用 printf 函数打印弗成嘛,这个函数又不是说只能输出正数,负数也是能显示出来的,而且还可以格式化输出,比你自己写的函数好用多了吧!
但是有些有项目履历的又会问:我有多个输出位置须要进行输出,比如我要在 LCD 上显示温度,我还要在串口上打出 AD 值,而 printf 函数只能重定向一个位置,这样不是还得自己写一个打印函数吗?真的是这样吗?我们剖析以下问题

1、什么时候往什么地方进行输出我们知道吧?

2、打印的时候可以不同时打印是吧?

3、在一个位置须要打印的时候可以轻微等一等是吧?

如果这些问题的答案是肯定的,那么就有办法。
在须要往串口打印的时候,重定向到串口;当须要打印到 LCD 的时候,可以重定向到 LCD,怎么做,一个函数指针就能搞定的事。

设置一个函数指针,当须要打印到 LCD 的时候,将该指针指向 LCD 字符输出函数,当须要打印到串口的时候,指针指向串口字符输出函数,那么就能精确打印到相应的位置。

须要重定向的函数如下:

int fputc(int ch, FILE f)

{

PutChar(ch); // 打印字符的函数指针

return ch;

}

那么为什么要知足上面的条件呢?只有知道什么时候往什么地方输出才能修正函数指针。
而后两个条件便是 printf 函数本身的限定了,它是一个不可重入函数,在往串口打印的时候你就别打断它,让它又往 LCD 打印,由于这样会毁坏函数,导致打印出来的东西不伦不类。
因此打印的时候只能往一个位置进行打印,在打印完之后才能再切换到下一个打印位置,这势必引出第三个问题的思考。
这里可以采取锁的办法进行处理,正在打印的时候就上锁,不打印的时候就开释锁,让别人利用。

题外话说的彷佛比较多,连续说补码。

既然你都说不用进行转化了,那么就没什么好说的了,但是我所说的不用转化是在数据刚好是 8bit,16bit,32bit,64bit 的情形下,这样机器就可以直策应用,但是如果 AD 转化的数据是 10bit,12bit,20bit,24bit,又该怎么办,是不是又得走上老路,按部就班的进行转化呢?如果真是这样,我就不会专门写一篇了,前面写了那么多,便是为了引出这个啦!

上面的是 24 位的情形,彷佛和 8bit,16bit 这些数据的补码类似,都是全为 1 的时候为 -1,在最大数加 1 的时候变成最小值。

怎么处理呢?一条语句就 OK!

int AD_Value; //这条不能算哈,但很关键

AD_Value= ((AD_Value<< 8) >> 8);

看到这一条语句是不是以为这个人有病啊,左移完 8 位又右移 8 位,这不是闲着没事干吗?不好意思这是我自己想出来的,我也没病。
在思考出来之前,我也上网找过方法,由于我觉得该当存在一种大略的方法进行转化的,以是想上网看看能不能找到,如果能找到最好,实际上我没找到,网上可能也是有这个方法的,只是可能是我运气不好,没找到罢了。
就算作是我的原创好啦!
手动纯洁微笑脸。
其余利用 printf 函数进行多方打印(重点是往 LCD 打印)也是我自己突发奇想的,再加一个手动微笑脸。

好了,不扯了,再扯就晚了!

说重点,为什么这样处理就能达到我们想要的效果呢?原来位移操作有一个特性,利用这个特性就能将 24 位的补码转化成 32 位的补码形式,不对啊,怎么还是补码,不是说好了转化成原码啊,如果你还在纠结这个,你还没理解我前面所写的东西,再去前面看看吧,少年!
真不扯了,连续这个特性:这个特性便是当有符号变量进行位移操作的时候,如果高位为 1,进行右移时,高位补 1;如果高位为零,右移时高位补 0,这便是和无符号变量处理的不同!
亲测哦亲!
也便是说在进行右移的时候它已经进行了符号位的判断了,首先通过左移 8 位,让最高位为 1 或 0,然后再右移 8 位,根据右移的特性就完成了将 24 位有符号补码值转化为 32 位有符号变量,并且这种转化是不会影响数据的大小的。
其它位数的转化同理。
其余当前测试条件为 KEIL ARM 环境,其他环境不敢担保这条语句的精确性哦。

---------------------------------------------------------------------------------------------------------------------------------------------2018/07/30 Osprey

标签:

相关文章