联合体在单片机编程中的应用

数据库2025-11-05 14:06:2715

01联合体

之前的联合文章《枚举和结构体的结合》文中提到,结构体就像是体单打包封装,把一些有共同特征的片机变量封装在内部。结构体是编程一种构造类型或复杂类型,它可以包含多个类型不同的应用成员。在C语言中,联合还有另外一种和结构体非常类似的体单语法,叫做联合体(Union)(有些地方也叫做共用体)。片机

联合体举例如下

union data{

char n;

char ch;

char f;

};

union data a,编程 b, c;

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

结构体占用的体单内存大于等于所有成员占用的内存的总和(存在字节对齐问题,这里不深入讨论)。片机

联合体占用的编程内存等于最长的成员占用的内存。联合体中如果对新的应用成员赋值,就会把原来成员的免费源码下载值覆盖掉。

//上文的联合体定义

char data;

a.n = 0x0A;//虽然只修改了成员变量n,但是ch和f变量都会被改变

data = a.f;//那么data的值就会被修改为0x0A

02联合体的应用

联合体在一般中的编程应用中还是很少的,在单片机编程中较多,在之前的文章《枚举和结构体的结合》将枚举和结构体的结合,下面的例子简单说明下联合体在结构体中的应用(我的日常开发中联合体一般都是和结构体一起使用的)。

在做显示屏应用时牵扯到一个概念,显示屏(全彩)上一个像素点是由于Red,Green,Blue三种颜色组成,在888模式下,每个像素点都是由8个bit组成的,这个时候为了便是一个像素点就需要用到结构体,这也对应前面的高防服务器文章,结构体就像是打包封装,把一些有共同特征的变量封装在内部。

typedef struct{

uint8_t Red;

uint8_t Green;

uint8_t Blue;

uint32_t Pix_Value;

}LCD_Pixvalue_S;

上面这样的写法是十分清晰的,访问很方便,可以单独访整个像素,也可以访问像素的某个颜色,有个问题那就是我操作红色像素,需要重新给Pix_Value成员赋值,如下

LCD_Pixvalue_S LCD_Pixvalue;

LCD_Pixvalue.Red = 0x12;

LCD_Pixvalue.Pix_Value = LCD_Pixvalue.Red<<16 | LCD_Pixvalue.Red<<8 |LCD_Pixvalue.Blue;

需要多一句代码,并且内存占用也大。当然,直接用下面写法,不会多占用内存,但是访问不方便。

typedef struct{

uint32_t Pix_Value;

}LCD_Pixvalue_S;

那么这个时候,使用联合体和结构体组合起来,就可以既不会多占内存,访问也很方便。

typedef union{

struct{

uint8_t Red;

uint8_t Green;

uint8_t Blue;

}Pix;

uint32_t Pix_Value;

}LCD_Pixvalue_S;

那么就可以如下操作

LCD_Pixvalue_S LCD_Pixvalue;

uint32_t data;

LCD_Pixvalue.Pix_Value = 0x0012FF00;

LCD_Pixvalue.Pix.Red = 0x25;//单独修改红色

data = LCD_Pixvalue.Pix_Value;//data的值就为0x0025FF00

当然,结构体的定义你也可以写到外面,其他地方可以使用,如下

typedef struct{

uint8_t Red;

uint8_t Green;

uint8_t Blue;

}Pix_s;

typedef union{

Pix_s Pix;

uint32_t Pix_Value;

}LCD_Pixvalue_S;

那么关于内存占用的云服务器问题,上面的定义方法,定义一个LCD_Pixvalue_S类型的变量占用4个字节。示例图如下

03联合体在串口开发中的应用

上面举例LCD应用中联合体的应用,这个是由于LCD一个像素由红绿蓝3色组成,所以用联合体很方便。在单片机项目开发中,串口协议解析也可以利用到联合体,十分方便。

在私有自定义协议中,合理定义协议,利用联合体代码十分方便。下面的例子不讲帧头,帧尾部分,举例联合体在协议解析中的应用,灵活应用。

串口协议举例如下

功能

字节长度

命令长度

4

命令字

1

命令内容

7

crc16

2

那么代码可以如下编写

typedef union{

struct{

uint32_t cmdlen;

uint8_t cmd;

uint8_t cmdbuf[7];

uint16_t crc16;

}unit;

uint8_t buffer[14];

}uart_buffer_s;

uart_buffer_s uart_buffer;

int main(void)

{

uint8_t len;

len = 0;

uart_buffer.buffer[len++] = 0x12;

uart_buffer.buffer[len++] = 0x34;

uart_buffer.buffer[len++] = 0x56;

uart_buffer.buffer[len++] = 0x78;

uart_buffer.buffer[len++] = 0xAA;

for(int i=0;i<7;i++)

{

uart_buffer.buffer[len++] = i;

}

uart_buffer.buffer[len++] = 0x11;

uart_buffer.buffer[len++] = 0x22;

while (1);

}

运行的结果如下

可以看到,我们只是往uart_buffer.buffer填充数据,模拟串口接收数据,接收完毕后,就自动解析出来我们自定义的cmdlen,cmd,cmdbuf和crc16。这里需要注意的是16位和32位的数据类型是小端模式,关于小端模式请看之前的文章《C语言在STM32中的内存分配》,这个还是很方便的。

!!!但是!!!需要注意字节对齐的问题,比如把上述cmdbuf修改为8个字节,就会出问题,如下

crc16就会出问题,这个就是字节对齐的问题,不懂的同学自行百度一下,这里不再重点讲解。

除了上述自定义协议解析时会用到联合体,还可以解决浮点型float的读取问题,float是占用4个字节的,如果将从串口接收的4个字节转换成float呢?联合体就可以可以解决这个问题

下面示例代码,我们知道浮点数231.5的16进制表示为0x43678000。

typedef union{

float data;

uint8_t buffer[4];

}uart_buffer_s;

uart_buffer_s uart_buffer;

int main(void)

{

uint8_t len;

len = 0;

uart_buffer.buffer[len++] = 0x00;

uart_buffer.buffer[len++] = 0x80;

uart_buffer.buffer[len++] = 0x67;

uart_buffer.buffer[len++] = 0x43;

while (1);

}

结果如下

可以看到我们模拟从串口收到4个字节,使用联合体,不用我们额外写代码,就可以自动转化为float型。当然这个转换也是小端模式的,小端模式详解请看文章《C语言在STM32中的内存分配》。

本文地址:http://www.bzve.cn/news/05c62999365.html
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

热门文章

全站热门

华为Mate10照相(从画质到拍摄功能,华为Mate10领先业界的照相实力)

windows 7打印机共享给他人提示无法保存打印机设置错误0x000006d

在固态硬盘上如何安装Win 7

Windows7系统锁定计算机的快捷方式如何设置?

红米Note4X32G(红米Note4X32G,一款卓越性能的经典机型)

windows 7/winxp修改重置svn的用户名密码的方法

Windows7系统修复缩略图显示错乱图文教程

在Ubuntu更新中,谁没有碰见个错误?在Ubuntu和其它基于Ubuntu的Linux发行版中,更新错误是一个共性的错误,也经常发生。这些错误出现的原因多种多样,修复起来也很简单。在本文中,我们将见到Ubuntu中各种类型频繁发生的更新错误以及它们的修复方法。合并列表问题当你在终端中运行更新命令时,你可能会碰到这个错误“合并列表错误”,就像下面这样:E:Encountered a section with no Package: header,E:Problem with MergeList /var/lib/apt/lists/archive.ubuntu.comubuntudistspreciseuniversebinary-i386Packages,E:The package lists or status file could not be parsed or opened.’可以使用以下命令来修复该错误:sudo rm -r /var/lib/apt/lists/*sudo apt-get clean && sudo apt-get update下载仓库信息失败 -1实际上,有两种类型的下载仓库信息失败错误。假如你的错误是这样的:W:Failed to fetch bzip2:/var/lib/apt/lists/partial/in.archive.ubuntu.comubuntudistsoneiricrestrictedbinary-i386Packages Hash Sum mismatch,W:Failed to fetch bzip2:/var/lib/apt/lists/partial/in.archive.ubuntu.comubuntudistsoneiricmultiversebinary-i386Packages Hash Sum mismatch,E:Some index files failed to download. They have been ignored, or old ones used instead那么,你可以用以下命令修复:sudo rm -rf /var/lib/apt/lists/*sudo apt-get update下载仓库信息失败 -2下载仓库信息失败的另外一种类型是由于PPA过时导致的。通常,当你运行更新管理器,并看到这样的错误时:你可以运行sudo apt-get update来查看哪个PPA更新失败,你可以把它从源列表中删除。你可以按照这个截图指南来修复下载仓库信息失败错误。下载包文件失败错误一个类似的错误是下载包文件失败错误,像这样:该错误很容易修复,只需修改软件源为主服务器即可。转到“软件和更新”,在那里你可以修改下载服务器为主服务器:部分更新错误在终端中运行更新会出现部分更新错误:Not all updates can be installedRun a partial upgrade, to install as many updates as possible在终端中运行以下命令来修复该错误:sudo apt-get install -f加载共享库时发生错误该错误更多是安装错误,而不是更新错误。假如尝试从源码安装程序,你可能会碰到这个错误:error while loading shared libraries:cannot open shared object file: No such file or directory该错误可以通过在终端中运行以下命令来修复:sudo /sbin/ldconfig -v你可以在这里查找到更多详细内容加载共享库时发生错误。无法获取锁 /var/cache/apt/archives/lock在另一个程序在使用APT时,会发生该错误。假定你正在Ubuntu软件中心安装某个东西,然后你又试着在终端中运行apt。E: Could not get lock /var/cache/apt/archives/lock – open (11: Resource temporarily unavailable)E: Unable to lock directory /var/cache/apt/archives/通常,只要你把所有其它使用apt的程序关了,这个问题就会好的。但是,假如问题持续,可以使用以下命令:sudo rm /var/lib/apt/lists/lock假如上面的命令不起作用,可以试试这个命令:sudo killall apt-get关于该错误的更多信息,可以在这里找到。GPG错误: 下列签名无法验证在添加一个PPA时,可能会导致以下错误GPG错误: 下列签名无法验证,这通常发生在终端中运行更新时:W: GPG error: http://repo.mate-desktop.org saucy InRelease: The following signatures couldn’t be verified because the public key is not available: NO_PUBKEY 68980A0EA10B4DE8我们所要做的,就是获取系统中的这个公钥,从信息中获取密钥号。在上述信息中,密钥号为68980A0EA10B4DE8。该密钥可通过以下方式使用:sudo apt-key adv --keyserver keyserver.ubuntu.com --recv-keys 68980A0EA10B4DE8在添加密钥后,再次运行更新就没有问题了。BADSIG错误另外一个与签名相关的Ubuntu更新错误是BADSIG错误,它看起来像这样:W: A error occurred during the signature verification. The repository is not updated and the previous index files will be used. GPG error: http://extras.ubuntu.com precise Release: The following signatures were invalid: BADSIG 16126D3A3E5C1192 Ubuntu Extras Archive Automatic Signing KeyW: GPG error: http://ppa.launchpad.net precise Release:The following signatures were invalid: BADSIG 4C1CBC1B69B0E2F4 Launchpad PPA for Jonathan French W: Failed to fetch http://extras.ubuntu.com/ubuntu/dists/precise/Release要修复该BADSIG错误,请在终端中使用以下命令:sudo apt-get cleancd /var/lib/aptsudo mv lists oldlistsudo mkdir -p lists/partialsudo apt-get cleansudo apt-get update本文汇集了你可能会碰到的Ubuntu更新错误,我希望这会对你处理这些错误有所帮助。你在Ubuntu中是否也碰到过其它更新错误呢?请在下面的评论中告诉我,我会试着写个快速指南。

友情链接

滇ICP备2023006006号-39