共用体实现浮点数、负数的存储

一、共用体

共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。

定义格式为:

union 共用体名 
{
    共用体成员 1,
    共用体成员 2,
    ...
};

 结构体和共用体的区别:结构体的各个成员会占用不同的内存,互相之间没有影响;而共用体的所有成员占用同一段内存,修改一个成员会影响其余所有成员。

结构体占用的内存大于等于所有成员占用的内存的总和(对齐造成的),共用体占用的内存等于最长的成员占用的内存。共用体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉。

使用场景:

1.通信中的数据包会用到共用体,因为不知道对方会发送什么样的数据包过来,定义几种格式的包,收到包之后就可以根据包的格式取出数据。

2.节约内存。如果有2个大内存的数据结构,但不会同时使用,可以考虑用共用体来设计。

3.某些应用需要大量的临时变量,变量类型不同,而且会随时更换。而堆栈空间有限,不能同时分配大量临时变量。这时可以使用共用体让这些变量共享同一个内存空间,这些临时变量不用长期保存,用完即丢,和寄存器差不多,不用维护。

二、数据存储

 1.浮点数

定义共用体

union eeprom_float
{
	float a;
	uint8_t b[4];
}float_write,float_read;

// 声明
float_write.a = 3.1415926;

浮点数是4个字节,声明float_write.a=3.1415926,由于共用体共占一段内存,把一个float拆分为4个字节,然后逐字节的写入EEPROM,来达到保存float数据的目的。所以,通过float_read.b即可拆分flaot数据

读写数据:

for(i=0;i<sizeof(float);i++)
{
	Write_AT24c02(0+i,float_write.b[i]);
	HAL_Delay(5);
}

for(i=0;i<sizeof(float);i++)
{
	float_read.b[i]=Read_AT24c02(0+i);
}

iic读写函数如下:

void Write_AT24c02(uint8_t addr,uint8_t data)
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(addr);
	I2CWaitAck();
	I2CSendByte(data);
	I2CWaitAck();
	I2CStop();
}

uint8_t Read_AT24c02(uint8_t addr)
{
	uint8_t val;
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(addr);
	I2CWaitAck();
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	val=I2CReceiveByte();
	I2CWaitAck();
	I2CStop();
	return val;
}

2.负数

定义共用体

union eeprom_s16
{
	int16_t a;
	uint8_t b[2];
}s16_write,s16_read;
//声明
s16_write.a = -777;

思路和浮点数一样。负数在内存中的存储和正数一样,只是最高位用于表示正负。通过拆分有符号数据,然后逐字节的存储。

for(i=0;i<sizeof(uint16_t);i++)
{
	Write_AT24c02(33+i,s16_write.b[i]);
	HAL_Delay(5);
}
for(i=0;i<sizeof(uint16_t);i++)
{
	s16_read.b[i]=Read_AT24c02(33+i);
}

 3.多种数据类型

定义共用体

union eeprom_dat
{
	uint8_t t1;
	uint16_t t2;
	uint32_t t3;
	int16_t t4;
	float f1;
	double f2;
	uint8_t str[20];
}eeprom_dat_write,eeprom_dat_read;

//声明
eeprom_dat_write.f2 = 3.1415926535;

要确保uint8_t足够大,为了各种类型都能得到安全的存储。

for(i = 0; i < sizeof(eeprom_dat_write.f2); i++)
{
	Write_AT24c02(i,eeprom_dat_write.str[i]);
	HAL_Delay(5);
}
for(i = 0; i < sizeof(eeprom_dat_write.f2); i++)
{
	eeprom_dat_read.str[i] = Read_AT24c02(i);
	
}

4. 16位/32位数据

union eeprom_u16
{
	uint16_t a;
	uint8_t b[2];
}u16_write;

union eeprom_u32
{
	uint32_t a;
	uint8_t b[4];
}u32_write;


// 16数据
u16_write.a = 11521;
for(i=0;i < sizeof(u16);i++)
{
	write_24c02(&u16_write.b[i],i,1);
	HAL_Delay(5);
}
for(i=0;i<sizeof(u16);i++)
{
	read_24c02(&u16_write.b[i],i,1);
}
	
// 32数据
u32_write.a = 999999;
for(i=0;i < sizeof(u32);i++)
{
	write_24c02(&u32_write.b[i],i,1);
	HAL_Delay(5);
}
for(i=0;i<sizeof(u32);i++)
{
	read_24c02(&u32_write.b[i],i,1);
}

注意:上电判断问题:

如何在设备第一次上电时从EEPROM读取我们设定好的值呢?第七届省赛中题目要求如下:

由于在初始化时EEPROM中存储的数值是不确定的,所以需要向EEPROM先写入我们的值,并且只要在设备第一次运行此程序时才写入,其余时刻直接从EEPROM读取数值。第一次读取的是设定的初值,之后读取到的是修改值。需要加一个判断语句,随便选取读取一个或者两个EEPROM的地址判断是否等于一个随机数。如果判断为真,就将初始值写入EEPROM;判断为假,就不写入初始值,并且判断语句只需要执行一次。

	
// 判断第一次写标志
uint8_t flag1_24c02,flag2_24c02;
uint8_t val_24c02=10;
// 读取eeprom地址33和34的值作为判断
read_24c02(&flag1_24c02,33,1);
read_24c02(&flag2_24c02,34,1);
	
if(flag1_24c02!= 10&&flag2_24c02!=10) //第一次上电不满足
{
	write_24c02(num,0,3);//写入设置的值
	HAL_Delay(10);
	write_24c02(&val_24c02,33,2); //保证程序第一次上电只执行一次
	HAL_Delay(10);
}
read_24c02(read,0,3);HAL_Delay(10);

地址33和34值都为10的可能性是非常小的,成功的概论还是比较高的。

连续读写

小数:

//共用体:几个不同的变量共同占用一段内存的结构;
union eeprom_float
{
	float a;
	uint8_t b[4];
}float_write,float_read;

// 显示小数
float_write.a = 3.1415926;
for(i=0;i<sizeof(float);i++)
{
	write_24c02(&float_write.b[i],i,1);
	HAL_Delay(5);
}
for(i=0;i<sizeof(float);i++)
{
	read_24c02(&float_read.b[i],i,1);
}

负数

union eeprom_s16
{
	int16_t a;
	uint8_t b[2];
	
}s16_write,s16_read;
// 显示负数
s16_write.a = -777;
for(i=0;i < sizeof(s16);i++)
{
	write_24c02(&s16_write.b[i],i,1);
	HAL_Delay(5);
}
for(i=0;i<sizeof(s16);i++)
{
	read_24c02(&s16_read.b[i],i,1);
}

  • 9
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 9
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Super.Bear

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值