探秘float

探秘float,第1张

众手捉之(众所周知),在class="superseo">单片机应用时对float的需求比较大,但它又不(不容易)让你用float,所以本文档的目的是:

  • 希望在flash中存储float,int,乃至结构体类型的数据
  • 涉及双机乃至多机通信时,能够不受数据类型的限制(想传啥数传啥数)

文章目录
        • float的表示和存储方式
        • 应用

float的表示和存储方式
  1. 表示方式
    一般情况下,float类型的数据占据的内存为4字节,32位,并且有其独特的表示方式(科学计数法),但是计算机眼中的科学计数法是这样的:
    ( ± ) 1. a × 2 b (1) (\pm)1.a \times 2^b \tag{1} (±)1.a×2b(1)
    例如:
    1010 ⇒ + 1.01 × 2 3 0101 ⇒ + 1.01 × 2 2 10101 ⇒ + 1.0101 × 2 4 0.0101 ⇒ + 1.01 × 2 − 2 \begin{aligned} 1010 &\Rightarrow +1.01 \times 2^3 \ 0101 &\Rightarrow +1.01 \times 2^2 \ 10101 &\Rightarrow +1.0101 \times 2^4 \ 0.0101 &\Rightarrow +1.01 \times 2^{-2} \ \end{aligned} 10100101101010.0101+1.01×23+1.01×22+1.0101×24+1.01×22

  2. 存储方式1

    如上式(1)所示,float类型的数据需要分三部分存储,分别是正负号, a a a b b b,所以32位的空间被划分为三部分:

    1. 符号位(1位):最高位存储符号
    2. 指数位(8位):左数第二位到第九位存储指数,但是需要把指数偏移127,所以这八位存储的数值为b+127
    3. 尾数位(23位):最后二十三位存储尾数,如果尾数为0.01则计算机会把它自动补齐为0.010_0000_0000_0000_0000_0000,并把小数点后的23位存储在尾数位中
  3. 举例
    10 ⇒ 1010 ⇒ 1.01 × 2 3 ⇒ 0 _ 10000010 _ 01000000000000000000000 10 \Rightarrow 1010 \Rightarrow 1.01 \times 2^3 \Rightarrow 0\_10000010\_01000000000000000000000 1010101.01×230_10000010_01000000000000000000000验证一下:

    int main(void)
    {
        float data = 10;
        int data_bit = *(int *)&data;           //把float的32位数据存储在int中
        std::string str = "";
    
        for (int i = 31; i>=0; i--)
        {
            //把这32位数据存储在string类型中,方便打印
            if (data_bit & 1 << i)  str+="1";
            else                    str+="0";
        }
        
        std::cout << str;                       //打印
        return 0;
    }
    

    输出结果:

    01000001001000000000000000000000
    

    甚至我们还可以“创造”一个浮点数(以713为例):
    713 ⇒ 1011001001 ⇒ 1.011001001 × 2 9 ⇒ 0 _ 10001000 _ 01100100100000000000000 ⇒ 0 x 44324000 713 \Rightarrow 1011001001 \Rightarrow 1.011001001 \times 2^{9} \ \Rightarrow 0\_10001000\_01100100100000000000000 \ \Rightarrow 0x44324000 71310110010011.011001001×290_10001000_011001001000000000000000x44324000

    验证一下:

    int main(void)
    {
        int data = 0x44324000;
        float data_f = *(float *)(&data);
        std::cout << data_f;
        return 0;
    }
    

    输出结果:

    713
    

    成功!!!

应用
  1. flash中存float:

    • 第一种写法
      float data;                         //你的float型参数
      void *data_void = (void*)(&data);   //把地址赋值给一个数组
      uint32_t flash_data;
      memcpy(&flash_data, data_void, sizeof(uint32_t));
      flash_program(flash_data);          //写flash的函数
      
    • 另一种写法
      float data;                         //你的float型参数
      uint32_t flash_data = *(uint32_t*)(&data);
      flash_program(flash_data);          //写flash的函数
      
    • 读取数据
      uint32_t flash_data;                //从flash读出的数据
      float data = *(float*)(&flash_data);
      
  2. uart通信发送接收float类型的数据

    • 发送端:
      float data;                             //要发送的数据
      uint8_t *p_data = (uint8_t*)(&data);    //p_data指向最低的八位
      
      uart_putchar(UART, p_data); p_data++;   //把float拆成四个uint8_t发送
      uart_putchar(UART, p_data); p_data++;   //同一行可以出现俩分号
      uart_putchar(UART, p_data); p_data++;
      uart_putchar(UART, p_data);             //连发四次即可
      
    • 接收端:
      \\推荐在uart接收中断函数中接收
      void UART_IRQHandler(void)
      {
          UART->ICR |= UART_ICR_RXICLR;       //清除接收中断标志
      
          float receive_data_f;               //你需要接收的参数
          static uint8_t receive_data[4];     //定义四个uint8_t参数
          static uint8_t count = 0;
      
          uart_getchar(UART, &receive_data[count]);
          if (count < 3)  count++;
          else
          {
              count = 0;
      
              //将拆开发送的4个uint8_t组合在一起
              uint32_t receive_data_bit = 0;
      
              //注意强转(uint32_t)不能少,不然uint8_t位数不够,不能左移8位以上
              receive_data_bit += (uint32_t)(receive_data[0] << 8*0);
              receive_data_bit += (uint32_t)(receive_data[1] << 8*1);
              receive_data_bit += (uint32_t)(receive_data[2] << 8*2);
              receive_data_bit += (uint32_t)(receive_data[3] << 8*3);
              
              receive_data_f = *(float *)(&receive_data_bit);
          }
      }
      
      
  • 类似的,float, double, int, 结构体都可以用以上这些方式进行读写传输。



  1. https://blog.csdn.net/albertsh/article/details/92385277 ↩︎

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/563590.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-02
下一篇 2022-04-02

发表评论

登录后才能评论

评论列表(0条)

保存