文章目录众手捉之(众所周知),在class="superseo">单片机应用时对float的需求比较大,但它又不(不容易)让你用float,所以本文档的目的是:
- 希望在flash中存储float,int,乃至结构体类型的数据
- 涉及双机乃至多机通信时,能够不受数据类型的限制(想传啥数传啥数)
- float的表示和存储方式
- 应用
-
表示方式
一般情况下,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×2−2 -
存储方式1
如上式(1)所示,float类型的数据需要分三部分存储,分别是正负号, a a a 和 b b b,所以32位的空间被划分为三部分:
- 符号位(1位):最高位存储符号
- 指数位(8位):左数第二位到第九位存储指数,但是需要把指数偏移127,所以这八位存储的数值为
b+127
- 尾数位(23位):最后二十三位存储尾数,如果尾数为
0.01
则计算机会把它自动补齐为0.010_0000_0000_0000_0000_0000
,并把小数点后的23位存储在尾数位中
-
举例
10 ⇒ 1010 ⇒ 1.01 × 2 3 ⇒ 0 _ 10000010 _ 01000000000000000000000 10 \Rightarrow 1010 \Rightarrow 1.01 \times 2^3 \Rightarrow 0\_10000010\_01000000000000000000000 10⇒1010⇒1.01×23⇒0_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 713⇒1011001001⇒1.011001001×29⇒0_10001000_01100100100000000000000⇒0x44324000验证一下:
int main(void) { int data = 0x44324000; float data_f = *(float *)(&data); std::cout << data_f; return 0; }
输出结果:
713
成功!!!
-
往
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);
- 第一种写法
-
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
, 结构体都可以用以上这些方式进行读写传输。
https://blog.csdn.net/albertsh/article/details/92385277 ↩︎
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)