大家好,欢迎进入C语言“贝塔”学习课堂,我是Beta,今天跟大家分享C语言结构体与共用体的妙用:
首先来分析一下结构体和共用体的区别:
共同体:使几个不同类型的变量共占一段内存(相互覆盖)。所占内存长度是各最长的成员占的内存长度。
结构体:把不同类型的数据组合成一个整体。所占内存长度是各成员占的内存长度的总和。
在华大单片机的官方样例中,对寄存器的定义就大量使用了这两种数据结构来完成对寄存器总体或者对寄存器每一位的操作。下面,我们通过UART寄存器结构体设计的例子来看一下它们的使用方法。
首先,我们声明一个位域结构体:
struct stc_uart_isr_field_t
{
__IO uint32_t RC : 1;
__IO uint32_t TC : 1;
__IO uint32_t FE : 1;
__IO uint32_t TXE : 1;
__IO uint32_t PE : 1;
__IO uint32_t CTSIF : 1;
__IO uint32_t CTS : 1;
};
stc_uart_isr_field_t 的结构体声明了UARTx_ISR里的每一个位的分配情况。对应一下技术参考手册对UARTx_ISR的描述:
可以看到结构体是按低位开始向高位排列,而后面跟的数字就是每一个寄存器域占的位长,例如第一个RC对应了UARTx_ISR的最低位。
然后再声明一个共同体:
union stc_uart_share_isr
{
__IO uint32_t ISR;
struct stc_uart_isr_field_t ISR_f;
};
里面有两个参数,一个是ISR,一个是上面声明的结构体。根据union共同体的说明,我们就知道整型变量ISR和结构体ISR_f占用了同一个数据空间,对ISR的操作会影响ISR_f,同样对ISR_f的操作会影响ISR。这也意味着,ISR这个32位整型变量的每一位,就对应了ISR_f这个结构体的相应的一个成员变量。例如,对ISR的最低位的操作,就对应了ISR_f中的RC这个位长为1的成员变量。
然后我们知道,上面的共用体stc_uart_share_isr是属于UART寄存器,正如技术参考手册上的描述:
所以我们又可以声明一个UART寄存器的结构体:
struct M0P_UART_TypeDef
{
union stc_uart_share_sbuf UART_SHARE_SBUF;
union stc_uart_share_scon UART_SHARE_SCON;
union stc_uart_share_saddr UART_SHARE_SADDR;
union stc_uart_share_scon UART_SHARE_SCON;
union stc_uart_share_saden UART_SHARE_SADEN;
union stc_uart_share_isr UART_SHARE_ISR;
union stc_uart_share_icr UART_SHARE_ICR;
union stc_uart_share_scnt UART_SHARE_SCNT;
};
这样,再将M0P_UART_TypeDef 声明的寄存器例如M0P_UART分配到UART寄存器的地址,就完成了一个名为M0P_UART寄存器的声明。
struct M0P_UART_TypeDef M0P_UART;
如何来操作呢?
例如,我想把RC改成1,就有两种方法来实现:
首先
//整体赋值
M0P_UART.UART_SHARE_ISR.ISR|= 0x01;
//位赋值
M0P_UART.UART_SHARE_ISR.ISR_f.RC= 0x01;
第一个是全局赋值,因此要和ISR不赋值的位进行或0,赋值位进行或1,即改变了ISR的最低两位为1,而第二个是位赋值,即直接对RC位进行1的赋值。
理解了这个方法后,再来看样例对寄存器的操作是不是就很轻松了?掌握这个方法以后,你也可以设计一个带全局或者位操作的结构体来完成自己的程序数据的应用了。
说明:本文章参考百度博主星蝶偶成阁的《结构体与共同体(联合体)的妙用》