【问题标题】:Convert binary ( integer and fraction) from VHDL to decimal, negative value in C code将二进制(整数和小数)从 VHDL 转换为十进制,C 代码中的负值
【发布时间】:2015-08-10 22:02:57
【问题描述】:

我有一个 14 位数据,从 FPGA 输入到 vhdl,NIos II 处理器从 FPGA 读取 14 位数据并执行一些处理任务,其中 Nios II 系统是用 C 代码编程的

14 位数据可以是正数、零或负数。在 Altera 编译器中,我只能将数据定义为 8,16 或 32。所以我将其定义为 16 位数据。

首先,我需要检查数据是否为负,如果为负,我需要将前两个 MSB 填充为位 '1',以便系统将其检测为负值而不是正值。

其次,我需要将此二进制表示的实际值计算为整数和分数的十进制值。

我从这个链接 (Correct algorithm to convert binary floating point "1101.11" into decimal (13.75)?) 了解到我可以将二进制(包含整数和小数)转换为十进制值。

具体说明,我可以使用此链接 (Correct algorithm to convert binary floating point "1101.11" into decimal (13.75)?) 引用的代码,转载如下:

#include <stdio.h>
#include <math.h>

double convert(const char binary[]){
  int bi,i;
  int len = 0;
  int dot = -1;
  double result = 0;

  for(bi = 0; binary[bi] != '\0'; bi++){
    if(binary[bi] == '.'){
      dot = bi;
    }
    len++;
  }
  if(dot == -1)
    dot=len;

  for(i = dot; i >= 0 ; i--){
    if (binary[i] == '1'){
      result += (double) pow(2,(dot-i-1));
    }
  }
  for(i=dot; binary[i] != '\0'; i++){
    if (binary[i] == '1'){
      result += 1.0/(double) pow(2.0,(double)(i-dot));
    }
  }
  return result;
}

int main()
{
   char  bin[] = "1101.11";
   char  bin1[] = "1101";
   char  bin2[] = "1101.";
   char  bin3[] = ".11";

   printf("%s -> %f\n",bin, convert(bin)); 
   printf("%s -> %f\n",bin1, convert(bin1)); 
   printf("%s -> %f\n",bin2, convert(bin2)); 
   printf("%s -> %f\n",bin3, convert(bin3)); 

   return 0;
}

我想知道这段代码是否可以用来检查负值?我确实尝试过使用 11111101.11 的二进制字符串,它的输出为 253.75...

我有两个问题:

  1. 为了读取负值,我需要做哪些修改?

我知道我可以做位移(如下)来检查msb是否为1,如果是1,我知道它是负值...

if (14bit_data & 0x2000) //if true, it is negative value

问题是,由于它涉及小数部分(但不仅仅是整数),如果该方法仍然有效,我会感到有点困惑......

  1. 如果二进制数原本不是字符串格式,有什么办法可以将其转换为字符串?二进制数最初来自用 VHDL 编写的 fpga 块,例如 14 位,以 msb 作为符号位,接下来的 6 位是整数的幅度,最后 6 位是小数部分的幅度。我需要 Altera Nios II 处理器的 C 代码中的十进制值。

【问题讨论】:

  • 你提到了FPGA。您使用哪种语言编写代码?高密度脂蛋白?视频博客?还是通过示例用 C 编写的软件代码?
  • @Quicky,感谢您的回复,抱歉没有说清楚,它是 fpga 中的 vhdl 和 Altera Nios II 系统中的 C 代码(将在主帖中进行编辑以进行澄清)
  • 但是你在这里质疑关注 C 代码?我不明白你到底在问什么?您是否只想检查这是否为负值?或者假设这是一个有符号数,计算这个二进制表示的实际值?
  • 14 位数据从 FPGA 输入到 vhdl 中,NIos II 处理器从 FPGA 读取 14 位数据并执行一些处理任务,其中 Nios II 系统用 C 代码编程
  • 好的,这很清楚。那么代码的目标是什么?

标签: string binary fpga signed


【解决方案1】:

好的,所以我关注的是你想重用你在问题开头提到的算法,并假设你的签名数字的二进制表示是Two's complement,但我不是根据您的 cmets 确定您的输入与算法使用的输入相同

首先填充 2 MSB 以获得 16 位表示

16bit_data = (14_bit_data & 0x2000) ? ( 14_bit_data | 0xC000) : 14_bit_data ;

如果值为正,则值将保持不变,如果为负,这将是正确的 16 位二进制补码表示。

对于小数部分,与您在问题中提到的算法相比,一切都相同。
对于整数部分,除了 MSB 的处理外,一切都相同。
对于无符号数 MSB(即 bit[15])表示 pow(2,15-6)(6 是小数部分的宽度),而对于二进制补码表示中的有符号数,它表示 -pow(2,15-6)意思是算法变成了

/* integer part operation */    
while(p >= 1)
{
  rem = (int)fmod(p, 10);
  p = (int)(p / 10);
  dec = dec + rem * pow(2, t) * (9 != t ? 1 : -1);
  ++t;
}

如果你不想要 * 运算符,或者说不同

/* integer part operation */    
while(p >= 1)
{
  rem = (int)fmod(p, 10);
  p = (int)(p / 10);
  if( 9 != t)
  {
     dec = dec + rem * pow(2, t);
  }
  else
  {
     dec = dec - rem * pow(2, t);
  }
  ++t;
}

对于您提到的第二种算法,考虑到您的格式,如果 dot == 11 和 i == 0 我们处于 MSB(10 个整数位后跟点),因此代码变为

for(i = dot - 1; i >= 0 ; i--)
{
   if (binary[i] == '1')
   {
       if(11 != dot || i)
       {
           result += (double) pow(2,(dot-i-1));
       }
       else
       {
           // result -= (double) pow(2,(dot-i-1));
           // Due to your number format i == 0 and dot == 11 so
          result -= 512
       }
   }
}

警告:在 brice 算法中,输入是字符串,如“11011.101”,而根据您的描述,您有一个整数输入,所以我不确定该算法是否适合您的情况

【讨论】:

  • 对不起,我试图理解...我能够在我之前提到的链接中使用页面底部的代码(作者 brice),但不是线程启动器,因为编译器不支持 fmod,我知道这要求很高,请您指出以下代码中整数部分所需的更改:
  • 请编辑您的问题以添加代码或信息,您将能够以更好的方式格式化
  • 感谢您的回复,是的,我已在原始帖子中添加代码并正确获取它,因为我无法在评论中这样做。您能否为我指出代码中整数部分所需的更改
  • 如果我理解正确,您之前的帖子的等效更改:如果我错了,请纠正我 for(i = dot-6; i >= 0 ; i--){ if (binary[ i] == '1'){ 结果 += (double) pow(2,(dot-i-1)); } }
  • 这不会考虑符号位,因为您只考虑整数部分。我更新了我的 brice 算法答案
【解决方案2】:

我认为这应该可行:

float convert14BitsToFloat(int16_t in)
{
    /* Sign-extend in, since it is 14 bits */
    if (in & 0x2000) in |= 0xC000;

    /* convert to float with 6 decimal places (64 = 2^6) */
    return (float)in / 64.0f;
}

要将任何数字转换为字符串,我会使用sprintf。请注意,它可能会显着增加您的应用程序的大小。如果你不需要float和什么来保留一个小应用程序,你应该自己制作转换函数。

【讨论】:

  • 感谢您的回复,我需要将此二进制表示的实际值计算为整数和分数的十进制值。例如,“in”是 15282 (0011 1011 1011 0010),但它不是真正的值,如何确保我得到的值是 -30.750015 而不是 15282? 14位数据定义如下:以msb为符号位,后面6位是整数的幅度,后6位是小数部分的幅度。
  • 这就是这段代码的作用,将带符号的 14 位和 6 位小数部分转换为浮点数,它可以很好地处理符号。请注意,您似乎很困惑,符号的 1 位 + 6 位整数 + 6 位小数是 13 位,而不是您输入的 14 位。我的代码假定 7 位整数部分和 6 位小数部分。另外,我很不确定 15282 应该如何等于 -30.75。 15282 是 -1102,它给出 -17.21875(与我的代码相同)
  • 感谢您的回复,总位数我错了。有 7 位整数部分和 6 位小数部分,你介意解释一下如何得到 -17.21875 吗?我很抱歉这个简单的问题。当我运行代码时,我得到 1006.781250,我想我错过了一些重要的点,对不起
  • 首先,如果值为负,则取正值。对于使用 2 的补码的 15282,这是 2^14-15282 = 1102。二进制(带小数点)的 1102 是 10001.001110,整数部分很简单:10001 = 17。小数部分是 1/8+1/16+1 /32 = 0.21875,总数 => -17.21875。
  • 感谢您的宝贵回复...我现在了解如何手动获取值 -17.21875,但我不明白您发布的 C 代码如何用于显示该值 (-17.21875) 时我运行代码?对不起,我的理解不佳
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-16
  • 2019-04-26
  • 1970-01-01
  • 2019-03-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多